当前位置: 首页 > news >正文

SpringBoot整合Canal

一 linux  + docker compose版本

1.第一步:基础环境

(1)第1步:安装jak、maven、git、nodejs、npm

yum install maven        mvn -v            安装maven时会帮安装jdkyum install git          git --version     2.27.0yum install nodejs       node -v           v12.22.11yum install npm          npm -v            6.14.16

(2)第2步:安装docker

# 第1步:创建docker配置目录
mkdir /etc/docker# 第2步:创建配置文件
tee /etc/docker/daemon.json <<-'EOF'
{"debug": true,"storage-driver": "overlay2","storage-opts":["overlay2.override_kernel_check=true"],"graph":"/opt/docker","registry-mirrors": ["https://hub-mirror.c.163.com","https://docker.mirrors.ustc.edu.cn","https://registry.docker-cn.com"]
}
EOF# 第3步:使用镜像源安装docker
dnf install docker# 第4步:启动docker
systemctl start docker# 第5步:开机自动启动
systemctl enable docker# 第6步:查看docker版本信息
docker info

(3)第3步:安装docker compose

dnf install docker-compose

(4)第四步:创建docker-compose.yml文件,并上传到linux

# 第一步:创建文件夹
mkdir test-canal# 第二步:创建docker-compose.yml文件
vim docker-compose.yml# 附:文件代码
version: "3"  
services:  mysql:  network_mode: mynetwork  container_name: mymysql  ports:  - 3306:3306  restart: always  volumes:  - /etc/localtime:/etc/localtime  - /home/mycontainers/mymysql/data:/data  - /home/mycontainers/mymysql/mysql:/var/lib/mysql  - /home/mycontainers/mymysql/conf:/etc/mysql  environment:  - MYSQL_ROOT_PASSWORD=root  command:   --character-set-server=utf8mb4  --collation-server=utf8mb4_unicode_ci  --log-bin=/var/lib/mysql/mysql-bin  --server-id=1  --binlog-format=ROW  --expire_logs_days=7  --max_binlog_size=500M  image: mysql:5.7.20  rabbitmq:     container_name: myrabbit  ports:  - 15672:15672  - 5672:5672  restart: always  volumes:  - /etc/localtime:/etc/localtime  - /home/mycontainers/myrabbit/rabbitmq:/var/lib/rabbitmq  network_mode: mynetwork  environment:  - RABBITMQ_DEFAULT_USER=admin  - RABBITMQ_DEFAULT_PASS=123456  image: rabbitmq:3.8-management  canal-server:  container_name: canal-server  restart: always  ports:  - 11110:11110  - 11111:11111  - 11112:11112  volumes:  - /home/mycontainers/canal-server/conf:/home/admin/canal-server/conf - /home/mycontainers/canal-server/logs:/home/admin/canal-server/logs  network_mode: mynetwork  depends_on:  - mysql  - rabbitmq  # - canal-admin  image: canal/canal-server:v1.1.5  

2.第二步:配置Canal

我们需要修改下Canal环境的配置文件:canal.propertiesinstance.properties,映射Canal中的以下两个路径:

  • /home/admin/canal-server/conf/canal.properties。其中canal.destinations意思是server上部署的instance列表,

  • /home/admin/canal-server/conf/example/instance.properties。这里的/example是指instance即实例名,要和上面canal.properties内instance配置对应,canal会为实例创建对应的文件夹,一个Client对应一个实例

以下是我们需要准备的两个配置文件具体内容:

(1)第1步:创建canal.properties,并上传到指定位置 

