kakfa-3:ISR机制、HWLEO、生产者、消费者、核心参数负载均衡
1. kafka内核原理
1.1 ISR机制
光是依靠多副本机制能保证Kafka的高可用性,但是能保证数据不丢失吗?不行,因为如果leader宕机,但是leader的数据还没同步到follower上去,此时即使选举了follower作为新的leader,当时刚才的数据已经丢失了。ISR是:in-sync replica,就是跟leader partition保持同步的follower partition的数量,只有处于ISR列表中的follower才可以在leader宕机之后被选举为新的leader,因为在这个ISR列表里代表他的数据跟leader是同步的。如果要保证写入kafka的数据不丢失,首先需要保证ISR中至少有一个follower,其次就是在一条数据写入了leader partition之后,要求必须复制给ISR中所有的follower partition,才能说代表这条数据已提交,绝对不会丢失,这是Kafka给出的承诺
1.2 HW&LEO原理
-
LEO
last end offset,日志末端偏移量,标识当前日志文件中下一条待写入的消息的offset。举一个例子,若LEO=10,那么表示在该副本日志上已经保存了10条消息,位移范围是[0,9]。 -
HW
Highwatermark,俗称高水位,它标识了一个特定的消息偏移量(offset),消费者只能拉取到这个offset之前的消息。任何一个副本对象的HW值一定不大于其LEO值。小于或等于HW值的所有消息被认为是“已提交的”或“已备份的”。HW它的作用主要是用来判断副本的备份进度.下图表示一个日志文件,这个日志文件中只有9条消息,第一条消息的offset(LogStartOffset)为0,最有一条消息的offset为8,offset为9的消息使用虚线表示的,代表下一条待写入的消息。日志文件的 HW 为6,表示消费者只能拉取offset在 0 到 5 之间的消息,offset为6的消息对消费者而言是不可见的。
leader持有的HW即为分区的HW,同时leader所在broker还保存了所有follower副本的leo(1)关系:leader的leo >= follower的leo >= leader保存的follower的leo >= leader的hw >= follower的hw (2)原理:上面关系反应出各个值的更新逻辑的先后-
更新LEO的机制
- 注意
- follower副本的LEO保存在2个地方
(1)follower副本所在的broker缓存里。 (2)leader所在broker的缓存里,也就是leader所在broker的缓存上保存了该分区所有副本的LEO。-
更新LEO的时机
- follower更新LEO
(1)follower的leo更新时间每当follower副本写入一条消息时,leo值会被更新(2)leader端的follower副本的leo更新时间当follower从leader处fetch消息时,leader获取follower的fetch请求中offset参数,更新保存在leader端follower的leo。- leader更新LEO
(1)leader本身的leo的更新时间:leader向log写消息时
- 注意
-
更新HW的机制
-
follower更新HW
follower更新HW发生在其更新完LEO后,即follower向log写完数据,它就会尝试更新HW值。具体算法就是比较当前LEO(已更新)与fetch响应中leader的HW值,取两者的小者作为新的HW值。 -
leader更新HW
- leader更新HW的时机
(1)producer 向 leader 写消息时 (2)leader 处理 follower 的 fetch 请求时 (3)某副本成为leader时 (4)broker 崩溃导致副本被踢出ISR时- leader更新HW的方式
当尝试确定分区HW时,它会选出所有满足条件的副本,比较它们的LEO(当然也包括leader自己的LEO),并选择最小的LEO值作为HW值。这里的满足条件主要是指副本要满足以下两个条件之一:(1)处于ISR中(2)副本LEO落后于leader LEO的时长不大于replica.lag.time.max.ms参数值(默认值是10秒)
-
-

2. producer消息发送原理
2.1 producer核心流程概览

