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 实现来添加自定义压缩格式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/72418.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javascript深浅拷贝

概念 浅拷贝:新对象与原对象指向同一份内存地址 深拷贝:新对象与原对象完全独立,新对象与原对象指向的是两个内存地址 实现方式 浅拷贝 1.直接赋值 let source_obj {a: 1,b: 2 } let target_obj source_obj; 2.Object.assign let s…

Windows中的命令行提示符里的Start命令执行路径包含空格时的问题

转载:电脑知识收藏夹 Blog Archive Windows中的命令行提示符里的Start命令执行路径包含空格时的问题 当使用Windows 中的命令行提示符执行这段指令时(测试Start命令执行带空格的路径的程序或文件问题),第一行Start会成功执行,跳出记事本程…

Oracle 遍历变量游标

背景 由于我们的数据库系统中的游标特别多,DBA让我们优化,减少游标的使用。 电脑系统:windows数据库:Oracle数据库图形化界面工具:Toad,DBeaver(我測試的時候用的)记录日期:2023-09-04 具体实…

React Router 路由守卫

React Router 路由守卫 组件内路由守卫 1、下面是使用高阶组件实现路由守卫的示例代码&#xff1a; import React from react; import { Route, Redirect } from react-router-dom;const PrivateRoute ({ component: Component, isAuthenticated, ...rest }) > (<Rou…

计算机重点学科评级B-,山东省属重点高校考情分析

山东科技大学(B-) 考研难度&#xff08;☆☆&#xff09; 内容&#xff1a;23考情概况&#xff08;拟录取和复试分析&#xff09;、院校概况、23专业目录、23复试详情、各专业考情分析、各科目考情分析。 正文1175字预计阅读&#xff1a;3分钟 2023考情概况 山东科技大学计…

Android12之解析/proc/pid进程参数(一百六十四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

记一次诡异的Cannot find declaration to go to,Cannot resolve method

记一次诡异的 Cannot find declaration to go to&#xff0c; Cannot resolve method getOnExpressions in Join 对于项目中通常问题&#xff0c;清除缓存&#xff0c;重启idea&#xff0c;或者仔细检查语法通常都能解决问题&#xff0c;但是这次却失效了&#xff0c;以下是原…

Scala面向对象编程(高级部分)

1. 静态属性和静态方法 &#xff08;1&#xff09;回顾Java中的静态概念 public static 返回值类型 方法名(参数列表) {方法体} 静态属性… 说明: Java中静态方法并不是通过对象调用的&#xff0c;而是通过类对象调用的&#xff0c;所以静态操作并不是面向对象的。 &#xff0…

支持向量机(一)

文章目录 前言分析数据集线性可分情况下的支持向量机原始问题凸优化包解法对偶问题凸优化包解法 数据集线性不可分情况下的线性支持向量机与软间隔最大化 前言 在支持向量机中&#xff0c;理论逻辑很简单&#xff1a;最大化最小的几何间隔。但是实际编写代码过程中有一个小点需…

试用CSDN提供的AI创作助手生成关于Java个版本和未来发展的文章【AI】

本文是使用CSDN提供的AI创作帮手生成&#xff0c;出本句说明外其余均有AI生成&#xff0c;下面是我让AI列举各个Java版本的新功能和特点。 各个Java版本的新功能和特点 功能和特点&#xff1a; Java 8新功能和特点&#xff1a; Lambda表达式函数式接口方法引用Stream API接…

深入探讨Java Stream流:数据处理的新思维

文章目录 1. 流式思想1.1 输入流与输出流1.2 Stream流 2. 使用Stream流的步骤3. 获取Stream流3.1 容器3.2 数组 4. Stream流中间操作方法4.1 filter(Predicate<? super T> predicate)4.2 limit(long maxSize)4.3 skip(long n)4.4 distinct()4.5 sorted() 和 sorted(Comp…

Java使用pdfbox将pdf转图片

前言 目前比较主流的两种转pdf的方式&#xff0c;就是pdfbox和icepdf&#xff0c;两种我都尝试了下&#xff0c;icepdf解析出来有时候会出现中文显示不出来&#xff0c;网上的解决方式又特别麻烦&#xff0c;不是安装字体&#xff0c;就是重写底层类&#xff0c;所以我选择了p…

【Spring】aop的底层原理

&#x1f384;欢迎来到边境矢梦的csdn博文&#x1f384; &#x1f384;本文主要梳理 Spring 中的切面编程aop的底层原理和重点注意的地方 &#x1f384; &#x1f308;我是边境矢梦&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以…

vue递归组件

父组件&#xff1a; <template><div><treeVue :treeData"treeData"></treeVue></div> </template><script setup lang"ts"> import { reactive } from "vue"; import treeVue from "./tree.vue…

Linux查看指定端口是否被占用

在Linux中&#xff0c;可以使用多种方法来检查一个特定端口&#xff08;例如3306&#xff0c;通常由MySQL使用&#xff09;是否被占用&#xff1a; 使用netstat命令: 如果系统中已安装了netstat&#xff0c;可以使用以下命令检查3306端口&#xff1a; netstat -tuln | grep 330…

人体呼吸存在传感器成品,毫米波雷达探测感知技术,引领智能家居新潮流

随着科技的不断进步和人们生活质量的提高&#xff0c;智能化家居逐渐成为一种时尚和生活方式。 人体存在传感器作为智能家居中的重要组成部分&#xff0c;能够实时监测环境中人体是否存在&#xff0c;为智能家居系统提供更加精准的控制和联动。 在这个充满创新的时代&#xf…

科技资讯|苹果Vision Pro头显申请游戏手柄专利和商标

苹果集虚拟现实和增强现实于一体的头戴式设备 Vision Pro 推出一个月后&#xff0c;美国专利局公布了两项苹果公司申请的游戏手柄专利&#xff0c;其中一项的专利图如下图所示。据 PatentlyApple 报道&#xff0c;虽然专利本身并不能保证苹果公司会推出游戏手柄&#xff0c;但是…

Redis6搭建高可用的多主多从集群

Redis6搭建高可用的多主多从集群 环境准备搭建redis6集群安装redis6修改配置文件修改cluster-enabled修改cluster-config-file修改cluster-node-timeout 启动集群 环境准备 首先我们需要6台redis&#xff0c;那么为啥是6太呢&#xff1f;是因为我们要部署多master和多slaver集…

07-Spring Cloud

1、如何设计一个注册中心&#xff1f; 高可用&#xff1a;通过集群的方式 高并发&#xff1a;减少响应时间、提高吞吐量 并发用户数等&#xff0c;通过增加服务器性能、 扩展服务实例的方式 高性能&#xff1a;程序处理速度 考虑 数据存储结构、通信机制、集群同步。 集群…

C++中引用详解!

前言&#xff1a; 本文旨在讲解C中引用的相关操作&#xff0c;以及引用的一些注意事项&#xff01;搬好小板凳&#xff0c;干货来了&#xff01; 引用的概念 何谓引用呢&#xff1f;引用其实很容易理解&#xff0c;比如李华这个同学&#xff0c;他因为很调皮&#xff0c;所以…