# 第一步:创建配置文件所在的目录
mkdir -p  /home/admin/canal-server/conf# 第二步:把配置文件上传到下面的目录 
cd /home/admin/canal-server/conf附:文件内容
################################################  
########     common argument   ############  
################################################  
# tcp bind ip  
canal.ip =  
# register ip to zookeeper  
canal.register.ip =  
canal.port = 11111  
canal.metrics.pull.port = 11112  
# canal instance user/passwd  
# canal.user = canal  
# canal.passwd = E3619321C1A937C46A0D8BD1DAC39F93B27D4458  # canal admin config  
# canal.admin.manager = canal-admin:8089  # canal.admin.port = 11110  
# canal.admin.user = admin  
# canal.admin.passwd = 6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9  # admin auto register 自动注册  
# canal.admin.register.auto = true  
# 集群名,单机则不写  
# canal.admin.register.cluster =  
# Canal Server 名字  
# canal.admin.register.name = canal-admin  canal.zkServers =  
# flush data to zk  
canal.zookeeper.flush.period = 1000  
canal.withoutNetty = false  
# tcp, kafka, rocketMQ, rabbitMQ, pulsarMQ  
canal.serverMode = tcp  
# flush meta cursor/parse position to file  
canal.file.data.dir = ${canal.conf.dir}  
canal.file.flush.period = 1000  
# memory store RingBuffer size, should be Math.pow(2,n)  
canal.instance.memory.buffer.size = 16384  
# memory store RingBuffer used memory unit size , default 1kb  
canal.instance.memory.buffer.memunit = 1024   
# meory store gets mode used MEMSIZE or ITEMSIZE  
canal.instance.memory.batch.mode = MEMSIZE  
canal.instance.memory.rawEntry = true  # detecing config  
canal.instance.detecting.enable = false  
#canal.instance.detecting.sql = insert into retl.xdual values(1,now()) on duplicate key update x=now()  
canal.instance.detecting.sql = select 1  
canal.instance.detecting.interval.time = 3  
canal.instance.detecting.retry.threshold = 3  
canal.instance.detecting.heartbeatHaEnable = false  # support maximum transaction size, more than the size of the transaction will be cut into multiple transactions delivery  
canal.instance.transaction.size =  1024  
# mysql fallback connected to new master should fallback times  
canal.instance.fallbackIntervalInSeconds = 60  # network config  
canal.instance.network.receiveBufferSize = 16384  
canal.instance.network.sendBufferSize = 16384  
canal.instance.network.soTimeout = 30  # binlog filter config  
canal.instance.filter.druid.ddl = true  
canal.instance.filter.query.dcl = false  
canal.instance.filter.query.dml = false  
canal.instance.filter.query.ddl = false  
canal.instance.filter.table.error = false  
canal.instance.filter.rows = false  
canal.instance.filter.transaction.entry = false  
canal.instance.filter.dml.insert = false  
canal.instance.filter.dml.update = false  
canal.instance.filter.dml.delete = false  # binlog format/image check  
canal.instance.binlog.format = ROW,STATEMENT,MIXED   
canal.instance.binlog.image = FULL,MINIMAL,NOBLOB  # binlog ddl isolation  
canal.instance.get.ddl.isolation = false  # parallel parser config  
canal.instance.parser.parallel = true  
# concurrent thread number, default 60% available processors, suggest not to exceed Runtime.getRuntime().availableProcessors()  
canal.instance.parser.parallelThreadSize = 16  
# disruptor ringbuffer size, must be power of 2  
canal.instance.parser.parallelBufferSize = 256  # table meta tsdb info  
canal.instance.tsdb.enable = true  
canal.instance.tsdb.dir = ${canal.file.data.dir:../conf}/${canal.instance.destination:}  
canal.instance.tsdb.url = jdbc:h2:${canal.instance.tsdb.dir}/h2;CACHE_SIZE=1000;MODE=MYSQL;  
canal.instance.tsdb.dbUsername = canal  
canal.instance.tsdb.dbPassword = canal  
# dump snapshot interval, default 24 hour  
canal.instance.tsdb.snapshot.interval = 24  
# purge snapshot expire , default 360 hour(15 days)  
canal.instance.tsdb.snapshot.expire = 360  ################################################  
########     destinations    ############  
################################################  
canal.destinations = canal-exchange  
# conf root dir  
canal.conf.dir = ../conf  
# auto scan instance dir add/remove and start/stop instance  
canal.auto.scan = true  
canal.auto.scan.interval = 5  
# set this value to 'true' means that when binlog pos not found, skip to latest.  
# WARN: pls keep 'false' in production env, or if you know what you want.  
canal.auto.reset.latest.pos.mode = false  canal.instance.tsdb.spring.xml = classpath:spring/tsdb/h2-tsdb.xml  
#canal.instance.tsdb.spring.xml = classpath:spring/tsdb/mysql-tsdb.xml  canal.instance.global.mode = spring  
canal.instance.global.lazy = false  
canal.instance.global.manager.address = ${canal.admin.manager}  
#canal.instance.global.spring.xml = classpath:spring/memory-instance.xml  
canal.instance.global.spring.xml = classpath:spring/file-instance.xml  
#canal.instance.global.spring.xml = classpath:spring/default-instance.xml  #################################################  
########         MQ Properties      ############  
#################################################  
# aliyun ak/sk , support rds/mq  
canal.aliyun.accessKey =  
canal.aliyun.secretKey =  
canal.aliyun.uid=  canal.mq.flatMessage = true  
canal.mq.canalBatchSize = 50  
canal.mq.canalGetTimeout = 100  
# Set this value to "cloud", if you want open message trace feature in aliyun.  
canal.mq.accessChannel = local  canal.mq.database.hash = true  
canal.mq.send.thread.size = 30  
canal.mq.build.thread.size = 8  #################################################  
########         RabbitMQ       ############  
#################################################  
rabbitmq.host = myrabbit  
rabbitmq.virtual.host = /  
rabbitmq.exchange = canal-exchange  
rabbitmq.username = admin  
rabbitmq.password = RabbitMQ密码  

