首页
视频
留言
壁纸
直播
下载
友链
统计
推荐
vue
在线工具
Search
1
ElasticSearch ES 安装 Kibana安装 设置密码
421 阅读
2
记一个报错GC overhead limit exceeded解决方法
344 阅读
3
Teamcity + Rancher + 阿里云Code 实现Devops 自动化部署
230 阅读
4
JAVA秒杀系统的简单实现(Redis+RabbitMQ)
209 阅读
5
分布式锁Redisson,完美解决高并发问题
206 阅读
JAVA开发
前端相关
Linux相关
电商开发
经验分享
电子书籍
个人随笔
行业资讯
其他
登录
/
注册
Search
标签搜索
AOP
支付
小说
docker
SpringBoot
XML
秒杀
K8S
RabbitMQ
工具类
Shiro
多线程
分布式锁
Redisson
接口防刷
Jenkins
Lewis
累计撰写
146
篇文章
累计收到
14
条评论
首页
栏目
JAVA开发
前端相关
Linux相关
电商开发
经验分享
电子书籍
个人随笔
行业资讯
其他
页面
视频
留言
壁纸
直播
下载
友链
统计
推荐
vue
在线工具
搜索到
1
篇与
的结果
2021-03-14
JAVA秒杀系统的简单实现(Redis+RabbitMQ)
1、分析秒杀时大量用户会在同一时间同时进行抢购,网站瞬时访问流量激增。秒杀一般是访问请求数量远远大于库存数量,只有少部分用户能够秒杀成功。秒杀业务流程比较简单,一般就是下订单减库存。上述三点的主要问题就是在高并发的情况下保证数据的一致性。2、使用的技术和架构2.1 秒杀架构图2.2 实现流程使用 redis 缓存秒杀的商品信息,秒杀成功后使用消息队列发送订单信息,然后将更新后数据重新写入redis。RabbitMQ监听器在接受到消息后,将订单信息写入数据库。在秒杀时使用redisson对商品信息上锁。2.3 流程图3、准备工作3.1 安装redis cluster教程一大堆,这里我就不多赘述了,可以参考:https://blog.csdn.net/CFrieman/article/details/835830853.2 安装RabbitMQ和erlang教程一大堆,这里我就不多赘述了,可以参考:https://blog.csdn.net/qq_36505948/article/details/827341334、具体实现4.1 SeckillServicepublic class SeckillService { @Autowired private RedisClusterClient rt; @Autowired private SeckillMapper sm; @Autowired private RedissonClient redissonClient; // 加锁 @Autowired private RabbitmqSendMessage rsm; @Autowired private SecorderMapper om; /** * 初始化 ,将mysql中的商品信息缓存到redis中 * @return */ public List<Seckill> querySeckill() { List<Seckill> list = (List<Seckill>) rt.get("secgoods"); if(list==null) { list = sm.selectByExample(null); rt.set("secgoods", list, 60*30); } return list; } public boolean queryStartTime(Seckill sec) { Date date = new Date();// 比较时间,是否到秒杀时间 Date startTime = sec.getStarttime(); // 秒杀活动还未开始 if (startTime.getTime() > date.getTime()) { return false; } return true; } // 减库存redis public void decreaseStock(String id) { int goodsid = Integer.parseInt(id); List<Seckill> list = (List<Seckill>) rt.get("secgoods"); if (list!=null) { for (Seckill sec : list) { if (goodsid==sec.getId()) { sec.setCount(sec.getCount()-1); //写回redis rt.set("secgoods", list, 60*30); return ; } } } } // public Seckill findSec(String secid) { List<Seckill> list = (List<Seckill>) rt.get("secgoods"); int id = Integer.parseInt(secid); for(Seckill sec:list) { if(sec.getId()==id) { return sec; } } return null; } // 开始秒杀 public String goSeckill(String goodsid, String username) { String key = username + ":" + goodsid; String secid = goodsid; Long value = (Long) rt.get(key); if (value != null) { return "exist"; } Seckill sec = findSec(secid); boolean flag = queryStartTime(sec); if (!flag) { return "notTime"; } RLock rLock = redissonClient.getLock("miaosha"); rLock.lock(); if (sec.getCount() > 0) { decreaseStock(goodsid); // 减少库存 rt.set(key, System.currentTimeMillis(), 60*30); Secorder newOrder = new Secorder(); newOrder.setCreatetime(new Date()); newOrder.setGoodsid(Integer.parseInt(goodsid)); newOrder.setStatus("未付款"); newOrder.setUsername(username); String json = JSONObject.toJSONString(newOrder); rsm.send(json); // 异步下单 rLock.unlock(); // 解锁 return "success"; } else { rLock.unlock(); return "failed"; } } // 写入mysql public void saveOrder(String json) { Secorder order = JSON.parseObject(json, Secorder.class); int n = sm.updateCount(order.getGoodsid()); int m = om.insert(order); } }4.2 RabbitmqListenner@Service public class RabbitmqListenner implements MessageListener { @Autowired private SeckillService ss; @Override public void onMessage(Message msg) { byte[] data = msg.getBody(); try { String json = new String(data,"utf-8"); System.out.println(json); ss.saveOrder(json); //将监听到的订单写入MySQL } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }4.3 RabbitmqSendMessagepublic class RabbitmqSendMessage { @Autowired private RabbitTemplate rt; private final String QUEEN_NAME = "MIAOSHA"; /** * 发送消息 * @param msg */ public void send(String msg) { rt.convertAndSend(QUEEN_NAME,msg); } }4.4以上就是整个业务流程的核心代码,使用redisson保证数据一致性,用rabbitmq异步下单将下单及写数据库这个长操作变成两个短操作。GitHub源码地址,关于数据库建表什么的,大家直接去源码里看吧。5.优化限流:使用验证码,请求秒杀接口需要验证图形验证码的正确性,这样也很好的防止脚本的不断访问;防刷:一个用户对一个路径的访问次数在一定时间内有限制,使用redis可以解决接口地址隐藏:接口地址传参,保证秒杀接口不是一个固定路径,防止接口被刷,同时也可以有效隐藏秒杀地址。
2021年03月14日
209 阅读
0 评论
1 点赞