Canal实现Mysql数据同步至Redis、Elasticsearch

文章目录

    • 1.Canal简介
      • 1.1 MySQL主备复制原理
      • 1.2 canal工作原理
    • 2.开启MySQL Binlog
    • 3.安装Canal
      • 3.1 下载Canal
      • 3.2 修改配置文件
      • 3.3 启动和关闭
    • 4.SpringCloud集成Canal
      • 4.1 Canal数据结构![在这里插入图片描述](https://img-blog.csdnimg.cn/c64b40c2231a4ea39a95aac81d771bd1.png)
      • 4.2 引入依赖
      • 4.3 配置多个数据同步的目的地
      • 4.4 application.yml
      • 4.5 监听配置
      • 4.5 监听配置
        • 4.5.1 监听测试类
        • 4.5.2 redis数据同步
        • 4.5.3 Elasticsearch数据同步
        • 4.5.4 Es Api 封装业务类 EsApiService
      • 4.6 canal日志
      • 4.7 第二种方案(解决数据库存在下划线,用上述方法,某些字段会为空)
        • 4.7.1 引入依赖
        • 4.7.2 创建监听
        • 4.7.3 实体类
      • 4.8 canal整合异常问题排查思路
        • 4.8.1 无法正常启动
        • 4.8.2 使用canal监听数据 启动成功了 没有报错 不过一直监听不到消息

1.Canal简介

官网
https://github.com/alibaba/canal
在这里插入图片描述
在这里插入图片描述

canal [kə’næl] ,译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费

早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同步的业务需求,实现方式主要是基于业务 trigger 获取增量变更。从 2010 年开始,业务逐步尝试数据库日志解析获取增量变更进行同步,由此衍生出了大量的数据库增量订阅和消费业务。

基于日志增量订阅和消费的业务包括

  • 数据库镜像
  • 数据库实时备份
  • 索引构建和实时维护(拆分异构索引、倒排索引等)
  • 业务 cache 刷新
  • 带业务逻辑的增量数据处理

当前的 canal 支持源端 MySQL 版本包括 5.1.x , 5.5.x , 5.6.x , 5.7.x , 8.0.x

1.1 MySQL主备复制原理

在这里插入图片描述

  • MySQL master 将数据变更写入二进制日志( binary log, 其中记录叫做二进制日志事件binary log events,可以通过 show binlog events 进行查看)
  • MySQL slave 将 master 的 binary log events 拷贝到它的中继日志(relay log)
  • MySQL slave 重放 relay log 中事件,将数据变更反映它自己的数据

1.2 canal工作原理

  • canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议
  • MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )
  • canal 解析 binary log 对象(原始为 byte 流)

2.开启MySQL Binlog

对于自建 MySQL , 需要先开启 Binlog 写入功能,
配置 binlog-format 为 ROW 模式,这里以mysql8.0.27为例,my.cnf 中配置如下

#开启bInlog
log-bin=mysql-bin
#以数据的方式写binlog日志 :statement 是记录SQL,row是记录数据
binlog-format=ROW
binlog-ignore-db=mysql

在这里插入图片描述
在这里插入图片描述
修改后,重启mysql服务。

  • 创建cannal
  • 授权 canal 链接 MySQL 账号具有作为 MySQL slave 的权限,
flush privileges;
#创建用户cannal
CREATE USER canal IDENTIFIED BY 'canal';
#把所有权限赋予canal,密码也是canal
GRANT ALL PRIVILEGES ON canaldb.user TO 'canal'@'%' identified by "canal";
//GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%' identified by "canal";
#刷新权限
flush privileges;

如果已有账户可直接 grant

ALTER USER 'canal'@'%' IDENTIFIED WITH mysql_native_password BY 'canal'; #更新一下用户密码
FLUSH PRIVILEGES; #刷新权限

通过以下命令,可以查看mysql用户信息

#查看所有数据库
show databases;
#使用mysql数据库
use mysql;
#查看当前库下所有表
show tables;
#查看user表
select Host, User from user;

3.安装Canal

3.1 下载Canal

点击下载地址,选择版本后点击canal.deployer文件下载

https://github.com/alibaba/canal/releases
在这里插入图片描述

3.2 修改配置文件

打开目录下conf/example/instance.properties文件,主要修改以下内容