此时canal.serverMode = tcp,即TCP直连,我们先开启这个服务,然后手写Java客户端代码去连接它,等下再改为RabbitMQ。

通过注释可以看到,canal支持的服务模式有:tcp, kafka, rocketMQ, rabbitMQ, pulsarMQ,即主流的消息队列都支持

(2)第2步:创建instance.properties,并上传到指定位置 

# 第一步:创建配置文件所在的目录
mkdir -p  /home/admin/canal-server/conf/example# 第二步:把配置文件上传到下面的目录 
cd /home/admin/canal-server/conf/example附:文件内容
################################################  
# mysql serverId , v1.0.26+ will autoGen  
#canal.instance.mysql.slaveId=123  # enable gtid use true/false  
canal.instance.gtidon=false  # position info  
canal.instance.master.address=mymysql:3306  
canal.instance.master.journal.name=  
canal.instance.master.position=  
canal.instance.master.timestamp=  
canal.instance.master.gtid=  # rds oss binlog  
canal.instance.rds.accesskey=  
canal.instance.rds.secretkey=  
canal.instance.rds.instanceId=  # table meta tsdb info  
canal.instance.tsdb.enable=true  
#canal.instance.tsdb.url=jdbc:mysql://127.0.0.1:3306/canal_tsdb  
#canal.instance.tsdb.dbUsername=canal  
#canal.instance.tsdb.dbPassword=canal  #canal.instance.standby.address =  
#canal.instance.standby.journal.name =  
#canal.instance.standby.position =  
#canal.instance.standby.timestamp =  
#canal.instance.standby.gtid=  # username/password  
canal.instance.dbUsername=canal  
canal.instance.dbPassword=canal  
canal.instance.connectionCharset = UTF-8  
# enable druid Decrypt database password  
canal.instance.enableDruid=false  
#canal.instance.pwdPublicKey=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALK4BUxdDltRRE5/zXpVEVPUgunvscYFtEip3pmLlhrWpacX7y7GCMo2/JM6LeHmiiNdH1FWgGCpUfircSwlWKUCAwEAAQ==  # table regex  
canal.instance.filter.regex=.*\..*  
# table black regex  
canal.instance.filter.black.regex=mysql\.slave_.*  
# table field filter(format: schema1.tableName1:field1/field2,schema2.tableName2:field1/field2)  
#canal.instance.filter.field=test1.t_product:id/subject/keywords,test2.t_company:id/name/contact/ch  
# table field black filter(format: schema1.tableName1:field1/field2,schema2.tableName2:field1/field2)  
#canal.instance.filter.black.field=test1.t_product:subject/product_image,test2.t_company:id/name/contact/ch  # mq config  
canal.mq.topic=canal-routing-key  
# dynamic topic route by schema or table regex  
#canal.mq.dynamicTopic=mytest1.user,topic2:mytest2\..*,.*\..*  
canal.mq.partition=0  

把这两个配置文件映射好,再次提醒,注意实例的路径名,默认是:/example/instance.properties

(3)第3步:修改canal配置文件

我们需要修改这个实例配置文件,去连接MySQL,确保以下的配置正确:

canal.instance.master.address=mymysql:3306  
canal.instance.dbUsername=canal  
canal.instance.dbPassword=canal  

mymysql是同为docker容器的MySQL环境,端口3306是指内部端口。

这里多说明一下,docker端口配置时假设为:13306:3306,那么容器对外的端口就是13306,内部是3306,在本示例中,MySQL和Canal都是容器环境,所以Canal连接MySQL需要满足以下条件:

  • 处于同一网段(docker-compose.yml中的mynetwork)

  • 访问内部端口(即3306,而非13306)

dbUsername和dbPassword为MySQL账号密码,为了开发方便可以使用root/root,但是我仍建议自行创建用户并分配访问权限

