keystone代码概要分析及服务并行化

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

 

测试数据(很粗略的对比)

并行化之前,并发访问keystone以认证token,结果为6.65个请求每秒。

并行化之后为13个请求每秒

系统资源如下:

over

你可能感兴趣的:(keystone)