我怀疑这是可能的,但这是问题和建议的解决方案(提出的解决方案的可行性是这个问题的对象):
我有一些“全局数据”需要可用于所有请求。我将这些数据保存到Riak并使用Redis作为访问速度的缓存层(现在......)。数据被分成大约30个逻辑块,每个块大约为8 KB。
每个请求都需要读取这些8KB块中的4个,从而导致从Redis或Riak读入32KB数据。这是对任何特定于请求的数据的补充,这些数据也需要被读取(这是相当多的)。
假设每秒甚至3000个请求(这不是实时服务器,所以我没有实数,但3000ps是一个合理的假设,可能更多),这意味着从Addis或Riak的ADDITION转移到96KBps从应用程序逻辑中发出的其他调用已经不那么重要了。此外,Python正在解析这些8KB对象的JSON 每秒3000次。
所有这一切 - 特别是Python不得不反复反序列化数据 - 似乎是一种彻头彻尾的浪费,一个非常优雅的解决方案就是将反序列化的数据缓存在Python中的内存中本机对象中,当所有这些“静态”数据变得陈旧时,我可以定期刷新。一分钟(或几小时),而不是每秒3000次。
但我不知道这是否可行。您实际上需要一个“始终运行”的应用程序来缓存其内存中的任何数据。而且我知道在nginx + uwsgi + python组合中不是这种情况(与节点之类的东西相比) - 除非我知道,否则 python内存数据不会在所有请求中保留 非常错误。
不幸的是,这是一个我“继承”的系统,因此无法在基础技术方面做太多改动,也不足以了解nginx + uwsgi + python组合如何在启动Python方面发挥作用进程和持久的Python内存数据 - 这意味着我可能会错误地认为我的上述假设!
所以,直接建议这个解决方案是否有效 +对材料的引用可以帮助我理解nginx + uwsgi + python如何在启动新进程和内存分配方面起作用,这将有很大帮助。
P.S:
已经查看了nginx,uwsgi等的一些文档,但还没有完全理解我的用例的后果。希望现在在这方面取得一些进展
如果内存中的东西可以解决,我会扔掉Redis,因为我只缓存上面提到的静态数据。这使得进程内持久性内存中的Python缓存对我来说更具吸引力,减少了系统中的一个移动部分,并且每个请求至少减少了四次网络往返。
答案 0 :(得分:3)
您建议的内容并非直接可行。由于新进程可以在您的控件之外上下旋转,因此无法将本机Python数据保留在内存中。
然而,有几种方法可以解决这个问题。
通常,只需要一级键值存储即可。有时候,为值设置固定大小的缓冲区(可以直接用作str
/ bytes
/ bytearray
个对象;在那里需要struct
所需的任何其他内容序列化)就是你所需要的。在这种情况下,uWSGI的内置caching framework将照顾您需要的一切。
如果您需要更精确的控制,您可以查看如何在SharedArea
之上实现缓存并执行自定义操作。但是,我不推荐这样做。它基本上为您提供了与文件相同的API,并且仅使用文件的唯一真正优势是服务器将管理文件的生命周期;它适用于所有支持uWSGI的语言,甚至是那些不允许使用文件的语言;如果您以后需要,它可以更轻松地将您的自定义缓存迁移到分布式(多台计算机)缓存。我认为其中任何一个都与你无关。
获得平坦键值存储的另一种方法是使用Python的stdlib anydbm
,但没有固定大小的缓冲区。键值查找与pythonic一样:它看起来就像dict
,除了它备份到磁盘上的BDB(或类似)数据库,在内存中适当缓存,而不是存储在内存中的哈希表中。
如果您需要处理其他一些简单的类型 - 任何非常快/非腌制的内容,例如int
s - 您可能需要考虑shelve
。
如果您的结构足够严格,则可以将键值数据库用于顶级,但可以通过ctypes.Structure
访问值,或使用struct
进行de / serialize。但通常情况下,如果你能做到这一点,你也可以消除最高级别,此时你的整个事情只有一个Structure
或Array
。
此时,您可以使用普通文件进行存储 - mmap
(ctypes
)或open
和read
(对于{ {1}})。
或使用struct
Shared ctypes
Objects直接从共享内存区域访问multiprocessing
。
与此同时,如果你实际上并不是一直需要所有的缓存数据,而是每隔一段时间只需要一点点,那就是数据库的用途。同样,Structure
等可能就是您所需要的,但如果您有复杂的结构,请绘制ER图,将其转换为一组表,并使用类似MySQL的东西。
答案 1 :(得分:1)
你没有说回写这些数据,它是静态的吗?在这种情况下,解决方案很简单,我不知道所有“不可行”的响应是什么。
Uwsgi工作人员是始终在运行的应用程序。因此,数据绝对会在请求之间保持不变。您需要做的就是将东西存储在全局变量中,就是这样。并记住它是每个工人,并且工作人员会不时重新启动,因此您需要正确的加载/失效策略。
如果数据很少更新(很少在重新启动服务器时),您可以节省更多。只需在app构建期间创建对象。这样,它们将被创建一次,然后所有工作人员将分离主服务器,并重用相同的数据。当然,它是写时复制的,所以如果你更新它,你将失去内存的好处(如果python决定在gc运行期间压缩其内存,同样的事情会发生,所以它不是超级可预测的。)
答案 2 :(得分:0)
我自己从未尝试过,但是你可以使用uWSGI的SharedArea来完成你所追求的目标吗?
答案 3 :(得分:0)
“根据我的知识,所有请求都不会保留python内存数据,除非我非常错误。”
你错了。使用uwsgi的全部意义,例如,CGI机制是跨线程持久化数据并节省每次调用的初始化开销。您必须在processes = 1
文件中设置.ini
,或者,根据uwsgi的配置方式,它可能会代表您启动多个工作进程。记录env
并查找'wsgi.multiprocess': False
和'wsgi.multithread': True
,并且单个工作程序的所有uwsgi.core
个线程都应显示相同的数据。
您还可以使用内置的stats-server
查看有多少个工作进程以及每个进程下的“核心”线程。
这就是为什么uwsgi提供lock
和unlock
函数来操作多个线程的数据存储。
您可以通过在应用中添加/status
路径来轻松测试,该路由只转储全局数据对象的json表示,并在更新商店的操作后经常查看。