java面试项目三:在线教育

news2024/11/15 23:27:38

1、项目简介

项目规模:15人

项目周期:2021.5-至今

开发环境:Intellij IDEA、Maven、JDK1.8、GIT

所用框架:Spring、SpringBoot、Mybatis-Plus、SpringCloud、Shiro、XXL-Job、

其他技术:RocketMQ、Redis、Mysql、MongoDB、ElasticSearch、JWT、Nginx、Nacos、Gateway、Nginx、EasyExcel、Sentinel

项目描述:XX在线教育是垂直的小学、初中、高中知识学习网站,课程紧跟前沿理念,帮助学生在当今课程体系体量压力较大的环境下,保证学生学习成绩提高,课程设置科学,满足不同基础用户的学习需求,快速匹配学习路线,使教育资源共享化,降低了学习门槛,课程主要分为免费课,VIP课,付费课三种,平台主要通过课程抽成,VIP会费及广告收费收取利益,平台主要分为网站前台,运营商后台,讲师后台等三方面组成

技术描述:

                  1、SpringCloud来建立各微服务之间的实时/异步的业务调用

                  2、通过Redis来完成首页轮播图缓存展示,分布式幂等校验,以及分布式锁的应用,课程排行等

                  3、RocketMQ来解耦服务间信息的同步,分布式事务,确保最终一致性,并对晚上起到削峰的作用

                  4、GateWay用来统一路由、对各业务线请求进行鉴权、限流处理提高系统健壮性

                  5、借助MongoDB完成评论,反馈留言等非核心业务数据的存储,使用EasyExcel导入导出

                  6、XXL-Job以及JavaMail实现定时发送邮件给老师统计本月课程售卖情况以及购买人群相关信息

                  7、通过阿里云第三方技术实现OSS图片上传,Alidayu短信发送,视频点播以及AliPay支付功能

                  8、借助ElasticSearch完成全文检索以及根据用户喜好定向推送课程(Redis)等

                  9、Nginx进行请求分发,负载均衡,Sentienl对高压接口进行限流和降级

项目职责:

            1、配合产品讨论业务方案,并持续跟进,参与项目的需求探讨

            2、负责后台广告模块、智能推荐的日常开发

            3、对核心业务的攻关,并提供相关解决方案,对其他需求开发的补位

            4、修改测试人员提出的BUG,编写相关接口文档,配合前端人员完成接口联调

            5、完成上级交代的其他任务,根据需求文档完成所分模块进行日常开发工作

二、项目介绍 

我最近参与的这个项目是服务于在职提升人员为主的在线教育平台,通过和.

个人老师入驻形式,向学习者提供在线和点播的网络授课资源。

对于上架的课程我们分成了免费与付费两种课程,所以平台是通过抽取佣金的方式来进行盈利的。包括像首页我们也是有广告投放功能,这也是平台盈利的方式之一。

整个平台主要分为网站前台、运营商后台、讲师管理后台三个子系统,我就从整体项目的架构方面来给您介绍吧。

三、项目开发流程 

在我们项目立项以后,项目经理、研发部和产品部一起针对项目进行了需求分析会议。会议结束以后,产品部门会给我们研发部提供需求文档,然后我们研发部再进行开会分析这些需求,根据需求进行分组后,分组后再进行讨论、创建表、写排期等,开发文档我们使用是这个swagger自动生成API文档。然后就是和我们项目老大一块去搭建框架,然后提交到远程仓库master上,由组员进行拉取分支,接下来就是根据需求进行开发。

四、项目架构图 

 

五、架构介绍 

1、微服务架构

在设计的时候考虑到项目是2C的(面向学员个人的),随着项目的运营,访问量也会不断增加的,所以我们这个项目选用的是SpringCloud+Nacos的微服务架构模式,其实当时也有考虑过dubbo+zookeeper;使用Dubbo+zooKeeper的话服务之间的依赖性太强,综合考虑还是选用了SpringCloud+Nacos的微服务架构,您也知道这个SpringCloud提供了很多成熟的服务组件,能为微服务架构提供一站式的解决方案, 而且调用方式使用的是更加轻量的RestFul API,服务与服务之间不存在耦合和依赖,只需要遵守规范和约定就能互相调用。并且每个微服务是使用Spring Boot来开发的,开发速度也很快,而且呢也很容易和其他技术进行整合。

2、入口层

首先是入口层,我们在这里用Nginx做了负载均衡和反向代理,对用户请求进行了转发。它的响应速度、抗并发、限流这些功能性能上都比较高,所以咱们业内用的也比较多。为了防止单点故障,我还给Nginx做了主备。像静态资源、详情页面也都是用它来做处理的,实现了资源的动静分离

