大家好,我有下一个环境python2.7.5:
flask==0.10.1
flask-wtf==0.8.4
jinja2==2.7
werkzeug==0.9.1
flask-mongoengine==0.7.0
mongoengine==0.8.2
pymongo==2.5.2
uwsgi==1.9.13
并有下一个应用程序'app.py':
from flask import Flask
from flask.ext.mongoengine import Document, MongoEngine
from mongoengine import StringField  
class Config(object):
    DEBUG = True
    MONGODB_HOST = ('mongodb://localhost:27017,localhost:27018/'
                    'test?replicaSet=rs0')
    MONGODB_DB = True
app = Flask(__name__)
app.config.from_object(Config)
MongoEngine(app)
class Test(Document):
    test = StringField(default='test')
    meta = {
        'allow_inheritance': False,
    }
    def __unicode__(self):
        return self.test
Test(test='test1').save()
@app.route('/')
def hello_world():
    return unicode(Test.objects.first())
if __name__ == '__main__':
    app.run('0.0.0.0', 8080, True)
我有下一个 nginx 配置:
server {
    listen       80;
    server_name  localhost;
    location / {
        include uwsgi_params;
        uwsgi_pass unix:/tmp/uwsgi.sock;
    }
}
我开始 uwsgi 为:
/path/to/env/bin/uwsgi \
  --module app:app \
  --env /path/to/env/ \
  --pythonpath /path/to/app/ \
  --socket /tmp/uwsgi.sock \
  --pidfile /tmp/uwsgi.pid \
  --daemonize /tmp/uwsgi.log \
  --processes 2 \
  --threads 2 \
  --master
我有两个 mongodb 实例:
mongod --port 27017 --dbpath /path/to/mongo/data/rs0-0 --replSet rs0 \
  --smallfiles --oplogSize 128
和
mongod --port 27018 --dbpath /path/to/mongo/data/rs0-1 --replSet rs0 \
  --smallfiles --oplogSize 128
并将 mongo 控制台中的副本集配置为:
rsconf = {
    _id: "rs0",
    members: [{_id: 0, host: "127.0.0.1:27017"}]
};
rs.initiate(rsconf);
rs.add("127.0.0.1:27018");
所以它运作良好。但是当我关闭和启动主要或次要 mongo 实例时,我的应用程序无法恢复连接,并且每次之后我都有下一个异常:
...
  File "/path/to/app/replica.py", line 33, in hello_world
    return unicode(Test.objects.first())
  File "/path/to/env/local/lib/python2.7/site-packages/mongoengine/queryset/queryset.py", line 325, in first
    result = queryset[0]
  File "/path/to/env/local/lib/python2.7/site-packages/mongoengine/queryset/queryset.py", line 211, in __getitem__
    return queryset._document._from_son(queryset._cursor[key],
  File "/path/to/env/local/lib/python2.7/site-packages/pymongo/cursor.py", line 470, in __getitem__
    for doc in clone:
  File "/path/to/env/local/lib/python2.7/site-packages/pymongo/cursor.py", line 814, in next
    if len(self.__data) or self._refresh():
  File "/path/to/env/local/lib/python2.7/site-packages/pymongo/cursor.py", line 763, in _refresh
    self.__uuid_subtype))
  File "/path/to/env/local/lib/python2.7/site-packages/pymongo/cursor.py", line 700, in __send_message
    **kwargs)
  File "/path/to/env/local/lib/python2.7/site-packages/pymongo/mongo_replica_set_client.py", line 1546, in _send_message_with_response
    raise AutoReconnect(msg, errors)
pymongo.errors.AutoReconnect: No replica set primary available for query with ReadPreference PRIMARY
当我使用mongoengie==0.7.10which useReplicaSetConnection代替MongoReplicaSetClient时,mongoengine==0.8.2我有下一个例外:
- 次要,获取请求,次要,获取请求: - 我第一次有: - pymongo.errors.AutoReconnect: 127.0.0.1:27017: [Errno 104] Connection reset by peer- 后: - pymongo.errors.AutoReconnect: No replica set primary available for query with ReadPreference PRIMARY
- Down primary,获取请求,up primary,获取请求: - 我第一次有: - pymongo.errors.AutoReconnect: 127.0.0.1:27017: [Errno 111] Connection refused- 后: - pymongo.errors.AutoReconnect: No replica set primary available for query with ReadPreference PRIMARY
- 向下主要或次要,向上主要或次要,获取我一直的请求: - pymongo.errors.AutoReconnect: not master and slaveOk=false
所以两个 mongo 实例只是简单的例子。如果我再添加一个实例(总共 3 个),那么:
- 如果我关闭任何辅助设备,那么一切正常。如果我向下和向上一个二级然后向下或向下和向上第二个二级然后一切正常。 
- 如果我上下两个辅助 - 一些问题。 
- 如果我关闭主节点或仅关闭一个主节点(两个辅助节点可用) - 一些问题,尽管 mongo 选择了新的主节点!!! 
如果我启动一个 uwsgi 进程(没有--master两个或三个 mongo 实例):
/path/to/env/bin/uwsgi \
  --module app:app \
  --env /path/to/env/ \
  --pythonpath /path/to/app/ \
  --socket /tmp/uwsgi.sock \
  --pidfile /tmp/uwsgi.pid \
  --daemonize /tmp/uwsgi.log \
  --processes 1 \
  --threads 2
或使用开发服务器运行应用程序:
/path/to/env/bin/python app.py
然后应用程序在关闭和启动 mongo 实例后恢复连接没有问题。
我在生产中进行了一些部署,有时与 mongo 实例的连接可能会中断(几秒钟)。之后,在重新启动 uwsgi 之前,我的应用程序无法正常工作。
所以我有两个问题:
- 为什么它发生在几个 uwsgi 进程中?
- 如何在关闭和启动 mongo 实例后修复正常的应用程序工作?
UPD1self.__schedule_refresh() :我试图理解问题,现在当我关闭一个 mongo 节点时出现连接异常时我有不同的行为:
- 对于一个过程: - 在此声明之前:rs_state有两个成员:active withup == True,downed withup == False。
- 在这句话之后:rs_state有一个活跃的成员up == True。
 
- 在此声明之前:
- 对于两个进程: - 在此声明之前:rs_state有两个成员:active withup == True,downed withup == False。
- 在此声明之后:rs_state有两个成员:active withup == True,downed withup == False(未更改)。
 
- 在此声明之前:
当我启动 mongo 节点时,self.__schedule_refresh(sync=sync)也会有不同的行为:
- 对于一个过程: - 在这句话之前:rs_state有一个活跃的成员up == True。
- 在此声明之后:rs_state有两个成员活跃于up == True,向上up == True。
 
- 在这句话之前:
- 对于两个进程: - 在此声明之前:rs_state有两个成员使用 激活up == True,使用 增加up == False。
- 在此声明之后:rs_state让两个成员活动,用up == True,向上up == False(没有改变)。
 
- 在此声明之前:
所以看起来 mongo 无法更新副本集状态(请参阅__schedule_refresh):
def __schedule_refresh(self, sync=False):
    """Awake the monitor to update our view of the replica set's state.
    If `sync` is True, block until the refresh completes.
    If multiple application threads call __schedule_refresh while refresh
    is in progress, the work of refreshing the state is only performed
    once.
    """
    self.__monitor.schedule_refresh()
    if sync:
        self.__monitor.wait_for_refresh(timeout_seconds=5)