从一到无穷大 #15 Gorilla,论黄金26H与时序数据库缓存系统的可行性

在这里插入图片描述本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权。

引言

缓存系统的高效存在前提,在满足前提的情况下可以接受缺陷便没有理由不引入缓存系统,但是具体影响因素需要仔细权衡,时序数据库只有常态极端场景下缓存有显著效果。

时序数据库缓存系统的可行性

我曾在[1]中讨论过在DB前放置缓存的缺陷,即:

  1. 外部缓存会增加延迟
  2. 外部缓存增加了不必要的成本
  3. 外部缓存会降低可用性
  4. 外部缓存破坏了数据库缓存
  5. 外部缓存忽略了数据库缓存能力和资源

[3]中提到DAX类缓存适合的场景:

  1. 需要低响应时间的业务
  2. 热点明显的应用
  3. 读取请求占总请求比例较高
  4. 不需要强一致性

我们从Gorilla的视角去看这个问题,现有基于HBase的TSDB性能过差,但是存量数据2PB又不想迁移,如何可以快速满足日益增长的业务需求?现有的需求是这样的:

  1. 写的可用性极其重要
  2. 需要较强的容错能力,能够承受频繁的单机,网络故障和版本发布
  3. 查询峰值40000/s,要求基本在10ms级别,且宕机时读不中断
  4. 一致性不那么重要,数据能反映具体趋势即可
  5. 临近的数据点比老旧的数据点更有意义
  6. 百分之八十五的查询聚集在过去26h
  7. 二十亿时间序列,每秒产生1200万个数据点,每天产生 1 万亿个数据点(每个数据点 16 字节,那就占用 16TB 内存)
  8. 系统需要高效的扩容机制
  9. 现有监控系统依赖于TSDB做图表分析(分为交互式和接口拉取)和告警,但是基于Hbase的TSDB查询P90高达几秒,对于交互式系统可以容忍,但是接口分析和告警无法接受

考虑下这种情况下基于memcache/redis的write-through cache是否可以生效呢?

论文中提到这种方法在加入一个新的时间序列时需要先判断时间序列是否存在,再执行插入,这意味着一个插入需要两个请求,对memcache的流量负载较高,所以否定了这种做法。

我认为还有一些问题:

  1. 时序数据库的查询常态是分析需求,很少存在点查,且查询语句where条件中的时间范围始终变化,这意味着这层缓存需要有查询聚合能力,并不是简单的kv接口可以实现,也就是说使用现有系统的memcache/redis是无效的;
  2. 超过缓存系统时限乱序数据的写入性能依旧很差,因为cache的有效时间是有限的,数据仍旧需要写入底层Hbase;
  3. 云原生数据库我们需要在云上售卖,在使用cache是如何做租户隔离?在cache上花费的精力其实无法让小用户收益,其次运营非常复杂,在一个大集群中存在大小客户时cache的粒度又该如何设置?
  4. cache存储什么数据?时序数据库不同于kv没有明显热点,且写入均衡,但是查询上因为告警/监控业务的特殊性最近的数据被访问的概率更大,所以做cache肯定是存最近的原始数据,也就是现在的Gorilla

当解决了这些问题后会发现,我们其实就是实现了一个计算+存储层,老数据降冷Hbase。

现有的云原生时序数据库比如InfluxDB IOX,Lindorm都是存算分离的,存储节点本身就是内存写入,随后将数据/索引写入远端存储(对象存储,分布式文件系统),这其实意味着在写入的角度来看已经是cache了,而且计算上在拥有计算下推能力时单查询性能时非常出色,且存储节点也可以用类似于Gorilla缓存原始数据。从这个角度看,如果把Gorilla看作缓存,Hbase看作远端存储,事实上这个架构和现有的时序数据库分布式是相似的。

以Lindorm举例,即Gorilla=TsCore+TsProxy,Hbase=DFS,Gorilla优势只有26H以内小查询会快。
如果不存在DFS,TsCore走三副本保障一致性,即Gorilla=TsCore+TsProxy,Hbase=TsCore,一般现有的时序数据库写入性能极高,cache带来的高写入吞吐已然没有意义,查询上Gorilla对于26H以内有压倒性优势,但是26H以外现有架构的方法显然是更优秀的(现有架构会趋向于老数据的元信息下刷磁盘,所以初次读取需要大量IO,后续读取和26H以内一样快),除此之外现有的时序数据库在一致性,扩缩容上也更具优势。以我们的运营经验来看,并不存在显著的“26H”这种数字,周级别的分析非常常见,且存在和上个周期的对比需求,也就是说视图选择1d,实际会查询2d,两条曲线做对比分析。

