Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Capacity Unit Read/Write Statistics #235

Closed
qinzuoyan opened this issue Dec 19, 2018 · 7 comments
Closed

Support Capacity Unit Read/Write Statistics #235

qinzuoyan opened this issue Dec 19, 2018 · 7 comments
Assignees
Labels
type/enhancement Indicates new feature requests

Comments

@qinzuoyan
Copy link
Contributor

Now we already supported read/write QPS statistics, but it is not enough for pricing.

Like Aliyun Table Store and AWS DynamoDB, we should support Capacity Unit (CU) read/write statistics.

Comparation:

Service Read CU Size Write CU Size
Aliyun Table Store 4KB 4KB
AWS DynamoDB 4KB 1KB
HBase 1KB 1KB
Pegasus 1KB 1KB
@qinzuoyan qinzuoyan added the type/enhancement Indicates new feature requests label Dec 19, 2018
@qinzuoyan
Copy link
Contributor Author

qinzuoyan commented Mar 8, 2019

需求:

  • 持久化:统计数据持久化到Pegasus中,便于查询和统计
  • 准确:CU统计要准确,不要重复、不要漏
  • 方便查询:每月统计账单

CU计算:

  • CU粒度可配置(譬如4KB还是1KB)
  • 类似recent_expire_count,ReplicaServer统计每个replica的recent_read_cu和recent_write_cu

持久化:

  • collector负责收集数据,并持久化到Pegasus的stat表中(表名也是可配置的)
  • collector定期从各个ReplicaServer拉取最近的counter数据,将read_cu和write_cu写入到stat表中
  • 如何避免漏写:ReplicaServer的counter数据是定期生成的(参见perf_counter::take_snapshot方法),假设每10秒生成一次,collector就可以每8秒拉一次数据,这样肯定不会漏数据
  • 如何避免重复写:由于collector拉数据的时间间隔小于ReplicaServer生成counter的时间间隔,collector就有可能从ReplicaServer拉到重复的数据,这时可以根据perf_counter_info.timestamp来进行排重

stat表设计(仅供参考):

  • hash_key: {timestamp}_{node}。其中timestamp是perf_counter_info.timestamp;node是ReplicaServer的地址。
  • sort_key: {app_id}.{partition_id}.read_cu
  • value: cu值

另外一种设计(更压缩):

  • hash_key: {timestamp}_{node}
  • sort_key: read_cu或者write_cu
  • value: json串,譬如{"1.1":100,"2.2":30}

统计月度账单:

  • 统计整个集群的月度账单:对stat表进行full_scan,对hashKey进行前缀过滤(限定时间范围),统计read_cu和write_cu;
  • 统计单个表的月度账单:对stat表进行full_scan,对hashKey进行前缀过滤(限定时间范围),对sortKey进行前缀过滤(限定app_id),计算整体的read_cu和write_cu;

优化点:

  • ReplicaServer可以对counter查询的regex和result增加cache,这样避免重复创建regex或者重复生成结果

@zhangyifan27
Copy link
Contributor

zhangyifan27 commented Mar 18, 2019

需要实现的主要功能:

  1. ReplicaServer计算CU
  • 增加两个VOLATILE_NUMBER类型的counters: _pfc_recent_read_units 和 _pfc_recent_write_units
  • [pegasus.server]增加配置项:perf_counter_capacity_unit_size
  • 特殊计算细节
    读相关操作: NotFound计1个read_cu。
    原子操作: read_cu计为1,write_cu按数据size计算。
  1. Collector将CU数据持久化
  • 定期获取每个ReplicaServer的read_cu和write_cu(具体通过call_remote_command实现,可参考get_app_stat)

  • 将收集到的数据进行去重处理:根据perf_counter_info的timestamp进行去重

  • 将去重后的数据写入到pegasus表中(可参考available_detector的实现)

  • [pegasus.collector]增加配置项
    capacity_unit_stat_app (记录CU统计信息的表名)
    capacity_unit_stat_fetch_interval_seconds(获取CU统计信息的时间间隔,必须小于perf_counter_update_interval_seconds才能不漏统计信息)

  1. 统计账单

stat表设计:

  • hash_key:{node.address}_{timestamp}
  • sort_key: recent.read.cu / recent.write.cu
  • value: {app_name},{partition_index},{cu_value}

stat表数据量估算:
假设每10s写一条数据,一条数据1KB,一个节点一天的数据量是:2* 3600 * 24/10=17280KB约等于17M,那么1000天(不到三年)的数据量就是17G,如果集群有10个节点就是170G。

@qinzuoyan
Copy link
Contributor Author

数据存储如果使用json太浪费,可以考虑使用thrift + tcompact + zstd

@zhangyifan27
Copy link
Contributor

为了更准确的数据去重,在perf_counters::take_snapshot() 记录更新counter数据的timestamp,list_snapshot_by_regexp中得到的perf_counter_info.timestamp也应该是最近更新的timestamp而不是当前时间。

