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

消息中间件-kafka实战-第五章-kafka重复消费、顺序消费及死信队列

目录

  • 一、参考
  • 二、路由规则(分片规则)
  • 三、触发重复消费的场景
    • 场景一:触发rebalance
      • 问题描述
      • 可能原因
      • 实际影响参数
      • 在kafka0.10.1 之前:
      • 在kafka0.10.1之后:
      • 解决方案
    • 场景二:服务宕机
      • 可能原因
      • 解决方案
    • 消息幂等性
  • 四、kafka参数特性
    • 常见配置
  • 五、死信队列
    • 方案一:工厂类KafkaListenerContainerFactory
      • 配置工厂类
      • 死信队列消费者
    • 方案二:错误ConsumerAwareListenerErrorHandler
      • 配置
      • 消费者
  • 六、顺序消费
    • 场景

一、参考

kafka如何解决重复消费?
Kafka重复消费

二、路由规则(分片规则)

发一个消息,如何知道消息被默认分片到哪里

1.如果没有指定key,是随机分片

2.如果指定了key,即 kafkaTemplate.send(topic, null, jsonValue);

可以套用一下公式计算:

      key.hashCode() % 12

例如有一个topic 叫test,有8个patition,key=“1”,则日志文件在

    "1".hashCode() % 8=1

在 *****/log/test-1/ 目录下面

三、触发重复消费的场景

场景一:触发rebalance

参考:使用Kafka时一定要注意防止消费速度过慢触发rebalance而导致的重复消费
参考:spring设置kafka超时时间没有生效的解决方法(解决rebalancing问题)

rebalance就是kafka认为消费者已经离线或者挂掉,就会触发rebalance把消息分配给新的消费者kafka重新平衡是按group
即当消费速度过慢时有可能会触发rebalance, 这批消息被分配到另一个消费者,然后新的消费者还会消费过慢,再次rebalance, 这样一直恶性循环下去。发生这种情况最明显的标志就是日志里能看到CommitFailedException异常,然后还会带上下面一段话:

问题描述

Commit cannot be completed since the group has already rebalanced and assigned the partitions to another member. This means that the time between subsequent calls to poll() was longer than the configured max.poll.interval.ms, which typically implies that the poll loop is spending too much time message processing. You can address this either by increasing the session timeout or by reducing the maximum size of batches returned in poll() with max.poll.records.

可能原因

  • 原因1:强行kill线程,导致消费后的数据,offset没有提交(消费系统宕机、重启等)。
  • 原因2:设置offset为自动提交,关闭kafka时,如果在close之前,调用 consumer.unsubscribe() 则有可能部分offset没提交,下次重启会重复消费。
  • 原因3:(重复消费最常见的原因):消费后的数据,当offset还没有提交时,partition就断开连接。比如,通常会遇到消费的数据,处理很耗时,导致超过了Kafka的session timeout时间(0.10.x版本默认是30秒),那么就会re-blance重平衡,此时有一定几率offset没提交,会导致重平衡后重复消费。
  • 原因4:当消费者重新分配partition的时候,可能出现从头开始消费的情况,导致重发问题。
  • 原因5:当消费者消费的速度很慢的时候,可能在一个session周期内还未完成,导致心跳机制检测报告出问题。
  • 原因6:并发很大,可能在规定的时间(session.time.out默认30s)内没有消费完,就会可能导致reblance重平衡,导致一部分offset自动提交失败,然后重平衡后重复消费

实际影响参数

这里我们需要明确一下,在Kafka 0.10.1.0以后的版本中,影响rebalance触发的参数有三个,说明如下:

  • spring.kafka.properties.session.timeout.ms(默认10秒10000)
    这个参数定义了当broker多久没有收到consumer的心跳请求后就触发rebalance,默认值是10s。在0.10.1.0之前的版本中,由于心跳请求是在poll()拉取消息的方法中执行的,因此如果当前批次处理消息耗时太长,就会导致consumer没有机会按时发送心跳,broker认为消费者已死,触发rebalance。在0.10.1.0或更新的版本中解决了这个问题,心跳请求会在单独的线程中发送,因此就不会出现因为消息处理过长而发不出心跳的问题了。而每次发送心跳请求的时间 spring.kafka.properties.heartbeat.interval.ms = 3000(默认三秒)

  • spring.kafka.properties.max.poll.interval.ms(默认值为5分钟300000)
    这个参数定义了两次poll()之间的最大间隔,默认值为5分钟。如果超过这个间隔同样会触发rebalance。在多数情况下这个参数是导致rebalance消息重复的关键,即业务处理消息耗时太长,导致一直没有commit确认收到的消息,然后超过了消费者设置的最大拉取时间。有人可能会疑惑,如果5分钟都没处理完消息那肯定时出了问题,其实不然。能否在5min内处理完还取决于你每次拉取了多少条消息,如果一次拿到了成千上万条的话,5min就够呛了。有也可能是某个消费者节点正在调试,导致线程一直阻塞在那里,然后超过了最大拉取时间.

  • spring.kafka.consumer.max.poll.records
    这个参数定义了poll()方法最多可以返回多少条消息,默认值为500。注意这里的用词是"最多",也就是说如果在拉取消息的时候新消息不足500条,那有多少返回多少;如果超过500条,就只返回500。这个默认值是比较坑人的,如果你的消息处理逻辑比较重,比如需要查数据库,调用接口,甚至是复杂计算,那么你很难保证能够在5min内处理完500条消息,也就是说,如果上游真的突然大爆发生产了成千上万条消息,而平摊到每个消费者身上的消息达到了500的又无法按时消费完成的话就会触发rebalance, 然后这批消息会被分配到另一个消费者中,还是会处理不完,又会触发rebalance, 这样这批消息就永远也处理不完,而且一直在重复处理。