-
1、ProducerInterceptors是一个拦截器,对发送的数据进行拦截
ps:说实话这个功能其实没啥用,我们即使真的要过滤,拦截一些消息,也不考虑使用它,我们直接发送数据之前自己用代码过滤即可 -
2、Serializer 对消息的key和value进行序列化
-
3、通过使用分区器作用在每一条消息上,实现数据分发进行入到topic不同的分区中
-
4、RecordAccumulator收集消息,实现批量发送
按照分区构建不同的队列,将消息封装成一个个batch(16kb)
它是一个缓冲区,可以缓存一批数据,把topic的每一个分区数据存在一个队列中,然后封装消息成一个一个的batch批次,最后实现数据分批次批量发送。 -
5、Sender线程从RecordAccumulator获取消息
-
6、构建ClientRequest对象
-
7、将ClientRequest交给 NetWorkClient准备发送
-
8、NetWorkClient 将请求放入到KafkaChannel的缓存
-
9、发送请求到kafka集群
-
10、调用回调函数,接受到响应
3. producer核心参数
- 回顾之前的producer生产者代码
package com.kaikeba.producer;import org.apache.kafka.clients.producer.*;import java.util.Properties;
import java.util.concurrent.ExecutionException;/*** 需求:开发kafka生产者代码*/
public class KafkaProducerStudyDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {//准备配置属性Properties props = new Properties();//kafka集群地址props.put("bootstrap.servers", "node01:9092,node02:9092,node03:9092");//acks它代表消息确认机制 // 1 0 -1 allprops.put("acks", "all");//重试的次数props.put("retries", 0);//批处理数据的大小,每次写入多少数据到topicprops.put("batch.size", 16384);//可以延长多久发送数据props.put("linger.ms", 1);//缓冲区的大小props.put("buffer.memory", 33554432);props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");//添加自定义分区函数props.put("partitioner.class","com.kaikeba.partitioner.MyPartitioner");Producer<String, String> producer = new KafkaProducer<String, String>(props);for (int i = 0; i < 100; i++) {// 这是异步发送的模式producer.send(new ProducerRecord<String, String>("test", Integer.toString(i), "hello-kafka-"+i), new Callback() {public void onCompletion(RecordMetadata metadata, Exception exception) {if(exception == null) {// 消息发送成功System.out.println("消息发送成功");} else {// 消息发送失败,需要重新发送}}});// 这是同步发送的模式//producer.send(record).get();// 你要一直等待人家后续一系列的步骤都做完,发送消息之后// 有了消息的回应返回给你,你这个方法才会退出来}producer.close();}}
3.1 常见异常处理
-
不管是异步还是同步,都可能让你处理异常,常见的异常如下:
1)LeaderNotAvailableException:这个就是如果某台机器挂了,此时leader副本不可用,会导致你写入失败,要等待其他follower副本切换为leader副本之后,才能继续写入,此时可以重试发送即可。如果说你平时重启kafka的broker进程,肯定会导致leader切换,一定会导致你写入报错,是LeaderNotAvailableException2)NotControllerException:这个也是同理,如果说Controller所在Broker挂了,那么此时会有问题,需要等待Controller重新选举,此时也是一样就是重试即可3)NetworkException:网络异常,重试即可 我们之前配置了一个参数,retries,他会自动重试的,但是如果重试几次之后还是不行,就会提供Exception给我们来处理了。 -
retries
- 重新发送数据的次数
-
retry.backoff.ms
- 两次重试之间的时间间隔
3.2 提升消息吞吐量
-
buffer.memory
- 设置发送消息的缓冲区,默认值是33554432,就是32MB
如果发送消息出去的速度小于写入消息进去的速度,就会导致缓冲区写满,此时生产消息就会阻塞住,所以说这里就应该多做一些压测,尽可能保证说这块缓冲区不会被写满导致生产行为被阻塞住 -
compression.type
- producer用于压缩数据的压缩类型。默认是none表示无压缩。可以指定gzip、snappy
- 压缩最好用于批量处理,批量处理消息越多,压缩性能越好。
-
batch.size
- producer将试图批处理消息记录,以减少请求次数。这将改善client与server之间的性能。
- 默认是16384Bytes,即16kB,也就是一个batch满了16kB就发送出去
如果batch太小,会导致频繁网络请求,吞吐量下降;如果batch太大,会导致一条消息需要等待很久才能被发送出去,而且会让内存缓冲区有很大压力,过多数据缓冲在内存里。 -
linger.ms
- 这个值默认是0,就是消息必须立即被发送
一般设置一个100毫秒之类的,这样的话就是说,这个消息被发送出去后进入一个batch,如果100毫秒内,这个batch满了16kB,自然就会发送出去。但是如果100毫秒内,batch没满,那么也必须把消息发送出去了,不能让消息的发送延迟时间太长,也避免给内存造成过大的一个压力。
3.3 请求超时
- max.request.size
- 这个参数用来控制发送出去的消息的大小,默认是1048576字节,也就1mb
- 这个一般太小了,很多消息可能都会超过1mb的大小,所以需要自己优化调整,把他设置更大一些(企业一般设置成10M)
- request.timeout.ms
- 这个就是说发送一个请求出去之后,他有一个超时的时间限制,默认是30秒
- 如果30秒都收不到响应,那么就会认为异常,会抛出一个TimeoutException来让我们进行处理
3.4 ACK参数
acks参数,其实是控制发送出去的消息的持久化机制的。
-
acks=0
- 生产者只管发数据,不管消息是否写入成功到broker中,数据丢失的风险最高
producer根本不管写入broker的消息到底成功没有,发送一条消息出去,立马就可以发送下一条消息,这是吞吐量最高的方式,但是可能消息都丢失了。 你也不知道的,但是说实话,你如果真是那种实时数据流分析的业务和场景,就是仅仅分析一些数据报表,丢几条数据影响不大的。会让你的发送吞吐量会提升很多,你发送弄一个batch出去,不需要等待人家leader写成功,直接就可以发送下一个batch了,吞吐量很大的,哪怕是偶尔丢一点点数据,实时报表,折线图,饼图。 -
acks=1
- 只要leader写入成功,就认为消息成功了.
默认给这个其实就比较合适的,还是可能会导致数据丢失的,如果刚写入leader,leader就挂了,此时数据必然丢了,其他的follower没收到数据副本,变成leader. -
acks=all,或者 acks=-1
- 这个leader写入成功以后,必须等待其他ISR中的副本都写入成功,才可以返回响应说这条消息写入成功了,此时你会收到一个回调通知.
这种方式数据最安全,但是性能最差。 -
如果要想保证数据不丢失,得如下设置
(1)min.insync.replicas = 2ISR里必须有2个副本,一个leader和一个follower,最最起码的一个,不能只有一个leader存活,连一个follower都没有了。(2)acks = -1每次写成功一定是leader和follower都成功才可以算做成功,这样leader挂了,follower上是一定有这条数据,不会丢失。(3)retries = Integer.MAX_VALUE无限重试,如果上述两个条件不满足,写入一直失败,就会无限次重试,保证说数据必须成功的发送给两个副本,如果做不到,就不停的重试。除非是面向金融级的场景,面向企业大客户,或者是广告计费,跟钱的计算相关的场景下,才会通过严格配置保证数据绝对不丢失
3.5 重试乱序
- max.in.flight.requests.per.connection
- 每个网络连接可以忍受 producer端发送给broker 消息然后消息没有响应的个数
- 消息重试是可能导致消息的乱序的,因为可能排在你后面的消息都发送出去了,你现在收到回调失败了才在重试,此时消息就会乱序,所以可以使用“max.in.flight.requests.per.connection”参数设置为1,这样可以保证producer同一时间只能发送一条消息
消息重试是可能导致消息的乱序的,因为可能排在你后面的消息都发送出去了,你现在收到回调失败了才在重试,此时消息就会乱序,所以可以使用“max.in.flight.requests.per.connection”参数设置为1,这样可以保证producer同一时间只能发送一条消息
4. broker核心参数
-
server.properties配置文件核心参数
【broker.id】 每个broker都必须自己设置的一个唯一id【log.dirs】 这个极为重要,kafka的所有数据就是写入这个目录下的磁盘文件中的,如果说机器上有多块物理硬盘,那么可以把多个目录挂载到不同的物理硬盘上,然后这里可以设置多个目录,这样kafka可以数据分散到多块物理硬盘,多个硬盘的磁头可以并行写,这样可以提升吞吐量。【zookeeper.connect】 连接kafka底层的zookeeper集群的【Listeners】 broker监听客户端发起请求的端口号,默认是9092【unclean.leader.election.enable】 默认是false,意思就是只能选举ISR列表里的follower成为新的leader,1.0版本后才设为false,之前都是true,允许非ISR列表的follower选举为新的leader【delete.topic.enable】 默认true,允许删除topic【log.retention.hours】 可以设置一下,要保留数据多少个小时(默认168小时),这个就是底层的磁盘文件,默认保留7天的数据,根据自己的需求来就行了【log.retention.hours】
可以设置一下,要保留数据多少个小时(默认168小时),这个就是底层的磁盘文件,默认保留7天的数据,根据自己的需求来就行了【unclean.leader.election.enable】
默认是false,意思就是只能选举ISR列表里的follower成为新的leader,1.0版本后才设为false,之前都是true,允许非ISR列表的follower选举为新的leader
5. consumer消费原理
5.1 Offset管理
每个consumer内存里数据结构保存对每个topic的每个分区的消费offset,定期会提交offset,老版本是写入zk,但是那样高并发请求zk是不合理的架构设计,zk是做分布式系统的协调的,轻量级的元数据存储,不能负责高并发读写,作为数据存储。所以后来就是提交offset发送给内部topic:__consumer_offsets,提交过去的时候,key是group.id+topic+分区号,value就是当前offset的值,每隔一段时间,kafka内部会对这个topic进行compact。也就是每个group.id+topic+分区号就保留最新的那条数据即可。而且因为这个 __consumer_offsets可能会接收高并发的请求,所以默认分区50个,这样如果你的kafka部署了一个大的集群,比如有50台机器,就可以用50台机器来抗offset提交的请求压力,就好很多。
5.2 Coordinator 协调器
-
Coordinator的作用
每个consumer group都会选择一个broker作为自己的coordinator,他是负责监控这个消费组里的各个消费者的心跳,以及判断是否宕机,然后开启rebalance.根据内部的一个选择机制,会挑选一个对应的Broker,Kafka总会把你的各个消费组均匀分配给各个Broker作为coordinator来进行管理的.consumer group中的每个consumer刚刚启动就会跟选举出来的这个consumer group对应的coordinator所在的broker进行通信,然后由coordinator分配分区给你的这个consumer来进行消费。coordinator会尽可能均匀的分配分区给各个consumer来消费。 -
如何选择哪台是coordinator
-
consumer-roup-id.hashcode % 分区数 =》分区号,该分区的leader所在的broker就是这个consumer group的coordinator。
首先对消费组的groupId进行hash,接着对consumer_offsets的分区数量取模,默认是50,可以通过offsets.topic.num.partitions来设置,找到你的这个consumer group的offset要提交到consumer_offsets的哪个分区。比如说:groupId,"membership-consumer-group" -> hash值(数字)-> 对50取模 -> 就知道这个consumer group下的所有的消费者提交offset的时候是往哪个分区去提交offset,找到consumer_offsets的一个分区,consumer_offset的分区的副本数量默认来说1,只有一个leader,然后对这个分区找到对应的leader所在的broker,这个broker就是这个consumer group的coordinator了,consumer接着就会维护一个Socket连接跟这个Broker进行通信。

