1

我正在实现一个处理针对邮件服务器的身份验证的 PAS 插件。实际上只实现了 DBMail。

我意识到,enumerateUsers每个请求都会多次调用 PAS 插件中的函数,并且需要我的插件为每个(后续)请求打开/关闭 SQL 连接。当然,这是非常昂贵的。

连接本身在一个 plone 工具中处理,该工具能够处理多个不同的邮件服务器并将enumerateUsers调用委托给代表已注册服务器的包装器对象。

我现在的问题是,我应该使用哪种缓存(OOBTree、Session?)来为重复枚举提供临时本地存储并避免后续的 SQL 连接?

另一个想法是,挂钩到第一次登录时发生的用户创建过程,外部用户发出问题并完全“本地化”用户。

第三个想法是,如果可能的话,将所需的数据存储在特定的成员中。

这里的最佳做法是什么?

4

1 回答 1

4

确实,我会缓存查询结果。您需要决定将结果缓存多长时间,如果长期存储,如何使缓存无效或检查更改。

这些决策没有最佳实践,因为它们完全取决于存储的数据类型和后端的 API。例如,如果它们支持某种新鲜度查询,那么您将永远存储所有内容并轮询后端以查看缓存是否需要更新。

你可以从一个简单的请求缓存开始;每个请求查询一次,将其存储请求对象上。随着请求对象被清理,您的缓存将在请求结束时自动失效,下一个请求将是一个干净的状态。

如果您的后端用户很少更改,您可以在本地缓存中缓存更长时间的信息。我会在插件上使用 volatile 属性。任何以 开头的属性_v_都会被持久性机制忽略。因此,存储在_v_volatile 属性中的任何内容都是线程本地的,并且仅在进程的生命周期内存在,重新启动服务器会自动清除这些。

至少您应该使用_v_volatile 属性来存储您的后端 SQL 连接。这样它们就可以在请求之间保持打开状态,并且可以重复使用。类似以下方法的方法会很好:

def _connection(self):
    # Return a backend connection
    if getattr(self, '_v_connection', None) is None:
        # Create connection here
        self._v_connection = yourdatabaseconnection
    return self._v_connection

您还可以在插件上使用持久属性来存储缓存。此缓存将提交给 ZODB 并在重新启动后持续存在。然后,您确实需要弄清楚如何使内容无效;存储时间戳并在旧时驱逐数据等。

您的缓存数据结构完全取决于您的应用程序需求。如果您不保留信息,那么字典(用户名-> 信息)可能就足够了。持久化缓存可以从使用 aOOBTree而不是字典中受益,因为它们减少了不同线程之间发生冲突的机会,并且在处理大量数据时效率更高。

无论您做什么,都不需要使用 Session。会话容易发生冲突,不能很好地扩展,并且无论如何都不是存储这种缓存的地方。

于 2012-09-20T09:06:08.247 回答