今天我们来说一说Zookeeper内部原理中的请求、事务和标识符
返璞归真:ZooKeeper内部原理——请求、事务和标识符ZooKeeper服务器会在本地处理只读请求(exists、getData和getChildren)。假如⼀个服务器接收到客户端的getData请求,服务器读取该状态信息,并将这些信息返回给客户端。因为服务器会在本地处理请求,所以ZooKeeper在处理以只读请求为主要负载时,性能会很⾼。我们还可以增加更多的服务器到ZooKeeper集群中,这样就可以处理更多的读请求,⼤幅提⾼整体处理能⼒。
那些会改变ZooKeeper状态的客户端请求(create、delete和setData)将会被转发给群⾸,群⾸执⾏相应的请求,并形成状态的更新,我们称为事务(transaction)。其中,请求表⽰源⾃于客户端发起的操作,⽽事务则包含了对应请求处理⽽改变ZooKeeper状态所需要执⾏的步骤。我们通过⼀个简单点的例⼦,⽽不是ZooKeeper的操作,来说明这个问题。
假如,操作为inc(i),该⽅法对变量i的值进⾏增量操作,如果此时⼀个请求为inc(i),假如i的值为10,该操作执⾏后,其值为11。再回过头看请求和事务的概念,其中inc(i)为请求,⽽事务则为变量i和11(变量i保存了11这个值)。
现在我们再来看看ZooKeeper的例⼦,假如⼀个客户端提交了⼀个对/z节点的setData请求,setData将会改变该znode节点数据信息,并会增加该节点的版本号,因此,对于这个请求的事务包括了两个重要字段:节点中新的数据字段值和该节点新的版本号。当处理该事务时,服务端将会⽤事务中的数据信息来替换/z节点中原来的数据信息,并会⽤事务中的版本号更新该节点,⽽不是增加版本号的值。
返璞归真:ZooKeeper内部原理——请求、事务和标识符⼀个事务为⼀个单位,也就是说所有的变更处理需要以原⼦⽅式执⾏。以setData的操作为例,变更节点的数据信息,但并不改变版本号将会导致错误的发⽣,因此,ZooKeeper集群以事务⽅式运⾏,并确保所有的变更操作以原⼦⽅式被执⾏,同时不会被其他事务所⼲扰。在ZooKeeper中,并不存在传统的关系数据库中所涉及的回滚机制,⽽是确保事务的每⼀步操作都互不⼲扰。在很长的⼀段时间⾥,ZooKeeper所采⽤的设计⽅式为,在每个服务器中启动⼀个单独的线程来处理事务,通过单独的线程来保障事务之间的顺序执⾏互不⼲扰。最近,ZooKeeper增加了多线程的⽀持,以便提⾼事务处理的速度。
同时⼀个事务还具有幂等性,也就是说,我们可以对同⼀个事务执⾏两次,我们得到的结果还是⼀样的,我们甚⾄还可以对多个事务执⾏多次,同样也会得到⼀样的结果,前提是我们确保多个事务的执⾏顺序每次都是⼀样的。事务的幂等性可以让我们在进⾏恢复处理时更加简单。当群⾸产⽣了⼀个事务,就会为该事务分配⼀个标识符,我们称之为ZooKeeper会话ID(zxid),通过Zxid对事务进⾏标识,就可以按照群⾸所指定的顺序在各个服务器中按序执⾏。服务器之间在进⾏新的群⾸选举时也会交换zxid信息,这样就可以知道哪个⽆故障服务器接收了更多的事务,并可以同步他们之间的状态信息。
zxid为⼀个long型(64位)整数,分为两部分:
- 时间戳(epoch)部分
- 计数器(counter)部分。
每个部分为32位,在我们讨论zab协议时,我们就会发现时间戳(epoch)和计数器(counter)的具体作⽤,我们通过该协议来⼴播各个服务器的状态变更信息。
网友评论