随着系统并发请求激增,参考电商秒杀、当下集中核酸采取等业务场景,如果突然大量数据请求业务系统。此时如果没有做任何缓存措施,直接保存数据库,即使你的数据库做了集群和分库分表,也会由于扛不住并发压力崩溃的。基于最简单的存储模型,就是用Redis做缓存,数据业务插入到Redis缓存中,然后缓存依据系统的处理能力依次批量插入数据库,就有效避免数据库崩溃的情况发生了。
基于最简单的存储模型,就是用Redis做缓存,数据业务插入到Redis缓存中,然后缓存依据系统的处理能力依次批量插入数据库,就有效避免数据库崩溃的情况发生了。
然后有人说:Redis就不会崩了吗?
当然,Redis也有它的并发上限,但是Redis是基于内存的,数据库是基于硬盘的,缓存要比数据库轻量得多!
简单模型大致如下:
核心功能是:每条数据都直接通过StringRedisTemplate下的leftPushAll方法插入缓存,然后再通过定时任务,调用rightPop方法取出指定数量的集合数据,批量持久化到数据库中。注意:插入的时候从左边插入,取的时候就要从右边取出,这样的话就跟队列一样,先进先出、依次按序保存了。
Springboot大致实现的demo如下,仅供参考
1. 建项目,导入redis、mysql的依赖,yml中做配置等
略(我用的Springboot+mybatis+mybatisPlus+mysql的项目)
2. 数据库中新建一张表用于测试,对应实体、mapper、service、controller新建
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class TempLog {
@TableId
private Long logId;
private String logParam;
private String logMsg;
private String createTime;
}
3. controller中引入StringRedisTemplate
@Slf4j
@RestController
@RequestMapping("/temp")
public class TempLogController {
@Autowired
private TempLogService tempLogService;
@Autowired
private StringRedisTemplate redisTemplate;
private static final String CACHE_KEY = "TEMP_LIST";
}
4. 写一个方法,模拟数据插入,使用redis的opsForList()插入数据到缓存中
/**
* 模拟:插入数据,单条存入到缓存集合中(从左边插入)
*/
@GetMapping("/saveCache")
public R saveCache(){
TempLog tempLog = TempLog.builder().logParam(StringUtils.getUuid())
.logMsg(StringUtils.getRandomStr(10))
.createTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()))
.build();
log.info("数据插入...........");
redisTemplate.opsForList().leftPushAll(CACHE_KEY, JSON.toJSONString(tempLog));
return R.ok();
}
5. 开启一个定时任务,模拟定时把缓存中的集合数据插入到数据库中
/**
* 定时任务,把缓存中的集合数据插入到数据库中
* 模拟:每3s执行一次,每次从缓存中取50条数据(从右边取出)
*/
@Scheduled(cron = "*/3 * * * * ?")
public void saveDB(){
//注意:redis6.2.0以上才支持rightPop(key, count)方法,redis6.2.0版本以下调用rightPop(key, count)方法会报错,
//低版本只能使用rightPop(key)单条取
//rightPop(key, count) 返回值是List
//rightPop(key) 返回值是String
log.info("定时任务...........");
List<String> list = redisTemplate.opsForList().rightPop(CACHE_KEY, 50);
if (list != null && list.size() > 0) {
List<TempLog> collect = list.stream().map(i -> {
TempLog tempLog = JSON.parseObject(i, TempLog.class);
return tempLog;
}).collect(Collectors.toList());
//批量插入数据库
tempLogService.saveBatch(collect);
}
}
注意:redis6.2.0以上才支持rightPop(key, count)方法,redis6.2.0版本以下调用rightPop(key, count)方法会报错
6. 测试看下效果
使用Jmeter开启100个线程,循环20次,默认发起2000次请求
可以看到1秒钟,就把所有的数据都提交到缓存中了,并发量达到 2000/s 了!
然后缓存中的数据依次批量提交到数据库了!
完结!