前情回顾

前文我们完成了日志采集系统的日志文件监控,配置文件热更新,协程异常检测和保活机制。

本节目标

本节加入kafka消息队列,kafka前文也介绍过了,可以对消息进行排队,解耦合和流量控制的作用,为什么一定要用kafka呢?主要原因就是在日志高并发读取后,如果直接将消息发给前端或者写入数据库,会造成崩溃或者卡死。kafka可以对消息进行排队和减轻压力,这样无论以后将这些消息录入数据库也好,传给前端分析也好,都能保证系统稳定性。代码我们也写过和测试了,只需要将之前写好的kafka读写消息代码整合过来即可。

主函数创建kafka生产者

在主函数中创建kafkaProducer,然后在defer中回收该资源。我们将该producer传递给每个监控日志的协程中,当日志有修改,就通过producer将修改的信息写入kafka,用kafka排队和缓存,可以提高稳定性,减少流量高峰。

func main() {
//省略...
kafkaProducer := &kafkaqueue.ProducerKaf{Producer: producer}
configMgr = make(map[string]*logconfig.ConfigData)
keyChan := make(chan string, KEYCHANSIZE)
ConstructMgr(configPaths, keyChan, kafkaProducer) defer func() {
mainOnce.Do(func() {
//省略...
kafkaProducer.Producer.Close()
})
}() for {
select {
case pathData, ok := <-pathChan:
if !ok {
return
}
//省略...
for conkey, conval := range pathDataNew {
oldval, ok := configMgr[conkey]
if !ok {
//省略...
go logtailf.WatchLogFile(configData.ConfigKey, configData.ConfigValue,
ctx, keyChan, kafkaProducer)
continue
} if oldval.ConfigValue != conval.(string) {
//省略...
go logtailf.WatchLogFile(conkey, conval.(string),
ctx, keyChan, kafkaProducer)
continue
} } case keystr := <-keyChan:
val, ok := configMgr[keystr]
if !ok {
continue
}
//省略...
go logtailf.WatchLogFile(keystr, val.ConfigValue,
ctxcover, keyChan, kafkaProducer)
}
}
}

WatchLogFile函数携带了该producer。有人会问多个协程共享producer是否会出问题?我查看了Producer发送消息的源码

红框中使用了chan传递数据,所以在多个协程调用producer的发送函数是没问题的。

监控协程写入kafka消息

当日志新增时,我们在监控日志的协程向kafka写入消息

func WatchLogFile(pathkey string, datapath string, ctx context.Context, keychan chan<- string, kafProducer *kafkaqueue.ProducerKaf) {
//省略逻辑...
for true {
select {
case msg, ok := <-tailFile.Lines:
//省略逻辑...
kafProducer.PutIntoKafka(pathkey, msg.Text)
case <-ctx.Done():
fmt.Println("receive main gouroutine exit msg")
fmt.Println("watch log file ", pathkey, " goroutine exited")
return
} }
}

封装kafkaProducer

上述代码中调用的kafkaProducer是我自己封装的,其实就是组合了原生的kafka生产者,并且封装了发送函数

func CreateKafkaProducer() (sarama.SyncProducer, error) {
config := sarama.NewConfig() // 等待服务器所有副本都保存成功后的响应
config.Producer.RequiredAcks = sarama.WaitForAll
// 随机的分区类型:返回一个分区器,该分区器每次选择一个随机分区
config.Producer.Partitioner = sarama.NewRandomPartitioner
// 是否等待成功和失败后的响应
config.Producer.Return.Successes = true // 使用给定代理地址和配置创建一个同步生产者
producer, err := sarama.NewSyncProducer([]string{"localhost:9092"}, config)
if err != nil {
fmt.Println("create producer failed, ", err.Error())
return nil, err
}
fmt.Println("create kafka producer success") return producer, nil
}

  上面的函数返回了原生的kafka生产者接口,接下来我们封装这个原生接口,然后编写了写入kafka的方法

type ProducerKaf struct {
Producer sarama.SyncProducer
} func (p *ProducerKaf) PutIntoKafka(keystr string, valstr string) {
//构建发送的消息,
msg := &sarama.ProducerMessage{
Topic: "logcatchsys",
Key: sarama.StringEncoder(keystr),
Value: sarama.StringEncoder(valstr),
}
partition, offset, err := p.Producer.SendMessage(msg) if err != nil {
fmt.Println("Send message Fail")
fmt.Println(err.Error())
}
fmt.Printf("Partition = %d, offset=%d, msgvalue=%s \n", partition, offset, valstr) }

  

启动kafka测试

我们先启动zookeeper和kafka
zookeeper进入bin文件夹点击zkServer.cmd即可启动
kafka启动使用如下命令

.\bin\windows\kafka-server-start.bat .\config\server.properties

然后我们创建主题logcatchsys

.\bin\windows\kafka-topics.bat --create --zookeeper localhost:2181 --replication-factor 1 --partitions 16 --topic logcatchsys

这样我们为主题logcatchsys创建了16个分区。
接下来我们启动消费者

.\bin\windows\kafka-console-consumer.bat --bootstrap-server localhost:9092 --topic logcatchsys --from-beginning

然后我们启动我们的采集系统和测死脚本,看到如下

可以看到当日志文件不断被写入时,我们的采集系统会将修改的内容实时监控并写入kafka队列,然后kafka消费者从队列中取出这些消息。

总结

