Chanjet:基于Go Channel、Buffer Pool和零拷贝实现的高性能双缓冲通道

Chanjet:基于Go Channel、Buffer Pool和零拷贝实现的高性能双缓冲通道

Chanjet 基于Go Channel、Buffer Pool和零拷贝实现的高性能双缓冲通道 Chanjet 项目地址: https://gitcode.com/gh_mirrors/ch/Chanjet

项目介绍

Chanjet 是一个基于 Go 语言实现的高性能双缓冲通道,它利用了 Go Channel 的强大功能和 Buffer Pool 的优势,以及零拷贝技术,实现了数据的高效处理和传输。Chanjet 通过设计精巧的数据结构和算法,提高了通道的读写性能,同时减少了内存分配和销毁的开销,从而在保证数据安全的前提下,提升了系统的整体性能。

项目技术分析

Chanjet 的核心功能是基于 Go Channel、Buffer Pool 和零拷贝技术实现的高性能双缓冲通道。Go Channel 是 Go 语言中用于并发编程的一种数据结构,它可以安全地在不同的协程之间传输数据。Buffer Pool 则是一种内存池技术,用于缓存和复用内存块,从而减少内存分配和销毁的开销。零拷贝技术则是指在数据传输过程中,尽量减少数据在内核空间和用户空间之间的复制,从而提高数据传输效率。

Chanjet 的设计理念是将数据写入和读取分离,采用双写缓冲区设计,active 通道用于实时接收数据,passive 通道用于异步处理数据。当 active 满足切换逻辑执行通道轮转后,passive 转换为 active 实时写入通道接收数据,active 转换成 passive 异步处理通道。这样,即使接收方消费受限,也不会明显的阻塞 passive 通道的使用。同时,Chanjet 还设计了统一的读取队列,将 passive 通道中的所有数据写入到统一的 readq 通道中,接收方只需从 readq 中获取数据即可。

项目及技术应用场景

Chanjet 的应用场景非常广泛,包括但不限于:

  1. 日志系统:Chanjet 可以作为日志收集和传输的中间件,将日志数据高效地写入到存储系统或分析系统中。

  2. 数据处理系统:Chanjet 可以作为数据处理的中间件,将数据从源端传输到处理端,并保证数据的安全和可靠性。

  3. 数据同步系统:Chanjet 可以作为数据同步的中间件,将数据从一个系统同步到另一个系统,并保证数据的完整性和一致性。

  4. 高并发系统:Chanjet 可以作为高并发系统的中间件,将数据在不同的协程之间高效地传输,从而提高系统的并发性能。

项目特点

Chanjet 的特点如下:

  1. 双写缓冲区设计:active 通道用于实时接收数据,passive 通道用于异步处理数据,当 active 满足切换逻辑执行通道轮转后,passive 转换为 active 实时写入通道接收数据,active 转换成 passive 异步处理通道。

  2. 统一读取队列设计:passive 异步缓冲通道需要快速异步的将所有数据写入到统一的 readq 通道中,接收方(比如文件写入)只从 readq 中获取即可,这样即使接收方消费受限也不会明显的阻塞 passive 通道的使用。

  3. 复合通道轮转策略:当 active 通道中数据大小触发一定的阈值,比如最大容量的 80%,立即进行轮转。当达到一定时间,比如 5 秒还没有进行通道轮转时,后台定时程序立即触发通道轮转,防止因长期没有新数据写入导致接收方无法获取通道内数据的问题,也尽可能减少数据丢失的风险。

  4. 无锁化设计:双缓冲通道不使用加锁保护通道切换,使用原子状态实现并发安全的通道切换,大大提升了性能。

  5. 缓冲池设计:使用缓冲池设计,通道切换时复用池中可用通道,防止出现频繁的通道创建和销毁的开销。

  6. 完善监控的设计:完善的监控指标设计,支持 Prometheus 和 OpenTelemetry,目前已支持 Prometheus 指标,抽象批量上报接口,上报指标数据定时批量刷新到底层指标收集器,3700000 条数据写入单条指标上报总耗时 1.5 秒,批量刷新指标总耗时 <1.1 秒,耗时减少 400 毫秒左右,大大提升了性能。

性能测试结果

Chanjet 在性能测试中表现出色,无论是在写入还是读取操作上,都展现出了高效的数据处理能力。以下是一些性能测试结果:

  • 128B 测试结果:操作次数达到 9,593,606 次,单次耗时为 138.6 ns/op,内存分配为 157 B/op,分配次数为 0 次。
  • 64KB 测试结果:操作次数达到 7,249,588 次,单次耗时为 171.6 ns/op,内存分配为 208 B/op,分配次数为 0 次。
  • 1MB 测试结果:操作次数达到 8,231,407 次,单次耗时为 179.2 ns/op,内存分配为 489 B/op,分配次数为 0 次。

