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

gRPC之数据压缩Snappy、zstd

文章目录

  • gRPC之数据压缩Snappy
    • 一、背景
    • 二、什么是snappy
      • 1. Snappy适合场景
    • 三、demo: Go代码实现了一个snappy压缩格式的压缩器for grpc
      • 1. 这段代码怎么保证并发安全的?
    • 四、什么是zstd
    • 五、 zstd和snappy有什么区别,如何选择?
    • 六、demo: Go代码实现了一个zstd压缩格式的压缩器for grpc

gRPC之数据压缩Snappy

一、背景

gRPC支持数据压缩,可以有效减少网络传输的数据大小,提高传输效率。

gRPC默认就支持压缩,不需修改代码就可以获得压缩带来的好处。

二、什么是snappy

Snappy是Google开发的一种快速压缩和解压算法。

snappy
美: [ˈsnæpi]
英: ['snæpi]
adj. 精练的;简洁的;漂亮入时的;烦躁的
网络 爽快的;时髦的;漂亮的

Snappy的主要特点包括:

  • 速度快:相比gzip和zlib,Snappy的压缩和解压速度都要快得多。
  • 压缩率低:Snappy的压缩率比gzip低,一般在原始数据的30%~70%左右。
  • 内存占用小: Snappy只需要预留原始数据大小相等的内存就能完成压缩和解压。
  • 简单设计:Snappy算法简单,压缩和解压的代码也比较简短。
  • 广泛支持:目前已经有多种语言实现了Snappy,可以很容易地集成使用。
    Snappy的设计目标更注重速度,针对的是大数据量的网络传输场景。由于压缩速度快,CPU占用少,所以即使压缩率不高,也能提升大数据网络传输的效率。

1. Snappy适合场景

Snappy比较适合以下场景:

  • 大数据网络传输,例如MapReduce、RPC等。
  • 对CPU资源敏感的场景。
  • 内存有限的场景。
  • 压缩和解压需要频繁进行的场景。

Snappy以些许的压缩率作为代价,换来了极快的压缩速度。在对速度和CPU敏感的场景下,Snappy可以作为一个不错的压缩算法选择。

三、demo: Go代码实现了一个snappy压缩格式的压缩器for grpc

开源代码:https://github.com/bytedance/Elkeid/blob/db989a102fafccee9db4eb229af3f73b453022de/server/agent_center/common/snappy/snappy.go

package snappy// This code is based upon the gzip wrapper in github.com/grpc/grpc-go:
// https://github.com/grpc/grpc-go/blob/master/encoding/gzip/gzip.goimport ("io""io/ioutil""sync"snappylib "github.com/golang/snappy""google.golang.org/grpc/encoding"
)const Name = "snappy"type compressor struct {poolCompressor   sync.PoolpoolDecompressor sync.Pool
}type writer struct {*snappylib.Writerpool *sync.Pool
}type reader struct {*snappylib.Readerpool *sync.Pool
}func init() {c := &compressor{}c.poolCompressor.New = func() interface{} {w := snappylib.NewWriter(ioutil.Discard)return &writer{Writer: w, pool: &c.poolCompressor}}encoding.RegisterCompressor(c)
}func (c *compressor) Compress(w io.Writer) (io.WriteCloser, error) {z := c.poolCompressor.Get().(*writer)z.Writer.Reset(w)return z, nil
}func (c *compressor) Decompress(r io.Reader) (io.Reader, error) {z, inPool := c.poolDecompressor.Get().(*reader)if !inPool {newR := snappylib.NewReader(r)return &reader{Reader: newR, pool: &c.poolDecompressor}, nil}z.Reset(r)return z, nil
}func (c *compressor) Name() string {return Name
}func (z *writer) Close() error {err := z.Writer.Close()z.pool.Put(z)return err
}func (z *reader) Read(p []byte) (n int, err error) {n, err = z.Reader.Read(p)if err == io.EOF {z.pool.Put(z)}return n, err
}

这个代码是基于grpc-go库中的gzip压缩器实现的。grpc-go是Go语言的gRPC库的源码,其中包含了一个gzip压缩格式的实现。这个Snappy的压缩器实现,是参考和借鉴了grpc-go中gzip压缩器的实现方式,使用了类似的结构和方法。

主要的相似点是:

  1. 定义compressor结构体实现压缩接口
  2. 使用sync.Pool重用压缩对象
  3. 实现Compress和Decompress方法
  4. 注册压缩器到gRPC
    所以本质上,是用类似的方式实现了另一种压缩算法Snappy,而不是直接使用grpc-go中的gzip

