es和数据库同步方案

5.5 课程信息索引同步

5.5.1 技术方案

通过向索引中添加课程信息最终实现了课程的搜索,我们发现课程信息是先保存在关系数据库中,而后再写入索引,这个过程是将关系数据中的数据同步到elasticsearch索引中的过程,可以简单成为索引同步。

通常项目中使用elasticsearch需要完成索引同步,索引同步的方法很多:

1、针对实时性非常高的场景需要满足数据的及时同步,可以同步调用,或使用Canal去实现。

1)同步调用即在向MySQL写数据后远程调用搜索服务的接口写入索引,此方法简单但是耦合代码太高。

2)可以使用一个中间的软件canal解决耦合性的问题,但存在学习与维护成本。

canal主要用途是基于 MySQL 数据库增量日志解析,并能提供增量数据订阅和消费,实现将MySQL的数据同步到消息队列、Elasticsearch、其它数据库等,应用场景十分丰富。

它的地址:

github地址:https://github.com/alibaba/canal

版本下载地址:https://github.com/alibaba/canal/releases

文档地址:https://github.com/alibaba/canal/wiki/Docker-QuickStart

Canal基于mysql的binlog技术实现数据同步,什么是binlog,它是一个文件,二进制格式,记录了对数据库更新的SQL语句,向数据库写数据的同时向binlog文件里记录对应的sql语句。当数据库服务器发生了故障就可以使用binlog文件对数据库进行恢复。

所以,使用canal是需要开启mysql的binlog写入功能,Canal工作原理如下:

1、canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump

协议

2、MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )

3、canal 解析 binary log 对象(原始为 byte 流)

详细使用Canal进行索引同步的步骤参考:Canal实现索引同步.pdf

2、当索引同步的实时性要求不高时可用的技术比较多,比如:MQ、Logstash、任务调度等。

MQ:向mysql写数据的时候向mq写入消息,搜索服务监听MQ,收到消息后写入索引。使用MQ的优势是代码解耦,但是需要处理消息可靠性的问题有一定的技术成本,做到消息可靠性需要做到生产者投递成功、消息持久化以及消费者消费成功三个方面,另外还要做好消息幂等性问题。但是MQ会产生数据可靠性问题,在之前的文档之我们讲解了MQ的消息可靠性。使用MQ技术实现难度还是比较大的。

Logstash: 开源实时日志分析平台 ELK包括Elasticsearch、Kibana、Logstash,Logstash负责收集、解析和转换日志信息,可以实现MySQL与Elasticsearch之间的数据同步。也可以实现解耦合并且是官方推荐,但需要增加学习与维护成本。

任务调度:向mysql写数据的时候记录修改记录,开启一个定时任务根据修改记录将数据同步到Elasticsearch。 

我们实现这个同步功能使用索引同步的方案进行解决。

实现代码

1、拷贝CourseIndex 模型类到内容管理model 工程的dto包下。

2、在内容管理服务中添加FeignClient

Java
package com.xuecheng.content.feignclient;

import com.xuecheng.content.model.dto.CourseIndex;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

/**
 * @description 搜索服务远程接口
 * @author Mr.M
 * @date 2022/9/20 20:29
 * @version 1.0
 */
@FeignClient(value = "search",fallbackFactory = SearchServiceClientFallbackFactory.class)
public interface SearchServiceClient {

 @PostMapping("/search/index/course")
 public Boolean add(@RequestBody CourseIndex courseIndex);
}

定义SearchServiceClientFallbackFactory :

Java
@Slf4j
@Component
public class SearchServiceClientFallbackFactory implements FallbackFactory<SearchServiceClient> {
    @Override
    public SearchServiceClient create(Throwable throwable) {

        return new SearchServiceClient() {

            @Override
            public Boolean add(CourseIndex courseIndex) {
                throwable.printStackTrace();
                log.debug("调用搜索发生熔断走降级方法,熔断异常:", throwable.getMessage());

                return false;
            }
        };
    }
}

3、编写课程索引任务执行方法

完善CoursePublishTask类中的saveCourseIndex方法

Java
//保存课程索引信息
public void saveCourseIndex(MqMessage mqMessage,long courseId){
    log.debug("保存课程索引信息,课程id:{}",courseId);

    //消息id
    Long id = mqMessage.getId();
    //消息处理的service
    MqMessageService mqMessageService = this.getMqMessageService();
    //消息幂等性处理
    int stageTwo = mqMessageService.getStageTwo(id);
    if(stageTwo > 0){
        log.debug("课程索引已处理直接返回,课程id:{}",courseId);
        return ;
    }

    Boolean result = saveCourseIndex(courseId);
    if(result){
        //保存第一阶段状态
        mqMessageService.completedStageTwo(id);
    }
}

private Boolean saveCourseIndex(Long courseId) {

    //取出课程发布信息
    CoursePublish coursePublish = coursePublishMapper.selectById(courseId);
    //拷贝至课程索引对象
    CourseIndex courseIndex = new CourseIndex();
    BeanUtils.copyProperties(coursePublish,courseIndex);
    //远程调用搜索服务api添加课程信息到索引
    Boolean add = searchServiceClient.add(courseIndex);
    if(!add){
        XueChengPlusException.cast("添加索引失败");
    }
    return add;

}

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

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

