在线教育实习经验总结

 介绍一下的你实习做的项目吧?

主要就是服务于考研学生培训的微服务C端项目,主要分前台和后台,其中的黄金链路就是从用户登录到购买课程再到课程观看的流程。那在这个过程中还存在一些辅助模块来提高用户的使用体验,包括问答,点赞,热门榜,积分及优惠劵模块,我只要就是负责对辅助模块的开发。

介绍一下课程模块

课程模块我印象最深的就是用户购买课程加入课表的业务,课表表只要就是关联用户和课程的关系,并且是个一对多的关系。在用户就完成付款后就会调用回调函数发送购买课程的消息,消息的主要数据就是订单号,课程集合,用户id,我们的学习服务就会监听对应的消息,在得到消息后做批量插入的操作,因为在一个订单中可能会购买多个课程,在这个过程中难点就是我们需要消息消费的幂等性问题,我们需要关闭了消费者自动确认机制,在我们消费完消息后再发送消费者确认标识最终移除消息。

哦对了,在课程模块中因为有大量的即可会使用到课程的消息,最开始的时候我们主要就是重复的去远程调用获取课程的信息但是呢效率很低,就使用了redis做缓存效果还是很好的,但是呢,每次去访问redis需要网络开销效率还是跟不上,所以我们最终就搭建了二级缓存,主要就是基于Caffaine实现的,因为Caffaine是基于jvm的就不要考虑网络开销的问题,也正是因为这个特性,所以在做数据一致的时候,我们需要使用redis的发布与订阅模块来通知所有的节点中caffaine缓存的清除操作。

你这个合并写请求的实现介绍一下?(在项目中有没有遇到难点?)

在编写学习模块中,提交观看位置的业务的优化是比较难的。在业务需求上,我们需要保证用户的续播效果且误差要在30s之内 ,在播放视频的时候前端每隔15秒就会提交一次观看位置,用户只要也是进行观看视频这种视频的长度基本数在一个小时以上,上级反映同时观看视频的用户在3000左右,也就是说每秒的平均的tps(吞吐量)在三千,那这这时候直接打db明显是不合适的。因此就进行了合并写请求的优化。那我给您继续介绍一下实现流程你看行吗?

我们会发现同一个用户每次观看位置只有最后一次是有效的,那我们干脆就让最后一次的观看位置打db,使用redis的hash结构进行存储,大key存储课表id主要就是关联课程和用户,小key存储节id,value就是存放观看位置mount。在每次将数据先存储到redis中,在使用mq发送一个延迟20s消息主要就是基于死信队列实现的,也是该模块进行监听,主要作用就是将20s前的观看位置和当前redis中观看位置进行比较,如果发现相同,那就说明这20s没有进行观看了这时候就修改数据库中的观看位置。如果发现不相同的话,就不做操作即可。可以说移除了99%的打db操作。

问:那用户直接拉进度条也会视为已看完吗?

那在我们的项目中,就是规定主要用户进度条到达50%就认为其已看完。如果真的需要这个需求的话。我想想,因为前端每隔15秒提交一次请求,使用总时长除以15除2就可以计算总提交数。使用hash结构存储对应的视频的提交次数。大key存储课表id,小key存储节id,value存储提交次数,在每次提交位置的时候就会将value+1。观看位置50%时候判断hash中的提交数是否大于等于总提交数,当然可能存在用户拖动进度条的观看操作,所以我们可以设置一个因子控制总提交数,就比如0.5。这是我目前的写法。

介绍一下问答模块吧?