在kafka0.10.1 之前:

检查整个消费者死亡和检查消费则处理线程,使用的同一个线程,如果设置的max.poll.interval.ms大于session.timeout.ms,遇到一个处理时间过长的消息,会由于线程忙于处理消息,而无法发送心跳,导致kafka认为改消费则已完全死亡,进而进行Rebalance
所以推荐设置:heartbeat.inerval.ms < max.poll.interval.ms < session.timeout.ms

在kafka0.10.1之后:

session.timeout.ms 和 max.poll.interval.ms 解耦了,拆成了两个线程,不用再担心它们之间的依赖关系
推荐设置:heartbeat.interval.ms < session.timeout.ms

解决方案

要避免出现上述问题也很简单,那就是提前评估好处理一条消息最长需要多少时间,然后务必覆盖默认的max.poll.records参数。在spring-kafka中这个原生参数对应的参数项是max-poll-records。对于消息处理比较重的操作,建议把这个值改到50以下会保险一些。

  • 调整几个参数
spring.kafka.properties.max.poll.interval.ms = 600000
spring.kafka.consumer.max.poll.records = 20
spring.kafka.properties.session.timeout.ms = 25000# spring设置kafka参数session超时时间时,要小于请求超时时间与处理超时时间,例如:request.timeout.ms = 30000  session.timeout.ms = 15000    max.poll.interval.ms = 300000session.timeout.ms < request.timeout.mssession.timeout.ms < max.poll.interval.ms
  • 把这个组里比较重要的几个topic移动出去,换到其它组(java里只需要改一行):
//这里没有显式配置组,用的是上方KafkaConfig.java里的commonGroup组
//@KafkaListener(topics = "${kafka.topic.commit}")//改为了显式配置组,把这个topic移动到新组 commitGroup
@KafkaListener(topics = "${kafka.topic.commit}", groupId = "commitGroup")
  • 减少每次拉取的消息记录数和增大poll之间的时间间隔
  • 拉取到消息之后异步处理(保证成功消费)

场景二:服务宕机

可能原因

  • 消费者宕机、重启等。导致消息已经消费但是没有提交offset。

  • 由于网络问题,重复消费不可避免,因此,消费者需要实现消费幂等。#

解决方案

  • ①:消息表

  • ②:数据库唯一索引

  • ③:缓存消费过的消息id

消息幂等性

可以通过redis.setnx方法
key = topic:pardition:offset
redis.setnx(key ,alue);如果没设置过返回1,设置过返回0

四、kafka参数特性

新版kafka的broker幂等性具体实现原理:
  kafka每次发送消息会生成PID和Sequence Number,并将这两个属性一起发送给broker,broker会将PID和Sequence Number跟消息绑定一起存起来,下次如果生产者重发相同消息,broker会检查PID和    Sequence Number,如果相同不会再接收。

PID:每个新的 Producer 在初始化的时候会被分配一个唯一的 PID,这个PID对用户完全是透明的。生产者如果重启则会生成新的PID。

常见配置

fetch.min.byte:配置Consumer一次拉取请求中能从Kafka中拉取的最小数据量,默认为1B,如果小于这个参数配置的值,就需要进行等待,直到数据量满足这个参数的配置大小。调大可以提交吞吐量,但也会造成延迟

fetch.max.bytes,一次拉取数据的最大数据量,默认为52428800B,也就是50M,但是如果设置的值过小,甚至小于每条消息的值,实际上也是能消费成功的

fetch.wait.max.ms,若是不满足fetch.min.bytes时,等待消费端请求的最长等待时间,默认是500ms

max.poll.records,单次poll调用返回的最大消息记录数,如果处理逻辑很轻量,可以适当提高该值。一次从kafka中poll出来的数据条数,max.poll.records条数据需要在在session.timeout.ms这个时间内处理完,默认值为500

consumer.poll(100) ,100 毫秒是一个超时时间,一旦拿到足够多的数据(fetch.min.bytes 参数设置),consumer.poll(100)会立即返回 ConsumerRecords<String, String> records。如果没有拿到足够多的数据,会阻塞100ms,但不会超过100ms就会返回

max.poll.interval.ms,两次拉取消息的间隔,默认5分钟;通过消费组管理消费者时,该配置指定拉取消息线程最长空闲时间,若超过这个时间间隔没有发起poll操作,则消费组认为该消费者已离开了消费组,将进行再均衡操作(将分区分配给组内其他消费者成员)

