day04-高并发优化
方案选择
实现了学习计划和学习进度的统计功能。特别是学习进度部分,为了更精确的记录用户上一次播放的进度,我们采用的方案是:前端每隔15秒就发起一次请求,将播放记录写入数据库。
在并发较高的情况下,会给数据库带来非常大的压力
在机器性能一定的情况下,提高单机并发能力就是要尽可能缩短业务的响应时间(ResponseTime),而对响应时间影响最大的往往是对数据库的操作。而从数据库角度来说,我们的业务无非就是读或写两种类型。
对于读多写少的业务,其优化手段大家都比较熟悉了,主要包括两方面:
- 优化代码和SQL
- 添加缓存【如Redis内存级别缓存】
对于写多读少的业务,大家可能较少碰到,优化的手段可能也不太熟悉,这也是我们要讲解的重点。
对于高并发写的优化方案有:
- 优化代码及SQL
- 变同步写为异步写
- 合并写请求:先写到Redis在写到DB,中间的不必要保存的都不写入DB,只将Redis最后一次保存到DB. 如前端每隔15秒就发起一次请求:视频播到第15秒更新moment到15、播到第30秒更新moment到30,播到第45秒更新moment到45,但我们要的是最后用户播放到的moment
-
变同步为异步:
不只是MQ一种方式,很多
合并写请求:【因为我们目的就是降低数据库的操作次数 所以采用这种方案】
写数据到缓存可以出现覆盖
方案
优化位置:
Redis要存的东西:User_id, 课程id 学习到的时间。因为User_id+课程id就是课表ID,所以存LessionID
操作redis的目的,就是更新哪一个视频哪一个小节下面学习了多少时长
public void writeRecordCache(LearningRecord record) {
log.debug("更新学习记录的缓存数据");
try {
// 1.Hashvalue是JSON形式
String json = JsonUtils.toJsonStr(new RecordCacheData(record));
// 2.拼装Hash的key
String key = StringUtils.format(RECORD_KEY_TEMPLATE, record.getLessonId());
// 写入redis
redisTemplate.opsForHash().put(key, record.getSectionId().toString(), json);
// 3.添加缓存过期时间:1分钟
//因为延迟任务是20s执行的,在这之前都持久化到DB了
redisTemplate.expire(key, Duration.ofMinutes(1));
} catch (Exception e) {
log.error("更新学习记录缓存异常", e);
}
}
Redis存的HashValue那个类,转成JSON的
@Data
@NoArgsConstructor
private static class RecordCacheData {
private Long id;
private Integer moment;
private Boolean finished;
public RecordCacheData(LearningRecord record) {
this.id = record.getId()<