# 进入docker中的mysql容器  
docker exec -it mymysql bash  
# 进入mysql指令模式  
mysql -uroot -proot  # 编写MySQL语句并执行  
> ...  
-- 选择mysql  
use mysql;  
-- 创建canal用户,账密:canal/canal  
create user 'canal'@'%' identified by 'canal';  
-- 分配权限,以及允许所有主机登录该用户  
grant SELECT, INSERT, UPDATE, DELETE, REPLICATION SLAVE, REPLICATION CLIENT on *.* to 'canal'@'%';  -- 刷新一下使其生效  
flush privileges;  -- 附带一个删除用户指令  
drop user 'canal'@'%';  

用navicat或者shell去登录canal这个用户,可以访问即创建成功

(4)第4步:启动,它将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。

# 第一步:仓库网络
docker network create mynetwork
# 第二步:启动
sudo docker-compose -f /home/test-canal/docker-compose.yml up -d

(5)第5步:开放端口

最近使用 OpenEuler 部署项目,发现防火墙放通端口的方法找不到,因此在这里记录:
 
# firewall-cmd --query-port=8084/tcp --permanent
no
# firewall-cmd --add-port=8084/tcp --permanent
success
# firewall-cmd --reload
success
# firewall-cmd --query-port=8084/tcp --permanent

3.第三步:整合SpringBoot Canal实现客户端

(1)第1步:idea新建一个spring boot项目

有必要的话降低spring boot的版本:

(2)第2步:Maven依赖:

<canal.version>1.1.5</canal.version>  <!--canal-->  
<dependency>  <groupId>com.alibaba.otter</groupId>  <artifactId>canal.client</artifactId>  <version>${canal.version}</version>  
</dependency>  
<dependency>  <groupId>com.alibaba.otter</groupId>  <artifactId>canal.protocol</artifactId>  <version>${canal.version}</version>  
</dependency>  

(3)第3步:新增组件并启动:

import com.alibaba.otter.canal.client.CanalConnector;  
import com.alibaba.otter.canal.client.CanalConnectors;  
import com.alibaba.otter.canal.protocol.CanalEntry;  
import com.alibaba.otter.canal.protocol.Message;  
import org.springframework.boot.CommandLineRunner;  
import org.springframework.stereotype.Component;  import java.net.InetSocketAddress;  
import java.util.List;  @Component  
public class CanalClient {  private final static int BATCH_SIZE = 1000;  public void run() {  // 创建链接  CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress("localhost", 11111), "canal-exchange", "canal", "canal");  try {  //打开连接  connector.connect();  //订阅数据库表,全部表  connector.subscribe(".*..*");  //回滚到未进行ack的地方,下次fetch的时候,可以从最后一个没有ack的地方开始拿  connector.rollback();  while (true) {  // 获取指定数量的数据  Message message = connector.getWithoutAck(BATCH_SIZE);  //获取批量ID  long batchId = message.getId();  //获取批量的数量  int size = message.getEntries().size();  //如果没有数据  if (batchId == -1 || size == 0) {  try {  //线程休眠2秒  Thread.sleep(2000);  } catch (InterruptedException e) {  e.printStackTrace();  }  } else {  //如果有数据,处理数据  printEntry(message.getEntries());  }  //进行 batch id 的确认。确认之后,小于等于此 batchId 的 Message 都会被确认。  connector.ack(batchId);  }  } catch (Exception e) {  e.printStackTrace();  } finally {  connector.disconnect();  }  }  /**  * 打印canal server解析binlog获得的实体类信息  */  private static void printEntry(List<CanalEntry.Entry> entrys) {  for (CanalEntry.Entry entry : entrys) {  if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN || entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND) {  //开启/关闭事务的实体类型,跳过  continue;  }  //RowChange对象,包含了一行数据变化的所有特征  //比如isDdl 是否是ddl变更操作 sql 具体的ddl sql beforeColumns afterColumns 变更前后的数据字段等等  CanalEntry.RowChange rowChage;  try {  rowChage = CanalEntry.RowChange.parseFrom(entry.getStoreValue());  } catch (Exception e) {  throw new RuntimeException("ERROR # parser of eromanga-event has an error , data:" + entry.toString(), e);  }  //获取操作类型:insert/update/delete类型  CanalEntry.EventType eventType = rowChage.getEventType();  //打印Header信息  System.out.println(String.format("================》; binlog[%s:%s] , name[%s,%s] , eventType : %s",  entry.getHeader().getLogfileName(), entry.getHeader().getLogfileOffset(),  entry.getHeader().getSchemaName(), entry.getHeader().getTableName(),  eventType));  //判断是否是DDL语句  if (rowChage.getIsDdl()) {  System.out.println("================》;isDdl: true,sql:" + rowChage.getSql());  }  //获取RowChange对象里的每一行数据,打印出来  for (CanalEntry.RowData rowData : rowChage.getRowDatasList()) {  //如果是删除语句  if (eventType == CanalEntry.EventType.DELETE) {  printColumn(rowData.getBeforeColumnsList());  //如果是新增语句  } else if (eventType == CanalEntry.EventType.INSERT) {  printColumn(rowData.getAfterColumnsList());  //如果是更新的语句  } else {  //变更前的数据  System.out.println("------->; before");  printColumn(rowData.getBeforeColumnsList());  //变更后的数据  System.out.println("------->; after");  printColumn(rowData.getAfterColumnsList());  }  }  }  }  private static void printColumn(List<CanalEntry.Column> columns) {  for (CanalEntry.Column column : columns) {  System.out.println(column.getName() + " : " + column.getValue() + "    update=" + column.getUpdated());  }  }  
}  