所以这篇论文的架构其实是在解决诸多约束下的现实问题,不是一个所有公司通用分布式解决方案。但是这篇文章发表在2015,在八年前互联网规模在别人还在mysql/Cassandra时能有这样的监控系统解决方案已经非常优秀,而且这篇文章现在来看最具实践意义的其实是时间戳 delta-of-delta和浮点压缩算法XOR,到现在仍旧广泛使用在时序数据的列存压缩,从这个角度讲这篇文章其实非常经典。

回归题目的后半部分,时序数据库缓存系统的可行性如何?

以现有云原生数据库发展来看,不可行,原因如下:

  1. 时序数据库不存在明显访问热点,只是最近数据相对于历史数据访问频率更高,所以缓存中不能存数据项,只能存新的数据集合
  2. 因为部分业务时序数据的敏感性,一致性要求较高,不允许数据丢失,意味着缓存只能write-through,所以只能用于加速读
  3. 时序查询需要计算引擎,意味着缓存系统需要有计算能力(开发复杂性),那么时序需要的缓存系统实际就是缓存最近数据的计算节点,现有的架构存储节点已经可以承担这部分功能,无非是数据的缓存机制更加灵活,不是只缓存某个时间段的数据

所以在现代TSDB前放置缓存就是用RAM去换部分查询的高效,显著增加成本的同时增加系统复杂性。

总结下Gorilla优缺点:

优点:

  1. 26H以内小查询性能高
  2. 解决现实问题,开发成本低(不需要做引擎,不需要做数据搬迁)

缺点:

  1. 依赖于85%查询26H以内数据
  2. 一致性较差
  3. 单点故障写入可用性依靠客户端hold住1m以内数据,存在服务中断时间,有数据延迟写入风险,对监控视图有影响
  4. 26H以外查询Hbase,性能较差,且基本无法优化
  5. 查询无法做计算下推,大查询可预料的性能低下
  6. 26H以内数据降采样/流式计算目前的实现存在Hbase,仍旧查询性能差

论文细节

压缩算法

在这里插入图片描述

delta-of-delta

keypoints在于发现绝大多数数据点都是以固定间隔到达的。比如时间序列通常每 60 秒记录一个点,这样意味着单个时间序列的连续点时间戳是高度相似的,比如连续的时间60,60,59,61 只需要存储60,0,-1,2,稍加解析便可知道每个时间点具体值。

具体算法逻辑如下:
在这里插入图片描述
可以从下图看到效果非常显著,96%的数据点用一个比特就可以表示。
请添加图片描述

XOR

keypoint有两点:

  1. 发现大多数时间序列中的值与相邻数据点相比变化不大,这其实很好理解,很多时序数据的曲线基本是平缓的,比如成功率,请求数,利用率等。
  2. 数据相近的话sign, exponent, 以及尾部的几个比特基本一致

具体算法直接参考[2]即可,我就没必要搬运论文了。

memory / disk structures

请添加图片描述
内存结构没有奇巧淫技:

  1. ShardMap存储两小时的shard,用于减小一个结构内时间线数量
  2. TSmap存储时间线到TS的指针,vector用于加速扫描数据
  3. TS用于存储append log和blocks,压缩章节中提到120个时间点一个block(平衡压缩和解析开销)

磁盘结构也相对简单:

  1. key lists:用于快速扫描数据,文中提到内存中封闭的block会执行重写,以重新分配内存,减少内存碎片
  2. append-only logs:用于单节点宕机时另外一个节点快速恢复非block的数据,在刷新之前数据缓冲64kB,所以宕机可能造成数据丢失
  3. complete block files:数据文件
  4. checkpoint files:用于标记完整的block文件何时刷新到磁盘,在进程崩溃时如果没有将block文件刷新到磁盘,当新进程启动时,checkpoint不存在,新进程读取append log

Handling failures

需要容忍单机故障(频繁发生,版本发布可以看作单点故障)和集群故障(需要在意外发生时保持运行)
主要措施有三点:

  1. multi region用于集群故障
  2. 单机故障时写请求:ShardManager 会将其故障节点负责的数据范围分配给集群中的其他节点,分配期间,客户端对接收到的数据进行缓冲。缓冲区的大小可容纳 1 分钟的数据,超过 1 分钟的数据点会被丢弃;当分配完成时接受写入。如果 Gorilla 主机以更可控的方式停机,它会在退出前将所有数据刷新到磁盘,所以软件升级不会丢失数据。
  3. 单机故障读:部分节点无法读取,查询将返回部分数据,并将结果标记为部分数据。当客户端库从故障区域查询中收到部分结果时,查询区域B,如果有完整的结果则返回。如果区域 A 和区域 B 都返回了部分结果,则这两个部分结果都会返回给调用者,并设置一个标志,说明某些错误导致了数据不完整。

