ci php redis,一次基于CI的Redis性能问题定位

点击访问原文

您还可以加入全栈技术交流群(QQ群号:254842154)

使用PHP的CI 3.0框架已经有一段时间了,它内置的类库虽然比较少,但是基本的都有,例如Cache模块,它提供了几种最常用的快速缓存的封装,包括apc、memcached和redis等。其中redis是比较常用的缓存,用于存储程序中经常用到并且不会频繁变化的数据。用法:

//加载类库

$this->load->driver('cache', array('adapter' => 'redis'));

//存字符串

$this->cache->save('key_str_hello', 'value_hello', 3600);

//存数组

$this->cache->save('key_array_hello', array('a' => 123), 3600);

//取

$data = $this->cache->get('key_hello');

//删除

$this->cache->delete('key_hello');

问题描述

在一次接口性能测试中,发现取数据时即使命中缓存,耗时也会比较长,基本在200-300毫秒左右。按常理隐约感觉缓存可能出现了问题。

问题定位

问题的关键是找出耗时的方法或代码片段。检查了跟业务相关的逻辑,没有耗时的操作。由于调用了比较多的CI库函数,假如要层层深入跟踪代码,可能会比较难定位。于是想到了xhprof,定位性能问题的利器,大家可以自行查资料如何使用。

于是在测试环境装了xhprof,并在待测试的方法中开启了xhprof的数据收集。得到了一个详细的函数调用路径及耗时,如下图:

5cb0936ec53b

image

可知,此次请求耗时341ms左右,从每个方法的耗时中不难发现,其中有一个Redis::sMembers方法耗时289ms之多,占到了将近85%时间。继续深入查看,发现Redis::get函数耗时19.4%占用了大部分时间。

5cb0936ec53b

image

sMembers是一个redis集合操作函数,用于获取指定key值的集合信息。于是马上想到了CI封装的redis类库,找到system/libraries/Cache/drivers/Cache_redis.php 文件。

经过代码阅读,发现在构造函数 __construct中有一行代码读取了_ci_redis_serialized这个key对应的值:

// Initialize the index of serialized values.

$serialized = $this->_redis->sMembers('_ci_redis_serialized');

empty($serialized) OR $this->_serialized = array_flip($serialized);

完整阅读完代码后发现,CI的redis类库在存储数据时,会区分普通字符串数据,和对象或数组数据,对于对象或数组,在存储到redis之前,会进行序列化操作,并把这个数据的key值存储到redis集合中(这个集合使用_ci_redis_serialized作为key);在取出数据时,首先从集合中查找对应的key是否存在,假如存在则进行反序列化操作。

也就是说,随着redis中存储的数组或对象越来越多,集合中存储的key也就越来越多。而每次redis的操作,都会触发一次取集合数据的操作。当数据量较大时,这个取集合数据的网络延时也会变得比较大。

问题解决

改写CI的redis类库,在构造函数中去掉取集合数据的操作,并通过 sIsMember 方法来判断当前的key是否为对象或数组。

总结

对于一些顽疾问题,追根溯源时别忘了借助一些外部工具

不要太相信框架

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值