如何更好地使用Kafka? - 事先预防篇
要确保Kafka在使用过程中的稳定性,需要从kafka在业务中的使用周期进行依次保障。主要可以分为:事先预防(通过规范的使用、开发,预防问题产生)、运行时监控(保障集群稳定,出问题能及时发现)、故障时解决(有完整的应急预案)这三阶段。
另外的篇幅请参考
如何更好地使用Kafka? - 事先预防篇-CSDN博客
如何更好地使用Kafka? - 故障时解决-CSDN博客
1. 事先预防原则
事先预防即通过规范的使用、开发,预防问题产生。主要包含集群/生产端/消费端的一些最佳实践、上线前测试以及一些针对紧急情况(如消息积压等)的临时开关功能。
Kafka调优原则:
-
确定优化目标,并且定量给出目标(Kafka 常见的优化目标是吞吐量、延时、持久性和可用性);
-
确定了目标之后,需要明确优化的维度:
-
通用性优化:操作系统、JVM 等;
-
针对性优化:优化 Kafka 的 TPS、处理速度、延时等。
2. 生产端最佳实践
2.1 参数调优
-
使用 Java 版的 Client;
-
使用 kafka-producer-perf-test.sh 测试你的环境;
-
设置内存、CPU、batch 压缩;
-
batch.size:该值设置越大,吞吐越大,但延迟也会越大;
-
linger.ms:表示 batch 的超时时间,该值越大,吞吐越大、但延迟也会越大;
-
max.in.flight.requests.per.connection:默认为5,表示 client 在 blocking 之前向单个连接(broker)发送的未确认请求的最大数,超过1时,将会影响数据的顺序性;
-
compression.type:压缩设置,会提高吞吐量;
-
acks:数据 durability 的设置;
-
避免大消息(占用过多内存、降低broker处理速度);
-
broker调整:增加 num.replica.fetchers,提升 Follower 同步 TPS,避免 Broker Full GC 等;
-
当吞吐量小于网络带宽时:增加线程、提高 batch.size、增加更多 producer 实例、增加 partition 数;
-
设置 acks=-1 时,如果延迟增大:可以增大 num.replica.fetchers(follower 同步数据的线程数)来调解;
-
跨数据中心的传输:增加 socket 缓冲区设置以及 OS tcp 缓冲区设置。
2.2 开发实践
(1) 做好Topic隔离
根据具体场景(是否允许一定延迟、实时消息、定时周期任务等)区分kafka topic,避免挤占或阻塞实时业务消息的处理。
(2) 做好消息流控
如果下游消息消费存在瓶颈或者集群负载过高等,需要在生产端(或消息网关)实施流量生产速率的控制或者延时/暂定消息发送等策略,避免短时间内发送大量消息。
(3) 做好消息补推
手动去查询丢失的那部分数据,然后将消息重新发送到mq里面,把丢失的数据重新补回来。
(4) 做好消息顺序性保障
如果需要在保证Kafka在分区内严格有序的话(即需要保证两个消息是有严格的先后顺序),需要设置key,让某类消息根据指定规则路由到同一个topic的同一个分区中(能解决大部分消费顺序的问题)。
但是,需要避免分区内消息倾斜的问题(例如,按照店铺Id进行路由,容易导致消息不均衡的问题)。
-
生产端:消息发送指定key,确保相同key的消息发送到同一个partition。
-
消费端:单线程消费或者写 N 个内存 queue,具有相同 key 的数据都到同一个内存 queue;然后对于 N 个线程,每个线程分别消费一个内存 queue ;
(5) 适当提高消息发送效率
-
批量发送:kafka先将消息缓存在内存中的双端队列(buffer)中,当消息量达到batch size指定大小时进行批量发送,减少了网络传输频次,提高了传输效率;
-
端到端压缩消息: 将一批消息打包后进行压缩,发送给 Broker 服务器后,但频繁的压缩和解压也会降低性能,最终还是以压缩的方式传递到消费者的手上,在 Consumer 端进行解压;
-
异步发送:将生产者改造为异步的方式,可以提升发送效率,但是如果消息异步产生过快,会导致挂起线程过多,内存不足,最终导致消息丢失;
-
索引分区并行消费:当一个时间相对长的任务在执行时,它会占用该消息所在索引分区被锁定,后面的任务不能及时派发给空闲的客户端处理,若服务端如果启用索引分区并行消费的特性,就可以及时的把后面的任务派发给其他的客户端去执行,同时也不需要调整索引的分区数(但此类消息仅适用于无需保证消息顺序关系的消息)
(6) 保证消息发送可靠性
-
Producer:如果对数据可靠性要求很高的话,在发送消息的时候,需要选择带有 callBack 的api进行发送,并设置 acks、retries、factor等等些参数来保证Producer发送的消息不丢失。
-
Broker:kafka为了得到更高的性能和吞吐量,将数据异步批量的存储在磁盘中,并采用了批量刷盘的做法,如果对数据可靠性要求很高的话,可以修改为同步刷盘的方式提高消息的可靠性。
3. 消费端最佳实践
3.1 参数调优
-
吞吐量:调整partition 数、OS page cache(分配足够的内存来缓存数据);
-
offset topic(__consumer_offsets):offsets.topic.replication.factor(默认为3)、offsets.retention.minutes(默认为1440,即 1day);
-
offset commit较慢:异步 commit 或 手动 commit
-
fetch.min.bytes 、fetch.max.wait.ms
-
max.poll.interval.ms:调用 poll() 之后延迟的最大时间,超过这个时间没有调用 poll() 的话,就会认为这个 consumer 挂掉了,将会进行 rebalance
-
max.poll.records:当调用 poll() 之后返回最大的 record 数,默认为500
-
session.timeout.ms
-
Consumer Rebalance:check timeouts、check processing times/logic、GC Issues
-
网络配置
3.2 开发实践
(1) 做好消息消费幂等
消息消费的幂等主要根据业务逻辑做调整。
以处理订单消息为例:
-
由订单编号+订单状态唯一的幂等key,并存入redis;
-
在处理之前,首先会去查Redis是否存在该Key,如果存在,则说明已经处理过了,直接丢掉;
-
如果Redis没处理过,则将处理过的数据插入到业务DB上,再到最后把幂等Key插入到Redis上;
简而言之,即通过Redis做前置处理 + DB唯一索引做最终保证来实现幂等性。
(2) 做好Consumer隔离
在消息量非常大的情况下,实时和离线消费者同时消费一个集群,离线数据繁重的磁盘 IO 操作会直接影响实时业务的实时性和集群的稳定性。
根据消费的实时性可以将消息消费者行为划分两类:实时消费者和离线消费者。
-
实时消费者:对数据实时性要求较高;在实时消费的场景下,Kafka 会利用系统的 page cache 缓存,直接从内存转发给实时消费者(热读),磁盘压力为零,适合广告、推荐等业务场景。
-
离线消费者(定时周期性消费者):通常是消费数分钟前或是数小时前的消息,这类消息通常存储在磁盘中,消费时会触发磁盘的 IO 操作(冷读),适合报表计算、批量计算等周期性执行的业务场景。
(3) 避免消息消费堆积
-
延迟处理、控制速度,时间范围内分摊消息(针对实时性不高的消息);
-
生产速度大于消费速度,这样可以适当增加分区,增加consumer数量,提升消费TPS;
-
避免很重的消费逻辑,优化consumer TPS:
-
是否有大量DB操作;
-
下游/外部服务接口调用超时;
-
是否有lock操作(导致线程阻塞);
-
需要特别关注kafka异步链路中的涉及消息放大的逻辑;
-
-
如果有较重的消费逻辑,需要调整xx参数,避免消息没消费完时,消费组退出,造成reblance等问题
-
确保consumer端没有因为异常而导致消费hang住;
-
如果使用的是消费者组,确保没有频繁地发生rebalance
-
多线程消费,批量拉取处理;
注:批量拉取处理时,需注意下kafka版本,spring-kafka 2.2.11.RELEASE版本以下,如果配置kafka.batchListener=true,但是将消息接收的元素设置为单个元素(非批量List),可能会导致kafka在拉取一批消息后,仅仅消费了头部的第一个消息。
(4) 避免Rebalance问题
A. 触发条件:
-
消费者数量变化: 新消费者加入、消费者下线(未能及时发送心跳,被“踢出”Group)、消费者主动退出消费组(Consumer 消费时间过长导致)
-
消费组内订阅的主题或者主题的分区数量发生变化;
-
消费组对应的 GroupCoorinator 节点发生变化
B. 如何避免非必要rebalance(消费者下线、消费者主动退出消费组导致的reblance):
-
需要仔细地设置session.timeout.ms(决定了 Consumer 存活性的时间间隔)和heartbeat.interval.ms(控制发送心跳请求频率的参数) 的值。
-
max.poll.interval.ms参数配置:控制 Consumer 实际消费能力对 Rebalance 的影响,限定了 Consumer 端应用程序两次调用 poll 方法的最大时间间隔。默认值是 5 分钟,表示 Consumer 程序如果在 5 分钟之内无法消费完 poll 方法返回的消息,那么 Consumer 会主动发起“离开组”的请求,Coordinator 也会开启新一轮 Rebalance。具体可以统计下历史的时间花费,把最长的时间为参考进行设置。
(5) 保证消息消费可靠性
一般情况下,还是client 消费 broker 丢消息的场景比较多,想client端消费数据不能丢,肯定是不能使用autoCommit的,所以必须是手动提交的。
Consumer自动提交的机制是根据一定的时间间隔,将收到的消息进行commit。commit过程和消费消息的过程是异步的。也就是说,可能存在消费过程未成功(比如抛出异常),commit消息已经提交了,则此时消息就丢失了。
(6) 保证消息消费顺序性
-
不同topic(乱序消息):如果支付与订单生成对应不同的topic,只能在consumer层面去处理了。
-
同一个topic(乱序消息):一个topic可以对应多个分区,分别对应了多个consumer,与“不同topic”没什么本质上的差别。(可以理解为我们的服务有多个pod,生产者顺序发送消息,但被路由到不同分区,就可能变得乱序了,服务消费的就是无序的消息)
-
同一个topic,同一个分区(顺序消息):Kafka的消息在分区内是严格有序的,例如把同一笔订单的所有消息,按照生成的顺序一个个发送到同一个topic的同一个分区。
针对乱序消息:
例如:订单和支付分别封装了各自的消息,但是消费端的业务场景需要按订单消息->支付消息的顺序依次消费消息。
-
宽表(业务主题相关的指标、维度、属性关联在一起的一张数据库表):消费消息时,只更新对应的字段就好,消息只会存在短暂的状态不一致问题,但是状态最终是一致的。例如订单,支付有自己的状态字段,订单有自己的状态字段,售后有自己的状态字段,就不需要保证支付、订单、售后消息的有序,即使消息无序,也只会更新自己的状态字段,不会影响到其他状态;
-
消息补偿机制:将消息与DB进行对比,如果发现数据不一致,再重新发送消息至主进程处理,保证最终一致性;
-
MQ队列:一个中间方(比如redis的队列)来维护MQ的顺序;
-
业务保证:通过业务逻辑保障消费顺序;
针对顺序消息:
两者都是通过将消息绑定到定向的分区或者队列来保证顺序性,通过增加分区或者线程来提升消费能力。
A. Consumer单线程顺序消费
生产者在发送消息时,已保证消息在分区内有序,一个分区对应了一个消费者,保证了消息消费的顺序性。
B. Consumer多线程顺序消费(具体策略在后面章节)
单线程顺序消费的扩展能力很差。为了提升消费者的处理速度,除了横向扩展分区数,增加消费者外,还可以使用多线程顺序消费。
将接收到的kafka数据进行hash取模(注意:如果kafka分区接受消息已经是取模的了,这里一定要对id做一次hash再取模)发送到不同的队列,然后开启多个线程去消费对应队列里面的数据。
此外,这里通过配置中心进行开关、动态扩容/缩容线程池。
(7) 处理Consumer的事务
通过事务消息,可以很好的保证一些业务场景的事务逻辑,不会因为网络不可用等原因出现系统之间状态不一致。
当更新任何一个服务出现故障时就抛出异常,事务消息不会被提交或回滚,消息服务器会回调发送端的事务查询接口,确定事务状态,发送端程序可以根据消息的内容对未做完的任务重新执行,然后告诉消息服务器该事务的状态。
4. 集群配置最佳实践
4.1 集群配置
-
Broker 评估:每个 Broker 的 Partition 数不应该超过2k、控制 partition 大小(不要超过25GB);
-
集群评估(Broker 的数量根据以下条件配置):数据保留时间、集群的流量大小;
-
集群扩容:磁盘使用率应该在 60% 以下、网络使用率应该在 75% 以下;
-
集群监控:保持负载均衡、确保 topic 的 partition 均匀分布在所有 Broker 上、确保集群的阶段没有耗尽磁盘或带宽
4.2 Topic 评估
-
Partition 数:
-
Partition 数应该至少与最大 consumer group 中 consumer 线程数一致;
-
对于使用频繁的 topic,应该设置更多的 partition;
-
控制 partition 的大小(25GB 左右);
-
考虑应用未来的增长(可以使用一种机制进行自动扩容);
-
-
使用带 key 的 topic;
-
partition 扩容:当 partition 的数据量超过一个阈值时应该自动扩容(实际上还应该考虑网络流量)。
4.3 分区配置
设置多个分区在一定程度上是可以提高消费者消费的并发度,但是分区数量过多时可能会带来:句柄开销过大、生产端占用内存过大、可能增加端到端的延迟、影响系统可用性、故障恢复时间较长等问题。
根据吞吐量的要求设置 partition 数:
-
假设 Producer 单 partition 的吞吐量为 P
-
consumer 消费一个 partition 的吞吐量为 C
-
而要求的吞吐量为 T
-
那么 partition 数至少应该大于 T/P、T/c 的最大值
5. 性能调优
调优目标:高吞吐量、低延时。
5.1 分层调优
自上而下分为应用程序层、框架层、JVM层和操作系统层,层级越靠上,调优的效果越明显。
调优类型 | 建议 |
---|---|
操作系统 | 挂载文件系统时禁掉atime更新;选择ext4或XFS文件系统;swap空间的设置;页缓存大小 |
JVM(堆设置和GC收集器) | 将JVM 堆大小设置成 6~8GB;建议使用 G1 收集器,方便省事,比 CMS 收集器的优化难度小 |
Broker端 | 保持服务器端和客户端版本一致 |
应用层 | 要频繁地创建Producer和Consumer对象实例;用完及时关闭;合理利用多线程来改善性能 |
5.2 吞吐量(TPS)调优
| |
---|---|
Broker端 | 适当增加num.replica.fetchers参数值,但不超过CPU核数 |
调优GC参数以避免经常性的Full GC | |
Producer端 | 适当增加batch.size参数值,比如从默认的16KB增加到512KB或1MB |
适当增加linger.ms参数值,比如10~100 | |
设置compression.type=lz4或zstd | |
设置acks=0或1 | |
设置retries=0 | |
如果多线程共享同一个Producer实例,则增加buffer.memory参数值 | |
Consumer端 | 采用多Consumer进程或线程同时消费数据 |
增加fetch.min.bytes参数值,比如设置成1KB或更大 |
5.3 延时调优
| |
---|---|
Broker端 | 适当设置num.replica.fetchers值 |
Producer端 | 设置linger.ms=0 |
不启用压缩,即设置compression.type=none | |
设置ackes=1 | |
Consumer端 | 设置fetch.min.bytes=1 |
6. 稳定性测试
kafka的稳定性测试主要在业务上线前针对Kafka实例/集群健康性、高可用性的测试。
6.1 健康性检查
(1) 检查实例:查看Kafka 实例对象中拿到所有的信息(例如 IP、端口等);
(2) 测试可用性:访问生产者和消费者,测试连接。
6.2 高可用测试
A. 单节点异常测试:重启Leader副本或Follower副本所在Pod
步骤:
-
查看topic的副本信息
-
删除相应pod
-
脚本检测Kafka的可用性
预期:对生产者和消费者的可用性均无影响。
B. 集群异常测试:重启所有pod
步骤:
-
删除所有pod
-
脚本检测Kafka的可用性
预期:所有broker ready后服务正常。
相关文章:

如何更好地使用Kafka? - 事先预防篇
要确保Kafka在使用过程中的稳定性,需要从kafka在业务中的使用周期进行依次保障。主要可以分为:事先预防(通过规范的使用、开发,预防问题产生)、运行时监控(保障集群稳定,出问题能及时发现&#…...

如何解决 IPA 打包过程中的 “Invalid Bundle Structure“ 错误
哈喽,大家好呀,淼淼又来和大家见面啦,咱们行业内的应该都知道,在开发 iOS 应用时,将应用打包成 IPA 文件是常见的步骤之一。最近很多小伙伴们说在打包过程中,有时会遇到 "Invalid Bundle Structure&qu…...

Vuex:Vue.js 的状态管理库
一、Vuex 简介 Vuex 是 Vue.js 的状态管理模式和库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 的出现解决了组件间共享状态的问题,使得状态管理变得简单、可预测和可维护。 二、Vuex 核心概…...

【简单介绍下Sass】
🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…...

IM 是什么?
在当今数字化的时代,即时通讯(IM)已经渗透到人们的日常生活和企业的工作环境中。IM技术的快速i发展为人们提供了一种高效、便捷的沟通方式,不仅推动了社会的信息化进程,也提升了企业的协同效率和竞争力。 作为企业级I…...

俄罗斯方块的代码实现
文章目录 首先是头文件的引入部分接下来是一些预处理指令接下来定义了两个结构体:接下来是全局变量g_hConsoleOutput,用于存储控制台输出句柄。之后是一系列函数的声明最后是main函数源码 首先是头文件的引入部分 包括stdio.h、string.h、stdlib.h、tim…...

出海企业哪种组网方案更省事?
对于出海企业而言,建立跨地区的数据传输和协同工作至关重要,以提升运营效率。因此,网络构建变得迫在眉睫。通过构建企业组网,企业能够加强与海外分支、客户和合作伙伴之间的联系,加速海外业务的发展。 然而,…...

triton编译学习
一 流程 Triton-MLIR: 从DSL到PTX - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/671434808Superjomns blog | OpenAI/Triton MLIR 迁移工作简介https://superjom...

源码知识付费系统,在线教学平台需要优化什么?
在线教育关于广大的关注者而言属于快捷度非常高的传达途径,尤其是白日没有过多时间的上班族或学习繁忙的学生,均能够通过可靠的在线教育完结自己的目的。如此巨大的市场潜力使得以在线教育为主的公司数量呈现出直线上升的趋势,很多的在线教育…...

后端常用技能:解决java项目前后端传输数据中文出现乱码、问号问题
0. 问题背景 最近做一个解析数据的小工具,本地运行时都正常,发布到服务器上后在导出文件数据时发现中文全部变成了问号,特此记录下问题解决的思路和过程 1. 环境 java 1.8 springboot 2.6.13 额外引入了fastjson,commons-csv等…...

SpringBoot中使用MongoDB
目录 搭建实体类 基本的增删改查操作 分页查询 使用MongoTemplate实现复杂的功能 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> 在ap…...

【TS】入门
创建项目 vscode自动编译ts 生成配置文件 tsc --init 然后发现终端也改变了:...

Apache ECharts
Apache ECharts介绍: Apache ECharts 是一款基于 Javascript 的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。 官网地址:https://echarts.apache.org/zh/index.html Apache ECh…...

超详细的胎教级Stable Diffusion使用教程(四)
这套课程分为五节课,会系统性的介绍sd的全部功能和实操案例,让你打下坚实牢靠的基础 一、为什么要学Stable Diffusion,它究竟有多强大? 二、三分钟教你装好Stable Diffusion 三、小白快速上手Stable Diffusion 四、Stable dif…...

串口属性中的BM延时计时器问题
如果使用程序修改则需要修改注册表对应位置如下 第一个示例(217) 第二个示例(219) 需要注意的事情是修改前必须点查看串口名称(例如上图是com5) 程序修改: 有没有办法以编程方式更改USB <…...

PyQt6--Python桌面开发(8.QPlainTextEdit纯文本控件)
QPlainTextEdit纯文本控件...

Java | Leetcode Java题解之第83题删除排序链表中的重复元素
题目: 题解: class Solution {public ListNode deleteDuplicates(ListNode head) {if (head null) {return head;}ListNode cur head;while (cur.next ! null) {if (cur.val cur.next.val) {cur.next cur.next.next;} else {cur cur.next;}}return…...

重生奇迹mu再生宝石怎么用有什么用
重生奇迹mu再生宝石有2个用处: 1、在玛雅哥布林处给380装备加PVP属性4追4以上的380级装备,守护宝石一颗,再生宝石一颗,成功得到PVP装备,失败宝石消失,装备无变化; 2、给非套装点强化属性用法跟祝福,灵魂,生命一样直接往装备上敲,成功得到随机强化属性一…...

pdf 文件版面分析--pdfplumber (python 文档解析提取)
pdfplumber 的特点 1、它是一个纯 python 第三方库,适合 python 3.x 版本 2、它用来查看pdf各类信息,能有效提取文本、表格 3、它不支持修改或生成pdf,也不支持对pdf扫描件的处理 import glob import pdfplumber import re from collection…...

PostgreSQL的学习心得和知识总结(一百四十三)|深入理解PostgreSQL数据库之Support event trigger for logoff
目录结构 注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下: 1、参考书籍:《PostgreSQL数据库内核分析》 2、参考书籍:《数据库事务处理的艺术:事务管理与并发控制》 3、PostgreSQL数据库仓库…...

https免费证书获取
获取免费证书的网址: Certbot 1. 进入你的linux系统,先安装snapd, yum install snapd 2. 启动snapd service snapd start 3.安装 Certbot snap install --classic certbot 注意如下出现此错误时,需要先建立snap 软连接后&am…...

C语言 | Leetcode C语言题解之第74题搜索二维矩阵
题目: 题解: bool searchMatrix(int** matrix, int matrixSize, int* matrixColSize, int target) {int m matrixSize, n matrixColSize[0];int low 0, high m * n - 1;while (low < high) {int mid (high - low) / 2 low;int x matrix[mid /…...

杰发科技AC7840——软件Sent_HAL39X
0. 序 使用PWM模拟Sent测试下7840的软件sent功能。 参考链接:SENT协议应用笔记 - TechPlus汽车工坊的文章 - 知乎 SENT协议 1. Sent功能测试 使用提供的软件Sent代码在7840上测试,接收数据OK 2. 参考资料 3. 数据解析 我们个根据上述参考资料尝试解析…...

IOS 开发 - block 使用详解
1.Blobk的定义 block的写法相对难记,不必司机应被,只需要在xcode里打出"inlineBlock"--回车, 系统会自动帮你把基础版写法给你匹配出来 //Block的基础声明//等号""之前是blobk的声明,等号“”后面是block的实现/*returnType:返回类型(void、int、String *…...

BUU-[极客大挑战 2019]Http
考察点 信息收集 http构造请求数据包 题目 解题步骤 参考文章:https://zhuanlan.zhihu.com/p/367051798 查看源代码 发现有一个a标签,但是οnclick"return false"就是点击后不会去跳转到Secret.php的页面 所以我就自己拼接url http://no…...

开发Web3 ETF的技术难点
开发Web3 ETF(Exchange-Traded Fund,交易所交易基金)软件时,需要注意以下几个关键问题。开发Web3 ETF软件是一个复杂的过程,涉及到金融、法律和技术多个领域的专业知识。开发团队需要综合考虑上述问题,以确…...

【K8s】Kubectl 常用命令梳理
Kubectl常用命令梳理 下面包含大致涵盖命令只需要替换对应的Pod \ NameSpace 查看 命名空间 是 ’worktest2‘ 下 名字包括 ’todo‘的所有 Pod kubectl -n worktest2 get pod|grep todo查看 所有命名空间下 名字包括 ’todo‘的所有 Pod kubectl get pods --all-namespace…...

机器学习-监督学习
监督学习是机器学习和人工智能中的一个重要分支,它涉及使用已标记的数据集来训练算法,以便对数据进行分类或准确预测结果。监督学习的核心在于通过输入数据(特征)和输出数据(标签或类别)之间的关系…...

搭建Docker私服镜像仓库Harbor
1、概述 Harbor是由VMware公司开源的企业级的Docker Registry管理项目,它包括权限管理(RBAC)、LDAP、日志审核、管理界面、自我注册、镜像复制和中文支持等功能。 Harbor 的所有组件都在 Dcoker 中部署,所以 Harbor 可使用 Docker Compose 快速部署。 …...

SpringBoot自定义初始化sql文件 支持多类型数据库
我在resources目录下有init.sql初始化sql语句 指定sql文件的地址 sql内容如下: /*角色表*/ INSERT INTO #{schema}ccc_base_role (id, create_time, create_user_id, is_delete, role_name, status, update_time, update_user_id) VALUES(b89e30d81acb88448d412…...