若超过这个时间则报如下异常:

org.apache.kafka.clients.consumer.CommitFailedException: Commit cannot be completed since the group has already
rebalanced and assigned the partitions to another member. This means that the time between subsequent calls
to poll() was longer than the configured max.poll.interval.ms, which typically implies that the poll loop is
spending too much time message processing. You can address this either by increasing the session timeout or by
reducing the maximum size of batches returned in poll() with max.poll.records. 
  即:无法完成提交,因为组已经重新平衡并将分区分配给另一个成员。这意味着对poll()的后续调用之间的时间比配置的max.poll.interval.ms长,这通常意味着poll循环花费了太多的时间来处理消息。

可以通过增加max.poll.interval.ms来解决这个问题,也可以通过减少在poll()中使用max.poll.records返回的批的最大大小来解决这个问题

max.partition.fetch.bytes:该属性指定了服务器从每个分区返回给消费者的最大字节数,默认为 1MB。

session.timeout.ms:消费者在被认为死亡之前可以与服务器断开连接的时间,默认是 3s,将触发再均衡操作

对于每一个Consumer Group,Kafka集群为其从Broker集群中选择一个Broker作为其Coordinator。Coordinator主要做两件事:

维持Group成员的组成。这包括加入新的成员,检测成员的存活性,清除不再存活的成员。

协调Group成员的行为。

poll机制

①:每次poll的消息处理完成之后再进行下一次poll,是同步操作

②:每次poll之前检查是否可以进行位移提交,如果可以,那么就会提交上一次轮询的位移

③:每次poll时,consumer都将尝试使用上次消费的offset作为起始offset,然后依次拉取消息

④:poll(long timeout),timeout指等待轮询缓冲区的数据所花费的时间,单位是毫秒

五、死信队列

方案一:工厂类KafkaListenerContainerFactory

配置工厂类

