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

芝法酱学习笔记(2.6)——flink-cdc监听mysql binlog并同步数据至elastic-search和更新redis缓存

一、需求背景

在有的项目中,尤其是进销存类的saas软件,一开始为了快速把产品做出来,并没有考虑缓存问题。而这类软件,有着复杂的业务逻辑。如果想在原先的代码中,添加redis缓存,改动面将非常大,还需要大量的测试工作。有些时候会有更离谱的情况,比如一些一些项目可能用JDK1.6写的,想要在这个框架下接入redis缓存,也会变得十分困难。
这时我们就会想到,能否像mysql的主从复制一样,监听mysql的binlog,对数据进行更新呢?Flink CDC就呼之欲出。

二、mysql环境搭建

需要注意的是,当前的flink-cdc,仅仅支持mysql8.0,8.4是完全不支持的。
由于我的mysql装的是8.4,为了方便起见,我们使用docker安装mysql8.0

2.1 docker-compose.yml

services:master:image: mysql:8.0.41container_name: mysql-8restart: always#mem_limit: 512Menvironment:MYSQL_ROOT_PASSWORD: study@2025TZ: Asia/Shanghaiports:- "3307:3306"volumes:- ./cfg/my.cnf:/etc/my.cnf- ./data:/var/lib/mysql- ./initdb:/docker-entrypoint-initdb.d- ./dump:/var/dump- ./log:/var/lognetworks:- mysql-cluster
networks:mysql-cluster:

2.2 初始化sql

-- 创建复制用户create role role_app;
GRANT SELECT,UPDATE,INSERT,DELETE ON *.* to role_app;
GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO role_app;CREATE USER 'app'@'%' IDENTIFIED WITH caching_sha2_password by 'study@2025' DEFAULT ROLE role_app COMMENT 'app user';FLUSH PRIVILEGES;-- 创建两个数据库,用于测试
CREATE SCHEMA `shop-center`;
FLUSH TABLES WITH READ LOCK;

2.3 注意点

首先把容器卷 - ./cfg/my.cnf:/etc/my.cnf的这一句注释掉,启动服务
而后使用下面语句,把配置文件粘出来

docker exec <id> cp /etc/my.cnf ./cfg/my.cnf

之后把注释打开,再重新启动

三、工程搭建与pom引用

3.1 主模块pom引用

flink程序不需要接入Spring框架,直接一个main就可运行。
但我们还想使用一些我们熟悉的接口,来操作redis和el。

		<dependency><groupId>org.apache.flink</groupId><artifactId>flink-core</artifactId><version>1.20.0</version></dependency><dependency><groupId>org.apache.flink</groupId><artifactId>flink-streaming-java</artifactId><version>1.20.0</version></dependency><dependency><groupId>org.apache.flink</groupId><artifactId>flink-clients</artifactId><version>1.20.0</version></dependency><dependency><groupId>org.apache.flink</groupId><artifactId>flink-runtime</artifactId><version>1.20.0</version></dependency><dependency><groupId>org.apache.flink</groupId><artifactId>flink-connector-mysql-cdc</artifactId><version>3.3.0</version></dependency>	

3.2 common-data模块

一些entity数据,为了保持各模块共通,最好独立到一个common模块。
同时,我还会把redis和el-search的操作,在这个模块接入并封装

3.2.1 pom引用

<dependencies><dependency><groupId>org.yaml</groupId><artifactId>snakeyaml</artifactId><version>2.3</version></dependency><dependency><groupId>co.elastic.clients</groupId><artifactId>elasticsearch-java</artifactId><version>8.17.0</version></dependency><dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch-x-content</artifactId><version>8.17.0</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-core</artifactId><version>5.8.32</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional><scope>provided</scope></dependency><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId><version>3.4.2</version></dependency><dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2-extension-spring6</artifactId><version>2.0.54</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.12.1</version></dependency><dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.54</version></dependency><dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId><version>6.4.2.RELEASE</version></dependency><!-- Flink Redis Connector --><!--        <dependency>--><!--            <groupId>org.apache.bahir</groupId>--><!--            <artifactId>flink-connector-redis_2.12</artifactId>--><!--            <version>1.1.0</version>--><!--        </dependency>--></dependencies>

