在 Python+uWSGI 应用中使用缓存
uWSGI 采用的是多进程模式。如果在 uWSGI 中运行的 Python 需要共享数据,可以使用第三方服务如 Redis/Memcached 等。如果数据量不大,还可以使用 uWSGI 提供的 缓存框架 。
uWSGI 有两套缓存框架。旧的一套叫做 WebCaching ,采用 cache 开头的配置项进行配置。我这里使用的是新的框架,采用 cache2
配置项进行配置。配置语法使用的是 key=value
语法。
1[uwsgi]
2
3master = true
4processes = 4
5threads = 1
6max-requests = 6000
7chmod-socket = 664
8buffer-size = 32768
9thunder-lock = true
10cache2 = name=default,items=20,blocksize=65536,keysize=60,bitmap=1
11
12wsgi-file = manage.py
13callable = flaskapp
14uid = app
15gid = app
16
17venv = %dvenv
18pidfile = %d%n.pid
19http = 127.0.0.1:5001
在生产服务器中,开启 master
线程是必须的。uWSGI 在启动的时候会自动开启一个 sweeper
线程来处理过期。从下面的 log 可以看出这点:
1WSGI app 0 (mountpoint='') ready in 2 seconds on interpreter 0x7f95aa818e00 pid: 54383 (default app)
2*** uWSGI is running in multiple interpreter mode ***
3spawned uWSGI master process (pid: 54383)
4spawned uWSGI worker 1 (pid: 54401, cores: 1)
5spawned uWSGI worker 2 (pid: 54402, cores: 1)
6cache sweeper thread enabled
7spawned uWSGI http 1 (pid: 54403)
如果加入了 purge_lru
的配置,则上面那句 cache sweeper thread enabled
不会出现。
1cache2 = 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 环境中则可以直接使用缓存功能。
1import pickle
2
3class Cache(object):
4 """
5 处理缓存
6 在 uWSGI 中运行的时候,使用 UWSGI 的缓存机制,实现进程间共享
7 否则,缓存到一个 dict 中
8 """
9 def __init__(self):
10 self.__g = None
11 try:
12 self.__uwsgi = importlib.import_module('uwsgi')
13 print('USE CACHE UWSGI')
14 except:
15 self.__g = {}
16 print('USE CACHE MEMORY')
17
18 def _getuwsgicache(self, name):
19 """
20 获取 UWSGI 缓存
21 :param name: 真实的 name,带有 regional 信息
22 :return: 序列化之后的 python 对象
23 """
24 raw_value = self.__uwsgi.cache_get(name)
25 # print('_getuwsgicache:', raw_value)
26 if raw_value is not None:
27 return pickle.loads(raw_value, encoding='utf8')
28 return None
29
30 def _setuwsgicache(self, name, value):
31 """
32 设置 UWSGI 缓存
33 :param name: 设置名称
34 :param value: 值
35 :return:
36 """
37 if value is None:
38 self.__uwsgi.cache_del(name)
39 return
40 raw_value = pickle.dumps(value)
41 # print('_setuwsgicache:', raw_value)
42 if self.__uwsgi.cache_exists(name):
43 self.__uwsgi.cache_update(name, raw_value)
44 else:
45 self.__uwsgi.cache_set(name, raw_value)
46
47 def get(self, name):
48 if self.__g is None:
49 return self._getuwsgicache(name)
50 return self.__g.get(name, None)
51
52 def set(self, name, value):
53 if self.__g is None:
54 self._setuwsgicache(name, value)
55 else:
56 self.__g[name] = value
更一般的使用方式是在 uWSGI 配置中通过内部路由来使用缓存。这部分可以参考 The uWSGI Caching Cookbook 。
全文完
- 文章ID:2659
- 原文作者:zrong
- 原文链接:https://blog.zengrong.net/post/use-cache-in-uwsgi-with-python/
- 版权声明:本作品采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可,非商业转载请注明出处(原文作者,原文链接),商业转载请联系作者获得授权。