3、网关层

接下来是网关层,为了保证服务的安全性,用zuul网关设置了微服务的统一请求入口,帮我们完成请求路由、校验过滤这些功能,对zuul网关也配置了集群,保证网关服务的一个高可用嘛。

4、服务层

再往下是服务层,我们是将服务统一注册到Nacos上面的, Nacos作为整个微服务的注册中心,同时也是配置中心,所有的配置都能传到Nacos上(Nacos的概念),加上个@RefreshScope注解就可以实现配置的实时刷新功能,服务之间通过Feign接口调用。因为Feign集成了Ribbon和熔断器(Hystrix),所以请求过来之后会通过Ribbon的负载均衡分配到一台机器并进行调用。也有效防止了服务扇出调用导致的雪崩效应,让系统更加稳定。由于咱们这个是分布式系统,许多依赖难免会调用失败,比如出现超时、异常这些,那熔断器就能帮我们避免因为依赖调用问题,而导致的系统级联故障,从而提高系统弹性。链路调用出现问题的话,定位起来也方便,用zipkin就行。

5、数据层

再往下就到了数据层,使用的是MySQL数据库,数据库的重要性就不用多说了,“非必要请求,肯定是不让它不走数据库的”。像一些“热数据”呢,是交给Redis处理的;对于项目中用户评论这样的数据,数据量特别大,访问也很频繁,但是结构比较松散的数据,是用MongoDB数据库存储的;搜索这方面使用的是ElasticSearch搜索引擎,提高搜索响应速度,因为ES相对于其他搜索引擎,它还有一个文件系统缓存(ES的近实时 或 文件系统缓存的作用),所以实时性比较高,ES还支持分布式,加入节点自动均衡等特点。当然,对他们也都做了集群配置,保证高可用嘛。除了借助中间件的方式,我们也对MySQL也做了主从同步,提高数据的安全性。另外,对于一些大表,比如订单表,就用mycat做了拆分,减轻了单表的压力。

6、消息队列

除此之外呢还使用了一些其他的中间件作为架构的补充,比如一些需要异步处理的场景,我是借助了RocketMQ的消息队列来处理的,对于项目中订单支付成功增加积分的业务,为了保证原子性,使用的RocketMQ的分布式事务消息来解决的。当然,对它也做了集群配置,保证它的一个高可用。

 六、项目模块-课程搜索

1、当学员点击分类查询或者是在搜索框中搜索进行展示的时候,需要到数据库进行联查多张表比如:(课程标签表...),然后再到前台进行展示;但是在数据库中进行联查多张表的话我考虑这样几个问题:

    1. 会增加数据库连接数,给数据库造成压力;
    2. 联查数据量大的话查询效率会很低;
    3. Mysql做like这样的模糊查询,效率和结果都不尽人意;

所以我就考虑使用索引库去解决这个问题

原因就在于mysql采用的是正排索引,所谓的正排索引就是我们得从头到尾把数据查询一遍,查看哪些数据里面包含我们要查询的关键字,效率非常低,其次就是mysql也没有分词,而且mysql索引存储的是字段的内容(如果字段内容过长,就只存前几位的内容为索引)

-----------------------------

2、但是倒排索引正好相反,他维护了一个字典表,key就是我们要搜索的关键词,value是包含这些关键词的数据的id,我们只要对比字典表就能知道哪几条数据有我们要查询的关键字,然后拿到这些数据的id,马上就能找到我们要找的数据了。

---------------------------------

3、当前主流的索引库有solr和elasticSearch,考虑到solr虽然搜索方面相对强大一些但是他的实时性并不高,问题就在于solr在建立索引时,搜索效率会下降,相比起来es的实时搜索效率会更高一些。毕竟es的搜索被称为近实时,而且天然支持分布式也是我们当时选择的一个原因。

----------------------------------------

4、

这里说一下ES的近实时:

Es设计的理念就是分布式搜索引擎,底层其实还是基于lucene的。核心思想就是在多台机器上启动多个es进程实例,组成了一个es集群。es中存储数据的基本单位是索引,一个索引差不多就是相当于是mysql里的一个库。index -> type -> mapping -> document -> field。

简单的说一下就是一个index包含多个type,type由多个mapping组成,type中有多条document,每条document有多个field。

接下来咱们再说一下而是其他比较好的地方:使用ES可以去实现模糊搜索、分词查询、高亮显示、聚合。