3.2.2 一些基本的entity类

@Data
public class GenItemEntity{Long id;String name;Long price;String brand;String specification;Integer version;
}

四、 redis操作和elsearch操作的封装

4.1 redis操作的封装

在pom上,接入spring-data-redis
而后,我们可以使用我们熟悉的RedisTemplate来操作redis

public class RedisConfig {public RedisConfig(){init();}protected FastJsonConfig redisFastJson(){FastJsonConfig config = new FastJsonConfig();config.setWriterFeatures(JSONWriter.Feature.WriteNullListAsEmpty,// 写入类名JSONWriter.Feature.WriteClassName,// 将 Boolean 类型的 null 转成 falseJSONWriter.Feature.WriteNullBooleanAsFalse,JSONWriter.Feature.WriteEnumsUsingName);config.setReaderFeatures(JSONReader.Feature.SupportClassForName,// 支持autoTypeJSONReader.Feature.SupportAutoType);return config;}protected FastJsonRedisSerializer fastJsonRedisSerializer(FastJsonConfig pFastJsonConfig) {FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);fastJsonRedisSerializer.setFastJsonConfig(pFastJsonConfig);return fastJsonRedisSerializer;}protected RedisConnectionFactory redisConnectionFactory(){// 这里最好读配置,我懒得搞了RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration("192.168.0.64",6379);redisConfiguration.setPassword("study@2025");GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>();poolConfig.setMaxTotal(2);  // 最大连接数poolConfig.setMaxIdle(2);    // 最大空闲连接数poolConfig.setMinIdle(2);    // 最小空闲连接数poolConfig.setMaxWait(Duration.ofMillis(3000)); // 连接等待时间ClientResources clientResources = DefaultClientResources.create();LettucePoolingClientConfiguration lettucePoolingClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(poolConfig).build();LettucePoolingClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder().clientResources(clientResources).commandTimeout(Duration.ofSeconds(5)).poolConfig(poolConfig).build();LettuceConnectionFactory redisConnectionFactory = new LettuceConnectionFactory(redisConfiguration,lettucePoolingClientConfiguration);redisConnectionFactory.afterPropertiesSet(); // 初始化连接工厂return redisConnectionFactory;}protected RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory, FastJsonRedisSerializer pFastJsonRedisSerializer) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();redisTemplate.setConnectionFactory(factory);redisTemplate.setEnableTransactionSupport(true);redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(pFastJsonRedisSerializer);redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(pFastJsonRedisSerializer);return redisTemplate;}protected void init(){mFastJsonConfig = redisFastJson();mFastJsonRedisSerializer = fastJsonRedisSerializer(mFastJsonConfig);mRedisConnectionFactory = redisConnectionFactory();mRedisTemplate = redisTemplate(mRedisConnectionFactory,mFastJsonRedisSerializer);mRedisTemplate.afterPropertiesSet();}private FastJsonConfig mFastJsonConfig;private FastJsonRedisSerializer mFastJsonRedisSerializer;private RedisConnectionFactory mRedisConnectionFactory;private RedisTemplate<String, Object> mRedisTemplate;public static RedisTemplate<String, Object> redisTemplate(){return Holder.INSTANCE.mRedisTemplate;}public static <T> String serialize(T entity){return JSON.toJSONString(entity,Holder.INSTANCE.mFastJsonConfig.getWriterFeatures());}private static class Holder {private static final RedisConfig INSTANCE = new RedisConfig();}}

4.2 elasticsearch操作的封装

由于el-search的连接器,需要配置apikey,以及https,我们最好使用yml配置,并且把http_ca.crt放进该模块的resouce中。
在IDEA环境下,有可能找不到子模块的资源,这时在主模块引入子模块时,只需要这样配置即可:

        <dependency><groupId>indi.zhifa.study2025</groupId><artifactId>common-data</artifactId><version>${project.version}</version><scope>compile</scope></dependency>

注意,重点是<scope>compile</scope>

public class EsClientConfig {@Setter@Getterprivate String host;@Setter@Getterprivate Integer port;@Setter@Getterprivate String apiKey;}
public class ElasticSearchClientProvider {private EsClientConfig esClientConfig;private RestClientBuilder builder;public ElasticSearchClientProvider() {try{init();}catch (Exception e){e.printStackTrace();}}public void init() throws IOException {Yaml yaml = new Yaml();try (InputStream inputStream = FileUtil.class.getClassLoader().getResourceAsStream("el-config.yml")) {if (inputStream == null) {throw new IllegalArgumentException("File not found: el-config.yml");}esClientConfig = yaml.loadAs(inputStream, EsClientConfig.class);} catch (Exception e) {throw new RuntimeException("Failed to load YAML file", e);}SSLContext sslContext;try (InputStream inputStream = FileUtil.class.getClassLoader().getResourceAsStream("http_ca.crt")){sslContext = TransportUtils.sslContextFromHttpCaCrt(inputStream);}catch (Exception e) {throw new RuntimeException("Failed to load http_ca.crt", e);}builder = RestClient.builder(new HttpHost(esClientConfig.getHost(), esClientConfig.getPort(), "https") // 替换为你的Elasticsearch地址).setDefaultHeaders(new Header[]{new BasicHeader("Authorization", "ApiKey " + esClientConfig.getApiKey())}).setFailureListener(new RestClient.FailureListener(){@Overridepublic void onFailure(Node node) {super.onFailure(node);}}).setHttpClientConfigCallback(hc->hc.setSSLContext(sslContext));}public ElasticsearchClient get(){RestClient restClient = builder.build();ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());ElasticsearchClient esClient = new ElasticsearchClient(transport);return esClient;}public static ElasticSearchClientProvider getInstance(){return Holder.INSTANCE;}private static class Holder {private static final ElasticSearchClientProvider INSTANCE = new ElasticSearchClientProvider();}}

五、 redis和elsearch的自定义sink编写

5.1 redis的sink编写

我们希望传入redis时,数据是被处理好的,redis的sink不需要处理任何逻辑,只管更新缓存和删除缓存。

5.1.1 RedisSinkCommand

public class RedisSinkCommand<T> {@Setter@Getterprotected ERedisCommand command;@Setter@Getterprotected long dua;@Setter@Getterprotected  String key;@Setter@Getterprotected  T value;public void initSet(String pKey, T pValue) {command = ERedisCommand.SET;dua = 300;key = pKey;value = pValue;}public void initDel(String pKey) {command = ERedisCommand.DEL;key = pKey;}}
public enum ERedisCommand {SET,DEL
}

5.1.2 SpringDataRedisSink

@Slf4j
public class SpringDataRedisSink<T> implements Sink<RedisSinkCommand<T>> {@Overridepublic SinkWriter<RedisSinkCommand<T>> createWriter(InitContext context) throws IOException {return null;}@Overridepublic SinkWriter<RedisSinkCommand<T>> createWriter(WriterInitContext context){return new LettuceRedisSinkWriter();}class LettuceRedisSinkWriter implements SinkWriter<RedisSinkCommand<T>> {@Overridepublic void write(RedisSinkCommand<T> pCmd, Context context) throws IOException, InterruptedException {RedisTemplate<String, Object> redisTemplate = RedisConfig.redisTemplate();switch (pCmd.getCommand()){case SET-> {redisTemplate.opsForValue().set(pCmd.getKey(),pCmd.getValue(),pCmd.getDua());}case DEL -> {redisTemplate.delete(pCmd.getKey());}}}@Overridepublic void flush(boolean endOfInput) throws IOException, InterruptedException {}@Overridepublic void close() throws Exception {}}}

5.2 elasticsearch的sink编写

elasticsearch的sink与redis的要求一致,在sink中不关心业务逻辑

5.2.1 ElCommand

@Data
public class ElCommand<T> {protected EElCommand command;protected String index;protected T entity;protected String id;
}
public enum EElCommand {CREATE,UPDATE,DELETE
}

5.2.2 ElSearchSink

public class ElSearchSink<T> implements Sink<ElCommand<T>> {@Overridepublic SinkWriter<ElCommand<T>> createWriter(InitContext context) throws IOException {return null;}@Overridepublic SinkWriter<ElCommand<T>> createWriter(WriterInitContext context){return new ElSearchSink.ElSearchSinkWriter();}class ElSearchSinkWriter implements SinkWriter<ElCommand<T>> {@Overridepublic void write(ElCommand<T> pCmd, Context context) throws IOException, InterruptedException {ElasticSearchClientProvider elasticSearchClientProvider = ElasticSearchClientProvider.getInstance();ElasticsearchClient elClient =  elasticSearchClientProvider.get();String index = pCmd.getIndex();String id = pCmd.getId();T entity = pCmd.getEntity();switch (pCmd.getCommand()){case CREATE,UPDATE -> {elClient.index(i->i.index(index).id(id).document(entity));}case DELETE -> {elClient.delete(d->d.index(index).id(id));}}}@Overridepublic void flush(boolean endOfInput) throws IOException, InterruptedException {}@Overridepublic void close() throws Exception {}}
}

六、主函数编写

public class FlinkMain {public static void main(String[] args) throws Exception {MySqlSource<String> mySqlSource = MySqlSource.<String>builder().hostname("192.168.0.64").port(3307).databaseList("shop-center") // set captured database.tableList("shop-center.item") // set captured table.username("app").password("study@2025").serverTimeZone("Asia/Shanghai").deserializer(new JsonDebeziumDeserializationSchema()) // converts SourceRecord to JSON String.startupOptions(StartupOptions.latest()).includeSchemaChanges(true).build();//        FlinkJedisPoolConfig jedisConfig = new FlinkJedisPoolConfig.Builder()
//                .setHost("192.168.0.64") // 替换为 Redis 主机
//                .setPort(6379) // Redis 端口
//                .setPassword("ilv0404@1314") // 如果有密码,设置密码
//                .build();StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.setParallelism(1);//        DataStream<BinlogInfo> mysqlStream = env.fromSource(mySqlSource, WatermarkStrategy.noWatermarks(),"Mysql source")
//                .map(str->{
//                    BinlogInfo res =JSONObject.parseObject(str, BinlogInfo.class);
//                    return res;
//                    }
//                 ).filter(bi->bi.getOp().equals("c")||bi.getOp().equals("u")||bi.getOp().equals("d"));
//
//        mysqlStream.addSink(new RedisSink(jedisConfig,new RedisItemMapper()));DataStream<RedisSinkCommand<GenItemEntity>> newMysqlStream = env.fromSource(mySqlSource, WatermarkStrategy.noWatermarks(),"Mysql source to redis").map(str->JSONObject.parseObject(str, new TypeReference<BinlogInfo<GenItemEntity>>() {}), TypeInformation.of(new TypeHint<BinlogInfo<GenItemEntity>>() {})).filter(bi->bi.getSource().getTable().equals("item") &&  (bi.getOp().equals("c")||bi.getOp().equals("u")||bi.getOp().equals("d"))).map(bi->{String op = bi.getOp();GenItemEntity itemEntity = bi.getAfter();String key = "item:"+itemEntity.getId();switch (op){case "c","u"->{RedisSinkCommand<GenItemEntity> redisSinkCommand = new RedisSinkCommand();redisSinkCommand.initSet(key,itemEntity);return redisSinkCommand;}case "d" ->{RedisSinkCommand<GenItemEntity> redisSinkCommand = new RedisSinkCommand();redisSinkCommand.initDel(key);return redisSinkCommand;}default -> {RedisSinkCommand<GenItemEntity> redisSinkCommand = new RedisSinkCommand();redisSinkCommand.initDel(key);return redisSinkCommand;}}},TypeInformation.of(new TypeHint<RedisSinkCommand<GenItemEntity>>() {}));newMysqlStream.sinkTo(new SpringDataRedisSink<GenItemEntity>());DataStream<ElCommand<GenItemEntity>> mySqlToElStream = env.fromSource(mySqlSource, WatermarkStrategy.noWatermarks(),"Mysql source to el").map(str->JSONObject.parseObject(str, new TypeReference<BinlogInfo<GenItemEntity>>() {}), TypeInformation.of(new TypeHint<BinlogInfo<GenItemEntity>>() {})).filter(bi->bi.getSource().getTable().equals("item") &&  (bi.getOp().equals("c")||bi.getOp().equals("u")||bi.getOp().equals("d"))).map(bi->{ElCommand elCommand = new ElCommand();GenItemEntity itemEntity = bi.getAfter();elCommand.setId(itemEntity.getId().toString());elCommand.setEntity(itemEntity);elCommand.setIndex("item_npc");String op = bi.getOp();switch (op){case "c"->elCommand.setCommand(EElCommand.CREATE);case "u"->elCommand.setCommand(EElCommand.UPDATE);case "d"->elCommand.setCommand(EElCommand.DELETE);}return elCommand;},TypeInformation.of(new TypeHint<ElCommand<GenItemEntity>>() {}));mySqlToElStream.sinkTo(new ElSearchSink());env.execute();}
}

七、代码展示

请道友移步码云

八、相关实践的思考

8.1 redis相关

我这里的代码,仅仅是学习用的。在真实项目中,redis缓存的更新,通常源于查询时,如果发现缓存中没有数据,则查mysql,并把缓存数据加入redis。如果监听到表数据的更改或删除,则直接删除相应缓存,等待查询时重新加入缓存。当然,这样做在同一数据并发访问时,会有重复设置缓存的可能性,我们把这种现象叫缓存穿透。可以在更新缓存前,用redisson加个锁,防止重复读取mysql并更新redis。

public class CacheService {@Autowiredprivate RedissonClient redissonClient;@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Autowiredprivate DataRepository dataRepository;public Object getData(String key) {// 第一次检查缓存Object value = redisTemplate.opsForValue().get(key);if (value != null) {return value;}RLock lock = redissonClient.getLock(key + ":LOCK");try {// 尝试加锁,设置锁超时时间防止死锁if (lock.tryLock(5, 30, TimeUnit.SECONDS)) {try {// 双重检查缓存value = redisTemplate.opsForValue().get(key);if (value != null) {return value;}// 查询数据库Object dbData = dataRepository.findById(key);// 更新缓存,设置合理过期时间redisTemplate.opsForValue().set(key, dbData, 1, TimeUnit.HOURS);return dbData;} finally {lock.unlock();}} else {// 未获取到锁,短暂等待后重试Thread.sleep(100);return redisTemplate.opsForValue().get(key);}} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RuntimeException("获取锁失败", e);}}
}

8.2 es相关

对于es,其实更新数据不建议采用这种方式。因为es中需要反范式设计,不可能用1张表的数据做es查询数据的。
对于电商系统的商品查询,我们可以在商品上架的时候更新es。并且商品商家状态下,不允许修改商品。商品下架时,删除es的数据。想要修改商品数据,可以先下架,再修改,而后上架。

相关文章:

芝法酱学习笔记(2.6)——flink-cdc监听mysql binlog并同步数据至elastic-search和更新redis缓存

一、需求背景 在有的项目中&#xff0c;尤其是进销存类的saas软件&#xff0c;一开始为了快速把产品做出来&#xff0c;并没有考虑缓存问题。而这类软件&#xff0c;有着复杂的业务逻辑。如果想在原先的代码中&#xff0c;添加redis缓存&#xff0c;改动面将非常大&#xff0c…...

JavaScript系列(58)--性能监控系统详解

JavaScript性能监控系统详解 &#x1f4ca; 今天&#xff0c;让我们深入探讨JavaScript的性能监控系统。性能监控对于保证应用的稳定性和用户体验至关重要。 性能监控基础概念 &#x1f31f; &#x1f4a1; 小知识&#xff1a;JavaScript性能监控是指通过收集和分析各种性能指…...

GESP2023年12月认证C++六级( 第三部分编程题(1)闯关游戏)

参考程序代码&#xff1a; #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <string> #include <map> #include <iostream> #include <cmath> using namespace std;const int N 10…...

git 新项目

新项目git 新建的项目如何进行git 配置git git config --global user.name "cc" git config --global user.email ccexample.com配置远程仓库路径 // 添加 git remote add origin http://gogs/cc/mc.git //如果配错了&#xff0c;删除 git remote remove origin初…...

系统URL整合系列视频一(需求方案)

视频 系统URL整合系列视频一&#xff08;需求方案&#xff09; 视频介绍 &#xff08;全国&#xff09;某大型分布式系统Web资源URL整合需求实现方案讲解。当今社会各行各业对软件系统的web资源访问权限控制越来越严格&#xff0c;控制粒度也越来越细。安全级别提高的同时也增…...

Vue.js 使用组件库构建 UI

Vue.js 使用组件库构建 UI 在 Vue.js 项目中&#xff0c;构建漂亮又高效的用户界面&#xff08;UI&#xff09;是很重要的一环。组件库就是你开发 UI 的好帮手&#xff0c;它可以大大提高开发效率&#xff0c;减少重复工作&#xff0c;还能让你的项目更具一致性和专业感。今天…...

计算图 Compute Graph 和自动求导 Autograd | PyTorch 深度学习实战

前一篇文章&#xff0c;Tensor 基本操作5 device 管理&#xff0c;使用 GPU 设备 | PyTorch 深度学习实战 本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started PyTorch 计算图和 Autograd 微积分之于机器学习Computational Graphs 计算图Autograd…...

51单片机入门_05_LED闪烁(常用的延时方法:软件延时、定时器延时;while循环;unsigned char 可以表示的数字是0~255)

本篇介绍编程实现LED灯闪烁&#xff0c;需要学到一些新的C语言知识。由于单片机执行的速度是非常快的&#xff0c;如果不进行延时的话&#xff0c;人眼是无法识别(停留时间要大于20ms)出LED灯是否在闪烁所以需要学习如何实现软件延时。另外IO口与一个字节位的数据对应关系。 文…...

如何获取sql数据中时间的月份、年份(类型为date)

可用自带的函数month来实现 如&#xff1a; 创建表及插入数据&#xff1a; create table test (id int,begindate datetime) insert into test values (1,2015-01-01) insert into test values (2,2015-02-01) 执行sql语句,获取月份&#xff1a; select MONTH(begindate)…...

【单层神经网络】softmax回归的从零开始实现(图像分类)

softmax回归 该回归分析为后续的多层感知机做铺垫 基本概念 softmax回归用于离散模型预测&#xff08;分类问题&#xff0c;含标签&#xff09; softmax运算本质上是对网络的多个输出进行了归一化&#xff0c;使结果有一个统一的判断标准&#xff0c;不必纠结为什么要这么算…...

使用开源项目:pdf2docx,让PDF转换为Word

目录 1.安装python 2.安装 pdf2docx 3.使用 pdf2docx 转换 PDF 到 Word pdf2docx&#xff1a;GitCode - 全球开发者的开源社区,开源代码托管平台 环境&#xff1a;windows电脑 1.安装python Download Python | Python.org 最好下载3.8以上的版本 安装时记得选择上&#…...

保姆级教程Docker部署KRaft模式的Kafka官方镜像

目录 一、安装Docker及可视化工具 二、单节点部署 1、创建挂载目录 2、运行Kafka容器 3、Compose运行Kafka容器 4、查看Kafka运行状态 三、集群部署 四、部署可视化工具 1、创建挂载目录 2、运行Kafka-ui容器 3、Compose运行Kafka-ui容器 4、查看Kafka-ui运行状态 …...

ChatGPT提问技巧:行业热门应用提示词案例--咨询法律知识

ChatGPT除了可以协助办公&#xff0c;写作文案和生成短视频脚本外&#xff0c;和还可以做为一个法律工具&#xff0c;当用户面临一些法律知识盲点时&#xff0c;可以向ChatGPT咨询获得解答。赋予ChatGPT专家的身份&#xff0c;用户能够得到较为满意的解答。 1.咨询法律知识 举…...

openRv1126 AI算法部署实战之——Tensorflow模型部署实战

在RV1126开发板上部署Tensorflow算法&#xff0c;实时目标检测RTSP传输。视频演示地址 rv1126 yolov5 实时目标检测 rtsp传输_哔哩哔哩_bilibili ​ 一、准备工作 从官网下载tensorflow模型和数据集 手动在线下载&#xff1a; https://github.com/tensorflow/models/b…...

STM32 TIM定时器配置

TIM简介 TIM&#xff08;Timer&#xff09;定时器 定时器可以对输入的时钟进行计数&#xff0c;并在计数值达到设定值时触发中断 16位计数器、预分频器、自动重装寄存器的时基单元&#xff0c;在72MHz计数时钟下可以实现最大59.65s的定时 不仅具备基本的定时中断功能&#xff…...

51单片机 05 矩阵键盘

嘻嘻&#xff0c;LCD在RC板子上可以勉强装上&#xff0c;会有一点歪。 一、矩阵键盘 在键盘中按键数量较多时&#xff0c;为了减少I/O口的占用&#xff0c;通常将按键排列成矩阵形式&#xff1b;采用逐行或逐列的“扫描”&#xff0c;就可以读出任何位置按键的状态。&#xf…...

SSRF 漏洞利用 Redis 实战全解析:原理、攻击与防范

目录 前言 SSRF 漏洞深度剖析 Redis&#xff1a;强大的内存数据库 Redis 产生漏洞的原因 SSRF 漏洞利用 Redis 实战步骤 准备环境 下载安装 Redis 配置漏洞环境 启动 Redis 攻击机远程连接 Redis 利用 Redis 写 Webshell 防范措施 前言 在网络安全领域&#xff0…...

kubernetes学习-配置管理(九)

一、ConfigMap &#xff08;1&#xff09;通过指定目录&#xff0c;创建configmap # 创建一个config目录 [rootk8s-master k8s]# mkdir config[rootk8s-master k8s]# cd config/ [rootk8s-master config]# mkdir test [rootk8s-master config]# cd test [rootk8s-master test…...

python 语音识别

目录 一、语音识别 二、代码实践 2.1 使用vosk三方库 2.2 使用SpeechRecognition 2.3 使用Whisper 一、语音识别 今天识别了别人做的这个app,觉得虽然是个日记app 但是用来学英语也挺好的,能进行语音识别,然后矫正语法,自己说的时候 ,实在不知道怎么说可以先乱说,然…...

一文速览DeepSeek-R1的本地部署——可联网、可实现本地知识库问答:包括671B满血版和各个蒸馏版的部署

前言 自从deepseek R1发布之后「详见《一文速览DeepSeek R1&#xff1a;如何通过纯RL训练大模型的推理能力以比肩甚至超越OpenAI o1(含Kimi K1.5的解读)》」&#xff0c;deepseek便爆火 爆火以后便应了“人红是非多”那句话&#xff0c;不但遭受各种大规模攻击&#xff0c;即便…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

宇树科技,改名了!

提到国内具身智能和机器人领域的代表企业&#xff0c;那宇树科技&#xff08;Unitree&#xff09;必须名列其榜。 最近&#xff0c;宇树科技的一项新变动消息在业界引发了不少关注和讨论&#xff0c;即&#xff1a; 宇树向其合作伙伴发布了一封公司名称变更函称&#xff0c;因…...

代码规范和架构【立芯理论一】(2025.06.08)

1、代码规范的目标 代码简洁精炼、美观&#xff0c;可持续性好高效率高复用&#xff0c;可移植性好高内聚&#xff0c;低耦合没有冗余规范性&#xff0c;代码有规可循&#xff0c;可以看出自己当时的思考过程特殊排版&#xff0c;特殊语法&#xff0c;特殊指令&#xff0c;必须…...