我们在项目中经常会用到nosql来储存访问率高的数据,大多数就是用redis,凭借着比mysql高得多的qps支持数,这样做确实能提高处理速度。那么,redis就只能用来做数据存储查询吗?当然不是!redis还有很多功能等待使用。

       

一、原子性:

        面对高并发抢购的场景,单用mysql记录来判断库存很容易发生超卖的情况。这时候我们可以利用redis decr原子性做锁,实现防止超卖。

1)使用decr方式:

<?php 

		$redis = new Redis();
		$redis->connect('localhost', '6379');
		$key = 'stock';
		
		$data = $redis->decr($key);
		
		if ($data>0){
			header('HTTP/1.1 200 success');
			echo 'success';
		}else{
			header('HTTP/1.1 400 Not Found');
			echo 'false';
		}

2)使用读取重构方式:

<?php 

		$redis = new Redis();
		$redis->connect('localhost', '6379');
		$key = 'stock';//redis数据库key [注:默认redis数据库选择第0号数据库]
		

		$data = $redis->get($key);
		$data = $data - 1;
		$redis->set($key, $data, 600);
		
		if ($data>0){
			header('HTTP/1.1 200 success');
			echo 'success';
		}else{
			header('HTTP/1.1 400 Not Found');
			echo 'false';
		}

我们预先设置stock=200,然后模拟1000并发请求持续性30秒。

1)

java redis 实现原子性 redis操作原子性_消息队列

2)

java redis 实现原子性 redis操作原子性_redis_02

从测试结果可以看到,第一种方式执行结果是正确199次,而第二种方式成功814次出现了大量的超卖,如果是在实际的产品中,后果不堪设想。

二、expired过期事件

        redis有ttl属性,当数据超过了livetime自动销毁时会触发事件,我们可以监控这个事件来进行业务处理。比如新订单有三十分钟支付时间,我们就设置订单的ttl为30min,过期事件修改订单为取消状态;又比如,一场线上考试定时两小时,我们就设置ttl为2h,事件触发结束考试。

   

       

三、消息队列

        无可否认redis队列对比起其他专门的消息队列如rabbitmq、activemq等是弱了点,从可选的部署模式、消息的丢失率都是差一点的,但是胜在小巧。当你需要消息队列,但不想多装的软件,而且消息的必要性又不高,这时候请选择redis的消息队列。

        consummer

<?php

fuction listen(){
        $redis = new Redis();
		$redis->connect(’localhost‘,'6379');
		$redis->auth(123456);
		$key = 'mq_';//redis数据库key [注:默认redis数据库选择第0号数据库]
    		
		while(1) {
			//从队列最前头取出一个值
			$mq_message = $redis->lPop($key);

        //TODO 自定义处理
        var_dump($mq_message);

    }
}

listen();

 producer

<?php

$redis = new Redis();
$redis->connect(’localhost‘,'6379');
$redis->auth(123456);
$key = 'mq_';//redis数据库key [注:默认redis数据库选择第0号数据库]

$redis->rPush($key, 'hello mq');
			
//关闭redis连接
$redis->close();

先cli模式运行consummer,fpm模式运行producer测试推入队列。