最近,线上某系统由于MySQL权限问题导致应用异常,恰好老板对此应用灰常关注,出此问题产品经理压力山大,势要抓程序员祭天,由此开发、运维怼的不可开交。

做为一名运维小伙伴,当然不愿意运维兄弟无端端的背黑锅。不管事故是如何发生的,运维兄弟的职业操守不容置疑。做为运维,你可以怀疑我的能力,但绝不允许你侮辱我的人品。带着给运维洗脱监守自盗的嫌疑,开始了本次事故的根因分析。

事故还原一、问题发现

开年,老板在开年致词之后心血来潮,准备在内部IM来一波动员,遂打开app,准备拉群ing,duang~~~,应用一直处于“添加成员中...”。

产品经理受到10000点暴击。

事故还原二、问题定位

产品经理立马召开会议,小A、小B、小C,你看我们产品出现这么个问题,到底是啥原因,能不能有个准确的说法啊。

开发、运维一顿操作猛于虎,最终发现日志上有个明显的报错:

由此出现上面开发、运维互相扯皮的一幕,那到底是什么问题呢。

事故还原三、根因分析

为了不让好人蒙冤,也不让坏人逃跑,我们继续深入事故分析。

日志显示是权限校验失败,所以先查下DB赋权是怎样给的。在MySQL实例,查询赋权如下:

上图显示对于同一个账号ims,分别有2部分的授权,而这2部分的授权使用密码也不相同。

了解到业务情况,IM分多个模块,运维在上线时,为不同模块分配了不同的库 imsdb、imsmsgdb,并配以不同的密码,但模块都混部在相同机器。

那问题是怎么产生的呢,我们来一起看看MySQL权限管理是如何实现的。

MySQL服务器通过MySQL权限表来控制用户对数据库的访问,MySQL权限表存放在mysql数据库里,由mysql_install_db脚本初始化。这些MySQL权限表分别user,db,table_priv,columns_priv和host。下面分别介绍一下这些表的结构和内容:

user:记录允许连接到服务器的用户帐号信息,里面的权限是全局级的。

db:记录各个帐号在各个数据库上的操作权限。

table_priv:记录数据表级的操作权限。

columns_priv:记录数据列级的操作权限。

host:配合db权限表对给定主机上数据库级操作权限作更细致的控制。这个权限表不受GRANT和REVOKE语句的影响。

而且MySQL服务对用户进行鉴权时,遵循最小匹配原则。

由此可知,IM应用在进行DB鉴权时,首先匹配到ims@192.168.3.133这条权限,这就导致另外一个模块以不同密码访问时鉴权失败,导致应用日志表现出来的情况。运维修改了其中一模块用户名,用于区分不同模块之间访问DB的权限,解决此次问题。

综合来看,此次问题还是由于运维能力不足,对MySQL权限管理原理不熟悉导致,仅以此文记录此次事故,以便后续知识积累增长。