主要逻辑如下:

  1. 定义了compressor结构体,包含sync.Pool成员用于重用压缩和解压的对象,减少GC。
  2. 定义了writer和reader结构体,封装了snappy的Writer和Reader,并包含一个指向compressor的pool,用于对象重用。
  3. 在init函数中注册了compressor到gRPC的压缩注册表中
  4. Compress方法会从池中取一个writer,reset并返回用于压缩的writer。
  5. Decompress方法会尝试从池中取reader,如果没有则新建,并返回用于解压的reader。
  6. Name方法返回压缩格式名称"snappy"。
  7. writer的Close方法会将writer放回池中重用。
  8. reader的Read方法在读完时会将reader放回池中重用。
    总结:
  9. 使用sync.Pool重用对象减少GC开销。
  10. 封装snappy的Writer/Reader实现gRPC压缩接口。
  11. 注册该compressor以支持snappy格式。
  12. 调用grpc时会自动使用该压缩器进行数据压缩。
    这样实现了一个高效的snappy压缩器来优化gRPC的数据传输。

1. 这段代码怎么保证并发安全的?

snappy在Go语言实现中自己实现了并发安全支持。具体来看:

  1. 定义了compressor结构体,内部维护两个sync.Pool池
  2. 在Compress方法中,从池中获取writer实例,重置并返回,实现复用
  3. 在Decompress中,从池中获取reader实例,或新建实例,并返回
  4. writer和reader在使用完成后会放回池中
    通过这种sync.Pool的机制,snappy实现了并发安全的压缩和解压。

sync.Pool之所以能够实现 goroutine 安全,的确是利用了其内部的互斥锁机制。
具体来看,sync.Pool 内部维护了一个 private pool 字段,它是一个 stack,用于存储缓存的对象。并且 pool 字段用一个 mutex 保护,以实现互斥访问。
当我们调用 Get() 方法取对象时,会对 mutex 加锁,从 pool 栈顶拿对象,解锁后返回。
当调用 Put() 方法置对象时,也是对 mutex 加锁,将对象推入 pool 栈顶,解锁。
正是通过这种互斥锁的机制,sync.Pool 实现了对 pool 的并发安全访问。多个 goroutine 调用 Get() 和 Put() 时,能够同步执行,避免了竞争条件。

四、什么是zstd

zstd是一种广泛使用的开源数据压缩算法。
它的全称是Zstandard,主要有以下几个特点:

  1. 压缩比
    zstd的压缩比非常高,通常可以将数据压缩到原始大小的20%左右,压缩效果明显优于一些老的压缩算法。
  2. 压缩速度
    相比其他高压缩比的算法,zstd的压缩速度也较快,仅次于速度最快的算法如LZ4。在多核CPU上,支持并行压缩来进一步提升速度。
  3. 内存占用
    zstd的编码和解码并不占用很多内存,可以在内存受限的环境下使用。
  4. 可扩展性
    zstd支持从1至22的压缩等级,压缩比和速度可根据不同等级进行平衡。
  5. 错误检测
    zstd在数据块添加校验值,可以检测压缩数据是否损坏。
  6. 多语言支持
    zstd已经支持了C、C++、Java、Go、Python、JavaScript等多种语言。
    zstd通过其高压缩比和快速的压缩速度,已经成为各种应用中的流行选择,被广泛应用于文件的压缩、数据存储、网络数据传输等方面。
    例如Linux kernel、Docker、Kafka、Hadoop、gRPC等知名开源项目都采用了zstd进行数据压缩。它可以明显减小数据量,提高存储和传输效率。

五、 zstd和snappy有什么区别,如何选择?

zstd和snappy都是流行的压缩算法,作为gRPC压缩器的区别主要有:

  1. 压缩比
    zstd的压缩比明显高于snappy,通常能够压缩到原始数据的20%左右,而snappy压缩比較低,大约在50%-70%之间。
    如果对网络带宽要求高,zstd可以提供更高的压缩效率。

  2. 压缩速度
    snappy的压缩速度非常快,是目前最快的压缩算法之一。zstd相比而言压缩速度较慢。
    如果对压缩加速要求高,snappy更合适。

  3. 内存占用
    snappy的编码解码占用内存很小,非常适合在内存受限的环境使用。
    zstd编码解码时需要更多内存。

  4. 兼容性
    snappy兼容性好,各语言的实现也比较成熟。zstd更新,语言支持还在持续改进中。
    所以其实两者有各自的优点,没有绝对的好坏。需要根据具体场景和需求选择。

