python - Mongodb复制集自动重新连接在nginx + uwsgi上下运行后无法正常工作

嗨,大家好,我有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.10而不是ReplicaSetConnection中的MongoReplicaSetClientmongoengine==0.8.2时,我有下一个异常(exception):
  • 激活辅助节点,获取请求,激活辅助节点,获取请求:

    我第一次有:
    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
    
  • 关闭主服务器,获取请求,打开主服务器,获取请求:

    我第一次有:
    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个),则:
  • 如果我取消任何中学类(class),则一切正常。如果我在一个中学上下来,然后再在第二中学上下来,那么一切也都很好。
  • 如果我上下两个辅助按钮-有些问题。
  • 如果我上下小学或刚读完一个小学(可使用两个中学)-尽管蒙哥选出了新小学,这还是有些问题!!!

  • 如果我启动一个uwsgi进程(对于两个或三个mongo实例,没有--master):
    /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实例后正常的应用程序工作?


  • UPD1 :
    我试图理解问题,现在当我关闭一个mongo节点时出现连接异常时, self.__schedule_refresh() 的行为有所不同:
  • 对于一个过程:
  • 在此语句之前:rs_state有两个成员:活跃于up == True,活跃于up == False
  • 在此语句之后:rs_state有一个 Activity 成员up == True
  • 对于两个过程:
  • 在此语句之前:rs_state有两个成员:活跃于up == True,活跃于up == False
  • 此语句之后:rs_state有两个成员:活跃于up == True,活跃于up == 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)
    

    最佳答案

    尝试使用uwsgi --lazy-apps选项。 MongoReplicaSetClient产生一个副本集MonitorThread,并且该线程无法在uwsgi worker进程派生中幸存。 --lazy-apps将在每个工作进程中初始化pymongo MonitorThread。

    https://stackoverflow.com/questions/17534642/

    相关文章:

    c# - MongoDB + C# 驱动程序 + 查询元素数组,其中每个数组元素包含要查询的子文档

    mongodb - 结合 Neo4J 和 MongoDB : Consistency

    mongodb - 与 skip() 和 limit() 一起使用的 Distinct() 命令

    php - 为什么这种 mongo 排序在 PHP 中不起作用?

    node.js - 模型操作的 Sails.js 身份验证

    c# - 使用 MongoDB 的 C# 驱动程序进行多字段查询

    node.js - NodeJS ExpressJS PassportJS - 仅用于管理页面

    python - 有人知道 pymongo 中 2dsphere 索引的工作示例吗?

    php - mongodb:查找列的最高数值

    node.js - 是否可以将额外的参数传递给 Mongoose 更新回调