k8s

etcd中version,revision,mod_revision,create_revision的区别

问题

etcd存储数据的过程中,在状态机里即MVCC模块中,kvIndex和boltdb存储了多个“version”,每个“version”的区别在哪里呢?

解决

实现

可以从代码里看到具体的实现。
当get某一个key时返回的是一个 RangeResponse。

type RangeResponse struct {
 Header *ResponseHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
 // kvs is the list of key-value pairs matched by the range request.
 // kvs is empty when count is requested.
 Kvs []*mvccpb.KeyValue `protobuf:"bytes,2,rep,name=kvs,proto3" json:"kvs,omitempty"`
 // more indicates if there are more keys to return in the requested range.
 More bool `protobuf:"varint,3,opt,name=more,proto3" json:"more,omitempty"`
 // count is set to the number of keys within the range when requested.
 Count                int64    `protobuf:"varint,4,opt,name=count,proto3" json:"c
}

RangeResponse结构体中,Header是响应头,里面有很多系统信息,Kvs是我们获得的 kv 数组,包括了返回数据。

type ResponseHeader struct {
 // cluster_id is the ID of the cluster which sent the response.
 ClusterId uint64 `protobuf:"varint,1,opt,name=cluster_id,json=clusterId,proto3" json:"cluster_id,omitempty"`
 // member_id is the ID of the member which sent the response.
 MemberId uint64 `protobuf:"varint,2,opt,name=member_id,json=memberId,proto3" json:"member_id,omitempty"`
 // revision is the key-value store revision when the request was applied.
 // For watch progress responses, the header.revision indicates progress. All future events
 // recieved in this stream are guaranteed to have a higher revision number than the
 // header.revision number.
 Revision int64 `protobuf:"varint,3,opt,name=revision,proto3" json:"revision,omitempty"`
 // raft_term is the raft term when the request was applied.
 RaftTerm             uint64   `protobuf:"varint,4,opt,name=raft_term,json=raftTerm,proto3" json:"raft_term,omitempty"`
}

ResponseHeader 中里有 Revision: revision is the key-value store revision when the request was applied。
revision存储的是k-v,每有一个请求,revision都会发生变化。

type KeyValue struct {
 // key is the key in bytes. An empty key is not allowed.
 Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
 // create_revision is the revision of last creation on this key.
 CreateRevision int64 `protobuf:"varint,2,opt,name=create_revision,json=createRevision,proto3" json:"create_revision,omitempty"`
 // mod_revision is the revision of last modification on this key.
 ModRevision int64 `protobuf:"varint,3,opt,name=mod_revision,json=modRevision,proto3" json:"mod_revision,omitempty"`
 // version is the version of the key. A deletion resets
 // the version to zero and any modification of the key
 // increases its version.
 Version int64 `protobuf:"varint,4,opt,name=version,proto3" json:"version,omitempty"`
 // value is the value held by the key, in bytes.
 Value []byte `protobuf:"bytes,5,opt,name=value,proto3" json:"value,omitempty"`
 // lease is the ID of the lease that attached to key.
 // When the attached lease expires, the key will be deleted.
 // If lease is 0, then no lease is attached to the key.
 Lease                int64    `protobuf:"varint,6,opt,name=lease,proto3" json:"lease,omitempty"`
}

KeyValue 里有:
CreateRevision:create_revision is the revision of last creation on this key。创建key时的版本信息。
ModRevision:mod_revision is the revision of last modification on this key。key最新修改的版本信息。
Version:version is the version of the key. A deletion resets the version to zero and any modification of the key increases its version。key的版本信息,key删除版本重置为0,key修改,版本增加。

watch时的revision:

for {
  rch := watcher.Watch(ctx, path, clientv3.WithRev(revision))
  for wresp := range rch {
        ......
  }
 }

验证

首先查看当前revision

"revision": 25023542

etcdctl endpoint status -w json | jq

file

写入数据

etcdctl put /foo bar
etcdctl get /foo -w fields

可以看到key /foo : "Revision" : 25031899,"CreateRevision" : 25031837",ModRevision" : 25031837,"Version" : 1
此时CreateRevision=ModRevision。

file

修改数据

etcdctl put /foo barr
etcdctl get /foo -w fields

可以看到key /foo : "Revision" : 25033644,"CreateRevision" : 25031837,"ModRevision" : 25033596,"Version" : 2
只有CreateRevision没有变,其他都发生了变化,version自增为2。

file

添加其他数据

etcdctl put /bar foo
etcdctl get /bar -w fields

可以看到key /bar : "Revision" : 25035136,"CreateRevision" : 25035081,"ModRevision" : 25035081,"Version" : 1
可以看到key /foo : "Revision" : 25035977,"CreateRevision" : 25031837,"ModRevision" : 25033596,"Version" : 2
添加其他数据对原有key /far没有影响,只有Revision发生了变化。

file

删除数据

etcdctl del /foo
etcdctl put /foo bar
etcdctl get /foo -w fields

可以看到key /foo : "Revision" : 25037033,"CreateRevision" : 25036999,"ModRevision" : 25036999,"Version" : 1
删除数据后,version重置为1,CreateRevision和ModRevision都为新值且相等,Revision一直在变化。

file

综上,可以得出结论:

  • Version:作用域为 key,某一个 key 的修改次数(从创建到删除),与其他 Revision 无关。
  • Revision:作用域为集群,逻辑时间戳,全局单调递增,任何 key 修改都会使其自增。
  • ModRevision:作用域为 key,等于修改这个 key 时的 Revision,只要这个 key 更新都会改变。
  • CreateRevision:作用域为 key,等于创建这个 key 时的 Revision,直到删除前都保持不变。

watch

查看当前版本

当前key /foo : "Revision" : 25037033,"CreateRevision" : 25036999,"ModRevision" : 25036999,"Version" : 1。

开始watch

etcdctl watch /foo -w fields --rev=25036999

从当前版本25036999开始watch,报错“watch was canceled (etcdserver: mvcc: required revision has been compacted”,这是因为这个版本已经被压缩了,需要从最近的revision开始watch。

file

etcdctl get /foo -w fields
etcdctl watch /foo -w fields --rev=25041798

file

修改,删除,添加key /foo,添加key /fooo。

etcdctl put /foo barr
etcdctl del /foo
etcdctl put /fooo barr
etcdctl put /foo bar

watch只有key /foo的三条输出,并没有key /fooo。
file

综上可以得出结论:

  • watch 某一个 key 时:想要从历史记录开始就用CreateRevision,最新数据就用ModRevision。但要注意revision是否被compacted。
  • watch 某个前缀:必须使用 Revision。
分类: k8s
0 0 投票数
文章评分
订阅评论
提醒
guest

0 评论
最旧
最新 最多投票
内联反馈
查看所有评论

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部
0
希望看到您的想法,请您发表评论x