如果需要高压缩率,zstd更合适;如果需要高速或内存受限则snappy更好。

六、demo: Go代码实现了一个zstd压缩格式的压缩器for grpc

开源代码:https://github.com/bytedance/Elkeid/blob/db989a102fafccee9db4eb229af3f73b453022de/server/agent_center/common/zstd/zstd.go

package zstdimport ("google.golang.org/grpc/encoding""io""github.com/DataDog/zstd"
)const Name = "zstd"func init() {c := &compressor{}encoding.RegisterCompressor(c)
}func (c *compressor) Compress(w io.Writer) (io.WriteCloser, error) {z := zstd.NewWriter(w)return z, nil
}func (c *compressor) Decompress(r io.Reader) (io.Reader, error) {z := zstd.NewReader(r)return z, nil
}func (c *compressor) Name() string {return Name
}type compressor struct {
}

实现了一个zstd压缩格式的gRPC压缩器。
分为以下几步:

  1. 导入需要的包,包括gRPC编解码包和zstd压缩算法包。
  2. 定义压缩器名称const Name = “zstd”。
  3. 初始化函数init()注册压缩器。
  • 创建compressor对象
  • 通过encoding.RegisterCompressor注册压缩器
  1. 实现Compress和Decompress方法。
  • Compress使用zstd.NewWriter封装writer生成zstd压缩writer
  • Decompress使用zstd.NewReader封装reader生成zstd解压reader
  1. 实现Name()方法,返回压缩器名称"zstd"。
  2. 定义compressor结构体实现gRPC的Compressor接口。

这样就实现了一个zstd格式的gRPC压缩器。

可以通过gRPC选项grpc.UseCompressor(Name)指定使用该压缩器。

压缩器会在gRPC消息编码时压缩数据,在解码时解压数据,从而减小消息大小,提高传输效率。
这是gRPC压缩器的典型实现方式,通过grpc.RegisterCompressor注册不同的 compress/decompress 实现来添加自定义压缩格式。

相关文章:

gRPC之数据压缩Snappy、zstd

文章目录 gRPC之数据压缩Snappy一、背景二、什么是snappy1. Snappy适合场景 三、demo: Go代码实现了一个snappy压缩格式的压缩器for grpc1. 这段代码怎么保证并发安全的? 四、什么是zstd五、 zstd和snappy有什么区别,如何选择?六、demo: Go代码实现了一个zstd压缩格…...

k8s之存储篇---存储类StorageClass

介绍 StorageClass 为管理员提供了描述存储"类"的方法。 不同的类型可能会映射到不同的服务质量等级或备份策略,或是由集群管理员制定的任意策略。 Kubernetes 本身并不清楚各种类代表的什么。这个类的概念在其他存储系统中有时被称为"配置文件&quo…...

WordPress(4)关于网站的背景图片更换

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、更改的位置1. 红色区域是要更换的随机的图片二、替换图片位置三.开启随机数量四.结束前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也…...

2 | Window 搭建单机 Hadoop 和Spark

搭建单机 Hadoop 和 Spark 环境可以学习和测试大数据处理的基础知识。在 Windows 操作系统上搭建这两个工具需要一些配置和设置,下面是一个详细的教程: 注意: 在开始之前,请确保你已经安装了 Java 开发工具包(JDK),并且已经下载了 Hadoop 和 Spark 的最新版本。你可以从…...

接口测试与功能测试的区别~

今天为大家分享的是我们在日常测试工作中, 一定会接触并且目前在企业中是主要测试内容的 功能测试与接口测试 一.功能测试与接口测试的基本概念。 1.1 什么是功能测试呢? 功能测试: 是黑盒测试的一方面, 检查实际软件的功能是否符合用户的需求 功能测试测试的内容包括以下…...

LeetCode 23 合并 K 个升序链表

LeetCode 23 合并 K 个升序链表 来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/merge-k-sorted-lists/description/ 博主Github:https://github.com/GDUT-Rp/LeetCode 题目: 给你一个链表数组…...

[国产MCU]-W801开发实例-TCP客户端

TCP客户端 文章目录 TCP客户端1、TCP协议简单介绍2、W801创建TCP客户流程本文将详细介绍如何在W801中使用TCP客户端。 1、TCP协议简单介绍 传输控制协议 (TCP) 是一种标准,它定义了如何建立和维护应用程序可以用来交换数据的网络对话。 TCP 与 Internet 协议 (IP) 一起工作,…...

