精华内容
下载资源
问答
  • 要理解IOPS,先要了解磁盘I/O的概念。I/O(input/output)从字义理解就是输入/输出,输入指的是对磁盘写入数据,输出...另一个重要指标是数据吞吐量,即每秒磁盘I/O的流量(写入+读出数据的大小),对于大量连续读写的应...

    要理解IOPS,先要了解磁盘I/O的概念。I/O(input/output)从字义理解就是输入/输出,输入指的是对磁盘写入数据,输出指的是从磁盘读出数据。磁盘IOPS(Input/Output per Second)即在一秒内磁盘能够处理的I/O请求数量,对于随机读写频繁的应用,IOPS是关键衡量指标。另一个重要指标是数据吞吐量,即每秒磁盘I/O的流量(写入+读出数据的大小),对于大量连续读写的应用,吞吐量是关键衡量指标。

    磁盘IOPS和吞吐量是动态变化的,其最大理论值受硬件指标影响,在实际测试时,不但与读写负载相关,也可以相互影响。一般来讲,单次I/O操作读写的数据量越大,此时的IOPS越小,反之亦然。同时,不同的场景对于IOPS和数据吞吐量的追求也不一样:

    读取10000个1KB文件,用时10秒 ,Throught(吞吐量)=1MB/s,IOPS=1000,追求IOPS。

    读取1个10MB文件,用时0.2秒 ,Throught(吞吐量)=50MB/s,IOPS=5,追求吞吐量。

    另外,不同类型的磁盘性能也有差异,目前常用的磁盘类型是SAS和SATA磁盘,一些高端存储也采用SSD盘,比如

    高性能云盘——每份数据保留4份,支持热迁移、快照备份等,提供长期稳定的I/O性能输出,适合web服务、中小型数据库、企业办公等大多数业务场景,满足核心业务测试、开发联调环境的I/O需求。

    SSD超高速云盘——采用高速SSD硬盘的分布式存储系统,兼具高性能云盘的所有优点,同时具有极高的随机读写IOPS、高吞吐量,适用于高负载、有密集I/O需求的核心关键业务系统,支持大型数据库运行。

    林创云https://www.lcthink.cn/services/cloudhost/

    展开全文
  • 7 月 24 日晚上 8 点,七牛云高级大数据架构师王珂在飞马网进行了题为《如何快速搭建智能化的统一日志管理系统》的音频直播,和大家探讨了日志平台建设中需要考虑的要点,并分享了七牛云在提高日志平台吞吐量上的...

    7 月 24 日晚上 8 点,七牛云高级大数据架构师王珂在飞马网进行了题为《如何快速搭建智能化的统一日志管理系统》的音频直播,和大家探讨了日志平台建设中需要考虑的要点,并分享了七牛云在提高日志平台吞吐量上的实践经验。本文是对直播内容的整理。

    日志样例

    上图列举了一些日志的例子,方便大家了解日志 概念,这里简单解释一下前两项。

    第一项是某网站的用户行为日志,以这条日志为例,包含了两类信息:一类是用户信息,例如「city」 这个是用户 访问来源地点 ,「useAgent」 用户的浏览器版本 ;还有一类是程序信息,例如 「pageSize」 还有 「pageView」表示页面尺寸。

    第二项是一个典型的 nginx 服务的日志,「remote_addr」 是请求来源地址,「request」是请求内容,「status」 是请求状态码。

    三个基础问题

    关于日志有三个基础的问题。

    第一个问题,什么是日志?

    维基百科上的描述是:日志是设备或者程序对自身状态和运作行为的记录。这里我的理解是,现在设备和程序会按预先定义好的模式输出自身的事件信息,这些事件信息被写入到文件或者数据库中就形成了日志;所以,日志实际上是对于事件信息的记录,上例中的nginx日志就是对一次请求事件的记录。

    第二个问题,为什么需要日志?

    为什么需要日志呢?因为设备和程序通过事件输出了运行状况相关的关键信息,例如服务器是否出现过异常,出现了什么异常,这些事件是设备和程序在设计时候预先定义好的,用来帮助使用者进行维护的。日志记录了事件,通过日志就可以看到设备和程序运行的历史信息,通过这些信息,可以了解设备和程序运行情况的变化,以更好的对于设备和程序进行维护。

    第三个问题,什么时间需要日志?

    主要是在系统出现问题的时候,通过对于运行过程中发生的历史事件,可以查找问题出现的原因。另外,统计系统的运行指标时也需要日志。

    日志平台建设探讨

    ELK 方案介绍

    业内最常见的日志采集方案就是 ELK,ELK 分别是方案中 3 个组件的缩写。

    • E 是 Elasticsearch,它是一个开源的实时分布式搜索引擎,它主要被用作日志数据的存储和搜索。

    • L 是 Logstash,这个组件是日志解析工具,用于通过正则表达式解析,将日志中的字段分解出来再传入 Elasticsearch 中。

    • K 是 Kibana,这个组件是展示工具。用于展示保存 Elasticsearch 中的日志数据,通过可视化的图表可以清楚了解到一段时间内日志中新进入了多少条记录,即发生了多少个事件,还可以看到不同类型的事件数目随时间的波动情况。

    在 ELK 出来之前,日志管理基本上都是通过登陆日志所在机器然后使用 Linux 命令或人为查看和统计 ,这样是非常没有效率的。ELK 有三个优点:快速、易上手、可扩展 :快速,ELK 将日志统一存储在 Elasticsearch 中,通过搜索查询日志的速度要比登陆机器上查询要快速的多;易上手,ELK 本身部署方便,通过官网上的教程就可以搭建起一套简单的 ELK;可扩展,Elasticsearch 和 Kibana 都有一些扩展插件,扩展插件提供了很多新的功能可以使用,和 Logstash 与 Kibana 具有相同功能的开源组件也有不少,可以按照使用的场景进行替换。

    其他日志相关组件介绍

    除了 Logstash 还有几种常用日志采集工具。

    • Rsyslog 一般用于收集系统的 syslog 日志;

    • Fluentd 主要用于容器日志收集;

    • Filebeat go 语言编写,专注于文件日志收集;

    • Flume 在传输链路中增加了 Channel 组件作为数据缓存,可以把数据保存到磁盘上以避免数据丢失。

    收集日志时除了收集工具还会用到缓存组件,主要的缓存组件有 2 个:Kafka 消息队列和 Redis 内存数据库。

    • Redis 主要用于小数据量低延迟要求的场景,多数情况下和 Storm 联用来处理实时数据。

    • Kafka 是通用的消息队列组件,适合场景比较多,类似 Kafka 的消息队列组件还有几种。

    构建日志采集方案的三要素和四原则

    使用接入工具和缓存组件构建日志采集方案时,我们需要考虑的三个要素:时效性、数量级和复杂度。

    • 时效性就是日志是否需要保障低时间延迟的传输,即我的设备和程序发生的事件需要在最短时间内拿到,还是可以允许有延迟,允许多长时间的延迟,几分钟还是几小时、或者半天也行。在方案制定过程中,时效性决定了是否要选择 Storm 实时流式方案。并作为测试过程的硬指标发挥作用,在模拟测试环节判断方案是否可用。

    • 数量级是对于日志条目数和空间大小的衡量要素。运行出错才做事件记录的程序日志和每秒收集一次传感器日志在数据条目和文件占用的磁盘空间上是有很大区别的,进行采集的时候对于采集组件的要求也是不同的。数量级影响采集工具和缓存组件的选择,在方案制定过程中,每天采集的条目数超过百万时候就需要增加缓存组件了,条目数过亿时候就需要考虑如何平衡数据写入和数据查询的资源了。

    • 最后一个要素就是复杂度,采集方案复杂度的产生主要由于原因:数量级、网络环境和采集工具。在数量级要求下,我们不得不添加缓存组件,把日志先写到 Kafka,再把日志写到 ES,增加一个 Kafka,就需要考虑 Kafka 的高可用问题和数据丢失问题,方案复杂度就提升了。方案的复杂度会影响方案的实施难度和维护难度,复杂度太高的方案即使设计出来也比较难落地。

    考虑到这三种因素,我们在选择日志采集方案的时候要考虑到四个原则。

    • 时效性要求不高,数量级也不大的情况优先采集文件,因为文件是最简单的也是最好采集的。

    • 在日志生成的过程中解决解析问题,而不是在传输过程中,也就是在日志生成的过程中就约束它的格式,而不是考虑在传输过程中统一它的格式。大部分的采集工具都支持中间改写日志信息,增加内容或者拆分内容,这些操作实际上增加了采集方案的复杂度,也使得替换采集工具的成本增加,需要尽量避免。

    • 不同的日志都有它的特点,那么是不是我们每一个具体的场景,都要选择不同的工具呢 ?我觉得是需要比较这个工具的特点带来的收益和增加工具来的的复杂度变化,如果新增工具不会对于原来的组件产生影响,也不会新增开发内容,运维上也能接受;那么是可以增加工具的,否则工具数量越少越好。

    • 如果数据量比较大的话,就要考虑多级的缓存处理。引入缓存主要就是为了分离上下游操作,在不影响 ES 性能的情况下,写入更多的数据。

    规划容器日志采集方案的要点题

    由于现在容器概念比较热,单独和大家聊一下容器日志采集需要考虑的内容。

    01  采集方式

    • 现在主流容器分配管理都是用的 K8s 架构,K8s 日志数据的收集比较简单,可以直接从 var/log/containers 下按照文件的形式获取;内部应用日志使用 Daemonset 的方式部署日志收集工具就可以完成收集。

    • 如果没有使用 K8s,仅使用了 Docker ,日志数据的收集会稍微麻烦一些,容器自身的 stdout 可以通过 Docker 自带的 logdriver 去归集。容器内部的应用日志,可以通过 Docker 自带的一些命令查看,或者使用第三方组件,比如 fluend-pilot 可以收集这部分日志。对于七牛云的实践来说,你也可以把容器内的日志投递出去。

    02  常见业务需求点

    • 避免容器迁移中日志丢失:在 K8s 中用 PVC 做持久化存储,将日志都写进去即可。 但带来的额外问题是,需要管理这个持久化存储。

    • 支持多种日志采集工具:每种日志采集工具配置不同的 Pod,然后用 Daemonset 去调用。

    • 在容器内应用日志中体现容器信息:K8s 1.7 里面提供了一个功能,在启动容器时可以把容器的信息写成容器内的公有变量。另一种方式在 Daemonset 里还是能够拿到容器系统变量的。

    七牛云日志平台面临的挑战

    七牛云日志平台日志主要有三个来源,第一是七牛云存储系统的日志,第二个是七牛云容器平台的日志,第三个是使用七牛云智能日志管理平台的客户上传的私有日志。现在日均数据流入量超 250 TB,3650 亿条,其中最大的客户日均数据流入量超过 45 TB。

    七牛云日志平台面临的主要挑战如下:

    • 数据量大,需要稳定支持大量数据的写入和查询;

    • 数据来源多,需要支持多种数据源的数据采集,并且采集过程要稳定可监控;

    • 平台用户功能需求多,需要支持丰富的扩展功能;

    • 平台用户大部分是企业用户,需要支持多租户场景,并提供用户权限管理功能。

    其中最大挑战,就是如何把大量的数据,高效的存储下来,保障数据不丢失的同时尽可能减少资源占用。

    七牛云日志平台架构介绍

    七牛云平台在技术选型阶段对于 ELK 方案进行了深度的使用和测试,具体实践中发现 ELK 方案主要有以下 4 点问题:

    • ELK 方案达不到七牛云在超大规模数据量的情况下系统稳定性及数据处理性能的要求;

    • ELK 方案达不到七牛云在多种数据源采集稳定性上的要求;

    • ELK 方案达不到七牛云用户多租户的要求;

    • ELK 方案达不到七牛云在机器学习等拓展功能方面的要求。

    最终评估的结果是 ELK 方案并不能解决七牛云面临的挑战,所以七牛云走上了自研的道路,当前七牛云的日志平台架构描述如下。

    • Logkit:统一采集日志数据,支持上百种数据源(包括文件、MySQL、MSSQL、ElasticSearch、MongoDB、AWS CloudTrail 等);支持在采集端完成对数据格式的解析与字段转换;内置 Channel 组件保证传输过程中数据不丢失;可以通过管理界面查看采集任务状态并管理任务配置。

    • Pipeline:日志平台统一的入口,可以接收从 log 文件、SDK、Web 端、IOT、云存储上通过 API 传输过来的数据。数据进入 Pipeline 后,我们基于 Kafka 做了实时计算组件,支持自定义的计算过程,计算的结果我们通过 Export 组件,根据不同情况将数据传输到后台 3 种存储组件当中。

    • Insight 集群:七牛云基于深度定制的 ES 开发的日志存储组件,主要用于支持超大规模日志数据的检索查询。另外,Insight 集群可以支持多租户的使用要求,并且集成了监控告警、报表和机器学习等拓展功能;

    • 七牛云的对象存储:七牛云通用存储组件,用于存储过了搜索期的冷数据,并支持自定义离线计算过程进行数据分析;

    七牛云经验分享-吞吐量问题

    七牛云是如何解决日志平台吞吐量的挑战的呢?

    首先,Pipeline 的 Kafka 集群通过扩展,是能够承接百 TB 级别的数据的;那么问题的瓶颈就变成了如何将百 TB 量级的数据从 Kafka中写入到 ES 上。由于原始数据进入到 Pipeline 中可能存在计算流程,负责写入 ES 的 Export 组件是不能直接从 Kafka 中拉取数据的,只能等待 Pipeline 的调用,即 Export 不能自主的安排写入进度而是必须要和用户的数据操作保持一致。在这样的情况下,Export 是不能直接去写 ES,因为可能同时出现多个用户的数据需要执行写入操作的情况,如果 Export 直接去写入,会产生资源竞争和阻塞。

    数据传输优化思路

    七牛云对数据传输优化主要分为 2 部分。首先,我们把获取 Kafka 数据、数据格式转换和过滤操作放在 Export 中操作,保持 Export 操作完成后的数据是可以直接写入 ES 中的;基于客户任务的调度的操作也放在 Export 这里,跟踪 Export 的状态就可以把数据接入的情况实时的反馈给客户。然后,在 Export 下面,我们做了一层传输队列层,通过传输队列提供缓存,数据先进入传输队列,然后根据当前 ES 的情况非对称的写入,保障数据写入过程不影响客户的查询检索,并且设计了一些故障恢复的措施。

    传输队列架构图

    传输队列的实现是基于内存队列和本地文件队列,这就跟 Flume 的 Channel 是相似的概念。但是在实现的过程中,还对它做了一些额外的分装。首先是 agent 组件,agent 可以理解为 scheduler 组件,它负责任务的创建和分配;第二个是 transaction 事务池,这个内存队列的入队和出队,都是通过 transaction 的事务池去处理的。为什么这里要用事务的概念?因为我们在写入 ES 的时候,如果写 200 条数据,会告诉我们有 150 条数据写进去了,有 50 条数据没有写进去,它不会区分是哪 50 条没有写进去。所以说,在这里使用 transaction 的意义就在于,如果真实的情况下,我们遇到这种情况,可以这 50 条数据重新发回 memary queue 里面,让内存队列继续写这 50 条数据。

    事务池的设计

    这是 transaction 内部的一个情况,当数据进入 Channel 的时候,如果有空间进,就会正常的写入数据;如果没有空间进,会返回 503 的错误。当数据出 Channel 以后,通过 transaction 保证数据的写入是完整的,如果这一次写入不成功,会将一些没有写入的数据回滚到 Channel 中。当数据需要停止的时候,会先停止下游的 sink ,并且启动一些磁盘的 sink ,将数据回滚到 Channel ,再通过磁盘 sink 写入到本地磁盘中。最后启动的时候,会直接先从本地磁盘把数据写入到 Channel 里面,然后再从正常的数据流中去写 Channel。

    通过传输队列层的设计七牛云实现了大量数据的稳定写入,整体上看传输队列通过多级缓存和任务分解机制实现了动态资源调配,将任务不断的分解,然后根据 ES 的情况,逐步把分解后的小数据块写入到 ES 中,避免了 ES 因为大量写入而崩溃;同时从 Kafka 取出数据后操作一直在内存中进行也保证了数据传输的速度。

    七牛云智能日志管理平台

    七牛云智能日志管理平台 能力全景图

    基础功能

    前边分享了我们的架构设计和实践经验,而在功能细节上,我们也针对传统方案的缺陷,比如 ELK 无法解决的需求点,进行了自主研发调优。

    • 数据采集层面,logkit 可以实现可视化的数据采集;并且在采集数据的过程中,可以看到实时流量和细分到每台机器的情况。

    • 日志搜索层面,我们支持多用户与用户权限管理;,可自动完成 Reblance 操作,无需用户过多关注,不会影响用户的查询效率;对于 ES 写入也做了深度的优化,可以在大量数据写入的同时保证 ES 的查询效率。

    • 数据可视化层面, 我们提供了用户体验极佳的搜索界面,并且提供了完整的报表体系,轻松满足用户的所有报表需求。另一方面,除了原生支持监控告警外,我们也支持对接第三方可视化工具,如 Grafana。

    智能化组件

    考虑到未来数据智能的趋势,我们还为用户提供了机器学习组件。组件的操作门槛很低,只要选定对应的索引和关注的指标 ,就能自动对指标曲线做学习建模;实现通过监控指标数据,智能发现异常值比如及时发现漏报情况;同时基于历史数据的全面学习我们也支持未来趋势的预测,可按时间纬度给出未来的预测曲线。

    七牛云智能日志管理平台覆盖了数据的全生命周期,适用于运维监控、安全审计及业务数据分析等场景,致力于降低用户的心智负担,帮助客户数字化升级。

    如果大家对七牛云智能日志管理平台感兴趣,可以点击阅读原文了解产品详情。现在我们有免费额度政策:新增日志数据 1 GB/月,存量日志数据 1 GB/月,日志仓库 1 个/月,API 调用次数 100 万次/月。欢迎大家注册体验。

    文档站地址:https://pandora-docs.qiniu.com

    推荐阅读

    牛人说

    「牛人说」专栏致力于技术人思想的发现,其中包括技术实践、技术干货、技术见解、成长心得,还有一切值得被发现的内容。我们希望集合最优秀的技术人,挖掘独到、犀利、具有时代感的声音。

    投稿邮箱:marketing@qiniu.com

    点击「阅读原文」免费开通

    展开全文
  • 我们认为,高吞吐量数据处理的核心限制已经从计算和存储转移到网络。Aurora 为关系数据库带来了一种新的体系结构来解决这一限制,最显著的是通过将重做处理(redo processing)推送到为Aurora 专门构建的多租户横向...

    目录

            1. 简介

            2. 规模耐久性

            3. 日志就是数据库

            4. THE LOG MARCHES FORWARD

            5. 将一切整合

            6. 性能结果

            7. 吸取的教训

            8. 相关工作

            9. 结论


    Amazon Aurora高吞吐量云原生关系数据库的设计考虑

    摘要亚马逊 Aurora 是一种关系数据库服务,用于作为亚马逊网络服务AWS的一部分提供的 OLTP 工作负载。在本文中,我们描述了 Aurora 的架构和导致该架构的设计考虑。我们认为,高吞吐量数据处理的核心限制已经从计算和存储转移到网络。Aurora 为关系数据库带来了一种新的体系结构来解决这一限制,最显著的是通过将重做处理(redo processing)推送到为 Aurora 专门构建的多租户横向扩展(multi-tenant scale-out)存储服务。我们描述了这样做不仅可以减少网络流量,还可以实现快速故障恢复、故障转移到副本而不丢失数据,以及容错、自修复存储。然后,我们描述了 Aurora 如何使用高效的异步方案在多个存储节点之间就持久状态达成共识,从而避免昂贵的恢复协议。最后,在将 Aurora 作为生产服务运营了18个月之后,我们分享了从客户那里学到的关于现代云应用对其数据库层的期望的经验。

    关键词数据库;分布式系统;日志处理;法定人数模型;复制;恢复;性能;OLTP

     

     

    1. 简介

    信息技术工作负载越来越多地转向公共云提供商。这种全行业范围的转型的重要原因包括能够在灵活的按需基础上提供容量,并使用运营费用而不是资本费用模型来支付容量。许多信息技术工作负载需要一个关系型 OLTP 数据库;为内部数据库提供同等或更高的功能对于支持这种长期过渡至关重要。

    在现代分布式云服务中,通过将计算从存储中分离出来,并通过在多个节点上复制存储,弹性和可扩展性日益增强。这样做可以让我们处理一些操作,例如替换行为不良或无法访问的主机、添加副本、从写入程序故障切换到副本、向上或向下扩展数据库实例的大小等。

    传统数据库系统面临的输入/输出瓶颈在这种环境下发生了变化。由于输入/输出可以分布在多租户群中的许多节点和许多磁盘上,因此单个磁盘和节点不再是热点。相反,瓶颈转移到请求输入/输出的数据库层和执行这些输入/输出的存储层之间的网络上。除了每秒数据包PPS和带宽的基本瓶颈之外,还有流量的放大,因为高性能数据库会并行向存储机群发出写操作。异常存储节点、磁盘或网络路径的性能会影响响应时间。

    虽然数据库中的大多数操作可能会相互重叠,但有几种情况需要同步操作。这会导致停顿和上下文切换。一种这样的情况是由于数据库缓冲区缓存中的缺失而导致的磁盘读取。读取线程在读取完成之前无法继续。缓存未命中还可能导致置换和刷新脏缓存页面以容纳新页面的额外代价。后台处理如检查点和脏页写入可以减少这种损失的发生,但也会导致停顿、上下文切换和资源争用。

    事务提交是另一个干扰来源;提交一个事务时的停顿会阻止其他事务的进行。在云级分布式系统中,使用多阶段同步协议阶段提交2PC处理提交是一项挑战。这些协议不能容忍故障,并且大规模分布式系统有连续的硬故障和软故障的 "背景噪声"。它们也是高延迟的,因为大规模系统分布在多个数据中心。

    在本文中,我们描述了亚马逊 Aurora ,这是一种新的数据库服务,通过在高度分布式的云环境中更积极地利用重做日志来解决上述问题。我们使用一种新颖的面向服务的体系结构见图1,该体系结构带有一个多租户横向扩展存储服务,该服务抽象出一个虚拟化的分段重做日志,并松散地耦合到一组数据库实例。虽然每个实例仍然包括传统内核的大部分组件查询处理器、事务、锁定、缓冲区缓存、访问方法和撤消管理,但是几个功能重做日志记录、持久存储、崩溃恢复和备份/恢复下放(off-loaded)到存储服务中。

    与传统方法相比,我们的体系结构有三大优势。首先,通过将存储构建为跨多个数据中心的独立容错和自我修复服务,我们可以保护数据库免受网络或存储层的性能差异以及暂时或永久故障的影响。我们观察到,持久性的失败可以被建模为长期的可用性事件,可用性事件可以被建模为长期的性能变化——一个设计良好的系统可以统一处理这些问题。其次,通过仅将重做日志记录写入存储,我们能够将网络 IOPS 减少一个数量级。一旦我们消除了这个瓶颈,我们就能够积极地优化许多其他的争用点,在我们开始的 MySQL 代码基础上获得了显著的吞吐量改进。第三,我们将一些最复杂和最关键的功能备份和重做恢复从数据库引擎中的一次性昂贵操作转移到在大型分布式机群中摊销的连续异步操作。这产生了没有检查点的近乎即时的崩溃恢复,以及不干扰前台处理的廉价备份。在本文中,我们描述了三个贡献:

    (1) 如何推断云规模的持久性,以及如何设计能够应对相关故障的法定系统。 2 

    (2) 如何通过将传统数据库的较低部分转移到这一层来利用智能存储。 3 

    (3) 如何消除分布式存储中的多阶段同步、崩溃恢复和检查点 4 

    然后,我们在第 5 节展示了如何将这三个想法结合起来设计 Aurora 的整体架构,然后在第 6 节回顾了我们的性能结果,并在第  7  节总结了我们的经验教训。最后,我们在第 8 节简要介绍了相关工作,并在第 9 节给出了结论。

     

     

    2. 规模耐久性

    如果数据库系统不做其他事情,它必须满足数据一旦被写入就可以被读取的约。不是所有系统都这样。在本节中,我们将讨论我们的法定模型背后的基本原理、我们对存储进行细分的原因,以及这两者如何结合起来,不仅提供耐用性、可用性和减少抖动,还帮助我们解决大规模管理存储集群的运营问题。

     

    2.1 复制和相关故障

    实例生存期与存储生存期不太相关(Instance lifetime does not correlate well with storage lifetime)。实例失败。客户关闭了它们。他们根据负载上下调整它们的大小。出于这些原因,它有助于将存储层与计算层分离。一旦这样做,这些存储节点和磁盘也不能避免出现故障。因此,必须以某种形式复制它们,以提供故障恢复能力。在大规模云环境中,存在节点、磁盘和网络路径故障。每个故障可能有不同的持续时间和不同的影响范围。例如,一个节点可能会暂时缺乏网络可用性,重新启动时会暂时停机,或者磁盘、节点、机架、叶或主干网络交换机甚至数据中心会永久出现故障。

    在复制系统中容忍故障的一种方法是使用基于法定人数的投票协议(quorum-based voting protocol)。如果复制数据项的每一个 V 副本都被分配了一个投票,则读或写操作必须分别获得 Vr 投票的读法定人数或 Vw 投票的写法定人数。为了实现一致性,法定人数必须遵守两个规则。首先,每次读取必须知道最近的写入,公式为 Vr + Vw > V。此规则确保用于读取的节点集与用于写入的节点集相交,并且读取仲裁包含至少一个具有最新版本的位置。其次,每次写操作必须知道最近的写操作,以避免写冲突操作,公式为 Vw > V/2。容忍单个节点丢失的常见方法是将数据复制到(V = 3个节点,并依赖 2/3 Vw = 2的写入法定人数和 2/3 Vr = 2的读取法定人数。

    我们认为 2/3 的法定人数是不够的。为了说明为什么,让我们首先解释 AWS 可用性区域(Availability Zone,AZ)的概念。接入点是一个区域的子集,它通过低延迟链路连接到该区域的其他接入点,但针对大多数故障包括电源、网络、软件部署、泛洪等进行隔离。跨 AZs 分布数据副本可确保典型的大规模故障模式仅影响一个数据副本。这意味着人们可以简单地将三个副本中的每一个放在不同的 AZ 中,并且除了较小的单个故障之外,还可以容忍大规模事件。

    然而,在大型存储设备群中,故障意味着,在任何给定的时刻,磁盘或节点的某个子集可能已经发生故障,并且正在被修复。这些故障可能独立地分布在 AZ A、B  C 中的每个节点上。但是,由于火灾、屋顶故障、洪水等原因,AZ C 的故障将破坏 AZ A  AZ B 中同时发生故障的任何副本的法定人数。此时,在 2/3 读取法定人数模型中,我们将丢失两个副本,并且无法确定第三个副本是否是最新的。换句话说,虽然每个 AZ 中副本的单个故障是不相关的,但 AZ 的故障是该 AZ 中所有磁盘和节点的相关故障。Quorums 需要容忍 AZ 故障以及同时发生的故障。

     Aurora,我们选择了一个设计点,该设计点允许 (a) 丢失一个完整的 AZ 和一个额外的节点AZ+1而不丢失数据,以及 (b) 丢失一个完整的 AZ 而不影响写入数据的能力。我们通过在 3  AZ 中以 6 次复制每个数据项来实现这一点,每个 AZ 中每个数据项有 2 个副本。我们使用的法定人数模型是 6 V = 6,写法定人数是 4/6 Vw = 4,读法定人数是 3/6 Vr = 3利用这样的模型,我们可以 (a) 丢失单个 AZ 和一个额外的节点3 个节点的故障而不丢失读可用性,以及 (b) 丢失任何两个节点,包括单个 AZ 故障并保持写可用性。确保读取仲裁使我们能够通过添加额外的复制副本来重建写入仲裁。

     

     

    2.2 分段存储(Segmented Storage)

    我们来考虑一下 AZ+1 是否提供了足够的耐久性这个问题。为了在该模型中提供足够的耐用性,必须确保在修复其中一个故障(Mean Time to Repair,MTTR)所需的时间内,不相关故障的双故障概率(Mean Time to Failure,MTTF)足够低。如果双重故障的概率足够高,我们可能会在 AZ 故障上看到这些,从而打破法定人数。超越一个点,很难降低 MTTF 独立失败的概率。相反,我们专注于减少 MTTR,以缩小双重失误的脆弱性。为此,我们将数据库卷划分为固定大小的小段,目前大小为 10GB。这些数据以 6 复制到保护组Protection GroupsPGs中,因此每个保护组由 6  10GB 的数据段组成,跨三个保护组组织,每个保护组中有两个数据段。存储卷(storage volume)是一组串联的 PGs,使用大量存储节点进行物理实施,这些存储节点使用亚马逊弹性计算云EC2作为虚拟主机进行配置,并连接固态硬盘。构成卷的 PGs 是随着卷的增长而分配的。我们目前支持在未复制的基础上增长到 64TB 的卷。

    分段(Segments)现在是我们独立的故障和修复单元。作为我们服务的一部分,我们监控并自动修复故障。在 10Gbps 网络链路上,10GB 的段可以在 10 秒内修复。我们需要在相同的 10 秒窗口中看到两个这样的故障,再加上一个不包含这两个独立故障中的任何一个的 AZ 故障,以失去法定人数。以我们观察到的失败率来看,这是完全不可能的,即使对于我们为客户管理的大量数据库来说也是如此。

     

     

    2.3 弹性的运营优势

    一旦一个人设计了一个对长期失败有天然弹性的系统,它自然也会对短期失败有弹性。能够处理 AZ 长期丢失的存储系统也可以处理因电源事件或需要回滚的坏软件部署而导致的短暂停机。一个可以处理仲裁成员的多秒可用性损失的节点可以处理存储节点上短暂的网络拥塞或负载(One that can handle a multisecond loss of availability of a member of a quorum can hand)

    由于我们的系统对故障有很高的容忍度,因此我们可以利用这一点来进行维护操作,以免造成数据段不可用。例如,数据管理heat management很简单。我们可以将热磁盘或节点上的某个段标记为坏段,通过迁移到机群中其他较冷的节点,可以快速修复仲裁。操作系统和安全修补(OS and security patching)是正在修补的存储节点的短暂不可用事件。甚至我们存储设备的软件升级也是这样管理的。我们一次执行一个 AZ,并确保一个 PG 中不超过一个成员同时被修补。这使我们能够在存储服务中使用灵活的方法和快速部署。

     

     

    3. 日志就是数据库

    在本节中,我们将解释为什么在第 2 节中描述的分段复制存储系统上使用传统数据库会在网络 IOs 和同步停顿方面带来难以承受的性能负担。然后,我们解释了我们将日志处理下放到存储服务的方法,并通过实验演示了我们的方法如何显著减少网络 IOs。最后,我们描述了我们在存储服务中使用的各种技术,以最大限度地减少同步停顿和不必要的写入。

     

    3.1 放大写的负担(The Burden of Amplified Writes)

    我们对存储卷进行分段并以 4/6 写入法定量以 6 复制每个分段的模型为我们提供了高弹性。不幸的是,对于 MySQL 这样的传统数据库来说,这种模型导致了难以维持的性能,因为 MySQL 为每个应用程序编写生成许多不同的实际 I/O。高 I/O 卷被复制放大,造成每秒数据包数(packets per secondPPS)沉重的负担。此外,输入/输出操作系统会导致同步点,从而导致流水线停滞和延迟扩大。尽管链复制(chain replication)及其替代方案可以降低网络成本,但它们仍会遭受同步停滞和附加延迟的困扰。

    让我们来看看写操作在传统数据库中是如何工作的。像 MySQL 这样的系统将数据页写入它公开的对象例如堆文件、B 树等。以及重做日志记录写入预写日志WAL。每个重做日志记录都由被修改页面的后映像前映像之间的差异组成(Each redo log record consists of the difference between the after-image and the before-image of the page that was modified)。日志记录可以应用于页面的前图像,以产生其后图像。

    实际上,还必须写入其他数据。例如,考虑一个同步镜像 MySQL (mirrored MySQL)配置,它实现了跨数据中心的高可用性,并在主备配置下运行,如图 2 所示。AZ1 中有一个活跃 MySQL 实例,在亚马逊弹性块存储EBS上有网络存储。AZ2 中还有一个备用 MySQL 实例,EBS 上也有网络存储。对主 EBS 卷的写入使用软件镜像与备用 EBS 卷同步(The writes made to the primary EBS volume are synchronized with the standby EBS volume using software mirroring)

     2 显示了引擎需要写入的各种类型的数据重做日志、归档到亚马逊简单存储服务S3以支持即时恢复的二进制(表单)日志、修改的数据页面、数据页的第二次临时写入双写)以防止页面损坏(the modified data pages, a second temporary write of the data page (double-write) to prevent torn pages)以及最后的元数据FRM文件。该图还显示了实际输入输出流的顺序,如下所示。在步骤 1  2 中,写入被发送到 EBS,EBS 又将其发送到 AZ 本地镜像,当两者都完成时,接收到确认。接下来,在步骤 3 中,使用同步数据块级软件镜像将写入转移到备用实例。最后,在步骤 4  5 中,写操作被写入备用 EBS 卷和相关镜像。

    上面描述的镜像 MySQL 模型是不受欢迎的,这不仅是因为数据是如何写入的,也是因为写入了什么数据。首先,步骤 1、3  5 是顺序的和同步的。延迟是附加的,因为许多写入是顺序的。抖动会被放大,因为即使是异步写入,也必须等待最慢的操作,使系统任由异常值摆布。从分布式系统的角度来看,该模型可以被视为具有 4/4 写入仲裁,并且容易受到故障和异常性能的影响。其次,由 OLTP 应用程序导致的用户操作会导致许多不同类型的写入,这些写入通常以多种方式表示相同的信息,例如,为了防止存储基础架构中的页面损坏而写入双写缓冲区(the writes to the double write buffer in order to prevent torn pages in the storage infrastructure)

     

     

    3.2  Redo 处理下放到存储

    当传统数据库修改数据页时,它会生成重做日志记录,并调用日志应用程序,将重做日志记录应用到页面的内存前映像,以生成其后映像。事务提交要求写入日志,但数据页写入可能会被推迟。

     Aurora 中,唯一跨越网络的写入是重做日志记录。从未页面从数据库层写入,不用于后台写入,不用于检查点,也不用于缓存回收。相反,日志应用程序被推送到存储层,在那里它可以用于在后台或按需生成数据库页面。当然,从一开始就从完整的修改链中生成每个页面是非常昂贵的。因此,我们不断在后台物化数据库页面,以避免每次按需从头开始重新生成它们。请注意,从正确性的角度来看,后台物化完全是可选的就引擎而言,日志是数据库,存储系统物化的任何页面都只是日志应用程序的缓存。还要注意,与检查点不同,只有具有长串修改的页面才需要重新具体化。检查点由整个重做日志链的长度决定。Aurora 页面具体化是由给定页面的链长度决定的。

    我们的方法显著降低了网络负载,尽管增加了复制写入,并提供了性能和耐用性。存储服务可以以令人尴尬的并行方式扩展输入/输出,而不会影响数据库引擎的写吞吐量(The storage service can scale out I/Os in an embarrassingly parallel fashion without impacting write throughput of the database engine)。例如,图 3 显示了一个 Aurora 集群,其中一个主实例和多个副本实例跨多个 AZ 部署。在此模型中,主服务器仅将日志记录写入存储服务,并将这些日志记录以及元数据更新流式传输到复制副本实例。输入输出流根据一个公共目标一个逻辑段,即一个 PG对日志记录进行完全排序,并将每一批传送到所有 6 个副本,其中该批保存在磁盘上,数据库引擎等待 6 个副本中的 4 个的确认,以满足写仲裁,并认为有问题的日志记录是持久的或加固的。副本使用重做日志记录将更改应用到它们的buffer caches(The replicas use the redo log records to apply changes to their buffer caches)

    为了测量网络输入/输出,我们使用 SysBench 只写工作负载运行了一个测试,其中包含上述两种配置的 100GB 数据集一个是跨多个 AZ 的同步镜像 MySQL 配置,另一个是 RDS Aurora(replicas across multiple AZs,跨多个 AZ 的副本。在这两个实例中,测试针对运行在 r3.8xlarge EC2 实例上的数据库引擎运行了 30 分钟。

    我们实验的结果总结在表 1 中。在 30 分钟的时间里,Aurora 能够维持比镜像 MySQL多 35 倍的事务。尽管使用 Aurora 将写入放大了 6 倍,并且不包括 EBS 中的链式复制和 MySQL 中的跨 AZ 写入,但 Aurora 中数据库节点上每个事务的 I/O 数量比镜像 MySQL 中的少 7.7 倍。每个存储节点都可以看到未复制的写入,因为它只是六个拷贝中的一个,导致该层需要处理的输入/输出减少了 46 倍。通过向网络写入更少的数据,我们节省了成本,这使我们能够积极复制数据以提高耐用性和可用性,同时,并行发出请求以最大限度地减少抖动的影响。

    将处理转移到存储服务还可以通过最大限度地减少崩溃恢复时间来提高可用性,并消除后台进程如检查点、后台数据页面写入和备份引起的抖动。

    检查崩溃恢复。在传统数据库中,崩溃后,系统必须从最近的检查点开始,并重放日志,以确保所有持久的重做记录都已应用。在 Aurora 中,持久重做记录应用程序在存储层连续、异步地发生,并分布在整个车队中。如果数据页不是最新的,对该页的任何读请求可能需要应用一些重做记录。因此,崩溃恢复的过程分散在所有正常的前台处理中。数据库启动时不需要任何东西。

     

     

    3.3 存储服务设计要点

    我们存储服务的核心设计宗旨是最大限度地减少前台写请求的延迟。我们将大部分存储处理转移到后台。鉴于存储层的峰值和平均前台请求之间的自然可变性,我们有足够的时间在前台路径之外执行这些任务(we have ample time to perform these tasks outside the foreground path)。我们也有机会用 CPU 换磁盘。例如,当存储节点忙于处理前台写请求时,没有必要运行旧页面版本的垃圾回收,除非磁盘接近容量。 Aurora 中,后台处理前台处理负相关。这不同于传统数据库,在传统数据库中,页面的后台写入和检查点与系统的前台负载呈正相关。如果我们在系统上建立了一个 backlog,我们将抑制前台活动,以防止长队列的建立。由于数据段以高熵分布在系统中的各个存储节点上,一个存储节点上的节流很容易由我们的 4/6 仲裁写入处理,所以表现为一个慢速节点。

    让我们更详细地回顾一下存储节点上的各种活动。如图 4 所示,它包括以下步骤(1) 接收日志记录并添加到内存队列中,(2) 将记录保存在磁盘上并进行确认,(3) 组织记录并识别日志中的空白,因为一些批次可能会丢失,(4) 与对等方利用 gossip 以填补空(5) 将日志记录合并到新的数据页面中,(6) 定期将日志和新页面转移到 S3,(7) 定期垃圾回收旧版本,最后 (8) 定期验证页面上的循环冗余校验代码。

    请注意,不仅上述每个步骤是异步的,而且只有步骤 (1)  (2) 在前台路径中,这可能会影响延迟。

     

     

    4. THE LOG MARCHES FORWARD

    在本节中,我们将描述如何从数据库引擎生成日志,以便持久状态、运行时状态和副本状态始终保持一致。特别是,我们将描述如何在没有昂贵的 2PC 协议的情况下高效地实现一致性。首先,我们展示了如何在崩溃恢复时避免昂贵的重做处理。接下来,我们解释正常操作以及如何维护运行时和副本状态。最后,我们提供恢复过程的详细信息。

     

    4.1 解决方案梗概:异步处理

    因为我们将数据库建模为重做日志流如第 3 节所述,所以我们可以利用日志作为有序的变更序列进的事实。实际上,每个日志记录都有一个关联的日志序列号(Log Sequence Number,LSN,它是由数据库生成的单调递增的值。

    这让我们通过以异步方式处理问题来简化维护状态的一致协议,而不是使用像 2PC 这样喋喋不休、不能容忍故障(chatty and intolerant)的协议。在高层次上,我们保持一致性和持久性,并在收到未完成存储请求的确认时不断提高这些点。由于任何单个存储节点可能会丢失一个或多个日志记录,因此它们会与 PG 的其他成员 gossip,寻找差距并填补漏洞。由数据库维护的运行时状态允许我们使用单个段读取,而不是仲裁读取,除非在状态丢失且必须重建时进行恢复。

    数据库可能有多个未完成的独立事务,这些事务可以以不同于启动的顺序完成达到已完成和持久的状态。假设数据库崩溃或重新启动,是否回滚的决定对于每个事务都是独立的。跟踪部分完成的事务撤销它们的这一逻辑保存在数据库引擎中,就像它正在向简单磁盘写入一样(The logic for tracking partially completed transactions and undoing them is kept in the database engine, just as if it were writing to simple disks)。但是,在重新启动时,在允许数据库访问存储卷之前,存储服务会进行自己的恢复,恢复的重点不是用户级事务,而是确保数据库看到统一的存储视图,尽管它是分布式的。

    存储服务确定最高 LSN,这样它可以保证所有先前日志记录可用性这称为 VCL  Volume Complete LSN。在存储恢复期间,LSN 大于 VCL 的每个日志记录都必须被截断。然而,数据库可以进一步约束点的子集,这可以通过标记日志记录来截断,并将它们标识为 CPLs 或一致性点 LSNs(The database can, however, further constrain a subset of points that are allowable for truncation by tagging log records and identifying them as CPLs or Consistency Point LSNs)。因此,我们将 VDL (耐用 LSN ,Volume Durable LSN)定义为最高 CPL,它小于或等于 VCL,并截断所有 LSN 大于 VDL 的日志记录。例如,即使我们有 LSN 1007 之前的完整数据,数据库也可能已经声明只有 900、1000  1100  CPLs,在这种情况下,我们必须在 1000 截断。我们完成到 1007,但只耐用到 1000(We are complete to 1007, but only durable to 1000)

    因此,完整性和持久性是不同的,并且可以认为一个 CPL 描述了某种必须有序接受的存储系统事务的有限形式。如果客户端不需要这种区分,它可以简单地将每个日志记录标记为一个公共对象。实际上,数据库和存储的交互方式如下

    (1) 每个数据库级事务被分解成多个有序的、必须原子执行的小型事务。

    (2) 每个小型事务由多个连续的日志记录组成需要多少就有多少

    (3) 小型事务中的最终日志记录是一个 CPL。

    在恢复时,数据库与存储服务对话以建立每个 PG 的持久点,并使用该持久点来建立 VDL,然后发出命令来截断 VDL 上的日志记录。

     

     

    4.2 正常运行

    我们现在描述数据库引擎的 "正常操作",并依次关注写、读、提交和副本。

    4.2.1 写入

    在Aurora中,数据库不断与存储服务交互,并保持状态以建立仲裁、提高卷持久性,并将事务注册为已提交。例如,在正常/转发路径中,当数据库收到确认以建立每批日志记录的写入仲裁时,它会推进当前的 VDL。在任何给定时刻,数据库中可能有大量并发事务处于活动状态,每个事务都生成自己的重做日志记录。数据库为每个日志记录分配一个唯一的有序 LSN,但有一个限制条件,即分配给 LSN 的值不能大于当前 VDL 值和一个称为 LSN 分配限制(LSN Allocation Limit,LAL的常数之和当前设置为 1000 。此限制可确保数据库不会远远领先于存储系统,并在存储或网络跟不上的情况下引入 back-pressure,从而抑制传入的写入。

    请注意,每个 PG 的每个段只看到卷中影响驻留在该段上的页面的日志记录的子集。每个日志记录都包含一个反向链接,用于标识该 PG 的前一个日志记录。这些反向链接可用于跟踪到达每个段的日志记录的完整点,以建立段完整 LSN(Segment Complete LSN,SCL),该 LSN 标识接收到 PG 的所有日志记录的最大 LSN。存储节点在相互 gossip 时会使用 SCL,以便找到并交换丢失的日志记录。

     

    4.2.2 提交

     Aurora 中,事务提交是异步完成的。当客户端提交事务时,处理提交请求的线程通过将其 "提交 LSN" 记录为等待提交的单独事务列表的一部分来搁置事务,并继续执行其他工作。等价的 WAL 协议是基于完成一个提交,当且仅当,最新的 VDL 大于或等于事务的提交 LSN(The equivalent to the WAL protocol is based on completing a commit, if and only if, the latest VDL is greater than or equal to the transaction’s commit LSN)。随着 VDL 进程的推进,数据库识别出符合条件的等待提交的事务,并使用专用线程向等待的客户端发送提交确认。工作线程不会暂停提交,它们只是拉取其他挂起的请求并继续处理。

     

    4.2.3 Reads

     Aurora 中,与大多数数据库一样,页面是从缓冲区缓存(buffer cache)中提供的,只有当缓存中不存在有问题的页面时,才会产生存储输入输出请求。

    如果缓冲区缓存已满,系统会找到一个要从缓存中替换的页面。在传统系统中,如果被替换的页面是一个 "脏页",那么在替换它之前会被刷新到磁盘。这是为了确保页面的后续提取总是最新的数据。虽然 Aurora 数据库在替换页面或在任何其他地方不会写出页面,但它会强制执行类似的保证缓冲区缓存中的页面必须始终是最新版本。只有当页面的 "页面 LSN"(标识与页面的最新更改相关联的日志记录大于或等于 VDL 时,才会通过从缓存中逐出页面来实现该保证。该协议确保(a) 页面中的所有更改都已在日志中得到强化,以及 (b) 缓存未命中时,请求当前 VDL 的页面版本以获得其最新的持久版本就足够了。

    在正常情况下,数据库不需要使用读取法定人数来建立共识。从磁盘读取页面时,数据库会建立一个读取点,代表发出请求时的 VDL。然后,数据库可以选择相对于读取点(read-point)完整的存储节点,知道它将因此接收最新版本。存储节点返回的页面必须与数据库中小型事务的预期语义一致(A page that is returned by the storage node must be consistent with the expected semantics of a mini-transaction (MTR) in the database)。由于数据库直接管理向存储节点输送日志记录和跟踪进度即每个段的 SCL,所以它通常知道哪个段能够满足读取SCL 大于读取点的段,因此可以直接向具有足够数据的段发出读取请求。

    假设数据库知道所有未完成的读取,它可以在任何时候基于每 PG 计算最小读取点 LSN。如果存在读取副本,写使用 gossip 协议,以在所有节点上建立每点最小读取点 LSN(If there are read replicas the writer gossips with them to establish the per-PG Minimum Read Point LSN across all nodes)该值称为保护组最小读取点 LSN PGMRPL,代表 "低水位线",低于该值时,保护组的所有日志记录都是不必要的(This value is called the Protection Group Min Read Point LSN (PGMRPL) and represents the "low water mark" below which all the log records of the PG are unnecessary)换句话说,存储节点段保证不会有读取点低于 PGMRPL 的读取页面请求。每个存储节点都知道数据库中的 PGMRPL,因此可以通过合并旧的日志记录并安全地垃圾回收它们来推进磁盘上的物化页面。

    实际的并发控制协议是在数据库引擎中执行的,就像传统的 MySQL 一样,数据库页面和撤消段是在本地存储中组织的。

     

    4.2.4 副本

     Aurora 中,单个写者和多达 15 个读取副本都可以装载一个共享存储卷。因此,读取副本不会增加存储消耗或磁盘写入操作的额外成本。为了最大限度地减少延迟,由写入程序生成并发送到存储节点的日志流也会发送到所有读取的副本。在读者中,数据库通过依次考虑每个日志记录来消耗这个日志流。如果日志记录引用了读者缓冲区缓存中的页面,它将使用日志应用程序对缓存中的页面应用指定的重做操作。否则,它只会丢弃日志记录。请注意,从写者的角度来看,副本异步使用日志记录,这表明用户提交独立于副本。复制副本在应用日志记录时遵循以下两个重要规则(a) 将应用的唯一日志记录是 LSN 小于或等于 VDL 的日志记录,以及 (b) 作为单个小型事务一部分的日志记录被自动应用到复制副本的缓存中,以确保复制副本看到所有数据库对象的一致视图。实际上,每个副本通常比写者落后一小段时间 20 毫秒或更短

     

     

    4.3 恢复

    大多数传统数据库使用诸如 ARIES 之类的恢复协议,该协议依赖于可以表示所有提交事务的精确内容的预写日志(write-ahead log,WAL的存在。这些系统还定期检查数据库,通过将脏页刷新到磁盘并将检查点记录写入日志,以粗粒度的方式建立持久性点。重新启动时,任何给定的页面都可能会丢失一些已提交的数据或包含未提交的数据。因此,在崩溃恢复时,系统通过使用日志应用程序将每个日志记录应用到相关的数据库页面来处理自上一个检查点以来的重做日志记录。这个过程使数据库页面在故障点达到一致的状态,之后可以通过执行相关的撤消日志记录来回滚崩溃期间正在进行的事务。崩溃恢复可能是一项昂贵的操作。减少检查点间隔有所帮助,但代价是干扰前台事务。Aurora 不需要这样的权衡。

    传统数据库的一个非常简单的原则是,在正向处理路径和恢复中使用相同的重做日志应用程序,当数据库脱机时,它在前台同步操作。我们在 Aurora 中也依赖于相同的原则,除了重做日志应用程序从数据库中分离出来,并在存储节点上并行运行,并且一直在后台运行。一旦数据库启动,它就会与存储服务协作执行卷恢复,因此,即使 Aurora 数据库在每秒处理超过 100,000 条写语句时崩溃,它也可以非常快地恢复通常不到 10 

    崩溃后,数据库确实需要重新建立其运行时状态。在这种情况下,它为每个 PG 联系一个段的读取法定人数,该法定人数足以保证发现任何可能已经达到写入法定人数的数据。一旦数据库为每个 PG 建立了一个读定额,它就可以重新计算 VDL,在这个 VDL 之上的数据将被截断,生成一个截断范围,该范围将使新 VDL 之后的每个日志记录失效,直到并包括一个终端 LSN,数据库可以证明它至少是有史以来最高的未完成日志记录的最高值。数据库推断这个上限是因为它分配了 LSNs,并限制了分配在 VDL 以上的距离前面描述的 1000 万的限制。截断范围用 epoch 号进行版本控制,并持久地写入存储服务,以便在恢复中断和重新启动的情况下不会混淆截断的持久性。

    数据库仍然需要执行撤消恢复,以便在崩溃时解除运行中事务的操作。但是,在系统根据撤消段(undo segments)建立这些正在进行的事务的列表之后,当数据库联机时,撤消恢复可能会发生。

     

     

    5. 一切整合

    在本节中,我们将描述 Aurora 的构建模块,如图 5 中的鸟瞰图所示。

    数据库引擎是 MySQL/InnoDB "社区" 的一个分支,主要在 InnoDB 如何读写磁盘数据方面有所不同。在社区 InnoDB 中,写操作导致数据在缓冲区页面中被修改,相关的重做日志记录按 LSN 顺序写入 WAL 的缓冲区。在事务提交时,WAL 协议只要求事务的重做日志记录持久地写入磁盘。实际修改后的缓冲区页面最终也会通过双写技术写入磁盘,以避免部分页面写入。这些页面写入在后台进行,或者在从缓存中替换的过程中进行,或者在执行检查点时进行。除了输入输出子系统,InnoDB 还包括事务子系统、锁管理器、B+ 树实现和相关的 "小型事务" 概念。中期审查是仅在 InnoDB 内部使用的构造,它对必须以原子方式执行的操作组进行建模例如,B+树页面的拆分/合并

     Aurora InnoDB 变体中,表示必须在每个 MTR 中自动执行的更改的重做日志记录被组织成由每个日志记录所属的 PGs 分片的批数据,并且这些批数据被写入存储服务。每个中期审查的最终日志记录被标记为一致性点。Aurora 支持与社区 MySQL 写者中支持的完全相同的隔离级别标准 ANSI 级别和快照隔离或一致读取。Aurora 读取副本在写入程序中获取有关事务启动和提交的连续信息,并使用这些信息来支持本地事务的快照隔离,这些事务当然是只读的。请注意,并发控制完全是在数据库引擎中实现的,不会影响存储服务。存储服务提供了底层数据的统一视图,该视图在逻辑上与将数据写入社区 InnoDB 中的本地存储所获得的视图相同。

    Aurora 利用亚马逊关系数据库服务作为其控制平面。RDS(Relational Database Service)在数据库实例上包括一个称为主机管理器(Host Manager,HM的代理,它监控集群的运行状况,并确定集群是否需要故障转移,或者是否需要替换实例。每个数据库实例都是一个集群的一部分,该集群由一个写者和零个或多个读组成。集群的实例位于单个地理区域中例如,us-east-1、us-west-1等,通常放置在不同的自动仓库中,并连接到同一地区的存储集群。为了安全起见,我们隔离了数据库、应用程序和存储之间的通信。实际上,每个数据库实例都可以在三个亚马逊虚拟私有云VPC网络上进行通信客户应用程序通过其与引擎交互的客户 VPC、数据库引擎和控制平面通过其相互交互的 RDS VPC 以及数据库通过其与存储服务交互的存储 VPC。

    存储服务部署在 EC2 虚拟机群集上,这些虚拟机在每个区域至少有 3 个自动存储区进行资源调配,并共同负责资源调配多个客户存储卷,在这些卷之间读写数据,以及在这些卷之间备份和恢复数据。存储节点操作本地固态硬盘,并与数据库引擎实例、其他对等存储节点和备份/恢复服务交互,这些服务可根据需要将更改的数据连续备份到 S3,并从 S3 恢复数据。存储控制平面使用亚马逊动态数据库服务来持久存储集群和存储卷配置、卷元数据以及备份到 S3 的数据的详细描述。对于编排长期运行的操作,例如存储节点故障后的数据库卷恢复操作或修复重新复制操作,存储控制平面使用亚马逊简单工作流服务。保持高水平的可用性要求在最终用户受到影响之前,对真实和潜在的问题进行主动的、自动化的早期检测。使用指标收集服务不断监控存储操作的所有关键方面,如果关键性能或可用性指标表明存在问题,就会发出警报。

     

     

    6. 性能结果

    在本节中,我们将分享我们在将 Aurora 作为生产服务运行方面的经验,该服务于 2015年 7 月推出。我们首先总结运行行业标准基准测试的结果,然后展示我们客户的一些性能结果。

     

    6.1 标准基准的结果

    在这里,我们展示了不同实验的结果,这些实验使用行业标准基准 SysBench  TPC-C 变体比较了 Aurora  MySQL 的性能。我们在连接到具有 30K 预配 IOPS  EBS 卷的实例上运行 MySQL。除非另有说明,这些都是 r3.8X 大型 EC2 实例,具有 32 个vCPU和 244GB 内存,采用 Intel Xeon E5-2670 v2(Ivy Bridge)处理器。r3.8XL 上的缓冲缓存设置为 170GB。

     

    6.1.1 根据实例大小进行扩展

    在这个实验中,我们报告了 Aurora 中的吞吐量可以随着实例大小线性扩展,最高实例大小可以是 MySQL 5.6  MySQL 5.7  5 倍。请注意,Aurora 目前基于 MySQL 5.6 代码库。我们在 r3 系列的 5  EC2 实例large、xlarge、2xlarge、4xlarge、8xlarge上运行了 1GB 数据集250 个表 SysBench 只读和只写基准测试。每个实例的大小正好是紧随其后的较大实例 vCPUs 和内存的一半。

    结果如图 7 和图 6 所示,分别用每秒写和读语句来衡量性能。Aurora 的性能在每个更高的实例大小下加倍,对于 r3.8xlarge,达到 121,000 次写入/秒和 600,000 次读取/秒,是 MySQL 5.7  5 倍,MySQL 5.7 的最高读取/秒和 125,000 次写入/秒。

     

    6.1.2 不同数据大小的吞吐量

    在这个实验中,我们报告说,Aurora 的吞吐量明显超过 MySQL,即使有更大的数据大小,包括具有缓存外工作集的工作负载。表 2 显示,对于 SysBench 只写工作负载,Aurora  MySQL  67 倍,数据库大小为 100GB。即使对于 1TB 的数据库大小和缓存外的工作负载,Aurora 仍然比 MySQL  34 倍。

     

    6.1.3 通过用户连接进行扩展

    在这个实验中,我们报告了 Aurora 中的吞吐量可以随着客户端连接的数量而扩展。表 3 显示了当连接数从 50 增长到 500 再增长到 5000 时,以每秒写入数计算的 SysBench OLTP 基准测试的运行结果。虽然 Aurora 从每秒 40,000 次写入扩展到每秒 110,000 次写入,但 MySQL 的吞吐量在大约 500 个连接时达到峰值,然后随着连接数量增长到 5000 个而急剧下降。

     

    6.1.4 使用副本扩展

    在这个实验中,我们报告说 Aurora 读取副本的延迟明显低于 MySQL 副本,即使工作负载更高。表 4 显示,随着工作负载在每秒 1000  10000 次写入之间变化,Aurora 中的复制延迟从 2.62 毫秒增加到 5.38 毫秒。相比之下,MySQL 中的副本延迟从不到一秒钟增长到 300 秒钟。在每秒 10,000 次写入时,Aurora 的复制延迟比 MySQL 小几个数量级。副本延迟是根据提交的事务在副本中可见所需的时间来衡量的。

     

    6.1.5 热行争用时的吞吐量

    在这个实验中,我们报告说,相对于 MySQL,Aurora 在具有热行争用(hot row contention)工作负载上表现非常好,例如基于 TPC-C 基准的工作负载。我们针对亚马逊 Aurora  MySQL 5.6  5.7 运行了Percona TPC-C变体,在 3.8xlarge 上, MySQL 使用了一个配备了 30K  EBS 卷。表 5 显示,Aurora 的吞吐量是 MySQL 5.7  2.3  16.3 倍,因为工作负载从 500 个连接和 10GB 的数据大小到 5000 个连接和 100GB 的数据大小不等。

     

     

    6.2 真实客户工作负载的结果

    在本节中,我们将分享一些客户报告的结果,这些客户将生产工作负载从 MySQL 迁移到 Aurora

     

    6.2.1 Aurora 应用响应时间

    一家互联网游戏公司将其生产服务从 MySQL 迁移到 Aurora  3.4x 大型实例上。他们的网络事务在迁移前的平均响应时间为 15 毫秒。相比之下,迁移后的平均响应时间为 5.5 毫秒,提高了 3 倍,如图 8 所示。

     

    6.2.2 Aurora 的延迟

    一家教育技术公司,其服务帮助学校管理学生笔记本电脑,将他们的生产工作负载从MySQL 迁移到 Aurora。迁移前后1400时选择和每条记录插入操作的中值P50 95% 延迟如图 9 和图 10 所示。在迁移之前,P95的延迟在 40 毫秒到 80 毫秒之间,比 P50 的大约 1 毫秒的延迟差得多。该应用程序遇到了我们在本文前面描述的那种糟糕的异常性能。然而,迁移后,两种操作的 P95 延迟显著改善,接近 P50 延迟。

     

    6.2.3 具有多个副本的副本延迟

     Pinterest  Weiner 报道,MySQL 副本通常远远落后于它们的写者,并且可能 "导致奇怪的错误"。对于前面描述的教育技术公司来说,副本延迟通常会增加到 12 分钟,影响应用程序的正确性,因此副本仅作为支持服务。相比之下,迁移到 Aurora 后,4 个副本的最大副本延迟从未超过 20 毫秒,如图 11 所示。Aurora 提供的改进的副本延迟让该公司将应用程序负载的很大一部分转移到副本上,从而节省了成本并提高了可用性。

     

     

    7. 吸取的教训

    我们现在已经看到客户运行的各种各样的应用程序,从小型互联网公司一直到运行大量 Aurora 集群的高度复杂的组织。虽然他们的许多用例都是标准的,但我们关注的是云环境中常见的场景和期望,这些场景和期望引领我们走向新的方向。

     

    7.1 多租户和数据库整合

    我们的许多客户都在运营软件即服务SaaS业务,或者独家运营,或者与一些剩余的内部客户一起运营,他们正试图转向他们的 SaaS 模式。我们发现,这些客户通常依赖于他们无法轻易更改的应用程序。因此,他们通常通过使用模式/数据库(schema/database)作为租赁单位,将不同的客户整合到一个实例上。这个习惯用法降低了成本当不可能所有的客户同时活跃时,他们避免为每个客户的专用实例付费。例如,我们的一些 SaaS 客户报告说,他们自己有超过 50,000 名客户。

    该模型与众所周知的多租户应用程序 Salesforce.com明显不同,后者使用多租户数据模型,将多个客户的数据打包到单个模式的统一表中,并按行识别租赁。因此,我们看到许多客户的统一数据库包含大量表。小型数据库中超过 150,000 个表的生产实例非常常见。这给管理元数据的组件如字典缓存带来了压力。更重要的是,此类客户需要 (a) 维持高水平的吞吐量和许多并发用户连接,(b) 一种模型,在该模型中,数据仅在使用时提供并付费,因为很难预先预测需要多少存储空间,以及 (c) 减少抖动,以便单个租户的峰值对其他租户的影响最小。Aurora 支持这些属性,非常适合 SaaS 的应用。

     

    7.2 高度并发的自动扩展工作负载

    互联网工作负载通常需要处理基于突发事件的流量峰值。我们的一个主要客户在一个非常受欢迎的全国电视节目中有一个特殊的场景出现,并经历了一个这样的高峰,大大超过了他们的正常峰值吞吐量,而没有给数据库带来压力。为了支持这种峰值,数据库处理许多并发连接是很重要的。这种方法在 Aurora 中是可行的,因为底层存储系统可扩展性很好。我们有几个客户每秒运行超过 8000 个连接。

     

    7.3 模式演变

    现代 Web 应用程序框架,如 Ruby on Rails,深入集成了对象关系映射工具。因此,应用程序开发人员很容易对他们的数据库进行许多模式更改,这使得数据库管理员很难管理模式的发展。在 Rails 应用程序中,这些被称为 "数据库迁移",我们已经听到了数据库管理员的第一手描述,他们要么必须处理 "每周几十次迁移",要么制定对冲策略以确保未来的迁移不会带来痛苦。MySQL 提供了自由的模式演化语义,并使用完整的表副本实现了大多数更改,这加剧了这种情况(The situation is exacerbated with MySQL offering liberal schema evolution semantics and implementing most changes using a full table copy)。由于频繁的 DDL 是一个实用的现实,我们已经实现了一个高效的在线 DDL 实现,它 (a) 基于每页版本化模式,并根据需要使用模式历史对单个页面进行解码,以及 (b) 使用写时修改原语modify-on-write primitive)将单个页面缓慢升级到最新的模式。

     

    7.4 可用性和软件升级

    我们的客户对云原生数据库有着苛刻的期望,这可能与我们如何运营集群以及我们修补服务器的频率相冲突。由于我们的客户主要将 Aurora 作为支持生产应用程序的 OLTP 服务,任何中断都可能造成创伤。因此,我们的许多客户对我们的数据库软件更新的容忍度非常低,即使这相当于每 6 周左右计划停机 30 秒。因此,我们最近发布了一个新的零停机补丁(Zero-Downtime Patch ,ZDP功能,允许我们在不影响运行中数据库连接的情况下为客户打补丁。

    如图 12 所示,ZDP 的工作方式是寻找一个没有活动事务的瞬间,并在那个瞬间将应用程序状态假脱机到本地临时存储,修补引擎,然后重新加载应用程序状态。在此过程中,用户会话保持活跃,并且忘记了引擎在幕后发生了变化。

     

     

    8. 相关工作

    在这一节中,我们将讨论其他的贡献,以及它们与 Aurora 所采取的方法之间的关系。

    将存储与计算分离。虽然传统系统通常被构建为庞大的守护进程,但是最近有一些关于数据库的工作,这些工作将内核分解成不同的组件。例如,Deuteronomy 就是这样一个系统,它将提供并发控制和恢复的事务组件(Transaction Component,TC与在 LLAMA 之上提供访问方法的数据组件(Data Component,DC分开,LLAMA 是一个无闩锁(latch-free)的日志结构缓存和存储管理器。Sinfonia  Hyder 是在横向扩展服务上抽象事务访问方法的系统,数据库系统可以使用这些抽象来实现。Yesqell 系统实现了多版本分布式平衡树,并将并发控制与查询处理器分开。Aurora 将存储分离到比 Deuteronomy、Hyder、Sinfonia  Yesquel 更低的级别。在 Aurora 中,查询处理、事务、并发、缓冲区缓存和访问方法与作为横向扩展服务实现的日志记录、存储和恢复是分离的。

    分布式系统。面对分区时正确性和可用性之间的权衡早已为人所知,其主要结果是在面对网络分区时单拷贝可串行化(one-copy serializability)是不可能的。最近,在有的文章中证明的 Brewer 的 CAP 定理指出,在存在网络分区的情况下,高可用性系统不能提供 "" 一致性保证。这些结果以及我们在云级别的(cloud-scale复杂和相关故障方面的经验激发了我们的一致性目标,即使存在由 AZ 故障导致的分区。

    Bailis 等人研究了提供高可用性事务(Highly Available Transactions,HATs的问题,这种事务既不会在分区期间不可用,也不会导致高网络延迟。它们表明,可序列化性、快照隔离和可重复读取隔离不兼容 HAT,而大多数其他隔离级别可通过高可用性实现。Aurora 提供了所有这些隔离级别,方法是做出一个简化的假设,即在任何时候都只有一个写者使用从单个有序域分配的 LSN 生成日志更新。

    谷歌的 Spanner 提供外部一致的读写,以及在一个时间戳上跨数据库的全局一致的读取。这些特性使 Spanner 能够支持一致的备份、一致的分布式查询处理和原子模式更新,所有这些都是在全球范围内进行的,甚至在正在进行的事务中也是如此。正如 Bailis 所解释的,Spanner 高度专用于谷歌的读重(读多写少)工作负载,并依赖于读/写事务的两阶段提交和两阶段锁定。

    并发控制。较弱的一致性PACELC和隔离模型在分布式数据库中是众所周知的,并导致了乐观的复制技术以及最终一致的系统。集中式系统中的其他方法包括基于锁定的经典悲观方案、像 Hekaton 中的多版本并发控制这样的乐观方案、像 HyPer  Deuteronomy 中的 VoltDB 和时间戳排序这样的分片方法。 Aurora 的存储服务为数据库引擎提供了持久保存的本地磁盘的抽象,并允许引擎确定隔离和并发控制。

    日志结构存储。日志结构存储系统是由 LFS  1992 年提出的。最近,Deuteronomy 和相关的 LLAMA  Bw-Tree 在存储引擎堆栈中以多种方式使用日志结构技术,并且像 Aurora 一样,通过写入增量而不是整页来减少写入放大Deuteronomy Aurora 都实现了纯粹的重做日志,并跟踪最高稳定的 LSN 来确认提交。

    恢复。虽然传统数据库依赖于基于 ARIES 的恢复协议,但最近的一些系统选择了其他性能途径。例如,Hekaton  VoltDB 在崩溃后使用某种形式的更新日志重建它们的内存状态。像 Sinfonia 这样的系统通过使用像进程对和状态机复制这样的技术来避免恢复。Graefe 描述了一种具有每页日志记录链的系统,该系统支持按需逐页重做,从而可以快速恢复。像 Aurora 一样,Deuteronomy 不需要重做恢复。这是因为 Deuteronomy 延迟了事务,因此只有提交的更新才会发布到持久存储中。因此,与 Aurora 不同,事务的规模可以在 Deuteronomy 中得到约束。

     

     

    9. 结论

    我们将 Aurora 设计为一个高吞吐量的 OLTP 数据库,它在云规模的环境中既不牺牲可用性也不牺牲持久性。最大的想法是摆脱传统数据库的单一架构,将存储与计算分离开来。特别是,我们将数据库内核的下半部分转移到一个独立的、可扩展的分布式服务中,该服务管理日志记录和存储。由于所有的输入/输出都是通过网络编写的,我们现在的基本限制是网络。因此,我们需要专注于减轻网络负担和提高吞吐量的技术。我们依靠仲裁模型来处理大规模云环境中发生的复杂和相关的故障,并避免异常性能损失,依靠日志处理来减少总的输入/输出负担,以及异步一致性来消除分布式存储中昂贵的多阶段同步协议、离线崩溃恢复和检查点。我们的方法简化了架构,降低了复杂性,易于扩展,并为未来的发展奠定了基础。

    展开全文
  • 这次是慢查询的故事,一些情况下很难避免,我们屏蔽来源,只讨论。从最开始只要简单处理能过滤报警(几百),坏个盘也就是这么。到小 Region灰度,单Client 峰值8K,再到大集群单 Client 峰值几万,程序一路翻车...

    前言

    这次是慢查询的故事,一些情况下很难避免,我们屏蔽来源,只讨论量。从最开始只要简单处理能过滤报警(几百),坏个盘也就是这么量。到小 Region灰度,单Client 峰值8K,再到大集群单 Client 峰值几万,程序一路翻车。

    对于报警而言,我们更关注各个来源每秒可以处理的量,总体意义不大,数据来源主要为双机压测结果(非Server吞吐量,且包含网络请求耗时)。

    一些环境下是不存也不方便引入其他中间件的,一个Centos7 自带的 Python 2.7.5 一路黑到底。

    项目不同阶段

    日常需求阶段(几百)

    慢查询有一定格式,我们简单抽象为 A 和 B,其中含义如下:

    A:  检测到一个查询还没结束,无法判定,因此记录到日志中

    B: 检测到一个很耗时的查询,并且已结束,记录到日志中

    因此常见组合方式为:

    • AA...AB (多次受到慢查询存在告警,最后受到结束告警)
    • B (刚好检测到一个耗时的查询,并且已结束)
    • A...A (异常情况)

    消息消费大致是B已完成,需要实时处理,A则需要抑制并判断阈值在报警,因此可以将服务分为 Server  和 Client:

    Client 读取日志,记录 Offset,过滤无效日志,发送成功则刷新 Offset,否则暂停读取,重发。

    Server则分为Master 和 Monitor,Master处理实时数据,其他的写入文件,完成就返回,剩下由有Monitor 消费,由此借助文件实现跨进程通信,以及消息实时落盘。(消息生成主键,因此重复写不影响,Monitor 读取时候直接去重即可。)

    有很多成熟文件DB,简单的操作背后都是时延增大,本文是直接读写文件。因写文件而速成,也会因文件也受限。

    多客户端冲突期

    第一版有个很大的竞争点,就是所有消息公用一个文件作为跨进程通信与落盘。因此多客户端已接入,立马互相竞争文件锁,性能瞬间只剩几十,惨不忍睹。

    提示:一个 Region 两台统计点,日志是随机打过去的,因此采用放在同一个文件进行比对。当然这是不合理的,当对同一个消息AB很短时间间隔内到达两个节点。再经过采集合并发送到报警服务器,基本无法保证有序。这个阶段已调整,单节点保序。

    按 Client 分消息队列,就是分文件了,性能又恢复了。

    小故障爆发期(几千,比如2-3千)

    这个时候就是把以前偷的懒都给补上了,当然不是每个思路都有效,比较有效的有:

    • 各类批量操作: 批量写消息、批量查数据库等
    • 更换序列化,比如由 Json 改为 Marshal
    • 优化时间格式处理, 自带的 strptime 性能很差,可以小用 panda
    • cache,集群、节点等相关属性变化很低,适合放内存

     替换实现是一个系统活,有一些测压对比统计,可以供大家参考,真正有提升在替换。

    内置

    单条序列化长度

    1K列表序列化长度

    单条1W次

    dumps

    单条1W次

    loads

    单次1K条

    dumps

    单次1K条

    loads

    json

    754

    771393

    0.1193

    0.2423

    0.0095

    0.0402

    pickle

    975

    318576

    1.8495

    1.6626

    0.1121

    0.0681

    marshal

    791

    495263

    0.0505

    0.0606

    0.0026

    0.0039

    ujson

    698

    712394

    0.0451

    0.0597

    0.0048

    0.0105

    msgpack

    629

    640259

    1.5178

    2.6460

    0.1622

    0.4593

    marshal 是不安全的,不通用的,不同版本也不兼容的。不过这速度,又是内网环境,我最终义无反顾选择了它。

    插入一个无效的优化手段,乍一看我是认为有效的。来个简单常见,就是消息记录,然后按 A、B分类,参考代码如下:

    def cls_message(handler, raws):
        """对日志分类,然后简单格式化下"""
        logger = logging.getLogger(handler)
        slow_dict = {}
        pending_dict = {}
        for message in raws:
            key = make_key(message)
            if message.get('flag') == 'Pending':
                pending_dict[key] = formatter(message)
                logger.debug("save client Pending message <%s> success!" % key)
            elif message.get('flag') == 'Slow':
                slow_dict[key] = formatter(message)
                logger.debug("got client slow message <%s>" % key)
            else:
                logger.warning("Message flag %s not define" % message.get('flag'))

     这个坑在多客户端就已经出现了,因为多进程写日志,采用文件锁。多客户端同时写,大家应该能猜到,效果就看表格吧。

    场景(2000条)耗时
    不打日志0.002063274383544922
    单线程打日志0.12387228012084961
    多线程打日志(4)0.4494140148162842
    多进程打日志(4)36.29296827316284

    偷懒点,可以直接关闭细节日志。深入思考也可以看出,单线程性能是牛逼的,不过为了写日志,上下文切换,性能直接降低近百倍。采用多线程,性能在降几倍,说明这种场景下,线程切换开销大于收益。而多进程受限于原先使用的文件锁,不太适合比较。

     分布式实时报警(几万)

    当各类优化到极致,细节日志都关掉,这样单实例的瓶颈已经出现了,很难在大幅度提升了。而基于文件的跨进程通信也是一个很慢的效率,CPU 密集型的 多线程也不会有效果,多进程创建销毁开销也很大,基本不太适用这种场景。因此基于 socket 的并行内存实时计算,可以预见是一个简单有效的方法。抽象下基础服务,我们大致需要如下:

    1. Master 服务,接收 Client 信息,然后转发给指定 Consumer 服务
    2. Consumer服务,只接收指定来源信息,消息独立而有序,避免跨进程内存共享
    3. LogServer服务,日志统一接收处理,提高效率,也方便排查问题。
    4. Monitor服务,对符合条件消息,进行报警

    服务拆分好,接着选 RPC 了,可以直接 Socket 封装,也可以使用已有的。当前 LogServer 采用Socket 通信,因为 logging 自带客户端,只需要实现服务端就可以了。

    场景(2000条)耗时
    单线程写 socket 日志0.11522245407104492

    其他的采用 Zeromq,这个性能与Socket一样,不过使用更方便,为了支持多客户端同时请求,才用了 ROUTER - DEALER 作为通信框架,参考了 locust_rpc 实现,简单易用。

    关于消息拆分粒度,我也做了个尝试,就是Master 接收到消息后,在按保序前提下分为 M 块,然后发送个 M 个Consumer,结果速度反而更慢了。我总结了下消耗:

    T_1 = T(rpc\_send) + T(consumer) + T(res)

    T_2 = T(loads) + T(hash) + T(dumps) + T(consumer)/M + T\binom{res}{M}

    虽然 Consumer 变快了,但是路径更长了,速度反而更慢了

    进入内存计算后,关于如何不丢失日志,我其实困惑了一段时间。

    方案一、预写日志。Consumer 收到消息,先写日志,在处理。这样又有新问题,比如网络不好,Client 未收到指定码触发重发,那么如何实现日志回滚?第二就是运行很长一段时间,一旦重启,这加载速度也太慢了。

    方案二、快照。这个好理解,缺点不及时?相对于预写日志,每条都写。然而真是这样吗?

    再回到方案一的问题,是不是负负得正,一的问题不就是二的答案吗!

    因为最近一直优化细节,反而忘记了整体,在最初设计中,为了保证数据不丢失,我们设计的原子操作是每次请求,而不是每条日志!跳出每次日志的来看,直接对每次请求执行快照,不就可以保证数据不丢失了。而覆盖写单次效率很不错,参考数据如下:

    类型

    次数

    单次大小

    虚拟机(三次)

    覆盖写

    1000

    1024

    0.12、0.12、0.13

    覆盖写

    1000

    1024 * 4

    0.12、0.11、0.13

    覆盖写

    1000

    1024 * 10

    0.14、0.13、0.16

    覆盖写

    1000

    1024 * 1000

    2.1、2.2、1.8

    Consumer 初始化的时候加载快照,之后每次消息过来,都在内存中计算。计算完毕,触发一次快照覆盖,然后返回 Master,失败返回异常码,则重发再来。

    支持更大并发

    考虑到在 Master 端进行数据在分割并没有效果,那么把 Client 包含进来,当做一个整体看待。正常按行读日志,效率也够了。毕竟写日志的上限在那里摆着,不用过度优化。不过日志格式转化是个CPU密集型任务,是可以通过 RPC 改为并行计算,顺带也实现了数据分片,简单的实现更高并发。

    优化总结:在数据流向路径不变的情况,优化原先模块或者拆分为并行计算,效果会很明显;反之为了并行而增大路径,额外增加的序列化成本,以及并行开销可能导致速度更慢。

    参考文献:

    zmq_rpc:  https://github.com/locustio/locust/tree/master/locust/rpc

    展开全文
  • 应用系统瓶颈查找

    2020-12-20 12:15:17
    网站响应慢了,用户开始埋怨,老大安排你去优化,可是优化如何开始呢。...按照一般的思路,我们对系统进行逻辑功能的划分,如静态服务器,动态服务器,数据库服务器,业务逻辑服务器。分别针对对这些服务...
  • 业务指标:如吞吐量(QPS、TPS)、响应时间(RT)、并发数、业务成功率等资源指标:如CPU、内存、Disk I/O、Network I/O等资源的消耗情况本文主要介绍一些广泛适用的、基本的资源指标以及这些指标在Linux服务器的获取...
  • 在前面的章节已经介绍了一些...如果隐士内存临时表的大小超过这2个设置,将会被转换为磁盘临时表。隐士临时表是一种并非自己创建,而是服务器创建,由于保存执行中的查询的中间结果的表。临时表最好呆在内存里,但是...
  • 单台 Elasticsearch 服务器提供服务,往往都有最大的负载能力,超过这个阈值,服务器性能就会大大降低甚至不可用,所以生产环境中,一般都是运行在指定服务器集群中。 除了负载能力,单点服务器也存在其他问题: 单...
  • jmeter(压力测试)指标分析

    千次阅读 2021-02-01 06:42:16
    若出现错误就要看服务端的日志,配合开发查找定位原因 Throughput:简称tps,吞吐量,默认情况下表示每秒处理的请求数,也就是指服务器处理能力,tps越高说明服务器处理能力越好。 压测结果的分析 有错误率同开发确认...
  • 测试TCP吞吐量 为了确定网卡的最大吞吐量,可以在任意客户端运行iperf命令,iperf将尝试从客户端尽可能快地向服务端发送数据请求,并且会输出发送的数据量和网卡平均带宽值。图1是一个最简单的带宽测试命令。 图1...
  • 依据长短日志的压测优化经验,日志系统的吞吐量可以通过调整kafka、logstash、ES的节点数来适应目标容量要求。Kafka的节点数大概为每分钟日志量的大小除以每分钟带宽满载的传输量,Logstash的数量可以观察消费堆积...
  • 五、吞吐量 系统的吞吐量(承压能力)和处理对CPU的消耗、外部接口、IO等因素紧密关联。单个处理请求对CPU消耗越高,外部系统接口、IO速度越慢,系统吞吐能力越低,反之越高。 系统吞吐量有几个重要指标参数:QPS...
  • 返回值报200,表示执行接口调试成功请求:发送的数据响应数据:返回的数据Thread Name:线程组名称Sample Start: 启动开始时间Load time:加载时长Latency:等待时长Size in bytes:发送的数据总大小Headers size in...
  • 服务器磁盘处于脱机

    2021-08-11 12:00:16
    服务器磁盘处于脱机 内容精选换一换配置目的端或启动目的端时提示“SMS.1311 目的端磁盘个数不够”。在配置目的端服务器过程中,会校验目的端磁盘数量是否和源端一致。当出现该错误时,检查目的端服务器磁盘数量是否...
  • Spring RocketMQ 集成实例项目简介springboot+RocketMQ实现spring与rocketmq的集成,作为一个范例提供给大家研究说明Apache RocketMQ是阿里开源的一款高性能、高吞吐量、队列模型的消息中间件的分布式消息中间件。...
  • pubg服务器维护中

    千次阅读 2021-08-11 11:32:25
    pubg服务器维护中 内容精选换一换在执行基本配置操作前,以root用户登录云服务器。在配置内网DNS后,弹性云服务器可以通过虚拟私有云的内网访问相关云服务,能够为用户提供更稳定、可靠的网络环境。配置DNS需要配置...
  • 服务器开机自检内存

    2021-08-11 06:38:18
    服务器开机自检内存 内容精选换一换华为云帮助中心,为用户提供产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题、视频帮助等技术文档,帮助您快速上手使用华为云服务。当对弹性云服务器执行...
  • 服务器的扩容

    2021-08-10 02:16:39
    服务器的扩容 内容精选换一换不支持直接加载外接硬件设备(如USB设备、银行U key、外接硬盘、加密狗等)。不支持带外管理,您的裸金属服务器资源统一由华为云管理和维护。不支持热迁移,服务器故障后会对业务造成影响...
  • 存储服务器怎么关机

    2021-08-12 08:28:30
    存储服务器怎么关机 内容精选换一换云硬盘支持在“可用”和“正在使用”状态进行扩容,通过管理控制台扩容成功后,仅扩大了云硬盘的存储容量,还需要登录云服务器自行扩展分区和文件系统。扩展分区和文件系统时可能...
  • 服务器一直处于关机状态 内容精选换一换为了保证数据安全,您可以对裸金属服务器中的所有云硬盘(系统盘和数据盘)进行备份,采用这种备份方式可以避免因备份创建时间差带来的数据不一致问题。云服务器备份支持基于...
  • 服务器内存型号怎么区分 内容精选换一换在“资源使用详情”区域内,内存分配率统计了当前系统的真实情况,包括部分系统管理内存。各项指标的计算方法如下。总量:可用内存容量,指所有DeC物理服务器上的物理内存容量...
  • 通常衡量一个Web系统的吞吐率的指标是QPS(Query Per Second,每秒处理请求数),解决每秒数万次的高并发场景,这个指标非常关键。举个例子,我们假设处理一个业务请求平均响应时间为100ms,同时,系统内有20台Apache...
  • 服务器数据篡改

    2021-08-11 03:43:08
    服务器数据篡改 内容精选换一换对象存储服务OBS是华为云提供的稳定、安全、高效、易用的云存储服务,具备标准Restful API接口,可存储任意数量和形式的非结构化数据。弹性文件服务SFS是华为云提供的按需扩展的高性能...
  • 电脑关机云服务器会关吗 内容精选换一换按需付费是后付费方式,可以随时开通/删除弹性云服务器,支持秒级计费,系统会根据云服务器的实际使用情况每小时出账单,并从账户余额里扣款。按需付费的弹性云服务器关机再次...
  • 云和本地服务器的优劣 内容精选换一换本节为您介绍如何通过控制台提供的远程登录功能(即VNC方式)登录到云服务器上。登录成功后,如需使用VNC界面提供的复制、粘贴功能,请参见后续处理。已绑定弹性公网IP。登录管理...
  • 服务器之间怎么迁移数据 内容精选换一换在本地主机和Windows云服务器上分别安装QQ.exe等工具进行数据传输。使用远程桌面连接mstsc方式进行数据传输。该方式不支持断点续传,可能存在传输中断的情况,因此不建议...
  • 服务器查看内存工具

    2021-08-12 04:06:03
    服务器查看内存工具 内容精选换一换numactl工具可用于查看当前服务器的NUMA节点配置、状态,可通过该工具将进程绑定到指定...每个节点包含16个CPU core,每个节点的内存大小约为64GB。同设备实时状态查询是检测设备...
  • 服务器数据盘与ssd磁盘 内容精选换一换根据是否支持挂载至多台云服务器可以将磁盘分为非共享磁盘和共享磁盘。一个非共享磁盘只能挂载至一台云服务器,而一个共享磁盘可以同时挂载至多台云服务器。共享磁盘是一种...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 40,960
精华内容 16,384
关键字:

服务器吞吐量正常大小