## mysql serverId,不要和 mysql 的 server_id 重复
canal.instance.mysql.slaveId = 10
#position info,需要改成自己的数据库信息
canal.instance.master.address = 127.0.0.1:3306 
#username/password,需要改成自己的数据库信息,与刚才添加的用户保持一致
canal.instance.dbUsername = canal  
canal.instance.dbPassword = canal
复制代码

3.3 启动和关闭

#进入文件目录下的bin文件夹
#Linux启动
sh startup.sh
##Linux关闭
sh stop.sh
#Windows启动
双击 startup.bat

4.SpringCloud集成Canal

4.1 Canal数据结构在这里插入图片描述

4.2 引入依赖

父工程规定版本,子工程引用

<!-- 统一管理jar包版本 --><properties><canal.version>1.2.1-RELEASE</canal.version></properties><!-- 子模块继承之后,提供作用:锁定版本+了modlue不用写groupId和version --><dependencyManagement><dependencies><!--Canal 依赖--><dependency><groupId>top.javatool</groupId><artifactId>canal-spring-boot-starter</artifactId><version>${canal.version}</version></dependency></dependencies></dependencyManagement>

4.3 配置多个数据同步的目的地

由于我们这里是多个服务对应同一个canal端,则需要配置多个数据同步的目的地

在canal的安装目录下打开canal.deployer-1.1.6\conf\canal.properties文件

在canal.destinations = example后面添加多个数据目录,用逗号分割,一个服务对应一个目录,这里默认只有一个example

#################################################
######### 		destinations		#############
#################################################
canal.destinations = example,ad,goods,course,order,secKill,auth

在这里插入图片描述

配置好后,重启canal服务
之后会看到会看到canal/conf目录下新增了这些数据目录的文件夹
我们需要将默认的example文件夹中的instance.properties配置文件复制到新创建的自定义数据目录中
在这里插入图片描述
在这里插入图片描述

4.4 application.yml

canal:#canal的地址server: 127.0.0.1:11111 #数据同步的目的地destination: goods

4.5 监听配置

去实现EntryHandler接口,添加自己的业务逻辑,比如缓存的删除更新插入,实现对增删改查的逻辑重写。

4.5 监听配置

去实现EntryHandler接口,添加自己的业务逻辑,比如缓存的删除更新插入,实现对增删改查的逻辑重写。

canal-client提供了EntryHandler,该handler中提供了insert,delete,update方法,当监听到某张表的相关操作后,会回调对应的方法把数据传递进来,我们就可以拿到数据往Redis同步了。

  • @CanalTable(“employee”) :监听的表
  • EntryHandler<Employee> : 拿到employee表的改变后的数据之后,会封装为Employee实体 投递给我们
4.5.1 监听测试类
@CanalTable("test")
@Component
@Slf4j
public class TestHandler implements EntryHandler<Test> {@Resourceprivate RedisService redisService;@Overridepublic void insert(Test test) {log.info("新增Test:"+test);}@Overridepublic void delete(Test test) {log.debug("删除Test:"+test);}@Overridepublic void update(Test before, Test after) {log.info("修改前Test:"+before);log.info("修改后Test:"+after);}}

在这里插入图片描述
通过日志可以看到我们在navicat中对test这张表的增删改操作均被监听到了

