Unicorn DB connection 遇到的问题

July 20, 2014 20:44


由于不明白为什么在Unicorn before_fork中,ActiveRecord需要disconnect, 所以在一个使用Sequel的项目没管这个,看着运行好像也没什么问题,就不了了之了。

项目上线后,在高并发下,发现一直出错,并发一掉下来问题又没了。在几天的折腾下, 才发现是查询出来的数据有问题。也不知道是为什么,于是复制服务器上的配置, 在本地用Unicorn把项目跑起来。

当时发现在有高并发请求时,就有机率出现查询出来的数据不对,折腾半天不明白是为什么。 想着如果我把Unicorn的process设置为1还会不会出问题呢?在设置成1个进程后;居然好了。 这才想起,使用ActiveRecord时有,在beforefork和afterfork时分别做了两件事, ActiveRecord::Base.disconnect! 与 ActiveRecord::Base.establish_connection。

那么应该就是这个的问题了,在Sequel中只要Sequel.disconnect!就好了。而连接时,我试过了, 只要有查询,就会自动connect。便在before_fork加入了Sequel.disconnect!,再试,果然好了。

在查询一下后得知,是因为socket的原因:

When a process forks, the child has copies of all the parent's open filehandles, including sockets. When you close a file or socket, you close only the current process' copy. If another process (parent or child) still has the socket open, the operating system doesn't consider their file or socket closed.

Take the case of a socket that data is being sent to. If two processes have this socket open, one can close it but the socket isn't considered closed by the operating system because the other still has it open. Until the other process closes the socket, the process reading from the socket won't get an end-of-file. This can lead to confusion and deadlock.

大概意思就是,当你fork一个process时,parent进程的filehandles和sockets都会被复制过去, 也就是他们的引用记数,会增加,当一个socket被关闭,操作系统并不会认为他被关闭了, 因为另一个process还在使用它。直到另一个进程也关闭了它,否则都读不到end-of-file。 这会造成混乱。也就是像我这次的情况,查询出来的数据错了,有时候丢失了, 有时会得到另一个进程查询的结果。

Comments: