高并发的解决方案

静态化处理

原理

例如商品页面等稳定资源,不经常会去修改它,但是用户经常会访问它,如果单纯的从数据库中提取数据,会并发量很低,除了缓存处理,现在提供一种新的思路是生成静态化的页面,使用的技术是Freemarker

1
2
3
4
5
6
7
// 注意这边引入的是Freemarker的包
@Resource
private Configuration freemarkerConfig;
// 获取模板对象
Template template = freemarkerConfig.getTemplate("goods.ftl");
// 生成静态网页的核心方法
template.process(传入的数据,输出的路径);

但是因为是静态页面,所以当商品详情修改后为了能够将静态页面也进行修改,所以需要跑一个定时任务,例如,每5分钟检查一下商品信息是否更改,将更改的商品重新生成静态页面

1
select * from t_goods where last_update_time >=now()- interval 5 minute

动静结合

当比如说商品评论需要显示在网页上时,动态的部分就用ajax去调用,静态的部分直接显示

Redis解决超卖现象

将秒杀活动建立一张表,起个定时任务将规定时间内的秒杀任务的商品ID放入redisList中,并发请求进来,因为redis的单线程机制,可以保证不会出现超卖现象,为了保证秒杀一人参与一次,也可以将抢到名额的用户ID和商品ID放入redisSet中,防止重复秒杀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void withRedis(@PathVariable("userId") String userId) {
Integer goodsId = (Integer) redisTemplate.opsForList().leftPop("miaosha:goodsId:1010");
if (goodsId != null) {
Boolean member = redisTemplate.opsForSet().isMember("miaosha:goodsId:1010:userId", userId);
if (member) {
System.out.println("编号为" + userId + "的用户不能重复秒杀");
} else {
System.out.println("编号为" + userId + "的用户抢到了");
}
redisTemplate.opsForSet().add("miaosha:goodsId:1010:userId", userId);
} else {
System.out.println("编号为" + userId + "的用户没抢到");
}
}

利用MQ进行流量削峰

原理

当服务器QPS只有500,但是实际上每秒有5000的访问量时,为了防止服务器不崩溃,所以需要用MQ进行流量削峰,以下订单为例

  • 用户的订单请求进行放入MQ,这时直接返回用户的订单号,用户界面跳出弹框

  • 3s后ajax异步去访问后台订单系统,根据实际订单生成返回内容

前端关于弹出的弹窗和定时访问可以使用SweetAlert2插件完成

利用Redis实现Session共享

比如用户登录需要Session时,如果是集群,那么普通情况下Session不共享,一台服务器有登录信息,另一台并不存储登录,此时的解决方案是使用Redis

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>

然后在启动类添加注解@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)即可, maxInactiveIntervalInSeconds设置redis超时时常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 使用redis来实现session共享
*/
@RequestMapping("/sessionShared/{name}")
public void sessionShared(HttpSession session, @PathVariable("name") String name){
session.setAttribute("login",name);

}

@RequestMapping("/check/{name}")
public void check(HttpSession session, @PathVariable("name") String name){
String login = (String)session.getAttribute("login");
if (login!=null){
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
}
赏个🍗吧
0%