sofastack / sofa-jraft

A production-grade java implementation of RAFT consensus algorithm.
https://www.sofastack.tech/projects/sofa-jraft/
Apache License 2.0
3.57k stars 1.14k forks source link

【JRaft RheaKV】 关于使用 rheaKVStore 时,如何设置regionId的疑惑,应该如何考虑及设计? #1132

Closed en-hui closed 1 month ago

en-hui commented 1 month ago

Your question

在查看jraft-example的rheakv代码时,发现regionId是在初始化rheaKVStore时人为指定的参数,也就意味着获取到的rheaKVStore,存储数据都是在该regionId分区中的。

而官网中的定义如下: Region: 最小的 KV 数据单元,可理解为一个数据分区或者分片,每个 region 都有一个左闭右开的区间 [startKey, endKey)

如果在使用时,不遵从官网中的用法,将顺序的数据乱序写入不同的Region,最终的效果会如何呢?

我应该如何认知所谓的分区,及如何考虑及设计此功能的使用,以避免违反最初设计?

Your scenes

Describe your use scenes (why need this feature)

Your advice

Describe the advice or solution you'd like

Environment

fengjiachun commented 1 month ago

RheakKV 中的一个 region 对应的是 jraft 的一个 raft group,所以你可以理解每个 region 都是隔离的,如果你不按照路由规则乱写,会写入了发现查不到,需要说明的是,只要你使用 rheakv client 写入,你也做不到乱写,不知道是不是你看错了文档或是代码,rheakv client 并不要求你在读写时填入 region id,而只是需要你在启动时配置文件告诉他所有的 region 如何分布,它在你发起读写请求的时候时自动路由的。

通常来说,如何分区还是要看实际场景,取决于业务上 key 是如何分布的,mutil region 是用于面对更大数据规模存储和读写吞吐的一个水平扩展,一般数据量不是很大的情况下,不必分区,一个 region 就可以了,比如一般的元数据存储场景,一个 region 通常就可以了

en-hui commented 1 month ago

`package com.alipay.sofa.jraft.example.rheakv;

import java.util.List;

import com.alipay.sofa.jraft.rhea.client.DefaultRheaKVStore; import com.alipay.sofa.jraft.rhea.client.RheaKVStore; import com.alipay.sofa.jraft.rhea.options.PlacementDriverOptions; import com.alipay.sofa.jraft.rhea.options.RegionRouteTableOptions; import com.alipay.sofa.jraft.rhea.options.RheaKVStoreOptions; import com.alipay.sofa.jraft.rhea.options.configured.MultiRegionRouteTableOptionsConfigured; import com.alipay.sofa.jraft.rhea.options.configured.PlacementDriverOptionsConfigured; import com.alipay.sofa.jraft.rhea.options.configured.RheaKVStoreOptionsConfigured;

/*

如上代码是在sofa-jraft的example中的示例Client,指定定了一个默认的regionId为-1,并给出了所有的集群地址列表: .withInitialServerList(-1L / default id /, Configs.ALL_NODE_ADDRESSES) //

而只是需要你在启动时配置文件告诉他所有的 region 如何分布,它在你发起读写请求的时候时自动路由的。 您的这句话,代码中并没有给出具体的使用方法

en-hui commented 1 month ago

我看懂了这个api,使用如上这种方式,其实是将-1的start和end都设置为了null,表示全部范围的数据都走这个分区。

假设需要按照范围进行分区,start和end很难根据byte排序做分区吧,作为一个kv存储,使用方在k上可能是任意字符串,如何设计这个分区呢?

en-hui commented 1 month ago

是不是只有第一次能够初始化配置,假设已经有数据存储了,这时候又修改了分区规则,那之前的数据在新的规则下可能查不到,有没有api能够做数据迁移,让原有数据适应新的分区规则。因为这个规则是客户端初始化配置给的,感觉有点奇怪呢? 每次的读写都根据本次的配置,如何保证整个集群下数据的分区规则

fengjiachun commented 1 month ago

而只是需要你在启动时配置文件告诉他所有的 region 如何分布,它在你发起读写请求的时候时自动路由的。

https://github.com/sofastack/sofa-jraft/blob/373c087824cba920cc87c67592c3bb7ec1d866f1/jraft-example/config/benchmark_client.yaml#L7-L31

Sorry, 忘记了给你贴一个例子,可以参考下上面链接的 benchmark client 的配置

至于你贴的代码,就是我建议你的,没到必要的时候单 region 就够了

是不是只有第一次能够初始化配置,假设已经有数据存储了

我举个例子,你有 A 业务域和 B 业务域,那么两个业务相关的 key 分别用 A 和 B 做前缀是不是就可以了呢,这属于按照业务来划分,当然如果你对自己的 key 的分布有一定了解,使用其他方式也可以

这时候又修改了分区规则,

这个分区是静态分区,不支持修改分区规则

如果你在纠结如何做分区,那么我的建议就是不做分区,直接用单 region,比如 etcd 就是单 region(single raft group),实际上可能是 RheaKV 的 API 略显复杂导致困扰了你,多 region 也并不是必须的。

关于动态分区我也一并回答下:

RheaKV 支持自动根据 region 的数据大小进行 split,但不能由你指定新分区的 range,是 RheaKV 内部自行计算的,然后会分裂为两个 raft group。这个能力要求部署 Placement Driver,PD 是如何工作的,请参考这篇文档的 PD 模块内部处理流程小节 要强调下的是这个能力没有经过长期的生产验证,所以没必要的情况下我也不推荐使用

en-hui commented 1 month ago

好的,我认为单分区已经能满足我的需要了,由于我要确认技术细节才能做出决策,感谢您对这个问题细致的解答