学成在线----day8

这篇具有很好参考价值的文章主要介绍了学成在线----day8。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、课程发布

为了提高网站的速度需要将课程信息进行缓存,并且要将课程信息加入索引库方便搜索,下图显示了课程发布后课程信息的流转情况:
学成在线----day8
1、向内容管理数据库的课程发布表存储课程发布信息,更新课程基本信息表中发布状态为已发布。
2、向Redis存储课程缓存信息。
3、向Elasticsearch存储课程索引信息。
4、请求分布文件系统存储课程静态化页面(即html页面),实现快速浏览课程详情页面。

课程发布表的数据来源于课程预发布表,它们的结构基本一样,只是课程发布表中的状态是课程发布状态,如下图:
学成在线----day8
redis中的课程缓存信息是将课程发布表中的数据转为json进行存储。
elasticsearch中的课程索引信息是根据搜索需要将课程名称、课程介绍等信息进行索引存储。
MinIO中存储了课程的静态化页面文件(html网页),查看课程详情是通过文件系统去浏览课程详情页面。

2、什么是分布式事务

一次课程发布操作需要向数据库、redis、elasticsearch、MinIO写四份数据,这里存在分布式事务问题。

什么是分布式事务?
首先理解什么是本地事务?

平常我们在程序中通过spring去控制事务是利用数据库本身的事务特性来实现的,因此叫数据库事务,由于应用主要靠关系数据库来控制事务,此数据库只属于该应用,所以基于本应用自己的关系型数据库的事务又被称为本地事务。

本地事务具有ACID四大特性,数据库事务在实现时会将一次事务涉及的所有操作全部纳入到一个不可分割的执行单元,该执行单元中的所有操作 要么都成功,要么都失败,只要其中任一操作执行失败,都将导致整个事务的回滚。

理解了本地事务,什么是分布式事务?

现在的需求是课程发布操作后将数据写入数据库、redis、elasticsearch、MinIO四个地方,这四个地方已经不限制在一个数据库内,是由四个分散的服务去提供,与这四个服务去通信需要网络通信,而网络存在不可到达性,这种分布式系统环境下,通过与不同的服务进行网络通信去完成事务称之为分布式事务。

3、 什么是CAP理论

控制分布式事务首先需要理解CAP理论,什么是CAP理论?
CAP是 Consistency、Availability、Partition tolerance三个词语的缩写,分别表示一致性、可用性、分区容忍性。
使用下边的分布式系统结构 进行说明:
学成在线----day8
客户端经过网关访问用户服务的两个结点,一致性是指用户不管访问哪一个结点拿到的数据都是最新的,比如查询小明的信息,不能出现在数据没有改变的情况下两次查询结果不一样。

可用性是指任何时候查询用户信息都可以查询到结果,但不保证查询到最新的数据。
分区容忍性也叫分区容错性,当系统采用分布式架构时由于网络通信异常导致请求中断、消息丢失,但系统依然对外提供服务。

CAP理论要强调的是在分布式系统中这三点不可能全部满足,由于是分布式系统就要满足分区容忍性,因为服务之间难免出现网络异常,不能因为局部网络异常导致整个系统不可用。

满足P那么C和A不能同时满足:
比如我们添加一个用户小明的信息,该信息先添加到结点1中,再同步到结点2中,如下图:
学成在线----day8
如果要满足C一致性,必须等待小明的信息同步完成系统才可用(否则会出现请求到结点2时查询不到数据,违反了一致性),在信息同步过程中系统是不可用的,所以满足C的同时无法满足A。

如果要满足A可用性,要时刻保证系统可用就不用等待信息同步完成,此时系统的一致性无法满足。

所以在分布式系统中进行分布式事务控制,要么保证CP、要么保证AP。

4、什么是BASE理论?

BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩写。
基本可用:当系统无法满足全部可用时保证核心服务可用即可,比如一个外卖系统,每到中午12点左右系统并发量很高,此时要保证下单流程涉及的服务可用,其它服务暂时不可用。
软状态:是指可以存在中间状态,比如:打印自己的社保统计情况,该操作不会立即出现结果,而是提示你打印中,请在XXX时间后查收。虽然出现了中间状态,但最终状态是正确的。
最终一致性:退款操作后没有及时到账,经过一定的时间后账户到账,舍弃强一致性,满足最终一致性。

5、分布式事务控制有哪些常用的技术方案?

