优惠券读服务优化
来源:互联网 发布:达内 java培训机构 编辑:程序博客网 时间:2024/04/27 10:52
优惠券读服务优化
前几天成功解决了发券时的并发问题,参考这里。但是用户领取得卡一多,读取速度也慢了下来,用户领取了200张卡以后,取得自己所有的卡需要5s左右。
主要业务场景,查询用户卡包,得到用户所有的卡券。
- 用户根据id分在不同的表。
- 卡券根据不同的商户,分在不同的表。
- 先用用户id拿到用户和卡的对应关系。
- 再根据每个卡的商户和 卡券id查询对应的卡券,因为卡分在不同的表,不能成批拿卡,只能串行拿。
- 拼装卡模板相关信息返回。
第一步,建立卡券的缓存系统。
以商户和卡券Id在添加一个字符前缀做key,把卡缓存在redis里,并在卡券状 态变更后,作废钓redis里对应的卡券。
这样做后,构建一个200张卡的卡包,第一次还是需要5秒,第二次访问只需要1s。大并发后响应时间更长。这显然不能满足要求。
第二步,建立用户的缓存系统。
在有了卡券的缓存后,另外以用户id为主键,对每一个用户查询的返回结果,再做一级缓存,形成二级缓存机制。用户卡有变动的时候,作废缓存。
有了二级缓存,还是200张卡,第一次访问需要5s,第二次响应在200ms。100个并发访问在400ms左右。
缓存预刷机制。
有了二级缓存之后,由于每次卡有变动,用户访问卡包构建cache在1s以上,会影响体验,我又加入了预刷缓存机制,在用户卡变动后,作废掉用户级别的缓存,和变动的单个卡的缓存,随即抛出一个用户的id进入队列,队列的尾端拿到用户的主键后,访问用户卡包构建缓存,这样当用户再次访问卡包的时候,响应体验提升很大。
第三步,并行构建卡券。
在没有任何缓存的情况下,一次访问200个卡券的卡包在6s以上。
在只有卡券这一级缓存的情况下,构建用户返回结果,也需要1s以上。
因为取200个卡券的执行是单个串行执行的,分析下来这里是性能的瓶颈。优化方案是: 在构建200个卡券的时候,每一批卡开一个线程去构建,200个卡,可以同时开20到40个线程去构建,来缩短用户卡多的时候,这里的时间消耗。
这样做后,先禁用用户级别的缓存,来压力测试这里的性能。
在没有任何cache的情况下,单次访问200个卡的卡包,响应 时间在500ms,在有卡缓存没有用户缓存的情况下,单次的响应时间在200ms,构建用户级别缓存的时间已经大大缩短了。但在高并发的情况下,会报错,一查是因为redis的连接不够了,每个线程需要20-40个redis连接,所以redis要扩大连接数。
下面是多线程部分代码,对象的名字做了处理,并除去了业务逻辑。
/** * Created by haoli */ if (itemsList != null && CollectionUtils.isNotEmpty(itemsList)) { int totalCount = itemsList.size(); int taskNumber = (totalCount%GROUP_COUNT == 0 ? totalCount/GROUP_COUNT:totalCount/GROUP_COUNT+1); List<FutureTask<List<YourObject>>> ft = new ArrayList<FutureTask<List<YourObject >>>(); for(int i=0; i<taskNumber ; i++) { int toSize = ((i+1)*GROUP_COUNT>totalCount-1 ?totalCount : (i+1)*GROUP_COUNT); List<ItemObject> tempList = itemsList.subList(i*GROUP_COUNT,toSize); SubQueryYourObjectTask task = new SubQueryYourObjectTask (tempList,this.yourService); FutureTask<List<YourObject >> ftItem = new FutureTask<List<YourObject >>(task); ft.add(ftItem); ThreadPoolExeService.execute(ftItem); } for(FutureTask<List<YourObject >> ftItem : ft){ try { totals.addAll(ftItem.get()); } catch (InterruptedException e) { log.error(e.toString()); } catch (ExecutionException e) { log.error(e.toString()); } }
上面用到的子任务类代码
/** * Created by haoli */ public class SubQueryYourObjectTask implements Callable<List<YourObject >> { private List<ItemObject > parameter; private YourService yourService ; public SubQueryYourObjectTask (List<ItemObject > rlist, YourService yours){ parameter = rlist; this.yourService = yours ; } @Override public List<YourObject > call() throws Exception { List<YourObject > results= new ArrayList<YourObject >(); for(ItemObject cbur :parameter ) { results .add(this.yourService .getXXXById(cbur )); } return results ; }}
优化到现在,不论是第一次还是之后的访问,都不慢了,在有二级缓存的情况下,cpu和连接资源消耗也不会太大。而且有缓存预刷机制,卡包数据更新后也不会慢了。
- 优惠券读服务优化
- 阿里云服务优惠券免费领取
- 商城综合版优化札记-优惠券
- 使用阿里云优惠券享受云数据库Redis单节点集群版高性能服务
- 微信摇一摇优惠券
- 自定义优惠券
- 自定义优惠券
- PAT优惠券
- 优惠券2
- windows系统服务优化
- win2003系统服务优化
- win2003系统服务优化
- 优化服务批处理
- Vista 服务优化
- XP服务优化
- ubuntu服务优化
- linux服务优化
- Centos系统服务优化
- 详解Linux安装GCC方法
- 日志显示错误NIC Agent
- 【poj 2451】半平面交
- 第十三周项目三 Dijkstra算法的验证
- Only one Looper may be created per thread
- 优惠券读服务优化
- 平台客户端日志查看说明
- Oracle 定义变量总结(转)
- 第十六节 协议栈LED实验
- STM32F103ZET6 之 通用定时器单脉冲模式实验
- windows下socket网络编程小节
- UNIX网络编程——记录上锁
- HUD 1014 Uniform Generator
- ReactNative 学习笔记Component 和createClass区别