redis可选应用场景

导语:

一、【进程内】缓存和【进程外】缓存

【进程内】缓存:就是把数据缓存在服务的进程内,就是进程内缓存,通常进程内缓存的实现载体,简单的可以是一个map,list。

【进程外】缓存:进程外缓存,最常见的,redis/memcache

二、二者的区别

进程内缓存省去了网络开销,所以依赖节省了内网带宽,响应时延时会更低。 进程内缓存,虽然节省了网络开销,但是数据存了多份,一致性比较难保障。 进程外缓存,虽然多一次网络交互,但是统一存储。 所以选用Redis,也不能乱用,需要分析具体的情况,具体分析。

下面介绍一下

redis 使用场景。

三、场景分析

A、进程内缓存:   ==场景一==:只读数据,在启动服务的时候,初始化加载到内存。(当然使用redis,也可以)

  ==场景二==:极其高并发的,如果透传后端压力极大的场景。例如:高并发的交易,秒杀,需要服务层控制流量的。

  ==场景三==:一定程度上,允许数据不一致业务。

B、进程外缓存:

  ==场景一==: 缓存——热数据

热点数据(经常会被查询,但是不经常被修改或者删除的数据),首选是使用redis缓存,毕竟强大到冒泡的QPS和极强的稳定性不是所有类似工具都有的,而且相比于memcached还提供了丰富的数据类型可以使用,另外,内存中的数据也提供了AOF和RDB等持久化机制可以选择,要冷、热的还是忽冷忽热的都可选。

结合具体应用需要注意一下:很多人用spring的AOP来构建redis缓存的自动生产和清除,过程可能如下:

Select 数据库前查询redis,有的话使用redis数据,放弃select 数据库,没有的话,select 数据库,然后将数据插入redis

update或者delete数据库钱,查询redis是否存在该数据,存在的话先删除redis中数据,然后再update或者delete数据库中的数据

上面这种操作,如果并发量很小的情况下基本没问题,但是高并发的情况请注意下面场景:

为了update先删掉了redis中的该数据,这时候另一个线程执行查询,发现redis中没有,瞬间执行了查询SQL,并且插入到redis中一条数据,回到刚才那个update语句,这个悲催的线程压根不知道刚才那个该死的select线程犯了一个弥天大错!于是这个redis中的错误数据就永远的存在了下去,直到下一个update或者delete。

  ==场景二==:计数器,诸如统计点击等应用,由于单线程,可以避免并发问题,保证不会出错,而且100%毫秒级别性能,命令:INCRBY。

  ==场景三==:队列,相当于消息系统,XNETD、MQ类似的使用方式,但是简单的使用可以,如果数据一致性要求较高的系统,还是使用XNETD、MQ等专业的系统。

  ==场景四==:位操作(大数据处理)用于数据量上亿的场景下,例如几亿用户系统的签到,去重复登陆次数统计,某用户是否在线状态等。 举例,想一下, 腾讯10亿用户,要几个毫秒内,查询到某个用户是否在线,你怎么做?千万别说给每一个用户,创建一个key,然后挨个记,这是一个非常可怕的事情,这里要用到位操作【setbit,getbit,bitcount】 原理:redis内构建一个足够长的数组,每个数组元素只能是0和1两个值,然后这个数组的下标index用来表示用户的id(qq号,必须是数字),那么很显然,这个记忆长的大数组,就能通过下标和元素值(0和1)来构建一个记忆系统。 ITS中,委托和估值系统,想要快速横向扩展,可以考虑这个模式。

  ==场景五==:幂等将请求唯一流水号,参数、接口等hash作为key存储到redis,然后每次请求,去查询,是否有一致的情况,如果有更具业务要求,返回,如弹出“交易已成交,请刷新”,弹出之前的返回结果等。

  ==场景六==:秒杀系统,基于 redis是单线程特征,防止出现数据库压爆的场景。

	//秒杀简单业务逻辑实现
	实现秒杀前请确认php成功安装redis扩展!
	<?php
	namespace app\home\controller;
	use Redis;

	class Redis extends Cauth{

		public function index(){
			//首先,加载一个Reids组件,
			$redis = new Redis();
			$redis->connect('127.0.0.1', 6379);
			$admin = Session('admin');
			$redis_name = 'miaosha';
			$uid = $admin['username'];
			//设置参加数量
			$num = 20;
			//如果当前人数少于20的时候,则加入这个队列
			if ($redis->lLen($redis_name)< $num) {
				//执行数据库操作
				$res = true;//'增删改查';
				//如果为真,则往队列新增
				if($res){
					$redis->LPush($redis_name,$uid);
				}else{
					$this->error('很不幸,未能参加抢购成功');
				}
				$user_list = $redis->Lrange($redis_name,0,20);
				var_dump($user_list);//可以查看list的内容
			}else{
				//如果当前人数已经达到20人,责任返回秒杀已完成
				echo '秒杀已结束';
			}
			$redis->close();
		}

	}
	//具体细节 参考 https://my.oschina.net/osgrace/blog/994417

  ==场景七==:优化查询列表,将需要返回的list,都放入redis,下一次用户查询,无需去数据库 分页,直接从redis获取list即可。

  ==场景八==:全页面缓存,如果你想使用的是服务器端内容渲染,你又不想为每个请求重新渲染每个页面,可以使用Redis把常被请求的内容缓存起来,能够大大的降低页面请求的延迟,已经有很多框架缓存页面,这就是页面静态化的一种方式。 // Set the page that will last 1 minute SET key "..." EX 60 // Get the page GET key

  ==场景九==:排行榜,Redis基于内存,可以快速高效的处理增加和减少的操作,相比于使用SQL请求的处理方式,性能的提升是非常巨大的。Redis的有序集合可以轻松实现“从一个大型列表中取得排名最高的N个元素”,毫秒级,而且非常简单。

  ==场景十==:Session 存储,这可能是应用的最广的点了,相比较于类似memcache 的session存储,redis具有缓存数据持久化的功能,当缓存因为出现问题而重启后,之前的缓存数据还在那里,这个就比较实用,避免因为session突然消失带来的用户体验问题。

四、注意点

==A、千万不要吧redis当作数据库用:==

redis的定期快照,不能保证数据不丢失。 redis的AOF回降低效率,并且不能支持太大的数据量。 不要期望redis做固化存储比mysql做的好,不同的工具做各自擅长的事情,把redis当作数据用,这样的设计八成是错误的。

==B、做好“雪崩”的预防措施==

“雪崩”的意思:程序逻辑,查询redis,如果没有,查询DB,当在高并发的情况下,出现redis宕机的情况,导致所有都去数据库,虽然redis自动恢复了,但是数据库已经被压垮了。 解决方案推荐:redis高可用的架构模式。

摘自:https://www.jianshu.com/p/ea0452a3a79c https://www.php.cn/redis/421843.html

记录你我
请先登录后发表评论
  • latest comments
  • 总共0条评论