目前完成了日志采集系统所有功能的开发和测试,包括配置文件的热更新,监控协程的自动关闭和启动,异常修复和自启动,日志消息的监听,
kafka消息的读写等。但这并不是终点,只是一个起点,以后会配合前端开发不断完善,目前先告一段落。
源码下载
https://github.com/secondtonone1/golang-/tree/master/logcatchsys
感谢关注公众号

Go项目实战:打造高并发日志采集系统(六)的更多相关文章

  1. Go项目实战:打造高并发日志采集系统(一)

    项目结构 本系列文章意在记录如何搭建一个高可用的日志采集系统,实际项目中会有多个日志文件分布在服务器各个文件夹,这些日志记录了不同的功能.随着业务的增多,日志文件也再增多,企业中常常需要实现一个独立的 ...

  2. Go项目实战:打造高并发日志采集系统(二)

    日志统计系统的整体思路就是监控各个文件夹下的日志,实时获取日志写入内容并写入kafka队列,写入kafka队列可以在高并发时排队,而且达到了逻辑解耦合的目的.然后从kafka队列中读出数据,根据实际需 ...

  3. Go项目实战:打造高并发日志采集系统(三)

    前文中已经完成了文件的监控,kafka信息读写,今天主要完成配置文件的读写以及热更新.并且规划一下系统的整体结构,然后将之前的功能串起来形成一套完整的日志采集系统. 前情提要 上一节我们完成了如下目标 ...

  4. Go项目实战:打造高并发日志采集系统(四)

    前情回顾 前文我们完成了如下目标1 项目架构整体编写2 使框架支持热更新 本节目标 在前文的框架基础上,我们1 将之前实现的日志监控功能整合到框架中.2 一个日志对应一个监控协程,当配置热更新后根据新 ...

  5. Go项目实战:打造高并发日志采集系统(五)

    前情回顾 前文我们完成了如下功能1 根据配置文件启动多个协程监控日志,并启动协程监听配置文件.2 根据配置文件热更新,动态协调日志监控.3 编写测试代码,向文件中不断写入日志并备份日志,验证系统健壮性 ...

  6. 《实战java高并发程序设计》源码整理及读书笔记

    日常啰嗦 不要被标题吓到,虽然书籍是<实战java高并发程序设计>,但是这篇文章不会讲高并发.线程安全.锁啊这些比较恼人的知识点,甚至都不会谈相关的技术,只是写一写本人的一点读书感受,顺便 ...

  7. 《实战Java高并发程序设计》读书笔记

    文章目录 第二章 Java并行程序基础 2.1 线程的基本操作 2.1.1 线程中断 2.1.2 等待(wait)和通知(notify) 2.1.3 等待线程结束(join)和谦让(yield) 2. ...

  8. 【实战Java高并发程序设计 7】让线程之间互相帮助--SynchronousQueue的实现

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...

  9. 【实战Java高并发程序设计6】挑战无锁算法:无锁的Vector实现

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...

随机推荐

  1. TensorFlow中numpy与tensor数据相互转化

    numpy与tensor数据相互转化: *Numpy2Tensor 虽然TensorFlow网络在输入Numpy数据时会自动转换为Tensor来处理,但是我们自己也可以去显式的转换: data_ten ...

  2. 深度排序模型概述(二)PNN/NFM/AFM

    在CTR预估中,为了解决稀疏特征的问题,学者们提出了FM模型来建模特征之间的交互关系.但是FM模型只能表达特征之间两两组合之间的关系,无法建模两个特征之间深层次的关系或者说多个特征之间的交互关系,因此 ...

  3. inferiors

    inferiors 英[ɪnˈfɪərɪəz] 美[ɪnˈfɪriərz] n. 不如别人的人; 级别(或地位)低的人; [词典] inferior的复数; info inferiors

  4. Mysql数据库备份—-通过LVM快照实现备份还原

    一.实验环境 一台测试机:A(172.18.30.1) 操作系统:Centos7 操作对象数据库版本:mariadb-10.2 二.实现目的 从A机器(172.18.30.1)简单搭建数据库,创建测试 ...

  5. 操作mysql 中文乱码情况

    解决方法  : 在连接字符串中设置charset=utf8  即可正常添加中文字符 <add name="mtgzghEntities" connectionString=& ...

  6. Tomcat配置多站点

    tomcat配置多个站点.可以这样. 在conf文件夹下创建文件:..conf\Catalina\localhost\aa.xml aa.xml的内容.如: <?xml version=&quo ...

  7. C# 父类代码动态转换子类

    百度上搜索C# 如何父类运行时转换成子类,没有得到相应答案,突然想起C# 有dynamic类型试试看结果成功了... 以后编写代码类似这样的代码 就可以删减掉了 if (en.type == EMap ...

  8. centos 安装mariadb 替代mysql

    yum install mariadb-server mariadb systemctl start mariadbmysql -uroot -p默认密码mysql -uroot -pmysql_se ...

  9. OUC_Summer Training_ DIV2_#16 725

    今天做了这两道题真的好高兴啊!!我一直知道自己很渣,又贪玩不像别人那样用功,又没有别人有天赋.所以感觉在ACM也没有学到什么东西,没有多少进步.但是今天的B题告诉我,进步虽然不明显,但是只要坚持努力的 ...

  10. LeetCode 101. 对称二叉树(Symmetric Tree)

    题目描述 给定一个二叉树,检查它是否是镜像对称的. 例如,二叉树 [1,2,2,3,4,4,3] 是对称的. 1 / \ 2 2 / \ / \ 3 4 4 3 但是下面这个 [1,2,2,null, ...