存储和一致性
文档提供了一个Crate怎么存储和分布其集群状态的概览,以及一致性和持久性的保证。
注意 由于Crate在很大程度上依赖于Elasticsearch和Lucene的存储和集群,Elasticsearch的用户看到这里的概念可能会很眼熟,因为实际上是从ElasticSearch的代码中重用的。
数据存储
Crate中每个表都是分片的,也就说表被切分存储在一个集群的多个节点之间。Crate中的每一个分片时一个Lucene的索引被分成段存储在文件系统上。物理上文件驻留在节点配置的数据目录下。
Lucene仅仅向段文件里追加数据,这意味着写入磁盘的文件将永远不会变。这使得复制和恢复很容易,因为同步分片只是简单地从特定的标记获取数据。
可以为每个表配置任意数量的副本分片。每个可操作的副本都保存一个和主分片完全同步的副本。
对于读操作,在主分片或任何副本分片上执行是没有区别的。Crate当执行路由操作时将随机分配分片。如果有必要可以配置此行为。更多细节,查看我们的多区域最佳实践指南。
写操作和读操作处理完全不同。这些操作在所有活动副本上以如下的方式来同步:
1.给定的操作下,将会在集群状态中查找主分片和活动的副本分片。这一步要成功,主分片和配置的副本分片的仲裁必须可用。
2.操作被路由到相应的主分片以便执行。
3.该操作在主分片上执行。
4.如果操作在主分片上执行成功,则将对所有副本并行执行此操作。
5.在所有副本的操作都执行完了,操作结果将会返回给调用者。
任何副本分片在步骤5中写数据失败后或者写超时,则将会立即被视为不可用。
文档级别的原子性
在Crate中,表的每一行是一个半结构化的文档,可以通过使用对象和数据类型任意嵌套。
对文档的操作都是原子的。这意味着在一个文档上的写操作作为一个整体成功或者没有任何影响。不管文档的嵌套深度的大小如何,都是这种情况。
Crate不提供事务。一旦Crate中的文档被赋予一个版本号,它将在每次变化后增长,所以像乐观并发控制这样的模式(参见使用Crate的乐观并发控制)可以帮助解决这个限制。
持久性
而一个分片有一个预写式日志,也被称为translog。他保证对文档的操作将持久化到磁盘,而不必为每个写操作发出Lucene-Commit操作。当translog被刷新时,所有的数据被写入Lucene的持久索引存储库,并且translog被清除。
在分片不正常关闭的情况下,tranlog中的事务在启动时被重放,以确保所有的操作时永久性的。
当一个新分配的副本从主分片初始化自己时也会直接传送translog。而不需要将段刷新到磁盘仅仅是为了副本分片的恢复。
文档的地址
每个文档都有一个内部的标识(查看 _id)。默认情况下,此标识派生自主键。生成在没有主键的表中,文档在创建时会自动分配一个唯一自动生成的ID。
每个文档使用路由关键字来路由到一个特定的分片。默认情况下这个key是列_id的值。然而这可以在表模式定义中来设置(查看路由)。
虽然对用户透明,但内部有两种方式如何创建已访问的文档:
get:
直接使用标识访问。仅当路由关键字和标识可以从给定的查询规范中计算出来。(了如:在where子句中指定完整主键)
这是访问文档的一个最有效的方法,因为只有一个分片被访问,并且只需要在_id字段上进行简单的索引查找。
search:
通过匹配表的所有候选分片中的文档字段进行查询。
一致性
Crate对于搜索操作最终是一致的。搜索操作在共享的indexReaders上执行,除了其他的功能外,还为碎片提供缓存和反向查找。一个IndexReader总被绑定从它启动的段,这意味着它被刷新才能看到新的更改,这会基于时间的方式也可以手动完成。因此,如果indexReader在变化后刷新,搜索将会看到一个更改。
如果一个查询规范导致在一个get操作,更改立即可见。这是通过首先在translog中查询实现的,该文档将始终具有文档的最新版本。因此,公共更新和获取使用情况是可能的。如果客户端更新一行而且更改后通过其主键查找该行,更改始终可见,因为直接从translog中检索信息。
注意
每个副本分片和它的主分片同步更新而且存储同样的信息。因此访问主分片和副本分片是一致的。只有刷新IndexReaderaffects的一致性。
集群元数据
集群元数据保存在所谓的“集群状态”中,其中包含以下信息:
- Tables schemas(表的模式)
- 主分片和副本分片的位置。基本上是从分片号到存储节点的映射。
- 每个分片的状态,将指示着分片当前是否已准备好使用,或者有其它状态,例如“初始化”,“恢复”或根本不能分配。
- 有关已发现节点和它们的状态的信息。
- 配置信息。
每个节点都有对集群状态的一份拷贝。然而只有一个节点允许在运行期间改变集群状态。这个节点被称作“主”节点而且是被自动选举出来的。“主”节点没有特殊的配置,任何在集群中节点都可以被选举为主节点。如果当前的主节点由于某种原因宕机也会自动重新选举。
注意
避免这样一个场景,因为网络分区化而选举出两个主节点,集群需要定义一个仲裁的节点数,用来选举主节点。更多的细节请看主节点的选举。
解释一系列导致集群状态变化的事件-这里有一个改变表模式的“ALTER TABLE”语句:
1.一个在集群中的节点接收到ALTER TABLE的请求。
2.节点发送一个请求到当前集群中的主节点来改变表定义。
3.主节点在本地改变集群状态并且发送一个变化通知给所有影响到的节点。
4.节点收到更改通知,并按此更改修改自己的信息,因此现在所有节点都和主节点的信息是同步的。
5.每个节点可能会执行一些本地的操作这依赖于集群的状态改变的类型。