实现CP就是要实现强一致性:
使用Seata框架基于AT模式实现
使用Seata框架基于TCC模式实现。
实现AP则要保证最终数据一致性:
使用消息队列通知的方式去实现,通知失败自动重试,达到最大失败次数需要人工处理;
使用任务调度的方案,启动任务调度将课程信息由数据库同步到elasticsearch、MinIO、redis中。

6、课程发布的事务控制方案

学习了这么多的理论,回到课程发布,执行课程发布操作后要向数据库、redis、elasticsearch、MinIO写四份数据,这个场景用哪种方案?

满足CP?
如果要满足CP就表示课程发布操作后向数据库、redis、elasticsearch、MinIO写四份数据,只要有一份写失败其它的全部回滚。
满足AP?
课程发布操作后,先更新数据库中的课程发布状态,更新后向redis、elasticsearch、MinIO写课程信息,只要在一定时间内最终向redis、elasticsearch、MinIO写数据成功即可。
目前我们已经有了任务调度的技术积累,这里选用任务调度的方案去实现分布式事务控制,课程发布满足AP即可。
下图是具体的技术方案:
学成在线----day8

1、在内容管理服务的数据库中添加一个消息表,消息表和课程发布表在同一个数据库。
2、点击课程发布通过本地事务向课程发布表写入课程发布信息,同时向消息表写课程发布的消息。通过数据库进行控制,只要课程发布表插入成功消息表也插入成功,消息表的数据就记录了某门课程发布的任务。
3、启动任务调度系统定时调度内容管理服务去定时扫描消息表的记录。
4、当扫描到课程发布的消息时即开始完成向redis、elasticsearch、MinIO同步数据的操作。
5、同步数据的任务完成后删除消息表记录。
时序图如下:
下图是课程发布操作的流程:
学成在线----day8
1、执行发布操作,内容管理服务存储课程发布表的同时向消息表添加一条“课程发布任务”。这里使用本地事务保证课程发布信息保存成功,同时消息表也保存成功。
2、任务调度服务定时调度内容管理服务扫描消息表,由于课程发布操作后向消息表插入一条课程发布任务,此时扫描到一条任务。
3、拿到任务开始执行任务,分别向redis、elasticsearch及文件系统存储数据。
4、任务完成后删除消息表记录。

7、课程发布接口开发

    @Transactional
    @Override
    public void publish(Long companyId, Long courseId) {

        //查询预发布表
        CoursePublishPre coursePublishPre = coursePublishPreMapper.selectById(courseId);
        if(coursePublishPre == null){
            XueChengPlusException.cast("课程没有审核记录,无法发布");
        }
        //状态
        String status = coursePublishPre.getStatus();
        //课程如果没有审核通过不允许发布
        if(!status.equals("202004")){
            XueChengPlusException.cast("课程没有审核通过不允许发布");
        }

        //向课程发布表写入数据
        CoursePublish coursePublish = new CoursePublish();
        BeanUtils.copyProperties(coursePublishPre,coursePublish);
        //先查询课程发布,如果有则更新,没有再添加
        CoursePublish coursePublishObj = coursePublishMapper.selectById(courseId);
        if(coursePublishObj == null){
            coursePublishMapper.insert(coursePublish);
        }else{
            coursePublishMapper.updateById(coursePublish);
        }

        //向消息表写入数据
//        mqMessageService.addMessage("course_publish",String.valueOf(courseId),null,null);
        saveCoursePublishMessage(courseId);

        //将预发布表数据删除
        coursePublishPreMapper.deleteById(courseId);

    }

8、课程发布消息sdk

