redis数据的轮询规则探讨(并发访问查询接口的性能问题思考)

业务场景如下:

公司举办司庆活动,使用微信端链接H5页面访问后台服务实现员工答题抢红包活动(除了微信网页授权登录用到微信API接口外,H5及后台服务均为公司自己研发)

redis数据的轮询规则探讨(并发访问查询接口的性能问题思考)

除了微信登录接口、员工信息获得接口、祝福语接口、抽奖接口外,还有一个员工中奖名单接口(通过轮询方式在抽奖活动页 面滚动展示)

由于预计员工瞬间涌入为万人以上,在处理并发访问查询接口时,当并发进程达到一定的数量时,数据库的瓶颈问题就出来,性能下降严重,很多查询进程处于等待阻塞状态。

经过调查发现引发性能问题的关键在于大量数据库连接请求处于排队中,数据库吞吐容量有限,如果不减少访问请求次数,那么优化SQL或减少查询记录数的有一定效果,但在并发超过一定数量的情况下(比如200)性能问题还是存在着。所以解决该问题的思路是转移数据库的压力,考虑使用缓存来处理大并发请求。这里考虑采用redis缓存来提高读取性能,降低对数据的IO操作。

接口功能业务:系统进入抽奖页面后,自动触发轮询调用员工中奖名单接口以获得员工中奖名单列表数据,假设轮询时间为5分钟一次(轮询时间可以由系统后台管理员自行设置)

那么一小时60分钟将会被5分钟分割为步长相等12等分时间段,每等份的临界值为 5,10,15,20,25,30,35,40,45,50,55,60分钟,那么在系统接受到的瞬间第一次名单请求(时间假设为整点0分)需要去从数据库读取数据(并将该次查询数据,以一定的 业务规则key值存入到redis中)外,其余的所有请求(0分至5分钟之间的所有请求,0

<=请求时间<5)都将去redis中取数据,从而减少了对数据库的压力。直到第二个临界点来临为止(第二个时间段 5分钟开始的首次请求,系统将重新去数据库查询数据,并再次存入到redis中)重新查询并存入新的数据以供其它请求查询。

那么问题来了,第一次请求是从数据库读取的数据,并以一定的规则(体现在key值上)存入到redis 中,系统如何对0~5分钟时间段所有请求生成同样的key值,然后通过key值去redis中取出 0分首次存入的数据呢?

参考以下方法 参数 currentTime为当前请求的系统时间,格式为 2018-06-07 17:12:00

参数 polling_time 为系统的轮询时间 比如 为 5 (分钟)

代码逻辑为 将60分钟按轮询时间分割为相等的时间段,生成一个数组

然后拿系统时间 分钟数 如 12去和临界值去比较,其实是判断12是否超过临界值15, 如果没有超过的话,则取上一个临界值10,然后封装成 2018-06-07 17:10:00 返回

/**
 * 根据轮询时长与当前时间生成key值
 * 业务逻辑:
 * 将60分钟按轮询时长分成若干等份 比如 轮询时长为5分钟,则分为 12等份 每等份的临界值为 5,10,15,20,25,30,35,40,45,50,55,60
 * 则传入的当前时间在等份中,返回该等份的最小值
 * 比如传入时间为2018-06-07 17:12:00 12 位于等份临界值 10 与 15之间 则返回值应该为10 最终返回时间应该为 2018-06-07 17:10:00
 * @param currentTime 当前时间 2018-06-07 17:12:00
 * @param polling_time 轮询时长(小于60分钟) 比如 5
 * @return 2018-06-07 17:10:00
 * @throws Exception
 */
 private String getWinningListKey(String currentTime ,String polling_time) throws Exception {
 String minute = "0";
 String [] arr = currentTime.split(" "); //17:12:00
 String [] arr1 = arr[1].split(":"); //12
 //1小时内的时间间隔
 int interval = 60/Integer.valueOf(polling_time);//60/5=12
 String [] intervalArr = new String[interval];//5,10,15,20,25,30,35,40,45,50,55,60
 for(int i = 0 ; i= Integer.valueOf(intervalArr[i])
 && Integer.valueOf(arr1[1])  
< Integer.valueOf(polling_time)*(2+i)){ minute = intervalArr[i]; break; } } minute = minute.length() == 1 ? "0"+minute : minute; return arr[0]+ " "+arr1[0]+":"+minute+":00"; }

这个逻辑的意思是 如果当前请求的系统时间没有超过或等于下一个临界点(15分),那么就取上一个临界点的值(10分钟),

这样,时间段内生成的key值总是保持一致,通过key去redis中获得历史拍照数据,一但达到临界点,又会重新生成新的key值,再依上述规则进行下去实现了业务逻辑的关于轮询数据获得与重新生成的业务规则。

经过重新压力测试,数据查询的瓶颈和进程阻塞问题得到根本性的解决。

redis数据的轮询规则探讨(并发访问查询接口的性能问题思考)

这里有一个值得注意的地方,虽然轮询时间是由管理员后台设置的,要求被60整除(比如5能被60整除),如果不能整除,那么时间段将会被切割的不完整,会遇到时间间隙,程序将会监控不到。


分享到:


相關文章: