简介
官网地址:https://www.couchbase.com/
Couchbase是一个较新的、发展迅速的nosql数据库技术。2014年,viber宣布使用Couchbase替换Mongodb,以适应10亿级的用户量,目前,Couchbase已大量运用于生产环境,国内使用的公司主要有新浪,腾讯等。
Couchbase是CouchDB和MemBase的合并。而memBase是基于Memcached的。因此Couchbase联合了Couchbase的简单可靠和memcached的高性能,以及membase的可扩展性。
灵活的数据模型:Couchbase中使用json格式存储对象和对象之间的关系。
Nosql数据库的一个特性是不需要定义数据结构,在Couchbase中,数据可以存储为key-value对或者json文档,不需要预先定义严格的格式,由于这种特性,couchbase支持以 scale out(水平扩展)方式扩展数据量,提升io性能,只需要在集群中添加更多的服务器就行了。相反,关系数据库管理系统scale up(纵向扩展),通过加更多的CPU,内存和硬盘以扩展容量。
Couchbase可用于单机环境,也可以和其他服务器一起提供分布式的数据存储。
特点
CouchBase是在memcached和redis之类缓存组件的基础上发展而来的,被称作为可能是最好的缓存系统。所其必然能满足之前的前辈所满足不了的地方。
传统的缓存组件包括memcached和redis有着这种或者那种的缺点:
- Cluster支持完善度不够或者直接没有Cluster
- 没有良好的高可用性机制,持久化支持的亦不是很完善
- 扩容和故障恢复能操作维护复杂
- 其他
而CouchBase则对上面的一些缺点都有着良好的支持。或者说
CouchBase所提供的任何单一功能,在市面上基本上都能找到一款数据库能够满足。但是这些数据库实际使用的话总是会有各种各样的妥协,性能很好的话,扩展性可能很差之类的。而CouchBase的目标就是建立一个大一统,各种功能都包含可用,所谓接近完美的数据库。
技术特征
数据存储
Couchbase通过使用buckets提供数据管理服务,buckets相当于关系数据库中的库,Couchbase中没有表的概念,保存数据时,先建bucket,然后就直接插入数据了。buckets可以供集群中的多个客户端程序访问。Couchbase通过Buckets组织,管理和分析数据资源。
Couchbase中有两种类型的数据bucket,当启动Couchbase服务的时候,可以选择需要的类型。
1)memcached buckets。只将数据存储在内存中。提供了一个分布式的(横向扩展),纯内存的,key-value缓存。Memcached buckets 设计用于关系数据库的缓存,可以缓存经常访问的数据,由此减少web程序中数据库的查询次数。
2)couchbase buckets。存数据在内存和硬盘。提供高可用性和可动态重新配置的分布式数据存储,提供数据持久化和复制服务。couchbase buckets 100% 兼容开源的分布式缓存memcached
内存分配
Server Quota:
Couchbase服务初始化时会给服务器分配内存限额,表示这个服务器中可用的最大内存,是node级的。初始配置在集群中的第一台服务器(node)上,所有服务器的内存配额都是一样的。例如集群中有10台服务器,服务器内存配额是16G,整个集群中共160G可用内存。如果需要加2个新的服务器,每个新的服务器需要16G的可用内存,集群中可用的内存数将是192G。
Bucket Quota:
Bucket 内存配额是分配给一个bucket的可用内存。配置在每个节点上,是从server quota中分配出去的。例如,如果你创建了一个新的bucket,限额是1GB,在10个节点的集群中,汇总后会有10G。如果添加两个节点,集群中汇总后会有12G的bucket 限额。
从图上可以看出,增加新的节点就可以扩展总的可用内存,从而增加存储的数据量。通过bucket限额系统可以判断数据是否应该调出内存。
vBucket
vBucket相当于一个key的子集,保存的是客户端存储对象的key值,vBuckets 用于在集群的节点间分配数据和备份数据。是 couchbase 实现 auto sharding,在线动态增减节点的重要基础。不是用户可访问的组件,但是至关重要。
通过vbucket,客户端直接访问保存信息的服务器,不需要通过中间代理或者其他架构,因此可以从数据中抽象出物理拓扑结构。这种方式使couchbase易扩展。
这种架构不同于memcached使用的架构,memcached的做法是用 key 算出一个 hash,得到服务器列表中的对应服务器。这个列表需要动态维护,还需要一个hash算法用于处理集群拓扑结构的变化。
如以下代码所示:
servers = ['server1:111', 'server2:112', 'server3:113']
server_for_key(key) = servers[hash(key) % servers.length]
这种算法很简单,也很容易理解,但也有几个问题:
1、如果一台服务器失效,会造成该分片的所有 key 失效。
2、如果服务器容量不同,管理非常麻烦。
3、运维、配置非常不方便。
为了把 key 跟服务器解耦,couchbase 引入了 vBucket。每个key都属于一个vbucket,查找对应的value时先用hash函数计算这个key属于哪个vbucket,再从vBucket 与服务器对应表中查找这个vbucket属于哪个服务器,映射表保存vbucket和服务器的对应关系,一个bucket一行,一个服务器可以对应多个vbucket。
1、key hash 对应一个 vBucket,不再直接对应服务器。
2、集群维护一个全局的 vBucket 与服务器对应表。
例如,集群中有3个服务器,客户端要查找 一个key对应的value值,首先计算key属于哪个Vbucket,在这个例子中,hash结果是vB8 ,通过查映射表,客户端确定vB8对应到服务器C,然后get操作直接发送到服务器C。
一段时间后,需要加一个新的服务器D到集群,vbuckets映射表更新为:
这时,客户端再想取key对应的value值,hash算法结果仍为vB8,但是新的映射表会将vB8映射到服务器D。
由于 vBucket 把 key 跟服务器的静态对应关系解耦合,基于 vBucket 可以实现一些非常强大有趣的功能,例如:
Replica,以 vBucket 为单位的主从备份。如果某个节点失效,只需要更新 vBucket 映射表,马上启用备份数据。
动态扩容。新增加一个节点后,可以把部分 vBucket 转移到新节点上,并更新 vBucket 映射表。
缓存管理
Couchbase自动管理缓存层,确保有足够的内存空间以维持性能。couchbase后台有个进程,专门把一定时间没有被访问的数据移出内存,这个进程的扫描时间和数据的最大无活动时间都是可以设置的。couchbase在对数据进行增删时会先体现在内存中,而不会立刻体现在硬盘上,从内存的修改到硬盘的修改这一步骤是由couchbase自动完成,等待执行的硬盘操作会以write queue的形式排队等待执行,也正是通过这个方法,硬盘的I/O效率在write queue满之前是不会影响couchbase的吞吐效率的,而write queue的长度是可以设置的。通过write queue执行大量写数据库操作时用户可能会感受到很短时间的内存飙升,但是异步特性和queue的使用使读写速度都非常快。
对于所有文档couchbase都会建立一个额外的56byte的metadata,这个metadata功能之一就是表明数据状态是否活动在内存中。同时文档的id也作为标识符和metadata一起长期活动在内存中。这表示对文档id不存在的情况服务器可以直接返回‘文档id不存在。couchbase官方建议bucket申请的内存中,metadata和key所占用的内存不应超过一半,否则couchbase的性能会显著下降。为了保证这个条件,当有效数据占用超过一定内存时就需要把超额数据移除了。
这里有低水位和高水位的概念,也就是说当移除数据过多以至于内存中有效数据占用内存低于低水位的时候,couchbase会随机挑一些文件到内存中以达到低水位。当有效数据内存占用超过高水位时,couchbase就会移除数据。高低水位都是可以设置的。
随着内存数据越来越多,会逐渐到达低水位,这时候,系统不会做任何处理。当数据量持续增加,到达高水位时,系统会启动一个job任务移除数据,当到达低水位时任务停止。如何进入数据的速度大于移除数据的速度,系统会返回空间不足的错误提示,直到有足够的内存为止。
如果只使用memcached buckets,服务器只提供数据缓存,不会持久化到硬盘。如果服务器内存空间不足,系统会使用LRU算法从内存中Eviction 数据,Eviction表示服务器会移除一个数据项的key,metadata和所有其他信息。Eviction后,数据将无法恢复。
数据持久化
考虑到性能,couchbase服务主要使用缓存为客户端保存和返回信息,同时会逐渐将数据保存到硬盘以维持高可靠性。如果有节点fail了可以直接从硬盘恢复数据,数据是逐渐持久化到硬盘的,同时保存到缓存层和硬盘write queue,不会阻塞客户线程。当客户端访问一个不在内存的数据时,持有load queue的进程会将数据读到内存,在数据返回之前客户端需要等待。
多线程读写:之前的couchbase版本,读写硬盘的线程只有一个。为了提高读写硬盘的速度和提高缓存命中率,现在couchbase提供了多线程读写。
多线程读写需要考虑线程之间的同步问题以避免冲突。为了维持性能和避免冲突,couchbase对每个线程访问的资源进行了静态分配,同时使用了资源锁。当创建多个读写线程时,服务器为每个线程单独分配了不同的vbuckets。通过这种静态协调方式,可以保证同一个vbuckets只有一个读线程和一个写线程可以访问。上图表示6个线程和两个数据vbucket。每个线程有预先分配的可读写范围。
负载均衡
Couchbase 服务器上数据的分配方式是通过vbucket结构实现的,如果想增加或减少集群中的机器,vbuckets中存储的数据都需要重新分配,vBucket map(映射表)也需要更新以适应新的集群结构。
Rebalancing 是集群结构发生变化时的数据调整,需要手动操作,这个过程改变vbuckets到服务器的分配,需要在服务器节点之间迁移数据以适应新的结构。
Rebalancing过程可以发生在集群运行和提供服务时,客户端使用现有架构读写数据,同时后端在节点之间迁移数据。一旦这个过程完成, 更新vBucket map表,并通知smart clients和代理服务(MOxi).
Rebalancing后数据在集群中重新分配,因此数据被均匀分配到整个数据库,这个过程需要考虑数据和数据的副本。
总结
数据存储:nosql,易水平扩展。
缓存层:低水位和高水位设置,文档metadata。
vBucket:使系统易于动态管理,自动分片,reblancing。
多线程持久化:预分配每个线程的访问范围,保证性能和可靠性。
参考
https://sq.163yun.com/blog/article/189804692240617472