课程发布操作执行后需要扫描消息表的记录,有关消息表处理的有哪些?
学成在线----day8
上图中红色框内的都是与消息处理相关的操作:
1、新增消息表
2、扫描消息表。
3、更新消息表。
4、删除消息表。
使用消息表这种方式实现最终事务一致性的地方除了课程发布还有其它业务场景。
学成在线----day8
如果在每个地方都实现一套针对消息表定时扫描、处理的逻辑基本上都是重复的,软件的可复用性太低,成本太高。
如何解决这个问题
针对这个问题可以想到将消息处理相关的逻辑做成一个通用的东西。
是做成通用的服务,还是做成通用的代码组件呢?
通用的服务是完成一个通用的独立功能,并提供独立的网络接口,比如:项目中的文件系统服务,提供文件的分布式存储服务。
代码组件也是完成一个通用的独立功能,通常会提供API的方式供外部系统使用,比如:fastjson、Apache commons工具包等。
如果将消息处理做成一个通用的服务,该服务需要连接多个数据库,因为它要扫描微服务数据库下的消息表,并且要提供与微服务通信的网络接口,单就针对当前需求而言开发成本有点高。
如果将消息处理做一个SDK工具包相比通用服务不仅可以解决将消息处理通用化的需求,还可以降低成本。
所以,本项目确定将对消息表相关的处理做成一个SDK组件供各微服务使用,如下图所示:
学成在线----day8
下边对消息SDK的设计内容进行说明:
sdk需要提供执行任务的逻辑吗
拿课程发布任务举例,执行课程发布任务是要向redis、索引库等同步数据,其它任务的执行逻辑是不同的,所以执行任务在sdk中不用实现任务逻辑,只需要提供一个抽象方法由具体的执行任务方去实现。
如何保证任务的幂等性
在视频处理章节介绍的视频处理的幂等性方案,这里可以采用类似方案,任务执行完成后会从消息表删除,如果消息的状态是完成或不存在消息表中则不用执行。
如何保证任务不重复执行
采用和视频处理章节一致方案,除了保证任务的幂等性外,任务调度采用分片广播,根据分片参数去获取任务,另外阻塞调度策略为丢弃任务。
注意:这里是信息同步类任务,即使任务重复执行也没有关系,不再使用抢占任务的方式保证任务不重复执行。

还有一个问题,根据消息表记录是否存在或消息表中的任务状态去保证任务的幂等性,如果一个任务有好几个小任务,比如:课程发布任务需要执行三个同步操作:存储课程到redis、存储课程到索引库,存储课程页面到文件系统。如果其中一个小任务已经完成也不应该去重复执行。这里该如何设计?

将小任务作为任务的不同的阶段,在消息表中设计阶段状态。
学成在线----day8文章来源地址https://www.toymoban.com/news/detail-512653.html

9、课程发布任务调度

package com.xuecheng.content.service.jobhandler;

import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.messagesdk.model.po.MqMessage;
import com.xuecheng.messagesdk.service.MessageProcessAbstract;
import com.xuecheng.messagesdk.service.MqMessageService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;


@Slf4j
@Component
public class CoursePublishTask extends MessageProcessAbstract {

    //任务调度入口
    @XxlJob("CoursePublishJobHandler")
    public void coursePublishJobHandler() throws Exception {

        // 分片参数
        int shardIndex = XxlJobHelper.getShardIndex();//执行器的序号,从0开始
        int shardTotal = XxlJobHelper.getShardTotal();//执行器总数
        //调用抽象类的方法执行任务
        process(shardIndex,shardTotal, "course_publish",30,60);


    }

    //执行课程发布任务的逻辑,如果此方法抛出异常说明任务执行失败
    @Override
    public boolean execute(MqMessage mqMessage) {
        //从mqMessage拿到课程id
        Long courseId = Long.parseLong(mqMessage.getBusinessKey1());

        //课程静态化上传到minio
        generateCourseHtml(mqMessage,courseId);


        //向elasticsearch写索引数据
        saveCourseIndex(mqMessage,courseId);

        //向redis写缓存

        //返回true表示任务完成
        return true;
    }
    //生成课程静态化页面并上传至文件系统
    private void generateCourseHtml(MqMessage mqMessage,long courseId){
        //消息id
        Long taskId = mqMessage.getId();
        MqMessageService mqMessageService = this.getMqMessageService();

        //做任务幂等性处理
        //查询数据库取出该阶段执行状态
        int stageOne = mqMessageService.getStageOne(taskId);
        if(stageOne>0){
           log.debug("课程静态化任务完成,无需处理...");
           return ;
        }

        //开始进行课程静态化
        int i=1/0;//制造一个异常表示任务执行中有问题

        //..任务处理完成写任务状态为完成
        mqMessageService.completedStageOne(taskId);


    }