6. consumer消费者Rebalance策略
比如我们消费的一个topic主题有12个分区:p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11
假设我们的消费者组里面有三个消费者。
6.1 range范围策略
range策略就是按照partiton的序号范围p0~3 consumer1p4~7 consumer2p8~11 consumer3
默认就是这个策略
6.2 round-robin轮循策略
consumer1: 0,3,6,9
consumer2: 1,4,7,10
consumer3: 2,5,8,11但是前面的这两个方案有个问题:假设consuemr1挂了:p0-5分配给consumer2,p6-11分配给consumer3这样的话,原本在consumer2上的的p6,p7分区就被分配到了 consumer3上
6.3 sticky黏性策略
最新的一个sticky策略,就是说尽可能保证在rebalance的时候,让原本属于这个consumer
的分区还是属于他们,然后把多余的分区再均匀分配过去,这样尽可能维持原来的分区分配的策略consumer1: 0-3
consumer2: 4-7
consumer3: 8-11 假设consumer3挂了
consumer1:0-3,+8,9
consumer2: 4-7,+10,11
7. consumer核心参数
【heartbeat.interval.ms】
默认值:3000
consumer心跳时间,必须得保持心跳才能知道consumer是否故障了,然后如果故障之后,就会通过心跳下发rebalance的指令给其他的consumer通知他们进行rebalance的操作【session.timeout.ms】
默认值:10000
kafka多长时间感知不到一个consumer就认为他故障了,默认是10秒【max.poll.interval.ms】
默认值:300000
如果在两次poll操作之间,超过了这个时间,那么就会认为这个consume处理能力太弱了,会被踢出消费组,分区分配给别人去消费,一遍来说结合你自己的业务处理的性能来设置就可以了【fetch.max.bytes】
默认值:1048576
获取一条消息最大的字节数,一般建议设置大一些【max.poll.records】
默认值:500条
一次poll返回消息的最大条数,【connections.max.idle.ms】
默认值:540000
consumer跟broker的socket连接如果空闲超过了一定的时间,此时就会自动回收连接,但是下次消费就要重新建立socket连接,这个建议设置为-1,不要去回收【auto.offset.reset】earliest当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费 latest当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从当前位置开始消费nonetopic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常
注:我们生产里面一般设置的是latest【enable.auto.commit】
默认值:true
设置为自动提交offset【auto.commit.interval.ms】
默认值:60 * 1000
每隔多久更新一下偏移量
官网查看kafka参数http://kafka.apache.org/10/documentation.html
8. 指定位置开始消费
1.从0开始消费
TopicPartition partition = new TopicPartition("order", 0);consumer.assign(Arrays.asList(partition));consumer.seekToBeginning(Arrays.asList(partition));while (true) {ConsumerRecords<Integer, String> poll = consumer.poll(Duration.ofMillis(100));for (ConsumerRecord<Integer, String> record : poll) {System.out.println(record.key() + "-------" + record.value());}}
2.从指定位置开始消费
TopicPartition partition = new TopicPartition("order", 0);consumer.assign(Arrays.asList(partition));//从指定位置开始消费consumer.seek(partition, 5310);while (true) {ConsumerRecords<Integer, String> poll = consumer.poll(Duration.ofMillis(100));for (ConsumerRecord<Integer, String> record : poll) {System.out.println(record.key() + "-------" + record.value());}}
9. 总结!!!
9.1、内核原理
ISR机制 :就是跟leader同步的follower的数量,默认再ISR列表中的follower才可以参与leader的选举,【unclean.leader.election.enable】参数默认是false,修改为true,就可以让不在ISR列表中的follower参与leader选举
HW:Highwatermark,标定了一个偏移量值,该偏移量之前的消息对消费者可见,可以消费。
LEO:last end offset,日志末端偏移量,标记当前log文件中下一条待写入的消息的offset。
HW<=LEO
更新机制
1、leader写log后更新自己的LEO
2、follower请求从leader拉去数据时带着自己LEO,leader根据这个跟更新这边follower副本的LEO
3、比较leader和副本取最小LEO更新作为leader的HW
4、follower得到同步数据包含leader的HW,写数据后更新自己的LEO,并得到的HW作为自己的HW更新
2、3、4会重复因为有多个follower会请求同步数据
9.2、生产者核心流程
生产者主线程经过消息序列化和分区,发送到一个缓冲区Record Accumulator(32M),这个缓冲区中会依照partition数量来构建多个队列,并将消息封装成一个个batch(16kb)【涉及一个参数linger.ms】,发送给sender线程,sender线程将消息封装成一个request发送给kafka的channel,kafka做出响应。
9.3、生产者核心参数
吞吐量
buffer.memory 默认 32MB 缓冲区Record Accumulator
batch.size 默认 16kb 缓冲区中的队列中的batch大小
linger.ms 默认是 0
假如设置为100ms,这样的话就是说,这个消息被发送出去后进入一个batch,如果100毫秒内,这个batch大小达到【batch.size的值】16kB,自然就会发送出去。
但是如果100毫秒内,batch没满,那么也必须把消息发送出去了,不能让消息的发送延迟时间太长,也避免给内存造成过大的一个压力。
compression.type 默认是none ,可以指定gzip、snappy,用于批量处理,批量处理消息越多,压缩性能越好。
ACK参数
ack=0 生产者发送消息不做确认,直接视为发送成功
ack=1 只确认leader写入成功,视为发送成功
ack=all(或-1) 确认leader写入成功以及ISR中的副本都写入成功,才视为发送成功
retries参数只能在 ack=1和all的时候起作用
消息重试乱序:
max.in.flight.requests.per.connection 就是生产者给broker发送消息可以接受有多少条消息没有响应,默认是5
消息重试是可能导致消息的乱序的,因为可能排在你后面的消息都发送出去了,你现在收到回调失败了才在重试,此时消息就会乱序,所以可以使用“max.in.flight.requests.per.connection”参数设置为1,这样可以保证producer同一时间只能发送一条消息
9.4、broker节点核心参数
【log.retention.hours】
可以设置一下,要保留数据多少个小时(默认168小时),这个就是底层的磁盘文件,默认保留7天的数据,根据自己的需求来就行了
【unclean.leader.election.enable】
默认是false,意思就是只能选举ISR列表里的follower成为新的leader,1.0版本后才设为false,之前都是true,允许非ISR列表的follower选举为新的leader
9.5、消费者offset偏移量管理
【auto.offset.reset】
【enable.auto.commit】
【auto.commit.interval.ms】
0.8前存在zk上,后面存在kafka自身的一个topic【consumer_offsets】里
一般不自动提交offset,
9.6、消费者Coordinator协调器
负责监控这个消费组里的各个消费者的心跳,以及判断是否宕机,然后开启rebalance.
consumer-roup-id.hashcode % 分区数 =》分区号,该分区的leader所在的broker就是这个consumer group的coordinator。
9.7、消费者负载均衡rebalance策略
范围策略,连续平分
轮循策略
黏性策略,在负载均衡的基础上如果有消费者宕机,保证其他消费者消费分区不变,将宕机的消费者的分区平分
相关文章:
kakfa-3:ISR机制、HWLEO、生产者、消费者、核心参数负载均衡
1. kafka内核原理 1.1 ISR机制 光是依靠多副本机制能保证Kafka的高可用性,但是能保证数据不丢失吗?不行,因为如果leader宕机,但是leader的数据还没同步到follower上去,此时即使选举了follower作为新的leaderÿ…...
【微知】如何查看Mellanox网卡上的光模块的信息?(ethtool -m enp1s0f0 看型号、厂商、生产日期等)
背景 服务器上插入的光模块经常被忽略,往往这里是定位问题最根本的地方。如何通过命令查看? 命令 ethtool提供了-m参数,m是module-info的意思,他是从光模块的eeprom中读取数据。(应该是用i2c协议读取的)…...
yum源选要配置华为云的源,阿里云用不了的情况
curl -O /etc/yum.repos.d/CentOS-Base.repo https://repo.huaweicloud.com/repository/conf/CentOS-7-reg.repo...
nginx accesslog 打印自定义header
比如我在请求的header中添加了一个path-match-type,那我现在nginx的accesslog 中打印出来,应该如何配置呢? rootnginx-59f5d66df6-jw5k8:/# cat /etc/nginx/nginx.conf user nginx; worker_processes auto;error_log /var/log/nginx/erro…...
好数——前缀和思想(题目分享)
今天我的舍友去参加“传智杯”广东省的省赛,跟我说了这样一道题,他说他想不出来怎么去优化代码,怎么做都是套用两层for循环超时,下面我就根据题意,使用前缀和的算法去优化一下思路,题目本身是不难的&#x…...
MWC 2025 | 移远通信大模型解决方案加速落地,引领服务机器人创新变革
随着人工智能、大模型等技术的蓬勃发展,生成式AI应用全面爆发。在此背景下,服务机器人作为大模型技术在端侧落地的关键场景,迎来了前所未有的发展机遇。 作为与用户直接交互的智能设备,服务机器人需要应对复杂场景下的感知、决策和…...
【大模型基础_毛玉仁】0.概述
更多内容:XiaoJ的知识星球 【大模型基础_毛玉仁】 系列文章参考 系列文章 【大模型基础_毛玉仁】0.概述 【大模型基础_毛玉仁】1.1 基于统计方法的语言模型 更新中。。。。。。 参考 书籍:大模型基础_完整版.pdf Github:https://github.co…...
ADB、Appium 和 大模型融合开展移动端自动化测试
将 ADB、Appium 和 大模型(如 GPT、LLM) 结合,可以显著提升移动端自动化测试的智能化水平和效率。以下是具体的实现思路和应用场景: 1. 核心组件的作用 ADB(Android Debug Bridge): 用于与 Android 设备通信,执行设备操作(如安装应用、获取日志、截图等)。Appium: 用…...
springboot425-基于SpringBoot的BUG管理系统(源码+数据库+纯前后端分离+部署讲解等)
💕💕作者: 爱笑学姐 💕💕个人简介:十年Java,Python美女程序员一枚,精通计算机专业前后端各类框架。 💕💕各类成品Java毕设 。javaweb,ssm…...
Ubuntu系统上部署Node.js项目的完整流程
以下是在Ubuntu系统上部署Node.js项目的完整流程,分为系统初始化、环境配置、项目部署三个部分: 一、系统初始化 & 环境准备 bash # 1. 更新系统软件包 sudo apt update && sudo apt upgrade -y# 2. 安装基础工具 sudo apt install -y buil…...
X Window---图形接口
摘抄自 鸟哥的linux私房菜 基础篇 第四版 有鉴于图形用户接口(Graphical User Interface, GUI) 的需求日益加重,在 1984 年由 MIT 与其他第三方首次发表了 X Window System ,并且更在 1988 年成立了非营利性质的 XFree86 这个组织。所谓的XFree86 其实是…...
数据序列化协议 Protobuf 3 介绍(Go 语言)
Protobuf 3 入门 1. 什么是序列化? 1.1 概念 序列化(Serialization 或 Marshalling) 是指将数据结构或对象的状态转换成可存储或传输的格式。反向操作称为反序列化(Deserialization 或 Unmarshalling),它…...
FineReport 操作注意
1.父单元格重复的时候,如何取消合并 效果如下: 只需要在单元格中,将数据设置为【列表】即可。 2.待定...
3D手眼标定转换详细实施步骤及原理概述
3D手眼标定转换详细实施步骤及原理概述 一、手眼标定的核心目标二、3D手眼标定的原理概述一、基本概念与坐标系定义**二、数学建模与方程推导****1. 坐标变换的齐次矩阵表示****2. 手眼标定方程推导** **三、方程求解方法****1. 分离旋转与平移****2. 旋转矩阵求解****3. 平移向…...
Verilog:SCCB控制器
目录 一、SCCB协议 (1)SCCB时序 (2)与I2C的区别 二、Verilog 实现 (1)设计要求 (2)设计要点 (3)模块完整代码 三、功能验证 (1)写…...
维度建模基础篇:从理论到核心组件解析
维度建模基础篇:从理论到核心组件解析 引言 在数据仓库与商业智能(BI)领域,维度建模(Dimensional Modeling)作为一种经典的数据组织方法论,自Kimball提出以来,已成为构建高效分析型系统的核心范式1,2,3。其以业务需求为导向,通过事实表与维度表的组合,实现对复杂…...
与中国联通技术共建:通过obdiag分析OceanBase DDL中的报错场景
中国联通软件研究院(简称联通软研院)在全面评估与广泛调研后,在 2021年底决定采用OceanBase 作为基础,自研分布式数据库产品CUDB(即China Unicom Database,中国联通数据库)。目前,该…...
大数据与网络安全讲座
🍅 点击文末小卡片 ,免费获取网络安全全套资料,资料在手,涨薪更快 大数据的价值为大家公认。业界通常以4个“V”来概括大数据的基本特征——Volume(数据体量巨大)、Variety(数据类型繁多)、Value(价值密度低)、Velocity(处理速度快…...
AtCoder Beginner Contest 395 E
点我写题 题意:给个有向图,从1出发,每次可以走一条有向边,花费为1,也可以选择把全部有向边翻转,花费x,问到n的最小花费 思路:最短路dp,定义dis[i][0/1]表示走到i为止&…...
Linux进程管理6 - CFS调度
0、CFS调度器 CFS调度器使用完全公平调度算法。 完全公平调度算法引入虚拟运行时间的概念:虚拟运行时间 = 实际运行时间 * nice_0_weight / 进程的权重。完全公平调度算法使用红黑树把进程按虚拟运行时间从小到大排序,每次调度选择虚拟运行时间最小的进程。时间片 操作系统进…...
张驰咨询:用六西格玛重构动力电池行业的BOM成本逻辑
在动力电池行业,BOM(物料清单)成本每降低1%,都可能改写企业的利润曲线。某头部企业的三元锂电池BOM成本曾较行业标杆高出11%,单电芯利润率被压缩至3%的生死线。然而,通过张驰咨询的六西格玛方法论ÿ…...
pyside6学习专栏(九):在PySide6中使用PySide6.QtCharts绘制6种不同的图表的示例代码
PySide6的QtCharts类支持绘制各种型状的图表,如面积区域图、饼状图、折线图、直方图、线条曲线图、离散点图等,下面的代码是采用示例数据绘制这6种图表的示例代码,并可实现动画显示效果,实际使用时参照代码中示例数据的格式将实际数据替换即可…...
SpringBoot获取YAML配置文件中的属性值(二):使用Environment环境组件读取值
Spring Boot 使用 Properties 和 YAML 配置文件文件,系列文章: 《Spring使用@Value注解与@PropertySource注解加载配置文件》 《SpringBoot获取YAML配置文件中的属性值(一):使用@Value注解、@ConfigurationProperties注解》 《SpringBoot获取YAML配置文件中的属性值(二)…...
14天 -- Redis 的持久化机制有哪些?Redis 主从复制的实现原理是什么? Redis 数据过期后的删除策略是什么?
Redis 的持久化机制有哪些? Redis 是一种高性能的键值存储系统,主要用于缓存、消息队列等场景。为了防止数据丢失,Redis 提供了多种持久化机制,主要包括以下两种: 1. RDB(Redis Database Backupÿ…...
《深度学习实战》第10集:联邦学习与隐私保护
第10集:联邦学习与隐私保护 2025年3月4日更新了代码,补充了实例程序运行截图 和 如何提高模型准确率的方法 系统梳理 集集精彩 代码验证 保证实战 随着数据隐私问题日益受到关注,联邦学习(Federated Learning) 作为一…...
如何解决跨域请求的问题(CORS)?
文章目录 1. 引言2. 理解 CORS2.1 CORS 基本概念2.2 同源策略与跨域分类 3. CORS 的核心机制3.1 预检请求(Preflight Request)3.2 简单请求 4. 服务器端配置 CORS4.1 关键响应头4.2 Node.js (Express) 示例4.3 其他后端语言配置 5. 前端处理 CORS 请求5.…...
【数据结构】二叉树总结篇
遍历 递归 递归三部曲: 1.参数和返回值 2.终止条件 3.单层逻辑(遍历顺序) var preorderTraversal function(root) { // 第一种let res[];const dfsfunction(root){if(rootnull)return ;//先序遍历所以从父节点开始res.push(root.val);//递归…...
软考-数据库开发工程师-3.1-数据结构-线性结构
第3章内容比较多,内容考试分数占比较大,6分左右 线性表 1、线性表的定义 一个线性表是n个元素的有限序列(n≥0),通常表示为(a1,a2, a3,…an). 2、线性表的顺序存储(顺序表) 是指用一组地址连续的存储单元依次存储线性表中的数据元…...
【五.LangChain技术与应用】【2.LangChain虚拟环境搭建(下):环境优化与调试】
一、Docker化部署:别让你的环境成为薛定谔的猫 经历过"在我机器上能跑"惨案的老铁都懂,传统虚拟环境就像个黑盒子。去年我帮客户部署LangChain应用,因为glibc版本差了0.1,整个服务直接崩成烟花。从那天起,我所有项目都强制上Docker! Dockerfile生存指南: #…...
deepseek+mermaid【自动生成流程图】
成果: 第一步打开deepseek官网(或百度版(更快一点)): 百度AI搜索 - 办公学习一站解决 第二步,生成对应的Mermaid流程图: 丢给deepseek代码,或题目要求 生成mermaid代码 第三步将代码复制到me…...
