懒癌患者基于 YCSB 构造 hudi upsert 数据集(上篇)

实时小白一枚,在线求更加强大和方便的工具
需求 对 hudi 进行 upsert 压测,简单的链路为 flink 消费 kafka 直接灌入 hudi 表,需要构造 10 亿条数据,可控制 insert 和 update 的配比
YCSB 调研
引言:熟悉 hudi 的伙伴应该了解到,recordKey 类似于主键是 hudi 的一级公民,通过 recordKey 可以快速定位到需要 update 的数据文件而不用重写所在分区下的所有数据文件。类比于 key-value 的存储,第一时间想到了 HBase,就从 HBase 伙伴了解到了压力测试工具:YCSB
Yahoo! Cloud Serving Benchmark : The goal of the YCSB project is to develop a framework and common set of workloads for evaluating the performance of different “key-value” and “cloud” serving stores
雅虎提供的客户端测试框架,用于评估不同的 key-value 存储和云服务的性能。根据配置文件,自动化构造数据对 db 进行 insert、update、delete、scan、read 压力测试。而本文重点关注构造数据部分
功能速看 两种模式
  • load : 数据初始化,所有的 operator 都是 insert
  • run : 客户端运行压测,operator 包括 read、scan、insert、update、delete(良好的设计方便后期扩展 kafka db)
关键配置
  • writeallfields : 对于 update 操作对应生成的数据是否包含所有字段。根据选择可以灵活配置 hudi 的 PayLoad
  • insertorder : 对生成的 key 是以非 hash 方式生成,对生成 update 的 key 非常重要
  • requestdistribution : update 数据的 key 的分布方式,后面使用 sequential ,自增 id 的方式
  • threadcount : 并发数,启动多少个线程并发生成数据
  • fieldcount : 生成的列个数(默认名称 field0, field1...)
  • zeropadding : 占位符个数,比如首个 key 是 user1,如果设置个数为5,那么 key 就是 user00001
案例 case 所有测试的基本配置如下 workload:
workload=site.ycsb.workloads.CoreWorkload readallfields=true insertorder=ordered requestdistribution=sequential threadcount=1 writeallfields=true fieldcount=7 zeropadding=10

case 1:load 模式
bin/ycsb.sh load basic \# basic 是默认 db,将结果打印到 终端,可选 redis、mongodb、hbase 等 -P ./workload \# 指向基本配置文件 -p static_col.dt=20220101 \# 扩展的字段,暂时不用考虑 -p static_col.ht=02 \# 扩展的字段,暂时不用考虑 -p insertstart=0 \# key 的起始 id,同上面的 workload 配置,这里优先级最高 -p insertcount=2# 总共插入两条# 结果如下,写入两条数据,分别是 INSERT op,key 为 user0000000000 和 user0000000001,从 0 开始自增 到 1,然后是统计数据,吞吐量/s,耗时等 Loading workload... Starting test. ***************** properties ***************** "writeallfields"="true" "fieldcount"="7" "insertcount"="2" "threadcount"="1" "readallfields"="true" "dotransactions"="false" "static_col.ht"="02" "requestdistribution"="sequential" "workload"="site.ycsb.workloads.CoreWorkload" "zeropadding"="10" "insertstart"="0" "static_col.dt"="20220101" "insertorder"="ordered" "db"="site.ycsb.BasicDB" ********************************************** DBWrapper: report latency for each error is false and specific error codes to track for latency are: [] INSERT usertable user0000000000 [ field1=2-(4]m9+n7G{; [s:C-350=F36@/=Om8@)5O1$A38&z&#"4Mg+02Rm>'b7Nq; V=85~/.(.Ak>(f'*,524"*&4 z field0=,X%=_m<>&5@1+]=9F)7Qq7'<':49':51b65>.; *85h Es#_q0'd; S7$S)0Fe9+f?3t5[+9&r @i'>n/@q35l6Qy&G/:Jw/N{5Eo? field6=3!>5O-*364,*9R!1T#?6:![o7Vw+E35[w''.; 000Go<[?43>?$40Nu7U; $Mc=\k2*f!Ps&W/-N! ),=O)98d:X99&x$M/59z#:~> field3=:E? &x6"($',(2p3Uy-""4; r-Bm>Q1*>9:."H1$_y*+|+2>1Ms+Zy/0,5S#$9<$Bo; ; $1?~1M'%D5)#f>Ta/$6 [i5=0<)f3]{*< ?M-05(=Dc?]-,Ue+I7!>f?N5)\y6 field5=; X=%/~7-x&^q.880 t))~.V=0Ri23x; Hc'_a8E1U!94h0La>64"024-("C3%C%3*>=Ke; ; <<9n-Ma2$.(Dw+O-<]!4706?z'J#6K%9@u/2l+-(-841$-7&<-t>*8$'f>F#8\u>Fu3%x2-r#Tk3F/59p"&29B9 N}5_w'Fo>B5S; 0,C/)*$7V5(A)&0&9=d(#(-0z#+f+G#.=2$Po9%( >f,Bg/=<-+ 0M/0)$8 field6=6Aw2/`0+p>%.6Bo/I{:1.,6`/N7)92-*61P!3"0-_w$E.Sy0/`68z,:l6\7; ,2 J!4@s3=8>Aq>=z:Ni/=f4R+4Gk$Ng"[k; ".0 field3=,M% Hw%W6U=/\y'D}&?&$T-6<<9; ,=*p3]#.Yo6O'3"&1!&=U9=:l Wg&9`%$|; =4)&b>O&9<50>6G}?I5!$n&=f%Q{*^!$W{> field2=9G-)1p'Sg&; 3!h7Fq4Qw:C1'Rw:; $'Gy64,>)~; Is8<2<&`<\y*; l?H5)R{&)85Uq=Nm>%`=[i'Ey9J{+]=:P#%[)-2~&Lc; Q+0 field5=+#40^q'.z?G; +(|'Gs.Wy/Iq; :"( l75> G97 ,4:h:S55T7#9(,%:$9(5V-))z#J+1"j&9x48~7%f%Wo>@-$Py7%z,58-; $$Xo2 field4=?!r*Hk.Lc'^; &F3-[q$2t#<""..(.<2)$,H?:0<$-")Wu2Q93T; _=82v'&~?=&0V!1 l) &