    //保存课程索引信息 第二个阶段任务
    private void saveCourseIndex(MqMessage mqMessage,long courseId){
        //任务id
        Long taskId = mqMessage.getId();
        MqMessageService mqMessageService = this.getMqMessageService();
        //取出第二个阶段状态
        int stageTwo = mqMessageService.getStageTwo(taskId);

        //任务幂等性处理
        if(stageTwo>0){
            log.debug("课程索引信息已写入,无需执行...");
            return;
        }
        //查询课程信息,调用搜索服务添加索引 ...

        //完成本阶段的任务
        mqMessageService.completedStageTwo(taskId);


    }
}

到了这里,关于学成在线----day8的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 黑马学成在线--项目环境搭建

    完整版请移步至我的个人博客查看:https://cyborg2077.github.io/ 学成在线–项目环境搭建 学成在线–内容管理模块 学成在线–媒资管理模块 学成在线–课程发布模块 学成在线–认证授权模块 学成在线–选课学习模块 学成在线–项目优化 Git仓库:https://github.com/Cyborg2077/xuecheng

    2023年04月15日
    浏览(40)
  • 前端学成在线

    网站根目录是指存放网站的 第一层 文件夹,内部包含当前网站的 所有素材 ,包含 HTML、CSS、图片、JavaScript等等。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uXIiqznv-1691944062625)(assets/1680336645218.png)] 首页引入CSS文件 [外链图片转存失败,源站可能

    2024年02月13日
    浏览(77)
  • 2.0-学成在线内容管理

    1.1 业务流程 内容管理的业务由教学机构人员和平台的运营人员共同完成。 教学机构人员的业务流程如下: 1、登录教学机构。 2、维护课程信息,添加一门课程需要编辑课程的基本信息、上传课程图片、课程营销信息、课程计划、上传课程视频、课程师资信息等内容。 3、课

    2024年01月20日
    浏览(50)
  • 微服务实战项目-学成在线-项目部署

    一个软件的生命周期包括:需求分析阶、设计、开发、测试、上线、维护、升级、废弃。 通过示例说明如下: 1、产品人员进行需求分析 2、设计人员进行软件架构设计和模块设计。 3、每个模块的开发人员并行开发,设计接口、进行编码,并进行单元测试 4、开发完毕,将代

    2024年02月13日
    浏览(44)
  • 案例:学成在线案例(html+css)

    典型的企业级网站 目的是为了整体感知企业级网站布局流程,复习以前知识。 学成在线PSD源文件 开发工具=PS(切图)/cutterman插件+vscode(代码)+chrome(测试) 我们本次采取结构和样式相分离思想: 创建study目录文件夹(用于存放我们这个页面的相关内容) 用vscode打开这个目

    2024年02月04日
    浏览(36)
  • 【前端实战小项目】学成在线网页制作

    网站根目录 是指存放网站的 第一层 文件夹,内部包含当前网站的 所有素材 ,包含HTML、CSS、图片、JavaScript等等。 项目文件夹(如study) images 文件夹:存放 固定使用 的图片素材,例如: logo、样式修饰图等等 uploads 文件夹:存放 非固定使用 的图片素材,例如:商品图、宣传图需要

    2024年02月21日
    浏览(39)
  • 学成在线项目开发技巧整理---第一部分

    视频项目链接: 学成在线 整理的是我个人认为偏生疏的知识点,不一定涉及的全面。 在系统中某些选项是几个特定的值的一个或多个,并且随着还可以动态添加。比如支付方式,配送方式等。 此时我们应该设计一个数据字典模块,在后台进行管理,然后前台要从后端查询。并

    2023年04月22日
    浏览(60)
  • 微服务实战项目-学成在线-项目优化(redis缓存优化)

    视频播放页面用户未登录也可以访问,当用户观看试学课程时需要请求服务端查询数据,接口如下: 1、根据课程id查询课程信息。 2、根据文件id查询视频信息。 这些接口在用户未认证状态下也可以访问,如果接口的性能不高,当高并发到来很可能耗尽整个系统的资源,将整

    2024年02月12日
    浏览(41)
  • 微服务实战项目-学成在线-内容管理模块(有项目实战实现)

    1.1 什么是需求分析 在百度百科中对需求分析的定义如下: 需求分析也称为软件需求分析、系统需求分析或需求分析工程等,是开发人员经过深入细致的调研和分析,准确理解用户和项目的功能、性能、可靠性等具体要求,将用户非形式的需求表述转化为完整的需求定义,从

    2024年02月13日
    浏览(69)
  • arm: day8

    1.中断实验:按键控制led灯 流程: key.h key.c do_lrq.c main.c

    2024年02月11日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包