IK分词器:ES默认是自带分词的。但是ES是国外的产品,他们只对英文分词效果好,而对我们汉字它会将每一个汉字分成一个词语,很显然这是不行的。因此我们当时选择了国内比较好用的分词器IK分词器。(如果问到其他的分词器可以说:庖丁分词器,ICU 分词器。thulac分词,(清华大学分词器)

查询高亮:ES在查询的时候我们可以设置查询关键字的高亮显示,指定高亮的样式,其实也就是拼接上html的样式标签。

索引库的更新:索引库的更新我们使用的是logstash进行数据库和ES的数据同步,他的工作原理很简单,就是定时执行我们配置文件中所定义的sql语句,他需要两个插件 一个是读取msql数据的插件,一个是同步ES的插件。

七、项目模块-广告模块 

1、广告页

由于广告页访问量比较大,而且更新较少,所以我们用了redis缓存,redis 对于1000万条以内的数据性能是比较高的,并且支持持久化和冷热交互。另外它还支持集群模式、哨兵监控和主从复制,我们当时使用了集群模式。redis和spring整合后有一个模板工具叫redistemplet  通过redistemplete可以存储多种数据类型。

2、广告投放

广告的收费设计有很多种,比如说CPC(点击次数)、CPA(转化效果)、CPM(千次曝光)等收费方式,我们采用的是CPM的计费方式。

首先,我们用Quartz定时器做了一个定时任务,就是定时获取广告缓存与数据库进行同步,然后对缓存中所有广告的曝光量进行判断,如果曝光量为0则无需任何操作,如果曝光量不为0,则对该用户的账户余额进行相应扣费(10元/1000次),扣费完成后将曝光量重置为0。然后判断账户余额是否小于100,如果小于100,就将该用户正在投放的所有广告进行数据同步,然后删除广告缓存,并将广告状态修改为待投放,同时调用短信接口发送短信提醒用户余额不足。

由于首页投放的广告会出现多个用户同时点击而被扣费的情况,为了避免数据不一致,我们使用了分布式锁,目前实现分布式锁的技术有很多, 我们在项目中是使用Redis来解决的。(redis分布式锁)

3、限时秒杀

我们每天会在定时发送一定数量的优惠券用于给用户抢券,为了严格控制优惠券的发放数量, 我是借助redis的decr来做的, 首先他们是可以保证原子性的, 我们提前将优惠券数量放到redis中, 当用户点击抢券的时候发送请求到服务端, 首先进行抢券开始时间的查询,如果当前时间小于抢券开始时间,直接返回错误,防止用户拿到接口直接调用的问题,然后判断优惠券的数量,如过数量小于等于0直接返回失败,这样的话后面的大量请求无需给系统带来压力。

如果当前数量还有的话,那么会根据当前的用户id +“counts”进行redis查询,我们是在抢购成功时通过redis给当前用户做了一个标记,目的是避免一个账户重复抢券的情况,然后如果数量充足,且无重复秒杀情况,执行decr操作,decr操作的话会执行减一并且返回当前的值,然后再次进行判断当前值是否小于0,如果是则返回失败。否则调用redis通过用户id +“counts”做key,值是默认给的一个success代表抢券成功(就是刚刚所说的重复抢券问题),然后mq异步的方式给用户-优惠券表中增加数据。

4、购物车

在详情页点击“加入购物车”或者“查看购物车”的时候我们做了一个判断,假如学生没有登录,我们会将学生加入到购物车中的课程信息存入到cookie中,然后在学生点击“去结算”时提醒学生进行登陆,登录成功后将购物车中的信息和学生对应的购物车中的信息关联起来存入到redis中,如果学生已经登录,那么学生将课程加入购物车时直接将课程信息存入redis中,之所以将信息放redis中的目的就是为了防止学生频繁操作购物车,增加系统压力,而redis可以看做是一个持久化的缓存。之后学生填写完收获地址信息以及选择支付方式,点击“提交订单”时会将redis中的信息取出来插入到数据库的订单表中,并清除redis中该学生购物车的信息,同时将订单表中该条记录的状态设置为1。 接下来学生可以选择进行支付,支付成功后会将订单的状态改为2,并将支付宝返回的交易信息存入数据库的交易记录表中,同时调用阿里接口发送短信通知学生支付成功,此时的订单已进入后台去处理,前台再查看订单时,我们会根据状态显示不同的信息,比如:状态1是未支付订单,状态为2的是支付成功等待审核状态。

八、项目模块-热门推荐

1、我们首页有一个课程推荐栏,当学员第一次访问时直接推荐当前最热门,评分最高的课程,之后随着学员浏览的课程我们会直接在课程推荐中推荐学员最近经常访问的课程进行推荐.

2、具体的实现是我们定义的标签,在讲师上传课程的时候需要指定添加的标签,我们并没有直接通过课程的分类来进行推荐,因为课程分类太广泛,局限性很大,而我们使用标签可以很好的扩展课程的维度。

3、而且考虑到首页访问量巨大,课程数据很多的情况,所以我当时采用的是redis缓存技术+ES搜索引擎实现的.来提高抗并发的能力以及记录课程标签的检索速度.

4、该模块分为两种情况,第一种就是用户不登录的情况,如果用户不登录的话我们就展示本站所有课程访问量前十的课程进行展示。

4.1.首先每当用户点击课程的时候我们都会将该课程的id作为key然后判断redis中是否存在该key,如果不存在,那就score为1并存入redis的zset数据结构中。如果存在就进行incr操作。

4.2.然后我们会从redis中取出排名前十的课程ID在ES索引库中使用terms查询课程数据,并返回页面进行展示。

这里我们只是将课程ID存入Redis,并没有将整个课程数据存入,因为内存非常的珍贵,我们不可能将那么多数据存入缓存,而且拿到课程ID之后是走的ES,而没有去给数据库增加压力.

5、第二种在学员登录的情况下,当学员每点击一次课程,会先判断redis中是否存在该课程标签.如果没有就直接将学员id加浏览量标识(”-num”)作为key,课程标签作为value存入redis缓存中,并将zset的分数设为1.如果redis中已存在该课程标签,就使用increment方法将分数+1.并且同时会将学员id加时间标识(“-time”)作为key,课程标签作为value,当前时间的时间戳作为分数存入缓存.目的是为了记录各个标签的访问时间.

6、此外我们使用quartz定时器每隔一段时间就查询这两个zset.将访问时间最近的三个标签删掉,目的是排除学员误触的情况.然后将访问量前三的课程标签以zset类型存入定向推荐缓存中.分数分别设为3,2,1.然后再获取学员最近访问的三个标签,也放入该缓存中,分数统一设为3,如果标签已存在直接使用incr+3.(这个缓存用来做定向推荐的,每一小时更新一次).

7、当学员再次访问首页时获取用来定向推荐的缓存中的标签,然后进行多字段查询elasticsearch拿到课程然后在课程推荐中展示。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/564257.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

梦x西游H5页面搭建教程Centos

梦x西游H5页面搭建教程Centos 大家好,我是艾西,今天给大家分享一款H5页面的游戏搭建教程。版本分为三种族、四种族、五种族,大家可以自己喜欢哪个版本自己尝试开服架设等,今天我们以三种族的为演示。 那么让我们直接进入正题开…

9. Linux下实现简单的socket通讯

本文简单介绍了UDP传输层协议,并在Linux下实现简单的socket通讯 一、UDP UDP(User Datagram Protocol,用户数据报协议)是一种无连接的传输层协议,它不保证数据包的可靠性和顺序。UDP在IP协议的基础上增加了简单的差错…

es 四 快速入门****

目录 查看集群状态 **颜色: 查看集群索引 **简单的索引操作 kibana 创建索引模式 Es 存储 文档 json数据 查看集群状态 get /_cat/health 带上表头 get /_cat/health?v **颜色: 绿色: 主分片副本分片可用 黄色: 主分片可用、副本分片不可用 红…

Java 与数据结构(6):快速排序

ChatGPT 中文指南(大全) 内容包含:如何开通chatgpt、chatgpt的同类站点、prompts 、AI绘图、ChatGPT 工具、相关报告论文、ChatGPT应用项目等 链接:ChatGPT 中文指南(大全) 指令指南,精选资源清单,更好的使用 chatGPT 让你的生产力…

C++线程池介绍和C++代码实现

1、介绍 1.1 线程池应用场景 在进行创建线程任务时,如果需要频繁的创建线程、销毁线程,这样会极大地降低效率,因为创建线程也是需要时间的,一个完整的线程处理运行时间包括:线程的创建时间、线程运作时间、线程的销毁…

【C++】-string的介绍以及使用(迭代器的介绍和使用)

💖作者:小树苗渴望变成参天大树 ❤️‍🩹作者宣言:认真写好每一篇博客 💨作者gitee:gitee 💞作者专栏:C语言,数据结构初阶,Linux,C 如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点…

谈谈国产化CRM系统市场前景与发展趋势

随着数字化时代的到来,CRM系统已经成为企业管理中不可或缺的一部分。在过去,大多数企业都选择使用海外CRM系统,比如Salesforce、SAP等,但随着国内CRM系统的逐渐发展,越来越多的企业开始将目光转向了国产CRM系统。 一、…

Qt--自定义控件

写在前面 Qt中提供了应用在各种场景的控件,使开发人员在实际工作中选择。但有些特定的场合中这些控件并不满足需要时,Qt允许使用自定义的控件。 例:我们在工作中有这样一种需求,点击按钮会根据一些其他状态来显示不同的图片&…

在外远程登录局域网下的象过河ERP管理系统,无需公网IP

文章目录 概述1.查看象过河服务端端口2.内网穿透3. 异地公网连接4. 固定公网地址4.1 保留一个固定TCP地址4.2 配置固定TCP地址 5. 使用固定地址连接 转发自CSDN远程穿透的文章:公网远程访问公司内网象过河ERP系统「内网穿透」 概述 ERP系统对于企业来说重要性不言而…

3D可视化智慧档案馆一体建设平台设计的主要依据

1、《中华人民共和国档案法》 2、《中华人民共和国档案实施办法》 3、GB/T 9386-1988《计算机软件测试文件编制规范》 4、GB/T 15532-1995《计算机软件单元测试规范》 5、GB/T 30961-2014 嵌入式软件质量度量 6、GB2421-89 电工电子产品基本环境试验规程 7、GB16796-2009…

【1377. T 秒后青蛙的位置】

来源:力扣(LeetCode) 描述: 给你一棵由 n 个顶点组成的无向树,顶点编号从 1 到 n。青蛙从 顶点 1 开始起跳。规则如下: 在一秒内,青蛙从它所在的当前顶点跳到另一个 未访问 过的顶点&#xf…

网终安全技术(刘化君)课后被略的答案

目录 8.HTTP客户机与Wb服务器通信通常会泄露哪些信息? 9.在TCP连接建立的3次握手阶段,攻击者为什么可以成功实施SYN Flood攻击?在实际中,如何防范此类攻击? 常用的网络漏洞扫描技术有哪几种?试举例说明。…

Visual Studio 2010环境新建C工程项目

新建C工程项目 文章目录 新建C工程项目前言1、新建空项目2、编写程序2.1 Hello World2.1 执行.exe文件 3、总结 前言 学习C语言使用的编译器比较多,常见的有VC6.0、Dev-C、Visual Studio、CodeBlocks等环境软件。 Visual Studio和CodeBlocks的功能就稍微强大很多&a…

MySQL_5 有丶牛逼的查询语句

目录 一、分组查询 1.基本语法 : 2.代码演示 : 二、分页查询 1.基本语法 : 2.代码演示 : 三、多表查询 1.定义 : 2.语法 : 3.演示 : 四、嵌套查询 1.定义 : 2.单行子查询 : 1 特点 2 演示 3.多行子查询 : 1 特点 2 演示 4.临时表 : 1 定义 2 演示 5.多列子查询 …

Emacs之实时渲染markdown(九十五)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…

Web安全常见攻击

前言 本篇主要简单介绍在 Web 领域几种常见的攻击手段。 1. Cross Site Script(XSS跨站脚本攻击) 首先插播一句,为毛叫 XSS,缩写明显是 CSS 啊?没错,为了防止与我们熟悉的 CSS(Cascading Style Sheets&am…

类ChatGPT的各种语言大模型LLM开源Github模型集合​

作为开发人员,面对堪称科技奇点爆发的ChatGPT,我们如何应对。当然是努力跟进,虽然ChatGPT不开源,但是有诸多不输ChatGPT的各类语言大模型LLM有分享。我们筛选出其中影响力较大的各个开源Github仓库,收录到 类ChatGPT的…

由浅入深Dubbo网络通信协议大全

目录 1 网络通信协议1.1 dubbo协议1.2 rmi协议1.3 hessian协议1.4 http协议1.5 webservice协议1.6 thrift协议1.7 rest协议1.8 grpc协议1.9 memcached协议1.10 redis协议 2 序列化实现剖析 1 网络通信协议 在之前的内容中,我们讲解了消费者端服务发现与提供者端服务…

局部最小值问题

局部最小值问题 自写&#xff1a; // arr 相邻的数不相等&#xff01; 返回一个局部最小的下标public static int oneMinIndex(int[] arr) {if(arr null || arr.length 0) {return -1;}if(arr.length 1) {return 0;}int L 0;int R arr.length - 1;if(arr[L] < arr[L 1…

C++判断大端小端

C判断大端小端 1. 基础知识 大端小端其实表示的是数据在存储器中的存放顺序。 大端模式&#xff1a;数据的高字节存放在内存的低地址中&#xff0c;而低字节则存放在高地址中。地址由小到大增加&#xff0c;数据则从高位向低位存放&#xff0c;这种存放方式符合人类的正常思维…