引言
在日常开发中我们有很多场景需要提供高并发的服务,那如果写出高并发的服务呢,目前最常用的方式就是使用缓存对数据访问进行加速。以提高接口的响应速度,提升并发量。
接下来我们来探索下如果更高效的使用缓存。我们以最常被使用的缓存redis为例分别分析下redis的5种数据结构的使用场景;
字符串(strings)
数据缓存
业务场景
使用缓存就是为了加速程序处理的效率,所以一般是对数据库数据的缓存,因为redis的读写效率高于数据库,还有一种是对于接口数据的缓存,一方面是保护下游服务避免流量直接打到下游服务,领一方面有些数据没有必要完全实时性。比如影城的座位图。
技术方案
key:业务前缀:业务唯一id
过期时间:随业务而定,有设置X时间(超时消失,然后访问时惰性加载)还有设置业务完全失效的,比如影城的座位图,当排期彻底过期后该缓存就没有意义。
初始值:一般该类型的缓存使用的都是惰性加载,不需要初始值;即缓存没有从远程资源获取存入缓存下次备用;
逻辑处理:先获取缓存,有缓存使用缓存,没有就调用远程资源,写入缓存。
在使用的时候也要根据相应的业务场景进行调整,比如上述的影城座位图缓存,为了客户体验即就算影城的这次接口没有返回数据,也不应该给用户看到的是空的信息,所以在做业务处理时,存入redis 的值不止是接口的返回数据,还有数据的请求时间,每次缓存获取完数据看下请求数据是否在规定的有效时间内,如果不在,调用接口刷新返回结果,如果有数据返回存入缓存返回数据,如果接口返回超时等错误,返回上次缓存的数据,尽量给客户提供最新的数据
限流 (INCR 命令)
业务场景
集群限流。有些服务是有最大访问限制的,即整个集群每分钟只能处理X个请求,有两种情况会有这2种需求,一种是对集群的保护。一种是营造业务繁忙的场景。只放少量的人进入后面的流程。
技术方案
key:业务前缀:yyyyMMddHHmm (后面的时间就是限流的单位,该事例是分钟)
过期时间:限流最小单位+X (x一般几秒就够,怕业务服务器和redis机器的时间有误差导致控制精度不足)
初始值:不需要设置 如果key 不存在 INCR 命令自动设置初始值为0
逻辑处理:进入方法第一件事就是进行自增处理,如果返回值大于限流值直接返回服务正忙。否则放行。
限流变种 如果资源同一时间只需要访问一次,比如影城特定场次座位图,在同一时间你只需去影城获取一次,所以在请求之前先获取值,如果等于1获取影城座位图,然后更新座位图缓存。 如果值大于1就不调用影城的座位图,而是稍作等待,使用缓存中的数据。
活动总量控制 (INCRBY 命令)
业务场景
发红包,在营销活动中经常有需求是对总量要进行控制的。因为成本问题不能进行超发。
技术方案
key:业务前缀:活动唯一标识;
过期时间:活动的解释时间+24小时;
初始值:活动的最大领取数;
逻辑处理:每次请求进来,判断完硬性条件,如活动状态,活动时间等,即确认完领取资格,调用INCRBY key -1 命令进行原子性减一。只要返回值>=0认为还有库存进行领取操作。如果活动的并发量太大,领取操作可以使用队列来进行异步处理。
增加库存:如果活动火爆需要增加库存,直接使用 set key 增加库存数来进行库存的增加。
利用set命令中nx参数做分布式锁
业务场景
需要并发控制的地方。举个具体的显示场景,比如1个停车位只能停1个车,如果2个车同时进入就是事故;但是这种1个资源只能被一个请求占用的情况使用 INCR 也能完成相同的功能。还有一种场景就是几个车道并入单车道,这种场景就没法用INCR ,因为INCR只能