Golang正确使用kafka的姿势-细节决定成败

【原创】开源OpenIM:轻量、高效、实时、可靠、低成本的消息模型 【原创】开源OpenIM:轻量、高效、实时、可靠、低成本的消息模型 1、内容概述 一套完整IM系统中,除开基本的业务设计,消息模型的设计是其中最为关键的一环,它关系到整个IM系统的可靠性、高效性、稳定性,因此需要设计一套合理的消息传递收发机制以承载IM的各种需求,OpenIM结合具体的业务场景,提炼出IM后端的重要接口,并经过反复推敲,验证,设计出了自己的一套通信协议OMTP,协议中每个字段尽量的减少冗余,使其精简高效、最大限度的满足现有的业务需求并能够支持业务的水平拓展,同时为了达到消息的实时可靠与高效, 阅读详情
本文转自 跟我学IM后台开发作者 杰克.许 经OpenIM技术人员整理修订后发布。
写在前面

Open-IM是由前微信技术专家打造的开源的即时通讯组件。Open-IM包括IM服务端和客户端SDK,实现了高性能、轻量级、易扩展等重要特性。开发者通过集成Open-IM组件,并私有化部署服务端,可以将即时通讯、实时网络能力快速集成到自身应用中,并确保业务数据的安全性和私密性。

Kafka在OpenIM项目中承担重要的角色,感谢作者在使用OpenIM中发现的bug(使用Kafka不当的bug)

了解更多原创文章:

【OpenIM原创】开源OpenIM:轻量、高效、实时、可靠、低成本的消息模型

【OpenIM原创】C/C++调用golang函数,golang回调C/C++函数

【OpenIM原创】简单轻松入门 一文讲解WebRTC实现1对1音视频通信原理

【OpenIM扩展】OpenIM服务发现和负载均衡golang插件:gRPC接入etcdv3

【开源OpenIM】高性能、可伸缩、易扩展的即时通讯架构

如果您有兴趣可以在文章结尾了解到更多关于我们的信息,期待着与您的交流合作。

01 背景

在一些业务系统中,模块之间通过引入Kafka解耦,拿IM举例(图来源):

img

用户A给B发送消息,msg_gateway收到消息后,投递消息到Kafka后就给A返回发送成功。这个时候,其实还没有持久化到mysql中,虽然最终会保持一致性。所以,试想如果Kafka丢消息了,是不是就出大问题了?A认为给B发送消息成功了,但是在服务器内部消息丢失了B并没有收到。

所以,在使用Kafka的时候,有一些业务对消息丢失问题非常的关注。

同样,常见的问题还有:

  • 重复消费的问题。
  • 乱序的问题。

下面我们来一起看一下如何使用sarama包来解决这些问题。

02 Kafka消息丢失问题描述

以下内容来源:

kafka什么时候会丢消息:https://blog.youkuaiyun.com/qrne06/article/details/94225070

上面我们担心的点需要进一步明确一下丢消息的定义:kafka集群中的部分或全部broker挂了,导致consumer没有及时收到消息,这不属于丢消息。broker挂了,只要消息全部持久化到了硬盘上,重启broker集群之后,使消费者继续拉取消息,消息就没有丢失,仍然全量消费了。所以我的理解,所谓丢消息,意味着:开发人员未感知到哪些消息没有被消费。

作者把消息的丢失归纳了以下几种情况:

1) producer把消息发送给broker,因为网络抖动,消息没有到达broker,且开发人员无感知。

解决方案:producer设置acks参数,消息同步到master之后返回ack信号,否则抛异常使应用程序感知到并在业务中进行重试发送。这种方式一定程度保证了消息的可靠性,producer等待broker确认信号的时延也不高。

2)producer把消息发送给broker-master,master接收到消息,在未将消息同步给follower之前,挂掉了,且开发人员无感知。

解决方案:producer设置acks参数,消息同步到master且同步到所有follower之后返回ack信号,否则抛异常使应用程序感知到并在业务中进行重试发送。这样设置,在更大程度上保证了消息的可靠性,缺点是producer等待broker确认信号的时延比较高。

3)producer把消息发送给broker-master,master接收到消息,master未成功将消息同步给每个follower,有消息丢失风险。

解决方案:同上。

