openstack采用了token认证的机制,各api的调用都会涉及到token的验证问题,使得keystone成为一个性能的瓶颈。
token的验证环节包括:验证请求中包含的token是否有效、过期,该token对应的用户组和用户id,对应的授权服务访问地址等。
性能瓶颈的解决-1:
由于openstack中的各api都是wsgi服务,并且都用到了keystoneclient提供的一个中间件(wsgi filter)auth_token,对应的文件位于:keystoneclient/middleware/auth_token.py。该中间件采用memcache来缓存token的相关信息到本地,从而减少各服务对keystone的直接访问,不过默认情况下缓存并未启用。为此,添加如下配置到nova.conf、cinder.conf…
[keystone_authtoken]
auth_uri = http://keystone_server:5000/
auth_host = keystone_server
auth_port = 35357
auth_protocol = http
admin_tenant_name = service
admin_user = nova
admin_password = password
memcache_servers = 127.0.0.1:11211
token_cache_time = 3600 #token本地缓存的失效时间设置为1个小时。
cache = true
auth_token中间件中,token认证的相关代码片段如下:
try:
token_id = cms.cms_hash_token(user_token)
cached = self._cache_get(token_id)
if cached:
return cached
if cms.is_ans1_token(user_token):
verified = self.verify_signed_token(user_token)
data = json.loads(verified)
else:
data = self.verify_uuid_token(user_token, retry)
self._cache_put(token_id, data)
return data
except Exception as e:
self.LOG.debug(‘Token validation failure.’, exc_info=True)
self._cache_store_invalid(user_token)
self.LOG.warn(“Authorization failed for token %s”, user_token)
raise InvalidUserToken(‘Token authorization failed’)
性能瓶颈的解决-2:keystone并行化
当前的keystone实现中并没有采用并行化的机制,keystone-all运行时分别发起两个进程、绑定到两个socket上,分别处理5000和35357端口上的请求。
#管理端口请求的处理
servers.append(create_server(CONF.config_file[0],
‘admin’,
CONF.bind_host,
int(CONF.admin_port)))
#业务端口请求的处理
servers.append(create_server(CONF.config_file[0],
‘main’,
CONF.bind_host,
int(CONF.public_port)))
def serve(*servers):
signal.signal(signal.SIGINT, sigint_handler)
for server in servers:
server.start()
keystone并行化的patch如下:
https://github.com/peterfeiner/keystone/commit/workers-for-grizzly.patch
大概的修改如下:
(1)引入了多线程下共享的socket
(2)根据配置选项works的大小,发起多个进程处理api的请求
代码修改之后,还需对keystone的配置做适当更新:
keystone默认的token存储后端为基于内存的k-v,范围在一个进程的空间内。并行化之后,多个进程需共享访问token的存储后端,这里采用memcache。修改keystone.conf,并安装memcache服务。
[token]
# driver = keystone.token.backends.memcache.Token