用于django app的uWSGI + nginx避免了pylibmc多线程并发问题?

tim*_*irg 6 django multithreading nginx uwsgi

介绍

本周我遇到了这个非常有趣的问题,最好从一些事实开始:

  • pylibmc不是线程安全的Django的memcached的后端使用时,直接在外壳启动多个Django的实例时并发请求命中会崩溃.
  • 如果使用nginx + uWSGI进行部署,那么pylibmc的这个问题就会神奇地消失.
  • 如果你切换django缓存后端python-memcached,它也会解决这个问题,但这个问题与此无关.

从第一个事实开始,这是我如何重现这个pylibmc问题:

失败了 pylibmc

我有一个django应用程序,它执行了很多memcached读取和写入,并且有这个部署策略,我在shell中启动多个django进程,绑定到不同的端口(8001,8002),并使用nginx来进行平衡.

我对这两个django实例启动了两个单独的负载测试,使用locust,这就是发生的事情:

fail_proof

在上面的屏幕截图中,他们都崩溃并报告完全相同的问题,如下所示:

断言"ptr-> query_id == query_id +1"对于函数"memcached_get_by_key"失败,可能是"程序员错误,query_id没有递增.",在libmemcached/get.cc:107

uWSGI来救援

所以在上面的例子中,我们了解到对memcached via的多线程并发请求pylibmc可能会导致问题,这在某种程度上不会影响uWSGI多个工作进程.

为了证明这一点,我从uWSGI以下设置开始:

master          = true
processes       = 2
Run Code Online (Sandbox Code Playgroud)

这告诉uWSGI启动两个工作进程,然后告诉nginx服务器任何django静态文件,并路由非静态请求uWSGI,看看会发生什么.在服务器启动的情况下,我在localhost中对django启动了相同的蝗虫测试,并确保每秒有足够的请求来引发对memcached的并发请求,结果如下:

uwsgi_success

uWSGI控制台中,没有死工人进程的迹象,并且没有工作人员重新生成,但是查看屏幕截图的上半部分,肯定有并发请求(5.6 req/s).

这个问题

我非常好奇如何uWSGI让它消失,我无法在他们的文档中了解到,回顾一下,问题是:

uWSGI是如何管理工作进程的,因此多线程memcached请求不会导致django崩溃?

事实上,我甚至不确定这是uWSGI管理工作者进程以避免这个问题的方式,还是其他一些魔术随之而来uWSGI的伎俩,我在他们的文档中看到了一些名为memcached路由器的东西明白,这有关系吗?

Rub*_*arí 3

难道不是因为你实际上有两个由uWSGI管理的独立进程吗?由于您设置的是进程选项而不是工作人员选项,因此您实际上应该有多个uWSGI进程(由于您使用的配置,我假设一个主进程+两个工作进程)。每个进程都会有自己加载的 pylibmc,因此线程之间不存在状态共享(毕竟您还没有在 uWSGI 上配置线程)。