import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.header.Header;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
import org.springframework.kafka.config.KafkaListenerContainerFactory;
import org.springframework.kafka.core.ConsumerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.listener.*;
import org.springframework.stereotype.Component;
import org.springframework.util.backoff.BackOff;
import org.springframework.util.backoff.FixedBackOff;import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Optional;/*** 消费MQ的消息配置* @author demo* @create 2022-11-12*/@Slf4j
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@ConditionalOnProperty(name = "mq.pipeline", havingValue = IotConstant.MQ_KAFKA)
public class KafkaReceiverConfig {@Resourceprivate ConsumerFactory<String,String> consumerFactory;@Resourceprivate KafkaTemplate<String,String>  kafkaTemplate;@Beanpublic KafkaListenerContainerFactory<?> retryKafkaFactory() {ConcurrentKafkaListenerContainerFactory<String, String> factory =new ConcurrentKafkaListenerContainerFactory<>();factory.setConsumerFactory(consumerFactory);// 最大重试次数2次,重试间隔10秒,超过2次(本身一次,重试一次)还没成功,进入死信队列// 注意:目前自动创建主题的配置关闭了,需要提前手动去创建好死信队列主题!!! 死信队列主题的命名方式:原主题名称 + .DLTfactory.setErrorHandler(new SeekToCurrentErrorHandler(new DeadLetterPublishingRecoverer(Collections.singletonMap(Object.class, kafkaTemplate), (cr, e) -> new TopicPartition(cr.topic() + ".DLT", cr.partition())), new FixedBackOff(10 * 1000L, 2L)));return factory;}}`### 消费者`````java/*** 发送消息* @param consumerRecord 消息记录* @param topicGroupId 消费组*/@KafkaListener(topics = "#{'${mq.alarm.inner.topic.name}'.split(',')}", containerFactory = "retryKafkaFactory")public void consumer(ConsumerRecord<?, String> consumerRecord, @Header(KafkaHeaders.GROUP_ID) String topicGroupId) {Optional<String> kafkaMessage = Optional.ofNullable(consumerRecord.value());if (kafkaMessage.isPresent()) {String id = null;try {String json = kafkaMessage.get();// todo...} catch (Throwable t) {// 判断是否可恢复异常if(isRecoverable(t)){// ...IotCacheUtil.deleteMessageId(id);// 送入死信队列throw  t;} else {log.error("消费失败 topic:{}, messageId:{}, offset:{}, partition:{} ,异常:{}",consumerRecord.topic(),id,consumerRecord.offset(),consumerRecord.partition(),t);}}}}

死信队列消费者

@KafkaListener( topics = "iotAiAlarmInner.DLT")public void messageListenerDLT(ConsumerRecord<?, String> consumerRecord, @Header(KafkaHeaders.GROUP_ID) String topicGroupId) {log.info("告警死信队列 topic:{}, offset:{}, partition:{} ,key:{}, message:{}",consumerRecord.topic(),consumerRecord.offset(),consumerRecord.partition(),consumerRecord.key(),Optional.ofNullable(consumerRecord.value()).orElse(null));Optional<String> kafkaMessage = Optional.ofNullable(consumerRecord.value());if (kafkaMessage.isPresent()) {}}

方案二:错误ConsumerAwareListenerErrorHandler

配置


/*** 消费MQ的消息配置* @author demo* @create 2022-11-12*/@Slf4j
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@ConditionalOnProperty(name = "mq.pipeline", havingValue = IotConstant.MQ_KAFKA)
public class KafkaReceiverConfig {@Resourceprivate ConsumerFactory<String,String> consumerFactory;@Resourceprivate KafkaTemplate<String,Object>  kafkaTemplate;/*** 针对tag消息过滤* producer 将tag写进header里* @return ConcurrentKafkaListenerContainerFactory*/@Beanpublic ConcurrentKafkaListenerContainerFactory<String,String> filterContainerFactory() {ConcurrentKafkaListenerContainerFactory<String,String> factory = new ConcurrentKafkaListenerContainerFactory<>();factory.setConsumerFactory(consumerFactory);// 被过滤的消息将被丢弃factory.setAckDiscarded(true);factory.setRecordFilterStrategy(consumerRecord -> {if (Optional.ofNullable(consumerRecord.value()).isPresent()) {for (Header header : consumerRecord.headers()) {if (header.key().equals(IotConstant.MQ_TAG) && new String(header.value()).equals(new String(IotConstant.MQ_TAG_VALUE.getBytes(StandardCharsets.UTF_8)))) {return false;}}}//返回true将会被丢弃return true;});return factory;}@Beanpublic ConsumerAwareListenerErrorHandler consumerIotAlarmAwareErrorHandler() {return new ConsumerAwareListenerErrorHandler() {@Overridepublic Object handleError(Message<?> message, ListenerExecutionFailedException e, Consumer<?, ?> consumer) {log.error("consumerAwareErrorHandler receive : {}, error:{}",message.getPayload(),e);//获取消息处理异常主题MessageHeaders headers = message.getHeaders();/*List<String> topics = headers.get(KafkaHeaders.RECEIVED_TOPIC, List.class);List<Integer> partitions = headers.get(KafkaHeaders.RECEIVED_PARTITION_ID, List.class);List<Long> offsets = headers.get(KafkaHeaders.OFFSET, List.class);*/Map<TopicPartition, Long> offsetsToReset = new HashMap<>();
//                String topic=headers.get("kafka_receivedTopic")+TOPIC_DLT;String topic="iotAlarmInner"+ KafkaAlarmListener.TOPIC_DLT;//放入死信队列kafkaTemplate.send(topic,message.getPayload());return message;}};}
}

消费者

import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.KafkaHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.net.UnknownHostException;
import java.util.Optional;/*** 内部自产自销消费者* @author demo* @create 2022-11-09*/
@Slf4j
@Component
@ConditionalOnProperty(name = "mq.pipeline", havingValue = IotConstant.MQ_KAFKA)
public class KafkaAlarmListener {@PostConstructpublic void init() {log.info("启动了通用告警消费者");}public static final String TOPIC_DLT=".DLT";@Resourceprivate DeviceService deviceService;/*** 发送消息* @param consumerRecord 消息记录* @param topicGroupId 消费组*/@KafkaListener(topics = "#{'${mq.alarm.inner.topic.name}'.split(',')}",errorHandler = "consumerIotAlarmAwareErrorHandler",concurrency = "3")public void consumer(ConsumerRecord<?, String> consumerRecord, @Header(KafkaHeaders.GROUP_ID) String topicGroupId) {execute(consumerRecord, false);}/*** 死信队列* @param consumerRecord 消息记录* @param topicGroupId 消费组*/@KafkaListener( topics = "iotAlarmInner"+TOPIC_DLT)public void deadConsumer(ConsumerRecord<?, String> consumerRecord, @Header(KafkaHeaders.GROUP_ID) String topicGroupId) {log.info("告警死信队列 topic:{}, offset:{}, partition:{} ,key:{}",consumerRecord.topic(),consumerRecord.offset(),consumerRecord.partition(),consumerRecord.key());execute(consumerRecord, true);}private void execute(ConsumerRecord<?, String> consumerRecord,boolean dead){String title = dead?"告警死信":"告警";Optional<String> kafkaMessage = Optional.ofNullable(consumerRecord.value());if (kafkaMessage.isPresent()) {String id = null;try {String json = kafkaMessage.get();// 解析AlarmMessageDTO message = JsonUtil.parse(json,AlarmMessageDTO.class);// 判断消息是否已处理id = message.getId();if(json.length()>10000){log.info("{} topic:{}, offset:{}, partition:{} ,key:{}, messageId:{}",title,consumerRecord.topic(),consumerRecord.offset(),consumerRecord.partition(),consumerRecord.key(),id);}else{log.info("{} topic:{}, offset:{}, partition:{} ,key:{}, content:{}, messageId:{}",title,consumerRecord.topic(),consumerRecord.offset(),consumerRecord.partition(),consumerRecord.key(),id, json);}if(IotCacheUtil.isExistMessageId(id)){log.error("{} topic:{}, messageId:{} 重复消息",title,consumerRecord.topic(), id);return;}// 处理deviceService.uploadAlarm(message);} catch (Throwable t) {if(dead){log.error("{} 消费异常 topic:{}, offset:{}, partition:{}, messageId:{} ,异常:{}",title,consumerRecord.topic(),consumerRecord.offset(),consumerRecord.partition(),id,t);return;}// 判断是否可恢复异常if(isRecoverable(t)){// ...IotCacheUtil.deleteMessageId(id);// 触发失败errorHandler死信队列throw  t;} else {log.error("{} 消费失败 topic:{}, offset:{}, partition:{}, messageId:{} ,异常:{}",title,consumerRecord.topic(),consumerRecord.offset(),consumerRecord.partition(),id,t);}}}}private boolean isRecoverable(Throwable t){if(t instanceof NullPointerException){return false;}else if( t instanceof UnknownHostException){return false;}return true;}}

六、顺序消费

利用kafka的分区(pardition)功能,通过生产者send的时候设置key,kafka的broker会根据key计算hash,发送到对应的分区

场景

比如用户三次修改名字
我们再发送消息的时候,把userId设置为key,这样保证三条消息都在一个pardition

相关文章:

消息中间件-kafka实战-第五章-kafka重复消费、顺序消费及死信队列

目录 一、参考二、路由规则&#xff08;分片规则&#xff09;三、触发重复消费的场景场景一&#xff1a;触发rebalance问题描述可能原因实际影响参数在kafka0.10.1 之前:在kafka0.10.1之后&#xff1a;解决方案 场景二&#xff1a;服务宕机可能原因解决方案 消息幂等性 四、kaf…...

python爬虫9:实战2

python爬虫9&#xff1a;实战2 前言 ​ python实现网络爬虫非常简单&#xff0c;只需要掌握一定的基础知识和一定的库使用技巧即可。本系列目标旨在梳理相关知识点&#xff0c;方便以后复习。 申明 ​ 本系列所涉及的代码仅用于个人研究与讨论&#xff0c;并不会对网站产生不好…...

从业务层的代码出发,去排查通用框架代码崩溃的问题

目录 1、问题说明 1.1、Release下崩溃&#xff0c;Debug下很难复现 1.2、用Windbg打开dump文件&#xff0c;发现崩溃在通用的框架代码中 2、进一步分析 2.1、使用IDA查看汇编代码尝试寻找崩溃的线索 2.2、在Windbg中查看相关变量的值 2.3、查看最近代码的修改记录&#…...

LLM预训练大型语言模型Pre-training large language models

在上一个视频中&#xff0c;您被介绍到了生成性AI项目的生命周期。 如您所见&#xff0c;在您开始启动您的生成性AI应用的有趣部分之前&#xff0c;有几个步骤需要完成。一旦您确定了您的用例范围&#xff0c;并确定了您需要LLM在您的应用程序中的工作方式&#xff0c;您的下…...

[Machine Learning] 损失函数和优化过程

文章目录 机器学习算法的目的是找到一个假设来拟合数据。这通过一个优化过程来实现&#xff0c;该过程从预定义的 hypothesis class&#xff08;假设类&#xff09;中选择一个假设来最小化目标函数。具体地说&#xff0c;我们想找到 arg min ⁡ h ∈ H 1 n ∑ i 1 n ℓ ( X i…...

serialVersionUID 有何用途?如果没定义会有什么问题?

序列化是将对象的状态信息转换为可存储或传输的形式的过程。我们都知道&#xff0c;Java 对象是保持在 JVM 的堆内存中的&#xff0c;也就是说&#xff0c;如果 JVM 堆不存在了&#xff0c;那么对象也就跟着消失了。 而序列化提供了一种方案&#xff0c;可以让你在即使 JVM 停机…...

C# OpenCvSharp DNN 二维码增强 超分辨率

效果 项目 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using OpenCvSharp; using OpenCvSharp.Dnn; using OpenCvSh…...

this.$refs使用方法

深入理解和使用this.$refs——Vue.js的利器 Vue.js是一个流行的JavaScript框架&#xff0c;用于构建交互性强大的用户界面。在Vue.js中&#xff0c;this.$refs是一个强大的特性&#xff0c;允许你直接访问组件中的DOM元素或子组件实例。本教程将带你深入了解this.$refs的使用方…...

Ohio主题 - 创意组合和代理机构WordPress主题

Ohio主题是一个精心制作的多用途、简约、华丽、多功能的组合和创意展示主题&#xff0c;具有敏锐的用户体验&#xff0c;您需要构建一个现代且实用的网站&#xff0c;并开始销售您的产品和服务。它配备了最流行的WordPress页面构建器 WPBakery Page Builder&#xff08;以前称为…...

mysql 、sql server trigger 触发器

sql server mySQL create trigger 触发器名称 { before | after } [ insert | update | delete ] on 表名 for each row 触发器执行的语句块## 表名&#xff1a; 表示触发器监控的对象 ## before | after : 表示触发的时间&#xff0c;before : 表示在事件之前触发&am…...

自然语言处理从入门到应用——LangChain:索引(Indexes)-[检索器(Retrievers)]

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 检索器&#xff08;Retrievers&#xff09;是一个通用的接口&#xff0c;方便地将文档与语言模型结合在一起。该接口公开了一个get_relevant_documents方法&#xff0c;接受一个查询&#xff08;字符串&#xff09;并返…...

春秋云境:CVE-2022-0543(Redis 沙盒逃逸漏洞)

目录 一、i春秋题目 二、CVE-2022-0543&#xff1a;&#xff08;redis沙盒逃逸&#xff09; 漏洞介绍&#xff1a; 漏洞复现&#xff1a; 一、i春秋题目 靶标介绍&#xff1a; Redis 存在代码注入漏洞&#xff0c;攻击者可利用该漏洞远程执行代码。 进入题目&#xff1a;…...

关于uniapp组件的坑

关于uniapp组件的坑 我有一个组件写的没什么问题,但是报下面这个错误 is not found in path “components/xxx/xxxx” (using by “components/yyy/yyy”) 最后经过排除发现命名需要驼峰命名法 我原本组件命名: 文件夹名 test_tttt 文件名 test_tttt.vue 不行 最后改成文件…...

AIGC与软件测试的融合

一、ChatGPT与AIGC 生成式人工智能——AIGC&#xff08;Artificial Intelligence Generated Content&#xff09;&#xff0c;是指基于生成对抗网络、大型预训练模型等人工智能的技术方法&#xff0c;通过已有数据的学习和识别&#xff0c;以适当的泛化能力生成相关内容的技术。…...

滑动验证码-elementui实现

使用elementui框架实现 html代码 <div class"button-center"><el-popoverplacement"top":width"imgWidth"title"安全验证"trigger"manual"v-model"popoverVisible"hide"popoverHide"show&quo…...

ubuntu 20.04 安装 高版本cuda 11.7 和 cudnn最新版

一、安装显卡驱动 参考另一篇文章&#xff1a;Ubuntu20.04安装Nvidia显卡驱动教程_ytusdc的博客-CSDN博客 二、安装CUDA 英伟达官网&#xff08;最新版&#xff09;&#xff1a;CUDA Toolkit 12.2 Update 1 Downloads | NVIDIA Developer CUDA历史版本下载地址&#xff1a;C…...

svg图片如何渲染到页面,以及svg文件的上传

svg图片渲染到页面的几种方式 背景&#x1f7e1;require.context获取目录下的所有文件&#x1f7e1;方式1: 直接在html中渲染&#x1f7e1;方式: 发起ajax请求&#xff0c;获取SVG文件 背景 需要实现从本地目录下去获取所有的svg图标进行预览&#xff0c;将选中的图片显示在另…...

GPT-LLM-Trainer:如何使用自己的数据轻松快速地微调和训练LLM

一、前言 想要轻松快速地使用您自己的数据微调和培训大型语言模型&#xff08;LLM&#xff09;&#xff1f;我们知道训练大型语言模型具有挑战性并需要耗费大量计算资源&#xff0c;包括收集和优化数据集、确定合适的模型及编写训练代码等。今天我们将介绍一种实验性新方法&am…...

深入理解ForkJoin

任务类型 线程池执行的任务可以分为两种&#xff1a;CPU密集型任务和IO密集型任务。在实际的业务场景中&#xff0c;我们需要根据任务的类型来选择对应的策略&#xff0c;最终达到充分并合理地使用CPU和内存等资源&#xff0c;最大限度地提高程序性能的目的。 CPU密集型任务 …...

Spring5学习笔记—AOP编程

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Spring专栏 ✨特色专栏&#xff1a; M…...

适用于 Docker 用户的 kubectl

适用于 Docker 用户的 kubectl 你可以使用 Kubernetes 命令行工具 kubectl 与 API 服务器进行交互。如果你熟悉 Docker 命令行工具&#xff0c; 则使用 kubectl 非常简单。但是&#xff0c;Docker 命令和 kubectl 命令之间有一些区别。以下显示了 Docker 子命令&#xff0c; 并…...

网络安全设备篇——加密机

加密机是一种专门用于数据加密和解密的网络安全设备。它通过使用密码学算法对数据进行加密&#xff0c;从而保护数据的机密性和完整性。加密机通常被用于保护敏感数据&#xff0c;如金融信息、个人身份信息等。 加密机的主要功能包括&#xff1a; 数据加密&#xff1a;加密机使…...

Rust 基础入门 —— 2.3.所有权和借用

Rust 的最主要光芒&#xff1a; 内存安全 。 实现方式&#xff1a; 所有权系统。 写在前面的序言 因为我们这里实际讲述的内容是关于 内存安全的&#xff0c;所以我们最好先复习一下内存的知识。 然后我们&#xff0c;需要理解的就只有所有权概念&#xff0c;以及为了开发便…...

Node.js-Express框架基本使用

Express介绍 Express是基于 node.js 的web应用开发框架&#xff0c;是一个封装好的工具包&#xff0c;便于开发web应用&#xff08;HTTP服务&#xff09; Express基本使用 // 1.安装 npm i express // 2.导入 express 模块 const express require("express"); // 3…...

阿里云通用算力型u1云服务器CPU性能详细说明

​阿里云服务器u1是通用算力型云服务器&#xff0c;CPU采用2.5 GHz主频的Intel(R) Xeon(R) Platinum处理器&#xff0c;通用算力型u1云服务器不适用于游戏和高频交易等需要极致性能的应用场景及对业务性能一致性有强诉求的应用场景(比如业务HA场景主备机需要性能一致)&#xff…...

设计模式之创建者模式

文章目录 一、介绍二、应用三、案例1. 麦当劳11随心配2. 代码演示3. 演示结果 四、优缺点五、送给读者 一、介绍 建造者模式(Builder Pattern)属于创建型设计模式&#xff0c;很多博客文章的对它的作用解释为用于将复杂对象的创建过程与其细节表示分离。但对于初学者来说&…...

Java之包,权限修饰符,final关键字详解

包 2.1 包 包在操作系统中其实就是一个文件夹。包是用来分门别类的管理技术&#xff0c;不同的技术类放在不同的包下&#xff0c;方便管理和维护。 在IDEA项目中&#xff0c;建包的操作如下&#xff1a; 包名的命名规范&#xff1a; 路径名.路径名.xxx.xxx // 例如&#xff…...

“深入解析JVM:Java虚拟机内部原理揭秘“

标题&#xff1a;深入解析JVM&#xff1a;Java虚拟机内部原理揭秘 摘要&#xff1a;本文将深入探讨Java虚拟机&#xff08;JVM&#xff09;的内部原理&#xff0c;包括JVM的架构、运行时数据区域、垃圾回收机制以及即时编译器等重要组成部分。通过对JVM内部原理的解析&#xf…...

Mac下Jmeter安装及基本使用

本篇文章只是简单的介绍下Jmeter的下载安装和最基本使用 1、初识Jmeter 前一段时间客户端app自测的过程中&#xff0c;有偶现请求某个接口返回数据为空的问题&#xff0c;领导让我循环100次请求这个接口&#xff0c;看看有没有结果为空的问题。听同事说有Jmeter的专业测试工具…...

云计算与边缘计算:加速数字化转型的关键驱动力

云计算和边缘计算技术正以惊人的速度改变着企业的业务和基础架构。这些先进的技术为企业带来了灵活性、可扩展性和成本效益的优势&#xff0c;重新定义了业务运作的方式。 云计算是通过互联网将计算资源提供给用户的一种服务模式。通过云计算&#xff0c;企业可以将应用程序、…...

TheGem主题 - 创意多用途和高性能WooCommerce WordPress主题/网站

TheGem主题概述 – 适合所有人的TheGem 作为设计元素、样式和功能的终极 Web 构建工具箱而设计和开发&#xff0c;TheGem主题将帮助您在几分钟内构建一个令人印象深刻的高性能网站&#xff0c;而无需触及一行代码。不要在编码上浪费时间&#xff0c;探索你的创造力&#xff01…...

Pytorch-day10-模型部署推理-checkpoint

模型部署&推理 模型部署模型推理 我们会将PyTorch训练好的模型转换为ONNX 格式&#xff0c;然后使用ONNX Runtime运行它进行推理 1、ONNX ONNX( Open Neural Network Exchange) 是 Facebook (现Meta) 和微软在2017年共同发布的&#xff0c;用于标准描述计算图的一种格式…...

vue使用websocket

建立websocket.js // 信息提示 import { Message } from element-ui // 引入用户id import { getTenantId, getAccessToken } from /utils/auth// websocket地址 var url ws://192.168.2.20:48081/websocket/message // websocket实例 var ws // 重连定时器实例 var tt // w…...

jmeter入门:接口压力测试全解析

一.对接口压力测试 1.配置 1.添加线程组&#xff08;参数上文有解释 这里不介绍&#xff09; 2.添加取样器 不用解释一看就知道填什么。。。 3.添加头信息&#xff08;否则请求头对不上&#xff09; 也不用解释。。。 4.配置监听器 可以尝试使用这几个监听器。 2.聚合结果…...

go、java、.net、C#、nodejs、vue、react、python程序问题进群咨询

1、面试辅导 2、程序辅导 3、一对一腾讯会议辅导 3、业务逻辑辅导 4、各种bug帮你解决。 5、培训小白 6、顺利拿到offer...

树莓派4B最新系统Bullseye 64 bit使用xrdp远程桌面黑屏卡顿问题

1、树莓派换源 打开源文件 sudo nano /etc/apt/sources.list注释原来的&#xff0c;更换为清华源 deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib no…...

EasyExcel入门介绍及工具类,网络下载excel

前言&#xff1a;在这里分享自己第一次使用EasyExcel并且编写工具类&#xff0c;且在接口中支持excel文件下载的一系列流程&#xff0c;包含所有前后端&#xff08;JSJAVA&#xff09;完整代码&#xff0c;可以根据自己需要自行提取&#xff0c;仅供参考。 一.引入EasyExcel依赖…...

【HarmonyOS北向开发】-04 ArkTS开发语言-ArkTS基础知识

飞书原文档&#xff1a;Docs...

【Alibaba中间件技术系列】「RocketMQ技术专题」小白专区之领略一下RocketMQ基础之最!

应一些小伙伴们的私信&#xff0c;希望可以介绍一下RocketMQ的基础&#xff0c;那么我们现在就从0开始&#xff0c;进入RocketMQ的基础学习及概念介绍&#xff0c;为学习和使用RocketMQ打好基础&#xff01; RocketMQ是一款快速地、可靠地、分布式、容易使用的消息中间件&#…...

营销活动:提升小程序的用户活跃度的关键

在现今竞争激烈的商业环境中&#xff0c;小程序已成为企业私域营销的重要工具之一。然而&#xff0c;拥有一个小程序并不足以保证用户的活跃度。营销活动作为推动用户参与的有效方式&#xff0c;对于提升小程序的用户活跃度起着至关重要的作用。本文将深入探讨营销活动在提升小…...

Neo4j之CALL基础

CALL 语句用于调用 Neo4j 数据库中预定义的函数、过程或者自定义的函数。它是用来执行一些特定操作或计算的重要工具。以下是一些常用的 CALL 语句示例和解释&#xff1a; 调用内置函数&#xff1a; CALL db.labels()这个示例中&#xff0c;调用了内置函数 db.labels() 来获取…...

【TypeScript】元组

元组&#xff08;Tuple&#xff09;是 TypeScript 中的一种特殊数据类型&#xff0c;它允许你定义一个固定数量和类型的元素组合。元组可以包含不同类型的数据&#xff0c;每个数据的类型在元组中都是固定的。以下是 TypeScript 中元组的基本用法和特点&#xff1a; // 声明一…...

数据仓库一分钟

数据分层 一、数据运营层&#xff1a;ODS&#xff08;Operational Data Store&#xff09; “面向主题的”数据运营层&#xff0c;也叫ODS层&#xff0c;是最接近数据源中数据的一层&#xff0c;数据源中的数据&#xff0c;经过抽取、洗净、传输&#xff0c;也就说传说中的 ETL…...

提升Python代理程序性能的终极解决方案:缓存、连接池和并发

在开发Python代理程序时&#xff0c;优化性能是至关重要的。本文将为你介绍一套终极解决方案&#xff0c;通过缓存、连接池和并发处理等技术&#xff0c;极大地提升Python代理程序的效率和稳定性。 游戏国内地更换虚拟含ip地址数据库地区 1.缓存技术 缓存是 .0-*-696ES2 0一…...

CSS和AJAX阶段学习记录

1、AJAX的工作原理&#xff1a; 如图所示&#xff0c;工作原理可以分为以下几步&#xff1a; 网页中发生一个事件&#xff08;页面加载、按钮点击&#xff09; 由 JavaScript 创建 XMLHttpRequest 对象 XMLHttpRequest 对象向 web 服务器发送请求 服务器处理该请求 服务器将响应…...

Android自定义View知识体系

View的概念、作用和基本属性 View是Android中的基本UI组件&#xff0c;用于构建用户界面。它可以是按钮、文本框、图像等可见元素&#xff0c;也可以是容器&#xff0c;用于组织其他View。View的作用是展示数据和接收用户的输入。它可以显示文本、图片、动画等内容&#xff0c…...

Springboot 自定义 Mybatis拦截器,实现 动态查询条件SQL自动组装拼接(玩具)

前言 ps&#xff1a;最近在参与3100保卫战&#xff0c;战况很激烈&#xff0c;刚刚打完仗&#xff0c;来更新一下之前写了一半的博客。 该篇针对日常写查询的时候&#xff0c;那些动态条件sql 做个简单的封装&#xff0c;自动生成&#xff08;抛砖引玉&#xff0c;搞个小玩具&a…...

Go 1.21新增的 slices 包详解(三)

Go 1.21新增的 slices 包提供了很多和切片相关的函数&#xff0c;可以用于任何类型的切片。 slices.Max 定义如下&#xff1a; func Max[S ~[]E, E cmp.Ordered](x S) E 返回 x 中的最大值&#xff0c;如果 x 为空&#xff0c;则 panic。对于浮点数 E, 如果有元素为 NaN&am…...

Python 在logging.config.dictConfig()日志配置方式下,使用自定义的Handler处理程序

文章目录 一、基于 RotatingFileHandler 的自定义处理程序二、基于 TimedRotatingFileHandler 的自定义处理程序 Python logging模块的基本使用、进阶使用详解 Python logging.handlers模块&#xff0c;RotatingFileHandler、TimedRotatingFileHandler 处理器各参数详细介绍 …...

Anaconda, Python, Jupyter和PyCharm介绍

目录 1 Anaconda, Python, Jupyter和PyCharm介绍 2 macOS通过Anaconda安装Python, Jupyter和PyCharm 3 使用终端创建虚拟环境并安装PyTorch 4 安装PyCharm并导入Anaconda虚拟环境 5 Windows操作系统下Anaconda与PyCharm安装 6 通过 Anaconda Navigator 创建 TensorFlow 虚…...