这些测试结果表明,Chanjet 在不同的数据大小下都能保持高效的性能,无论是小数据还是大数据,都能快速地完成读写操作。

监控指标说明

Chanjet 提供了完善的监控指标设计,支持 Prometheus 和 OpenTelemetry。这些监控指标可以帮助用户实时了解 Chanjet 的运行状态和性能表现。以下是一些监控指标说明:

  • 写入相关指标:包括写入操作总数、已写入数据的总字节数、写入失败的次数等。
  • 读取相关指标:包括读取操作总数、已读取数据的总字节数、读取失败的次数等。
  • 缓冲区切换指标:包括缓冲区切换操作总次数、切换延迟分布、定时任务跳过切换的次数等。
  • 异步处理指标:包括当前活跃的异步工作协程数量。
  • 缓冲池指标:包括对象池内存分配次数。
  • 通道状态指标:包括当前活跃通道中未处理的数据条目数量和未处理的数据总大小。
  • 指标类型说明:包括 Counter、Gauge、Histogram、CounterVec 等指标类型的特性和适用场景。

Chanjet 的监控指标设计全面且易于理解,用户可以根据这些指标来监控和优化 Chanjet 的性能和稳定性。

安装和示例

Chanjet 的安装非常简单,只需要使用以下命令即可:

go get github.com/TimeWtr/Chanjet

安装完成后,用户可以根据自己的需求编写相应的代码来使用 Chanjet。以下是一个示例代码:

package main

import (
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	cj "github.com/TimeWtr/Chanjet"
	"github.com/TimeWtr/Chanjet/_const"
	"github.com/TimeWtr/Chanjet/metrics"
	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

func main() {
	ser := gin.Default()
	bf, err := cj.NewBuffer(1025*1024*100,
		cj.WithMetrics(_const.PrometheusCollector))
	if err != nil {
		panic(err)
	}
	ser.GET("/metrics", gin.WrapH(metrics.GetHandler()))

	ch := bf.Register()
	exitChan := make(chan struct{}, 1)
	var wg sync.WaitGroup
	wg.Add(3)
	go func() {
		defer wg.Done()

		counter := 0
		for data := range ch {
			fmt.Println("[收到数据]: ", string(data))
			counter++
		}
		fmt.Println("通道关闭")
		fmt.Printf("接收到日志数据条数: %d", counter)
	}()

	go func() {
		defer wg.Done()
		defer bf.Close()

		template := "2025-05-12 12:12:00 [Info] 日志写入测试,当前的序号为: %d\n"
		for i := 0; i < 3100000000; i++ {
			err := bf.Write([]byte(fmt.Sprintf(template, i)))
			if err != nil {
				fmt.Printf("写入日志失败,错误:%s\n", err.Error())
				continue
			}
		}
		fmt.Println("结束了")
	}()

	// HTTP 服务协程
	go func() {
		defer wg.Done()

		srv := &http.Server{
			Addr:    ":8080",
			Handler: ser,
		}

		// 优雅关闭处理
		go func() {
			sigChan := make(chan os.Signal, 1)
			signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
			<-sigChan

			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
			defer cancel()

			if err := srv.Shutdown(ctx); err != nil {
				fmt.Printf("服务关闭异常: %v\n", err)
			}
			exitChan <- struct{}{} // 发送退出信号
		}()

		if err := srv.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
			fmt.Printf("服务启动失败: %v\n", err)
			exitChan <- struct{}{}
		}
	}()

	wg.Wait()
	fmt.Println("写入成功")
}

在这个示例中,我们创建了一个 Chanjet 实例,并通过 Chanjet 的 Register 方法获取了一个通道。然后,我们创建了三个协程,分别用于写入数据、读取数据和启动 HTTP 服务。最后,我们等待所有协程执行完毕,并输出 "写入成功"。

总结

Chanjet 是一个高性能的双缓冲通道,它基于 Go Channel、Buffer Pool 和零拷贝技术,实现了数据的高效处理和传输。Chanjet 的设计理念是将数据写入和读取分离,采用双写缓冲区设计和统一读取队列设计,以及无锁化设计和缓冲池设计,从而在保证数据安全的前提下,提升了系统的整体性能。Chanjet 的应用场景非常广泛,包括日志系统、数据处理系统、数据同步系统和高并发系统等。Chanjet 的性能测试结果表明,无论是在写入还是读取操作上,都展现出了高效的数据处理能力。此外,Chanjet 还提供了完善的监控指标设计,支持 Prometheus 和 OpenTelemetry,方便用户实时了解 Chanjet 的运行状态和性能表现。总而言之,Chanjet 是一个值得信赖的高性能双缓冲通道,它可以极大地提升系统的数据处理和传输能力。

Chanjet 基于Go Channel、Buffer Pool和零拷贝实现的高性能双缓冲通道 Chanjet 项目地址: https://gitcode.com/gh_mirrors/ch/Chanjet

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伍辰惟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值