Lessons learned

  1. Prioritize recent data over historical data
  2. Read latency matters
  3. High availability trumps resource efficiency

总结

基架的精髓是自我定位准确以及调教客户,切不可呈口舌之快,进而后患无穷。

参考:

  1. Don‘t Put a Cache in Front of Database
  2. Gorilla: 一个快速, 可扩展的, 内存式时序数据库
  3. In-memory acceleration with DynamoDB Accelerator (DAX)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: 要用 Go 语言实现一个内容管理系统 (CMS),你需要考虑以下几个方面: 1. 数据存储:你需要选择一种数据库,并使用 Go 语言来连接和操作数据库。常见的数据库有 MySQL、PostgreSQL 和 MongoDB。 2. 网站框架:你可以使用 Go 语言内置的 net/http 库来构建网站后端,也可以使用第三方框架,比如 Gin、Echo 和 Buffalo。 3. 网站布局和样式:你可以使用 HTML、CSS 和 JavaScript 来设计网站的布局和样式。 4. 网站功能:你可以根据需求来实现各种功能,比如文章发布、评论管理、用户注册登录等。 在开始实现之前,建议先了解 Go 语言的基础知识,包括变量、类型、流程控制、函数、指针等。同时,也建议了解一些常用的第三方库,比如用于数据库操作的 GORM 库和用于模板渲染的 html/template 库。 ### 回答2: 使用Go语言实现一个CMS系统是完全可行的。Go是一种现代化的编程语言,它具有高效的并发性能和简洁的语法,非常适合构建Web应用程序。 首先,我们可以使用Go的HTTP包来处理HTTP请求和响应。通过创建一个HTTP服务器,我们可以监听特定的端口,并对请求进行路由和处理。可以使用gorilla / mux库来进行路由器设置和管理。 接下来,我们可以设计和实现数据库模型。Go有很多流行的ORM(对象关系映射)库,如GORM和xorm。使用这些库,我们可以方便地将Go结构体映射到数据库表,并进行基本的CRUD(创建、读取、更新、删除)操作。 然后,我们可以创建处理程序来处理特定的请求,例如创建、编辑和删除内容。可以使用HTML模板引擎(如html / template)来生成动态的HTML页面,也可以使用Go的JSON库将数据以JSON格式返回给客户端。 为了保护用户登录和数据的安全,我们可以使用Go的加密库来存储和验证用户的密码,并使用会话管理库(如gorilla / sessions)来跟踪用户的认证状态。 最后,我们可以使用Go的测试框架(如testing / testing)来编写和运行单元测试和集成测试,以确保系统的正确性和稳定性。 总之,使用Go语言实现一个CMS系统是一项有趣且具有挑战性的任务。Go的简洁性、高效性和并发性能使其成为构建可扩展的Web应用程序的理想选择。 ### 回答3: 使用Go语言来实现一个CMS(内容管理系统)可以借助于一些Go语言的库和框架来快速搭建一个功能完善的CMS系统。 首先,可以使用Go的Web框架如Gin或Echo来处理HTTP请求和路由,这样能够方便地创建和管理不同页面的接口。 其次,可以使用Go的数据库驱动库如Gorm来连接数据库,如MySQL或PostgreSQL等,以存储和管理网站的数据。可以使用Gorm的模型和迁移功能来定义表结构和进行数据库迁移。 接下来,可以利用Go的模板引擎如html/template来生成动态页面,通过将数据库中的数据和模板结合,可以实现页面的渲染更新。 此外,由于CMS系统通常需要进行用户身份验证和授权管理,可以使用Go的身份验证和授权库如jwt-go或casbin来实现用户的登录、验证和权限管理功能。 同时,为了方便系统的扩展和维护,可以使用Go的依赖管理工具如Go Modules来管理项目的依赖关系。 总结起来,用Go实现一个CMS系统需要使用到Go语言的Web框架、数据库驱动库、模板引擎、身份验证与授权库等,通过这些工具可以方便地创建和管理网站的接口、数据库、页面、用户身份验证和权限管理等功能,从而实现一个功能完善的CMS系统

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

李兆龙的博客

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

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

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

打赏作者

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

抵扣说明:

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

余额充值