4)某个broker消息尚未从内存缓冲区持久化到磁盘,就挂掉了,这种情况无法通过ack机制感知。

解决方案:设置参数,加快消息持久化的频率,能在一定程度上减少这种情况发生的概率。但提高频率自然也会影响性能。

5)consumer成功拉取到了消息,consumer挂了。

解决方案:设置手动sync,消费成功才提交。

综上所述,集群/项目运转正常的情况下,kafka不会丢消息。一旦集群出现问题,消息的可靠性无法完全保证。要想尽可能保证消息可靠,基本只能在发现消息有可能没有被消费时,重发消息来解决。所以在业务逻辑中,要考虑消息的重复消费问题,对于关键环节,要有幂等机制。

作者的几条建议:

1)如果一个业务很关键,使用kafka的时候要考虑丢消息的成本和解决方案。

2)producer端确认消息是否到达集群,若有异常,进行重发。

3)consumer端保障消费幂等性。

4)运维保障集群运转正常且高可用,保障网络状况良好。

03 生产端丢消息问题解决

上面说了,只需要把producer设置acks参数,等待Kafka所有follower都成功后再返回。我们只需要进行如下设置:

  • \1. config := sarama.NewConfig() 2. config.Producer.RequiredAcks = sarama.WaitForAll // -1

ack参数有如下取值:

1. const (
2. // NoResponse doesn't send any response, the TCP ACK is all you get. 3.   NoResponse RequiredAcks = 0
4. // WaitForLocal waits for only the local commit to succeed before         responding.    
5. WaitForLocal RequiredAcks = 1   
6. // WaitForAll waits for all in-sync replicas to commit before          responding.    
7. // The minimum number of in-sync replicas is configured on the             broker    via   
8. // the `min.insync.replicas` configuration key.    
9. WaitForAll RequiredAcks = -1
10.  )

04 消费端丢消息问题

通常消费端丢消息都是因为Offset自动提交了,但是数据并没有插入到mysql(比如出现BUG或者进程Crash),导致下一次消费者重启后,消息漏掉了,自然数据库中也查不到。这个时候,我们可以通过手动提交解决,甚至在一些复杂场景下,还要使用二阶段提交。

自动提交模式下的丢消息问题

默认情况下,sarama是自动提交的方式,间隔为1秒钟

1.  // NewConfig returns a new configuration instance with sane                defaults.
2. func NewConfig() *Config {  
3. // …  
4. c.Consumer.Offsets.AutoCommit.Enable = true. // 自动提交 
5. c.Consumer.Offsets.AutoCommit.Interval = 1 * time.Second // 间隔 
6. c.Consumer.Offsets.Initial = OffsetNewest 
7. c.Consumer.Offsets.Retry.Max = 3 
8.  // ...
9.  }

