backend = oslo_cache.memcache_pool
the backend is <oslo_cache.backends.memcache_pool.PooledMemcachedBackend object at 0x7f46bb3b2d68>
前面可以看到,如果.conf文件中的cache 组中的backend = oslo_cache.memcache_pool
那么得到的backend就是oslo_cache.backends.memcache_pool.PooledMemcachedBackend
然后,我又在代码中将backend.set这个方法打印出来:
the backend.set is
<bound method GenericMemcachedBackend.set of
<oslo_cache.backends.memcache_pool.PooledMemcachedBackend object at 0x7fad77e497b8>>
可以看到backend.set是GenericMemcachedBackend.set中的方法,在dogpile/cache/backends/memcached.py文件中定义的
GenericMemcachedBackend.set中调用的是self.client.set(key, value, **self.set_arguments),而self.client又是一个属性method
oslo_cache.backends.memcache_pool.PooledMemcachedBackend在oslo_cache/backends/memcache_pool.py中定义的,继承的是GenericMemcachedBackend,所有可以调用其中的set方法。这个类又对client属性方法进行二次重载
the backend.client is
<oslo_cache.backends.memcache_pool.ClientProxy object at 0x7fce5f48a710>
backend.client返回的是ClientProxy类对象
在ClientProxy类中,传入的是oslo_cache._memcache_pool.MemcacheClientPool参数
class ClientProxy(object):
def __init__(self, client_pool):
self.client_pool = client_pool
def _run_method(self, __name, *args, **kwargs):
with self.client_pool.acquire() as client:
return getattr(client, __name)(*args, **kwargs)
def __getattr__(self, name):
return functools.partial(self._run_method, name)
这个函数暂时没有看懂,应该在调用ClientProxy(self.client_pool)的时候,直接调用__getattr__(self, name)函数吧,然后把client_pool中的conn对象直接返回了,这个时候,PooledMemcachedBackend.client就直接是client_pool中的conn的了,就可以直接调用其中的set、get等方法了!
现在的应用场景是想打开memcached服务的SALA安全认证,前面已经说了如何开启这个SALA安全认证的!
现在的想法是:
由于oslo_cache/_memcache_pool.py文件中的_MemcacheClient类继承的是memcache类
想着能不能创建一个_bmemcacge_pool.py文件,在这个文件中建立一个_bMemcacheClient类,让这个类继承bmemcache类
然后在memcache_pool.py文件中,用conf.sala_enable来判断调用哪个类!
现在在centos环境下进行验证:
把原来的demo代码copy到centos环境下进行验证,由于该环境没有安装openstack,因此并没有对应的库,需要执行:
pip install oslo_cache
执行:pip install python-memcached
安装memcache
执行demo之前,需要确认一下memcached服务是否已经开启了
netstat -an |grep 11211
如果没有开启的话,则执行命令
cd /opt/system/portaluser/memcached/bin
bash start
然后执行 python app.py
执行结果如下:
[jorh@localhost cache]$ python app.py
the caching is True and the cache_time is 7200
_get_default_cache_region
<dogpile.cache.region.CacheRegion object at 0x7fd9f951fd50>
_CACHE is <cacheutils.CacheClient instance at 0x7fda0790bc20>
value is none!
Traceback (most recent call last):
File "app.py", line 80, in <module>
value = id_to_glance_id(context,image_id)
File "app.py", line 26, in memorizer
val = _CACHE.set(key,value)
File "/home/jorh/cache/cacheutils.py", line 78, in set
return self.region.set(key,value)
File "/home/jorh/.local/lib/python2.7/site-packages/dogpile/cache/region.py", line 1112, in set
self.backend.set(key, self._value(value))
File "/home/jorh/.local/lib/python2.7/site-packages/dogpile/cache/backends/memcached.py", line 179, in set
self.client.set(key, value, **self.set_arguments)
File "/home/jorh/.local/lib/python2.7/site-packages/oslo_cache/backends/memcache_pool.py", line 32, in _run_method
return getattr(client, __name)(*args, **kwargs)
File "/home/jorh/.local/lib/python2.7/site-packages/memcache.py", line 727, in set
return self._set("set", key, val, time, min_compress_len, noreply)
File "/home/jorh/.local/lib/python2.7/site-packages/memcache.py", line 1016, in _set
server, key = self._get_server(key)
File "/home/jorh/.local/lib/python2.7/site-packages/memcache.py", line 433, in _get_server
if server.connect():
File "/home/jorh/.local/lib/python2.7/site-packages/memcache.py", line 1381, in connect
if self._get_socket():
File "/home/jorh/.local/lib/python2.7/site-packages/memcache.py", line 1413, in _get_socket
self.flush()
File "/home/jorh/.local/lib/python2.7/site-packages/memcache.py", line 1488, in flush
self.expect(b'OK')
File "/home/jorh/.local/lib/python2.7/site-packages/memcache.py", line 1463, in expect
line = self.readline(raise_exception)
File "/home/jorh/.local/lib/python2.7/site-packages/memcache.py", line 1449, in readline
data = recv(4096)
socket.timeout: timed out
可以看到上面没有读出相应的值的,并且出现错误!
如果关闭SASL之后,再执行代码会出现什么情况呢!
首先说明一下,如何关闭memcached的SALA认证,将start文件sudo ./memcached -d -f 1.1 -L -S -m 2048 -u os-user中的-S去掉,然后再将memcached这个服务重启一下就行了!有可能不会成功,这个时候,可能需要重启一下电脑才行!
执行python app.py命令,发现可以正常读出数据
[jorh@localhost cache]$ python app.py
the caching is True and the cache_time is 7200
_get_default_cache_region
<dogpile.cache.region.CacheRegion object at 0x7fc649207d50>
_CACHE is <cacheutils.CacheClient instance at 0x7fc6575f3c20>
value is none!
the set return value is None
the value is this is image_id:1234
_get_default_cache_region
<dogpile.cache.region.CacheRegion object at 0x7fc64719ca10>
cl.add return value: val = 90
key = mykey
VAL1 is 90
VAL2 is jihhhhsnna
_get_default_cache_region
<dogpile.cache.region.CacheRegion object at 0x7fc649207dd0>
cl1 VAL3 is jihhhhsnna
_get_default_cache_region
<dogpile.cache.region.CacheRegion object at 0x7fc6471a6250>
key = mykey
value2 is jihhhhsnna
走到这里,就非常高兴了,说明可以正常开启和关闭带有SALA认证的memcached服务
下面,我们将修改代码,让oslo_cache模块支持开启SALA认证的memcached服务!
首先修改cache.conf文件,里面增加如下的三个参数
memcache_sasl_enable = true
memcache_usrname = username
memcache_password = Password
之后,通过位于oslo_cache/core.py文件中的configure(conf)函数,将conf中的参数进行配置:
在configure函数中添加如下的内容(下面内容在oslo_cache/_opts.py文件中):
FILE_OPTIONS = {
'cache': [
...........
cfg.BoolOpt('memcache_sasl_enable',default=False,
help='Enable the SASL(Simple Authentication and Security Layer) if the sasl_enable is true, '
'else disable!'),
cfg.StrOpt('memcache_usrname',default='usrname',
help='the user name for the SASL'),
cfg.StrOpt('memcache_password',default='password',
help="the user's password for SASL!"),
],
}
之后,configure函数会将cache组中的所有配置项进行注册,然后就可以通过CONF.cache.SALA_enable, CONF.cache.os_user以及CONF.cache.passwd来调用相应的参数!
之后,会创建一个region对象,然后将这个CONF和region进行结合
region = cache.create_region()
cache.configure_cache_region(CONF,region)
下面我们看一下configure_cache_region(CONF,region)这个函数是如何修改(oslo_cache/core.py文件中):
在这个函数中主要调用两个函数:
config_dict = _build_cache_config(conf)
region.configure_from_config(config_dict,'%s.' % conf.cache.config_prefix)
第一个函数主要用于配置config_dict这个字典参数。
然后修改并添加如下的代码:
'''
在括号内,添加如下的三个关键字,'sala_enable', 'os_user', 'passwd'
'''
for arg in ('dead_retry', 'socket_timeout', 'pool_maxsize',
'pool_unused_timeout', 'pool_connection_get_timeout',
'sasl_enable', 'usrname', 'password'):
value = getattr(conf.cache, 'memcache_' + arg)
conf_dict['%s.arguments.%s' % (prefix, arg)] = value
后面就会将这个conf_dict返回,然后我们的三个参数就在这个字典中了!
虽然现在看起来字典中的key = oslo.cache.arguments,不知道为什么一定要加上这个prefix
后面当这个字典传到backend类中的时候,会将字典中key中的这个前缀去掉(感觉上面多此一举!)
region.configure_from_config这个函数主要用来确定存储后端backend的,这里不用进行改动!
现在工作已经完成一半了,因为我们已经得到了我们想要的参数,并且将这个参数放到字典中,后面只要能得到这个字典,我们就可以得到我们需要的这三个参数!
因为我们这里设置的后端存储是:backend=oslo_cache.memcache_pool,上面也有打印相应的参数实际对应的类对象实例!
因此对应的方法是:oslo_cache.backends.memcache_pool.PooledMemcachedBackend
下面看一下PooledMemcachedBackend中是如何调用的,可以看如下的代码:
from oslo_cache import _bmemcache_pool
def __init__(self, arguments):
#初始化父类中的__init__函数,后面可以直接调用父类中的属性
super(PooledMemcachedBackend, self).__init__(arguments)
if arguments.get()
self.client_pool = _memcache_pool.MemcacheClientPool(
self.url,#这个参数是在GenericMemcachedBackend中__init__的时候得到的!
arguments={
'dead_retry': arguments.get('dead_retry', 5 * 60),
'socket_timeout': arguments.get('socket_timeout', 3.0),
'server_max_value_length':
arguments.get('server_max_value_length'),
},
maxsize=arguments.get('pool_maxsize', 10),
unused_timeout=arguments.get('pool_unused_timeout', 60),
conn_get_timeout=arguments.get('pool_connection_get_timeout', 10),
)
那么,现在我们只需要重新构造一个类,让他继承bmemcached就可以了,然后根据arguments中的sala_enable是否为True来判断执行那个flow!
下面修改方案:增加一个_bmemcache_pool.py文件,在里面导入bmemcached模块,之后所有的代码都和_memcache_pool.py中的一样,只不过其中的类前面都添加b字符,以示区分;
def __init__(self, arguments):
#初始化父类中的__init__函数,后面可以直接调用父类中的属性
super(PooledMemcachedBackend, self).__init__(arguments)
if arguments.get('sala_enable'):
self.client_pool = _bmemcache_pool.bMemcacheClientPool(
self.url, # 这个参数是在GenericMemcachedBackend中__init__的时候得到的!
username=arguments.get('os_name'),
password=arguments.get('passwd'),
arguments={
'socket_timeout': arguments.get('socket_timeout', 3.0),
},
maxsize=arguments.get('pool_maxsize', 10),
unused_timeout=arguments.get('pool_unused_timeout', 60),
conn_get_timeout=arguments.get('pool_connection_get_timeout', 10),
)
else:
self.client_pool = _memcache_pool.MemcacheClientPool(
self.url,#这个参数是在GenericMemcachedBackend中__init__的时候得到的!
arguments={
'dead_retry': arguments.get('dead_retry', 5 * 60),
'socket_timeout': arguments.get('socket_timeout', 3.0),
'server_max_value_length':
arguments.get('server_max_value_length'),
},
maxsize=arguments.get('pool_maxsize', 10),
unused_timeout=arguments.get('pool_unused_timeout', 60),
conn_get_timeout=arguments.get('pool_connection_get_timeout', 10),
)
_bmemcache_pool.py文件的改动如下:
import bmemcached
.......
'''
class _MemcacheClient类改为class _bMemcacheClient,继承bmemcached.Client
'''
class _bMemcacheClient(bmemcached.Client): #
...........
............
#将class ConnectionPool(queue.Queue)改为class bConnectionPool(queue.Queue)
class bConnectionPool(queue.Queue):
...............
#将class MemcacheClientPool改为class bMemcacheClientPool,并继承bConnectionPool
class bMemcacheClientPool(bConnectionPool):
#在这个类中添加两个变量
def __init__(self, urls,username,password, arguments, **kwargs):
# super() cannot be used here because Queue in stdlib is an
# old-style class
ConnectionPool.__init__(self, **kwargs)
self.urls = urls
#添加如下两个变量!
self.username = username
self.password = password
self._arguments = arguments
# NOTE(morganfainberg): The host objects expect an int for the
# deaduntil value. Initialize this at 0 for each host with 0 indicating
# the host is not dead.
self._hosts_deaduntil = [0] * len(urls)
def _create_connection(self): #这里返回bmemcached对象!
return _bMemcacheClient(self.urls, self.username,self.password,
**self._arguments)
def _get(self):
# super() cannot be used here because Queue in stdlib is an
# old-style class
conn = bConnectionPool._get(self)
..........
bConnectionPool._put(self, conn)
raise
return conn
def _put(self, conn):
try:
......
bConnectionPool._put(self, conn)
这样整个代码就改动完成了,下面开始正式测试流程!
测试出现如下的错误:
status = 32
Traceback (most recent call last):
File "app.py", line 85, in <module>
myfun2('mykey')
File "app.py", line 73, in myfun2
cl2.set(key,'jihhhhsnna')
File "/home/jorh/cache/cacheutils.py", line 82, in set
return self.region.set(key,value)
File "/home/jorh/.local/lib/python2.7/site-packages/dogpile/cache/region.py", line 1112, in set
self.backend.set(key, self._value(value))
File "/home/jorh/.local/lib/python2.7/site-packages/dogpile/cache/backends/memcached.py", line 179, in set
self.client.set(key, value, **self.set_arguments)
File "/home/jorh/.local/lib/python2.7/site-packages/oslo_cache/backends/memcache_pool.py", line 33, in _run_method
print("getattr(client, __name)(*args, **kwargs) = %s"%(getattr(client, __name)(*args, **kwargs)))
File "/usr/lib/python2.7/site-packages/bmemcached/client/replicating.py", line 112, in set
returns.append(server.set(key, value, time, compress_level=compress_level))
File "/usr/lib/python2.7/site-packages/bmemcached/protocol.py", line 612, in set
return self._set_add_replace('set', key, value, time, compress_level=compress_level)
File "/usr/lib/python2.7/site-packages/bmemcached/protocol.py", line 591, in _set_add_replace
raise MemcachedException('Code: %d Message: %s' % (status, extra_content), status)
bmemcached.exceptions.MemcachedException
现在发现在关闭SALA的时候,执行是可以的,打开SALA之后,就出现上述的错误,现在的可能原因是username和password参数可能传入不对!
在_bmemcache_pool.py文件中,直接将__init__函数中的self._os-name和self._password设置为对应的值之后,发现读取正常了,那么出现上述现象的原因就是传入的认证参数不对!
添加代码链接:https://download.csdn.net/download/qq_33970713/12558596