一、前言
1、昨天在写一个python脚本,连接线上redis,有三个实例报invalid password ,很明显啊!不就是密码错误吗?确实是密码错误,我们将密码打印出来看下,然后使用redis-cli连接确实也连接不上,百分百是密码错误了。其实我是怀疑过pyredis的bug了,但是这个库其实已经很成熟了,不应该发生这么低级的错误才对,而且使用redis-cli也是有问题的,所以pyredis的bug是可以排除的,(出于安全原因,部分ip和密码已打码,忘见谅)不知道大家注意到没有报错的密码都带有%这个特殊字符,这个问题先暂时放着吧!

脚本部分代码如下
def get_redis_memory(host,port,password):try:pool = redis.ConnectionPool(host=host,port=int(port),password=password,db=0)r = redis.StrictRedis(connection_pool=pool,charset='utf-8')data = r.info()return data['used_memory']except Exception as e:print('redis error:%s' % e)
二、原因分析
1、刚开始确实一时半会没想到原因,于是想到了,如果那三个redis实例密码有问题,那么redis监控的数据应该是空白才对,因为redis密码也是从数据库获取的,但是查看监控是可以正常上报的,如图所示

这让我更郁闷了,问题在哪呢?于是想了一下,记起来redis监控进程是用用supervisor管理,于是登录相应机器,查看配置文件中相对应的redis实例信息,发现密码跟打印出的密码一模一样,如图所示

这个更让我觉得好奇了,于是我查看对应的redis exporter进程,原因就已水落石出

大家应该看到了吧,redis_exporter中密码是少了一个%的,笔者使用这个密码连接redis是ok的,好吧!原因基本水落石出了,就是数据库里面存储的密码是已经过运维开发为了偷懒,在数据库层面存储转义过的密码,为了便于supervisor识别带有%特殊字符,不然运行会直接报错,本人也测试了一遍,确实不行。我们都知道supervisor是用python写的,而python在处理%字符的时候,是需要使用两个%%进行转义的,当然单独使用一个%不需要,大家看如下代码
>>> print('%d %%') % digit20 %>>> digit = 20>>> print('%d%') % digitTraceback (most recent call last):File "<stdin>", line 1, in <module>ValueError: incomplete format>>> print('%d%%') % digit20%>>> print('%')%
笔者更倾向于是supervisor在这个%特殊字符处理上的一个鸡肋,容易让人入坑。
三、解决方法
1、解决办法
叫运维开发处理自己埋下的坑,特殊字符在动态生成supervisor配置文件的时候,是可以进行特殊处理的,推荐
2、python脚本做一个判断,比较傻,但是可以暂时可以解决目前的问题
if redis_pass.count('%') == 2:redis_pass = redis_pass.replace('%','',1)
由于笔者能力有限,有不足之处请多指教。

喜欢作者,可以关注一下




