如何让NoSQL内存数据库适合企业级应用

如何让NoSQL内存数据库适合企业级应用

作者:chszs,转载需注明。博客主页:http://blog.csdn.net/chszs

英文原文: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),以便挑选一个最佳的解决方案。能够实际体验一下这些服务就更好了,很多服务商为这个目的都提供了免费体验。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读752次。关系型数据库关系型数据库是一个结构化的数据库,创建在关系模型(二维表模型)基础上,一般面向于记录SQL语句(标准数据查询语言)就是一种基于关系型数据库的语言,用于执行对关系型数据库中数据的检索和操作主流的关系数据库包括Oracle、Mysql、SQL Server、Microsoft Access、DB2等非关系型数据库NoSQL(nOSQL=Not Only SQL),意思是“不仅仅是SQL”,是非关系型数据库的总称。除了主流的关系型数据库外的数据库,都认为是非关系型主流的NoSQ.._redis是非关系型数据库吗
文章浏览阅读687次,点赞2次,收藏5次。商城系统中,抢购和秒杀是很常见的营销场景,在一定时间内有大量的用户访问商场下单,主要需要解决的问题有两个:1. 高并发对数据库产生的压力;2. 竞争状态下如何解决商品库存超卖;高并发对数据库产生的压力对于第一个问题,使用缓存来处理,避免直接操作数据库,例如使用 Redis。竞争状态下如何解决商品库存超卖对于第二个问题,需要重点说明。常规写法:查询出对应商品的库存,判断库存数量否大于 0,然后执行生成订单等操作,但是在判断库存是否大于 0 处,如果在高并发下就会有问题,导致库存_php库存结余并发
文章浏览阅读1.4k次。MongoTemplate开发spring-data-mongodb提供了MongoTemplate和MongoRepository两种方式访问MongoDB,MongoRepository的方式访问较为简单,MongoTemplate方式较为灵活,这两种方式在Java对于MongoDB的运用中相辅相成。_springboot插入指定的mongodb数据库
文章浏览阅读887次,点赞10次,收藏19次。1.背景介绍1. 背景介绍NoSQL数据库是一种非关系型数据库,它的特点是可以存储非结构化的数据,并且可以处理大量的数据。HBase是一个分布式、可扩展的列式存储系统,它是基于Google的Bigtable设计的。HBase是一个开源的NoSQL数据库,它的核心功能是提供高性能的随机读写访问。在本文中,我们将对比HBase与其他NoSQL数据库,例如Redis、MongoDB、Cass...
文章浏览阅读819次。MongoDB连接失败记录_edentialmechanisn-scram-sha-1
文章浏览阅读470次。mongodb抽取数据到ES,使用ELK内部插件无法获取数据,只能试试monstache抽取mongodb数据,但是monstache需要mongodb replica set 模式才能采集数据。############monstache-compose文件。#replicas set 启动服务。# 默认备份节点不能读写,可以设置。# mydb指的是需要同步的数据库。#登录主mongodb初始化rs。#primary 创建用户。# ip地址注意要修改。# ip地址注意要修改。_monstache csdn
文章浏览阅读913次,点赞4次,收藏5次。storage:fork: trueadmin登录切换数据库注意: use 代表创建并使用,当库中没有数据时默认不显示这个库删除数据库查看表清单> show tables # 或者 > show collections表创建db.createCollection('集合名称', [options])table1字段类型描述capped布尔(可选)如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。_mongodb5
文章浏览阅读862次。Centos7.9设置MongoDB开机自启(超全教程,一条龙)_mongodb centos开机启动脚本
文章浏览阅读1.3k次,点赞6次,收藏21次。NoSQL数据库使用场景以及架构介绍
文章浏览阅读856次,点赞21次,收藏20次。1.背景介绍1. 背景介绍NoSQL数据库是一种非关系型数据库,它的设计目标是为了解决传统关系型数据库(如MySQL、Oracle等)在处理大量不结构化数据方面的不足。NoSQL数据库可以处理大量数据,具有高性能、高可扩展性和高可用性。但是,与关系型数据库不同,NoSQL数据库没有固定的模式,数据结构也不一定是表格。在NoSQL数据库中,数据存储和查询都是基于键值对、列族、图形等不同的...
文章浏览阅读416次。NoSQL定义:非关系型、分布式、开放源码和具有横向扩展能力的下一代数据库。由c++编写的开源、高性能、无模式的基于分布式文件存储的文档型数据库特点:高性能、高可用性、高扩展性、丰富的查询支持、可替换已完场文档某个指定的数据字段应用场景:社交场景:使用mongodb存储用户信息游戏场景:用户信息,装备积分物流场景:订单信息,订单状态场景操作特点:数据量大;读写操作频繁;价值较低的数据,对事物性要求不高开源、c语言编写、默认端口号6379、key-value形式存在,存储非结构化数据。_nosql
文章浏览阅读1.5k次,点赞3次,收藏2次。Exception in thread "main" redis.clients.jedis.exceptions.JedisConnectionException: Failed to create socket. at redis.clients.jedis.DefaultJedisSocketFactory.createSocket(DefaultJedisSocketFactory.java:110) at redis.clients.jedis.Connection.connect(Conne_redis.clients.jedis.exceptions.jedisconnectionexception: failed to create so
文章浏览阅读6.5k次,点赞3次,收藏12次。readAnyDatabase(在所有数据库上都有读取数据的权限)、readWriteAnyDatabase(在所有数据库上都有读写数据的权限)、userAdminAnyDatabase(在所有数据库上都有管理user的权限)、dbAdminAnyDatabase(管理所有数据库的权限);:clusterAdmin(管理机器的最高权限)、clusterManager(管理和监控集群的权限)、clusterMonitor(监控集群的权限)、hostManager( 管理Server);_mongodb创建用户密码并授权
文章浏览阅读593次。Redis是一个基于内存的键值型NoSQL数据库,在实际生产中有着非常广泛的用处_搭建本地redis
文章浏览阅读919次。Key 的最佳实践[业务名]:[数据名]:[id]足够简短:不超过 44 字节不包含特殊字符Value 的最佳实践:合理的拆分数据,拒绝 BigKey选择合适数据结构Hash 结构的 entry 数量不要超过 1000(默认是 500,如果达到上限则底层会使用哈希表而不是 ZipList,内存占用较多)设置合理的超时时间批量处理的方案:原生的 M 操作Pipeline 批处理注意事项:批处理时不建议一次携带太多命令。Pipeline 的多个命令之间不具备原子性。_redis高级实战
文章浏览阅读1.2k次。MongoDB 递归查询_mongodb数据库 递归
文章浏览阅读1.2k次。通过实际代码例子介绍:如何通过MongoTemplate和MongoRepository操作数据库数据_springboot操作mongodb
文章浏览阅读687次,点赞7次,收藏2次。首先欢迎大家阅读此文档,本文档主要分为三个模块分别是:Redis的介绍及安装、RedisDesktopManager可视化工具的安装、主从(哨兵)模式的配置。_redis 主从配置工具
文章浏览阅读764次。天下武功,无坚不摧,唯快不破!我的名字叫 Redis,全称是 Remote Dictionary Server。有人说,组 CP,除了要了解她外,还要给机会让她了解你。那么,作为开发工程师的你,是否愿意认真阅读此心法抓住机会来了解我,运用到你的系统中提升性能。我遵守 BSD 协议,由意大利人 Salvatore Sanfilippo 使用 C 语言编写的一个基于内存实现的键值型非关系(NoSQL)..._redis 7.2 源码
文章浏览阅读2k次。MongoDB 的增删改查【1】_mongodb $inc