Dynomite--将非分布式存储变为分布式
简介和概述
Netflix长期以来一直是微服务模式的倡导者。该模型提供更高的可用性,故障恢复能力和松耦合。这种架构的缺点是潜在的用户体验。每当客户加载主页或开始流式传输电影时,都会有许多微服务完成该请求。这些微服务中的大多数使用某种有状态的系统来存储和提供数据。几毫秒可以快速加起来,并产生多秒的响应时间。
Netflix的云数据库工程团队一直在寻找方法,从应用程序的数据库响应时间中减少毫秒,同时保持我们的本地高可用性和多数据中心高可用性的目标。考虑到这个目标,我们创建了Dynomite。
受Dynamo白皮书以及Apache Cassandra的经验启发,Dynomite是一个分片和复制层。Dynomite可以将现有的非分布式数据存储(如Redis或Memcached)制作成完全分布式的多数据中心复制数据存储。
服务器架构
动机
在开源世界中,有各种单服务器数据存储解决方案,例如Memcached,Redis,BerkeleyDb,LevelDb,Mysql(数据存储)。这些单服务器数据存储的可用性故事通常最终会成为主从设置。一旦流量需求超过这个设置,下一个合乎逻辑的进程就是引入分片。大多数人会同意这种设置不是微不足道的。而且,管理来自不同分片的数据对于应用程序开发人员来说也是一项挑战。
在高扩展性和大数据时代,Dynomite的设计目标是将这些单服务器数据存储解决方案转变为对等,线性可伸缩的集群系统,同时仍保留数据存储的本地客户端/服务器协议,例如,Redis协议。现在我们将介绍一些Dynomite服务器体系结构设计核心的高级概念。
Dynomite拓扑
Dynomite集群由多个数据中心(dc)组成。数据中心是有多组机架,机架是一组节点。每个机架由整个数据集组成,该数据集在该机架中的多个节点上分区。因此,多个机架可实现更高的数据可用性。机架中的每个节点都有唯一的标记,这有助于识别其拥有的数据集。
每个Dynomite节点(例如,a1或b1或c1)都有一个Dynomite进程与数据存储服务器共同放置,数据存储服务器用作代理服务器,流量路由器,协调器和gossiper。在Dynamo文件的上下文中,Dynomite是Dynamo层,它为可插入数据存储代理提供额外的支持,尽力保留本地数据存储协议。 数据存储可以是易失性数据存储(如Memcached或Redis),也可以是持久数据存储(如Mysql,BerkeleyDb或LevelDb)。我们目前的开源Dynomite产品支持Redis和Memcached。
复制
发送写入流量时,客户端可以连接到Dynomite集群上的任何节点。如果Dynomite节点恰好拥有基于其令牌的数据,则数据将写入本地数据存储服务器进程,并跨所有数据中心异步复制到群集中的其他机架。如果节点不拥有数据,则它充当协调器并将写入发送到拥有同一机架中的数据的节点。它还将写入操作复制到其他机架和DC中的相应节点。
在当前的实施中,如果本地机架中的节点成功存储写入,并且所有其他远程复制将异步发生,则协调器将Ok返回给客户端。
下图显示了客户端向非拥有节点发送写请求的后一种情况的示例。它按照分区方案属于节点a2,b2,c2和d2。该请求被发送到充当协调器的a1,并将该请求发送到适当的节点。
高可用的读取
多个机架和多个数据中心提供高可用性。客户端可以连接到任何节点来读取数据。与写入类似,如果节点拥有数据,节点将为读取请求提供服务,否则会将读取请求转发给同一机架中的数据拥有节点。在节点,机架或数据中心出现故障的情况下,Dynomite客户端可以故障切换到远程机架和/或数据中心的副本。
可插入的数据存储
由于TwitterOSS Twemproxy项目,Dynomite目前支持Redis和Memcached。对于每个数据存储,根据我们的使用经验,支持最实用的Redis / Memcached API的实用子集。在不久的将来,将根据需要添加对其他API的支持。
标准开源Memcached / Redis ASCII协议支持
任何可以与Memcached或Redis交谈的客户都可以与Dynomite交谈 - 无需任何更改。但是,除非使用我们的Dyno客户端(客户端架构部分中的更多详细信息),否则将会丢失一些内容,包括故障转移策略,请求限制,连接池等。
可扩展的I / O事件通知服务器
所有传入/传出数据通信都由单个线程I / O事件循环处理。还有其他线程用于后台或管理任务。所有线程通信都基于无锁循环队列消息传递和异步消息处理。 这种实现方式可以使每个Dynomite节点处理大量的客户端连接,同时仍然处理许多并行的非客户端任务。
对等,线性可扩展
群集中的每个Dynomite节点都具有相同的角色和责任。因此,集群中没有单点故障。有了这个优势,人们可以简单地将更多节点添加到Dynomite群集中以满足流量需求或负载。
缓存预热
目前,该功能可用于使用Redis数据存储的Dynomite。Dynomite可以通过填充空白节点或节点数据来减少性能影响。
不对称的多数据中心复制
如前所述,写入可以复制到多个数据中心。在不同的数据中心,Dynomite可以配置不同数量的机架和不同数量的节点。当流量不平衡到不同的数据中心时,这非常有用。
节间沟通和gossip
内置gossip的Dynomite有助于维护集群成员以及故障检测和恢复。这简化了Dynomite集群的维护操作。
在AWS和物理数据中心有功能
在AWS环境中,数据中心等同于AWS的区域,机架与AWS的可用区域相同。在Netflix,我们有更多的工具来支持在AWS中运行Dynomite集群,但通常情况下,这两个环境中的两个部署应该是相似的。
客户端架构
Dynomite服务器实现底层数据存储协议,并将其作为其公共接口。因此,可以使用Jedis,Redisson和SpyMemcached等流行的Java客户端直接与Dynomite交谈。
在Netflix,我们看到在一个地方封装客户端复杂性和最佳实践的好处,而不是让每个应用程序重复相同的工程工作,例如,拓扑感知路由,有效故障转移,带指数退避的负载剔除等。
Dynomite附带一个名为Dyno的Netflix本土客户端。Dyno在Jedis,Redisson和SpyMemcached等流行客户的顶端实施了受Astyanax(Netflix的Cassandra客户)启发的模式,以便轻松迁移到Dyno和Dynomite。
Dyno客户端功能
- 永久连接的连接池 - 这有助于减少客户端连接重用时Dynomite服务器上的连接流失。
- 支持拓扑的负载平衡(令牌感知),用于避免向不是指定数据所有者的Dynomite协调节点跳转。
- 应用程序特定的本地机架亲和力请求路由到Dynomite节点。
- 当本地Dynomite机架节点发生故障时,通过智能故障切换到远程机架实现应用程序弹性。
- 通过不断监控连接健康状况并回收不健康的连接,应对弹回的网络故障。
- 通过手术将流量从任何需要离线维护的节点路由出去的能力。
- 灵活的重试策略,如指数退避等
- 洞察连接池指标
- 高度可配置和可插拔的连接池组件,用于实现您的高级功能。
以下是Dyno如何进行故障转移以提高针对单个节点问题的应用程序弹性的示例。
有趣的事实
Dyno客户端努力保持与Jedis等客户端界面的兼容性,这极大地减少了在执行切换到Dynomite时已经使用Jedis的应用程序的障碍。 另外,由于Dynomite实现了Redis和Memcached协议,因此可以使用Dyno直接连接到Redis / Memcached本身并绕过Dynomite(如果需要)。只需将连接端口从Dynomite服务器端口切换到redis服务器端口即可。
Netflix拥有我们自己的本地客户端的间接层,可以灵活地执行其他很酷的事情,例如
请求拦截 - 您应该能够插入自己的拦截器来执行诸如
- 实现查询跟踪或慢速查询日志记录。
- 当事情发生在服务器端时,实施故障注入来测试应用程序的弹性。
微型批处理 - 向分布式数据库提交批处理或请求会变得棘手,因为根据分片/散列策略,不同的键映射到不同的服务器。Dyno能够接受用户提交的批次,将其拆分为封面下的碎片感知微批次,然后单独执行,然后在返回给用户之前将结果拼接在一起。很明显,在这里必须要处理部分故障,而且Dyno有能力仅仅针对负责该散列分区的远程机架副本重试失败的微批处理。
卸载 - 对于每个请求,Dyno的拦截器模型将使其能够执行配额管理和速率限制,以保护后端Dynomite服务器。
线性刻度测试
我们希望确保Dynomite能够在Netflix扩大其全球影响力的同时水平扩展以满足来自数百家微服务的流量需求。 我们使用6号静态Dynomite集群和一个使用dyno客户端的负载测试工具进行了简单测试。群集被配置为具有3的复制因子,即它是具有3个机架的单个数据中心。 我们加强了对群集的请求,同时确保99个百分点的延迟仍然在单个数字ms范围内。 然后,我们按比例扩大服务器机队和客户机队,并重复测试。我们经历了几个缩放周期,即6→12→24,并且在每个阶段我们记录了平均和99百分位潜伏期在可接受范围内的持续吞吐量。 即平均潜伏期<1ms,99百分位潜伏期3-6毫秒。
我们看到Dynomite随着我们向集群添加更多节点而线性缩放。这对于Netflix的数据存储至关重要,我们希望通过可预测的成本模型对吞吐量和延迟进行手术控制。Dynomite就是这样。
长期愿景和路线图
Dynomite有可能为任何数据存储提供基于服务器的分片和复制,只要创建一个代理来拦截所需的API调用即可。 Dynomite的这个初始版本以明文形式支持Redis和Memcahed分片和复制,备份和恢复。在接下来的几周内,我们将实施加密的数据中心间通信。我们还计划实施群集数据的协调(修复)并支持不同的读/写一致性设置,从而使其成为最终一致的数据存储。 在Dyno客户端,我们计划添加其他很酷的功能,例如卸载,分布式流水线和微量批处理。我们也在考虑与RxJava进行整合,为Redis / Memcached提供反应式API,使应用程序能够观察数据和事件序列。