问答模块主要分为两个表,问题表和回答表。问答表中根据目标问题id和目标回答id又分为回答及讨论,前端展示的格式类是b站的评论区,一个问题中包含多个回答,一个回答中包含多个讨论。并且会展示对应的点赞数。这模块中我认为比较难的就是点赞功能的实现,我给您介绍一下点赞功能的实现吧?(Zset的大key用来存储对应业务的类型,因为后续排行榜也会使用当前的redis的结构,使用该大key做区别

最开始的时候我们每次点赞及取消赞的时候都直接打db,但是呢,在后续测试的时候发现当出现恶意的点赞或取消赞就会优酷db也就是同时出现大量的这种请求,直接走db明显是不合理的。我们就考虑能不能先将点赞的数据存储到redis中。因此就使用redis的set进行存储,key存储业务id,value存储userId集合,使用zset存储点赞总数,key存储业务类型,member存储业务id,scope存储总点赞数。在每次修改set中数据的时候会调用scard方法计算中点赞数,然后修改zset中的数据。通过xxl-job定时任务每30s取除所有的总点赞数,批量的修改数据中的对应业务的点赞数。

但是呢,点赞本来就是一个低频业务,在项目中也没有什么大咖引流。点赞的总数基本3000以内,所以直接打db也是可行的,再使用redis又需要一定的网络开销,所以还是要根据实际情况来考虑吧。热门模块的实现思路类似但是在实际db上还是区别比较大的,我给您介绍一下这个模块,您看行吗?(因为热门榜只会展示前100条,直接使用xxl-job做一次定时任务即可)

热门榜也是基于这种实现方案,热门榜主要的就是展示当月的热门课程的数据,使用set存储存储用户和课程的关系,使用zset结构存储热门片源的热度,通过定时任务来做数据批量插入的操作,我们的任务只要就是插入数据并清除缓存,在业务上我们的排行榜是以月为单位,所以每一个月只会产生100条数据,我们就直接使用同一张表存储热门榜的信息。(在每个月月初做任务)但是呢,我在做完该业务后呢,因为但是这个业务还在开发阶段,需求又发生了改变,要求热门榜做成每日的(在每天12:00做任务)。

因此在设计上呢,我们就不能将这些热门榜数据都存储到一张表上了,不然就会导致数据堆积在不建立索引的情况下,查询效率就会很低下。我们就要做分表的操作,这里我们没有使用shareing-jdbc而是使用mybatis的insert标签配合SPEL语句来名命拼接并创建表的(就是类是 hot_时间),在任务上多加了个小任务就是创建数据表。最终,插入热门榜数据并删除redis中对应set和zset中的数据,完成任务。(在业务上用户可以查询近七天的热门榜)

为了防止大量的热门榜表的生成,我们会使用定时任务每隔一天删除八天前的热门表。保证数据库中只会有七张热门表

问:那为什么要设计成三个子任务,你是怎么保证任务的顺序性的呢?
如果将三个任务和为一个大任务的话,在后续其中每个模块执行错误的时候,需要整个任务重新执行,而分为三个任务的话,只需要从失败的位置重新执行即可,当然前提需要保证任务的顺序性,效率上明是比较高的,在xxl-job的控制面板中新建任务的时候我们就可以设置子任务的id,从而控制任务的执行顺序。

介绍一下积分模块吧?

积分表主要的字段就是userId,积分量。我们的规则就是用户通过打卡,观看课程及评论。来获取积分,也就是就是签到来获取积分,可以提供积分来购买商品。每观看一节课+3积分,一条评论+1分,每天通过看课及评论最多可以获得20积分,普通打卡+1分,连续签到大于等于六天+2,连续签到大于13天+3分并且在月初的时候重置连续签到,签到没有限制积分的。

使用redis存储每天获取积分值,在每天最开始获取积分的时候就会将键值对并数值ttl,ttl就是24:00减当前时间,第二天0点重置。

在签到设计上是比较难的。我们主要就是使用redis的bitMap结构来实现的,使用二进制来每日的签到情况,主要就是通过redisTemplate.opsForValue().setBit("名字",位置, 值)。因为连续签到的话,它获取的积分是不一样的,我们就需要通过bitMap判断连续签到的天数。主要就是将获取的数据循环的与1做异或操作(&1)+ 右移一位的操作(>>>1)。这样就可以获取对应的天数,添加对应的积分给用户。

f2e80c4388d34c7abdb38355461feb02.png

 介绍一下优惠劵模块吧?

我只参与了部分的优惠劵的开发,主要就是对代码的阅读。在领优惠劵的时候就会存在超领的问题。 我们不使用传统的版本号锁来解决,版本号锁每次只能又一个线程领卷成功,但是呢,在优惠卷吃充足的时候效率非常低,我们的解决方案就是去修改sql语句,主要就是修改条件语句当前领取卷数小于总优惠劵。但是呢,在后续测试的时候发现在相同用户并发抢卷的时候还是有超领的问题。那我就需要保证每次相同用户只能由一个领卷请求成功。因为是微服务项目,所以使用Synchronzied明显是不合适的,我们使用redisson的可重入锁实现分布式锁。

在后续我们可能会使用到分布式其他类型的锁,所以我们实现了动态获取锁及获取锁策略。

使用自定义注解+AOP+工厂模式+策略模式。

自定义注解主要就是为了配置用户需要的锁类型枚举及策略枚举。

   AOP主要就是控制上锁和解锁的时机。

  工厂模式主要就是一个enumMap,key存储锁类型的枚举,value就对应redisson实现锁的方法。

提供对应的枚举执行对应实现锁的方法。

  策略模式主要就是一个上锁的抽象方法,多个策略内部内都去实现该抽象方法。提供传入锁实例和策略的枚举实现上锁。主要的策略就包括: 不重试后快速失败,不重试后快速结束,有限重试后重试超时后失败,有限重试后超时后报错、等等策略。

68fea4946cba4d1d94c56d7e116986f5.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值