相关文章

MySQL数据库基本操作

目录 一、数据库中常用的数据类型 二、常用命令与操作 1.DDL数据库定义语言 1、登录用户的数据库 2、查看当前服务器中的数据库 3、切换/进入数据库 并 查看数据库中包含的表 4、查看数据库中表的结构 5、创建数据库 7、展示创建数据表时的结构 8、创建表&#xff0c…

用Python写一个武侠游戏

前言 在本教程中&#xff0c;我们将使用Python写一个武侠类的游戏&#xff0c;大的框架全部搭好了&#xff0c;很多元素都可以自己添加&#xff0c;让游戏更丰富 &#x1f4dd;个人主页→数据挖掘博主ZTLJQ的主页 个人推荐python学习系列&#xff1a; ☄️爬虫JS逆向系列专栏 -…

算法通关村第十关——快速排序算法

1 快速排序基本过程 快速排序的是将分治法运用到排序问题的典型例子。力扣912题&#xff0c;给你一个整数数组 nums&#xff0c;请你将该数组升序排列。 基本思想&#xff1a;是通过随机标记一个pivot元素将含有n个元素的序列划分为左右两个子序列left和right&#xff0c;其中…

06:TIM定时器功能------编码器接口功能

目录 1:简历 2: 正交编码器 3:编码器接口基本结构 4:编码器的工作模式 5:极性反转 A:编码器接口测速 1:连接图 2:函数介绍 3:步骤 4:代码 B:编码器接口计次 1:连接图 2:代码 1:简历 Encoder Interface 编码器接口 编码器接口可接收增量&#xff08;正交&#xff09;编…

变量函数及销毁函数中的变量-PHP8知识详解

今天分享php8知识详解中的变量函数及销毁函数中的变量&#xff0c;以及相应的示例代码。 1、变量函数 变量函数&#xff0c;是指通过变量来访问的函数。当变量后有圆括号时&#xff0c;PHP将自动寻找与变量的值同名的函数&#xff0c;然后执行该函数。 变量函数引用&#xf…

uniapp使用sqlite 数据库

uniapp使用sqlite 数据库 傻瓜式使用方式&#xff0c;按步骤&#xff0c;即可使用。 1.开启sqlite 在项目中manifest.json该文件中配置 2.封装数据库的调用方法 const sqlName "zmyalh" //定义的数据库名称 const sqlPath "_doc/zmyalh.db" //定义数…

如何通过人工智能和自动化提高供应链弹性?

全球供应链中的数字化转型已经引起了广泛关注&#xff0c;尽管在过去的十年中&#xff0c;这一话题被广泛讨论&#xff0c;但许多公司仍然对如何实现这一不明确的目标感到困惑。人们普遍认识到这种转变的重要性&#xff0c;而新冠疫情及其带来的巨大影响也为行业向数字化转型方…

【Go 基础篇】Go语言分支结构:掌握 if 和 switch,灵活控制程序逻辑

介绍 在编程中&#xff0c;分支结构是一种重要的控制流程&#xff0c;它允许程序根据不同的条件选择不同的执行路径。Go语言提供了两种主要的分支结构&#xff1a;if 和 switch&#xff0c;用于在程序中实现条件判断和多重选择。本篇博客将深入探讨Go语言中的if和switch分支结…

EureKa快速入门

EureKa快速入门 远程调用的问题 多个服务有多个端口&#xff0c;这样的话服务有多个&#xff0c;硬编码不太适合 eureKa的作用 将service的所有服务的端口全部记录下来 想要的话 直接从注册中心查询对于所有服务 每隔一段时间需要想eureKa发送请求 保证服务还存活 动手实践 …

后端开发有哪几种语言? - 易智编译EaseEditing

后端开发是构建应用程序的一部分&#xff0c;负责处理服务器端的逻辑、数据库交互和数据处理。有许多编程语言可用于后端开发&#xff0c;以下是一些常见的后端开发语言&#xff1a; Java&#xff1a; Java是一种广泛使用的面向对象编程语言&#xff0c;具有强大的跨平台能力。…

常见前端面试之VUE面试题汇总八

22. Vue 子组件和父组件执行顺序 加载渲染过程&#xff1a; 1.父组件 beforeCreate 2.父组件 created 3.父组件 beforeMount 4.子组件 beforeCreate 5.子组件 created 6.子组件 beforeMount 7.子组件 mounted 8.父组件 mounted 更新过程&#xff1a; 1. 父组件 befor…

Unity 之transform.LookAt() 调整一个物体的旋转,使其朝向指定的位置

文章目录 总的介绍补充&#xff08;用于摄像机跟随的场景&#xff09; 总的介绍 transform.LookAt 是 Unity 引擎中 Transform 组件的一个方法&#xff0c;用于调整一个物体的旋转&#xff0c;使其朝向指定的位置。通常情况下&#xff0c;它被用来使一个物体&#xff08;如摄像…