case 2:run 模式
构造 upsert 数据方式,测试的方式是先 load,再 run,比如 case 1 load 了 user0000000000 和 user0000000001 两个 key 的数据,在 run 模式中,重复写入这两条作为更新数据,并且也同时 insert 新 key 的数据从 2 开始
注意:下面的 case 是上自增序列下的时候调研出来的参数含义,并不代表一定适合其它的配置
bin/ycsb.sh run basic \# 使用 run 模式,包括 insert、update、scan 等 -P ./workload \# 指向基本配置文件 -p operationcount=4 \# insert + update + scan 等总共触发 4 次 -p recordcount=2 \# insert key 的起始 id 为 2 -p insertstart=0 \# update key 的起始 id 为 0 (为 case 1 已经初始化的范围) -p insertcount=2 \# update key 的最大值不超过 2,即为 0 和 1 -p readproportion=0 \# 没有读操作 -p updateproportion=0.5 \# 更新操作占 50% -p scanproportion=0 \# 没有扫描操作 -p insertproportion=0.5# 插入操作占 50%# 结果如下 # insert 和 update 产生的最终条数是近似 1:1,不是严格的 # update 数据的 key 从 user0000000000 ~ user0000000001 # insert 数据的 key 从 user0000000002 ~ user0000000003 Loading workload... Starting test. ***************** properties ***************** "insertorder"="ordered" "updateproportion"="0.5" "scanproportion"="0" "writeallfields"="true" "threadcount"="1" "operationcount"="2" "zeropadding"="10" "readallfields"="true" "requestdistribution"="sequential" "dotransactions"="true" "insertproportion"="0.5" "insertstart"="0" "workload"="site.ycsb.workloads.CoreWorkload" "insertcount"="1" "readproportion"="0" "fieldcount"="7" "recordcount"="1" "db"="site.ycsb.BasicDB" ********************************************** DBWrapper: report latency for each error is false and specific error codes to track for latency are: [] UPDATE usertable user0000000000 [ field1=(G5)P-.; ~#A3%.`"P!/&j7O; ?+ )8<42n?Qc3X{2Ws:,:0F3Q5!^a Uk'T9*V}?!vC{57z2@)=3n"L7*_5(0b-1"!De.-n20t,U%5 : Ig'Sm(Rc+E?:(b2B}%P94V$3z.4j8)v:Ke,%2,Uy9M192d-z:969 field6=*>N/44`&F)8; 2!7l87b:]'8?>%Es43z"$r!'l+>t!7t+<`6_; 000=?t+K&% field2=6T?=_s')b?Ng!4z/V{,$t&H?=?$=S12+$!I19%<97` &8(!|/*j#Ja0O3V1.U)42t:+,! field5=!((8Ak71>0&h!2j>2p&(|"Tk(G)!Ug'I7<#p4/2*+Ec#(H{.,0!"~50d#V):Bg'Ua774,&b)C+51.!(|>8b'&`*; b53 %R"V#$Kw'; ~6 ] INSERT usertable user0000000001 [ field1=6^e.Q5/<&1-"3Qg/10$Fe3,.)W19Ho'W{&>t#4b3=p'!~?9l/6* >02_s2R#.3b/T16I; %=8:; d3N14:l>Ym3%$(Jo<5G942(\q6Tw>P?*,&t=-$1S)x#Ia(Eu*9~)8*1 field3==8h*C=>Va2:<1',(Z=2Z99; .5=r**j3Ra"&.'W1)M [a#/4=Z+-Py91x#Yg'8v#S; 9S+9Mm3H{3@k9Q?5.,*2*-\9("8$"f,\c? field2=3Gm"7>3; *=Xs>6p*Di':t/Ny.9<0Ca"Sk&%b2O-1Nw<5&0Xq3.6%])7Wy+<6:J{?# 7'&(),?Mi'\g/">8])1<~.Is0Gw73<27n3 field5=$; >=@; 71t&]1?Ao#X9C#5)b>@u#]/8920Y/-P=1Xa94:-Lk7A-%Ey3_)$; (. >0$4%!<$9>/I#$Ra:2p; 5>6!h#X=>Vg7L9< field4=2*6%,`$^99,.7Q58I98&r"(&4S?52:5%l.^}5F+)"4/R)1X(Xu#Hm>'n*V#5Um67.:Z5):b&%p*3t$S+9/~ 60%.(; <`&Ew(S5$ ] [OVERALL], RunTime(ms), 9 [OVERALL], Throughput(ops/sec), 222.22222222222223 [TOTAL_GCS_PS_Scavenge], Count, 0 [TOTAL_GC_TIME_PS_Scavenge], Time(ms), 0 [TOTAL_GC_TIME_%_PS_Scavenge], Time(%), 0.0 [TOTAL_GCS_PS_MarkSweep], Count, 0 [TOTAL_GC_TIME_PS_MarkSweep], Time(ms), 0 [TOTAL_GC_TIME_%_PS_MarkSweep], Time(%), 0.0 [TOTAL_GCs], Count, 0 [TOTAL_GC_TIME], Time(ms), 0 [TOTAL_GC_TIME_%], Time(%), 0.0 [CLEANUP], Operations, 1 [CLEANUP], AverageLatency(us), 1.0 [CLEANUP], MinLatency(us), 1 [CLEANUP], MaxLatency(us), 1 [CLEANUP], 95thPercentileLatency(us), 1 [CLEANUP], 99thPercentileLatency(us), 1 [UPDATE], Operations, 1 [UPDATE], AverageLatency(us), 526.0 [UPDATE], MinLatency(us), 526 [UPDATE], MaxLatency(us), 526 [UPDATE], 95thPercentileLatency(us), 526 [UPDATE], 99thPercentileLatency(us), 526 [UPDATE], Return=OK, 1 [INSERT], Operations, 1 [INSERT], AverageLatency(us), 177.0 [INSERT], MinLatency(us), 177 [INSERT], MaxLatency(us), 177 [INSERT], 95thPercentileLatency(us), 177 [INSERT], 99thPercentileLatency(us), 177 [INSERT], Return=OK, 1

总结 功能上,把 insert 操作作为 insert 数据,update 操作用之前写入过的 key 作为主键,就可以达到需要的效果,并且使用自增 id 的方式,可以不用缓存之前写入过的 key。并且可以灵活的设置 insert 和 update 的配比
但是自增 id 也有缺点,在并发条件下,自增 id 的并发问题就会导致其压测能力不会随着线程数增加而等比上升。所以如果没有这种需求,可以设置 hash key 而不是自增 key
完结但不全完结 懒癌患者比较难从 0 到 1 写个测试工具,做完以上调研,数据是有了,下篇,将介绍如何基于 ycsb 扩展 db,也不算 db,将魔爪伸向消息中间件 kafka,回到最初的需求(其实也比较简单)
【懒癌患者基于 YCSB 构造 hudi upsert 数据集(上篇)】欢迎关注公众号:
懒癌患者基于 YCSB 构造 hudi upsert 数据集(上篇)
文章图片

    推荐阅读