@qinzuoyan
Copy link
Contributor Author

qinzuoyan commented Mar 22, 2019

上面整体看起来基本问题不大了,就是有这么几点:

  • 考虑到以后要scan,所以HashKey用{timestamp}_{node}不太合适,改成这样更好:
    • HashKey: {timestamp},pref_counter_info中的timestamp,精确到秒。这样HashKey就是固定长度的。
    • SortKey: {node}。因为每次更新数据都是节点级别的。
    • Value: {"r":{1:{1:100,2:90},2:{0:30,2:40}}, "w":{1:{1:100,2:90}}}。read/write可以放在一个value里面,这样一次更新的数据写到一个value里面。
  • 另外value是直接用json串,还是用binary格式(zstd压缩)以节省存储空间,也需要再考虑考虑。

不过存储到Pegasus的数据格式是怎样,对现在收集数据的过程影响不大,是解耦合的。所以可以先把数据收集这块尽快实现了。

@qinzuoyan
Copy link
Contributor Author

qinzuoyan commented Apr 12, 2019

更新:不使用压缩,同一个表的QPS先汇总起来,减少体积,且只输出QPS不为0的数据。

  • Value: {1:[100,0],2:[0,30]} ,其实[]中为[read,write]

@neverchanje
Copy link
Contributor

neverchanje commented May 22, 2019

计量规则

读吞吐量:

Get 单行读操作:

  • 返回Value数据大小<=4KB,则消耗读CU = 1。
  • 返回Value数据大小>4KB,则消耗读CU = 实际Value数据大小按4KB整除向上取整。
  • 返回NotFound,则消耗读CU = 1。
  • 返回rocksdb error,则消耗读CU = 0。

BatchGet多行读操作:

  • 消耗的读CU为所有单行读操作消耗的CU之和。
  • 每单行读操作消耗的读CU按规则1进行计算。

MultiGet多行读操作:

  • 返回数据行数>0,则消耗读CU = 读取到的所有行的SortKey+Value数据大小之和除以4KB向上取整。
  • 返回数据行数=0,则消耗读CU = 1。
  • 返回InvalidArgument/NotFound,则消耗读CU=1。
  • 返回rocksdb error,则消耗读CU = 0。

SortKeyCount操作:

  • 成功返回个数,则消耗读CU = 1。
  • 返回rocksdb error,则消耗读CU = 0。

TTL操作:

  • 成功返回TTL,则消耗读CU = 1。
  • 返回NotFound,则消耗读CU = 1。
  • 返回rocksdb error,则消耗读CU = 0。

Scan操作:

  • Scan操作分多批从服务端获取数据,消耗的读CU为所有批次读操作消耗的CU之和。
  • 单批返回数据行数>0,则消耗读CU = 读取到的所有行的HashKey+SortKey+Value数据大小之和除以4KB向上取整。
  • 单批返回数据行数=0,则消耗读CU = 1。
  • 返回InvalidArgument/NotFound,则消耗读CU=1。
  • 单批返回rocksdb error,则消耗读CU = 0。

写吞吐量:

单行Set操作:

a. 写成功,则消耗写CU = 单行HashKey+SortKey+Value数据大小之和除以4KB向上取整。
b. 出现异常,则消耗写CU = 0。

单行Del操作:

a. 写成功,则消耗写CU = 单行HashKey+SortKey数据大小之和除以4KB向上取整。
b. 出现异常,则消耗写CU = 0。

BatchSet/BatchDel操作:

a. 消耗的读写CU为所有单行操作消耗的CU之和。
b. 每个单行操作消耗的读写CU按规则1和规则2计算。

MultiSet操作:

a. 写成功,则消耗写CU = 所有行的SortKey+Value数据大小之和除以4KB向上取整。
b. 出现异常,则消耗写CU = 0。

MultiDel操作:

a. 写成功,则消耗写CU = 所有行的SortKey数据大小之和除以4KB向上取整。
b. 出现异常,则消耗写CU = 0。

incr操作:

a. 返回操作成功后的新值,则消耗读CU = 1,写CU = 1。
b. 出现InvalidArgument异常,则消耗读CU = 1,写CU = 0。
c. 出现其它异常,则消耗读CU = 0,写CU = 0。

check_and_set操作:

a. 返回setSucceed,则消耗读CU = 1,写CU = Value数据大小除以4KB向上取整。
b. 出现InvalidArgument或TryAgain异常,消耗读CU = 1,写CU = 0。
c. 出现其它异常,则消耗读CU = 0,写CU = 0。

check_and_mutate操作:

a. 返回setSucceed,则消耗读CU = 1,写CU = MutationList中所有行的SortKey+Value数据大小之和除以4KB向上取整。
b. 出现InvalidArgument或TryAgain异常,消耗读CU = 1,写CU = 0。
c. 出现其它异常,则消耗读CU = 0,写CU = 0。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/enhancement Indicates new feature requests
Projects
None yet
Development

No branches or pull requests

3 participants