出现异常如下 RuntimeError: Second simultaneous read on fileno 8 detected. Unless you really know what you're doing, make sure that only one greenthread can read any particular socket. Consider using a pools.Pool. If you do know what you're doing and want to disable this error, call eventlet.debug.hub_multiple_reader_prevention(False)
2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake File "/usr/lib/python2.7/dist-packages/memcache.py", line 862, in get 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake return self._get('get', key) 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake File "/usr/lib/python2.7/dist-packages/memcache.py", line 846, in _get 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake return _unsafe_get() 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake File "/usr/lib/python2.7/dist-packages/memcache.py", line 830, in _unsafe_get 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake rkey, flags, rlen, = self._expectvalue(server) 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake File "/usr/lib/python2.7/dist-packages/memcache.py", line 955, in _expectvalue 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake line = server.readline() 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake File "/usr/lib/python2.7/dist-packages/memcache.py", line 1125, in readline 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake data = recv(4096) 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake File "/usr/local/lib/python2.7/dist-packages/eventlet/greenio.py", line 249, in recv 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake timeout_exc=socket.timeout("timed out")) 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake File "/usr/local/lib/python2.7/dist-packages/eventlet/hubs/__init__.py", line 117, in trampoline 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake listener = hub.add(hub.READ, fileno, current.switch) 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake File "/usr/local/lib/python2.7/dist-packages/eventlet/hubs/poll.py", line 27, in add 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake listener = super(Hub, self).add(evtype, fileno, cb) 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake File "/usr/local/lib/python2.7/dist-packages/eventlet/hubs/hub.py", line 126, in add 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake evtype, fileno, evtype)) 2013-03-08 18:27:27 17870 TRACE glance.store.chunkcache.fake RuntimeError: Second simultaneous read on fileno 8 detected. Unless you really know what you're doing, make sure that only one greenthread can read any particular socket. Consider using a pools.Pool. If you do know what you're doing and want to disable this error, call eventlet.debug.hub_multiple_reader_prevention(False)
出现问题时的大致模型如下
class CacheBackend(CacheBackendBase): ''' Cache in memcached servers. ''' def __init__(self): value_length = CONF.chunkcache_memcached_value_length servers = CONF.chunkcache_memcached_servers self.memcache = memcache.Client(servers, debug=1, server_max_value_length=value_length) @staticmethod def instance(): global CACHE_BACKEND if CACHE_BACKEND is None: CACHE_BACKEND = CacheBackend() return CACHE_BACKEND def get(self, key, default=None): result = self.memcache.get(str(key)) return result or default def exist(self, key): return self.get(str(key)) != None def set(self, key, value): result = self.memcache.set(str(key), value) if result == 0: raise exception.MemcacheSetError() return result def delete(self, key): if self.exist(key): result = self.memcache.delete(str(key)) if result == 0: raise exception.MemcacheDeleteError() return True def clear(self): # No need for clearing memcached. return True
经过同事交流,推测可能是因为fork之前有socket连接在或者是多个进程重用了一个socket导致,但是感觉都不太能讲得通,对这块确实不太了解,先记录下来解决方案,有谁了解的求解释~
下面是解决的模型,大致改动就是在每个set,get,delete处都new一个memcache client,
可以新建一个socket?不过看memcache模块,好像也是有socket缓存的啊,会去缓存中拿同个socket,
下面的disconnect_all加与不加都一样,不会出现问题,而且在上面的模块中加上disconnect_all再重试也不起作用,
实在无法理解,但是确实解决了问题,多次测试都未复现上述问题。
class CacheBackend(CacheBackendBase): ''' Cache in memcached servers. ''' def __init__(self): self.value_length = CONF.chunkcache_memcached_value_length self.servers = CONF.chunkcache_memcached_servers @staticmethod def instance(): global CACHE_BACKEND if CACHE_BACKEND is None: CACHE_BACKEND = CacheBackend() return CACHE_BACKEND def get(self, key, default=None): client = _connect(self.servers, self.value_length) result = client.get(str(key)) client.disconnect_all() return result or default def exist(self, key): return self.get(str(key)) != None def set(self, key, value): client = _connect(self.servers, self.value_length) result = client.set(str(key), value) client.disconnect_all() if result == 0: raise exception.MemcacheSetError() return result def delete(self, key): client = _connect(self.servers, self.value_length) if self.exist(key): result = client.delete(str(key)) if result == 0: raise exception.MemcacheDeleteError() client.disconnect_all() return True def clear(self): # No need for clearing memcached. return True def _connect(servers, value_length=chunkstore.Store.CHUNKSIZE): return memcache.Client(servers, debug=1, server_max_value_length=value_length)