在线教育平台项目总结

一、业务流程

1.企业(B)

内容管理、媒资、缓存、消息、任务调度、搜索

2.个人(C)

搜索、缓存、订单、支付、学习

二、关键技术

1.缓存三兄弟:

缓存穿透,高并发请求过来之后,查询数据库中存在数据,都发现缓存中没有,还是会去多次查数据库。如果查询数据库中不存在数据,高并发会一直查数据库,因为数据写入不到redis里。即请求穿透了缓存一直在查数据库。解决方案:1.参数校验,不符合规则直接返回2.把数据库中不存在数据也给缓存到redis,查缓存时也有该key,但是值为null。这种情况要加过期时间,防止数据库中什么时候真的有了该key。

缓存雪崩,缓存的大量key失效,因为他们设置了相同的缓存失效时间。解决方案:1.使用同步锁,只允许一个线程访问,性能不高。2.对同一类型的key设置不同的过期时间。3.缓存预热,取出来加随机的过期时间。

缓存击穿,大量并发访问同一个热点数据,热点数据失效后同时访问数据库。解决方案:1.同步锁,性能太低。不要直接在方法名上加synchronized,只锁查询数据库的代码,缓存查询可以高并发访问,锁进来后还要再查一次缓存。2.热点数据不过期。

2.JWT登录:

使用jwt(json web token令牌可以自己校验,无状态认证,不存储用户身份。有三部分,header(头部),内容(用户的信息),签名(前两部分想加再加密),资源认证服务有密钥.密钥分为对称性加密和非对称性加密。对称性能高(即认证服务的和资源服务的密钥一样,非对称加密认证自己保留私钥,公钥下发给客户端和资源服务。内容可以根据token还原,放一些公开信息(比如头像).管控起来后http接口测试就不能正常进行,要带token去访问。在SecurityContextHolder中可以拿到用户信息(存储在jwt的token中)

要自定义UserDetailService类连接用户数据库,传给username,连同用户名、密码、权限一起返回给spring security框架。密码不是明文存储,采用bcrypt加密,每次生成的密码都不一样。将用户信息转成json传回,否则没有头像等信息,这个过程中要将密码等敏感信息置空。获取的时候可以写一个工具类json转对象

由于有很多可能的提交信息方式,比如:账号密码,手机验证码,微信扫码,因此需要统一认证,新建一个DTO类。userdetailservice原本传入的是username,现在要传入的是DTO类的json串。使用fastjson

重写DAOAuthenticationProvider(DaoAuthenticationProvider通过UserDetailsService以及PasswordEncoder,将用户名密码替换成UserDetails和Authorities),authentication(认证)authorization(授权)不止使用密码校验,所以要重写方法。一个接口有很多个实现类,在service中增加名字(password_authservice,wx_authservice)

3.幂等性、索引同步:

本地消息表+任务调度的机制来完成分布式事务的最终数据一致性的控制。建的本地消息表和课程发布表在同一个数据库,使用数据库事务控制,保证发布了就一定会在消息表中,然后任务调度定时调度消息表存储给redis,es,minIO。若当中有失败的,则下次定时会继续发,已经成功的根据幂等性,会跳过。

4.分布式锁

本地锁每个JVM都会查一次数据库。实现方案:1.数据库乐观锁(谁update成功)2.基于redis的set nx(不存在才可以在redis里面存,看是否可以set成功),set lock01 01 NX EX 30要记得设置过期时间,否则其他拿不到锁,锁过期时间很难设置,可以手动删除锁,为了防止删除别人的锁,可以判断锁的值是不是自己设置的。代码不具有原子性,要借助lua脚本,让cpu一次性执行完毕,可能有断电等问题,过期时间的值还是不精确。3.zookeeper4.redisson,自旋锁(非阻塞锁),另起线程看门狗,看线程是否干完活,可以续过期时间。

悲观锁synchronized总认为有线程抢锁,拿到锁后再执行。乐观锁认为没有线程抢锁,尽管执行,如果没有执行成功就重试。

5.数据库事务控制:

关于文件上传过程中的事务控制,抽取出只有数据库操作的方法来加。在类内curProxy通过代理对象调用。文件名为md5值+.jpg ,.mp4.content-type来判断是图片还是文档、视频

脏读:指的是读到了其他事务未提交的数据,未提交意味着这些数据可能会回滚

不可重复读(Update):指的是在同一事务内,不同的时刻读到的同一批数据可能是不一样的

幻读(Insert):假设事务A对某些行的内容作了更改,但是还未提交,此时事务B插入了与事务A更改前的记录相同的记录行,并且在事务A提交之前先提交了,而这时,在事务A中查询,会发现好像刚刚的更改对于某些数据未起作用。

6.熔断降级:

Hystrix框架实现熔断、降级处理。开启feign熔断保护,定义降级逻fallbackFactory,降级处理逻辑(返回一个null对象,上游服务请求接口得到一个null说明执行了降级处理。)@feignClient,微服务雪崩A->B->C,Cdown了,会影响B进而影响A。下游服务异常熔断后,上游服务不再调用异常的微服务而是执行了降级处理逻辑(一种保护系统的手段),使用hystrix框架实现熔断、降级处理。解决:定义fallback类,重新处理,这种方法拿不到熔断异常信息。定义fallbackfactory类,出现熔断之后,上游调用create方法来进行降级处理(可以拿到熔断的异常信息)

7.异常处理:

抛给框架处理。运用AOP思想,@ControllerAdvice控制增强,通常和@ExceptionHandler结合使用。增强类处理。在base里写,和前端约定返回的异常信息模型,新建本项目自定义异常类型(继承runtimeexception),新建类写异常处理(可以区别捕获的异常类型)。

异常处理除了输出在日志中,还需要提示给用户。1.自定义项目异常类,使用该类的cast函数在业务代码中throw异常,在全局异常处理器(加了@RestControllerAdvice控制器增强和@ExceptionHandler)中处理该异常,定义restErrorResponse类实现序列化接口return给前端。

异常处理器中要解析jsr303的异常,否则会报unknow的统一异常信息,因为他不属于xuecheng的程序员自定义类型异常。前端后端都要校验,为了防止使用postman等访问后端。

多个接口共用模型类(新增id为空,但修改id不为空),使用分组校验。

8.权限控制:

分两种方式,基于角色的访问控制和基于资源的访问控制。if里面写的是角色还是是否有这个权限(一个属性字段)。基于资源的访问控制健壮性更好。使用@PreAuthorize("hasAuthority('权限标识符')")进行控制,标识符会在数据库中定义。在方法前面加该注解,拥有此权限才可以访问该方法。

细粒度授权(数据权限),对某一资源有访问权限,但是可以访问到的数据不一样,比如两个培训机构。course_base中有培训机构id。在service接口根据参数去做,security框架无法实现

9.跨域:

跨域是基于浏览器的同源策略,协议(https)、主机、端口三者,

1.通过script标签的src属性进行跨域请求

2.在响应头添加 Access-Control-Allow-Origin:*

3.通过nginx代理跨域,因为服务端之间没有跨域

10.页面静态化方案

课程信息页面的访问量较大,并且课程信息发布后在一段时间不会修改,这里使用Freemarker(thymeleaf)静态化技术将课程信息页面静态化,提前生成html页面并通过媒资管理模块的文件服务上传到文件系统,用户浏览课程信息页面通过分布文件系统浏览,提高了课程信息页面访问性能。

11.JVM的GC机制:

(1)哪些内存需要回收?

堆和方法区,程序计数器、虚拟机栈、本地方法栈3个区域是随线程而生,随线程而灭的

(2)什么时候回收?

判断对象是否可以回收,有两种比较经典的判断策略。

  • 引用计数算法,count+1-1,=0时失效
  • 可达性分析算法,为起点开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots 没有任何引用链相连时。

(3)如何回收?

  • 标记-清除(Mark-Sweep)算法,大量不连续的内存碎片
  • 复制(Copying)算法,(新生代)当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
  • 标记-整理(Mark-Compact)算法,(老生代)让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

12.输入网址到显示:

1、输入网址
2、DNS解析获取域名对应的IP地址
3、建立TCP连接
4、web浏览器向web服务器发送HTTP请求
5、服务器的永久重定向响应
6、浏览器跟踪重定向地址
7、web服务器做出应答
8、浏览器显示 HTML
9、浏览器发送请求获取其他嵌入在 HTML 中的资源
10、web服务器关闭TCP连接

三、组件

1.Nacos:

服务注册中心和配置中心

namespace、group、dataid。

namespace(开发环境,测试环境,上线环境)和group(学成在线,瑞吉外卖)。

Dataid:  包括三部分:服务名、环境名、扩展名,

content-service-dev.yaml配置文件  由(content-service)-(dev). (yaml)三部分组成

server:servlet:context-path: /contentport: 63040test_config:a: 3ab: 3b#配置本地优先
spring:cloud:config:override-none: true

2.Gateway:

负载均衡、路由转发、统一鉴权

前端请求到Nginx,通过负载均衡到Gateway网关,通过网关将请求转发至各个微服务。网关从nacos读取服务地址

3.Redis

白名单、热点数据

实现分布式锁,避免课程查询等公开接口出现缓存击穿问题

4.RabbitMQ

将支付结果发通过给fanout类型的交换机,由交换机将消息广播发送至每个接收支付结果的微服务。

5.Elasticsearch

倒排索引,对课程发布信息进行索引和搜索。

布尔查询、聚合搜索、过滤器、高亮显示等功能

6.XXL-Job

由调用中心和执行器组成,调用中心负责按任务调度策略向执行器下发任务,执行器负责接收任务执行任务。主要用于索引同步

配置调度过期策略和阻塞处理策略,避免同一个执行器多次重复执行同一个任务

调度过期策略:忽略:调度过期后,忽略过期的任务,从当前时间开始重新计算下次触发时间;
阻塞处理策略:丢弃后续调度。

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

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

相关文章

升降梯人数识别摄像机

升降梯人数识别摄像机是一种智能监测设备,主要用于实时识别和计算升降梯内乘客的数量。通过搭载先进的图像识别技术和人工智能算法,该设备可以准确监测乘客进出数量,提供重要数据支持和信息反馈,帮助管理人员有效管理升降梯运行&a…

STM32学习和实践笔记(4): 分析和理解GPIO_InitTypeDef GPIO_InitStructure (a)

深入分析及学习一下上面这一段代码的构成与含义。 首先,这个GPIO_InitTypeDef GPIO_InitStructure;其实与int a 是完全类似的语法格式以及含义。 GPIO_InitStructure就相当于a这样一个变量。不过从这个变量的名字可以知道,这是一个用于GPIO初始化的结构…

界面控件DevExtreme JS ASP.NET Core 2024年度产品规划预览(一)

在本文中我们将介绍今年即将发布的v24.1附带的主要特性,这些特性既适用于DevExtreme JavaScript (Angular、React、Vue、jQuery),也适用于基于DevExtreme的ASP.NET MVC/Core控件。 注意:本文中列出的功能和特性说明官方当前/预计的发展计划&a…

hcip实验4:gre mgre ppp综合实验

实验拓扑: 实验目的: 1.R5为ISP,只能进行IP地址配置,其所有地址均配为公有IP地址 2.R1和R5间使用PPP的PAP认证,R5为主认证方;R2与R5之间使用ppp的CHAP认证,R5为主认证方;R3与R5之间使用HDLC封装; 3.R1、R…

MQ消息队列详解以及MQ重复消费问题

MQ消息队列详解以及MQ重复消费问题 1、解耦2、异步调用3、流量削峰4、MQ重复消费问题,以及怎么解决?4.1、重复消费产生4.2、解决方法: https://blog.csdn.net/qq_44240587/article/details/104630567 核心的就是:解耦、异步、削锋…

当面试官问你插入排序算法,你敢说自己会吗?

算法学习的重要性 在程序员的世界里,算法就如同一座桥梁,连接着问题与解决方案,是实现优秀程序的关键。 掌握算法,就能够在面对各种问题时,找到最合适的解决方法,以最少的时间和空间,实现最优的…

解析基础设施即代码:重新定义云管理

由于现代架构、应用程序接口和相互关联的服务之间的互联性越来越强,云基础设施的复杂性也与日俱增。随着需要管理的云资源数量不断增加,企业开始采用基础设施即代码(IaC)来解决云应用的复杂性和相互依赖性问题。 IaC 提供各种工具…

《深入探索 Netty 框架:构建高效稳定的网络应用》

大家好,今天我将为大家深入介绍 Netty 框架,并分享一些基于 Java 实现的代码示例。 Netty 是一个非常强大的网络框架,它提供了一种高效、可靠的方式来构建网络应用程序。它具有以下优点: 高性能:通过优化的 IO 处理和线…

波长可调激光器中的增益芯片和SOA

----翻译自SATO Kenji,ZHANG Xiaobo于2019年发表的文章 摘要: 本文讨论了用于波长可调激光器(TL)的半导体光放大器(SOA)和增益芯片的设计规则。即与常规SOA或激光器相似,也有一些不同之处。位…

酷开科技不断深耕智能电视领域,用酷开系统带给消费者更多可能性

在这个网络快速发展的时代,电视行业也发生了巨大变革。与以往单纯的“看”电视不同,人们不再满足于现有的状态,消费者对电视娱乐的追求更加丰富,这也就带给智能电视产业无限的发展可能。酷开科技瞄准这一产业趋势,不断…

家庭影院触摸屏中应用的电容式触摸芯片

家庭影院的主要组成部分包括显示设备、音响设备、信号源和接线设备等。其中,显示设备通常采用高清电视或投影仪,音响设备包括功放、音箱、低音炮等,信号源可以是蓝光光盘、游戏机、有线电视、网络电视等多种媒体设备。 家庭影院的影像信号通…

[C#]winform使用OpenCvSharp实现透视变换功能支持自定义选位置和删除位置

【透视变换基本原理】 OpenCvSharp 是一个.NET环境下对OpenCV原生库的封装,它提供了大量的计算机视觉和图像处理的功能。要使用OpenCvSharp实现透视变换(Perspective Transformation),你首先需要理解透视变换的原理和它在图像处理…

vulhub打靶记录——healthcare

文章目录 主机发现端口扫描FTP—21search ProPFTd EXPFTP 匿名用户登录 web服务—80目录扫描search openemr exp登录openEMR 后台 提权总结 主机发现 使用nmap扫描局域网内存活的主机,命令如下: netdiscover -i eth0 -r 192.168.151.0/24192.168.151.1…

适配器模式:桥接不兼容的接口

在软件开发中,我们经常会遇到需要将现有的类与新的系统或客户端集成的情况,但这些类可能因为接口不兼容而无法直接使用。适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口之间能够相互协作&#x…

css预编译sass,css也可以变得优雅

1. 嵌套选择器 #content {article {h1 { color: #333 }p { margin-bottom: 1.4em }}aside { background-color: #EEE } }编译后 #content article h1 { color: #333 } #content article p { margin-bottom: 1.4em } #content aside { background-color: #EEE }2. 变量声明和使…

力扣贪心算法--第一天

前言 今天是贪心算法的第一天,算法之路重新开始! 内容 之前没了解过贪心算法。 什么是贪心 贪心的本质是选择每一阶段的局部最优,从而达到全局最优。难点就是如何通过局部最优,推出整体最优。 一、455.分发饼干 假设你是一…

题目:学习static定义静态变量的用法

题目:学习static定义静态变量的用法    There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog content is all parallel goods. Those who are worried about being cheate…

JS中的运算符

1.&& 逻辑与 &&会从左到右执行表达式,直到某个表达式的运行结果返回false,如果全部为true,则返回最后一个中表达式的执行结果 console.log(1 && 2) // 2 console.log(1&&10&&15) // 15 console.log(1&&0&&am…

Android的图片加载框架

Android的图片加载框架 为什么要使用图片加载框架?图片加载框架1. Universal Image Loader [https://github.com/nostra13/Android-Universal-Image-Loader](https://github.com/nostra13/Android-Universal-Image-Loader)2. Glide [https://muyangmin.github.io/gl…