【问题标题】:Memcache client with connection pool for Python?带有 Python 连接池的 Memcache 客户端?
【发布时间】:2013-10-29 17:30:17
【问题描述】:

python-memcached memcache 客户端的编写方式是每个线程都有自己的连接。这使得 python-memcached 代码变得简单,这很好,但如果您的应用程序有数百或数千个线程(或者如果您运行大量应用程序),则会出现问题,因为您将很快用完 memcache 中的可用连接。

通常这种问题是通过使用连接池来解决的,而且我见过的 Java memcache 库确实实现了连接池。在阅读了各种 Python memcache 库的文档之后,似乎唯一提供连接池的是pylibmc,但它对我来说有两个问题:它不是纯 Python,而且似乎没有从游泳池。虽然不是纯 Python 可能不会破坏交易,但没有超时肯定是。也不清楚这些池将如何使用,例如dogpile.cache

最好我想找到一个纯 Python memcache 客户端,它带有可以与 dogpile.cache 一起使用的连接池,但我也愿意接受其他建议。不过,我宁愿避免更改应用程序逻辑(例如将所有 memcache 操作推入更少的后台线程)。

【问题讨论】:

    标签: python multithreading memcached connection-pooling


    【解决方案1】:

    一位同事提出了一个似乎对我们的用例来说效果很好的想法,所以在这里分享一下。基本思想是,您预先创建要使用的 memcache 客户端数量,将它们放入队列中,当您需要 memcache 客户端时,您从队列中拉出一个。由于 Queue.Queue get() 方法具有可选的超时参数,您还可以处理无法及时获取客户端的情况。您还需要处理 memcache 客户端中 threading.local 的使用。

    这是它在代码中的工作方式(请注意,我实际上并没有运行这个确切的版本,所以可能存在一些问题,但如果文字描述对您没有意义,这应该会让您知道):

    import Queue
    
    import memcache
    
    # See http://stackoverflow.com/questions/9539052/python-dynamically-changing-base-classes-at-runtime-how-to 
    # Don't inherit client from threading.local so that we can reuse clients in
    # different threads
    memcache.Client = type('Client', (object,), dict(memcache.Client.__dict__))
    # Client.__init__ references local, so need to replace that, too
    class Local(object): pass
    memcache.local = Local
    
    class PoolClient(object):
        '''Pool of memcache clients that has the same API as memcache.Client'''
        def __init__(self, pool_size, pool_timeout, *args, **kwargs):
            self.pool_timeout = pool_timeout
            self.queue = Queue.Queue()
            for _i in range(pool_size):
                self.queue.put(memcache.Client(*args, **kwargs))
    
        def __getattr__(self, name):
            return lambda *args, **kw: self._call_client_method(name, *args, **kw)
    
        def _call_client_method(self, name, *args, **kwargs):
            try:
                client = self.queue.get(timeout=self.pool_timeout)
            except Queue.Empty:
                return
    
            try:
                return getattr(client, name)(*args, **kwargs)
            finally:
                self.queue.put(client)
    

    【讨论】:

    • 我不知道为什么,但是使用池然后使用单个客户端会降低我的时间性能
    【解决方案2】:

    非常感谢@Heikki Toivenen 提供解决问题的想法!但是,我不确定如何准确调用 get() 方法以便在 PoolClient 中使用 memcache 客户端。使用任意名称直接调用 get() 方法会产生 AttributeError 或 MemcachedKeyNoneError。

    通过结合@Heikki Toivonen 和pylibmc 对问题的解决方案,我想出了以下问题的代码并在此处发布以方便将来的用户(我已调试此代码,应该可以运行):

    import Queue, memcache
    from contextlib import contextmanager
    
    memcache.Client = type('Client', (object,), dict(memcache.Client.__dict__))
    # Client.__init__ references local, so need to replace that, too
    class Local(object): pass
    memcache.local = Local
    
    class PoolClient(object):
        '''Pool of memcache clients that has the same API as memcache.Client'''
        def __init__(self, pool_size, pool_timeout, *args, **kwargs):
            self.pool_timeout = pool_timeout
            self.queue = Queue.Queue()
    
            for _i in range(pool_size):
                self.queue.put(memcache.Client(*args, **kwargs))
    
            print "pool_size:", pool_size, ", Queue_size:", self.queue.qsize()
    
        @contextmanager
        def reserve( self ):
            ''' Reference: http://sendapatch.se/projects/pylibmc/pooling.html#pylibmc.ClientPool'''
    
            client = self.queue.get(timeout=self.pool_timeout)
    
            try:
                yield client
            finally:            
                self.queue.put( client )
                print "Queue_size:", self.queue.qsize()
    
    
    # Intanlise an instance of PoolClient
    mc_client_pool = PoolClient( 5, 0, ['127.0.0.1:11211'] )
    
    # Use a memcache client from the pool of memcache client in your apps
    with mc_client_pool.reserve() as mc_client:
        #do your work here
    

    【讨论】:

      猜你喜欢
      • 2017-08-04
      • 1970-01-01
      • 1970-01-01
      • 2012-05-22
      • 2017-12-24
      • 1970-01-01
      • 2015-05-15
      • 2021-12-23
      • 2012-06-13
      相关资源
      最近更新 更多