一、背景
Kerberos 是一种网络认证协议,其设计目标是通过密钥系统为客户端、服务器端的应用程序提供强大的认证服务。 作为一种可信任的第三方认证服务,Kerberos是通过传统的密码技术(如:共享密钥)执行认证服务的,被Client和Server同时信任。KDC是对该协议中第三方认证服务的一种具体实现,一直以来都是美团点评数据平台的核心服务之一,在Hive、HDFS、YARN等开源组件的权限认证方面有着广泛的应用。该服务将认证的密钥事先部署在集群的节点上,集群或者新节点启动时,相应节点使用密钥得到认证。只有被认证过节点才能被集群所接纳。企图冒充的节点由于没有相关密钥信息,无法与集群内部的节点通信,从而有效的确保了数据的安全性、节点的可信赖性。
但随着平台业务的快速增长,当前线上KDC的处理能力不足和不能可靠监控的问题被凸显的日益严重:线上单台KDC服务器最大承受QPS是多少?哪台KDC的服务即将出现压力过大的问题?为什么机器的资源非常空闲,KDC的压力却会过大?如何优化?优化后瓶颈在哪儿?如何保证监控指标的全面性、可靠性和准确性?这都是本文需要回答的问题;从本次优化工作达成的最终结果上来看,单台服务器每秒的处理性能提升16倍左右,另外通过共享内存的方式设计了一个获取KDC各项核心指标的接口,使得服务的可用性进一步提升。
为方便大家,表1总结并解释了本文中后续会涉及到一些专业名词的简称。
表1 相关名字解释
名词缩写名词解释
BDBBerkeley DB,是一种简单、小巧、可靠、高性能的数据库
LDAP是一种轻量目录访问协议,英文全称是Lightweight Directory Access Protocol,一般都简称为LDAP
AS全称Authentication Service ,KDC中负责认证服务
KDCKey Distribution Center,密钥分配中心,KDC在kerberos中通常提供AS和TGS两种服务
TGTClient在从KDC那边获得Ticket之前,需要先获得这个Ticket的认购权证,这个认购权证在Kerberos中被称为TGT:Ticket Granting Ticket
TGS全称Ticket-Granting Service ,KDC中负责授予票据服务
PREAUTHKDC防止暴力、多次尝试破解密码的一种机制
IDC互联网数据中心
图1为美团点评数据平台KDC当前服务架构,目前整个KDC服务部署在同一个IDC。
二、KDC原理介绍
Client、 KDC和Server在认证阶段主要有Client和KDC的AS、Client和KDC的TGS以及Client和Server的交互三个过程,下文将详细介绍三个过程的交互,其中图2中的步骤1和2、3和4、5和6分别对应下文的A、B、C三部分。
A:Client和AS的交互
用户以明文的形式发送自己的信息、以及想要申请的TGT Principal(默认为KDC的TGT:krbtgt/REALM@REALM)等信息给AS服务。
AS服务验证该用户信息存在数据库中后,给客户端返回两大块信息:
1)使用用户的密钥加密其申请的TGT和一个Session Key返回用户,用户得到加密信息后,使用自己密钥解密得到其申请的TGT和Session Key(后续都简称 SKCandK)。
2)以KDC自身密钥加密用户申请的TGT、SKCandK、用户自己信息等;简称{TGT}Ktgs,该部分信息被Client保存在本地。
B:Client和TGS的交互
Client访问TGS获取访问网路中某一Server的ticket请求。Client端会把第一部分中保存在本地的{TGT}Ktgs和用SKCandK加密的客户端信息发送KDC的TGS模块。
TGS收到请求后,检查请求Server存在数据库中后,用自己的密钥解密得到TGT中的SKCandK,然后便可以解密得到用户的信息并验证其合法性;通过后,TGS会生成一个新的Session Key,简称SKCandS;同时返回两部分信息:
1)用SKCandK加密的SKCandS、能够访问Service的ticket等信息。
2)用Service密钥加密的Client info、SKCandS等信息,简称{ TService}KService。
C:Client和Server的交互
Client拿到访问Service的ticket后,向Service发起请求,同时将两部分信息发送给Server:1)通过SKCandS加密的Client info等信息。2)第二部分TGS返回客户端的{ TService }KService。
Server端收到Client的请求信息后,用自己的密钥解密获取到TService信息,就能够解密SKCandS加密的客户端信息,和TService中的客户端信息进行对比,通过后,整个KDC认证过程结束,Client和Service进行正常的服务通信。
三、主要优化工作
通过对KDC原理的分析,很容易判断只有前两部分才可能直接给KDC服务带来压力,因此本文涉及到的工作都将围绕上一部分的前两个环节展开分析。本次优化工作采用Grinder这一开源压测工具,分别对AS、TGS两个请求过程,采用相同机型(保证硬件的一致性)在不同场景下进行了压力测试。
优化之前,线上KDC服务启动的单进程;为最低风险的完成美团和点评数据的融合,KDC中keytab都开启了PREAUTH属性;承载KDC服务的部分服务器没有做RAID。KDC服务出现故障时,机器整体资源空闲,怀疑是单进程的处理能力达到上限;PREAUTH属性进一步保证提升了KDC服务的安全性,但可能带来一定的性能开销;如果线上服务器只加载了少量的keytab信息,那么没有被加载到内存的数据必然读取磁盘,从而带来一定的IO损耗。因此本文中,对以下三个条件进行变动,分别进行了测试:
对承载KDC服务的物理机型是否做RAID10。
请求的keytab在库中是否带有PRAUTH属性。
KDC是否启动多进程(多进程设置数目和物理机核数一致)。(实际测试工作中进行了多次测试)。
A:Client和AS交互过程的压测
表2为AS压测的一组平均水平的测试数据,使用的物理机有40核,因此多进程测试启动40个进程。
表2 Client端和KDC 压测AS的处理能力,单位为:成功处理请求个数/s
AS请求条件测试结果
单进程,有PREAUTH,不做RAID49
单进程,有PREAUTH,做RAID1053
单进程,无PREAUTH,不做RAID100
单进程,无PREAUTH,做RAID10104
40进程,有PREAUTH,不做RAID115
40进程,有PREAUTH,做RAID10990
40进程,无PREAUTH,不做RAID2000
40进程,无PREAUTH,做RAID101985
分析表2中的数据,很容易提出如下问题从而需要进一步探索:
比较表2中第一行和第二行、第三行和第四行,主机做不做RAID为什么对结果几乎无影响?
该四组(测试结果为49、53、100和104所在表2中的行)数据均在达到处理能力上限一段时间后产生认证失败,分析机器的性能数据,内存、网卡、磁盘资源均没有成为系统的瓶颈,CPU资源除了某个CPU偶尔被打满,其他均很空闲。分析客户端和服务端的认证日志,服务端未见明显异常,但是客户端发现大量的Socket Timeout错误(测试设置的Socket超时时间为30s)。由于测试过程中,客户端输出的压力始终大于KDC的最大处理能力,导致KDC端的AS始终处于满负荷状态,暂时处理不了的请求必然导致排队;当排队的请求等待时间超过设置的30s后便会开始超时从而认证出错,且伴随机器某一CPU被打满(如图3)。 显然KDC单进程服务的处理能力已经达到瓶颈且瓶颈存在单核CPU的处理能力,从而决定向多进程方向进行优化测试。
图4为本次压力测试的一个通用模型,假设KDC单位时间内的最大处理能力是A,来自客户端的请求速率稳定为B且 B>A ;图中黄色区域为排队的请求数,当某一请求排队超过30s,便会导致Socket Timedout错误。
比较表2中第1和3行、第2和4行、第7和8行相比,为什么有PREAUTH属性的认证QPS大致是无该属性处理能力的一半?
如果Client的keytab在KDC的库中不带有PREAUTH这一属性,Client发送请求,KDC的AS模块验证其合法性之后返回正确的结果;整个过程只需要两次建立链接进行交互便可完成。如果带有PREAUTH属性,意味着该keytab的认证启动了Kerberos 5协议中的 pre-authentication概念:当AS模块收到Client的请求信息后;故意给Client返回一个错误的请求包,Client会“领悟到”这是KDC的AS端需要进行提前认证;从而Client获取自己服务器的时间戳并用自己的密钥加密发送KDC,KDC解密后和自身所在服务器的时间进行对比,如果误差在能容忍的范围内;返回给Client正确的TGT响应包;过程如图5所示:
根据对问题2的分析,表2中第5和7行的值的比例应该近似为1:2,为什么第5行的值只有115,结果和理论差距如此之大?
KDC的库中对客户端的keytab开启PREAUTH属性,客户端每认证一次,KDC需要将该次认证的时间戳等信息写到本次磁盘的BDB数据库的Log中;而关闭PREAUTH属性后,每次认证只需要从库中读取数据,只要给BDB数据库分配的内存足够大,就可以最大程度的减少和本次磁盘的交互。KDC40进程且开启PRAUTH,其AS处理能力的QPS只有115,分析机器性能的相关指标,发现瓶颈果然是单盘的IO,如图6所示。使用BDB提供的工具,查看美团点评数据平台KDC服务的BDB缓存命中率为99%,如图7所示。
KDC AS处理能力在多进程做RAID条件下,有无preauth属性,KDC服务是否有瓶颈?如果有在哪里?
经多次实验,KDC的AS处理能力受目前物理机CPU处理能力的限制,图8为有PREAUTH属性的CPU使用情况截图,无PREAUTH结果一致。
B:Client和TGS交互过程的压测
表3为TGS压测的一组平均水平的测试数据。
表3 Client端和KDC 压测TGS的处理能力,单位为:成功处理请求个数/s
TGS请求条件测试结果
单进程,有PREAUTH,不做RAID63
单进程,有PREAUTH,做RAID1058
单进程,无PREAUTH,不做RAID66
单进程,无PREAUTH,做RAID1061
40进程,有PREAUTH,不做RAID1303
40进程,有PREAUTH,做RAID101342
40进程,无PREAUTH,不做RAID1347
40进程,无PREAUTH,做RAID101339
分析表3中的数据,可以发现KDC对TGS请求的处理能力和主机是否做RAID无关,结合KDC中TGS的请求原理,就较容易理解在BDB缓存命中率足够高的条件下,TGS的请求不需要和本次磁盘交互;进一步做实验,也充分验证了这一点,机器的磁盘IO在整个测试过程中,没有大的变化,如图9所示,操作系统本身偶尔产生的IO完全构不成KDC的服务瓶颈。KDC单进程多进程的对比,其处理瓶颈和AS一致,均受到CPU处理能力的限制(单进程打满某一CPU,多进程几乎占用整台机器的CPU资源)。从Kerberos的设计原理分析,很容易理解,无论KDC库中的keytab是否带有PREAUTH属性,对TGS的处理逻辑几乎没有影响,压测的数据结果从实际角度验证了这一点。
C:其他问题
Client和KDC的交互,支持TCP和UDP两种协议。在网络环境良好的情况下,两种协议的KDC的测试结果理论上和实际中几乎一致。但是在原生代码中,使用TCP协议,在客户端给KDC造成一定压力持续6s左右,客户端开始认证出错,在远未达到超时时限的情况下,Client出现了"socket reset"类的错误。KDC查看内核日志,发现大量"possible SYN flooding on port 8089(KDC的服务端口). Sending cookies",且通过netstat -s发现机器的xxxx times the listen queue of a socket overflowed异常增高,种种现象表明可能是服务端的半连接队列、全连接队列中的一个或者全部被打满。主要原理如图10所示:
发现KDC服务所在服务器:半队列/proc/sys/net/ipv4/tcp_max_syn_backlog为2048;
全队列:1)系统参数/proc/sys/net/core/somaxconn=65535,查看代码listen()函数的传入值为5!
故而判断TCP的瓶颈在于全队列,因此目标为将listen函数的第二个backlog参数变成可控可传入。
四、KDC可监控的设计和实现
开源社区对Kerberos实现的KDC完全没有对外暴露可监控的接口,最初线上的场景主要通过检索Log进行相关指标的监控,在统计服务QPS、各种错误的监控等方面,存在准确准确监控难的尴尬局面。为了实现对KDC准确、较全面的监控,对KDC进行了二次开发,设计一个获取监控指标的接口。对监控的设计,主要从以下三个方面进行了考虑和设计。
设计上的权衡
监控的设计无论在什么场景下,都应该尽可能的不去或者最小程度的影响线上的服务,本文最终采用建立一块共享内存的方式,记录各个KDC进程的打点信息,实现的架构如图11所示。每个KDC进程对应共享内存中的一块区域,通过n个数组来存储KDC n个进程的服务指标:当某个KDC进程处理一个请求后,该请求对监控指标的影响会直接打点更新到其对应的Slot 数组中。更新的过程不受锁等待更新的影响,KDC对监控打点的调用仅仅是内存块中的更新,对服务的影响几乎可以忽略不计。相比其他方式,在实现上也更加简单、易理解。
记录每个KDC进程的服务情况,便于准确查看每个进程的对请求的处理情况,有助于定位问题多种情况下出现的异常,缩短故障的定位时间。例如:能够准确的反应出每个进程的请求分布是否均匀、请求处理出现异常能够定位到具体是某个进程出现异常还是整体均有异常。
程序的可扩展性
任何指标的采集都是随着需求进行变更的,如果程序设计上不具有良好的扩展性,会后续的指标扩展带来很大的困扰。
第一版KDC监控指标的采集只区分请求的成功与失败两种类型,美团点评数据平台KDC库中所有的keytab都具有PREAUTH属性。根据上文可知,去掉PREAUTH属性后,AS请求的QPS能够提升一倍。后续随着服务规模的进一步增长,如果AS请求的处理能力逐步成为瓶颈,会考虑去掉PREAUTH属性。
为了准确监控去掉PREAUTH属性这一过程是否有、有多少请求出现错误,需要扩展一个监控指标,因此有了KDC监控的第二版。整个过程只需要修改三个地方,完成两个功能的实现:1. 添加指标 ;2. 打点逻辑的添加。 整个修改过程简单明了,因此,该KDC监控程序的设计具有非常好的扩展性。图12为监控指标的罗列和注释。
接口工具kstat的设计
获取KDC监控指标的接口工具主要分为两种:1. 获取当前每个KDC进程对各个指标的累积值,该功能是为了和新美大的监控平台Falcon结合,方便实现指标的上报实现累加值和分钟级别速率值的处理;2. 获取制定次数在制定时间间隔内每个进程监控指标的瞬时速率,最小统计间隔可达秒级,方便运维人员登陆机器无延迟的查看当前KDC的服务情况,使其在公司监控系统不可用的情况下分析服务的当前问题。具体使用见图13 。
五、总结
通过本次对KDC服务的压测实验和分析,总结出KDC最优性能的调整方案为:
1. KDC服务本身需要开启多进程和以充分利用多核机器的CPU资源,同时确保BDB的内存资源足够,保证其缓存命中率达到一定比例(越高越好,否则查询库会带来大量的磁盘读IO);
2. 选择的物理机要做RAID,否则在库中keytab带有PREAUTH属性的条件下,会带来大量的写,容易导致磁盘成为KDC的性能瓶颈。通过建立一块共享内存无锁的实现了KDC多进程指标的收集,加上其良好的扩展性和数据的精确性,极大的提高了KDC服务的可靠性。
相比原来线上单进程的处理能力,目前单台服务器的处理性能提升10+倍以上。本次工作没有详细的论述TCP协议中半队列、全队列的相关参数应该如何设定才能达到最优,和服务本身结合到一起,每个参数的变更带来的影响具体是啥?考虑到TCP本身的复杂性,我们将在未来的文章中详细讨论这个问题。
作者简介
鹏飞,美团点评基础数据部数据平台大数据SRE组,离线计算组SRE负责人,2015年11月加入美团点评。
长按识别关注我们,每天都有精彩内容分享哦 ~ ~
网友评论