跳转到: 导航, 搜索

Swift/MemcachedConnPool

Memcached 连接池 - 行为和问题

在 Chuck Thier 提交之前的 Swift 代码库中,https://review.openstack.org/45134,使用 swift/common/memcached.py 模块的代码中,连接到 memcached 服务器的数量可能会无限制地增长。Chuck 的提交引入了连接池的概念,并配置了最大连接数。

这允许管理员计算他们的 memcached 服务器配置可以处理多少并发连接,并将这些连接分配给可用的节点和工作进程(通常是代理服务器)。

例如,如果管理员管理 4 台 memcached 服务器,每台服务器能够处理 64 个并发连接,并且有 4 个代理服务器节点,每个节点有 4 个代理服务器工作进程,那么 max_memcached_connections 参数将被设置为 4,允许每个节点上的工作进程拥有 4 个连接到 memcached 服务器的连接(4 个连接 * 4 个工作进程 * 4 个节点 = 64)。

管理员需要配置合适的 max_memcached_connections 参数值,使其在他们的环境中表现良好。

问题

正如 https://code.launchpad.net/bugs/1235027 所记录的那样,Chuck 的补丁存在一个问题,即创建的连接超过了配置的最大连接数,并且它们的创建没有限制。产生这些额外连接的原因在于代码中的一个假设,即在尝试“获取”用于使用的连接时遇到的任何 ExceptionTimeout 异常都意味着与 memcached 服务器的连接已损坏,并且必须创建一个新的连接。事实证明,代码不仅会计时 connect() 系统调用返回连接所需的时间,还会计时调用 greenlet 等待从池中检索连接的时间。由于它无条件地为稍后创建新连接创建一个占位符,当检索连接的时间过长时(即使所有与 memcache 服务器的连接都已创建),这些新连接就会无限制地增长。

正如 https://review.openstack.org/49739 提出的修复方案,通过简单地不限制连接检索的超时,从而消除了泄漏,连接创建仍然会超时。

然而,存在一个担忧,如果连接检索没有超时,那么当连接检索时间过长时,请求服务时间可能会急剧下降。

需要考虑的情景

似乎有三种情景我们需要考虑连接检索超时原因

  • 情景 #1:memcached 服务器速度慢,操作超时
在这种情况下,如果某个操作超时,则将关闭与 memcache 服务器的连接,并创建一个占位符,以便下一次连接尝试可以创建一个新的连接。如果给定服务器的错误达到配置的阈值,则该服务器将在配置的时间段内不被考虑,并且未来的操作将跳过此服务器。
但是,所有等待连接到此服务器的 greenlet 仍然会尝试在看到占位符时创建连接,并继续执行其操作,并在其操作随后由于超时而失败时移动到下一个服务器。
  • 有连接检索超时
对仅连接检索操作进行单独超时将导致在达到错误限制之前跳过该服务器,目前(在没有进一步的代码更改的情况下)。这可能会导致缓存无效,从而导致更多的后端 acct/cont/obj 操作。
  • 没有连接检索超时
通过完全删除超时,如 50031 中提出的,一旦达到错误限制(1 分钟内 10 个错误),memcached 服务器将不再在错误限制时间段内(1 分钟)被考虑。
  • 情景 #2:memcached 服务器速度慢,操作没有超时
如果 memcached 服务器速度慢,但速度不够慢以至于 memcache 操作超时,那么涉及该 memcached 服务器的请求的服务时间也会变慢。
  • 有连接检索超时
当连接检索上设置超时时,只有当有足够多的请求需要连接时,才会检测到慢速 memcached 服务器
  • 没有连接检索超时
当连接检索上没有设置超时时,将无法检测到慢速服务器,因此请求将继续变慢。
  • 情景 #3:memcached 服务器不慢,但等待连接的并发请求比可用连接多
如果有很多请求排队等待连接到 memcached 服务器,那么鉴于 memcache 键空间上的相当均匀分布,所有 memcache 服务器可能都面临相同的问题。如果键空间不均匀,那么就很难解决这个问题。