uWSGI 采用的是多进程模式。如果在 uWSGI 中运行的 Python 需要共享数据,可以使用第三方服务如 Redis/Memcached 等。如果数据量不大,还可以使用 uWSGI 提供的 缓存框架

uWSGI 有两套缓存框架。旧的一套叫做 WebCaching ,采用 cache 开头的配置项进行配置。我这里使用的是新的框架,采用 cache2 配置项进行配置。配置语法使用的是 key=value 语法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[uwsgi]
master = true
processes = 4
threads = 1
max-requests = 6000
chmod-socket = 664
buffer-size = 32768
thunder-lock = true
cache2 = name=default,items=20,blocksize=65536,keysize=60,bitmap=1
wsgi-file = manage.py
callable = flaskapp
uid = app
gid = app
venv = %dvenv
pidfile = %d%n.pid
http = 127.0.0.1:5001

在生产服务器中,开启 master 线程是必须的。uWSGI 在启动的时候会自动开启一个 sweeper 线程来处理过期。从下面的 log 可以看出这点:

1
2
3
4
5
6
7
WSGI app 0 (mountpoint='') ready in 2 seconds on interpreter 0x7f95aa818e00 pid: 54383 (default app)
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 54383)
spawned uWSGI worker 1 (pid: 54401, cores: 1)
spawned uWSGI worker 2 (pid: 54402, cores: 1)
cache sweeper thread enabled
spawned uWSGI http 1 (pid: 54403)

如果加入了 purge_lru 的配置,则上面那句 cache sweeper thread enabled 不会出现。

1
cache2 = name=default,items=20,blocksize=65536,keysize=60,bitmap=1,purge_lru=0

在文档中并没有找到 purge_lru 设置为 0 是否可以禁用缓存过期这个功能。倒是老版本的缓存设置中有一个 cache-no-expire 选项可以直接禁用缓存过期功能。

uWSGI 会自动插入一个名为 uwsgi模块 到运行在其下的 Python app 中,使用这个模块提供的 缓存接口 可以对 uWSGI 提供的缓存功能进行操作,有这样几个接口:

  • uwsgi.cache_get
  • uwsgi.cache_set
  • uwsgi.cache_update
  • uwsgi.cache_exists
  • uwsgi.cache_del
  • uwsgi.cache_clear

文档写得非常简略,从字面也很容易理解它们的意思。

为了方便使用,我封装了一个 Cache 类。这样在本地开发的时候直接使用一个 dict 模仿缓存,而在 uWSGI 环境中则可以直接使用缓存功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import pickle
class Cache(object):
"""
处理缓存
在 uWSGI 中运行的时候,使用 UWSGI 的缓存机制,实现进程间共享
否则,缓存到一个 dict 中
"""
def __init__(self):
self.__g = None
try:
self.__uwsgi = importlib.import_module('uwsgi')
print('USE CACHE UWSGI')
except:
self.__g = {}
print('USE CACHE MEMORY')
def _getuwsgicache(self, name):
"""
获取 UWSGI 缓存
:param name: 真实的 name,带有 regional 信息
:return: 序列化之后的 python 对象
"""
raw_value = self.__uwsgi.cache_get(name)
# print('_getuwsgicache:', raw_value)
if raw_value is not None:
return pickle.loads(raw_value, encoding='utf8')
return None
def _setuwsgicache(self, name, value):
"""
设置 UWSGI 缓存
:param name: 设置名称
:param value: 值
:return:
"""
if value is None:
self.__uwsgi.cache_del(name)
return
raw_value = pickle.dumps(value)
# print('_setuwsgicache:', raw_value)
if self.__uwsgi.cache_exists(name):
self.__uwsgi.cache_update(name, raw_value)
else:
self.__uwsgi.cache_set(name, raw_value)
def get(self, name):
if self.__g is None:
return self._getuwsgicache(name)
return self.__g.get(name, None)
def set(self, name, value):
if self.__g is None:
self._setuwsgicache(name, value)
else:
self.__g[name] = value

更一般的使用方式是在 uWSGI 配置中通过内部路由来使用缓存。这部分可以参考 The uWSGI Caching Cookbook

全文完

留言

2017-11-24
次访问