《爵士乐史》乔德.泰亚 笔记

第一章 【美国音乐的非洲化】 【乡村布鲁斯和经典布鲁斯】 布鲁斯:不止包括忧愁、哀痛 十二小节布鲁斯特征: 1.乐型(A:主、B:属、C/D:下属):A→A→B→A→C→D→A→A 2.旋律:大三、小三、降七、降五 盲人…...

工程制造领域:企业IT架构

一、IT组织规划架构图 1.1 IT服务保证梯队与指导思想 二、整体业务规划架构图 三、数据化项目规划架构图 四、应用系统集成架构图...

PY32F003F18点灯

延时函数学习完之后,可以学习PY32F003F18的GPIO输出功能。 1、Debug引脚默认被置于复用功能上拉或下拉模式:PA14默认为SWCLK: 置于下拉模式PA13默认为SWDIO: 置于上拉模式PF4默认为Boot:Boot引脚默认置于输入下拉模式 2、GPIO输出状态&#…...

Mac不想用iTerm2了怎么办

这东西真是让人又爱又恨,爱的是它的UI还真不错,恨的是它把我的环境给破坏啦!让我每次启动终端之后都要重新source激活我的python环境,而且虚拟环境前面没有括号啦!这怎么能忍!在UI和实用性面前我断然选择实…...

x86_64 ansible 源码编译安装

源码 GitHub - ansible/ansible: Ansible is a radically simple IT automation platform that makes your applications and systems easier to deploy and maintain. Automate everything from code deployment to network configuration to cloud management, in a languag…...

数据结构学习系列之顺序表的两种插入方式

方式1:在顺序表末端插入数据元素,代码如下:示例代码: int insert_seq_list_1(list_t *seq_list,int data){if(NULL seq_list){printf("入参为NULL\n");return -1;}if(N seq_list->count){printf("顺序表已满…...

Matlab/Python教程系列 | 根据目录下的已有图片制作视频(动画)

MATLAB和Python的编程教程: 根据目录下的已有图片制作视频(动画) 注1:本文系“MATLAB/Python编程教程”系列之一,致力于使用Python和Matlab实现特定的功能。本次要实现的功能是:根据目录下的已有图片制作视频(动画)。 在这个教程中,我们将一起学习如何使用MATLAB和Python编…...

Pyecharts数据可视化(一)

目录 1.Pyecharts简介 2.Pyecharts的常用方法 3.Pyecharts绘制柱状图 3.1 绘制并列柱状图 3.2 绘制水平直方图 1.Pyecharts简介 Pyecharts是一个用于创建交互式图表的Python库。它基于Echarts,一个强大的JavaScript图表库,Pyecharts允许Python开发者…...

stable diffusion实践操作-提示词-图片结构

系列文章目录 stable diffusion实践操作-提示词 文章目录 系列文章目录前言一、提示词汇总1.1 图片结构11.2 图片结构21.3 图片结构3 二、总结 前言 本文主要收纳总结了提示词-图片结构。 一、提示词汇总 1.1 图片结构1 StylesArtistshudson river school哈得逊河学派alpho…...

程序员自由创业周记#2:前期准备

感恩 上次公开了创业的决定后,得到了很多亲朋好友和陌生朋友的鼓励或支持,以不同的形式,感动之情溢于言表。这些都会记在心里,大恩不言谢~ 创业方向 笔者是一名资质平平的iOS开发程序猿,创业项目也就是开发App卖&am…...

Elasticsearch实战(四):Springboot实现Elasticsearch指标聚合与下钻分析open-API

文章目录 系列文章索引一、指标聚合与分类1、什么是指标聚合(Metric)2、Metric聚合分析分为单值分析和多值分析两类3、概述 二、单值分析API设计1、Avg(平均值)(1)对所有文档进行avg聚合(DSL)(2…...

Opencv图像暗通道调优

基于雾天退化模型的去雾算法,Opencv图像暗通道调优,(清华版代码)对普通相片也有较好的调优效果,相片更通透。 结合代码实际运行效果、算法理论模型、实际代码。我个人理解,实际效果是对图像的三个颜色通道…...

怎样来实现流量削峰方案

削峰从本质上来说就是更多地延缓用户请求,以及层层过滤用户的访问需求,遵从“最后落地到数据库的请求数要尽量少”的原则。 1.消息队列解决削峰 要对流量进行削峰,最容易想到的解决方案就是用消息队列来缓冲瞬时流量,把同步的直…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

dify打造数据可视化图表

一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...