Couchbase集群和Redis集群解析
Couchbase集群和Redis集群解析
首先,关于一些数据库或者是缓存的集群有两种结构,一种是Cluster;一种是master-salve.
关于缓存系统一般使用的就是Redis,Redis是开源的,它可以单机使用,也可以做集群使用。
Redis集群是一个分布式、容错、的Redis实现,集群可以使用的功能是普通单机Redis所能使用的功能的一个子集
Redis集群中不存在中心节点或者代理节点,集群的其中一个主要的目标是达到线性可扩展性
集群的容错功能是通过使用主节点和从节点来实现的(master-slave)。
Redis集群中的节点有3大责任:
(1) 持有键值对数据。
(2) 记录集群的状态,包括键到正确节点的映射。
(3) 自动发现其它节点,识别工作不正常的节点,并在有需要时,在从节点中选举出新的主节点。
Redis节点之间使用Gossip协议来进行工作:
(1) 传播关于集群的信息,以此来发现新的节点。
(2) 向其它节点发送PING数据包,确定节点是否正常工作。
(3) 在特定事件发生时,发送集群信息。
键分布模型:Redis集群的键空间被分割为16384个槽,集群的最大节点数量也是16384个。(官方文档推荐的最大节点数量为1000个左右)。
每个主节点都负责处理16384个哈希槽的其中一部分。
当集群没有执行重置操作,每个哈希槽都只由一个节点进行处理。
重置是指将某个/某些槽从一个节点移动到另一个节点。(移动键操作是原子操作,在移动期间,两个节点都会处于阻塞状态,以免出现竞争条件)。
MOVED转向
一个Redis客户端可以向集群中的任意节点(包括从节点)发送命令请求。
请求节点将会查询命令所要处理的键所在的槽。
(1) 如果要查找的哈希槽正好就是本节点负责,就直接处理。
(2) 如果查找的槽不是本节点负责,记录请求的记录,并向客户端回复一个MOVE错误,给出键当前所在的IP和端口。
ASK转向
容错(添加节点和节点失效的情况):节点失效检测、集群状态检测、从节点选举
以上说的Redis的功能在2.8才稳定使用。
而Couchbase可以实现Redis的缓存功能同时还可以对数据进行持久化,存入到硬盘中,Couchbase是基于文档或者是JSON格式数据的存储的数据库,
数据存储采用vBuckets处理的。
The diagram below shows how the Key to Server mapping (vBucket map) works. There are three servers in the cluster. A client wants to look up ( get
) the value of KEY. The client first hashes the key to calculate the vBucket which owns KEY. In this example, the hash resolves to vBucket 8 ( vB8
) By examining the vBucket map, the client determines Server C hosts vB8. The get
operation is sent directly to Server C.
After some period of time, there is a need to add a server to the cluster. A new node, Server D is added to the cluster and the vBucket Map is updated.
The vBucket map is updated during the rebalance operation; the updated map is then sent the cluster to all the cluster participants, including the other nodes, any connected “smart” clients, and the Moxi proxy service.
Within the new four-node cluster model, when a client again wants to get
the value of KEY, the hashing algorithm will still resolve to vBucket 8 ( vB8
). The new vBucket map however now maps that vBucket to Server D. The client now communicates directly with Server D to obtain the information.
Couchbase不但支持Cluster同时,Cluster之间还支持Replication
现在最好的结构有两种:
Couchbase集群
Couchbase服务器可以单独运行,也可以作为集群运行。在Couchbase集群里,运行一个或多个Couchbase实例。集群里所有节点是相等的,提供相同的功能和信息,没有层次结构或者拓扑的概念,也没有主节点、从节点之分。整个集群共享每个独立节点的信息,每个节点负责对数据的一部分进行响应。
集群是水平扩展的。要增加集群的容量,你只需加多一个节点。节点间没有父子关系或者层次结构。这意味着Couchbase在存储容量和性能方面,都可以做到线性扩容。
集群管理
集群里的每个节点包含了集群管理器组件。集群管理器负责下述行为:
• 集群管理
• 节点管理
• 节点监控
• 可管理的REST API
• 统计报表
• 实时日志
• Multitenancy
• 访问安全
Buckets
Couchbase使用命名buckets提供数据管理服务,buckets是独立的虚拟数据容器。一个bucket就是Couchbase服务器集群里的一逻辑组物理资源,它可以被集群里的多个客户端应用使用。buckets提供安全的机制来组织、管理、分析数据存储资源。
Couchbase提供两种核心类型的buckets,如下描述。Couchbase根据bucket类型来提供运行时的统计报告。
• Couchbase类型:提供高可用和动态重配置的分布式数据存储,提供持久化存储和复制服务。这种bucket也100%兼容Memcached协议。
• Memcached类型:提供直接寻址的、分布式的、内存型的文本缓存。这种bucket被设计来作为关系型数据库的补充 — 缓存经常查询的数据,从而减少对数据库的查询量,提高性能。
不同的bucket类型提供不同的核心功能。Couchbase类型的bucket提供一种高可用、动态重配置、分布式的数据存储,在集群的节点发生故障时,它允许集群自我修复,并继续提供服务。
Couchbase bucket的特有功能
• 持久性:数据单元异步从内存写往磁盘,防范服务重启或较小的故障发生时数据丢失。持久性属性是在bucket级设置的。
• 复制:对couchbase类型的bucket,可以配置数据复制的份数。集群里的每个节点既保存活跃的数据,又保存数据副本。假如某个节点挂了,数据副本可以提升为活跃的容器,从而继续提供高可用服务。
• 重新组织:集群里的数据可以重新组织和分布,从而动态增加或删除bucket和服务器。
• bucket容积改变:couchbase类型的bucket可以动态调整容积,在应用需要时它们的大小可以被改变。
buckets可以用来隔离单个应用程序提供多租户,或隔离数据类型,以提高性能和可视性。couchbase服务器允许你配置不同的端口来访问不同的buckets,每个bucket都可以设置密码验证。
Smart client客户端通过使用couchbase的管理REST API,自动发现集群结构的改变。这点保证了客户端应用可以无间断的从正确节点上访问所需数据。
couchbase服务器允许你在生产环境里混合使用不同类型的buckets。内存和磁盘配额是基于bucket配置的,所以资源使用可以跨集群管理。配额可以在运行时修改,使得管理员能随时重新分配资源。
vBuckets
一个vBucket定义为couchbase集群里key空间的一个子集的拥有者。通过使用vBuckets,信息在集群里分发更有效。vBucket系统被用于分布式数据,以及支持多节点间的数据复制。
客户端在访问bucket里的数据时,是与存储了该数据的vBucket所在的集群节点进行通信。这种直接访问方式允许客户端与数据节点直接通信,而无需使用代理或重定向架构。其结果是从逻辑分区数据里抽象了物理拓扑,保证了couchbase的弹性服务。
这种架构也不同于memcached所用的方法,memcached使用客户端key哈希,从预定义的列表里选取服务器。这要求维护一份服务器的活跃列表,并指定哈希算法例如Ketama,以在拓扑里维护数据一致性。vBucket架构也比传统的RDBMS系统使用的数据分区更灵活。
vBuckets并非面向用户的组件,但它们是couchbase服务器里非常重要的组件,是至关重要的可用性和弹性服务的支承。
每个文档ID属于一个vBucket。有一个映射函数用来计算给定的文档属于哪个vBucket。在couchbase服务器里,该映射函数是个哈希函数,它取文档ID作为输入,输出vBucket标识符。一旦定位了vBucket标识符,会继续从一个表里查找该vBucket位于哪个服务器上。这个表包含每行一个vBucket,vBucket与它的宿主主机成对出现。位于该表里的服务器通常服务了多个vBuckets。
内存数据
Couchbase架构包含了一个内置的cache层。这种机制允许非常快速的响应时间,因为数据是直接写往内存的,并且读的时候,也是从内存返回数据给客户端。
这种设计的效果,提供了一个内置的cache层作为系统操作的中央部分延伸。客户端接口与内存数据打交道,它将信息写往Couchbase的内存;返回的数据也是从内存里获取,或者先从磁盘加载到内存,再返回给客户端。
这种处理方式保证了最佳性能。为了提高性能,你应该给每个节点分配最大数量的可用内存。内存跨集群汇总起来以供使用。
这点与其他数据库系统的设计不同,其他数据库的处理方式是,信息写往数据库,然后要么有一个独立的cache层,要么依赖于操作系统的cache机制,把经常使用的信息放在内存以供访问。
Ejection
Ejection是和Couchbase buckets一起使用的机制,它的作用是从内存里删除数据,给活跃的、更频繁使用的数据让出空间,它是cache系统的核心部分。Ejection自动执行,它联合磁盘持久存储系统,保证内存里的数据已经持久写往磁盘,从而安全的删除。
该系统确保内存存储的数据在删除前,已经写往磁盘,在下次客户端需要时,它又可以从磁盘加载到内存。Ejection的核心作用是让系统能够保持经常使用的数据驻留在内存,并且在客户端需要从磁盘加载数据时,它能重新在内存里分配空间。
对于Couchbase buckets,数据永不删除,除非客户端明确的删除文档,或者文档已到达过期时间。而ejection机制在从内存里删除数据时,会保存数据的副本到磁盘上。
Expiration
每个存在Couchbase里的文档有一个可选的过期时间(expiration)。默认是没有过期时间(例如,数据永久存储)。过期时间可用来设置数据的生命周期,系统自动从数据库里删除过期的数据。
在数据存储时,由用户指定文档的过期时间。在数据更新时,过期时间可以同步被更新,还可以通过couchbase协议手工更新。过期时间可以是相对时间(例如60秒),也可以是绝对时间(例如2012年12月31日中午12点)。
使用过期时间的典型场景是Web session。假如用户停止了活动,你希望session里的数据自动删除。通过设置expiration,session数据会过期并且自动删除,从而释放内存和磁盘给其他数据使用。
Eviction
Eviction是针对memcached buckets从内存里完全删除数据的过程。memcached使用一种LRU(最少近期使用)算法来从系统里完全删除不再使用的数据。
在memcached bucket里,LRU数据会完全删除以释放空间,因为memcached buckets没有持久化存储。
磁盘存储
为了提高性能,Couchbase倾向于在内存里存储数据和提供服务。然而,很难保证有足够的资源可以做到这点。比较常见的做法是把经常使用的工作数据存放在内存,并且快速响应给客户端。
除了尽可能多的存放数据在内存外,couchbase也保存数据到磁盘。磁盘持久性允许更容易的备份/恢复操作,也允许数据量增大到超过内置cache层的容量。
Couchbase自动在内存和磁盘间转移数据(在后台异步执行),保持经常使用的数据在内存,不经常使用的数据在磁盘。couchbase经常监控客户端访问的信息,让活跃的数据保留在cache层内。
将数据从cache里删除,腾出空间给更活跃信息使用的过程叫做ejection(前面的章节已描述)。通过couchbase集群里每个bucket的预先设定的阈值来决定何时执行ejection.
使用磁盘存储引发的问题是,客户端在请求文档ID时,必须知道信息是否存在。couchbase使用元数据结构来解决这个问题。元数据里存储了数据库里每个文档的信息,并且元数据位于内存里。这意味着假如文档ID无效,服务器可以立刻返回”document ID not found”消息。当然,如果文档有效,那么要么从内存里立刻返回,要么先从磁盘读取到内存再返回(从磁盘读会产生延时,或者导致超时)。
转移数据到磁盘的过程是异步的。在couchbase提供服务的同时,数据在后台异步转移到磁盘。如果并发写往数据库的量很大,客户端可能收到服务器内存临时不够的通知,直到更多数据转移到磁盘,内存有剩余为止。
类似的,假如couchbase需要从磁盘加载数据回内存,这个过程也是在后台发生的,后台进程从队列里读取请求,然后从磁盘读取数据装载回内存。客户端一直等待,直到数据加载到内存,然后返回给客户端。
这种异步机制以及使用队列的方式,使得读写处理非常快,从而消除了典型的负载和性能尖峰,这通常是造成RDBMS性能不稳定的原因。
热启动
当couchbase重启,或者执行备份恢复的启动时,它进入热启动的状态。热启动从磁盘加载数据到内存,从而让数据对客户端可用。
在服务请求之前,热启动必须完成。根据数据库容量和配置的不同,以及存储数据数量的不同,热启动可能要花费一定的时间来完成。
Rebalancing
数据在couchbase里的存储方式是通过vBucket结构提供的分布式机制来实现的。假如你想扩展或收缩couchbase集群,这时存储在vBuckets里的信息需要在集群节点间重新分布,并且对应的vBucket映射表也需要更新来适应新的结构。这个过程叫做rebalancing.
在集群的存储结构改变时,rebalancing必须手工执行。rebalance进程重新对存储信息的vBuckets进行分配,在集群节点间物理的转移数据,以匹配新的结构。
Rebalancing过程可以在集群运行并正常服务请求时执行。数据在后台进行转移,客户端的读和写仍然针对当前存在的结构,直到转移完成,系统会更新vBucket映射表,并将结果通知smart clients和Moxi proxy(它们是couchbase的客户端)。
其结果是整个集群的分布式数据重新分配,数据在整个数据库里均衡分布,并兼顾了支持系统运转的数据和数据副本的数量。
副本和复制
除了集群里的分布式数据外,couchbase还可以在集群里创建数据副本。这些副本也与vBucket结构协调工作,各个vBucket的数据副本在整个集群里分布。分布式副本跟核心数据的处理方式一样,而副本的存在可以防止集群里的单点故障。
集群里的副本复制是完全点对点的,数据在节点间直接交换,没有拓扑、层次或主从关系。客户端将数据写往一个节点时,数据被存在vBucket里,同时使用TAB系统分发到一个或多个副本vBucket.
在集群里的一个节点发生故障时,副本vBucket被激活,用来代替故障节点的vBuckets进行工作。这个过程秒完成,因为副本是在原始数据创建的同时就创建了,不会临时执行拷贝;副本vBucket已经持有数据在那里,坐等被激活。副本vBucket激活后,会更新系统的映射表,以便客户端直接与新的vBucket结构通信。
副本的配置是基于每个bucket的。根据数据安全层次的不同,你可以对不同的bucket配置不同数量的副本。请注意,只有在集群里的机器数量足够时,副本才可能被激活。例如,你配置了一个bucket保持3个副本,只有在集群里有4个节点时,副本才会激活。
一个bucket的副本数量,在bucket创建后不允许再修改。
Failover
数据的副本在整个集群里分布。对于couchbase类型的bucket你可以配置副本的数量,就是说在一个couchbase集群里对每份数据保存多少数量的副本。
在服务器发生故障时(不管是临时故障还是管理维护),可以使用称为failover的技术把故障节点标记为不可用,从而激活该服务器对应的副本vBuckets。
failover进程联系每个保存了副本的服务器,更新内部映射表,将客户端的请求映射到新的可用节点上。
可以手工执行failover,也可以使用内置的自动failover机制,在集群里的节点不可用超过一定时间后,failover自动打开。
TAP
TAP是couchbase集群的内部协议,在多个方面用来进行内部数据交换。TAP提供了系统内执行了变更的数据的数据流。
TAP被用于数据复制,在不同的vBuckets之间拷贝数据副本。它也用于rebalance过程,在vBuckets之间转移数据从而使数据在整个系统里重新分布。
客户端接口
有许多couchbase的客户端可用,它们归为2类,一类是smart clients,另一类是memcached兼容客户端。smart clients完全与集群进行通信,根据内置的集群配置和基于vBuckets的分布式信息,数据自动写往集群里的正确节点。smart clients与集群保持通信,确保在故障转移或者rebalancing时,客户端更新自己的配置,将数据写入到正确的节点。
如果使用非智能的memcached兼容的客户端,就必须使用一个位于客户端的Moxi组件。Moxi作为一个代理服务器存在,位于客户端连接和couchbase集群之间。除了让传统的memcached客户端可以写往couchbase集群,Moxi还提供了集群级的分布和接口。使用Moxi还让你在不改变任何已存在的memcached应用的前提下,获取couchbase的特有功能所带来的优势。
在couchbase服务器里,存储和获取信息的方式根据实际情况而不同。所有方法可以归类为CRUD这4类基本操作:Create(创建),Retrieve(获取),Update(更新),Delete(删除)。
创建
使用couchbase的客户端接口,根据文档ID将文档信息存储到数据库里。批量操作也可行,并且比多个单次操作更有效。
对于基本的存储、获取信息的操作,couchbase兼容memcached客户端协议。对于更高级的操作,你需要使用couchbase客户端库。
存储的值可以是任何二进制值,包括结构化和非结构化的串,序列化对象,或者原生的二进制数据例如图片或音频。
获取
为了获取数据,你必须先知道文档ID。也可以执行批量操作,同时获取多个文档,这比单次操作更有效。
更新
包括更新整个文档的操作,也包括追加数据到已存在记录的操作,或者递增和递减整数值。
删除
有个单一的删除操作,用来从数据库里删除整个文档。
各语言的库
couchbase官方支持下列语言和环境的smart clients库:
• Java (http://www.couchbase.com/develop/java/current)
• .NET (http://www.couchbase.com/develop/net/current)
• PHP (http://www.couchbase.com/develop/php/current)
• Ruby (http://www.couchbase.com/develop/ruby/current)
• C [libcouchbase] (http://www.couchbase.com/develop/c/next)
在笔者写此书时,也有一个实验性的Python库可用(http://www.couchbase.com/develop/python/current)。Mark Nunberg还写了个Perl客户端Couchbase::Client,它基于C的libcouchbase库。你可以在CPAN上获取到这个库。
Proxy (Moxi)
Couchbase的Moxi组件提供了一个代理服务,允许传统的memcached客户端在不修改应用的前提下,使用couchbase服务。该代理服务提供了在客户端和服务器之间的连接池,在couchbase集群的内部拓扑变更时,它及时通知客户端,从而保证了信息在集群里分布正确。
假如你使用了smart clients客户端库,就不必使用Moxi。
Moxi可以部署在服务端,也可以在客户端。产品环境里在服务端部署Moxi可能会带来问题,建议只部署在客户端。
管理工具
Couchbase被设计为尽可能易用,不要求管理员太多的关注,除了监控健康状态和容量。系统提供了三种途径来管理和监控couchbase服务器和集群。
• Web管理控制台
Couchbase包含一个内置的web管理控制台,提供了完整的接口功能,包括配置、管理、监控你的服务器。
• 命令行接口
Couchbase提供了一套命令行工具,用于控制和访问couchbase服务器和集群。可以结合命令行和你自己的脚本和管理过程,来提供附加的功能,比如自动故障转移、备份等。
• 管理REST API
Web控制台和命令行工具都利用了内置的REST API,API提供了完整的管理功能。所有的管理功能都通过REST API提供,并且它扮演了服务器的认证接口的角色。
因为REST API提供了完善的功能,你可以在自己的管理脚本或程序里使用它,来实现不同的操作。
统计和监控
为了了解couchbase集群正在做什么以及如何执行,系统提供了完整的统计和监控信息。统计信息在所有的管理接口都可以看到。统计系统非常完整,你可以监控和定位到每一个细节。监控系统健康的核心统计报表通过web控制台提供,该报表使用内置的实时图形,允许你实时监控系统的健康和性能状况。
Hello Couchbase
Couchbase存储信息时,信息的值为文档,键是文档ID。这使得开发和部署应用非常简单。在存储信息时,提供文档内容和对应的文档ID。在获取信息时,提供文档ID就可以获取到对应的值。
只要你知道文档ID,就总可以获取到信息的内容。数据简单的按字节顺序存放。这意味着你既可以存放裸信息(例如字串或整数)、复杂的数据结构(例如JSON),也可以存放序列化对象。序列化会转换特定语言的原生对象为合适的字节串,今后从服务器里获取时,它们又可以还原为对象。
基本的存取过程非常简单。下述示例里我使用了Ruby,不过其他语言的客户端都以相同方式工作,因为它们都使用了相同的核心协议。
安装了ruby客户端库后,就可以编写一段简单的程序来存放信息到couchbase,然后再获取信息。如下是示例的hello-wrold.rb程序:
require 'rubygems'
require 'couchbase'
client = Couchbase.new "http://127.0.0.1:8091/pools/default"
client.quiet = false
begin
spoon = client.get "spoon"
puts spoon
rescue Couchbase::Error::NotFound => e
puts "There is no spoon."
client.set "spoon", "Hello World!", :ttl => 10
end
• 头两行加载必要的库
• 下一行打开到couchbase集群的连接。此处定义里,URL必须指向集群里的至少一个节点,这里是本机地址。default表示bucket名字,你可以使用其他bucket,假如已经配置了。
• 后面的行执行获取和存储操作。假如初次获取操作(针对spoon这个ID)失败,我们就将数据写入到DB里。只要文档ID存在,脚本就打印出对应的存放值。
你可以从命令行运行和测试该脚本。第一次运行时,应该输出这个错误串:
shell> ruby hello-world.rb
There is no spoon.
指定的文档并没有存在于数据库,但随后就加进去了。第二次运行时,就可以打印文档的值:
shell> ruby hello-world.rb
Hello World!
此外,字串文档在存储时,赋予了一个过期时间10秒。这意味着在存放信息后,等待超过10秒信息就被删除了。假如首次运行脚本后,超过10秒再第二次运行该脚本,会输出如下错误串:
shell> ruby hello-world.rb
There is no spoon.
尽管这是一个非常简单的示例程序,它描述了使用基本的get/set操作,在couchbase里存取信息的原理。
客户端与集群的交互
在开发应用时,最常见的问题是,客户端和客户端库如何与集群通信,如何适应运行中集群的拓扑结构改变。通常而言,在客户端与数据库交互中,couchbase扮演一个黑盒子。假如你使用了smart client,集群的拓扑、节点结构,以及对应信息的变更,完全由vBucket映射表和客户端库联合起来自动处理。
客户端库负责客户端与集群中各个节点的直接通信。你用来初次建立连接的那个节点,不会扮演代理或网关的角色。smart client(或Moxi)会加载vBucket映射表,从映射表里学习到把不同信息存储到集群里的哪个节点。客户端直接与正确的节点通信,中间没有代理或网关。
在拓扑结构改变时(例如,rebalance或者故障转移),客户端库自动处理任何临时的错误。总之而言,你不必关心任何集群的配置与拓扑相关信息。
关于客户端与集群的通信机制,请见之前的文档,Couchbase的Smartclient有何作用
过期时间
过期时间(time to live [TTL])的用途是,在存储信息时设置一个超时值,它让文档自动过期删除。除了delete()函数外,文档的过期值是从数据库里删除信息的唯一方法。一旦过期时间到了,数据就会删除。
过期时间设置为一个数字,它代表秒数。如果这个数字代表的秒数,小余30天(30*24*60*60秒),这个值就是相对值。例如,3600秒表示文档在一个小时后过期。如果秒数大于30天,过期值就是绝对值,表示从epoch时间以来的绝对秒数。
过期时间可以用在不同的应用场景,但最普通的场景是使用它存储session数据。例如你可以用它存储session并设置过期时间2小时,用户如果超过2小时没访问网站,session自动删除。
如果用户还在访问数据,可以使用touch()和getAndTouch()函数来更新过期时间,不必另外执行数据更新操作来更新过期值。
除了过期时间,所有文档在存储时也带了一系列标签(flags)。并非所有的客户端库都支持标签,但如果支持,你可以用标签来增加文档描述信息,例如文档类型。
【注】这次测试中,遇到了一些问题,因此本文用E文编写,随后发到Couchbase社区咨询一下。
We have five nodes as the couchbase cluster, the servers have enough memory and disk, with ubuntu 12.04 OS. Couchbase server version: 2.0.1 community edition (build-170). I use the default bucket for test, it has been assigned 5GB memory totally.
The test Ruby script is as below:
require 'couchbase'
require 'securerandom'
client = Couchbase.connect("http://couch.example.com:8091/pools/default/buckets/default"
100000.times do |s|
value_10k = SecureRandom.hex(5120)
key_uuid = SecureRandom.uuid
begin
client.set key_uuid, value_10k, :ttl => 3600
rescue Couchbase::Error::Base => e
puts e
end
end
More »
文档数据
文档数据是纯字节序列,服务器不会试图去解析或理解存储的文档格式。这意味着你可以存储从数字到图片的任何东西。这种开放的存储结构,也意味着不必去声明或定义要存储信息的结构,你可以充分灵活的自己定义所需要的结构。
存储简单的信息,例如数字或字串,只需简单的将数据写进文档值。存储复杂的信息结构,你可能需要序列化对象,或者更通用的JSON结构。
序列化
序列化将特定语言的复杂的内部结构,例如hash或对象,转换为字节序列,从而可以存储在couchbase里。序列化的结构还能被还原成原来的数据结构,从而被特定的语言直接使用。
所有的couchbase客户端库在存取文档时,都自动支持序列化和反序列化结构或对象。
JSON
序列化信息的问题是,它是语言约定的。假如你在Java里存储一个对象或数据结构到couchbase,它被序列化为一个只有java语言库才能识别的串。假如要跨语言进行信息存储,你需要使用更通用的格式,比如JSON。
JSON之所以流行,一是因为它很简洁(它看起来像许多脚本语言的内置hash结构),二是它可以被Javascript直接使用,这样在web基础的应用里,不必对它做特别处理。
JSON的格式有良好的描述,详见http://json.org. 在couchebase里使用JSON的最好方法是,每条记录存储一个JSON哈希结构。例如,可以定义一条啤酒记录如下:
{
"id": "beer_Hoptimus_Prime",
"type": "beer",
"abv": 10.0,
"brewery": "Legacy Brewing Co.",
"category": "North American Ale",
"name": "Hoptimus Prime",
"style": "Imperial or Double India Pale Ale",
}
许多语言支持类似的hash、hashmap或关联数组结构,有相应的库可以将hash结构转换为JSON格式,并还原它们。
请注意:couchbase 2.0在使用JSON存储信息时,允许你使用查询和索引的高级功能。
在couchbase里存储数据
couchbase是一个严格的文档型数据库。这就意味着,信息根据文档ID存储在数据库里。没有必要设置数据格式、创建表结构,甚至不需要告诉couchbase关于要存储的信息。你要做的所有工作就是根据指定文档ID存储文档数据。
因为文档的结构原因,在开发应用时有一些不同的考虑点。让我们了解下文档ID和文档值的基本因素。
文档ID
文档ID(或key)非常重要,它用来索引存储的数据。key在一个bucket里必须是唯一的。
key用来标识所存储的信息,可以是任意字串,通常最大长度128位。couchbase没有机制为你自动创建文档ID。假如使用UUID,就必须在你自己的程序里使用对应的UUID库。
通常实践是,使用前缀、类型、分隔符来区分存储在每个bucket里的不同信息。例如,可以使用beer_9834759这个ID来存储关于啤酒的信息。这里的beer前缀标识记录类型,下划线作为分隔符,后面的数字作为唯一的啤酒ID。
couchbase 1.8没有获取文档ID列表的功能,也不能遍历一个bucket里的所有文档。除非指定文档ID,你不能查询信息。然而,这一点会在couchbase 2.0里予以改进和支持。
针对上述问题的一个解决方案是在应用里创建信息链。例如,当一个新的啤酒记录追加到数据库里时,你可以更新一个beer_list的文档,它包含了所有的啤酒记录ID。因为更新是原子性的,所以可以维护这么一份最新的信息列表。实践做法可以参考这篇博客:https://blog.couchbase.com/maintaining-set-memcached
应用程序可以通过使用和读取一个固定的记录来引导自身的数据查询,这个记录要么是本地的配置,要么是在数据库里的配置记录。
CAS机制
除了核心函数外,还有一个特殊函数叫做CAS (compare and swap). CAS提供了一个校验合,让多个客户端在同时更新文档时避免产生冲突。
例如,考虑如下场景:
1. 客户端A获取到文档Martin的值
2. 客户端B也获取到文档Martin的值
3. 客户端A修改文档,并更新到数据库
4. 客户端B也修改文档,并更新到数据库
在上述场景里,客户端B的修改会覆盖掉A修改的值。
为了解决这种情况,可以使用cas()函数。它要求提供从数据库里返回的唯一的CAS值。CAS值在文档更新时,每次都会改变,即使文档更新后的内容不变。将更新发送到服务器时,假如客户端提供的CAS值与服务器里当前存储的CAS不匹配,更新就会失败。
使用CAS后的应用场景如下:
1. 客户端A获取到文档Martin的值,以及对应的CAS值
2. 客户端B也获取到文档Martin的值,以及对应的CAS值
3. 客户端A修改了文档,并且提交到数据库,同时提交CAS,本次更新成功,数据库也同步更新CAS
4. 客户端B也修改了文档,并且尝试使用CAS进行数据库更新,本次更新失败,因为客户端的CAS与服务器存储的CAS现在不同了
因此,CAS提供了一种检查机制,保证你当前更新的文档自上次获取以来,没有发生变更过。
在编程代码里,CAS是一个类似于update()的函数。取决于环境的不同,你可能先要使用gets()函数来获取到文档信息和CAS值。
例如,在java里先用gets()获取文档信息和CAS值,接着用cas()方法来更新文档:
1
2
3 CASValue customer = client.gets("customer";
CASResponse casr = client.cas("customer", customer.getCas(), "new string value";
CAS的局限性是在客户端库这一级并没有强制执行它。假如你想对所有的更新操作使用CAS,就必须明确的使用它来代替标准的文档更新函数。
在google groups里建立了一个Couchbase中文讨论组:
Couchbase是开源分布式、面向文档的NoSQL数据库。它是基于集群设计的,通过它的web管理系统,很容易配置一套高性能的集群。扩容方便,性能随着容量增加而线性增加。包括AOL、Linkedin、Zynga等公司在使用它。风河博客(www.nsbeta.info)翻译了一系列关于Couchbase的文档。
对Couchbase有兴趣童鞋可使用Gmail加入讨论。论坛地址:
https://groups.google.com/d/forum/couchbase-china
couchbase支持的core协议和操作方法如下表所示。
不管客户端库如何,这些函数在各种语言里工作方式都差不多,可能在语言自己的实现规范上有所不同。例如,可以在ruby里增加一个值:
1 couchbase.incr("counter", 5)
在.NET里,函数调用是:
1 client.Increment("counter", 100, 1);
上述第二个参数是假如指定文档ID不存在时的默认值。
基本操作
couchbase基于文档ID,执行非常简单的文档存取模型。在存储信息时,不需要定义表或结构,不需要写复杂的查询去获取信息。
couchbase里的所有操作遵循下列规则:
• 所有操作是原子性的
这意味着服务器里没有锁机制,不可能存在来自多个客户端的并发命令破坏了数据。然而,这也意味着如果多个客户端对同一文档ID执行set操作,只有最后一个操作有效。为了管理这种并发和竞争条件,可以使用CAS操作。这要求提供一个附加的校验值,在校验值不合的情况下,文档不会被更新。
• 所有数据操作都要求key
所有对数据的操作,都要求提供一个key。不能执行全局操作,或者针对多个key的操作(multiple-get除外)。
• 没有内部锁
在存储或更新数据时,系统并没有一个内部锁。操作要么完全成功,要么因为某种理由失败(例如,临时内存不足)。
不同的客户端语言执行core协议,从而与couchbase服务器通信:
• 所有客户端执行core协议
对不同的语言和环境,尽管在结构和函数名字上有些不同,但它们都执行同样的核心操作协议。例如,所有实现里都有set()协议调用,尽管有些客户端把它叫做”store”.
• 函数调用结构差异
因为不同的语言和环境的差异,对于core协议的函数调用结构也许不同。例如在java里,可变参数方法不可用,因而有多个同一函数的变体。在其他语言里,例如perl、python、ruby,hash是核心变量类型,经常被用来存储和返回信息。
• 不同的语言提供额外的功能
某些客户端实现提供额外的函数调用和结构,这些是原生core协议所没有的。例如在java里,所有操作既可以是同步也可以是异步的,允许你在get或set操作时,继续处理其他信息。
• 并非所有实现支持标签
标签在服务器里和数据一起存储,并非被所有语言的客户端支持。
配置选项
为了得到最佳的couchbase服务器和客户端环境,你应该使用couchbase客户端的一种。这些smart clients结合了核心接口协议(用来存取数据)和管理协议。后者允许客户端直接与couchbase集群通信,理解vBucket映射表,以便信息能直接发送到集群里的单个节点。在故障转移或rebalance时,同样的机制允许vBucket映射表的变更快速生效。
couchbase直接支持六种客户端库:
• Java
• .NET
• PHP
• Ruby
• C (libcouchbase)
• Python
上述每种都叫做smart client,提供了系统关键功能和集群管理配置的最佳组合。可以从这里了解更多信息:http://www.couchbase.com/communities/all-client-libraries
假如你想使用memcached兼容的库,或者你的应用已经使用了这种协议,那么建议用Moxi服务,它在兼容memcached的同时,又利用了couchbase集群架构的优势。
Moxi代理服务在memcached协议和couchbase集群之间扮演接口角色。couchbase在协议级100%与memcached兼容。你应当在每个客户端安装Moxi,配置Moxi连接到couchbase集群,然后本地程序使用localhost作为主机名连接到Moxi服务。更多信息请参考couchbase官方文档:http://www.couchbase.com/documentation
尽管couchbase兼容memcached协议,但是某些高级couchbase协议是memcached不支持的,这些优势就会利用不上。
Couchbase集群和Redis集群解析的更多相关文章
- Linux(ubuntu)安装redis集群,redis集群搭建
今天学习一下redis集群的搭建.redis在现在是很常用的数据库,在nosql数据库中也是非常好用的,接下来我们搭建一下redis的集群. 一.准备 首先我们要安装c语言的编译环境,我们要安装red ...
- 【集群】Redis集群设计原理
Redis集群设计包括2部分:哈希Slot和节点主从 节点主从: 主从设计不算什么新鲜玩意,在数据库中我们也经常用主从来做读写分离,直接上图: 图上能看得到的信息: 1, 只有1个Master,可以有 ...
- redis单点、redis主从、redis哨兵sentinel,redis集群cluster配置搭建与使用
目录 redis单点.redis主从.redis哨兵 sentinel,redis集群cluster配置搭建与使用 1 .redis 安装及配置 1.1 redis 单点 1.1.2 在命令窗口操作r ...
- 支撑微博亿级社交平台,小白也能玩转Redis集群(原理篇)
Redis作为一款性能优异的内存数据库,支撑着微博亿级社交平台,也成为很多互联网公司的标配.这里将以Redis Cluster集群为核心,基于最新的Redis5版本,从原理再到实战,玩转Redis集群 ...
- Redis 集群规范
什么是 Redis 集群??Redis 集群是一个分布式(distributed).容错(fault-tolerant)的 Redis 实现,集群可以使用的功能是普通单机 Redis 所能使用的功能的 ...
- Dubbo入门到精通学习笔记(十五):Redis集群的安装(Redis3+CentOS)、Redis集群的高可用测试(含Jedis客户端的使用)、Redis集群的扩展测试
文章目录 Redis集群的安装(Redis3+CentOS) 参考文档 Redis 集群介绍.特性.规范等(可看提供的参考文档+视频解说) Redis 集群的安装(Redis3.0.3 + CentO ...
- 搭建分布式 Redis Cluster 集群与 Redis 入门
目录 Redis 集群搭建 Redis 是啥 集群(Cluster) Redis Cluster 说明 Redis Cluster 节点 Redis Cluster 集群模式 不能保证一致性 创建和使 ...
- 分布式缓存技术redis学习系列(四)——redis高级应用(集群搭建、集群分区原理、集群操作)
本文是redis学习系列的第四篇,前面我们学习了redis的数据结构和一些高级特性,点击下面链接可回看 <详细讲解redis数据结构(内存模型)以及常用命令> <redis高级应用( ...
- 离线安装redis集群
Step0:redis集群组件需求 Step1:离线安装ruby Step2:离线安装rubygems Step3:安装rubygems的 redis api Step4:离线安装tcl 8.6 St ...
随机推荐
- 利用css新属性appearance优化select下拉框
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...
- css+html简单的布局demo
于html介绍css作风.可以改变html块状布局,局更加美观.接下来看一个基础布局的小样例: <html> <head> <meta http-equiv=" ...
- Advance Installer安装问题
一,在Advance Installer中注冊dll 1,首先将文件加入到Files And Folders中.此处以InstallValidate.dll为例. 2,在Custom Action处进 ...
- Google软件构建工具Bazel
转载Google软件构建工具Bazel FAQ 本文是我的翻译,原文在这里.欢迎转载,转载请注名本文作者和原始链接注:如果想了解Bazel的原理,可以看看我之前翻译的Google Blaze原理及使用 ...
- Redis源代码分析(一)--Redis结构解析
从今天起,本人将会展开对Redis源代码的学习,Redis的代码规模比較小,很适合学习,是一份很不错的学习资料,数了一下大概100个文件左右的样子,用的是C语言写的.希望终于能把他啃完吧,C语言好久不 ...
- foj 2082 树链剖分 第2天
擦,没啥好说的,这个模板至少得打10遍..纪念自己成功的打错了.. #include <iostream> #include <cstdio> #include <cst ...
- python tcp socket 多线程
不多说,直接上代码 client.py #!/usr/bin/python import socket,sys,string host="localhost" port=8000 ...
- RethinkDB创始人教你如何打造一个伟大的互联网产品
关于作者 我叫Slava Akhmechet,本人是 RethinkDB 的创始人之一,RethinkDB是开源,分布式数据库,旨在帮助开发人员与运营商在打造实时应用时处理无结构数据 如何打造一个伟大 ...
- 查看oracle数据库服务器的名字
原文:查看oracle数据库服务器的名字 windows 中 1. select name from v$database ; 直接运行就可以查看了, 2.查看tnsnames.ora 的连接,有个S ...
- python向mysql中存储JSON及Nodejs取出
虽然把JSON数据存入mysql也是比较蛋疼,但是相比使用Nodejs嵌套处理多个mysql查询并拼接返回数据也算是没mongo时的一个折中方案了. 我使用python拼接了一个json格式的字符串, ...