4.5.2 redis数据同步
@CanalTable("employee")
@Component
@Slf4j
public class EmployeeHandler implements EntryHandler<Employee> {//把数据往Redis同步@Autowiredprivate RedisTemplate<Object,Object> redisTemplate;@Overridepublic void insert(Employee employee) {redisTemplate.opsForValue().set("EMP:"+employee.getId(),employee);}@Overridepublic void delete(Employee employee) {redisTemplate.delete("EMP:"+employee.getId());}@Overridepublic void update(Employee before, Employee after) {redisTemplate.opsForValue().set("EMP:"+after.getId(),after);}
}
4.5.3 Elasticsearch数据同步
import top.javatool.canal.client.annotation.CanalTable;
import top.javatool.canal.client.handler.EntryHandler;@CanalTable("t_goods")
@Component
@Slf4j
public class GoodsHanlder implements EntryHandler<Goods> {@Resourceprivate EsApiService esApiService;@Resourceprivate GoodsService goodsService;/*** 新增商品后同步es* @param goods*/@SneakyThrows@Overridepublic void insert(Goods goods) {log.info("新增:" + goods);goods = goodsService.getById(goods.getId());//同步至estry {esApiService.bulkRequest(EsConst.GOODS,goods);}catch (Exception e){log.error("同步es失败:"+e.getMessage());}}/*** 更新商品后同步es* @param before* @param after*/@SneakyThrows@Overridepublic void update(Goods before, Goods after) {log.info("修改前:" + before);log.info("修改后:" + after);after = goodsService.getById(after.getId());//同步至esesApiService.updateDocument(EsConst.GOODS,String.valueOf(after.getId()),after);}/*** 删除商品后同步es* @param goods*/@SneakyThrows@Overridepublic void delete(Goods goods) {log.info("删除:" + goods);//同步至esesApiService.deleteDocument(EsConst.GOODS,String.valueOf(goods.getId()));}
}
4.5.4 Es Api 封装业务类 EsApiService
package com.youzi.elasticsearch.service;import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;import java.io.IOException;
import java.util.List;/*** EsService : es API封装类** @author zyw* @create 2023/9/19 17:31*/
@Component
@Slf4j
public class EsApiService {@Autowired@Qualifier("restHighLevelClient")private RestHighLevelClient client;/*** 更新文档信息* @param index 索引名称* @param id id* @param data 更新的对象* @return* @throws IOException*/public boolean updateDocument(String index, String id,Object data) throws IOException {UpdateRequest request = new UpdateRequest(index, id);request.id("1");request.timeout(TimeValue.timeValueSeconds(1));request.doc(JSON.toJSONString(data), XContentType.JSON);UpdateResponse update = client.update(request, RequestOptions.DEFAULT);log.info("更新文档信息:" + update);return true;}/*** 插入单个** @param index 索引名称* @param data 批量新增的对象* @return* @throws IOException*/public boolean bulkRequest(String index, Object data) throws IOException {BulkRequest bulkRequest = new BulkRequest();bulkRequest.timeout("10s");//批处理请求bulkRequest.add(new IndexRequest(index).source(JSON.toJSONString(data), XContentType.JSON));BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);return bulk.hasFailures();}/*** 批量插入** @param index 索引名称* @param list 批量新增的对象集合* @return* @throws IOException*/public boolean bulkRequest(String index, List<Object> list) throws IOException {BulkRequest bulkRequest = new BulkRequest();bulkRequest.timeout("10s");//批处理请求for (int i = 0; i < list.size(); i++) {//批量更新和批量删除,就在这里修改对应的请求就可以了bulkRequest.add(new IndexRequest(index).source(JSON.toJSONString(list.get(i)), XContentType.JSON));}BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);return bulk.hasFailures();}/*** 删除文档信息** @param index 索引名称* @param id    id* @throws IOException*/public boolean deleteDocument(String index, String id) throws IOException {DeleteRequest request = new DeleteRequest(index, id);request.timeout(TimeValue.timeValueSeconds(1));DeleteResponse delete = client.delete(request, RequestOptions.DEFAULT);log.info("删除文档信息:" + delete);return true;}
}

4.6 canal日志

如果不想让控制台一直打印某些信息,可以配置如下配置屏蔽AbstractCanalClient类process()一直打印this.log.info(“获取消息 {}”, message)。

logging:level:#禁止AbstractCanalClient 打印常規日志 获取消息 {}top.javatool.canal.client: warn  

4.7 第二种方案(解决数据库存在下划线,用上述方法,某些字段会为空)

上面的方式只适合数据库字段和实体类字段,属性完全一致的情况;当数据库字段含有下划线的适合,因为我们直接去监听的binlog日志,里面的字段是数据库字段,因为跟实体类字段不匹配,所以会出现字段为空的情况,这个适合需要去获取列的字段,对字段进行属性转换,实现方法如下:

4.7.1 引入依赖
        <dependency><groupId>com.xpand</groupId><artifactId>starter-canal</artifactId><version>0.0.1-SNAPSHOT</version></dependency>
4.7.2 创建监听
@CanalEventListener
@Slf4j
public class KafkaListener {@Autowiredprivate RedisTemplate redisTemplate;/*** @param eventType 当前操作数据库的类型* @param rowData   当前操作数据库的数据*/@ListenPoint(schema = "maruko", table = "kafka_test")public void listenKafkaTest(CanalEntry.EventType eventType, CanalEntry.RowData rowData) {KafkaTest kafkaTestBefore = new KafkaTest();KafkaTest kafkaTestAfter = new KafkaTest();//遍历数据获取k-vList<CanalEntry.Column> beforeColumnsList = rowData.getBeforeColumnsList();List<CanalEntry.Column> afterColumnsList = rowData.getAfterColumnsList();getEntity(beforeColumnsList, kafkaTestBefore);log.warn("获取到提交前的对象为:" + kafkaTestBefore);getEntity(afterColumnsList, kafkaTestAfter);log.warn("获取到提交后的对象为:" + kafkaTestAfter);//判断是新增还是更新还是删除switch (eventType.getNumber()) {case CanalEntry.EventType.INSERT_VALUE:case CanalEntry.EventType.UPDATE_VALUE:redisTemplate.opsForValue().set("kafka_test" + kafkaTestAfter.getId(), kafkaTestAfter);break;case CanalEntry.EventType.DELETE_VALUE:redisTemplate.delete("kafka_test" + kafkaTestBefore.getId());break;}}/*** 遍历获取属性转换为实体类** @param columnsList* @param kafkaTest*/private void getEntity(List<CanalEntry.Column> columnsList, KafkaTest kafkaTest) {SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");for (CanalEntry.Column column : columnsList) {String name = column.getName();String value = column.getValue();switch (name) {case KafkaTest.ID:if (StringUtils.hasLength(value)) {kafkaTest.setId(Integer.parseInt(value));}break;case KafkaTest.CONTENT:if (StringUtils.hasLength(value)) {kafkaTest.setContent(value);}break;case KafkaTest.PRODUCER_STATUS:if (StringUtils.hasLength(value)) {kafkaTest.setProducerStatus(Integer.parseInt(value));}break;case KafkaTest.CONSUMER_STATUS:if (StringUtils.hasLength(value)) {kafkaTest.setConsumerStatus(Integer.parseInt(value));}break;case KafkaTest.UPDATE_TIME:if (StringUtils.hasLength(value)) {try {kafkaTest.setUpdateTime(format.parse(value));} catch (ParseException p) {log.error(p.getMessage());}}break;case KafkaTest.TOPIC:if (StringUtils.hasLength(value)) {kafkaTest.setTopic(value);}break;case KafkaTest.CONSUMER_ID:if (StringUtils.hasLength(value)) {kafkaTest.setConsumerId(value);}break;case KafkaTest.GROUP_ID:if (StringUtils.hasLength(value)) {kafkaTest.setGroupId(value);}break;case KafkaTest.PARTITION_ID:if (StringUtils.hasLength(value)) {kafkaTest.setPartitionId(Integer.parseInt(value));}break;case KafkaTest.PRODUCER_OFFSET:if (StringUtils.hasLength(value)) {kafkaTest.setProducerOffset(Long.parseLong(value));}break;case KafkaTest.CONSUMER_OFFSET:if (StringUtils.hasLength(value)) {kafkaTest.setConsumerOffset(Long.parseLong(value));}break;case KafkaTest.TEST:if (StringUtils.hasLength(value)) {kafkaTest.setTest(value);}break;}}}
}
4.7.3 实体类
@Data
@TableName("kafka_test")
public class KafkaTest {public static final String ID = "id";public static final String CONTENT = "content";public static final String PRODUCER_STATUS = "producer_status";public static final String CONSUMER_STATUS = "consumer_status";public static final String UPDATE_TIME = "update_time";public static final String TOPIC = "topic";public static final String CONSUMER_ID = "consumer_id";public static final String GROUP_ID = "group_id";public static final String PARTITION_ID = "partition_id";public static final String PRODUCER_OFFSET = "consumer_offset";public static final String CONSUMER_OFFSET = "producer_offset";public static final String TEST = "test";@TableId(type = IdType.AUTO)private Integer id;@TableField("content")private String content;@TableField("producer_status")private Integer producerStatus;@TableField("consumer_status")private Integer consumerStatus;@TableField("update_time")private Date updateTime;@TableField("topic")private String topic;@TableField("consumer_id")private String consumerId;@TableField("group_id")private String groupId;@TableField("partition_id")private int partitionId;@TableField("consumer_offset")private Long consumerOffset;@TableField("producer_offset")private Long producerOffset;@TableField("test")private String test;
}

4.8 canal整合异常问题排查思路

4.8.1 无法正常启动

canal配置文件中mysql连接方式是否有效,

是否已为canal单独配置mysql账号,并赋予权限

服务对应的自定义数据存储目的地中配置文件是否完整,初始配置文件需要与默认的exmple中配置文件一致

更改配置文件之后如果自定义的数据目录还是无法连接,则将对应目录下的meta.dat文件删除之后再重启

4.8.2 使用canal监听数据 启动成功了 没有报错 不过一直监听不到消息
  1. 检查canal的配置,确保配置正确,特别是数据库的连接信息;
  2. 检查canal的日志,确保没有报错;
  3. 检查数据库的binlog是否开启,确保binlog格式为row;
  4. 检查数据库的binlog是否有变更,确保有变更;
  5. 检查canal的过滤规则,确保过滤规则正确;
  6. 检查canal的版本,确保版本与数据库版本兼容;
  7. 检查canal的运行环境,确保环境正确;
  8. 检查canal的配置文件,确保配置文件正确;
  9. 检查canal的运行状态,确保运行正常;
  10. 检查canal的监听端口,确保端口没有被占用。

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

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

相关文章

python装13的一些写法

一些当你离职后&#xff0c;让老板觉拍大腿的代码 1. any(** in ** for ** in **) 判断某个集合元素&#xff0c;是否包含某个/某些元素 代码&#xff1a; if __name__ __main__:# 判断 list1 中是否包含某个/某些元素list1 [1,2,3,4]a any(x in [5,4] for x in list1) 输…

【AI语言模型】阿里推出音视频转文字引擎

一、前言 阿里的音视频转文字引擎可以正式使用&#xff0c;用户可体验所有AI功能&#xff0c;含全文概要、章节速览、发言总结等高阶AI功能。通过阿里云主账号登录&#xff0c;可享受以下权益&#xff1a; 每日登录&#xff0c;自动获得2小时转写时长&#xff1b; 每邀请1名好…

python项目2to3方案预研

目录 官方工具2to3工具安装参数解释基本使用工具缺陷 future工具安装参数解释基本使用工具缺陷 python-modernize工具安装参数解释基本使用工具缺陷 pyupgrade工具安装参数解释基本使用工具缺陷 对比 官方工具2to3 2to3 是Python官方提供的用于将Python 2代码转换为Python 3代…

Jenkins学习笔记4

配置构建流程&#xff1a; Jenkins任务创建&#xff1a; 1&#xff09;创建新任务&#xff1a; 把这个Accept first connection改成 No Validation。问题得到解决。 构建触发器这块暂时没有需要配置的。 传输文件到nginx-server这个web服务器中。 将文件上传到/usr/share/n…

Django(18):中间件原理和使用

目录 概述Django自带中间件Django的中间件执行顺序自定义中间件函数使用类 其它中间件钩子函数process_viewprocess_exceptionprocess_template_response如何使用这3个钩子函数&#xff1f; 全局异常处理小结 概述 中间件(middleware)是一个镶嵌到Django的request(请求)/respo…

Learn Prompt-Prompt 高级技巧:Agents 组件详解

在以LLM驱动的Agent系统中&#xff0c;LLM扮演着Agent的大脑角色&#xff0c;并辅以几个关键组件&#xff1a; 规划&#xff1a;LLM能够进行全面的规划&#xff0c;不仅仅是简单的任务拆分。它可以评估不同的路径和策略&#xff0c;制定最佳的行动计划&#xff0c;以实现用户给…

MongoDB【部署 02】mongodb使用配置文件启动、添加为系统服务及自启动(一个报错:[13436][NotMasterOrSecondary])

MongoDB使用配置文件启动、添加为系统服务及设置自启动 1.是什么2.下载安装启动配置2.1 下载2.2 安装2.3 配置2.4 使用配置文件启动 3.设置系统服务及自启动3.1 设置为系统服务3.2 自启动 1.是什么 【以下内容来自ChatGPT3.5】 MongoDB是一个流行的开源文档型数据库管理系统&a…

41. Linux系统配置FTP服务器并在QT中使用QFtp实现文件上传

1. 说明 这篇博客主要记录一些在Linux系统中搭建FTP服务器时踩过的一些坑,以及在使用QFtp上传文件时需要注意的问题。 2. FTP环境搭建 在linux系统中,需要安装vsftpd,可以在终端中输入下面的命令进行安装: sudo apt-get install vsftpd使用上述命令安装后,系统中会有一…

ChunJun(OldNameIsFlinkX)

序言 ChunJun主要是基于Flink实时计算框架,封装了不同数据源之间的数据导入与导出功能.我们只需要按照ChunJun的要求提供原始与目标数据源的相关信息给Chunjun,然后它会帮我们生成能运行与Flink上的算子任务执行,这样就避免了我们自己去根据不同的数据源重新编辑读入与读出的方…

学习笔记|模数转换器|ADC原理|STC32G单片机视频开发教程(冲哥)|第十七集:ADC采集

文章目录 1.模数转换器&#xff08;ADC&#xff09;是什么&#xff1f;手册说明&#xff1a; 2.STC32G单片机ADC使用原理19.1.1 ADC控制寄存器&#xff08;ADC_CONTR)19.1.2 ADC配置寄存器&#xff08;ADCCFG)19.1.4ADC时序控制寄存器&#xff08;ADCTIM&#xff09;19.3 ADC相…

CSS盒子模型、列表样式

盒子模型 常用的html标签都可以看作一个盒子&#xff0c;称为盒子模型 盒子由四部分组成&#xff1a; content、padding、border、margin 边框 border:border-width&#xff08;粗细&#xff09; | border-style(样式) | border-color&#xff08;颜色&#xff09; #one{bor…

云原生的简单理解

一、何谓云原生&#xff1f; 一种构建和运行应用软件的方法 应用程序从设计之初即考虑到云的环境&#xff0c;原生为云而设计&#xff0c;在云上以最佳姿势运行&#xff0c;充分利用和发挥云平台的弹性分布式优势。 二、包括以下四个要素 采用容器化部署&#xff1a;实现云平…

蓝牙核心规范(V5.4)10.6-BLE 入门笔记之L2CAP

蓝牙篇之蓝牙核心规范(V5.4)深入详解汇总 1.概述 L2CAP负责协议复用、流量控制、服务数据单元(SDU)的分段和重组。它使用通道的概念来分隔在堆栈层之间传递的数据包序列。固定通道不需要设置,立即可用,并与特定的上层协议相关联。通道也可以通过指定的协议服务多路复用器…

湖南衡阳3D扫描在生物仿真研究的应用高精度三维扫描螃蟹-CASAIM中科广电

生物仿真研究与应用一直是科研及工艺品的热门方向&#xff0c;很多设计脱胎于生物本身&#xff0c;传统方式又大多只能以画师手绘为主&#xff0c;做到“纤毫毕现”极其困难&#xff0c;故而才有了“齐白石的虾”、“徐悲鸿的马”等出圈的艺术家的画作&#xff0c;对于某种生物…

深度学习论文: ISTDU-Net:Infrared Small-Target Detection U-Net及其PyTorch实现

深度学习论文: ISTDU-Net&#xff1a;Infrared Small-Target Detection U-Net及其PyTorch实现 ISTDU-Net&#xff1a;Infrared Small-Target Detection U-Net PDF: https://doi.org/10.1109/LGRS.2022.3141584 PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTo…

jvm-sandbox-repeater源码解析-配置管理

一、配置初见 源码里提供的控制台截图如下&#xff1a;&#xff08;怎么搭建自己去百度&#xff09; 从中取出对应的配置如下&#xff1a; { "degrade": false, //阻断能力 "exceptionThreshold": 1000, //异常采样率 "httpEntrancePatterns&qu…

SunTorque亮相GAF2023数字化智能装配工程与装备技术大会

智能扭矩系统-智能拧紧系统-智能扭矩控制-SunTorque GAF2023数字化智能装配工程与装备技术大会在中国上海汽车会展中心盛大开幕&#xff0c;青创智通与装配领域、智能制造、数字化应用等相关先进智造技术的知名企业一齐亮相。 本次展会&#xff0c;我们带来了扭矩相关解决方案…

Vivado IP中Generate Output Products的设置说明

文章目录 Vivado IP中Generate Output Products的设置说明Synthesis OptionsRun Settings 官方文档中的介绍Generate Output ProductsSynthesis Options for IP 参考文献 Vivado IP中Generate Output Products的设置说明 在创建IP核时&#xff0c;将IP核的信息配置完成之后会弹…

数据预处理方式合集

删除空行 #del all None value data_all.dropna(axis1, howall, inplaceTrue) 删除空列 #del all None value data_all.dropna(axis0, howall, inplaceTrue) 缺失值处理 观测缺失值 观测数据缺失值有一个比较好用的工具包——missingno&#xff0c;直接传入DataFrame&…

面向面试知识-Redis

面向面试知识-Redis 什么是Redis 运行于内存的基于key-value的非关系型数据库。 一款开源的内存数据结构存储&#xff0c;用作数据库、缓存、消息代理等。&#xff08;可以基于Redis实现分布式锁、以及消息队列&#xff09; 发布订阅&#xff1f;&#xff1f; 对数据类型的操…