英文原文:How to Make Your In-memory NoSQL Datastores Enterprise-Ready
对于每一个关注用户体验的Web应用或移动应用而言,NoSQL内存数据库(例如开源的 Redis和Memcached)正逐步成为事实上的标准。但是,近几年来,大型企业在采用这些数据库方面还面临着诸多挑战,主要是由于性能、可扩展性和可用性方面的问题。
非常幸运的是,现代编程语言(例如Ruby、Node.js、Python等)和开发平台(例如Rails、Sinatra、Django等)已经内置了很多工具和开发库。这些工具和开发库能够有效利用内存数据库的高性能和各种操作命令,能够实现当前流行的多种应用项目。
这些开源项目的案例包括作业管理、论坛、实时分析、Twitter克隆、地理位置搜索以及高级缓存等等。
但是,对于这些项目成功至关重要的是数据库系统的可用性(Availability)、可扩展性(Scalability)和性能(Performance)。
本文粗略的介绍如何利用内存数据库构建企业级应用,包括一些技巧和建议;这些技巧和建议能够解决云端NoSQL数据库管理面临的七大挑战。
一、可用性(Availability)
无论你在做什么,对于你的应用来说数据必须是时刻可用的。这对于内存数据库来说尤为重要;因为,如果没有适当的措施,当下面的情形发生时你的数据将会部分或全部丢失:
1) 节点失效(在云中经常发生)
2) 进程重启(你可能需要不时的进行重启)
3) 按需要扩展(我们假设你可能需要这个)
对于情形1和情形2有两种方式来解决;情形3将在稍后讨论。
1、复制:你要确保将你的数据集保存一份到集群的另一节点,如果是另一数据中心则更为可靠,以便应付数据中心发生故障(亚马逊AWS在2012年至少发生了4次故障)。不幸的是事情并非如此简单。随便就能举一个复制非常困难的例子:
一旦程序的写频率增加,你会发现应用服务器写入速度远大于复制的速度,尤其是在主节点和复制节点存在网络拥堵的情形下。一旦发生这种情况,如果数据集非常大,节点的复制同步很有可能永远也完不成。
2、自动切换:为什么需要这个?内存数据库每秒处理的请求比一般数据库通常多100倍,这就意味着每增加一秒宕机时间就会延迟更多的请求处理并给用户带来不好的用户体验。在实现自动切换时一定要遵循下面的原则:
(1) 确保主存储节点一旦失效就立刻切换到备用复制节点。这一般基于成熟健壮的看门狗技术 (Watch Dog),看门狗持续的监控节点,一旦发现失效就切换到健康的复制节点。
(2) 对于你的应用程序而言切换过程应尽可能透明;最理想的情况是无需更改任何配置。更高级的解决方案是仅仅修改DNS中存储节点的IP地址,确保修复过程在几秒钟之内完成。
(3) 自动切换应当基于Quorum并且是完全一致(Fully Consistent)或最终一致(Eventually Consistent)的。讨论下面继续:
二、网络分割过程中和完成后的一致性
网络分割(Network Split)在云中频繁发生,对地球上的分布式存储系统而言也是最复杂的问题。一旦发生分割,应用程序可能只会找到内存数据库的部分节点;同时,每个NoSQL内存数据库节点也可能只能找到其他部分NoSQL数据库节点。
为什么说这是一个非常严重的问题呢?如果你的数据库包含一些隐蔽的设计缺陷,当网络分割发生时,应用程序很可能会把数据写入错误的节点。这意味着,当网络分割的情况恢复时,应用程序之前的写请求操作的数据就会丢失。这对NoSQL内存数据库来说这是一个非常重要的话题,因为NoSQL内存数据库每秒的写操作数量远大于其他NoSQL数据库系统。
一个设计得当的NoSQL内存数据库是什么样子的呢?很不幸,你只能从下面两个非常糟糕的候选中进行选择:
(1) 如果NoSQL内存数据库是完全一致的,在某些情况下你是不允许写入任何内容的,除非网络分割恢复。
(2) 如果NoSQL内存数据库是最终一致的,应用程序可以对“读”请求采用quorum方法——返回一个值或者阻塞。
注意:到目前为止,业界并不存在最终一致的NoSQL内存数据库产品,所以只有选项1是可以实际应用的方案。
三、数据的耐久性(Durability)
尽管NoSQL内存数据库解决方案提供了多种复制选择,你还是需要着重考虑数据的持久化和备份,原因如下:
(1) 或许你不想为内存复制支付额外的费用,但是仍希望将数据集保存在某个地方,以便在遇到节点故障时能够将数据恢复(即使恢复速度很慢)。
(2) 你肯定希望在遇到任何故障时(比如节点故障、多节点故障、数据中心故障等)都能将数据恢复并且希望保留另外一个选择——将数据保存在另外一个安全的地方,即使数据不能与最新的修改同步。
(3) 还有其他一些采用数据持久化的理由,比如导入产品数据集到阶段环境,以便于测试。
现在你已经确信数据持久化是必要的,在大多数云环境中你应当使用附属在云主机上的存储设备(像AWS的EBS、Azure的Cloud Derive等)。如果你将数据保存在本地硬盘,当遇到节点故障时你就会丢失数据。
一旦数据得到持久化保存,你最大的挑战将变成:在更新数据持久化存储的同时保证NoSQL内存数据库的速度。
四、稳定的性能
NoSQL内存数据库(例如Redis或Memcached)的设计目标是:在毫秒延迟内,每秒钟能够处理超过10万个请求。但是,这个数字在云环境下是很难达到的,除非你遵循以下原则:
1、确保你的解决方案使用的是功能强大的云主机(Cloud Instance),比如AWS的 m2.2xlarge/m2.4xlarge云主机或者是Azure的A6/A7云主机,而且还有一个专用环境。
另外,可以实现一种预防跨不同云账户的“吵闹的邻居”现象的机制。此机制应该能监控你的数据集的性能,可实时监控、按命令监控、基于一定的规则去监控、或根据一套机制去监控,比如当发现延迟超过阈值就自动迁移数据集到另一个节点。
2、避免存储的I/O瓶颈,确保解决方案使用了功能强大的存储设备,最好是配置了RAID。其次,要确保在“请求数突然暴增”的情况下也不会阻塞你的应用。例如,使用开源Redis方案,你可以配置slave节点执行持久化存储操作;master节点专注于处理用户请求,在“请求数突然暴增”的情况下避免超时现象。
3、测试云厂商提供的各种关于存储I/O优化的建议,例如AWS的PIOPS。大多数情况下,这些建议对随机访问(读或写)来说很有用;但是,对于NoSQL内存数据库经常采用的像顺序写之类的情况来说就没什么优化价值。
AWS的PIOPS
4、 如果内存数据库基于单线程架构(例如Redis),要确保不要在同一个线程中运行多个数据库。不然,某个数据库在执行命令的过程中很有可能会阻塞另外一个数据库。
五、网速
大多数云主机都配置了一块千兆(1Gbps)网卡。在NoSQL内存数据库上下文中,此千兆网卡需要处理:
1、应用程序的请求
2、集群内部的通信
3、复制
4、存储访问
这很容易造成运行瓶颈。因此,下面提供一些建议可解决此问题:
(1) 为每一台云主机配置万兆网卡(10Gbps,但是要有心理准备,它非常昂贵)
(2) 选择能够为一些特殊应用在VPC内部配置多块千兆网卡的云服务商,例如AWS
(3) 采用能够在NoSQL内存数据库节点之间高效分配资源的解决方案以便让网络阻塞最小
六、可扩展性(Scalability)
对于简单的键值(Key / Value)缓存解决方案(例如Memcached或者Redis的简单应用),其扩展不会被认为是严重问题;因为在大多数情况下,它只需在服务器列表中增加或删除节点并修改哈希函数。但是,对于实际遭遇过此问题的人就会意识到它仍然是一个令人痛苦的问题。
对于此问题我们有一些建议:
1、采用一致性哈希(Hashing)。
用简单的哈希函数(例如求模)做扩展时,意味着遇到扩展事件会丢失所有的键数据。另一方面,很多人不知道的是:即使采用一致性哈希函数,在扩展的时候你仍然会丢失部分数据。例如,在扩展的时候你会丢失1/N的键数据,N是你扩展后的节点数目。所以,如果N比较小,它就是一个很痛苦的过程(比如对2个节点的集群采用一致性哈希函数进行扩展,就意味着会丢失1/3的数据)。
2、建立一种机制,用扩展事件同步所有的NoSQL内存数据库的客户端,以预防这样的事件发生——在扩展过程中不同的应用服务器写入到不同的节点。
当进行某些复杂操作时,例如Redis的UNION和INTERSECT操作,扩展就会成为非常实际的问题。这些命令等同于SQL中的JOIN命令,在多线程架构下,如果不增加一定的延迟和复杂性,这些操作就不能实现。应用程序级的分片(Sharding)能够解决一定的问题,因为它允许在分片级运行一些复杂命令。但是,这需要很复杂的设计,并且与NoSQL内存数据库的配置有一定的关联。比如,分片的应用必须注意节点上存储的每一个主键;扩展事件(如重分片)需要修改大量代码和额外的执行开销。
另外,一些人声称,新一代的超高速RAM,比如亚马逊AWS的HIgh Memory Cluster Eight Extra Large 244GB内存(cr1.8xlarge),能够解决节点扩展中遇到的大多数问题。
但现实是有所不同的,对于25GB-30GB数据集规模,对于像Redis之类的内存数据库,还有一些其他的操作问题会阻止扩展的执行。这些问题与本文前面提到的挑战密切相关,像复制、存储I/O、单核的单线程架构限制、网络带宽开销等。
七、巨大的运维开销
NoSQL内存数据库在处理所有的操作方面会产生巨大的额外开销。你需要对这些技术进行深入了解,以便在紧要关头能做出正确的决策。同时,因为这些技术更新频率很快(可能是非常快),你还要时刻关注这些系统的趋势和最新变化。
八、结论
正如我们上面所说的一样,为了更好的利用Redis、Memcached等开源技术带给我们的优势,我们需要对这些技术进行深入了解和掌握。对于企业IT团队来说,为了能够在企业环境中使用NoSQL内存数据库,了解如何更好的应对这些挑战就显得尤为重要。不是我持有偏见,我强烈建议寻找一些能够攻克可扩展性和高可用性限制而不损害功能和性能的商业解决方案;因为执行这些内部操作需要该领域的高级专家,而这是非常稀少的。
在市场上有一些关于Redis和Memcached的NoSQL服务(NoSQL-as-a-service);我建议你对每一个可用的服务进行深入的比对(就像DIY),以便挑选一个最佳的解决方案。能够实际体验一下这些服务就更好了,很多服务商为这个目的都提供了免费体验。