这里的自动提交,是基于被标记过的消息(sess.MarkMessage(msg, “"))

1. type exampleConsumerGroupHandler struct{}
2. func (exampleConsumerGroupHandler) Setup(_ ConsumerGroupSession)        error   { return nil }
3. func (exampleConsumerGroupHandler) Cleanup(_ ConsumerGroupSession)      error { return nil }
4. func (h exampleConsumerGroupHandler) ConsumeClaim(sess                  ConsumerGroupSession, claim ConsumerGroupClaim) error {  
5. for msg := range claim.Messages() {      
6. fmt.Printf("Message topic:%q partition:%d offset:%d\n", msg.Topic,      msg.Partition, msg.Offset)      
7. // 标记消息已处理,sarama会自动提交     
8. sess.MarkMessage(msg, "") 
9. }   
10. return nil
11. }

如果不调用sess.MarkMessage(msg, “"),即使启用了自动提交也没有效果,下次启动消费者会从上一次的Offset重新消费,我们不妨注释掉sess.MarkMessage(msg, “"),然后打开Offset Explorer查看:

img

那么这样,我们就大概理解了sarama自动提交的原理:先标记再提交。我们只需要保持标记逻辑在插入mysql代码之后即可确保不会出现丢消息的问题:

正确的调用顺序:

1. func (h msgConsumerGroup) ConsumeClaim(sesssarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error {   
2. for msg := range claim.Messages() {
3. // 插入mysql
4. insertToMysql(msg)      
5. // 正确:插入mysql成功后程序崩溃,下一次顶多重复消费一次,而不是因为Offset超         前,导致应用层消息丢失了     
6.  sess.MarkMessage(msg, “") 
7.  }  
8.  return nil
9.  }

错误的顺序:

1. func (h msgConsumerGroup) ConsumeClaim(sess                           sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error { 2. for msg := range claim.Messages() {     
3. // 错误1:不能先标记,再插入mysql,可能标记的时候刚好自动提交Offset,但mysql插入失败了,导致下一次这个消息不会被消费,造成丢失      
4. // 错误2:干脆忘记调用sess.MarkMessage(msg, “"),导致重复消费   
5. sess.MarkMessage(msg, “")      
6. // 插入mysql      
7. insertToMysql(msg)  
8.  }  
9.  return nil
10. }

sarama手动提交模式

当然,另外也可以通过手动提交来处理丢消息的问题,但是个人不推荐,因为自动提交模式下已经能解决丢消息问题。

1. consumerConfig := sarama.NewConfig()
2. consumerConfig.Version = sarama.V2_8_0_0consumerConfig.
3. Consumer.Return.Errors = falseconsumerConfig.
4. Consumer.Offsets.AutoCommit.Enable = false  // 禁用自动提交,改为手动
5. consumerConfig.Consumer.Offsets.Initial = sarama.OffsetNewest
6. func (h msgConsumerGroup) ConsumeClaim(sess sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error {   7. for msg := range claim.Messages() {      
8. fmt.Printf("%s Message topic:%q partition:%d offset:%d  value:%s\n", h.name, msg.Topic, msg.Partition, msg.Offset, string(msg.Value))      9. // 插入mysql     
10. insertToMysql(msg)      
11. // 手动提交模式下,也需要先进行标记     
12. sess.MarkMessage(msg, "")      
13. consumerCount++      
14. if consumerCount%3 == 0 {         
15. // 手动提交,不能频繁调用,耗时9ms左右,macOS i7 16GB         
16. t1 := time.Now().Nanosecond()         
17. sess.Commit()         
18. t2 := time.Now().Nanosecond()         
19.fmt.Println("commit cost:", (t2-t1)/(1000*1000), "ms")      
20. }   
21. }   
22. return nil
23. }

05 Kafka消息顺序问题

投递Kafka之前,我们通过一次gRPC调用解决了消息序号的生成问题,但是这里其实还涉及一个消息顺序问题:订阅Kafka的消费者如何按照消息顺序写入mysql,而不是随机写入呢?

我们知道,Kafka的消息在一个partition中是有序的,所以只要确保发给某个人的消息都在同一个partition中即可。

1. 全局一个partition

这个最简单,但是在kafka中一个partition对应一个线程,所以这种模型下Kafka的吞吐是个问题。

2. 多个partition,手动指定

1. msg := &sarama.ProducerMessage{   
2. Topic: “msgc2s",   
3. Value: sarama.StringEncoder(“hello”),   
4. Partition: toUserId % 10,
5. }
6. partition, offset, err := producer.SendMessage(msg)

生产消息的时候,除了Topic和Value,我们可以通过手动指定partition,比如总共有10个分区,我们根据用户ID取余,这样发给同一个用户的消息,每次都到1个partition里面去了,消费者写入mysql中的时候,自然也是有序的。

img

但是,因为分区总数是写死的,万一Kafka的分区数要调整呢?那不得重新编译代码?所以这个方式不够优美。

3. 多个partition,自动计算

kafka客户端为我们提供了这种支持。首先,在初始化的时候,设置选择分区的策略为Hash:

p.config.Producer.Partitioner = sarama.NewHashPartitioner

然后,在生成消息之前,设置消息的Key值:

1. msg := &sarama.ProducerMessage{   
2. Topic: "testAutoSyncOffset",   
3. Value: sarama.StringEncoder("hello"),   
4. Key: sarama.StringEncoder(strconv.Itoa(RecvID)),
5. }

Kafka客户端会根据Key进行Hash,我们通过把接收用户ID作为Key,这样就能让所有发给某个人的消息落到同一个分区了,也就有序了。

4.扩展知识:多线程情况下一个partition的乱序处理

我们上面说了,Kafka客户端针对一个partition开一个线程进行消费,如果处理比较耗时的话,比如处理一条消息耗时几十 ms,那么 1 秒钟就只能处理几十条消息,这吞吐量太低了。这个时候,我们可能就把逻辑移动到其他线程里面去处理,这样的话,顺序就可能会乱。

img

我们可以通过写 N 个内存 queue,具有相同 key 的数据都到同一个内存 queue;然后对于 N 个线程,每个线程分别消费一个内存 queue 即可,这样就能保证顺序性。PS:就像4 % 10 = 4,14 % 10 = 4,他们取余都是等于4,所以落到了一个partition,但是key值不一样啊,我们可以自己再取余,放到不同的queue里面。

img

06 重复消费和消息幂等

这篇文章中:

kafka什么时候会丢消息:https://blog.youkuaiyun.com/qrne06/article/details/94225070

详细了描述了各种丢消息的情况,我们通过设置 RequiredAcks = sarama.WaitForAll(-1),可以解决生产端丢消息的问题。第六节中也对消费端丢消息进行了说明,只需要确保在插入数据库之后,调用 sess.MarkMessage(msg, "”) 即可。

如果出现了插入Mysql成功,但是因为自动提交有1秒的间隔,如果此时崩溃,下次启动消费者势必会对这1秒的数据进行重复消费,我们在应用层需要处理这个问题。

常见的有2种思路:

  1. 如果是存在redis中不需要持久化的数据,比如string类型,set具有天然的幂等性,无需处理。
  2. 插入mysql之前,进行一次query操作,针对每个客户端发的消息,我们为它生成一个唯一的ID(比如GUID),或者直接把消息的ID设置为唯一索引。

第2个方案的难点在于,全局唯一ID的生成,理论上GUID也是存在重复的可能性的,如果是客户端生成,那么插入失败,怎么让客户端感知呢?

所以,这里我认为还是需要自定义ID生产,比如通过组合法:用户ID + 当前时间 + 32位GUID,是不是几乎不会重复了呢(试想,1个人发1亿条文本需要多少年。。。)?

07 完整代码实例

consumer.go

1. type msgConsumerGroup struct{}
2. 
3. func (msgConsumerGroup) Setup(_ sarama.ConsumerGroupSession) error   { return nil }
4. func (msgConsumerGroup) Cleanup(_ sarama.ConsumerGroupSession) error { return nil }
5. func (h msgConsumerGroup) ConsumeClaim(sess sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error {   6. for msg := range claim.Messages() {      
7. fmt.Printf("%s Message topic:%q partition:%d offset:%d  value:%s\n", h.name, msg.Topic, msg.Partition, msg.Offset, string(msg.Value))
8. 
9. // 查mysql去重      
10. if check(msg) {          
11. // 插入mysql          
12. insertToMysql()      
13. }
14.
15. // 标记,sarama会自动进行提交,默认间隔1秒      
16. sess.MarkMessage(msg, "")  
17. }   
18. return nil
19. }
20.
21. func main(){    
22. consumerConfig := sarama.NewConfig()    
23. consumerConfig.Version = sarama.V2_8_0_0 // specify appropriate version    
24. consumerConfig.Consumer.Return.Errors = false    
25. //consumerConfig.Consumer.Offsets.AutoCommit.Enable = true      
26. // 禁用自动提交,改为手动  //
27. consumerConfig.Consumer.Offsets.AutoCommit.Interval = time.Second * 1 // 测试3秒自动提交    consumerConfig.Consumer.Offsets.Initial = sarama.OffsetNewest
28.
29. cGroup, err := sarama.NewConsumerGroup([]string{"10.0.56.153:9092",    "10.0.56.153:9093", "10.0.56.153:9094"},"testgroup", consumerConfig)  30. if err != nil {       
31. panic(err)   
32. }
33. 
34. for {      
35. err := cGroup.Consume(context.Background(), []string{"testAutoSyncOffset"}, consumerGroup)       
36. if err != nil {         
37. fmt.Println(err.Error())         
38. break     
39. }   
40. }
41. 
42.  _ = cGroup.Close()
43. }

producer.go

1. func main(){    
2. config := sarama.NewConfig()    
3. config.Producer.RequiredAcks = sarama.WaitForAll // 等待所有follower都回复ack,确保Kafka不会丢消息    
4. config.Producer.Return.Successes = true    
5. config.Producer.Partitioner = sarama.NewHashPartitioner
6.
7.  // 对Key进行Hash,同样的Key每次都落到一个分区,这样消息是有序的
    // 使用同步producer,异步模式下有更高的性能,但是处理更复杂,这里建议先从简单的入手    
8. producer, err := sarama.NewSyncProducer([]string{"10.0.56.153:9092"}, config)    
9. defer func() {       
10. _ = producer.Close()    
11. }()    
12. if err != nil {       
13. panic(err.Error())   
14. }
15.
16. msgCount := 4   
17. // 模拟4个消息    
18. for i := 0; i < msgCount; i++ {        
19. rand.Seed(int64(time.Now().Nanosecond()))        
20. msg := &sarama.ProducerMessage{          
21. Topic: "testAutoSyncOffset",          
22. Value: sarama.StringEncoder("hello+" + strconv.Itoa(rand.Int())),   
23. Key:   sarama.StringEncoder("BBB”),        
24. }
25.
26.  t1 := time.Now().Nanosecond()        
27. partition, offset, err := producer.SendMessage(msg)        
28. t2 := time.Now().Nanosecond()
29.
30. if err == nil {            
31. fmt.Println("produce success, partition:", partition, ",offset:", offset, ",cost:", (t2-t1)/(1000*1000), " ms")        
32. } else {           
33. fmt.Println(err.Error())      
34.      }   
35.   }
36.}

结束

OpenIM github开源地址:

https://github.com/OpenIMSDK/Open-IM-Server

**OpenIM官网 :**https://www.rentsoft.cn

**OpenIM官方论坛:**https://forum.rentsoft.cn/

我们致力于通过开源模式,为全球企业/开发者提供简单、易用、高效的IM服务和实时音视频通讯能力,帮助开发者降低项目的开发成本,并让开发者掌控业务的核心数据。

IM作为核心业务数据,安全的重要性毋庸置疑,OpenIM开源以及私有化部署让企业能更放心使用。

如今IM云服务商收费高企,如何让企业低成本、安全、可靠接入IM服务,是OpenIM的历史使命,也是我们前进的方向。

如您有技术上面的高见请到我们的论坛联系沟通,用户也可与我们的技术人员谈讨使用方面的难题以及见解

Golang 操作Kafka Golang操作kafka 阅读详情

相关推荐

Golang的Kafka 框架支持consumer group

golang的kafka 框架有很多种, sarama是一种比较常用的,是用golang写的,但是不能支持consumer group。 confluent是一种,是调用c语言的库librdkafka,可以支持consumer group。但是会麻烦一点,需要安装librdkafka。 安装librdkafka 先看官网上的一句话。 This client for Go depends on li...

与数据和AI有关的东西 3795

2024年Golang面试进阶指南:深入GMP、GC与分布式系统设计

并发编程是构建高性能、高可用系统的核心技术,其核心在于理解并发原语、调度机制与内存管理。以Go语言为例,其GMP调度模型通过Goroutine、Machine和Processor的协作,结合工作窃取机制,实现了高效的并发执行。垃圾回收(GC)则采用三色标记法,通过写屏障等技术减少STW时间,保障程序性能。这些底层原理为开发分布式系统、微服务架构提供了坚实基础,尤其在云原生场景下,结合gRPC、服务发现、分布式锁等组件,能够构建出高并发、可扩展的后端服务。本文聚焦Golang面试热点,深入解析GMP模型、GC

weixin_30729609的博客 329

实时机器学习数据管道设计:从Kafka到特征存储的工程实践

数据管道是机器学习落地的核心基础设施,其本质是保障原始数据稳定、低延迟、可验证地流向模型输入端。它涉及流式摄取、状态化处理、特征计算与服务化等关键环节,技术原理围绕事件时间处理、状态一致性、Schema演化与端到端延迟控制展开。在金融、工业、农业等实时决策场景中,管道质量直接决定模型实效性与业务SLA。本文聚焦股票预测这一典型高吞吐、低延迟、强有序场景,深入解析Kafka分区规划、Flink状态后端选型、Delta Lake事务治理及自研特征存储等硬核实践,融合实时数据管道、特征工程流水线两大热词,提供可复

weixin_33895516的博客 378

Golang操作kafka

kafka cluster: kafka集群,一台或多台服务器组成 Broker: Broker是指部署了Kafka实例的服务器节点。每个服务器上有一个或多个kafka的实 例,我们姑且认为每个broker对应一台服务器。每个kafka集群内的broker都有一个不重复的编号,如图中的broker-0、broker-1等...... Topic:消息的主题,可以理解为消息的分类,kafka的数据就保存在topic。在每个broker上都可以创建多个topic。实际应用中通...

qq_36410466的博客 5166

Go语言API签名验证实战:HMAC-SHA256防篡改与防重放攻击

API签名验证是保障接口安全的核心技术,通过密码学原理确保请求的完整性和身份真实性。其核心机制是利用密钥对请求参数生成唯一的消息认证码(MAC),服务端通过相同算法验签来抵御数据篡改和身份伪造。HMAC-SHA256作为当前行业标准算法,结合时间戳和随机数机制,能有效防范重放攻击。在微服务架构和API网关场景中,签名验证已成为分布式系统安全通信的基石。本文以Go语言为例,深入解析签名验证的工程实现,涵盖参数排序、防重放设计等关键细节,并针对高并发场景提供性能优化方案,帮助开发者构建工业级安全的API防护体系

weixin_33910385的博客 387

库存与预警模块:Go语言构建高并发库存系统的工程实践

本文介绍了一个基于Go语言实现的电商库存管理系统,重点解决了库存管理中的核心挑战:数据一致性、高并发扣减、实时同步等问题。系统采用Canal监听MySQL binlog实现实时同步,Redis Lua脚本保证原子扣减,Kafka实现多分库异步同步。关键模块包括库存预占与超时释放机制、EasyExcel报表导出和自动预警补货功能。架构上分为业务应用层、库存服务API层和辅助模块,技术选型包括Gin、GORM、Redis、Canal等组件。系统支持秒级库存变更感知、百万级数据报表导出和智能预警,具备高并发处理能

分享AI、区块链技术及应用,未来已来 41

openMPM源码分析(六)

前言: 主要是围绕transport库,但从API角度很好理解,但深入到库的实现,代码就比较晦涩了。   test/filetestdemo/host/src/demo_filetest.c 直接进入main函数。 首先是命令行参数,一共6个,而前半部分就是围绕这些参数的初始化展开的。 1.打开输入文件:inFile=fopen(argv[1],"rb"); 以二进制方式只读。 2.

上善若水 997

一种高超声速飞行器弹道的仿真方法

设计并实现了一个高超声速飞行器弹道仿真算法,并应用到基于OSGEarth的态势中。

eyepeak的博客 6541

强大的 Go 语言实现的 Apache Kafka 客户端 —— confluent-kafka-go

在分布式系统和流处理领域,Apache Kafka 已经成为不可或缺的一员。针对这一强大的消息中间件,Confluent 提供了一个专门为 Go 语言设计的客户端库——`confluent-kafka-go`。这个库不仅传承了 Apache Kafka 的精髓,还通过与 Confluent Platform 的深度整合,为企业级应用提供了高性能、可靠且未来可扩展的解决方案。 ## 项目介绍 `...

gitblog_00160的博客 1292

保姆级教程:彻底清理Win11更新缓存并解除外设,一次搞定0xc1900101更新错误

本文提供了一套完整的Win11更新报错0xc1900101解决方案,涵盖软件环境净化和硬件设备隔离。通过终止干扰进程、重置更新组件、清理临时文件以及断开外设等步骤,有效提升更新成功率。特别强调外设驱动兼容性对解决0xc1900101错误的关键作用。

weixin_33483304的博客 417

利用HTML+CSS设计PPT:html-to-pptx实现自动化转换与可编辑输出

在办公自动化和前端开发领域,将网页技术应用于文档生成是一个重要的技术方向。其核心原理在于通过解析HTML/CSS的结构与样式,将其映射为目标文档的原生对象模型。这项技术的价值在于,它能够将Web技术栈强大的布局与样式能力(如Flexbox、CSS Grid)与办公软件(如Microsoft PowerPoint)的广泛兼容性和可编辑性相结合。在实际应用场景中,这种技术特别适合需要快速生成兼具设计感与实用性的演示文稿,例如数据报告、产品发布和营销材料。本文探讨的html-to-pptx项目正是这一思路的工程实

weixin_30652491的博客 486

Kafka Agent 设计 - 可靠事件记录不是一件简单的事情

用 golang 编写,解决事件快速同时可靠入Kafka的问题。绿色表示goroutine(可能是不同的线程),蓝色表示共享的资源。所有对蓝色资源的访问需要加锁。磁盘队列使用内存映射文件实现ring buffer。kafka agent启动的时候有一个bootstrap的broker列表,同时发送的时候会与每个相关的broker维护一个...

weixin_34283445的博客 379

搞定安卓11+抓包难题:用Kitsune Mask、magic_overlayfs和LSPosed三件套绕过SSL Pinning(保姆级教程)

本文详细解析了安卓11+系统中抓包面临的核心挑战,包括SSL Pinning和Root检测机制,并提供了使用Kitsune Mask、magic_overlayfs和LSPosed三件套的完整解决方案。通过动态分区技术解析和工具链配置,帮助开发者绕过安全限制,实现高效抓包分析。

weixin_42665255的博客 442

揭秘高频交易中的并发瓶颈:5个关键指标决定系统成败

破解高频交易的并发瓶颈,提升系统性能的关键在于5个核心指标。本文深入解析高并发场景下的延迟、吞吐量、订单执行速度等关键因素,揭示优化高频交易系统的实用方法。掌握这些指标,显著增强交易响应能力与稳定性,值得收藏。

GatherLume的博客 927

别再手动配电脑了!手把手教你用Windows Server 2022搭建企业AD域(附DNS配置避坑指南)

本文详细介绍了如何使用Windows Server 2022搭建企业AD域,提升20+终端的管理效率。通过实战案例和避坑指南,解析AD域的核心价值、部署步骤及DNS配置技巧,帮助企业实现集中权限管理、安全策略统一部署,显著降低IT运维成本。

weixin_30652897的博客 348

【HarmonyOS】ArkUI的组件扩展

ArkuI的组件扩展主要是通过等装饰器来对于一些常用的自定义组件进行封装, 来简化UI开发流程, 提高自定义组件的可复用性。

2302_79763237的博客 1166

Go重构机器学习Pipeline:数据加载、特征计算与在线服务性能优化实战

机器学习工程中,Python生态虽丰富,但在高吞吐数据加载、低延迟特征计算和高并发在线推理等场景常面临GIL限制、GC抖动与IO阻塞等系统级瓶颈。Go语言凭借零拷贝内存映射(mmap)、无GC压力的预分配计算、轻量goroutine并发模型及gRPC高效通信,天然适配这些‘体力密集型’环节。其技术价值不在于替代模型训练,而在于构建确定性、可预测、易运维的ML基础设施层。典型应用场景包括实时推荐系统的特征实时计算、大规模离线数据预处理加速、以及Python模型服务之上的高性能推理网关。本文即基于真实生产环境,

weixin_33443972的博客 310

GPS天线结构、原理、测试

【有源陶瓷天线构成】GPS天线是由接收天线和前置放大器两个部件组成。GPS接收天线的作用,是将卫星来的无线电信号的电磁波能量变换成接收机电子器件可摄取应用的电流。绝大部分内置GPS天线为右旋极化陶瓷介质,其组成部分为:陶瓷天线、低噪音信号模块、线缆、[接头](h

数字世界 万物互联 2万+

别再死记硬背了!一张图帮你理清Redis、Kafka、Nginx这些中间件到底该怎么选

本文提供了一套实用的中间件选型方法论,帮助开发者在Redis、Kafka、Nginx等主流中间件中做出精准选择。通过业务场景匹配度、技术栈亲和性、团队能力储备等多维评估,避免常见选型误区,提升分布式系统架构设计的效率与可靠性。

weixin_30219613的博客 278

巡检机器人的基于ROS系统的任务管理架构设计总结

本文探讨了基于ROS(机器人操作系统)的工业巡检机器人任务管理架构设计,提出分层闭环方案。架构围绕稳、准、活、扩四大目标,分为感知层(多源数据融合)、调度层(智能决策)、执行层(动作控制)和数据层(存储交互)。关键技术包括ROS2实时性优化、功能包复用和多机器人协同调度。实践案例显示,该架构在电力巡检中使任务完成率达99%,在化工园区实现95%覆盖率。当前挑战包括SLAM地图漂移和多机通信延迟,未来可通过语义SLAM和区域通信优化。

start_up_go的博客 464

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Go语言云原生安全实战:JWT认证、RBAC授权与数据加密全链路防护

在云原生与微服务架构中,安全是系统设计的核心基因。认证与授权作为访问控制的基础,通过JWT(JSON Web Token)实现无状态认证,并结合RBAC(基于角色的访问控制)模型进行精细化权限管理,确保资源访问的合法性与安全性。数据安全则涉及传输与存储两个层面,TLS/SSL保障传输过程加密,而应用层采用AES等对称加密算法对敏感字段进行加密存储,结合bcrypt等抗碰撞哈希函数处理密码,构建双重防护。这些技术共同为高并发、分布式的云原生应用提供了从入口到落盘的全链路安全加固方案,有效抵御越权访问、数据泄露

weixin_30617737的博客 441

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

某互联网二次面试:深入回答技术问题

Go 的 GC 和栈管理通过优化性能和内存使用,为开发者提供了高效的并发处理机制。Redis 和 Kafka 作为现代分布式系统的核心组件,通过分片、负载均衡和持久化机制确保了高可用性和数据一致性。而在数据库设计方面,合理的索引和范式选择,能够有效地提升系统的查询效率与数据一致性。在面对技术挑战时,良好的架构设计与不断学习是解决问题的关键。

qq_33665793的博客 995

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

从被拒到拿offer:一个架构师的简历重构成败复盘(2025实战版)

掌握程序员简历优化技巧2025,告别石沉大海。本文以架构师真实重构经历,拆解高薪岗位适配策略、技术亮点提炼与成果量化方法,提升面试转化率。从被拒到拿offer的实战经验,值得收藏。

PoliVein的博客 853

Open-AutoGLM支持导出代码文件?1个被忽视的核心配置决定成败

解决Open-AutoGLM代码导出难题,一文掌握关键配置方法。针对“Open-AutoGLM支持代码框导出文件吗”这一常见疑问,揭示影响导出功能的核心设置,适用于本地部署与多环境调试,正确配置后可直接导出.py或.json格式文件,提升开发效率,值得收藏。

ProcePerch的博客 648

AI智能体开发语言选择指南:Python、TypeScript、Go与Java深度对比

在构建AI智能体时,编程语言的选择是决定项目成败的关键技术决策之一。从技术原理上看,智能体开发融合了LLM集成、工具调用、状态管理和外部系统交互等多种范式,这要求所选语言不仅具备良好的语法特性,更需要强大的生态系统支持。其技术价值在于平衡开发效率、运行时性能与长期可维护性,直接影响智能体的迭代速度和上线后的稳定性。常见的应用场景包括自动化客服、数据分析助手和业务流程自动化等。本文聚焦于Python、TypeScript、Go和Java等主流语言,通过对比生态成熟度、开发效率、性能表现和团队适配度等维度,并结

weixin_30443731的博客 807

从零开始打造高并发后端应用:技术栈选型全攻略

在当今互联网时代,高并发场景无处不在,从电商大促到社交平台的信息流推送,再到在线教育的直播互动,都对后端应用的性能提出了严峻挑战。同时,结合服务发现机制(如Consul、Eureka),可以实现服务的自动注册与发现,提升系统的可扩展性和容错能力。合理的技术栈选型,不仅能提升系统的性能和稳定性,还能降低开发和运维成本,为业务的快速发展奠定坚实基础。3. 分布式数据库(如TiDB、CockroachDB):结合了关系型和NoSQL的优势,支持水平扩展和强一致性,适合大规模高并发场景。四、消息队列与异步处理。

2501_90410679的博客 15
上一篇: 通俗易懂 即时通讯初学者入门 WhatsApp技术架构
下一篇: 【OpenIM原创】AppServer、AppClient、Open-IM-Server以及Open-IM-SDK之间的关系
OpenIM
博客等级 码龄5年 295粉丝 68原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值