点击访问原文

您还可以加入全栈技术交流群(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的数据收集。得到了一个详细的函数调用路径及耗时,如下图:

image

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

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是否为对象或数组。

总结

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

不要太相信框架

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

  1. Redis第一话 -- Redis介绍以及基于Docker安装Redis

    随着缓存技术的发展,Redis已经成为了工作中使用的最多的缓存技术了. 那么对Redis的了解肯定是必不可少的. 1.Redis介绍 Redis是基于C语言开发的纯内存存储KV结构的一个数据库.获取数 ...

  2. docker redis 配置文件_基于Docker搭建Redis一主两从三哨兵

    点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 作者:oscarwin juejin.im/post/5d26b03de51d454fa3 ...

  3. 基于ci框架 php商城,如何基于CodeIgniter框架实现购物车功能

    这篇文章主要介绍了基于CI(CodeIgniter)框架实现购物车功能的方法,结合实例形式分析了CodeIgniter框架购物车功能类的定义及数据库建立相关sql命令,需要的朋友可以参考下 本文实例讲 ...

  4. redis系列:基于redis的分布式锁

    一.介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分为两部分,一个是单机环境, ...

  5. 基于Jedis实现Redis分片的理解

    2019独角兽企业重金招聘Python工程师标准>>> 基于Jedis实现Redis分片的理解 博客分类: 缓存 一 理解前提 分片是为了把鸡蛋放到几个篮子里,而Dynamo型的分片 ...

  6. 基于Codis的Redis集群部署

    Codis是基于代理的高性能Redis集群方案,使用Go语言进行开发,现在在在豌豆荚及其它公司内已经广泛使用,当然也包括我们公司. Codis与常见的Redis集群方案对比. 在搭建的时候,个人觉得R ...

  7. 如何基于MySQL及Redis搭建统一的kv存储服务 | 秦波

    一.MySQL+Redis常用部署方式 1.1  拓扑 1.2  特点 业务层通过双写同时写MySQL及Redis.读通常在Redis,若读取不到,则从MySQL读取,然后将数据同步到Redis,Re ...

  8. Redis Primer(1)基于JedisPool的Redis hset并发性能测试 - @钟超 · 技术博客专栏 - 博客频道 - CSDN.NET...

    Redis Primer(1)基于JedisPool的Redis hset并发性能测试 - @钟超 · 技术博客专栏 - 博客频道 - CSDN.NET Redis Primer(1)基于JedisP ...

  9. k8s redis集群_基于K8S部署redis哨兵集群

    本 文 主 要 内 容 什么是Kubernetes分布式容器管理平台 PaaS平台redis-sentinel集群架构简介 PaaS平台部署redis哨兵集群 redis-sentinel容器测试及验 ...

最新文章

  1. LeetCode简单题之分割平衡字符串
  2. Android 应用Crash 后自动重启
  3. android 8.0手机无法更新版本,安卓手机升级安卓8.0后 系统以后可能都无法回退
  4. luogu P1231 教辅的组成
  5. java nio.Buffer的属性变化
  6. php学习_与mysql的连接 2013.01.04
  7. Calibration校准halcon算子,持续更新
  8. mybatis的select、insert、update、delete语句
  9. (98)Verilog HDL:流水灯设计
  10. 【IT】使用gdb调试code
  11. 简单的代码提交,还能玩出这么多花样?
  12. select case语句_图解Go select语句原理
  13. IDEA快捷键拆解系列(七):Analyze篇
  14. webstorm中 scss或sass配置自动编译
  15. 阿里巴巴短信验证码使用
  16. ed302安兔兔版main.31.com.antutu.ABenchMark.fix23下载安装使用教程
  17. lzo的正确c语言代码,LZO 使用跟介绍
  18. 华为路由器相同网段DHCPv6配置
  19. CAT的Server初始化
  20. Java课设对对碰_JAVA课程设计题目

热门文章

  1. 《中学生可以这样学Python》84节配套微课免费观看地址
  2. Python老师遇到的那些无语的问题
  3. Python花式编程案例锦集(2)
  4. Python 3.6新特性(部分)
  5. Python批量提取PDF文件中的文本
  6. 基于递归的前序二叉树遍历实现
  7. 手写call,apply
  8. jdialog 数据量大加载出现白板_王者荣耀:队友真的有人机?白板熟练进排位,资料面都是假的...
  9. php paerser,GitHub - iSinser/sinser-php-sdk: 迅析PHP SDK
  10. python摄像头识别快递单号查询_python如何免费对接快递鸟api单号识别查询接口