 (4)第4步:启动类Application:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class CanalDemoApplication extends CommandLineRunner {@Autowiredprivate CanalClient canalClient;@Overridepublic void run(String... args) throws Exception {canalClient.run();}public static void main(String[] args) {SpringApplication.run(CanalDemoApplication.class, args);}}

4.第四步:测试

        启动程序,此时新增或修改数据库中的数据,我们就能从客户端中监听到

5.报错

(1)【gpt】ERROR: for mymysql  Cannot start service mysql: network mynetwork not found

这个错误提示表明 Docker 容器无法找到名为 "mynetwork" 的网络。可能是由于以下几个原因导致的:

  1. 你没有创建名为 "mynetwork" 的 Docker 网络。在运行容器之前,需要先创建一个自定义网络。你可以使用以下命令创建一个自定义网络:

    docker network create mynetwork

    然后再尝试启动 mysql 服务。

  2. 如果你已经创建了 "mynetwork" 网络,但是它位于不同的 Docker 主机上,或者由于某种原因被删除了,那么容器将无法找到该网络。请确保网络存在,并且与运行 mysql 容器的主机关联。

  3. 可能是 Docker daemon 没有正确配置网络驱动程序,导致无法创建网络。你可以尝试重启 Docker 服务,或者检查 Docker 配置文件以确保网络驱动程序配置正确。

如果以上方法都没有解决问题,可以提供更多关于你的环境和具体操作的信息,以便更好地帮助你解决问题。

(2)ERROR: for canal-server  Cannot start service canal-server: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/home/mycontainers/canal-server/conf/canal.properties" to rootfs at "/home/admin/canal-server/conf/canal.properties": mount /home/mycontainers/canal-server/conf/canal.properties:/home/admin/canal-server/conf/canal.properties (via /proc/self/fd/6), flags: 0x5000: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type

        volumes:  
            - /home/mycontainers/canal-server/conf/canal.properties:/home/admin/canal-server/conf/canal.properties  
            - /home/mycontainers/canal-server/conf/instance.properties:/home/admin/canal-server/conf/example/instance.properties  
            - /home/mycontainers/canal-server/logs:/home/admin/canal-server/logs 

改为

