php 操作redis 数据类型并发实测

近期项目中遇到接口并发量比较高的情况,采用的是redis先缓存再进行数据同步的逻辑,但是实际运行中发现redis数据缺失或者溢出的情况,因此今天抽空代码实测下,以便最终来选择一种最可靠的数据结构(最终终于测试成功!!!)

需求:每个id次请求时成功或失败次数+1,每秒可能多个id都会发起请求
数据类型: {success:1,fail:1}
1.先用普通的key-value数据类型,以下是代码(使用thinkphp5.0框架)
    public function index()
    {
        Redis::Instance();
        $id=$this->request->param('id','1');
        $plus=$this->request->param('plus','success');
        $cachekey='test:'.$id;
        $data=Redis::get($cachekey);
        if(!$data){
            $data=['success'=>0,'fail'=>0];
        }else{
            $data=json_decode($data,true);
        }
        $data[$plus]=$data[$plus]+1;
        Redis::set($cachekey,json_encode($data));
    }

使用apipost 100并发压测结果如下(实际项目也打不到100,按100测试也足够):

image.png

理论上redis中 success值应为667,但实际结果如下:
image.png

分析: 100并发下跟实际预期数值有偏差,且偏差量不小,实际项目的话用此方式可行性很低,因为会出现数据不准确的情况

2.再用hash类型测试,以下是代码(使用thinkphp5.0框架)
    public function index2()
    {
        Redis::Instance();
        $id=$this->request->param('id','1');
        $plus=$this->request->param('plus','success');
        $cachekey='test:'.$id;
        $data=Redis::hget($cachekey);
        if(!$data){
            $data=['success'=>0,'fail'=>0];
        }
        $data[$plus]=$data[$plus]+1;
        Redis::hsets($cachekey,$data);
    }

使用apipost 100并发压测结果如下

image.png

理论上redis中 success值应为663,但实际结果如下:
image.png

分析: 跟上面的方法结果基本一样,可行性不高

3.经网络搜索到了setnx事务锁的方法,我们实际在测试下,代码如下:
    public function index3()
    {
        Redis::Instance();
        $id=$this->request->param('id','1');
        $plus=$this->request->param('plus','success');
        $cachekey='test:'.$id;
        $lockkey='cando';
        if(Redis::setnx($lockkey,1,10)){
            $data=Redis::hget($cachekey);
            if(!$data){
                $data=['success'=>0,'fail'=>0];
            }
            $data[$plus]=$data[$plus]+1;
            Redis::hsets($cachekey,$data);
            Redis::del($lockkey);
        }
    }

理论上此方法可行,但是实际测试结果跟上面情况大差不差,因为有些请求触发了锁机制,数据就没有被记录下来,最终也会导致数据记录缺失的情况

4.list类型也是常用的,我们再实际测试下,代码如下
    public function index4()
    {
        Redis::Instance();
        $id=$this->request->param('id','1');
        $plus=$this->request->param('plus','success');
        $cachekey='test:'.$id;
        Redis::lpush($cachekey,$plus);
    }
apipost1000压测结果如下(上强度了,请求失败率请忽略):#####

image.png

理论上redis中 success值应为1176,实际结果如下:

image.png

分析: list类型可用性较高,再后续几次测试中都做到了 0 误差,异步同步数据时将数量统计方法修改下即可

总结:实际项目中遇到并发高的情况,list 比 k-v、hash类型更稳定也能确保数据不丢失

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容