        volumes:  
            - /home/mycontainers/canal-server/conf:/home/admin/canal-server/conf 
            - /home/mycontainers/canal-server/logs:/home/admin/canal-server/logs 

参考:

1. SpringBoot整合Canal+RabbitMQ监听数据变更~ (qq.com)

2. 实战!基于canal同步mysql数据到elasticsearch - 知乎 (zhihu.com) 

相关文章:

SpringBoot整合Canal

一 linux docker compose版本 1.第一步&#xff1a;基础环境 &#xff08;1&#xff09;第1步&#xff1a;安装jak、maven、git、nodejs、npm yum install maven mvn -v 安装maven时会帮安装jdkyum install git git --version 2.27.0yum in…...

用 Python 提取某一个公众号下的所有文章

当我们想要提取某一个公众号下的所有文章时&#xff0c;我们可以借助微信公众平台的开放接口&#xff0c;通过Python编写一个爬虫程序来实现。下面是一个示例代码&#xff0c;以及如何将其转化为一篇详细的微信公众号推文文章。 1. 导入所需库 首先&#xff0c;我们需要导入所…...

鸿蒙4.0实战教学—基础ArkTS(简易视频播放器)

构建主界面 主界面由视频轮播模块和多个视频列表模块组成&#xff0c;效果图如图&#xff1a; VideoData.ets中定义的视频轮播图数组SWIPER_VIDEOS和视频列表图片数组HORIZONTAL_VIDEOS。 // VideoData.ets import { HorizontalVideoItem } from ./HorizontalVideoItem; impo…...

4. 深入 Python 流程控制

​​​​​​ 4. 深入 Python 流程控制 除了前面介绍的 while 语句&#xff0c;Python 还从其它语言借鉴了一些流程控制功能&#xff0c;并有所改变。 4.1. if 语句 也许最有名的是 if 语句。例如: >>> x int(raw_input("Please enter an integer: "))…...

2000-2022年上市公司股票流动性指标数据/股票流动性Amihud(原始数据+计算代码+计算结果)

2000-2022年上市公司股票流动性指标数据/股票流动性Amihud&#xff08;原始数据计算代码计算结果&#xff09; 1、时间&#xff1a;2000-2022年 3、指标&#xff1a;证券代码_没有单位、交易日期_没有单位、日个股交易金额_元、考虑现金红利再投资的日个股回报率_没有单位、交…...

Unity 数据存储PlayerPrefs管理类

Unity 数据存储PlayerPrefs管理类 Unity 数据存储PlayerPrefs管理类实现存取实体类对象存储格式为Json格式Singleton.csInventoryEntity.csDataManager.cs用法如下 Unity 数据存储PlayerPrefs管理类 实现存取实体类对象 存储格式为Json格式 源码如下&#xff1a; Singleton…...

一篇文章学会如何使用 NestJS 过滤器处理系统全局异常情况

前言 在实际的应用开发中&#xff0c;你或许遇到过异常处理机制不统一或错误信息展示混乱的现象。为了解决这些问题&#xff0c;NestJS提供了一个优雅的解决方案&#xff1a;过滤器&#xff08;Filter&#xff09;。本文将从实际出发&#xff0c;向你介绍NestJS过滤器的基本概…...

ubuntu 守护进程 supervisor

# 安装 apt-get install supervisor# 检查 echo_supervisord_conf# 查看配置文件所在位置 # [include] # files /etc/supervisor/conf.d/*.conf ps -ef | grep supervisorcd /etc/supervisor/conf.d/lscat frp.conf[program:frp] command /data/work/frp/frpc -c /data/work/…...

SparkStreaming_window_sparksql_reids

1.5 window 滚动窗口滑动窗口 window操作就是窗口函数。Spark Streaming提供了滑动窗口操作的支持&#xff0c;从而让我们可以对一个滑动窗口内的数据执行计算操作。每次掉落在窗口内的RDD的数据&#xff0c;会被聚合起来执行计算操作&#xff0c;然后生成的RDD&#xff0c;会…...

爬虫工作量由小到大的思维转变---<第二十四章 Scrapy的`统计数据`收集stats collection ---12月26日补>

前言: 前两篇是讲的数据诊断分析,还有一篇深挖解决内存泄漏的文章,目前我还没整理汇编出来;但是,想到分析问题的时候,忽然觉得爬虫的数据统计好像也挺重要;于是,心血来潮准备来插一篇这个------让大家对日常scrapy爬的数据,做到心里有数!不必自己去搅破脑汁捣腾日志,敲计算器了…...

Kafka:本地设置

这是设置 Kafka 将数据从 Elasticsearch 发布到 Kafka 主题的三部分系列的第一部分;该主题将被 Neo4j 使用。第一部分帮助您在本地设置 Kafka。第二部分将讨论如何设置Elasticsearch将数据发布到Kafka主题。最后 将详细介绍如何使用连接器订阅主题并使用数据。 Kafka Kafka 是…...

.NetCore NPOI 读取excel内容及单元格内图片

由于数据方提供的数据在excel文件中不止有文字内容还包含图片信息&#xff0c;于是编写相关测试代码&#xff0c;读取excel文件内容及图片信息. 本文使用的是 NPOI-2.6.2 版本&#xff0c;此版本持.Net4.7.2;.NetStandard2.0;.NetStandard2.1;.Net6.0。 测试文档内容&#xf…...

TCP/UDP协议

1. 请解释TCP和UDP的主要区别。 TCP和UDP都是位于传输层的协议&#xff0c;具有不同的特点和应用场景。以下是它们的主要区别&#xff1a; 连接方式&#xff1a;TCP是面向连接的协议&#xff0c;这意味着在数据传输之前需要先建立连接。这通常通过三次握手来建立连接&#xff…...

3D 渲染如何帮助电商促进销售?

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 3D 渲染图像因其高转化率而成为亚马逊卖家的最新趋势。它是电子商务平…...

使用栈求表达式的值【数据结构】

中缀表达式转后缀表达式 转换流程&#xff1a; 初始化一个运算符栈。自左向右扫描中缀表达式&#xff0c;当扫描到操作数时直接连接到后缀表达式上。当扫描到操作符时&#xff0c;和运算符栈栈顶的操作符进行比较。如果比栈顶运算符高&#xff0c;则入栈。如果比栈顶运算符低…...

{MySQL}索引事务和JDBC

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、索引1.1索引是什么1.2作用1.3代码 二、事务2.1什么是事务2.2使用 三.JDBC总结 前言 接着上次&#xff0c;继续讲下MySQL 提示&#xff1a;以下是本篇文章正…...

Qt designer界面和所有组件功能的详细介绍(全!!!)

PyQt5和Qt designer的详细安装教程&#xff1a;https://blog.csdn.net/qq_43811536/article/details/135185233?spm1001.2014.3001.5501 目录 1. 界面介绍2. Widget Box 常用组件2.1 Layouts&#xff08;布局&#xff09;2.2 Spacers&#xff08;间隔器&#xff09;2.3 Item V…...

mysql_存储过程

举例子 createdefiner root% procedure insert_batch_test(IN START int(10), IN max_num int(10)) BEGINDECLAREi INT DEFAULT 0;SET autocommit 0;REPEATSET i i 1;INSERT INTO test (std, score)VALUES (CEILING(RAND() * 10 100), CEILING(RAND() * 50 50));UNTIL i …...

uboot学习及内核更换_incomplete

官方文档 在前面 文章目录 uboot常见命令学习环境变量网络控制台uboot标准启动其他 升级uboot或内核bin和uimg以及booti和bootm的区别制作uImage更换内核更换uboot后续计划 uboot常见命令学习 环境变量 Environment Variables环境变量 autostart 如果值为yes&#xff0c;则会…...

KVM 自动化脚本的使用及热/冷迁移

一、介绍 目录结构介绍 [rootkvm-server kvm]# tree -L 2 . ├── control # 控制脚本目录 │ ├── KVMInstall.sh # kvm服务安装脚本 │ ├── VMHost.sh # kvm虚拟机克隆脚本 │ └── VMTemplate.sh # kvm模板机安装脚本 ├── mount # 此目录保持为空&…...

Unity中Shader裁剪空间推导(在Shader中使用)

文章目录 前言一、在Shader中使用转化矩阵1、在顶点着色器中定义转化矩阵2、用 UNITY_NEAR_CLIP_VALUE 区分平台矩阵3、定义一个枚举用于区分当前是处于什么相机 二、我们在DirectX平台下&#xff0c;看看效果1、正交相机下2、透视相机下3、最终代码 前言 在上一篇文章中&…...

ES的使用(Elasticsearch)

ES的使用&#xff08;Elasticsearch&#xff09; es是什么&#xff1f; es是非关系型数据库&#xff0c;是分布式文档数据库&#xff0c;本质上是一个JSON 文本 为什么要用es? 搜索速度快&#xff0c;近乎是实时的存储、检索数据 怎么使用es? 1.下载es的包&#xff08;环境要…...

车牌识别技术,如何用python识别车牌号

目录 一.前言 二.运行环境 三.代码 四.识别效果 五.参考 一.前言 车牌识别技术&#xff08;License Plate Recognition, LPR&#xff09;在交通计算机视觉&#xff08;Computer Vision, CV&#xff09;领域具有非常重要的研究意义。以下是该技术的一些扩展说明&#xff1…...

爬虫工作量由小到大的思维转变---<第二十五章 Scrapy开始很快,越来越慢(追溯篇)>

爬虫工作量由小到大的思维转变---&#xff1c;第二十二章 Scrapy开始很快,越来越慢(诊断篇)&#xff1e;-CSDN博客 爬虫工作量由小到大的思维转变---&#xff1c;第二十三章 Scrapy开始很快,越来越慢(医病篇)&#xff1e;-CSDN博客 前言: 之前提到过,很多scrapy写出来之后,不…...

Servlet入门

目录 1.Servlet介绍 1.1什么是Servlet 1.2Servlet的使用方法 1.3Servlet接口的继承结构 2.Servlet快速入门 2.1创建javaweb项目 2.1.1创建maven工程 2.1.2添加webapp目录 2.2添加依赖 2.3创建servlet实例 2.4配置servlet 2.5设置打包方式 2.6部署web项目 3.servl…...

【C#与Redis】--高级主题--Redis 哨兵

一、简介 1.1 哨兵的概述 哨兵&#xff08;Sentinel&#xff09;是 Redis 分布式系统中用于监控和管理多个 Redis 服务器的组件。它的主要目标是确保 Redis 系统的高可用性&#xff0c;通过实时监测主节点和从节点的状态&#xff0c;及时发现并自动处理故障&#xff0c;保证系…...

linux安装python

文章目录 前言一、下载安装包二、安装1.安装依赖2.解压3.安装4.软链接5.验证 总结 前言 本篇文章介绍linux环境下安装python。 一、下载安装包 下载地址&#xff1a;官方网站 我们以最新的标准版为例 二、安装 1.安装依赖 yum -y install openssl-devel ncurses-devel li…...

【如何破坏单例模式(详解)】

✅如何破坏单例模式 &#x1f4a1;典型解析✅拓展知识仓✅反射破坏单例✅反序列化破坏单例✅ObjectlnputStream ✅总结✅如何避免单例被破坏✅ 避免反射破坏单例✅ 避免反序列化破坏单例 &#x1f4a1;典型解析 单例模式主要是通过把一个类的构造方法私有化&#xff0c;来避免重…...

什么是 SPI,它有什么用?

文章目录 什么是 SPI&#xff0c;它有什么用&#xff1f; 什么是 SPI&#xff0c;它有什么用&#xff1f; SPI 全称是 Service Provider Interface &#xff0c;它是 JDK 内置的一种动态扩展点的实现。 简单来说&#xff0c;就是我们可以定义一个标准的接口&#xff0c;然后第三…...

FolkMQ 新的消息中间件,v1.0.25

简介 采用 “多路复用” “内存运行” “快照持久化” “Broker 集群模式”&#xff08;可选&#xff09;基于 Socket.D 网络应用协议 开发。全新设计&#xff0c;自主架构&#xff01; 角色功能生产端发布消息&#xff08;Qos0、Qos1&#xff09;、发布定时消息&#xff…...

做网站推广的联系方式/seo学校培训班

以下是我的所有推荐文章&#xff0c;其中多半是文章系列&#xff0c;并且这个索引会在以后过程中进行追加&#xff0c;所以&#xff0c;各位看到的&#xff0c;永远都不是最新的&#xff0c;呵呵&#xff01; 大叔推荐文章系列 DotNetCore跨平台~文章索引&#xff5e;永久更新&…...

给个网站2022年手机上能用的/搜索排名影响因素

昨天听一个前同事说他们公司老大让他去研究下关于Nginx 方面的知识&#xff0c;我想了下Nginx 在如今的开发技术栈中应该会很大可能会用到&#xff0c;所以写篇博文记录总结下官网学习教程吧。 花了点时间写了篇Nginx入门学习教程 阅读后你将Get以下技能 什么是代理&#xff…...

长沙市网站制作哪家好/google谷歌搜索引擎入口

一、负载均衡介绍 负载均衡&#xff08;Load Balance&#xff09;&#xff1a; 建立在现有网络结构之上&#xff0c;它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。其意思就是分摊到多个操作单元上…...

容城网站建设/黄冈网站seo

这两个依赖jar包会发生冲突&#xff0c;如果同时存在启动时不会发生错误&#xff0c;都能正常启动&#xff0c;当访问时会报错 报错截图&#xff1a; 错误原因&#xff1a; spring-boot-starter-web依赖于spring-web 两个都依赖相当于重复依赖spring-web导致冲突 解决方法&…...

手工制作花朵/湖北seo服务

最新的FineUI QQ交流群请看这里&#xff1a;http://fineui.com/qqgroup/如果你喜爱ExtAspNet&#xff0c;可以通过如下QQ群和大家交流&#xff1a;ExtAspNet技术交流群1&#xff1a;158028499(已饱和)&#xff0c;100人&#xff0c;创始人&#xff1a;sanshi ExtAspNet技术交流…...

深圳好的网站建设公司排名/百度app免费下载

Mock 单元测试的重要性就不多说了&#xff0c;我这边的工程一般都是Spring BootMybatis&#xff08;详情可参看《Spring bootMyBatisPageHelperJSON》&#xff09;&#xff0c;现在写一下Spring Boot下怎么测试Controller、Service。 Controller测试 本文就简单一点&#xff0c…...