From 8d2fbce11edde0f5704daf770a11eab9e074734c Mon Sep 17 00:00:00 2001 From: luhe Date: Wed, 21 Sep 2022 15:54:30 +0800 Subject: [PATCH 001/145] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=94=AF=E6=8C=81ZK-Kerberos=E8=AE=A4=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../streaming/km/persistence/kafka/KafkaAdminZKClient.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java index c8849ee7..0b824ddb 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java @@ -132,7 +132,9 @@ public class KafkaAdminZKClient extends AbstractClusterLoadedChangedHandler impl kafkaZkClient = KafkaZkClient.apply( zookeeperAddress, - false, +// false, +// 添加支持zk的Kerberos认证 + true, Constant.DEFAULT_SESSION_TIMEOUT_UNIT_MS, Constant.DEFAULT_SESSION_TIMEOUT_UNIT_MS, 5, From 8e5a67f565d240359be32b5a990cecbf5c791cb6 Mon Sep 17 00:00:00 2001 From: luhe Date: Wed, 21 Sep 2022 15:58:59 +0800 Subject: [PATCH 002/145] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=94=AF=E6=8C=81ZK-Kerberos=E8=AE=A4=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zk_kerberos/img.png | Bin 0 -> 64697 bytes docs/zk_kerberos/img_1.png | Bin 0 -> 17428 bytes docs/zk_kerberos/img_2.png | Bin 0 -> 312993 bytes docs/zk_kerberos/img_3.png | Bin 0 -> 312993 bytes docs/zk_kerberos/zk支持Kerberos配置文档.md | 32 +++++++++++++++++++++ 5 files changed, 32 insertions(+) create mode 100644 docs/zk_kerberos/img.png create mode 100644 docs/zk_kerberos/img_1.png create mode 100644 docs/zk_kerberos/img_2.png create mode 100644 docs/zk_kerberos/img_3.png create mode 100644 docs/zk_kerberos/zk支持Kerberos配置文档.md diff --git a/docs/zk_kerberos/img.png b/docs/zk_kerberos/img.png new file mode 100644 index 0000000000000000000000000000000000000000..c51c1c00ebb07f4d75844729e8d32cbc2ab0e395 GIT binary patch literal 64697 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 literal 0 HcmV?d00001 diff --git a/docs/zk_kerberos/img_2.png b/docs/zk_kerberos/img_2.png new file mode 100644 index 0000000000000000000000000000000000000000..f15ed55e2483302b66b40b22fb12aff91f402f5b GIT binary patch literal 312993 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�M$g8*r|zOMiHNl*NRkuUuaF+nE*? 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 ^8?SLm zRd%ErLW_K1p3to)k5#gL;jm%DCOyb)J)I-~-LXgP7=@%dJ^cds@RcA1QF}$DO|z)L z7r=0IslL8_Jd)IVSOD*oq@9rhmoDPeR$Kk4l=#Zy_5L*8#G}18U-4QoD$?b(>a~>| z>bK$y{F|Bcq>JCa6nBt+$}GI7xe5C?+9;|oOPEod>TtYGIXJEUlu%J@p~qZ=vvTvYUxkxJ!D zy^N8ZSy~Yw{5%XxXS6jOvcX|EG{a3)%_)Z*; z1K9sDWZw(a7e@nE!79S|zVHJstGb|w8MP0Ifieh<*a(ipc*n;oFD)ZxEgrXIh?$s# z$(T~Yru-25d8n(dC@3bUNO-A>+%JUC?4vPFU%^cBL{n7u$RmLVOkARPeM|jYtz##8 zUxUKF$=#%l2f%0Cy26hIq%-)vOm|JBZa?h{aT?>(8$#x~ui17=$av^qRHw_m>nDwb z=rw*$S!Pca$uWCd;K>)LrKBRuPD!XgwefI^hL}oQ42S(p!(}}TlTB3Z=lC@IlP^GJ zTwcw`M`m*33xeRTSp(4NdGo+@ByYupG58@+Yr&VYVj47%#|zy!9w9OR`|p8qSp@?P z<+_fgH&bfnxoK%Q%z>2hd=F9?Q`TGO_DI)j89j2zzaOH2(1uVFdhzRP*N##{wp?%W zl|TULz^!`Y*j}_3jc~y$8{I|GWWZWj5*zXJ94if*$wwOg`4d0|@24bRJQEMygD@FP zIhR-Y_O6aNvLCERxkv zt^bOF`uH>r0QWJ#l=ZXm4p@s9k3-?fJW%AJgt?UP_3f&u!-kEWpH4&*o##|^ zytsV|f3orj(c?)hBK|;G{aZ#?MKoZ=-%!FS9AqqIIcg_mb-J>IA6bHH^SccOPP%EN z2(XLO7mgh^Z0d?!Z~^`Cox9)gtDs4UJRY2$9@kY=x9sWG-B7)g)5upOniDw&ui7-T zpKNo?PdGT+(cG4 z4s#w}nQJEt4q|~xB&~dFV@^*{z6|Jq6nabpQQjzE2{rWLEg=4z7Q6y)fbM;0-9e1V zQP#)#-rdwYb#`}mHPq6Yw8poF8iYCD{+ia`%)!;&t-FS5`^jqqS!AjRtc%{aytE!9 z$lZKyz0yOMrB5jlwkEpWTwUFqEjy^FOy1zvdTmr=J2kTh?nMd-^waPvwT`mcu!*ZJ zh{dvX$@#Qa97st`+$DXK5E6B9cXx7jadCEb?msQH07Om9!PyvLYX?^s7k3jKosOOC zgA;P$gBC|}6lmOt>-*;Go0+({y4hOmw%4{k6-`eTI6O}Iz6FEiRaLsVxb^I2rJ`+j zJ}Hk^FJhVjxuFAhrZ55udNwZ3jxGeXWrwdqU)j0Nsz^v#*VWafyN#Wevht7_TT2Cp zG^3UpZrPh*J@u@doZZ}d=yq)9F@8l!HPcW@@;OWEuFfv5-A(n?Z9Hx~17_ok*v|o_ z7&|}B(?++8i;J6^t(IE5fit&!1;-B#HG{KRz??O?k>Uugi+Cw$)QFvtvwnDI1FuzF zGP&@VxZfY*j$>M_y8BJ&ZaS+7Hbr zt)qs+pe++|6>e@0cvpaAG%$wFPEI>6z}BTDwdvjRt6RMByB0m%>JjifcRv?it^DBJ z5vw999`4T0ggN?7UPsO__;1MR9L&8FWNxI_)5Xoj!BkyYeZhe+4rvH~@hLUjMytJ1 z7gr}UosQ=23Aqpssdb`dM4qZ|c5e2@9d)~TKP_fcqMh40)d`5^gq3e3rA~>q`3$(xv?SUOfNnzS zO6GZ5$tY+#K~=8fRvv*^Z#>?!D<|wUR5kSMV8Xk)cIjdgm!=s+8NX-(WuHy0fZ z^)ZW&P=U{v(2U#S%UeCW+1NX~I#_m6Htrd6kL0c=+EIg4f9!*I(P|Hh;Hngs>U4?O zJIM&stnX@2HE0RrJW%*Z3sx10TiM^8GV90z){VU*@dFL7mGBye*%9ys+Q(P7PwFYD zTL7!88#xZo`V5`cBRQ2qKAS=Q8(V5do4DSpF$1NbB^_?G|L z-{4^8L5`j7woRONpp%Lxr4&cQ2jx zIeqH^F;CR*)Qetcgailqoc2x2Cbzm?+9dxKzW&RniPu9fp7ZrNecHzd z|2Z8PRsgx`dBr);FI~FekB9lRe?)W=Ib;%86|cUVl_ejduKbOw@xOe%l)L#0l(8X9uVh2PQ`<$h;x4jVSEDuFQvbw zQ7Qyf^&Pm`PvZV2mEC=wLrWNHvdWWUqVa?Cp|`#eStkgue+AsSjE6D7{+liaG}h)b8VipYTwKO{&|UBa!#>o7qIjIP`$0Z;0^vL z`24jhGVru7sj-)U`aZrP7cQO;38w58_Z*sQ$qBUNeR^VO=%oO^1_T0_Il?Yah`My? z+!?^h#}^)iMw4*zf&iXzs>`uF@$)(D6Lj`vAvsN7N3Yt15aM;Cnjo>=iQqnD?K> zg)u}s|D9;DX}R!Ks~GYJ`U$%{G5iu4&!Ct`FF1ez;rp6TS1+H##lb;m(qA*N1o6~O ze~{=4J@L75FR3v{Q3R@r-bWJ7@$);EnhS{<1R+Mt>ni^rdtU(;<s_9C zW}Y)=&YU?jbLLFqsbkP^cR$CFr%LP|F-SS3oVO3}VQRyVozEoJqIB`J%pZxLPM^J= zOP0ulVwauxj}P(S@tWLF!H`7%<>lSKdhXoCn^~|2%RHm&C7JQ>ahCgUU`inK8D(HZ zJvADOdicppRMe%v6ZPf}F70DHOpT-o5ENzIx_Iu~)q6kaFhokL!oPrWualHfxiaRp zQrlb+(yys9&;K`&b-ZArz$ie~^ItbO%SA*&x$jcfmV$Y~y_6yV_Ibh_*Ez` zxw5@mmb9O3U3otLJkx$_zxlgRJrq{qzX*9#MnrsGIRGx*B$5D+{yZ)hC-8U>Bugqm zz{iisJ@v$OyetX-#z{~X`1Hxk0$D^X-$_OW)H9s!waTXv2xabnuMlv;2TGKyrl6E7 zu4W~>7S6(hOX^AeWz`m+2Sq_?d|9TchM=^B6b7Zq*pfnWwu*qqm~T{W%O^=1xSG&+FlVHUKT>zTq^7u+R*q>v8_goU6-Di&`WngryM1C2R zD%B7KzrZvKXaU)miH@ku&?OD|@2OksU$$YMU+4&|BkqJ#HLYIuqw!RPx->j zAkReAP;4~?l%L8#ffN%5nu0j>6@RN`+Wr!&$xOHS_UspHJ zVG|#HA$#Yr?F9XmpBEo6XNsGfn_uwmJUDj43u&ume|@uV(F|y{5fhGG0Y_=znOq4{pu};~BNk5@ z>*nSf6mkUi>7`puSp4<#i?B^wza*1*s^wOOk{18+#>hea-Q3&{U4S?rLee#b{K5xE zca8BFgj;RO>fK41@R{;UV<6XRBo8O&`_a(Afv#?D0|o}|x&}8Pl}{R_Ojvww^NRki zu6_HCIehjhh$j)IoT&GIE+wMw?Q{47Id4@#VUWnpit?K_9y85Ic!oGyD6xxefFhbNem$ zJe3(hASOZ)KW*;hQLBE<;kOD^sDk1NrsFGzYiL<73JzI0-bJUj*{RoQxVJ&Ln4HM& zjSQ{3_=JXpIM>&)?>jYDh=*7>NfdQE%(`avQF8)9LV}y=v21$J$RkehB4O^-zV2@SAUE=ac*Ufr|Y)y2iJxeW^;w?z=$PJHcLX?kM( zx5$W3W%!&`KnF9Ka-<<7!%0Er_n7$a;uQcI<((Hewj;~PF*qc2R{xf@%p6`Mav61_ z40O5jT<};;P4>LN5Px5H?OMj+Pm;m>z#1;&-O%Af{nq~(vOd7RmYQvQ@8kmDfO5iM zNEV2M`Ev&~)3ENoF(lNtmz};%htC7ShH={4*@As4sMWTY0QC=4U@XF^jZdP3Z3WaSku_E z8Nr?z!`uc=#I1&B0SMKYzYpT*sA@IJvy$XD&CP2!?K>khWKDY$wRR&{LLgqDkel&! z(F6~d-kmJ!>LSFxM($@&*=ocB#%VFPcIfMB4W5p>^bA8So#~rz($u`Tn**CT&GN^j zt!`Cc*RY`{J+7#_yfS3O$EIY!l^QU*lWzFt^t$ft+*XHRNuOF*19cp}4i43-!iglYWj=w*|F9t7IA@>Umq2jdShOv#|}_ z5*Kui-seh1oxgTMSC)S3ppekH9&KuxG<*_QT#l$y{cvghL@iCTIsPGmQwD0)G&=Ag zfe1Aum6Ef8$5!GVjT~q1h9|13S%oT8K{XgtCMO31S>#7us)JC#g=m_#dQhWU&Bx@C zPI_=|Pj%x?OuT}$hlVUP?=YO{$5`lWX5+kq{!Y5FQCr81M#Xq`a2{eAJ|y>4i$v+2 zjMaORh!iSSk_r$@ru1BR$l4vpChk1_qkCb?aGMTUuJxt7m0p z)nM=47LlR-ASbfjkajKrqlm6YAKQ~c!w{>qG9U}lxK zy9d!Ygo4bMHVElEO&}{0bmap)r6g}X*f9w=2V*oS>w`k#C0>$p*AStNcNnFz#MQ3( z5QsA*6mX@Pw%V%^s@Vmi0jp>=%Cv109CfVRs0fzCUBPC{DsrWKPSQs#>Zk6#czrTR zUESnTbon8A;dx16`i{`x-GALmczfDVO*{AsoUNmxo^*ekI#LUNPlH93jBZiaZlKDW z%jj|;C;7e!LJPu~@Hv~tw5et{D5sR@L84V6E{B*}m^zr7_M8hny~>oSLKS`i%*6#+ zS#aw0>}oHh(=>vEtpqMs5TDMh!Yb+9H{6HQ+Z(ENn!FSDzv3bYs5;Hbklke()wWwF zwr3f4jK~I^b!>Tmg9iQ6K&=%|?ZP&6nuhx-uL#!2cTVo4Zqz9S6arCi{G9EpCQqI` z?@f}*Q^VXSltYD=ZQ2ye=^H8ZU4vjGBLK|o%S zXpMI(4eNneA(n88v6{IUJQQiw|G)%0lBbX^3te3|3TZZcpHBjTlnTFHUW<^<$&d1P zWWGBz2O*2cDG-KEnI;tyja)Lnk4^2C<1s0G!n8wkdZD^);>j8l{9jngDdzD@L`N6k z*=q9$GJGg2j6CDSwycHv%*SJDX>l>;JAX{Gn)O{5!RCkf#TdAAz~FoZri=_q;;-r< z^?-|D%5WiotSEH66Ebtb0#w4~;HJI#rw>xMcm<*8lrW8g25Y{(bD_1lT@8K1u)DB^ zFYBIA;^Sas?-?LcF-{OrrV0E8*jKk7jz{K_VraD!OZy?+CQ;1I31x4G`Lsip{eNqS zJW2p}awjw6jx$6c>TnW0%(uOUY1i+>(1iaBaI5k0=)7lgFQn04eDq(Ypt5HLUmEEk zk5zx+Y8OM))WX5_wVQec0M+6bKb=~MklD?0O&KcW>Cg6RBK5HQNdj_-ydeFF1&g^C znr@83o%VdbDCfDgy4vWq5F~@%F{Bi<)h=zCY00*$ZeV)g8B9~?-Ae=l9*4{4l|*0v zQyu9Xd<8a&Qd0)ZES!}0*+Cb%%-KnveDBV#K5oNRk$5bZhmv0a5!IKCv> zHo1+OxnlwuVsm4k^lfZl(yZ@_pk=Mwxn6ijf);QS9NB7ZCT|nLAtty>=-&1TNWIqW zco<2+o+*lJsROZu_CJGZYPliu0D@9D&LI>gC^cm|PJ^}CN`kr%ukmi*Z{hx4Ylff2g2w_TJ80b1uUfg*C(*Fait1# z(jvcoyL@_E`xdSC--&_7{ax+|45Q=Qn5sEW+d)K~i~qf|)dy+Rxt9ouOsfHJ^PKCe z*B?sPnUuB~JS=#30wLDYlkcI`$oZI+URK%;{a~F>$mbSAtGz$5qC!)KE*Cx6J_%_W z-GOHc#SMZemuDd_rz1gW>=JRF{ss$>1uDa=C3DHIvKV0*-DBj zTl%6`xNq@og$&!q7efwJh0)E#2fG*RYpVC3nZP`;MZk!9aeoIbi~i(x zFy*37MDWXbO~jge_$6T)EEN4QqM@c;FYy1tqE46=aW1%$ri@4|>V@AfN=zBJz(7Ph`?M21Y>e zSz9=uwO;MoSR1w-vWmH3wIHUo3F;|zGxoE6bCFu@tC6s*4dZG_;q_CyckezFn+2&A z=oSEdB~j6o8E8?vrT6OS=;)}(Z}{Kj46>u5qCo1pC(QlS(%fL*t6a|4BN~Xc=gD_? zUy$SOpx$^WtQZqhMig^(BVw`kK8C=JiYlI}DnAcf?Pi0B-z?Oe7j>hy8f)erh;u4} z+Z&Fyu&^+wsbko<`>RCxD1v2R914> ztC5*17I>HuHvhvJ9TxIC4m(O5vgWjTk`uD(oI*T_={~}@pD<;ZVvA!gm#xacgMuL~ zbZiGKfx(9CStQ-rh6m$qcOX2PqJ9_A;YTRUe7?`v*gmRI^fYV&(z1O|Bl80d)O0DX zj44Bmg|wcwsI|`qoRgR`qR(gi5li#<8<_awhxhj`vaqnIu7-tk&UaFG4>`?PD>)>xeiGZ$|eE-m-rh4z` zVWlu(P-*0W=_3@T-rHhm)-stZy0vZ?s_yWOxW&^233_==;Z}tY4kqP zgjXk9Sen+r^CYCb=EQUIoXJ8({o;xdNX_ngR95*+`|<7+OuA0NjuMBkXwyVTRIghq zB*LZ9BDk%v@}>+USw&G&rVQy)p3SxFJcwOIL_OiwW~?7}+z0+Din{d8*hChIJjC7A z*JMrHatHr@cf#Mmy!B^tiTmir#*Wi>!!NlQO;xBu6)FK4Q)YfY%WAEM7K@lwnf#A` z;jwV(nHW*VLmd`t`X0D$8cZ3XaM#RE$h2h?s0H4N0nO^R8lGER^7weLnFg|I>luru zklfgo#;EhG-C*i~eiuI4JsqjlxW?#r`EFkcs4`_ThBq?S(ye1<31G9?o{RUv+bTAj zAeOmM^mNaxM%^aSC&ODCH5;)JehIVPn`qh&SqTgvgW|VKYhc#(ge)*9&`ed;axXir zrUUbY%&e>U>y=t~*0q;h30n$IzE~;er6w#I++It+$%7bhmQ*rVrGp|rxq~IE?W8T3 z0BXv-Iy|4n(mqeL9jvyCM0bzO)j`%LZ;^8liscYcMO^stFFaLUbo8x=nleJsrtvLV z)}0vr{@YBMq9LuSv->ZC1t+54<8OwrSSai+#0FK=@ARP%?z!ylHg`Y#&HqxrhK6q# z?0S$j`JXjq(tFfrH66PS6F^Ow4=0ziklKm2;FbiD9|WcRlG2ojH?FNs*iD8e5jV}> zW6aQ2D~fJmjJnR=BNPRCH&konLiX!^+LXB!>VvdR9wvhI&WHbh?_q;l`fLz^1n|Jp;6ymr)9dEG z4(JAPl`lsE+LVDKJ9zq?gue@3v31nu9E2#|Bw7a$mh$-oTdmrnwRc6tj!{(@T^1`! zd}vV}P1^O4lash=Tpv6Un!5I^kc{PYYv#`3+1jYy={q1u>#Cz^ z``!t%-deGc&!6X$6XRlIKY27TY&tR^E-|H8^#)&M0Lxm+O?8ziOoEaWCQ1IOsJuL? zo>xqO{9}Ns6ef$36qQ-Z$)hqsb&Bf3R1;8ze-aX38JITgnAVMD&^eKh6$cONlaz-$ zv=D38^FmQcv~4xyw)6znLF5KqQSe}!S`GuSRw#@-R~w-X*J5dL-)@FhLukb*tcZC7 z?Q2^0T@GV8rxBZJDwIAv2J@_>6xSb79?l zasP%IjfcaTB|Zl;?cMQ32-Uc%>H=!IO_3kf#uS;i=;7_{J$!^$9fa5&#uo^IFaa2U z@Eu~x_zQ_KsG>cI`?iQXp_5tNj?+spfm~>{``gAL4dZ9TofKCJ53|%e`1{>ZJYMd6 z1RI(aR=@j1A%JZgtpQr$9laaMv+r$ou2Vu_<#Sfm2SaQD2#;i+KFjJ^DHm7KgC? zP#D#!4)R)kRs??Tc*xJ5(AlW5vme+oCFSn%(k;QX1k>o!?GinzXBmsNc~G1)6* znke%Hodj)rI4i^iBaEXhNv6By3?`1?i;#?3mWiCb)l*2R$sHhiyyMRrZz)KNS z)bZm5eet|y6d1#NkhC{P<|9<|I`Je|6!lUfoyV5CqnfQE3mE;7{pM(Ogtk1%%l~lP z#@N)>w!S%mu9haAk6AkQ{UUq$S{15Lg~~vDf{9!Q9d|nfA??4SL2Y83@f(2Zwu^)5 zhhV9zwXx#_ajuMZ`Ybncfp*%nJ({>@K9JnS8dF~z&D;%Z62}+2vg)=a_ZR_uolNSv zEfYXDC5lNX_>rBSo}LMs=O>WXy{>j&zf)3Avih@Yb(*$E>WNBF{hs~ygoT0Oyj4NV z{gy2A^9x!v+fZG7=59E?aev!H#IpDZDi9Fp*|cVhF=P>4Va^55fKe%rce0Si(NDl8 zj4Q#zP|cPx#8E)z?TqK98feHGa4}Y9$}sxC_vO!I9 zZD%DwJ*#JTHL>b8n|UNmY@&;X{y_*3Ysz?-RvKN2hry$g5G36&U}^kuEn4#A<-s`! z8NXt#02gf>*+!?)5VH5EglTlO?D3vC2J9C80sekV7A^Bzv24a*mX_X$58_LD$%_-3 znmCZ-W95KuYTVd33TZWn5i@nMOMQb5Q^7q%cC9|?)}Ppv*?b$Wx~y<8t0ZWvfvD>{ zNp7I0ezPJ49lwa(YFkx`)0do+Vr3Y+{y>z!5ZpoXzdu_znZq% z;>iP$j^V{`at%0WR zgYZ!mf{OZ#&W81R&SM@4;u}{-!`EFErvhTHtYfi^uO~9ftuiQ0xTeq2SbHN@^5ogR znFyImE{k60-Kv^{Hwo{fMAWJHr9I!Tj?@m4HA0MA8%81BCXofigNk25;s#^GFK?8C zNt;Pq$V5zua;P)}c{v&B=^1ouQW~YaVw{kfo3BV`VIC;r0*<^A5SH??aGtCj#juRr z!XG%xk3vT2l|fjVn?<#{e4Y|+Ax_BtAyyMoDEN_ylZuEtk~Hvq4ku(}|4?LZaX~K5 zl2;_w)Dj3vav)C@o#sk|U!0G#bk86Hhwx3DdyGTn55Y zem2STbHiE{{x&3WWnkhj66H{!5wvs+r3OH#Pb+V#+&BGYEBb2rKF}_ zSns38s&(p32CR$FgU!WB?)G?O(L4Q?IL%cs4H5pxN=Z&mPDy#uMhA7CvLz)YB{3l( z7sByn^);^6+&d7bCdMZu6J+Kp=`bR(4Y9?yLt~E>($DAjwyxD^NH$h4g|W^JbsO|s z5|f(x@W4_XgtlIf0S+i1`RG{KS`} znawd>#bnk&ww0J7~-lJm)tt-=Vfm@44SnQlB1O zjZ-&V_)0XnVsS*}3k$v58V}!aL+W{Udp*=)9Gu|D&rC^3#0?$oWmDU_&ph1F$%%(uWNQz#^gy$D#7oN{wJ9#HjH-lbxo_i|_4~|^N=bbjz5=KIdFh)9Q3nt?D_+{q zp^jbO=aDIqcMqFaN8{JS!j&WoS#ji!XsFj>5;(~zo##{xA&m%`<=t8Xp=t-8lx^<{ zN@2K-x)FjCOuJ1W$1$1Ufs}-R;SI4OUUU%L`=}ws>`+JDu+>7yqT^@c=|j5=-MBmz z0D*Aam+U9ylPom7FwO<8tTsCTu`GTMCE(4e+y`COB!$`A_f% zp^5Pudvn4N&#fK$CXkh6F#+(o-E+I*ETh+*lRRPOEt&6~j1khcyB}BP$v}PE@9lKaX#&*Chsj=%G94@2;&~@DSdttbb=(it9w|B)%ga54aX@*Oiz3VQ? zQbqtb{=PldfW~d!l1aRRK~;r+3UW7Ni%PO0XL$BCG_|lcueTuNbO~v0+IVlS?`zxG z!NP*==;U(!9ZYShQIa43dd7(E2F4a_3p1zw-j5=n4XJn~y}Rz>y+H?>}K?hD-50+*>2my`%To?59_*X+_)Fo3e7pL+G^ zV#>C#vu(2R1jOHD2v!EDj6fvFjh;Kq-O$9s(#&f1`lCGHB=m&*sK>5t>YHQ6SekVk zF#5`?IGRPS5DDm2GsMXF(;66#ZNXlR*JtK3rHQUsjZGkIq*JEND z)gda%qmB>HE{3&iXm4p@-o8`6d!N&2VLu|Sw5bQ|G&eOiFfcGR2c}uHbyK>y&Gh#l zksj^vTjmz#COC_+sTr`lUek-D`Eui4dOLSFVO!L%XTK)=HqE7kF4EicKb^L?vCWnE))3oCJ}HFlXnF8fx-90E$)!_y&6>o>4un|1Cs=y6mQmVaE)%y(y+ zTViHdNw-?PjvmqEigaZqQit54eXA$4asMzj^ziXZEQE<8PP?~jT3tg!ODk(rGjmJQ zb=IB%vK6EJ({Uy1^&#u}tsbZFNUQNVT)59^$Mmj7P24e0Lw#Et8kyF!vM{6dwCQw* zkfpfoLP4wf^m0f?$3{4ZS;I!-R_$Qchl-Ou9c4tlLC;C)WPnrEZcJ(Cx3_4}$dYZ| zp|kt_h;$O!ma?hI)Et z$6t_>3R0#_?A;wW!QOoqSsjuwWj0K7#EN(o@zji6$d!tw%(9`4a8k$>@DGzVWwPF%wbRox z=`bvb>xZ*U*<7~B&6qM-pPU=&>9N~9PLMZc9vzyGv-Fz230{*iW%8%F znCs~o9(+VkDwLTriI4V~>FL?_nUq6{kv3&EPw$LNTYB&z$x=oDH}SC(TTicHj}K%n zQ)SBhYmmExiP2)kMTJ~CZ4oOEu@(^&7Lp}k$rJGl9Gs_!S-Yc262*hF&~jx}5u99w z3*J=eCt2{g#YF_g98PgD^P5l9E?hk)enLSH>?ntTk4un$h((Z#GnGoJQ&d<;Rl0;H zs=;Kz44}a$B!v(N@bkiA=8Gzou^5sUiprSA{1-0EgR&%*m-G|d>%{!R z%-~3Vs#M7$$iorm!C55Pq2o(vE-DmDO*sXDb1sLRgOdV&U&txul!CuALl00UZdR_s z+OIUEnMQSo3;_Z@Cag#-66KQii;xy|`b*L~;4(}2ycm^lHDQTDtCfiRK&4xaa2BJ4 zTP!DpSXpy9oWe4BVtSJ*;C7L3H7EyKO#nj!Zq#C_(u!3XF%n3(S~2r!am^{yenHfQ z|CXp1R!YpmHxh0pLKa~Ty)03-Y%az<8jPuBsMVcEf z+EjA1LZa0b5+KL|+?Xk!00gL@S;){Vp8(d0{7s(>ghEQQLSaPURWP|irpYIO603-5 zig~K=PeT4WNwNmRG!L^ABnDl`1&G&a#DA5gz}m4)lH@N{do=$m09mBI)T>1)5L@UKFNDI*z_6ipfNPkQl<_z$UpT&kPX zKg%7Jf2t2loNNflnQA2pMf$lazza|sLl4n=Wt0dZ2|}ZmWvB?!s#8H#k)kUiNg9*@ z#rW|udS9UQf_r($_=G^CN&Te^l2oM-f^d}b`OHxl#Vm?XRDrx$#x$r}rSq19-%-Xd z0)H49O`+AGo-$06OIMBGS{bG6r4J>LOI1Y0Z~P>rMOsEb$Wd0A56iqIr=YN?Nd+Y) zo7|FArI7nPg*Zv78^P}iijpHnPCrQNE+td^Uw{;;awtDV{uzOE#pR&t`LBFNb;>Uk zMzW|*l7B{^A`8(=;y>hHP@Y9Zn^;9s75+KM`N}YTDK{rOzmRwbikpOKn-XqzHrY2U z6J_Rw{G6N|v3I)M3pv@@)H(g{G%%C5l!HqvAQ$gSqm)yKzhA&Cg;x9(`bKg7kDOd) zgIaVFDx%EOka>G_`+4l=E0pRE)f*l8`1lnrFihW8NVr@`L^aK26p5Xo>Q~%1*Mo^Fg z{X_1v)JF~je<(Ls$>y>gpu?&pfGHc)T`sfLUKx}W18HzdK~yIE%zycyROvVVj)ttl z?}d0Y1o`}tr^+K9KyBN&XV=$nIFd=^>$k-duR^6EYsv^kytI!K+>9Ay z?7FrNa{|wj@2j3HF=+*1%Y00Y*=!>{*P(Nwe~=5KNtUAg?AxdIOr18y*<)rJ3_U7K z5|Jthz*jnA$^d75W448{`6T~+#I291=T9kOih|tqE8*KGPa5t%VkwQnLnm@i4{q$* zqA9Mv0o$yPcVKiD!$G<16avEk=zFL7IkmxAOxcF5drx^B3879@EaxbFC<6h%IO)^l zwW}8OckZ$4B1Be|He4k6D=dht{E39QQM0^U^o-bSW7BcVcNCHpHJtir9|X}agN9D6 zh8^C(VSm-$m8!8}ESz+ZK&yIt&4j?E2_>B5 zFVEKdFB$04ed`(KIt!Vsl>pOb#gSc2wWX_5qgKtSTds-3j)y8CWeiC_mWIj%3hJF=YOwQ4Nd53voeg-(-x&eE)=-?YaUWv;ap^y%k2$2+%biuHr7jeY1D#>HO# zRgtPP#2{G&S)YbGw{2i%&Nel2Xx`(}lSslg0d>kwdUdsLkLD)ef8W?`{PJu*5rFav zl?5Sy_BLMPo5_9JS(%xe8klzNGyY8i1gcThr-Z=QoNbebJJh$s3QEte`O*zn;N#-O z?+3?1TQvry>d>_9@dprgQnlv#Z$Xvj`R_qFrAi-4Ky8svw~lu2(8%1v!pgj<_oB@- zB9~%D+Lj3~uerBttH*A#JNo`1Gi@|^^DX=s zYyI!fk5otMQ@7s8&d%O3y(`kUf00&9{LBmI^|3T_9P}|GEBWKSmgd#kjaY}DmI#EL zv={dJsO$6{ILnQ#Q`J%RBhSB+POKmc<%0T-+b#~SY3wQhdT%b zg0#J>{4YHIg1>TY|9t#>=3ekBS2bWz2|K-FD5`CH{zX!D+}r+*^cweFOlMdhu7uj# zSUL~(Y;9Io&89zbLNAA0T9^D8-EEAT4gHvy9ryTzr7rSWOZ@7^)477gubbBe%$hZ8 z!NP^d&)&@=E{sb00~w8;p76J`tmih&tErxDt=40~gOS--E4{fdWY^*Anc3N2UYw~{ z3pE}ZTq?k z_FsQaMnXlR2*_jHoRi&}HE7diX#Wlfu226gDq9jK`AX8a1qL3!{Q>?g*MK8yKt&5& z8tK~)d>5ac`0Ov6T4?y{zaUK@h<|;3F~-uRixw_iyllllr+V7f&T!?Zlsk?T$Rkd6 z`1Sz5#q(#+o{9N9d(NDhGiPo)1w-S*Q#(mvOBOC#J`i8 z%)yN_d*zP9apWX242t~BJ!@9t>MU8j2xG;ZG1ZaU%G0Dw71AyO3gO>Jr*{XfKR|A| z7q>Ds8aOGTfq{QLjDY9mv>IdPr)>3K22a56SO5Tk07*naRILNwU$k`UU=5@hdgB{T ziF|wk2!mEzw8U?PTPt=A`+->4l(w3XFzv^e%WO@xaa+#do_l%c91Wxqb}JS?FG%?u z8W6B}{#+2wl>ygYL$F<@p_PJEgrEK;?C9C(%*?FBs8MZAS%w{=AcP9YT2A!U`nt$v zdPrh+R(itgV@J=V5o17`nfW?^aaj^zQ@UPj?+p4~PXi-F%sCdg3K_084PY6PBpi0Az~ zm-a{6rq?6$AmEH5%c}4j0Bg6EnOoAG?}W$u4UoD|(2}96be0?qFu&yoipzHUckgZEj>9p34WZM-B-t=F9{{4l0K@xk{)csv;C7_nH9)uYlb7;rctnD zgsWL{Ds-}8_1YcWhfSO~aq@^kjo57tkRyMJmKOa=dU|4PGJJOX@D6pFjg*?-%TN(M z*99Sm&*Ymb>668~ql*!$e&!3gPLg;xMoN`kHEeCT-+^1)_3tU&?&5iwndD7a>%9#QC*YP1kJi13`OLuX)hcPkXjc9jPCD$83Au4;_be z8h-jAV8+)n6bxu$zM2H2SLB!o#vW4pya)#!WYoC3ukVEM;UC#A4q%d+^&Wz|%n0|M#&xth4O#rXm@J#Bs-_r1QgYN^ zs}VB3_nlUUv#_^~VaIW@FDeI}P9)xhsL)RRM`8koxpvm8q2)Y2IJ<Y1Rct#JaF1|pNK*=E&Wyo_e&~D_ilKd`R}{#jecmBRD1VLZzW||t z%Z2lX|9zD3isetz4H~sm04yLSfOA z?$$#{%>I9Bs1OL2_G)P8G?|(*(gbr8t{Wp(B~6)y?$$PL;uy_|_i7+C`@kzmCEnnC z2*krLN_t>#YI6Kdrl?%Aj9Qt`4=rigevq3Z+i5~5c}SL};9CU~T{?J<7-eW+aOBO8 za#~FcnAh^S5D6$Z;(R@0%j+=(AeREzg_gA1zPY`dx-aGtJ}WDZS;AP-vw=~oNm$u% z3yS#y(T*{l)vC8o#fsy@aZOF#{T~>omXw#rYauiw=!{6*f0aYZ%vnF8WgYvW8N??_ zkp9vH8z0AD5%I?lX2zvzW=+fgem_iIQ~xqV&H_Z=3DZPq%8uLchp=d7cXmy?uJ2O0 z-0#mD7}WGTSn+NGaXK!AO+bEPdwtFJ6SkAbIUbfZTYGQBs;VfTi|N zY5z}v_P8Hk++Dj}|Md&?{teLBFn4!Mv1&6M#u!0f_?ES2?tvskUs>OF*lc3p$Wu>4 z+7w5e)j(+5<6PV)en=b*E37Eaj3q&k*2zrE#qYT2pHnqeP=M@pl6@_!wH_w9PO{+B zIUN>SBEC*?#$Jd#Mk5pKp4|l*HBS(TI5AghA~YuS4lV9Rs1HJFD^7kAi87iSqRz8- zi^!>c{O^;!Gmv_XYu`Znp@`z7{*Bet)C|s4BHAyV+r2;R$HKEMdk5PlJ?}(;M@reb zA+mB4b9o&?>f7&u8KHD>k9uR=*)joX8Qo6+AtQY;v$q{;K6|U`c zL%y)wQ|3BJPUO{EYH0etH&|6U)KvF37@Nnp)3)gg`xxaOVxgeERH&7rq|$oX8wdWby|(3RH^=>3*%21~9lW&<++LW2+W^Um;gFZ=nwg(~BzGpPz8Ssntg|(v`oqQnJS7~|H z2entYW7=9y-TmzSk=aPM=~vjnfFp7^A@{=(V}quV*?B`7SEpBh(2F3-1wD@=SlG9* z%lyM4@e&IpkSS@^Dm%d63FC6_8j(<~>K^+m|?1^Cn8%-MsR)?w9fj1r3YACIXa z%?&rAagQk=ePLNYTU38QIk&gbt+DT)?)WWSIL5nAo9+YNr(xTG^p$r<477BE_n(+K zw3nH=d9&8tF20HtK|xAdfeLNvz3m9qJn$k76Ho}vD)jAOtkZTp__zo}!tZao8nIAq z3v1g(bGE~c5aq08NF}hDjb2AgCuKgZHg1dn#BUl1@uw(6T2ebCmKrB?K z!7BWA$e1$o+}OHpy~&0W7$1e7FX$lF;?v(mX%BP}nzIj97pN(-cTP`a()t_GE{6h# zuu#p>vzM)0FnNG$S3@10Md9y7qVyI9sOOx$BC#p+Y~LKDR{LrsOtzr8g@U}C%*@Oz z#oIdMAtX_73zB^Ybm%=~qF49ENW)-8&^}HnS#u`Z9lwGMyWsrlZz~NLMW(p|2`$%J_NMYBwK5Ry3e6?zii;5Nr04FQT-& z)evj`k+)dGOT02GULuEcK=6*DDI=sSpQ6l(Ev)Ldo|;wyTMjCTV<05QgG)oayVNx4 z{VttLhgd=4L+hHTUH@^*mM!sgY2T)o=i^8fS9VK*v07wJ89MV0U)aCpKv*ij7CaQy zaEKs2K1vItrcBWA#w>eR2nSA>RvLfbK#MhT+g*48rmy%z!as(#>M(L0P^(%UFs4lY zw~l7Wq3e*POP4HOyaXd)+bLij@C;l(Mf_AZTZ6f9T{#S}a)ta3Fe?p;rVM4;Pnj}H zJR8-pY`)BI*({%-c8yyG9l0wKmqS9siqc;kGS{=cpHxKL>y>etfM&`2bk^3g(F@$a zvmP3&qeaKxW3JF%ymNZ*cEbblkJHQgA-y(n&`p(%@KT_5Va$z9CdSR*Wr5Kto-$Ay ztHiILLr-4_z+Zl=fwO$hxBjh-jT&@ax@5_eG2We8)vIOd7$IOxnN4>fiaf0H2!!GD z+*zo3IoqkUrb(|Zj2|^>K+i7bcFi^%c}QGtMF|gg>8WX$H|}=y%9E6oxY=$^k-q(N z2>PsK@n71MIs68CKP)HFBj=6}|dDMOlbk9JQa z-UI(hPy?4Af5TF@`svuxPe)gE@7<++`|*Wv8eqWm_24frF~lXH*8J;}E2^n!HFR>n z{NQ6s?B`)E*){EYMCX?>_YtcGU4}Wb)LGlSLlShd3f`~6?}Cgev&_Rz%fTaG$gIlb zzB{4ALaQz&iE^Lmve3A#cX0}b$H)I}pVCI1-7bj?L-_v>|JpNp#Bjgh-QQy#S!^3H9ttV|2LBLb+HNC%m0#dJaCjkWIr<#{;NrW$SL3P@YdlvbJ0>&YPrfwv% z$OqGdm;R!SrIyz;m?oCv(Me62C%dL&W9UXS7*!x_{O{eZSdJ4yM39&Nv!+bo@TMAe zZdj|+QMusr`I;=W^h~@c=|(jcYtd0^%9KAqNJE7w!yF1LoafQdqVf3jLU>Y?RspzM$VU&Tc8qChB@*4y{EnD z((qS!!uI3KIX#5t9Uwu_71RVgB#pCiTpN~Ek2Jn`DJ$x_o(7r;rUo{AVGldw>E0UE z4DKYAK*d$IK$$7i*#cQN?>1`Wh!Mj_U`$%RgDeU&M&z}%!)n!c{z15?vaG*_-)YJ$ z9o)E@vF)hQqek@WWn*PBDtKoyco6{zD>y!m`aS0y5Q+7sD$vyM#r^Ev=5b1SJbvDU z4s5-4Q+QOSx$zz9n*{y!iOb_RT6XuFzL?b zYPx36GGL-oPOFK;k|y9LZe2cm_%QF&cfMZUFkHQQvjo^+k~3ulN9MY-syoFH4wqXh zgR|?geyDcrWvU47@i~d7VV-NQGih1RP1VrY(Ay$q+*4}G;5u&})k)L98QUy5?@v@m zDEKO@`$j%Ef#(CJEyrd-kZ_fBQE%#^q`QrcG<+7p{w6gCDF+HOJ_ODf@9jPA-iNfU z6I<7%_pttr4JH!YNXZ&EEF41EBl#+e;A*yOMf-wBp$`Q`#W@6E82JBWy$DR_260fa6>Lz!=94(pN)xyAWGHyp+Q4xOS z!0hgtrk%foKB{2mCky&=whLRW_q6>Y0k4n*XPDX3!lL7JoCJ=3+;p!NHCmGsJv>ga zl4#aqFw>*ghqRE|<~s?Pc(|+}_icS0G$oAOrh(0_Vjh-J;w$5p2I9(7RUozKZ)_Zk zH0<8x5vG+2<8N+KN7YV#;fYF*2?VH6D*AH3{TemH}?t>iuJxKh<#DRj!l`x$6w*!9FEF( zMT#3t8DFkisiW4z03_&LMc)^!>KQ-bnaO$?b=7WArT?Yc+^Zum#kk=DkW(U@0-T=?RufsJ%pk0zR< zykha_Qe2qN<&}ui9_wqONo4n@B~Kx*VyfSLCjN11nTtlv4ykZY3mkcTdu#zh`nSpYu2R=)vMPuTmSmR(nq4Mr!B4ow z#ggG%cIHsxZmZj49@(=~Anbn*Y87OEd*C~4*s$Tly**ux4C;32J9NZ|VMB+FIP(}Z ziL&ngKZTHbfpdMkHuavi(r4J>bnm$6yPlN4= zvDD4BZkq|z<>|;G7nZ(LGHG~0^6k0^Ej~uuRl2G2yj#|_b6ZBYAKx5XjF8^#WYX}$ z6qra4qky&rVcM~ ztJPpYr9_4*-_o3ccGcR9CHIPnL{D~1L26dd(_zs<^5V%kZo2gcOa4>}I>j$ezGsZk zf^e8{V+43MuGw_N4?@||CH)YpzV>XH+b=~l80Hx_!a@Ui29q=76{^wvrzRRYp^wQyb%J^Q z?0ZcKiI0nm`ua6CHtx=zdAQxLL@S??P~(I5{i%f-n!fuveYjyn%jyk1a|N&@h5t-` zv{M6V?RxTEBtCAV3XCaJ6y45HV`R`pKA+Dm=Fq@qBC*mrAK-1=r%`LL3s2XCoU#ohqvm_4#2eXk)FA~WSQ(x%aq_&;=GWbJsC51B3 zUiRh8Dq|a`m){cNVxppBW8=O)Y*AOU-!eG&KB=3v`@EgF)xMEdySilxVwv7c2EHk_ z8UdM92s548nr(@jj^qR~wE$vn{)tevBkyu5Y&8n$aXkHXcs00C9W+nwn`2rUy8GTU zS1DzFK4Ab?5Q9&5ImJqs_U+<2Y^4RBr{|0cCbu`Wa+yPu3O^mkruNo*%1;r}ih$d% zhTbK31(5VCOc$Y5$DxDY24BFsSIBf*L=KT5P20Cj_#7onqq~`5le_4*7$Kh~OY_^) z%VFO5IT!e7mqQ$=Wob%x?bZG%iQpjyNiWI2ats%CFg_c;BQ6XG$c%Z3 z6OLbhMwrfUo}>$&Tsef3-ojR$gaCMflNo(*=g!?HuNDw9mJ&eizlbLnaF#po;v`R) zbWZkJT-e@YsrgU>jpTVcV5ph3h3lXtSh-vd9`DrBq0^wn#8Ho$;=H@(_U_!d>q{zG z5u+QAr5UbPI!?Y|mt(}^DLT?V{}s4OwaUADr!WCezL4c8NkdY%Ur|nSm?Y++%JYqYFy6 z&l@pz*397G;6a@lupM09edpq~<%5vq&Gl%mWz{VxIM}-#+pM`uY#w!8pu{aWb-Ob1w=+zcBg+F2WIayo7bjp(8#Up#`)U`PE>N_wEf2TBm!(>l{SdP8>uMP|d4hr%a z+GqVKI0UZfDoDH4*T<(;uL=kZ3hKnJj&$m;1Ois?zKD$>?!boFE@}|`N3eeYM&R0= zr%9Xx<)90v0YmCx{kYJ7&1#Y-VEyidAE1^>;_lQ!sFk~KU|?WCU|@fzhBXWvZhgxp zR45iobwuXD&A61nm9vN8R_icydLX83W7yN%;f6KpoQ@#cjzW;sR1>ut{ihJPpk#_q znRa{YtZEvDzKepEjdj(oV;24d5Ay;Z+_xtT_OwOS8^@6)0wv@~fiYzYzuF=+z>lon zOV(W|LrXHc86e}{bD)foQ@@b^D-1Kaw=hqnOh z{pXLwOl#{g8JOn3?jv(Sw|r^Tl$qJv5a~Ax48rdQ%o;OT6KPIfcagrE`8phzGkxE4 zA|cieq|$FhK+fTiQCb=2AnTa?X*%>tYw z_02K!ni{>w%nS|+XlGNm` zs{@0UO&w9IdhO|9Hz1SrDtF~U1+g@}t3D{z&9`9-j0UO@l!8_9`7E5eM>hS4qL;ZD zdsa7W-Jx-tZ<8!g5xOgyPbf!-4d>*DLWNBt9v4n9q`zwJV14R+Avqq%6M)kq;b;Cg z2X)AEDUbd-fIl?Fe|>Z=UHTFIhE~jkyQ%X>%V_|IBDci56>Ydufy^Z4YTp_T9}8&AP-M3@6kRJ$B*^$ zgaT)+J4Cvd(kVS%{t!L8cmy+T_?T(WzQXzzsSZ=6_}32?&z*)#^&U3lk3SE@XTcDy zSY4_{pPgBc3Gnpv8Zlkb7W1$m z(Qgti!^3Ov&sd2rvB1*gMzjsiQBjW^O@MmJu1;B4PLS72kCnP^GKE{)TR zy|6cEg3su|UhwXSQKL^@ekl}lEaAo3iM}&lGM12h_A=0Mr66wc>}j_nas=c|ektq) z3)0_S@SQP#_l}K=gLYEiS4pcK4_P=VXdmH`5=Jrl{dTzTq3523sHrjMk)%W z-MJ_&YTc44xDR>^AGPnoL%Q}LgwYqWWkx?;JPW?`$L^aEZ>RVLvbT| zO`Nv$#^Xqm#^e$5Q}%6L3EgI#@44q+nG~5~7|_8rGvfB_Nt4Hn7y)7cZ8|96z->sy zVw;<^cin7HFVDe4e6BzHM6xL1e5F8X5ESlPGh^Dc+0SBO6_2(9B_ku^4o+ASa)g|5 zXP8Ob>FWN~SP`Fl7E7{F_Q1cqjEI#pr%m(Q_#MPeTuJ)hqLdA513r*w=(H?xPt4l3 z3KzEMLkc-PLX!vqiEl3Agw;FGQoDl`M*kx?y?qHzy72)Pj~SW?0R@S#7fqWsD{y-b zs1k+%O5x)(n{bwcH$gU}X%-bEuU|ZE+MHEUSyX=z*+_UcdD5iIZ(#+ciE{ejuLy^f8v6U9Cds1E z5WjAGDBw31RfWF~dDX32KB*b^{mavd?tNa11dwBZX_CG#kD?OsU@&Q=T)1kF!{f=h;=|$t&{9nlH^0U+Gw$khcu=kdV#8V)a%&o2fvB)QTzf98_QUxh$*t0~@dS)t5h$&|je zkt@~Ruz29s;t?Nmg$|_%H~=Dm&_DE42mB@iMq5pOm9a9dMzbsZGP$s_6s-5k4#^PS z2KYgOE|nE2)uVwR`5{FGh)8oum*#T$a?ByZ3Hm|0v#SExDPW4iT|@3XkdQ>>p~O{Y z+6|jBq%K51$Vxl-q0_`l6;&Bf(iB-nE2Xr31tgD>?nAB`1*IXMAflqBObi&Uu9$?I zfYeh70hFIg)tFQ7I@wZVoCvRhDCB<*b?iA5j@T%i$jqRAMWX{uDhh##iD@U!@_x zs3E3BtRMcycm7spfSg{f!oLB9J%)b?l{>yyh2IR>o3V){n;rXk>*mm12Ttb`=RX)o zgv{poAJg;qakD;o&D@GDvtAm1QzLCi3kyT+{74 z{`#0ePWO-uax|+hqzv*or1HSD1J-pI2r4rUz?@t*i#QMM>e%eggtl>!#t%4n3)eR zVP=NyKAW0DUFym!je)q1%AOGb_x`yN1)}%>cbQKyjFu;$q9Kh?&wX_H#Noq-j~qDy zQh4DuJ;8zh&oBIb_xPdBp`knX9Z4o`Pr~vzLkK9%dwJAd` zv(#+mo@!DcX}qGRSO0?U9R61#5oe~SiD?4R&M1{r6=>e5_cw6EZ4W#1KA!0y3WZf5 z8~S|j@d-Uo9Lg=DQPnK#u=0Pbe zdk7D#9<5!+*45Rmg=vlMqn8%Ib%A9~O_#m@ro0P_b1om>wPLnUQ#(r?UAwCh#Gz8P zJkjyLIPqDJCMMR+dboCKZlG_w?_M03St3#9%WxJrv&&%HT{uIlVpjk<6V}EdQ$1>% z)pK@pbMDl>hxY<<(oe}TkiP@QHvAdLEk4NrOdMRRbngbb2$?)2H-MJIHv%ShaF9o1 zBtFr~BlkRfJiXqwu70=PEw3U)Sy*5!0 zRvT94Pi~s-(6STmgAQyHeVcYS-@|oRs%HG9#NG1kg$)gxwsmuHX=h(wtCsbyOK_-I zRhG)2jC`@JhW|Dz$sdX}| zqZB?R|E??p{sq7W3fb|YTaXpn+5ZKo>OO+>cfA|ww{F+jrH`{qmyVWo>Nt;E{)4Zo z*?vEWEeggJ-Nhq6{_f~jg~~&0%H)uXkaFHN(M5w-!l71d<9a&OXyO%ALbS^L9aE7S z`*s2hcnNnxSV&{XLp+kfiBMwB6wY&R+r0aPEEvL}UkKsA^9~Kf3b{j$1t#2PtD&ho z?u*3hAC(6UYxeYTkiC5)+lCEnZEWf{u(PqT>F*0s?SDkwAKb6!w4jjPeq#}feLbFB zm#9*DX((Xs+#c2@ohFjl_M$yAdTSVUiXmS5CESA8C_rSy*Kg5rCj&+r*XtEi0QQ{H zBI!ix`X(QwZg%-26KW+ZJ&Vf+nj^05YHr`Cegi_Y9njp>YZ2K>RWg~Qe*U@NZuPLY zx3jaWZ)0OyAOB<1xZRLQvTP&*_xvxx^QZhD_Pzrys+{XP14tDCrHImdN05$)V(-28 zUe~tvuGstP+Ittp?plx{y@M5zj)(>EC9BRVL{*-hs~7AgBMv%jgakpYOBo}QtR z5&j&v<~SsZI@pU+SD7)?+Nj&q9q@ymq`>7~**n*x|HN~5E_tZ5vY$$#<6G@mp%x=mFj5Y~FWz<8;JQe~?ACODHAOLerfbi@v3)-=E+v`O z=LX(5;O^>(*=A;9G+^lDi$SnTP?hd$VxSrfhm`?ddwb$hz(Eo-x|!aSKNJ5y7={1G zz%ym?a$yT`@X&5)a7s~m8SXsUqfO+^hI--z zP9;Pj{TOpyTS6SMTAd7p?yUlHb3BKd$(xMEQe0IAedmr*9b}D$6@n-dy~HjHdwTQc z&HEn;YJ({W1)G=!Pj*g1NaJ!~baYfyWE9{{GEA1#=(zL;J6NdglMHy4C{;yUT}kqT zRtRl@q7fcs(H&&I%=F0{-jzU64b>kER5?sV-t&I;%1Sz&j@A|*9D#ioJ-f|{4?vf-DKlF?qO#H1|JDJ&s0~k?NKtPWI zxU_mK3n2yD!P({T5Mtw%kFai`)pc5QbaYtAvlYXf5v%PJI63U+#e0C20WKZ{EFaTR zNG0*x^o08U8KYaR#kzCpIxFLs64w_fT7<4wGw4 z8Oj@W-it085V~Xjk*7qIM3zQPnWP6>5mLOHL;~woCYsAhZo3cbTqImDAnWN~7E)>2 zlo3E#DfrJGncNvkbV?&v*7P?)`n@ADuR?>5Y?>u6h5F7r%qCJ$FE0V%OL@Az607eT zuR00%kMrKS4ajmX-`=?kk;BS! z-gw`*Tf|%FtaJZw{0i_6F8G=U3rwD4EL-UJ&*PAjak$)^h;z7G-Tve=Qyix#hQ{uB zjO};2pJMMMb4i`fFpMU#jP^|KGHAj6Kl=KNrzNh&F~<4r4DY zMdC{L5{mJQz!^Vf87^up_xZ;dP>WR@@U(}yh8vrPTl85}4Ht!v32BJy{Fn<8Eb(iv zir$4kId`lzFej%XOM|(8~2$a z#>@3UyXwmI{f&@%=l7&J2?AcIIKfs`ddtJag3zPbMhwgb&Whq21KUF|c}3$ostnn5 zmnn==LXv+4fwfUV%q*|>?ZHx-TCn;mbd*R%eq(b8?HL|cbGM%!U@kvk-EF8cdVmI(U0I1+Vg3kR z#b%l^_+2Z?VOH0(zqOz#Lo@pApJm&B!M;WPWQ_-rwI|_i5I_y{;RCHq!RS!H&yH+Q-)4)c@EQ3wwqo*tp;S-uJl8+jkc`QyaS-Uzvo?=1)hUWEoel^IbGBZ zdynsLrhwb{j+0jgnk(Tivkp9D_*&vOekmF|8M`#$J~V=wVQZEaJD z>gE=_vQ%wz`Bg!})x}6sH|{H`w&GOVw#Z}2Y5bLUGWOZUEb&&4-jNV(phAs-S_&&re>HjkiWsn*ttE8Yfr|e(+?FNLJeB0 z!l^*8UM9RWUTpXWo=TF+)8@|_)T5VsCkJ_P=|2zOr#HOxT8~isAmZf5hw!2pzD6i` zeM1hlI20mq)BsV49|I5LhH=OrLgL~ofCeONKP?ZWDE5ayJgS}Ymp=owR>{u-OXB#- z)=?dd`>w{>lW%z<39V;Yu#sLg-yqAqZKD+p`hVdvmC1J%k?euMOb)hF>0Z^+w0?T6 zh-Zh?R&wwK9YTo!hp6h3W!()(7Bt=ymXKhVD{1qEFRp7ykOX;C-!u>yQG_x4T6lSF zc^kbxWn5;qld@j_wG3pz9~EP4Wo#yF$KR^+KO9;*OikP4E&pi7y2bnuxa1|-pF3-c zn~a6Swy+Tl=Vf6=S5*@0JgbCe4PAdDFzIA#J4YQ%|>7au1Fli<&z1oK zrVKWkp`6muwr%GfkFCtODUQU>M8bJFqJ*8{cUS384nQ}8khDgZSLD!UDmIjo#Jk&? zZ^|$*)d!01)g|17<<5kr(T2Neu%(Q{REQ{8RSv?M{j4nuO(lm@Hr(e-{ce&T?`$op zGw8PQF54#y43Jh$4E!^i}^@Fp0RDL4NF39=Y?wccoc8Q$_}{7S)?vCU{fZ! z2r4n;#3HjU)1a`b1Y-q>8ApSlZi|w!Dbsavttk_BdLa^%r>4wzHB{cL%z^ocC8c9( zW^8O?Y-D8YH2fv8nPB+z1E!3mTJU?K&*AEq9)`814CzfdTSr;Dj00aB+J1zBTH|l- z?GQ((!_bw*qX}0Vh0MV?4lSef|-m6>f5ldB5 z-^AG1%*4pp*!sj%unhbTO=XEo`DH*~*W`o(?cF~F9+eOiJLI3ufgtz1Jak4R`0Ucw z?OalcuTYlHek7qCMb7vUMHs%C5pt%jy!HbULY&F=YlCEuMS}-r1y1A^&gf=fHEeZc z;G;2}4Utsq-4}^dl!);V8S}9Z&g!9JJ0vVDblDhZYyi#Ne7+J7pt;M7%6O+~s{Yc$Iil=tfkdkj>Zf>gC zT2@@cAuxy7uELA@ZqO>@=ENAtpb2{(Vm?s;t4(8n9%8E`qojrjP*-RnZQLWC@VS`; zl;
    !=`Y)bB$Du`_|4oV3?b!NI}%mQPkuQQL7jiabd;pE0Oq@+swIP;khZJ!`ev zt4!PE1w&PQy)>hj5t47y&eR0N)7aR!O|r`hFfJ=AKrAzZj*78ZhXTO8<5%xyqNdFD ziI(yveMpyIh3&HiozzUattQFe(e+YEFHHJJ2O;J5dRUsU+A=fMkz%3w2Yi{IXUc#$ zVKK0M`VqX%aVXzQ78-hb{ZEGR=&L$y|an`GbCW!i4IUHAg`kAq6Z>-&ezaceQd zJ&`fA9b?x!&tb5!yr;HCr}_BHu^HBC9Vg*0mzFqdb^C3~{D)9yfobQ&j^bLqzQESq zN-UvYqRvSpw8uY>DSN3Rfrf8?fb~K-8Ex*HY$~JgLE=`I&+^bT@R)M>;>C-X&N!$^ zw(c;#0M}b}PB(oSqtQFSI;bqiBIvVk3`IO8+)ey?w=MM&~mTt042mGr0{=n;kYI<%#B&PRBWuwj7?1RHB`mLrL+u8mY*bgr-A84-4u?_ zc0@?V(#8r*NqtQT@fK=Y1|wD+W?=ggrmfZEO!A0|yg7aJk(5mW91taB@`2L!?ai&0 z2!c zG+BhjQZ49Wv$DSyOUnc7d6Bbe07@gpwRQb)cOC`aZwynG(YZZxpX7;K)H8o9X@Maz z2@Q8d^Fc zcvoE{ZAA|96YgL{UcP!we?3+Esg(PlUp&xifgH!~1rfyJ`<2*Qd33^_=Uk;v_+RB-&a9mGj?7AT^AS_^yI9b1e&=QH$%QDQZni^zNPr@Q0U;WBAg704S1Z$;WaxX;=j@QDl2?doJCc5P#i5t71RORD*aKZ-wR zLMIeNKJZ^)_{V&B^x|H+c5{zlPVSs$Wi@>d{&IMZy;k?%rp$i`b=-bqFD*kzH3Uu- zghm*4d>)d}iGg0Fe4=$LlL71Tw<_>Ks2pY_XFDEi3htMfYZ?l2ojkg_I6FGKxO%u) zOSDkF5S4?A*gM`<>~R@a5}5`+okFGhSwc@r5P?Ca|r5D;)_+f0^(+JPH>37KDEe!oGn z^g?b{N_1qHAIb9M@{U$4>G^+Mk4Z?!N!M2OmT2kp5ez|axceHkUku4VN+%>VD2=xs zbYnFVZ~ZI>Ixldx$qP~uL)#yKWi!2_f^qjX_)A3*tUTUa(@Uy-Hxdp-h}h6x>e|{N zt<;UWbar!eaBy+!YN^vk#bzW~)+-xnD`PtemVO9wyS76*eV0KwoS!mc;}V@;y|R}! zQg(VzxC;w-wdP=M4+GSF$r;|Ssx(`9WHS+FHF$o>qJgEF!}DepzYrt1=)fs2hkpO+ zims@&c`|g(LOX~$s3;sng}GsTc*A;HWT(j8x#`YyAHTqc0~oO(hy&nNo6Dt?qWFw ziJf$%ZCty#x;Q&IJ9qPNk!PW$=OQry!kmBU>Oy|s_NdGBllWU{F<3o&#+j*hoC2Z- zo^PNZsISbuq@qUj0|5Fo+%u=TX|a0$c@|&5<1O5B1WcK!5d5_Ys^F9V0X)FC2wT;J z_{vbyIG-chilL*k5qwObx zXUdE-SF#;SBnT70p6#S!(qk=27Sh&4fhsP#z_f?NtsqG2&;m{UsS8X(@o?*K)Y34e zW&q2n$Vg2sC~s76{~G++Terh>*t@rTnw8lE@EJWi&*8Tz^B+S^Tp2J}xMivC>Mh)+ z9fXu`Z(P+`UFM#^b%6hWeq#ed3g;rAi;cRl1hHCOi-#Q+$L4pn910x|AGvPrB;9Aj zmd?-d*IJ38B^ThF>YRvktq|I91Gd7lX(a55&&$TRxVZERphxS8Zo4&Zzv9w1sr3_U zk@;|!xVT0r9nOmc9ouuZkFu3B>6ZyguX4jst5!yXbE&3*inj(n@o+L!0E~p z*BtnePgZ#tCM6*>)o1^M;!=9C#O?buSk-v`(yBcv~*)?{(YVbK*-Td4d~QZF4Dhl#t{@J0<3BAwc({^)L~y!j4Tq7+|4 z4vQhFvr(Au?2)#z_EX4gGpyHq=%R~^2d@Q@{z;S1FoNeYALDNsNul##Ck40OD`7ZB-kn=N22dUESCUL)rC1JABinn`E|IBtc-5|>~i2G=4M*r z+gxG-6~7O*RYC^67L!;_!WAWDes)SyRv{71qSO(#ZKSokrInDBiuaw=#fPu+re+5i z$HKI?rYS4)s@<-`O)pf(cHtqwO1Hsf}yhG4Dg_DKK2f?Q?Z{_^E3ARVpa3L zysgj#i@WQ!b(%>wItqDHBDCyX<86?FRYV5JWL|Q(jXWB><|;40Sy~g zU67R>&e8c@#kG6$_Pz72!{_E9RxLZtrB~iX-gVby84p+uEAAqyfUc$P7~Mfqzbgq7 z!Q9+D97!2QaCrI{z3PRLWn$ueQez%C1rhUYbzaPm360|;QOn; z#u+F{dEQCHm03|y3BwmIb8(>?LYmLX*}0ETuTxRhv9h+-S5}&|?id?nls`*en&GMp zK6;m;M2u`gIKmh`Z*mAQq5wLv>Ye1oPjq}cSC zAlUrsfb@Udg5=3Pt&}y)tPI-e8oNDy^9?6d5s&6;%ljfE9|DesjYYGdfLV1eQ;`!l zsDF)@OFDI{{|?@>VQCDd4O=sJPdXdxD5$o> zOtZsTY;Di@CvwS>6CJH4-rS5(Yu`*bf}{~s29~1XtQ5#n`tFV-Lc9FZ@pCIc^;cfp zGNWxfWg|;#V^e+Y4!wO7fuEwfMtc3(Sx;T9)*6P^R+h%?b*xT5A=@}H4W%DfO>^N>CZr9gaU2nu3454@5G1^(RLF+)R7)5^+P&rsdaz8{HxM5YrfGdswlzRO{g zaN~0XwM4VaK4;rDBxg@yVwz0CZ!s5H` zyl|H(+D|+^z7R_|CQJ!jyk#s%mie3ak8so)u=)xt7=TWJ!*pI;S&r|x7%yt05L~MG zoH%=!m7=;9R!~~H+5={8$|oI6e&Q1k8z9ZFJ?tpaFv1PW!n)@eSmkS=A9$)MKfww& zLOC^CD|1WIYP(F>kPiu*4MRF$Qms2!nVDH>x7Fx7ZdqC}jlx!+DhirX`Q^p9u4Wp> z`uG(!b#2f1fT%N7sa@1tu;kUSXc+68YPZv#xBhgQD9LCNv{z<->8%Y)^%x0XN#|BL zWQ6wi{#JZl%yI;Eile5?hG9A_Oo`PN_q2xn1ppGBOE=s<#6 zG}Y6bATH@zujlZCtT58)@XwLw;AK>u(}=Z2o4{4i;VNx3t&Od5)mT~@n06W-0-L^= zDzdg4dub`oF?~OnP;9rwaM0-|C##koF@9|eTO zk{fuYEtTVp*Kv;?Jxa<1e@`$@i*rK5BS>5r=(@?R-12YlLxRI{OLzwXe#=b4S>j$3 zuL!=YIVrI+@p*W7cywL~G1F@k>VuY3@G&hUBJ6LcUwgt{ovPQA78(a zkl?4}h9`j$C1mg_yjY${awDESee}e)ka&pJEUkP$J1ris~qLGVheiV1)6=#gI* z37bqkF-vkkgkh3=o=}pf#rE0LPDbp`IXod;1*8#w}_Cik0cMQ zK$C1=vlH=qJ`M_{Q$`IJssup=p}g?@Q=I3iUk-75A_ehsy?Ygn2@ZVzhIc+)A zH}5`>XH>j>5gF+3O9=>xh=xU@CJErO-zUDs8T;7V3=k;~*|zY7kH!E%uP zGMI?#<7Yv^fqaI)N{6|?hLS+9xgyBNM6QNIHNL0zHqE7+P{vP{070?gQ!bvL>!M&=IS23Z%0e+M` z{OKR@n%19NCc;uHN+BWG$_@}(!6HbVElS(9&$HlC7aS_ko@}N_9zYba*(XutK2Uz{vmbKExMVK|~A${o>tCP@4B4 zA|fJ_1d^-~75b&{a~giis}vG@vksrxDX$~(b3T)vK#*w_g*iAO`c*PDd<3%80nL*B zCMG@^=8``o$HygsJN&2A7tyb&D2mMc8$S#6kCUWg#{&s}Rr^E0slJ&G_JT8|BKI`^ zS5W6Yh0SU-xX=iIYXbLwS5$`YLd`g%2ErA)05}b*Nf$M7>$`TBgDL ztv~`d#&zI3Xzj2B0zmNgn&$<2~QFYk)<^o|1$fp0?ZoLQC$sc z;}-xLS2G^dO#Q(ApVE;3tEjKOexw!r#{WUoH)R-b5UHvpsMiVN_DB2B+^XNYp_upwX?pHCdAG9Z<|<_*hYm)2TM%OP!qJ_`sCs4|hEfa(J0qD2uouOXWYD}4MXkd$WVaXxE6s_PyKLzvW5 z_8P!Da$vAi!)P9W&xGUb8X2JUHBOtb*1?O)Q|0sX+i;_&Zj}p;}}GP&$24Aw@@I{4*;C6dD@n!$GV9`MC)2nwC&XVB){s6 zN$AT9T;V4W4%K~qqDE>jz#W2b#G%#A+e%pnB0B*7sMR)9ta!2|P(b~{LMxQD zl*avD;RA6O(mwws>eB~kNcDH4UIEbbzW0594QgkD;fTBMe9s1QRU>I2ob?m`!)VZQ znt`8RCk?=azlkw`_WMJ9~^-i?)8u2Zu-6LOwpfKggr2vy+Rfv$Lb4<6>~P6gi8_ z@cX%pz-tq_yEtIl#w?3X&!vx{#zJ03iy(&NMpmOANm;y>CxPdk2@!ea_s3=p8kZ zhLQ0m=JL4%yAFB7ZxQ8C&;^^y{LBq=r(j9zKV)Kf3T*!o=qIXQLppGio^0^?6;*2tAso^| z?;h>j3)h_6$jPgo=a3C%<(cybc|a97kt%R@@#x-t-%W`5+laI?#Gb>SDUXhI@7C8Z z37Vm>SqTBb5DrRomES4P-VSyS_O5@d`0G<4&*_!&;Z?wuVFR5U99#yES{$54;`a!9 zPkQsG*xOx+B-Jvl|Hx44;mL*W1?S9-^6uWf+qI}hj;3dTF!(IlyKs2tPA(Ww;E*{P z{Nuzwzj`!;>IWCl4}TmX`)(TLm{7p`SLEM0u%)j%u1os?GuOwHqbeGyOUlx>VP4aF z_rUrDi~6}+5O9xh43fSjN6i^E7%SC@Gnc02QC|&_rHKMBOIg|@-KRDK%etlrvgtoO~EtA^XisawZ>tb`ip>kzV1 z(TrozNrv*Y;0bdUp1pqE>&y`oIi%+{^=l>8(cs;d{CHmrg!D{cvw^9p>8yhf7-4QD z6dW>m%m_K%zGcg48xDDU-xzA6Dy7>a6MA`A&d7N2@PvyZs*)j90Lr2;b)cE5$-o)7%2rNvlWC>>}qGFgPA$& zuph&>GJh7Rm5>o~$p%-nIj(3E6Eh2gb_%%a{2^K+excHB6FbYbvfOjp3(M}JIrD;2 z$<|WgyrJDZ_vYp)a#G4G_nh*+?zMKo^sD3$a;7YOYBzhR0&~n|6I)BzcQO4Cd8x)& zL-*Hl$3G$}kNSO!ZjE$^^3Sd*in5x!PF?rD zxZgku*^S?ZAIu?}N1mNrAulOEZ_^>~8#lHtn|<^?xMbE{u;76*Ej#kM9Wc$DFwNXp zLkR*ck`Q)Sa$shzI%k*}?100Lgq=y}3Gjn@28meR7ynwFN9m_?>NC&8G3#K%ha zJA`FP7wZR0&=1r0-(f`S2g-o#q&Hz9K~JAz-uTeZ*Qvm_k`I9sJN4Om;+nVj+5S#y zEtFlNKEfu?`h$8tD9K(&H_j)bzG3=MTm{>`iAl|63KD(IR22Fw+=P|tn9dqXCf(nC z19=wOpc?_tYA<@@&>FSYFrXZ;AHSOD;_o(P=>4D4USSUS3UI(bB&w9CLN0KeL=CJ% zC=4tGhDlsl&ZZR|cW+=f$4>4JDzYt5+pZaO+e4#Nkr|;n)eUpC{K7fp>2&Rt4ZR4d z%Bte{i12h`^b;~TF(Cn|Ur1<05f8(B!-bUQWrv4{e<^~+Tv{ehD*loY5%q$;FaG0{ zUv zLI(qRu^0AFw39L%O3y1kJi}31rw=dKL-9+k7HH<-0Q{Am6{aVLK?P3EBkkIqCbv|f_-gq1)a9cjmzM;N{$`!|R@xd5T|p(Jh^{!4ziQ^(vz;MAhV zK%;E!pJ>^-!whcWMn)DMxTmWqoR zN0KNqLd}cWZhBL9JY*W>0IaSu%!knP+S(c}mPUpHmcm7{-SO?6Z3s!{IWs0gPy?cxG>QM*LQ1|bSUyW73h~>3w7<=uL@{Ca&yCA>p>)f!jGV&cY8U@ z@o@MHrYth>_Ia;IpG$LRTWgvRZ^D$JOMCu@CZbm6BqkqR8)v0tHWrSd;8YggzjglB z)5y}i7;|ySS;vJ(W&P>cHO{`r%)jYlNSH+2LpQP4jDo)D*XPg-cRft2pIjFik9KP7 zyC)SxKqS$12NUDi2wFDSR==Zznxf8`NOJZy!^B+1@_;mraKklk*G{#)nfu+Ck67u8 zD2vxy_SRzcU3HIM3OhWzrH1Pla(h{NpgKYePK4Ly_)Z+0>gqmePc=M=*PZN}?xA5} ztF749^B!zuYs!=<7}-&E|%F@it43CiT z=em=A41bux!$)6id`;X1`;D6&1+KV9TbT}%A+Qj}{>fHKHsg42Rh??q3XR=IW|Tz> zyio8>nb$4`Drceuqv8Ars131mq6tD$=9a(#a|`%%=sPYG_Gk;$ZK43TzE2E0b>YhE zk6&-C8X=+5g`9mS%DSk7+FJzf7Mb&NWP3bZ`8$NF<(peaD715n{ZvdwZo;$Bt3?sV zaYG>CIcpJldLEM0e?dZ?F%UWZsuXH{^DQ|pu)+J&k!eMCu!b1ga2u8~FoOS{j--rV z=acFYLBMbPMDPwS$jycQ)mK*!L@jNTE3hCSnY(4)z<~qDg{2YsXu7g%Z@96dH&S#>D+8^EeO z&MatW*7qZv)+^dd2QAKFsy=krlAU|A@Xk%wrhrOfru7i!x}ebxYboq$o8QfT3b&o!?YBa zR#tP*&g~_p&^cQ$Q&Fq|V$D4E%S;)5MdPwF{SUTPw~GG;XEI~`Hp#xV{tyTMa-3{8Ty%x{#`yQd7rrxt7Gv)QV$HY8TlaN0V z#T%%^U0o$E(>fBy15C-6bPs)Ty}@f4;I?pAYqGvmxwNO2ti_=BWUM>Cho1e2t+c7! z+&C1ebQC-|wdsYtTBdQc!%nnoYa00lng^ZHOt`aIR>>mhWvH2~%vutyq-j&ePHn9> z?7(M$lkgTiQ^se%p1D&^{Om^c1J9K4>~E#wSbGAtAh_VeTL~vr6vXI@v&L=#xozB( zsTK9=BvUaoViye78K!WAzJkN#gWT%MlA?-ghP}{Uv%TwrN+R$=t3VWLO&LSgi_dvR z^AF286{lU}jn!-?H6(*W^kJyiHmtk1T=0V{l-i2y1ta_J_KK#rm8J!a955^(g*T9; zxUzHrtBrf3rVM?P;?2`WtUeP!IKlJ3ys&Qa+)bD1O<9RgrjPM(aduvR@&2`ai^k91 z1v=<+q_M2{yu(5GYy9<1Qi__sDbPU)wY;bfE=YLX#o4)|xxToBxUsdPYbRGHXXih* zLJ-L4a|%R+iDe_YTH<4cjjjvvi+*5)!TNBo#jZ-!#b5 zn8^Lc&q1BzBv%g7leQWTu|Uajk_9hrNVCwoJDE&gm<$WeIu?ZMu)GqEEjl{Sk=52V z6W3sFjFv1~OidYv3H)m!k~T=hHC~x+tIl$qcNE`T1p$}1LC0nxarvidxFh7k(55uq z0Rk|g^F*7HV}wP62!8RGjNrhaD`$7RIXa&6O~x0iNl?3_M|)ZzWYeYl{B0+)^T`Z@ zh=u|nHga{z`-Q#DCFBgIEtqTP-2b1KUl}emhi8YUNGX_wB)(ZOafoXtw_Qgrk=D>i zaZq4o1#Bh?J^DvIQ--7xC-%}LXT7!u{L)F|6e-qpGXO{|A%Q_&7xs5{vOoDK0a!!kWH39& z*yyad6#my#J2mGyV4pTafpSPcm*Ib?t*%pQIlN~TQR2{(Nwjk7H*m|T+r`isz_L&M z%=N)eei0rN- ziA79~s>W|y5M%gDO&JE>m{wo? z6`{38BZhIOILkYZ-~K%0>OdD~kKV%{ML|bi!%r$C_qLBS^q5;+(~$@Rh#qdR>Hh6x zWY0wBF&X!zk=&`s94gLnS5_iP#Rz`n=kd1kM#DBhE)gdx(7|nff}e+`TpQcIQ>Tt{ z9lRv15RTBqsq2U6=z09{>g7Y+#kjfm_3|aBb_;(^0l-10ID64V7o8agp^iGllb@K_t%nBG#y34u8XWwp{Oxs>=aRZQ~SYlR|UO>xF$^yB?7!znX!f{ z9VXN*0DiHFc%1vw8LMsw65N(uO`<}TyfYF*L)O9K9Y#UyB^E+wAmTQ*LD`k%u<7;c z(t%BxGW6-(D=T`l)Z8EfJNON9xu2u8TA)=|z;OTi=DxN9%XQS!OBXNBo6t`ZAr-U9 zp!9PhbS2PA@09YShl&z%fBU5{jhLaf`bgZJnGql2M?ZnETn6vH6#fEHG2~t|7~S# ztga-d?%v{JA+MzC8j@Z_`V|o+(&@gcoYkW`8R{Eh8>qd* z`1nk4U}0cda+Hir+b+HP?f(1R@m=c`S!lq*6Kqh6jmaYIP=%T@R4-gzIncmuHgx@> zJ03cUO%FJs-p-7i55epi)={+we;TInwVS%EhOXVDIg8JoJ3q;zgSdjOUt(i^Hl$;R(2OTopy!fjc>W0q?*%=QuBc%8!4XRxv(ZF{MxSKb;cCTHirNlDsIqd@p5-qw;>0(ytrit!GMut)?q!t~xMudQ7p_-wr zIi?IaWpSCp6h9M1WItj>Xh_JpJu5A=TFI(8#ga~%m=~CPzuc6e+A93yqPB*;vn%Nd ziwq|>+Fn^k%g|x!{H3_o#<-fcXk!ANtz_1_ei6JbId_bWidtKX5tC+|KX-2N=$=SI z>0D3-VFQQOK=sE+^ES#SLqCuj5TUFY(gZj~v%44$SqTG8cJiH;sMX~J;&lnLGOLk< z+@af{A^tw=mW*?9?ECahE?49Uvg_=&+jB?@w0ryvL9%M%J=LflAcwiKYtr-F-0!f`dW;QC~^aQQAa5CPic29rczNOmyp7X|jW|_=N4S zfR0i4{CXQHh0Ad;KaY(OHXO9ZG{=--XoLM4ttrD=b?pU1qDem7JzB=3#}_E0dedN& zmU@Huvpwv&U9{A#rbDOlG0dnXYy66R{cJTCpMb+Onr!Kmgrexv*pzuhywPe9eSUHC zO&MO}s4iJP%oHhFUU?E4^x*vPu4XbVWY?UBPV=`Z^B+JRQ)bx!9T}UErJ&Ei_$YjN zQ<{a=+)8J@hDftmb5DkFsVT!{j{o7pQnN|N74#+2Tooy(YMPoFtID!eJCBO^Ov1gE zrFB$ixhyzNW@TWvQOJq8NWA5f6qx)FCJoI+b-|ZEN7%JcvWogpR^Mc)NbabBtcULa z{UUrvFP(be>>g(?Z8)Hi%Y2Br>8d3uscc2gD`p<=n}~Jv=9}PVh!JpT8bZ=O=}piq z%9H^`&SlC{pK8j>Uxu*jTv7WbXvfbfc;_I8T&C`fi;f5j3!B@;SgGTPu!!iqGF(cA zM|&h;K9YC*5|i6W4Rsh#4<;18A|MEMQSRz-F5<0BLo$k~vN*o5m-~!EB=M_DJL%pl zA%K13O^&}>Fn9B*wgXf4RG=&Glc zb#L2HgmiBNMTUlk`dr#7%aU7t=Hcs92zVOjwH~p=H1ti34fOD6a**e-d?=eEA`&rS zb7fXfEh)Phe>32n?Wur}akrT{5SW*}Zjc6&)(p$$hcSGfgaWqd43_bt&jVJhU0$p!7(*4$!WWMGEE+5{~^@z zl{vGxCsK089XFd@iOu<}fWKQH@pExy3_HWLCF;5CGH$qKWe|IP(_o#}9Y#XM=0s`B zp@nB)KDq4UyA4yjuoSdzL}Oi9Hp*J5eUFv6eyhsLu*}`s*k4S+EQzeLH)sw`gG;>4 zu~h_F(;vwqwCob^%nlkFtE?Q3m)$+uprw8<2oBB_aug&C;;}-@3DXoqt1idWxt7v& zA1w(qVLL2fN1t7YBw7Y!GL@ATu-+MYUP6*}G8h&GMD7LU!r@I=tb>n$uT1z?5OLaH z62pbPZLFn+>m0D=glkU#rKIdbSbuwSYfB4#eSHH1gElQ?TF59Em^(dA!nsR(8HsnC zaR9Tkq_iAshGm2FRlAZoaNdC?LQsckAD$_&&>yFWV`fpRo3=zNEsJg*9$mY6v_?o? zzt4wqup&giB`7g&af+jg__PClgyh=x38A?vDk`A=E*`8WVKbWSY!b0lLBSy#*ytqR z(Ybc0ozq9q?O2h*Vc8r`$z-gfhHl2+*br_`1X%?2=FCpdb(c3AMFb7@H$Z*lM`2TD z#!-I`1X^q=O5yi|sw%Gy{pGZKej?kGfoyz<^Rb&qI!>%kTtElF3=5%kT)prTx z5q9W071@P7lvO?E;2yK0tOOH#Vo6sqqi$r~0qQaLjkl7x^r?tX_3ik&pdHeM_2aCp zt<8+Fjc1^z)mB2hg{r3Rn6)Pvm>~H)t`q~#?%DxU!P{aPN4QiWwQiifrtZX?M2|mu~0& zz7m*5Tg}6R3oS9trY4wX16>VCaf#OIT7Bp3gtSKbcxZ-|6=kJWRaIYOFUhjd?#JNC zS*st)KtCLqXez7Sm5lF&&ZX2WFj=;-pIIjXq@OUn>eEP@miEJe9(H9Dr+-uMMIDO% zdzKB-a3R|qK{f?%o9)=vYV`9Br;@LQI*Q2%Q#aqt~m)M`s} z+Z*@)qf(vWdyplDyyA;6S$M2Kofaa`FP4xph{^+9j-OTZ;+l%8;nPeqFC|K#>xz2C z>#LHe<@Hx2%8AGyvi(pRfOiBsiFCsLu)i@ zE4c3!zxziKp>2;+XhQO>by#r)WcBI5jVRV~|N zXU`lv^7qkW$B*w_DkCnv*C(CfE3$^5Q!IBqha*|Dx5Y5;E4+Dri_j8BgV)?(ptEjF zj|gJxFn!dn(?_BxYA(*QR<|4t(@x)q@+5N^G-1zUM(|zO38rG=^Us07{nNp-kH17~ zNu%k9{E6tXNwq+)MAj5p4%_RhsRqGLYLxTc+${nr_{di zT7^){`!!p|lDs7mIu!<{O!%3lNKz|?hIC+OvcV;qo-je+%b>5|Pm~l&0r}?7C6@qTRv+JeNg`}f1 zJ>)D03#q*3Ve=3jq~T6XnL4ji{LWhjp}+jn8PRR9`M9ve0}rcSkOQ6ROmJn%x5T$^ zlQW4ftBbGMpoqT|z%(G2|MXqsO;oMN7Qs{o@m8tTe(s{E13;*x{l-s5OVl>-fB4cwCoiIVyhts#kqtT-7L7aJ23b9mKM782k0&nqxk3KHE7WDN(d zjEj#y@n=7AnRY(!3Q3PnsgsJ8E(YG^T+Qz!i4Qx&<`QS!@fyGQ#EX}3>3zJa3gC5S)rC%CvOJC$H%Q6 z*;z)pV@Ospm&{=ApX?~!%JODlTx`gFd$pDxGY-L?0-?S#qTj*X2wy?iJ_ zs^%aJL{PXxTo?~SswC=w8CTeI--i7%XAFzG@;oz9K*r4nEj1*;!+@F6gXE-I}9Mpzv z<~isQa7LO)Yq~EIsp9$FwMRRoH)sQlPkECHB;F3U)l>P-EBr37Od##^iRAK zOzRazuatj!dtmz(zo?k_pa(*P+V@oi)-RY;&?<3 zWm?RoWw`Yn`v+ZkE_mIkon&j+f>Q{(-0RL{rKXsTMsca|5`E_ zA^H7}-V!kvS{l!k+0e^GQm=0$C^e8pEJDxUrsASLN1ekuYy6gLFXCdNqN8!jhup^e zh{-e9UPpGGeF&m{VdqRN>a+LXhgCc-_v3T_-Fx;&#l(f&KX0Kf?=X2QrkU4Oeh;{W z1GxzSdrqCl)IPkhQ&tQOSbmWU?+NFF;M8{ycVf!r?8Xvrc-~A6<-wZ4?QqhnH?TaaY##z*#&NA7_Y}OSE_S+%9S|+5@9vV-K#I;B0LuE8hA- zB$&AcU$dekV=!T!qn(hH#lu+O=d0xR9A44Yv)%D<4{h>(K?s1SL&b5Khzo0BV~DiY zy*GK74zhQW2|h6wUt4wJL2PW$q8a0K+qE)qnG2@Or!WoJj2%S%Cs%Ya6<4+nNX}=- zbRE9rdw2@YXf}#$CnV~NN_zF@NNt2%r)`gjkB^Cp42(#C)v&V69%fQ1cB2B~;^P8u zbySt@w&W<6SU`q7SYbFD>2nd{72agF+?kH-0ke zM*GD)Fa5Y}-V|+JeNz*geOCkVML5ugR8(5*gMO~g2KxHF2TYF5$OrorU;X-OP$y#p zeLZ|#PfyR*(e1Ab&tObS`o8>(*vSKW>+2ghyY_n!o5m28NdBPznbX(U*x2z&0yHjB z-5x`V!k=GWKJD*nsjH{2XJR~Qk>~4=U=Gvy!x-;F9c?>e0^EC!z7}3*yN3{fg2bYp zbJTOHzP=Hr+GE_zsAMpw;5{)JrJoP2n_+6Ir>kQ-d(%Z?hzl=|jw7?eE?DYf80s4s z7#ZOL4e$@EzEiVd(zA4FFB|tU8_0BnFcU#I=zyL%F>kQbL~s^?@gU((a>U)?{X6O# z=-aqWc=8f_?x@Mq5R_?o34w#%tn`3sM&lQ3eDNN}spaW@P92>dzAdVTb786~D_}Ql zz>#?d7F`p-T|!7tMxRoV9pY?gxZ!d**26VpXkxIjFYj1lVrp)nuRD1B;*cca=ONdC zl6=W?hNXp$zP`R?*WQP(1;VTYq51Uc{+NNVxL{~x1Pdd;&jo*z2(1kV?&K-#q7NIU zc$k>#>FMZ9p0^f!xM}}ZojbR`5tN2&+Q`U&){U;w`49*)BBC?y&^5vhPeptuZ7E&hsfDcRPX1fM=qGw z59MRqWWD2m}T?ZkqCmX2dS5x1gxFGIU$ zCNI|A#NwcT8dHD%RRH8pZtmM@L;C3G>X{l@F4}p4oEcB2$C&s#N9;S=;o9%qedOhk z*N{;EX*J;aWu06!wnp~!h}75){uB3pF;`a`8k^w%baeDcqVCq~Fu5y4G6`rEUD!0u z(wvHVpCevD(8kCRpfELZ#y~sFF+E+A^~z`(lvkz6LH#|t;>xtLbl!00 zAz=W#D2H_0nW5*+jg8$V5~rWKrp%E)dt*hs=MLT2&ogCCF74$wUEk2w zaF#jyZZSk{(w6)6&BLL#CYUEPmj9LZ%HPG(=H_z{)YzL_fK&QdLqe0*CyaBSyq3%Y z;b*b8&+LRtJK+ZtBfM5g`U$2qWpD@M&f~W5<{$}}>Z0Qt=j&={8JK&Vd=|21fQ3%a zrI6*z^BxvPo?b9j54$Q$zfSkC?lfw39-E<&RHLqM!cQ5o>IB@(ADU8jhuu2b)4~i_ zkgl%juqC_8h`(6=$M8R<_SM14)6`_juG3&l@%RZ@POTbvq^SQ~mWg`G|Bn#KnBn^JZe+z)aAZPE4uX2_NJ1gB zY#~C@@JbW-k2TxhU>cY*#I+4bhx!Rk zKu8{VJ;HfdG!Vki1|Ur1eG#lRS~Q<*^0isy5uONnRd^1$22sSD*MJFWkO?!n_8jBd z#2V6?12Qo{?gjdUy-PD+@ZW&XmHH2=VHt_B-i%tK?^9FJb+QnS(c*+XODHIx8{RMY zlcozK3I{YXDtLr4!SZU78qnMrYG@N$YXDK#>jTPxf9MjnAYuF`fEH>dVYOrlVVWp@ ziUQ>fB>>LTuE_=E(C_tW{t@sSJC6hPlSMWG`Z~hXM5AG8HI0x%W>D&-Qi!-Lq%;D` zY+e$V)bFPkft$Df75(bfo7d0(UNKx!QuTIxE<@LG>eYIKGDSQE2v~J!~a&rNBgmmsd8-g`Wy*mC4=n@8nP&L{RKmh+c(S5ZkbtSDi zRq)?OBQ)3RDE=j@zZZ2MC)mFK2T;%B=hv`C@RjRInn-X2)eAU%2}oxht@uC2&;Qe) z3L`HuXhI(sT|)yMZC#f>;~z#sM7v)kIgO*PB>cvI8Ffq6 z(!89+#Kgif_%1ksOpVhj0y4)@djq$u5NFBBqsMyvxcxz&R`@wPG4Wjq3DdzdpScjj zqXu9CG(*0))#cgmGqOHpQ{;T(ZR_AsSY7rmG4VqV*^kjYn!jdc;MdH`rJKJRQot?B z|L(I347KBT@?`cVi?^5aMG)))DWmkL@WLh4H+)~3d zc6m}_;(Ows+a%L!hCV4ti7Dw2=A?!I`dRW7BrU&)Y}jg&w7N1t4&0q3}Hv*q#zQM*#PsK8oLEBDqz^}DB7pu#Q-e+d=YalzXh#!2WQB>yU zBqt^&r=;;n5lkbjYc5Y9E;pCB0p7t*BUGjULkTpeLRat>xt$iy7H@X^d zA!K${^Emc{5abPEPMzwmEcup^@u8xjuK7-Ih{V=B<|oWEH4mcZT7D_`?Yi9O(vkIR zkCA|_^_38Cp&7pUzwuL0*OY<4slfy6ZIs*TXeld?ShS}I1cf(O_Tbbyt#*1kI@(5h z<|iM6cNK{X20FKHnE;yf{P9V1JtJ)$9lds1>rO%77J;ESl-$e)OqJQSeT&F8=} zm>St!3x*&__1a`}K&dUwcxE97-tiPly8;BR#Tt9^CDysx$Msc z|1i$y%|m+_=on~gYq!+Uow4dtDb2#=R+Sc{yo}tpeo^n9E+ZB|U@@Lop=fX_%QBPS zoZGv8(4g*agO*SSR)MFBAmn>MXI{B^2{ZaSE2(H{D!29+y%bK>5k11BwN{xOZlhSs zG}*56xbQ~6w5-^>&SvK7m}#nQXKgvdCITR$Fer@!TV7&DceYb%tF5Knrr(TBU+L*o zkcoTe;2HxxeH{!fy#wAM3}2l7H$h)C;L;v5Lj%kJP4)I0PQu21vZMfM1kpZ)hFV|NXDgR0l&hxK*9@oTX==uA{4~r)9b9_@nxF@z7LZ!a(Q$8K&s3DMO5P z4WW6q(-=ATa2}B~5e4!#@ZH|Lz)ByoD7I5^9kk|ME;MI4-B|eAZ)itj9Zf9_WmR+A z{{9KMb?36{fNuAF^I*5MK&|!O0HF&0%bgr~e;O_!`s^}}!B!v7+FElSJ?RUPudfd%IS54n-`w`+~{Tu&P)ZL6-oip5A$)wk^FXi0) zw?4+L(8!I%N1b8P{0@sD$xYtRaVL0d%LpW^;g?YaZGkq(s*;D7j*J;Sdc=qke=J;n z&;K>fQk3qiA&W+AxrMVl_ueFl#18wVfwX+*v>a`3uf07HQaI$3!sS+;UD5-!Hjl|E z$AwjVPFS~O&ZKc;Mh+i7YW(<}mmikUeRlPW;enbmWobU9stR*996EC3=-+=IzVsxL zHUM_sOIuacW$y8EE;s$z$<_$1xg5tdSTf*)G=u7FufI>mXMV#a1Ycc+Rn?y)ST!c$ zqUSg*U7Hz;W*SP0*-V0ypBo9aLi?(aE9(t)49Co!)k&kZLPv67C*LNZd<(nr_uM(F zGhh@T`X%|Gi`VIqx98587nw;$4$$~2Shnp)X4|9CP!hJGIwx zosnJ4ElmxzQ4{O4=qycsb$g2hQam04J7(`6nuU;@SKJrKB}~b3iHTG8`Spf5b0&@* zJ!1Iq5hJi53?DURWeVAK8gcXFoLSRGje?6K$>+9HPavZ(`}+q#-|=JES$WiA!<|U{ zVxianAA4T`7v=KxKT9`AcZZ@9b_W*51zRz&CB@FGA{JnGcU)WS?&8`?H-ggLvFtwo zIWxPkEW3za@9+J+|JU#5UVQd>o|)&&%$YN1X3jaYN*bYUcM=#F7?_&;i0%gRorbMQ zEo8H+3ql{>jn8hBLHVr~_w1avm*2+>5Rx3e%UIm4jXFA}0o(WN-Lrew?mai(g42gM z=}YDF*QnPw-o&su+}y+uEj3xjgO;#K@k!Njxh083_SKxkFn)-gJm*>QB@RiXsypG*|PR9vxxlz8jb8@4{^eJO;6OS4-b$Q^M1nRwy zyJ&vMzJsCB894dpyIW-t8b?lZ6w{*_Qqby$r;pxw5sm98HTtHxGP0YvkwbUYYx2g~ ztJx1U5~nEdC#8>kBpt(!Y-@`N#?MnUB)SpED1MCr%Rs5p9m zVhLgy{}WY)4()HQ?f3MUHg?Py+zrP}^E`I(F+@|XRTKVO!7DKcMxiI7L8DBRr@nF2 zk?c2PO)l}?$8A@T^m67X5Hq9U?}(9O#(8-8EL(G2P=^1;zXzTwla~u#b5U1TBcyU4 z+(iL*g2yBImQf^VmQPo0QzsIx4cfcJNmsgu?_qp}B~o_c{hl`ZI`(~LuUx$-~TvoGlit@{dz?^EU<1ikgy)~lB z(EJOF3ku7jguC53skNRU&<%)`t4bekC5yGCz^ma59L4v&s)IC@D_mRQB;x`@@EtZe z4=eBE8Jx@Bm%R9BaaUF$r12mbz9v$Z@l=`AN3BftpYRVLWcZc#c;{5aGK15^Nu}-g z>>**~Oad;8$cqa1)F--& zYS*JlyGr#@Q32Jyb8LHQ>oGh(WkUI@!;A1&nsu924DBVl%P>$|kUa0r3H-9txOupq zXU&+175%|;_K~v$nT?a|khJ#F)mQ@fyLPi$`%; ze}4*prN=lw{FO!1-OMzkn)jNPSO{}*QJL{VBrpEM2q~NSuMSw{zhXc;Ybgz@d$IJW z5Z-I#-$O%p(B#+PIqCM(g?Pf@I{4pOB;EMYh*>L3!z*Z&xfv=3yRK6)MN>97D>g-5T{ zC%dH(+WDf8sfsd?L9PKI_-17#7_qJyZmwiK5F%8RCik_L)#*AtU0{g~-r(jBZmwiL zd<{s!%1S&AhXlAHIpdE7zz5J@%fAk`!ChGO!UxDkoMkK>t2kdDt0FXQ*AuM%!zt8E z&75B9+8ri9@Vdl%+Hz7G?^1gU=1$NUq+}HjCM%+6IJK&bg;ukJkK*!(-T-^aWU%(^ zX{gl6vl=U3)s?uguMYVlq;Mw*=xwBvgTn^=U&BGPU4BAcUHAt`4ep6Kho&ka1il=4z0Ar=in_wlV1GL2_?Q@R5>oOJlA%+V`9@ z?GI(MZr`dw=Hf>;v63oh^)9=H#2Dn1#^1q%%ABLT7zx4|K~_9f#ztFZ*PW8XGF@J;YvEmV3eHS(YRUjabRa8N;l=V<_%3Lx$Q6ND-7gA$7eaqo4AsI)&B+n zolLn~T^vmH8Sx92H#a>&hZQSxnTuLcvC2?Czf}jg3fb!(dnli)u&ohLb zpf)-A<9l_O;^U{Mu5#cN=(XaMW2(v&d_1QpEp_4p&(!1S+}=p9GYu%eZDvQcHpBR@ zf3sFa!`577#IO@DKHfeLq-YXf!xUwHOHPH6m4TTNQ}X$ojFjS$&pd^#H0gmJLIak- zR+`9>o~knbqpS^`_(u(tglkEonR{Ssk{nzB|3h7IvilgxwH~{P$RH7f)dD90<3D(Z zyI_E&yzRsiauaug<*qH{4ICcD8LwGkiajm3K&zTV2j$Hv#JN{;% zjDpFtbkeDR>g!b29beE-S$9Zn3k8jDj}&{5b``CI{#x+X6mvdz(8A)!;z^?i=TU;M zts7(1({2CinFvV*oC>|ZV-_Be+?E~YKqnQ!X$=1>rSZ4$c(m?XJVVYp5Ppf^(3~M! zmII>m$vGzf#!SghHwYrs1h`_SB; zNYg%>VZu+%$Lh#ca^7`iWfj=`(zVvIq&B*!=iEd1lAeqmdSo_|RJskv2{DjGMcRa} zT3TAx*TZ>7j!}Yyz>}eG|6;LNt3zP@xuO~l;|-qF8d>xPB`En`Gf5PDk1i#ZFL$xl zZa0}|G9pGkrgrd4ec97oM_*f4$JW7r&nY$)qD4YdHIyjf)<(oaN60}n z;wYq`#|J*%J_8}Gn=vJH6_N`E1?8Lp=c2bpw`zX7Y=IWvZ^%ygBoJ3zZp*-?f2`B^g4cl+zEj>pDdNp@YNvf zM2dme!hYdH0#)wpha zOICBbaziA}mnWLiXxfg)_bkhn1tG)dnIz|;xIQNG6574u*|28VR#Rr&{7uWe zTuclMHPsFO+yizJb?QX}P2%0c{yhBUlF$;FUO)j{|;fw4y2Q{@EQ%fr**{igjyq&x+PJ)we z_~EQ93myMRW-T>&GdpWrIxnIpWp16`PRY)NzWnXuX{?xTxf2gY_?W}dwlsXTZ5S9r!7koG)g=9A0Pr$;Yge)el9$|}229Ygr5rYC%WtI;&*X=ot z-br}8OA<*R|GREksD?zmjXdX%N4aC6X$%Ax7D1RGIOGJelJF1(gytS6T2VF3qL_l1 zzWR~~DXC~0FFy&(GlD*kLZI~-b8nZKuC9*0o_PnS<2Q-z7YA0_Fl7(6PBHE{v!o=| zQX2UZ0V}ct{v>$Jk=b8QYJe~3f&{5;rIFLDqYPh_Nw^UxZ_p}?I5~)@-zI=+2FK?0 zkyGzWb{660_HiANY9BZW=_hmjG4NEGyhvwTEiIFduTsCS%G}vHLt0t3i}Pro@qLxG z^g9i3^PA9@W!Uu#S+^8PG;N*G1AZ)7>-YKaM%`<~T)mBhgeH4#xt4Euxy%p1WZ8qs*DrTa>T;ru$P0BK}S5@uZvSp$Gy_T zwz{a#+`~+*Dsy-)l2E-(lpeaW$|e@yVwjBwDnoPMo|a;vwO67Us>(3j4U-&@g;OrR zO1h`7fb4p@PM+-E$=(!}B} zXb4#ywb36dFOupJlOdI2mEZc?8g0A-ae=3|*Rc6x1s$pO`gTM59a98U84DFOY&F@M1Ol6qJh?S2kB zd2X$g?8gSd12QP$@>W(<6n#zHzVr`-6gFOiK)@o^1q#{=USB)3WXX~-&ONN#^*DA9 zC*f8@Ct|it?cwAB%FW#%H>BJunuOpN$>y{h=D$CuDup`qA2Vr^dz%)zWtlqus~`s*2*1^fk3@WqYswCsoH4Ul9>51F?7Ykql7!lzEg@@Cz=OL6Hx zo|Zr|TOYx>OBEFmq2%;@7Z$P$CrVR8@@Pe_p5P#-Wj1-rloW^1?wLk0kn@~ zMqD*UGPBl0*l2N!D764(59eI)xrc^I{|VbcYsU>hzPR0+#(^zlL>d5}5ZVl@8vj%>2HxYTe$$XA;kEn}y}- zlr69__aEJ00{ID^Lyeb%5`1s#WW>^aQ^us-T!|;-PYRi$r|ac)?V`v$N@P{gWy?ze zqa+Qxd?i7M1sRg+=pQex1qQwyOWyxami_-UYB!ibm03BmxlD7{Lfkl9*x<|ma7K=W zR^Lo#iry%((4_4TaN|~xgN1i_I7;Yu#4Uc*x2>dJ+bGcs3)L7df+<*+&=ROR~zH{DfLPr}Okccc(V~S5 z7cE-)AS{iJ$;W5ANGO^5E?K;2@nZaB>4u~EzgCs0%PaTXuAl|;7rczfy|UU>TBB>-q0i4QnZDF>EFEhCj$++(;fc2}yoqAb zT2)3x67?PHgZtVz=dNbmdvCt@m==GRPY-ELvpGwaEcTw(&EB}DyWi_LFjWz$8BvKJ z5-OMdyKu?k z#U7J7v@-1Hu`G;w<+0&;>6eE#T9PwX5YI9(w(YgRvJARyS<>KED&0qH23leF82(KQ zJuHRL9%5vc5%I`TAE{Ulhl3ZIx`|Ld(nijt*E|>mxlG=N(>l5qS3acTCb+lP7mub_ z=qWDW)3h1^^}FVaVnP!qeMCzoSw%HN0|RptqoHn|4?o1iL)cq}LVbI%N#4LTqJg(0 zL%rhpaSa4P{jO{2q?*C0Wv(ms6guc z-*7%edI}IAg1bNq1qXiN`|yBd1~gNGZ>%4sXg3T$d4J4X#eM*;i>UJp6b#$M@KqU@ zyw!K8rpZIrjFB?vOxAtsR2kUE#Ih*iwi-fX*OT2i^6~T%gk%oC29>_Lis-|< zk(|BQ*}R#xR@U3DoG%(sIm?RgyQ_Lfzgi2wzo} zSBUCmb-)@SE+Bq$t&4+d>+wbSs;Z(AOJjE4nD%N)8oI`Y2KojDMtT|uNp8KH088bf zib=n+dYqlCl9~yYE&BTSj|4(fH{HVbBQN8YRlOcx&H;M>Zo$XX@<@8$3)rM%zoeANTX*qsk9ohW{%{nBgsj04Kt(N`|l%j5Ym5{jel0*!lgdi zA&C?&5NTSUfU^E3as!v0gZrX{VC@Ez8j{@hyq>L06$z9%eVF2b!AePO92OXf;A9N+l*_(GP1w1JU{ zzMh_;iHV{V%d+1rsxk_vCu0gzyTSBrL%d4u{$#*wNNGm^Vd0~yApZD)7gs>ob)AZTo)AKDR%{C8&HEpRYAWs60GS2taQ-t(x9-?eq4kz&h8;saa~c|i`Lb=S#CbwTVvBNaunUeBV)t|(1e zS&UVL=o{-09-kr!TbD-KDxlHpt}%Q;##9%b-s$h}9~7BEcC2Zir8ioN5zXm#|e{h9W7 zhqh7ccWEUhB}Mr~B_+jaBkj~%jo>+g)+M7LqY*dlsfDiY={IS`B_(+UI89N&Xgk%G z!=OD%;yP+b4q9}YzP@Erdj$)ZoN8Wq#6h6aN=Di$%CwkF!VWRHpU){FwBa^PqZuY| zu$eS9ybx`-Px^dK{-@^hXhQHEdT-efD~+~OO1VHeH4344bZ{1u(zqW7t8XGnqpA#; z{YuO2;5%dq;`pqA@+PjL==hbulgHZOG5mTER_;%{!rcMxg{&Hllx<^4$6-o8n@gZ+ zJ03E8VOkHQEY*p(jdcw}!m^4>it`F^(-kZpVy)5Moy-8S;>mC8oKRzgI!*`U&BmAd zs;lbQBX~j^BxUwC8^2%W-qqM`^@Wn+;{3c^{P)c%JSWk(ok&)B8dNpk?DxEqwDieO z)I5e^$6Udq@50kz_5!-tCZD%M@|u3WNtLGv1iUqM17%(R=%5be7Ns z>$l3!XQZVSkB0G#i({YcP(;Z8EI2xe)Y|!Gzcz+_JZf*Q8)J%0dcx_R40o?rFZI@L zwT~JH{lwG#vn147Ckx!CM`ni}o`sP7na{*-hrzR;F-V~mXzikxpLnQUieP_xsD+S| zA2C}g40ANr+&m0{r)YUmqF$Zs}}NKjL!}4c-Dw*~NVU{{Cw|r4mDVUZ2Sv zXe2*qHYiC9oV*QI(1J+t3ENit`)@v!O%{hKNpveM^642YyH7s=Qz2Ny zA{=;PVSitwIPIkAk&kea9cS*5Hlc*ke>iteZN!hB$3Rj_G9{oaJtElO zfAy|Yg&-2@5%B)b5uD^Qglyp5;n|;+Wggt%@4t5Y7ZP5S)+60#On!d@CpmECIlitT zJ8L(C+$ht2J~dmt?EuVh@gd7pP1?tTDg(q9B)?sQhp2;>NMK8n8Qtsu@<>w>Ek755 zOF(VIp-OA==eV}C?lTL>_>KQK>V?R|czj@?qO{J4Dc<9qTC171d6rZHVhpoaMdrlb zEt=W%^YQj}(2{hTxgPe9$;x(N_Z#8n>FMP)X(Oh{jB2=;Ccr${+2_^z4WDcu#MxiiR%S3mk;M z5qBFaA1!)}@bdKZ^ziIxrK@k<=RT0wz}i*-b@5BBQ#u4sdUJ%mwLO2f^+|`k9XoEYi__MZuE`qx=Kp@ zMtjY0?XI9ptnHcmc1-n|@5+d2EDlU~s9>tr#H zyKP!W-R_=(rH#KCh+Az7u|2x9ZEo*T6L25w)?Ck|)6np&ax#cE$cuog@|S|Wy9^qF zIcoHf_R@;FD^GygY3h?5QnETv(*+W;Q(8(R2lp)?u4@%0K6oZ;uYuLuI#0k%K6Azl zd*fzi4kKdnKw;T1$qpfvshC|oJSPktpum!yzUCqq`iSURDZPDrv$uk@=BSz89&WD9 zG@2iL7>94>5SMR<0b}u3hW6{#Oh$I-!hPjrBoUbvRb{{#TUHnM94rLJ4(crC! z6h~dc1@}1&(xZ`Sm}tt7lrmD=one8xle1(0PdMYP9 znEKUWPn<-mEm6w3)OVdOvQ>|RU=e8HDKKxMYi3-sW|{fwAUu$>OAzo#r8Tp0yeWRt zcQNQ^^bVz&$$YH?X;{?1glF_!4d1-AaX5aUH2^jfYAT@#E-!aR#y#=Hy91MvaeK^T z(SP|OIa4xYha~a0)ca@ZkXVxU^9ZOPjV|ON&Z_V;&(d_o9gR@JI72f z=nEbT1NMQ>?k|!yztITlsWNm3jCpz2&)0X+^5CRe3rU{FTl&|ojlRCVN6y}dUxc-4 zo9O++s|)7M^YQgv6%h3JZ4w831mOPtvqx}}jl2FL^HM5xNfLJP`F-owt=k-(NmpfP zHlhK&1OLO$KfGxz&h4)&AdacE0Xr{gN6@N8^JdSQH48u5wEM_c5+gty@6h`d840^L zZou!a+juCcn7j{E@uvQvH_qX_0)qGF5L0%sSrPe_8~-XOVD*v(^L>1MFbzIFKKri1 z=!(Zg1llLL~3^^-}39YcTeWb@}0MMO-veu*7tf4p;k)yidle$XzyzVLVUsy(^CPL-hqFjb|GF6^2+7k_)f zvk#ytQr_Twq9*_B;We1BpnZ49f`(|0B899uyKnv3Co%O}t@LZq8vnD;tZc?z&CkNo2;tWn!M5S-8zT;~gr_m@ zZ!DPW>*E*rCW&lG;;&>zZCORW;xlXcs;zG#$= zyv6}v;+BUT4qUe`IP4pZ=S2xCJ-K=H$(wWqr5>rY=Y~B#zhcFTm$3qpge0uaPudf- zZr#q~Ib?y1rld?2{o(?a-RB>}tPEI)r22IC_}bv(WD&mJS7?&V=%+Zzz6%cp8H~Kg zxqo&We)K91=CnMT>8ea-)Yf(Dg7%*)q5~04LjL`D|0GUwEtK>%UJ~-REbAD~Y{TA^ zLZaXBGK1VwKHkAej$Q|IM!H}e_x!^8eP{4R=I2|1`%d7GIr6LXfK%TG!Q=Jpl+f2UA=vj&2ND6m9Jv_5|_3B0Q{P5Hrj|EiPELnT-w<`0W zf$(vXLgQK8PocID_$j{EiBIzr5Rzr$MH}h$CNE`}y&5{=-UZ zA_0x*G5@WoN3$?13jh8mXhi!IhkCuWUg{stib5<2Vjt8&SlWnbYu*gw2l1mqph;+u zsW_U&qn&7@;@xaS;zVN0%6`3$9-hGyAGa_zFgq zNK5#J;Ad4?S=n$izov#=RfV&xYVbq^xWvkxqOt@iphbiMjRw27MS+vBtE(tWRq>rvq3Ow{0N6RuN`Wi3 zxOiVY5N~`QcUDvgy1drbGer|=V<-<00tAFc-MM`Agh``d(;DUj+L|^rKeyU$g&znf z76va)L@k7l@1`;h*Fe*X$;Hxyej2wLVL@n3sBXHM0$x`1D?}iEk3$+qJr5>qVWrXL-wHzV5!czAhw+@1Dz?1r!HGJV`&@dOF!J{d%Pt-6E zAY$c5v?~ELB#ekFv3>ie(eOjxhj0sVNd^3PJ^&G^_}L47qH#1vfM9MvlBbB8Ap?d8 zN%YGhOtAnVB9xm(K^NrfehMW2304=%4Q}wSgpxO`z3)LFg~*aO8R8O(y!qo0UTkhU z8m6nCm5_-0VTfPS{*R(zJqxraA3|?5MEzHqlA;zr^zwfR8jO~|@jnR>wlaxtpDbCl z(0|>IueG~;JaJfg`OwaV3m2XyM&QDNkbqdn)7!jG`uxgioMh*r%fv$Jr$vfb(9a~l zeY$MH!lf$%!+{889^vrW7*ULC})CWd3~8wRhj?j z=FOxGFl1_!G#+qmV@fK%ehd!Y@ab#q`C3BnP}7Shp}aKv{`H&R@~Bag@Y5dxog&{p zwQJK~_sEU9?C`w!;^6~k(MGF@$S+e!^YjAt{0d5m`kqWnukFMjag0>ya z=k@fu7wUsNsLVdOV{OB_naZ`KMnv&E5J6B-Rw(br2T0(4c#OL_G1^*=~ z+P@Fjju5$Q^BezR2zxNSIJR6xMtktssUy2K*Rbjonpy^e3G-!D&U9xxRg0cer%q|5 zAvw@@Qx%9&IOPtu2nZ_q9T1D}8c=?!Hu(;e)Mzzj>eQYVs&>xPbE<&FYx^nPVEU16 z3$IoaKROCJPCPm=Pg6r{=%gvbo!Thq*_?a*jmR%i`O=TEORpW-Fni{BJ1ad&B)920 znC{aB#{8sr!TyWfTzYA!DJj|v&4AZMW>gPc;_X+R^WI(>Aw|bH5b;pXm=~A-oa^V@ z-CkKTHFM=WC=sN(TJqXh(zCa5m_dSK)7 z8RP#j(N;%tHjf2QvV>g>K1=cOome2y-o*Rq)nVKM5~J=HMWnx_}{%=4Mn$<9nx z0(tKQbM=2i?!exw5Y3ekijeZ>gT0H@Wz?NVyH9p^>)NgV{dnqIA)EO z)JdjFQg$x$i#Ralz%M-5?x(4$J9g6KvCds2B~=42f@P?foe1)c>V(O5wmk-qoib%o zbBkt%b|b=bDuKz!9#$nSKk?>ZpiV?nRR@7LXq^c@Y&xscUUP2cSb<(cpxY@0XNlQ> zDc|BTSWe4w%+#rq$GG%%ok5Q55LazH0CBJx<5cDp`e}92JF0o3fp-BEw`w+-z&y%%S(7sZ*v7?A|%x6mehrkLm%WVTq4V-7ONH zxEAGQWtEjxVi=4p8K8by-QdpaZ2iPy(9r=6?*Zy(`2Y;ui92L5%8J)FF`z@yNux@S`kK}DW5&QdsPp4%O3L;_X z-klH9(bm>CHa0LY(6wnX)@RwrREPqCAI06-fROCzPee&7{A44K#&4ibsz1}ZU_ihy zx3+t#Yv`PM0|$M8Sq7#u>u+;el!+L2x5%w2e~yz6Dr0K}_^;TFyv)<#1|U!_I= z7!o%V-@mkfncK7lw_o0OG16!=X*1I_Rc5zmw@%}iXXjvK=jRtdd^`fG&FuCaprK*& z{401fHXfCWE~QmuM6C9l+`L6|0|P@#6T@yj-9KfPS7m;jIceOgeW$POTELRfxdwq- zz9-tD34r)(8)ho0tE(#;?|lX?LKty(cVQmTGcYzZFwizO9yn=nWIAyY7L_5F_)O-+ zJ)1JgE%4ZdbL(axNsH&1aFb2q))dFxZD*>jt7mM4vokO-GBUz{SDqx%AjEJE7eY-l z?3{2Xdp$iJU2B*5HKYMJ?BY#-PMxuM!;2@UEs&Jwfv3!`R%IwNXMViY5^4ZQHZ%l+ zZ90xkEQ8@N{q+e2gw~!1Uk^Y{RfXt7lmS!}2D#ZbYcrnqyOc*e5Ry3pDhpGV_QF&K z%{|6*^wGpJ>uk^3|!o?or9sFp{cQMyLL{eA46xXf-2(f@am_b(c)zqbaT-q6hL)FSw2Bd zUT#rw=F~2xt_x3527J8F3rT6+ism^!W2L?>3Xo{fBhT0YV>)Q)b_y?m!m~->iTtn& z$_TB$kw{+4=w~R|#bX~N5W|@OZcTAv0VXUjCnqnzFzUueJ*}3{N!%BvEVYlGT&Ibf z_=!1XO&a@u8K_Wwc4VQthUUH}UvN38N|EvIf*o`|=!5!tdS;eZ2720deHRi9P`D|$ zRAVbo>T9L#we10Am5evXtc_Y;iO7WVi;@ErbTj|jrs*0QdS{8xcZ2NzJ0O;kg(2`> zQR@CWG=ggtzf; zcFE1ZcJ11AD1o^8iRX3-I+sr!)5bzcfz{Jv6Nd~6_+I2ie@SVh=b2nQFT^83;_Z!y zrGA41A`sVwYVX!0-%w>qZM+B4Q%Ipc>eWZaXmC?h89KgRUq42}Vc6N7i)EWRM3e0r zft7#Gcx#QO99%$EnH@7a_3_&)^oUDBFjQx~>29nkFNfTNF2g6p3s8_RT&DQz(+-w$ z#%+d$ybMeElJe!#t946)Lz8PALYdV2TM*K`+5}YwwhkF4`|SxeCH+GePMXWBZXv5O z7*Us3Bg8uTBnk7ti`y5hl~9{W8@SNUV(o-#zZCY@G8Qsw3o5w))j#D9j!9f4)2x}H=<~|6V_;08(S#OR?B8hb& zZ)$1&nwC`#rLS2s$Wpx%FAD8+&~7lY$tUYC%>ck$*0pxC8SMW zX2H3Jc&v@T5riZ(ZYPOdVc^AJozq)Ft7|d|U>b96wW3msPY{Kd;g-hPDl;8a(_fR{T+L&4r<4csYmPKJ9 z2WCzl&ejS#w!1DrPDx2gO^7@g82s0RD59Eit26)ZYN&x(eaeQbB%kk5C4humLHZ`0 z<7vp*s6ss{Zk2`um2Po~_9L7NEqWQS)2LNfK;Wl^HrJA#yN8^^)!=;rkjYlnm*Mti zN(!it&vq`Kfd4s=R^$|%+`0WhWCop&Q8DuT@`00AU&9*>*38HY>|4k8op~Gqzqq_< zT+H(edyn1#zG<>1^cz2odS@{Ck7^-p<66Msos5(7_M|MHP~J*siry+qAop$eaU0Py zn6^!`lhp56gf)qi^I6hn!PYF%xmoA0fp{1o|cIIdoXMxqedH;fs#?yGa>4`}w6s>V~lg11)aUsPqX-yWA^DIWbG81Re;#hT2n`e;nx_3ZeU zt5+=Fcl;uC+7!K7L0g)W+C>ia@;n4L;H``vN-UfHi||$WnI)LjuO{;L0%ESN#jL*l zK@uZ|)hTo4#Xam~qSmt4)bm#__HJwc=TSVsaA_r63!bi~pfGFenIoI#wdgeb!?!BF z5Ecs}reP}0{`x=}A;2Q8VwYp&G37BspA(r8EYClUEkYA-Iw8jsF{RN-|9 z%IeqGPG~oB>ERWlrA_+5v7=&Hoev<4SS?g#4r;CMe=!Uy01uQ2x7DO1c0Nf7dvtNd zij|jdlO<=-4Zs5>@7UZwdQJ`8;nz>O_1JP=@2H&6NnO3~92mUGabuAot8f#XdI!s} zjW`Q%i9Z_7^zEs|#`Z3`H4q*e-`_IDPNUtpg6ix8fh$+9-NW%@*dW$1F=}9|Hqw%{%6q2vX#J6q6nz#{nv7A8`s?Ljmfki8_ ze85vK=IRwT-6o#jvyi21Lr**TpIw)M1vzfztnRw{y=HTO8aOD9TNGg}g}nEJ;abDB zVRDCa)UP+v>6wMggs0WGN;t(sEo8cR?Bjf|9)9DOps|y&%c8E=o{SAA-3y$IePmuA zr0I}_XXK|AAW7qA-`GUU!CX*2#X(!EJC?k8?X-~7yu%Fa-9T=CADxRNROrdrc zSQ3gm$f=|vFrSGQ3V)@we&Ux2T zU1|N5czkEms19nKXOd@-C*5UZir)R(s*Eg>-}@p}fM#eIPQl0an(|%yj~+8>$e7V% zEYuWjohGD%}9MPog>dRjP`{|O@6}}YGLfzD@z4^+pC{) z$lKzx`gNcLuXl6oKK%ffo84RnjSaqy?@(2e1K#yqrZUUTPEEJRlzdv#*oA%i?m#L4+5#An4Bdyn&W3OGCKTvAPJ&B9V@NZ4V`Y1`tFe`XZeg<-Iv1 z!&1EziIr5K^6~EJvgSR=@x3C15pRb#_l>a}Yvn~)n8ClkKHDX$X7D^61a~8%^*4SM z>Z>w?jTG9|sWK%ISL9f%rI!+ztY`8p*6bs&txi-K?!nnTk*0k%UzK^D2F!<_aJe-L zI-6)V_h6X(_FAat+(Qgsm3ei@4@oHBj;)I)-BiGs#H~(!Y-`>+lsHXnb$8Th>t4oz z*(J^>`QwFdHpW_p#@&1Uv1xOFzO3}xkQhd+d=fNUDLFm~|FRnySe*vQ1h#K_2K(5zjI=#rAK`0N7jZe|_aN%eBM+uS;- zb)EsD>OZK;q`x_>jabceG0n!NMutX4wnv{P;`{9EPo41KY2*}3Li3g{?j8 z5WSB>*76umroUG|bwzbkOS?HMw@m1++q~~wN_66fb6u>Bw2X{<^mf^_$zM-KCh%Gu zBZk%K&Fg`a<+L6Cj{0(W`)qYdWZ!3MS`iFN-14u^wyM2+b|*%>_8ig%bK1)N_wf7l zz#1{&l5vi+b58$e&3e8|s)P!_C96&XRmT4U13qyi;`_a=ESAi{zrn;uh&I~wn7lAs zB{XJT2!{l;se4MU)1U7%x9v-h)SA{=$94>8Jfavt0AwqmD*H`K4b?qQ;S>&b6;)-9 zD%9t(QgOyIAY?~0CWL3_Ubyzw!_JK5!=;PwTt%w(gzEM+sm2_U&g=* zL!ine-`k2PLJX};@iDh^I>^x-~hUegxfV>yrYC}&)5RO=wdoFPn9W-?rI|A zXx|+niQ`XUb%h>jA{IodS0&$TZtn1o=-0t+t@S!hhtrOJUGXWim8L%HiRFk9mMF%i zW^lFQVBPtw4M3ILl9Bexo!}r?{G-&(zM0EPn5;HjlA)mb`r5Irw7N_w17|;O;Ap$% zLzgjx&wf>Lexni8ZZN_8Y0K1(5(a%UV1=a$ONOk_!+7?;{aFE18L20YhOWMXZ&p;o z;@PGNHu4tzup|pVJ`YKnP*tX)3U}FRkM{cd&MR=&cD9r=AF-B!U6u;mJML^8&5|?t zKo*Nh+cq^sUJVfv_qI=!QZ-y27#tY5e)?bs*i?!t7zHvXst; zgUTaPR8jm2RfZ0d1*2QaE2`^Tz?f^KqpmC|DXV8_wEn_72J)o2{*WpIVW}W+9~TzK z?G?};ONnN{aCiImkTSK~sW? zAhcV9`HKL=sWPQ8SG6S2!UGTD;^LyCWANXUjCvb4wV)d^)#)#7|qV@4u|dWW7D1faF%6e?e)EjZG*hg=3I0aor41C*S>;*s=;RGMm<2 z({Khg8f6+lp<1Uj@1> z7kYG#w361MwIEY`Ms`L>`uJP$sHh@_K@azM!r7T0vq)!cz+imvRGHE^hh{9Vpi4XF z4@T0hUZht-NyQg~5^!_lL}@kSl|ey)>(@^i&>A6?>#@aLXa%tee*&E9vgEjW$jYay zlfrLO)Q}nSt9{-`(LAo2DgAInQQqXqS16IVR;HU}nXe8?BgONvRZPi86D5@$52?$& z*sA-DUkIMrZ(c5p+7Xxh5mI{y%nS|oXzLUt*PLht)t;R+&HF86fT{7LvVkVDooDR9 zKi?jnhoq<~L)y43%t8*0-2e-fduDW&(eDS7AtLUU4z$wh;su>v+|sUSkd9KFGu%<5 zeZLVShPe*;!)5f?vF56%@2rCie=MoRA)g*H=7Whhv^cH<{0dcuq9!l%TVi}{L_}nC zbo7~36IjZ&w?9T_7nYIv_0O)#Q0b8O#zY#8BgctXXMX5lEblbbZP-xPKU`hMx((Ho zMjmjgFvOY@PEONv^M)8At#(s*_8Ij%Zqrp6iqe9dc?thKlyTY(Yw8LaW3i3PDvzp?md(gBBk=w$vRbrItT6Z=qzKshK}n&ps0Mg{+cc!sG9F|ikalz3 zNS1ELG~f#n4f;z#L@=j#Vi!I8UaljD4aGurdD-{yd4^)`g$f=LLLn;Rz}S>4-lAcWo?U5Hhg zS40BFzkBBHq_1GsJ24-4p&;R|t{j@M@g{y0bv+n&jIDQIQbJc*n2L-U{msqI+uV*M z8|tDt9^S@(zdqcmVbmsB;FWXBh9IrBWY$;p_Sut^0`LG2J-0oAf$IA8WgIhdpva|6wgvZAXI+BC5Ag5fXK4mkvTLoZX*&gdI1G zh&OlN$7jG5Nt1YMBObu6lY0CCq&?I?ihKFS-o#c$?luT`rlzv|LxWG?|C!SGd?pzHA*i0Z*^d}F&I_PBRx*42w#3NS$FM{C6LJOK7pKa$z^ zA!sXe;BTndy8Oxb8gm^hixS&!!zM!Hoei=`YRAJQhOgNOftEBq=F{tNXs?1Vp9ec= zm=2na^%Xcllw0-w`IA(_>Mzd*%OTly7e0$+bz(-ut;lq-QdDsm9-jsJ%AK9_SxD{J z-!NH>y}d;eA&+fWF;i9Lq)g~&V$@|uK6UMGNE#jFOOm_kOLq0#4>x!(kuiy=G6PqE zhE$xNc{XUK43b)U@+~7~N=k?GqU0Cdb(CbSx}LoAf?6`CM!ozyGWOYiKV8S+g2|S< zv`}j`miPsVsx|&sPA%?_RP4y|32#+{-aq%JD^fClk_bcV`PCzkob}6ZqE8g3s?wF! zBTae|b1ObPyBg?s@y4Bmo%_jA6ZP>uh$}7g?HOH!<{X42E};ok9S9+u{EueRXhc8= z6o7n!?1nL%oUm5%FeSrOR%Cu?r_Sm>`w+Y@F1JQNb@rNq*)G=R=C+qVfJCM|M)&W& zJU@ybbQ-sm#I=N7{+!o`HT7GB3v~V4!EQ*!I;xy0OuTEZ#v0`h!e2;aQT^}ME)Oib zXKcI(ci6KJ0`O|06y z%3#7TE;lhTF*UPLSCB?X#>CtLKk4roNRo-RVgq|cJm^-z;X5yOc_YQv(Irqu{Akbo z{x~xWb5l7Ml9X4)tdBEau)nVR31tM`myWY zg{i5oEU&1nD901x_-ku1@rPc679g_r=!7}$<<()`+o@@3o0^(7x3+HAuJgIKX;n!N zJ6PfxurSmHt50pH08{fWE+q7Z=*4Yfmx-k!6tg`3h6<9|@+5_hXOUL}aVA;@=D12t zj0_EptyXRazfAyowR4ie{q6LP(*RF8+*(iRH29G`L@rGH)C_ zTbb9V)Ddc?k4t0yD|%ERrrvD9=i8ylOO0ng0b06R5IS!{1Z z1sN3$e9uVVyhV$)fd_AM2q%fii-3Nm^lSK>af5YrwGA;VSeQFHbl7t2%&5-hU`|v6 zCz?@Kj|~aH-#z+PoS@)s^$s;=nf9LprY;=*A#p$fm#NNJF>Rosxt_VXnYnHEvrmDw zL^J^vOqHqKEmUV6c!5V?@_kGI=gr|+SQ=c30W~1uw%;3%jPyMOpJ}O z$TBmB?%8p$AJ`-lE#%A!XZ%9n`3K;eJXI#nK^eJ$?<(kbXi2pmGC#KpzW_4gYdrtEj86>u6eClb=Io+`7)rvrX6 zdM(kV1XY>rk9HtY^dAvNzs9Cg48PKt!m$oeX}ifBgNg;njms^GyMz0+UN1koWl8g* zd9HP{#7Vq%Lm%X=T9L7hTO8k28?m%|C4)u$&$Z=m{0!==GPHYhtHQ%RN5|8sAv~Et zo1`!!_4DV?x#Y}s`f^2aUR-Q!csRZt{w0k!O{Wr!HY2+z7e7nQARfV#b11m%^pyDc z_@t6b!iaSb8iJde6q8w43A3%*_qf%G32`Y|BwKdbmjs|7r-1qnH4svDAnDoV@lp8o z&tc&av2n4HxU}#ivZR_R&;JJ3pTi=eqGMyD!#=~K*e~fMS>rUqpNhilxP%nm&OgIs zrN%;DpTnYKVq>BrNzR{Bvq=O!u|l4yE-8+Ri1_q5yqtCrn7&meCB)>HL0_s%$1abH zkIke-7LysTK^f*-N)rBbWJE+hiRE5XQ5Xdk78Vu}85b8D5k_htDy~9s*+)FM)ujn> z@dYGs3Px3FKJWm|BrGhah&slLp^4C1U78m`-VTq5ii?Y(Ef5})2qLz+Bq1&?zqCpF zFM^_+DkV+N_;THQ#9HlBeCN3^20?Lek3%A#&=s2*IVd^z{S#msK^}_G6I)Kk+)v<*Aa=>wh z*D>jn@}f*kZCHE~|9xJ<27m`uW%)_*akRhC)=nn=!wjeDTXI5lBs6JcR00$mQhbj# zzI}0FPCC#K_BkU5R$h|hqw~uNtJl8T1Xjn?rNqRgWtBj(dN1*=(^GH_gyoS%h{i@3 zc3DDvTybsWa*~`|Re}k~Ew19_Tv>t%PDmjp_>C5mzFwN285frXfoO!ElE*a#VZi*9 zX~mbXNvO&Enh+nKSWJ2{KP&jRx~vdCNdA^pOU1Y3*!2AJdP0?9CnthX#RSL4$Ax|R z^ocSwK~!7{$rRo$$r7Bqni!K+RLN~1)v1KUsHrSTijPl7NpCobEXw(YbIU5A#@qs^srs6XDuFZOq^J5eOeA zNf(kSz%NpuEd&=5#7&nW?5cp65L_u0u@3PMAdW{G-`4%#1~GdF1mbEy2%HA42aRY^ zzY4#$t^b#UM)2d|M{7o4HCz}?%nFvQ>hH$n= z>N5U^#{vj?cr|J~(If~;NTBi`X7|tV3qSr{C0itZApySxwaxJZgw-bbfi%DI3m~k@ zK(}XO@j_9L9btQc-ewEvD|CN_2jSKOQN>TwP=e5u!f8Z-F5L;;B(j&>1X0B%=eNVo z4yVC~8UkK|zzJ0}RUP&9io-{PPd5MzSLEAp>PGGRVlw+qZbY9Hev|wZcnLrTDdC&K z0GA~wD<%vV6)Y~uZBdjpq2BnYKR(tk=XVQ80CfcpY&?dlCLu+5wBg1i)!B3gsRKzQ zK$;+Bd^Cx`9|8VogR%&G1!86qXT2turM5=JJ!o1b1GvyTc!0A$>Zhw?wtBb4Kp-m~ z_z8LB5>6xCP$;En)FxpQ&_eNU0!;u=#W_u6b$*iiwL@|sguzF?uVab$R(-Cjtu(<` z8UYtr9a^83M&JRVmXOA)HsKHdFvRwm2E9pSo${+tbib*6jlLj6tUcs3C3N#dmp~DkW@C#DwdlA;jgyh4UBdL1ecS zM7<=Ux)!O1rp^T$)(k&CQ2y$^^Zg={J};Iqfk*r|zMG>kWqdT04h`>!0gxdiL_{Eh!E)Kg_(oUP2>vcS{A(x!Fmj(aYHc{ZI9 z;ft@~_lG<6u(7dr8RZ%Ftr#S#_&!OsqT+91o}*l>ZESit4Zj}_-ntExrGE-KT9>9p z&71j$m5ogcn;u?k4wi91*fjnnPQll!7f#OinsNDQ0wb{OTyOsMU62_J!znqx&ZmR5 zm5o)4krNlkq?gbchw#fk1tF!O!G%~*4Iugb%|Ci{#jQ4c+^m>P2+$>xu%8%lzpIvs z2dOk}S;&UjoouXZteX#WTM+rJ2-Gx^XIA`+an5~hY;2reCcjC}Yn;=548NNHXi3U* z5;yovcCfXzwzlXqe&M?~5`ew-Q>B?VFP~ZLH{;apa0axiAFa2#(sTJX_)P(A)6AHA z6Z`dOWo>O~Ztb&pJBNtPLOB+RV_<(AdZb{+gJzvTMEh%14HDA6Q=CGVILv zJv+3XwgdbY8zGfwXcfmd`1Q1HiJ7xwcb98V!D)*_wr@((UQc)FYj0(3Wnn(qDF4m{@`2%&W(4|8 zwY0KsVe7c%^ldH~R`J8P=K^sx8k&-rRK~_;md)+^kBJg*djEe3v<3=h_3boaHSwbT z;a>AS5SFgY3G*H4>}X|WWoh9ybxCSA82F0hv>$2p-}oOueP?W@a;;kj1-QW%^6^-+@fD%DF>Y9x$LlK_b;A5bL`kr4Epy& zLKc2dQh>ZER&1Kg%7Z| z=Q4$nw{>Kt|Cql&H1xS=PhE8f*ROCKR!vQ5?t@z)XHK8MpE-W|bSQPt7Ly!zY&dF1+w z(5E5Y^kq%^&MqfyR+09mrIvKZNr9oEp({qVk~QuSo>xt{Mr39b&Gljm(G8 z*GzT6ib=g}+jQvK4*VUKorTyWG}Nm|P@<#XJ-Kw@9MF99=%uG`_+f$gk1-F#yr)lZ z-F=c%B-VtP(iZXPulXAfzIgTO%8_mI2=(^a%>nk{u*6EY_(HYvZ+<9P)2Zz z+$)av9Wk(9zkUPo|9$%oc506cwF*Q8*r?(E@V_fYx5PL5Ek8|f*3X3x+RfP6L4m7} z-h2`o`qFQpBa+s=8&v>G2ABKw{dK>!JD&o5s*cZ^grm1!@+;EXXY zzeHi7kI18APhNf~C3gOzXd_*gTQ+ZiiDuiucV2~FIk;LyMsn`n$M8Cr8*%3_uE>7Q z&bTuBIS+O)ZH6@4Clr$A5tZHlB~VG7(_c-}amo&S_1%bEph=5qQ!*Q`eD&bU(~k)- z&+`6r->jwarWG&Z!|8)|Mgb+ zZw615$x1uFa3V$()q{lGdQUU+A<0&FT$z}?6Q#Fll9?ZsF$sYt&5MZuU`uf zOFffuBv>k+SCedN_!PD`kqVl1nm&58YrLAFS0;J);ek1r=B6ILKy1sF_(%5<%c@V< ze}GQZE^Qo&vp9J9`L^)2FgMgRb3JzN3$Z>(q!>Z*C?7aLzVBX^pw?Sy$gG#YAh?N+ z>mc?~=?fECG%WH8{+09o5-vr{v>B$!)!Dv*n%2nWF(lqu%{sE4iD_3hsk}f3W6csHJSH2_$d@!@N8=Lq*q_ z9FSnPk8UAvLLw^yzItk-pjq%*g`{y2D1@AEVnIS|`z#f}ki#Q|758vaLdv>+En9jw z_iU)8>D^_@Hx8&OF?9V+D15qK7NPkuaEhK+oPYI7!h_eJ1v$4(WaMTag@?76GBjmU zkP(tr!!-M}@YdC7Xy2y)hr)6JG0nNfA13w;G-zVyhWneZud|t{Uyl{Irh-~TK?p0l zyU18}r?ye?hjUm4w3|5M2J>kFt>)Wq;0toWLOr>2XWJM{kG^nz81}oMb>bq1=-WB_ zG%*gG7RA(J%G5;W6-|WZ90$F@t3Dtdn%WUH@PQD4tWhlK-V19Ze zZm@9AH8OUIw%Tv}mw>&vASVY_W%f>KkJLR=xVSHIu|T{#yFv=d?tfCs@ITq9p*B!z}Db5F5R`0504$>6W(>x>$CKFq+HgEzdD zxmPa|JBypH-^EbV5kY}pY;Sc#Kz8XvuMQkcK5zrVVH#pP5|67YZ% z?yl-NloigDGpjMpkyqi$nZG5dj4&#|^PF4GE6;l#qlTpZIQf!1WK(%*7xj=-Jx!VE z!KUWz$I~a@?;Xa5(aeKM@CWzXpjM5fP5myurq>fOf`XivuRlX3al%O<W8Z$K zQT>?w^v~~7*$9uqFJsVXc-JCF$tYSUEa zu~WBi5ZzBKVgGBOrcC)zFCEXJ8<|>78M1`MKfYyYWXu)z3D`5RxPvNeXUmABAL8FT5wAL-2nkslGaRWI+cW zNDT5uK~0&Ii>u_2Tzraf3QVr^o{l>h`BmpgJXci%0jm*VD zEPQbR2g2J3HV*MdDo!axO_9@068jGeSg2&UUmk~9sY@9-cj(xrO}{^LDzN1NG(U@( zhmhgzYB7T)QbkRf#LdG|1LL=>o-A%UtX0VHlpO&1U+TvkS)xoW?)m$7DP zsihG7=SfT_HDwr(Vc=E4vm^4@E{p-^9tpNAYsxGRvTx`?V@9*!aiOTKqx_MQ{W~(i zfqsxYzA}{`eHRCdh1>42ms*^L=yOs#Z-C<o9Q?cOzrapw;lwSL8A17r$9Jw=In&%!x>@kJD_5>u zzI5^G_4@^&a6r_u-af#R_Q#yzK7O5Ur4%!ycjP{dmX|_%9qg2bcVADEzX5j`Ahqn%MQng}ow5pA4SMd8XQ{;FR6?s! z!1{-P$$1=Oq-l0BrG)I{0dXf5^|fp{nA%o-thD`SgH2P*Rx)h@PF7NQYfl$@TlI#G zRvx@wLB3AM@@sqMdwO^_*41(h8u;L20Z5Gm!blzYJ12B<2%btF6t>e>?Y8C$Qz;wl zzG>;Fj>c-9Aqz_@#9HhWm8&u#E~rCy{y}P1AN@c!GI_Zp zI+#i~a^HR=X3yG%Z9FZMfzh6ef)zA0XW$FZlC{BR5N8}bT(IX>|QKjS7q{_9#fP; zb5Er*Ik%Lg(8z7q1u!VWs?650UQ!113Z%kO?&gY`hMt}t81C-wy=QI*0VzpwGm!Ec zyOpfUfKSDZZ6lG4>O~UJRiY*l2dXtbTw14sq?*{lC-ArM&nX+@@biq@dlV4rFb5)7 zW0b#-SHo7p_$u)Js)OvWhxw(6X-uOta{}Wezc7tih1SBnI@8;#<;-IOh5V~mn zm!fhAG%jG0qGy=8_o5o~kDd-{&H72Y#+Y4|d39P2Nln@RkhB`C%B&vLOxm;s#3)Tm zY^;v-8{2t#d06PG8MNwt@dLR;RGd<-Y08vwu!`ny9_S~l<`0HZ)(u-3T$(Mer>BP- zZkjcxU_(U0{E|3!mVOFoBaikDP`N5|cy4>7 zVM(v16JJ&QkeeQ0Yr5_d%ybJM?^Tgj*mCVNs4zj{Ab&&Uh6Y|Ec15ZIdUa~~Uz{0+=)jT&77dHv5MnP3MZ$t~dHWPN^ zzst$K=hr6(u{|2TXvfK8M~)ra>)oh5YAJ5kiX&!+vEocZA}c zp@C)!4Sn7fL$lQs0QQ2R>l<_9>ORU@ZTre5G2iZvbj96CzdyO11mEsgk?&2V==JXi+1emY)4{FFDQ)?GI));Fj z+4dUqAhR;`8Ub6In)PIv_S+==w^7YkCVFNkq~`XXgVh-{cIw5oGDz;=a}Fa&cTz_I z6Zha|DlG-QI=7>-uEzkf`c~B6M#sMT1{0SYB^czXtM5M{RqF<)i#*!WnqRCld$NsJ6frF4u-es2Gj9Z)pALwCmnl|&n=fi>gPXl z>88x5Ya4NWHY8#z>${(UoJ;@p4EV}GsQ1<3_Nvw)c>*A+pXP9?4E z(*KH5!~m=K zavry|q!@qm>A@)oDV%#t)?8E1>mcbR2_J=Dmegt#lxc4hBIM-sE~a9`6TD>bleGKC zg4?w5ZQk6)6~kFeNnTaYta-?gltO4W$( zT(`_bxcF(;ZSfZ{u_RsI-M&p5pXOeK0EY(havFwB{CiK#!nTwE3mA89cWZsuzPVVF zm6wUQ6<3GE4JM+~%Ez`gmT%g%6o{-_KUAVxmw$O^I#RKEmWRpa6R%|MoGw<4113SQ z6w{OccR@r^uz60eh$HtHp}B!1z)l_gr8s-<+PMyPjXU%of9vf>(9^)y{Ejx#z9TnO zu%--aY=NYe^U6w!G3$$x_QPgw{0ICz``!WAU`m3?I_F!;ly1#rG;FV>6oN%qLkNH4 zzX8=wFnxO*t$@&$TkKUzkwd)X%sYQ0I)D8jSLG(b)CmgD_s!+e;Eh+vAH{>4={xkU zX39`p-8dM@H-1IWOE6`@O_bfpu{w6agU@;K@cQ-Zx4#v^pS4H_Ysy?&ttg{-NCx_ zKYvOmo0k0-B%F;ub@F6f{JAybgOIAt6PQPHdb+8)5B?#XqrFuccnt)xkZ?KZ&x5Eo zLBS9&BgcWOL=&q}bk9geR>U!-Ca5Vht&^!~yRlUdBYK)3Ub;!gs^L&x+FT_i>(kPlyWu3;M#h zPcLzn7az&JQNos5McH#G>`o53d#Um>@Ndz#RGjeOWeRyHOn~6S^E)`{a}HT$uB(M9 z0hu43;w*2{$i_1~BiZ=*(d*_r+gi2hJTUP^<*b)p)5{cgu$J)|y@h=!4zEwZt)-jD z-e30pXeC*hDqk5U{k%LvQ==j705L$Bw6~8i0UyZSg2GJWbMhbF#0*F(BAT+U+Wf}f zhH4@5u&!7?td+c`%g&?m`<9GQR8WpQk0C^D@%$dXoZ=l0)(nDQ!biD`REQ`WDm9%Z{rj>zJOD7*Csm-;( z?RWqEdb$0+KerUWeCP>m&{WyQd{Wf&(@W)~q{pq=jYs*e?)ptzjsD7G=gOj>GRG;n zapCltGjT^YPse5UU9b%keJbvJMgjg%>DDoQ5R&o@8*t#nskpfK?W^X_UB3&eLwiIu zz*dQ%G$qtdTi(3+wwU<1BYQk`)ZM$x%_r|B9hi-+oP|**arviX&j4%UFJ}=Mui0a% zDRX(lU_5VL6Ad|z?%(a#L|LP0*mpj&WvGXFhiSs^ADq?>A+x7>xL=7mTTEQxn350I z%o`~B4PJgW{&XJ~bwi)*dr)#>jQc z!T7l22U-}aJ9V0t%LB&)?zd+iCMvd})3Ml$Yir)XIv}~QLaa{+ZQ}e_ry4fUie(Rd z5#-)(h)|yu7xAxQwn)#jJBVfMnGK7kVoQBU1Xygf9EkWS&{n&*XFO)kq_r_;Vo#rr z#T-reNNz@Cc*S=vV@W%6Dr%7&LLpPvfux;2m!2m+7z{OKCbZR4uVbgxky6> zb)2w+jzHHoFHw_0CT?vu?2X0(9J4EO{H$4Dh#yBy{?OHei%~14uiS7ZE`ImwNy<{F z!-Or=PA*G5r;bqAv<-wL+G=sH)4=W)*J`YV@%6zzT+`{%Psox?rKqqM8sIqw{`tL= zzP$6OE%-O;4_p&$SefkPxl_k)KXE2LK6vlu?^`N3mtV<1@VM$Hvmgq|K;v=i*MEhPJp#eC)(< zAHbS2^8&3pBMbF`}cRnz`S@^fFu(E|I`Z!(5S))te%L*cSW=P@YzNZD$NhbxR_> z`yEQ;SAej+j{Or7?7GrpIJEZEcAC~63j!LsC6Qzys*c#8MXzI3aDuGW6CqDED)9TJ z`Qnu3qa#WABnwS1N_JC&?;K77L86M95^!%Hn562y!-?oqUeSft@=l4kO`bwg}%mQM2yF~nfSGV}Vv?v|d8uI>6AzrmhA;IkV*R8R$x z!~O8odPVdp+^-HDI{7vYdg!yWdne3aa`H_4vE6@KC`s7|Ps|}vg1+9}i_0JO=RO$L zPM#Rr&QVsiY2pW1l_BeM%)C&n^U%Px2~2gSm3_EChBcG>#LN>n2>r%Cg6h$JE1=`; zUNXzU(aFm@@Zcqo32=)bLX?woZ*W*gCnu+V!)B%Aaw>;|(sd(yd3(7#JHyV0lQS&x zcb&2Yx~72Pat7&iD`O4Zm#isO8p)!)z0FZfz=9Vbfo-I^s%o>pA4e6$sKQ)>o8%hWkBv`Me>RX^tKqQ`hW)uy#bOldm2KXyN1H z>f#8SLQcRM*A7=dKz(cKE$W;2ByM91A0Jm>BQDNy$ixM&GD?|>?<2dnS##E?pJLK@rq&>fiDF@>Lo2Lm^pon1iE+=!$(`@}u}q3DG{xwUig5TE9rK(m9Rho|Sl zRfhXOJLBZ=*x727yl^D zeApL+pY&U{)tuIy0Vi>>twy>1c*3jkQMmrR*>Lwq$fy zcQ;I$W3Pz|p1g;JOm@-k#<8$=o{qQ&__bQG?If8P)Thbl#%k__&TVGygJ{1P`EM?C z_V@K^-rNyd0V>&VKDf1s?am<3gvrtK$KWQQ@6(R!-+w_N5CN$#Zk!w0uPf$17SXQV z2Oqi!E>L0%q>_Fna$4(F4!D~AM@&s2Q3wTWgK?IGw+kDw0%Tw8)T{oWdXQhRczA%H zU)zKiFh68138FvK9~{F8T_&s`CN?|wp(OA7qaRkp+Y*SU6xERAXIc7#K5hK`x{oCe zeyoI1p-S902WOeJ9YTxIKFe09EOS~oP6@r40^gxpjuP-LaTiYLH)jiJOj=o*ry_Dj z7*0BP^CSF0X`(6lZ#sH8`1YDiw&+S0eqP+8zk**b?WbC;K4V37{Ctioh{?%5s#$1_2Vx=g zQXTKtk^El?mgc|1#Ya>m{(B%8xVTX4sO+lhr=6_Bfp34UDu%n&n~tnU6ml{FwB?t2t9=5S!(SBUd<7Z0+C&3;S7 z+#oj(a|zLKC0^YHvg^?zsLEGf&Xz`>*X7m+)vQ)dWkCW;7_EP0fwfa7Qd9-IMhd*D zQE7Oy_R<)rDjyc!34erQX;g6xsG^mvL&LJ02p|LWeWBND5M4=jEs(@CNUD@5{3!|X zKZHA8vDlyBU+V8rm?P~wev;*w?$T`S?K*5 z-K`G(0Bvk>5Q;{a%@EX&c6Hi!APh&XlrgLr)c#gYS(Sh)uF-4lh2%-HY}5|Q91^mx zG7pto(xst}HI#=~fGi0y4N9m~0s^=NolE-;ZJ;{!11XGcQ4uvr#gi0YMgY)A=-qCtxof=K$Pac zR@#3Y(4xX^^;fC`-uplP5@ystfuG{MXscEJUVV+{=a<}m5;d2Uet~J#*V6v#i3vgV zrPhC%13v)}O|0~5ag+NgNK{bOIlvb;{D`8O9{kHpt5#TbrTXJ}{bb`ee&aX9qM9kg z4tiw;H?Ae#c}NeWu*#YC<&5N)iHV7+nRM@z?VohcQ611HsRAj?OvPDVCeuq)>SX|l z1?}`X@1Nq*?k9a}MB6x3SOUjZ%ozu@ca$EwzD-blhvHao9>xtKIm63PJ;w${} z{mX}kj~;<=f)qUcS_qy3b+U)9^Ht%;>X#72&ZH%yBIDB+VW)bsE+vZE38TXE`8DW= zbn1^nXka-Y;M~CsxD7FuemsaBa=ibNi=Lcq<-NV*11o%{*poPGK~4=MmZctLLY5@9m5FIE%Tj|X(`dMy<^>i(j| z`5XVIQGHd0VKS3Wdo^xiXklxqr{&jsDjayhVgyQoAGKt7L+!?Pwzg(^21^cHWr+Tg zC_7{*x_V%Vfu5PItzBd7hQpUc@u~b(f=?i^1R;>ODo*@4+}yyx#@1F_MboeMlnl7! z89&cm*xApbi7iG0J?%C<7k%LfU{Y0|a)ltE_w`|#_boLyH@C61GuBq`K6zPjIdI@7 z3j>gf@+Jq869p{v6G@1epPFZjU6Q4!-I}4xG3DQ$4`^d=*u=!vrkPa}hwWF0ea1;{ z4yP8XA#^?*2dEG`Gy)3*4DZ{L0j33ZKPhh=4z?A2$8rt5>(1b9pVfc)#T;ioGnxBAA4oBSEzudvh z!phdRG43|z0SB)^=)Yf}nRbHG&$oNDurs!_u{P0d?BI9dRW459k?7Ac^ScTQz=D$y z8Hih}G5QlL2ek<&uz*wW_5O`Z%cl?b@^W-)KTg68VD$k#mr${Jc7H7$te~2j=^L#% zPJ)q;@vrpL?M`k@b&YMB8Z>ka?Eg9!t_zUVcPP`!G9L8xcfd@uHPbh@@s59%O_&Dq zesXCaVWv$d=WZl1jq11WuP*r8Sn8YGTIp+fhK>1L!ocKGnqA@N21SAkXC0Qf~T`CkFm38xl!Z{*zbdpUGK@h$or{~M?>Wk?{8veY)lie7zJ z!hwnG$DVqq?Sv@&7>nwQlS>d%-F6+8J#K6tgJd;N5uJ#o=iH8&or8l~`TP6&`nL3g zpMl+nW(b&~Hzzb?(3tITl;HFAZK?<@ISDI0KYO_-Jq4P6Yl{+6-hBNd{yp=-0d*;~ z^b8!jsi?@gay<3}aXtThKS~9mF61UT@q-_oB9&z=9M?OjZR=Kkm|nmBb5^~~D5Q?- zxi5}4L}=Dg(1Y18&KOIhAtZ>t_|m|bfFDsyhXx0=^Y`~73;+)F7`u=-uye+?F>5tw z?y1wKPo6v(n~?aOTwf$ki&CF{&hAAMItR6D<&P=DmgJ(lZ($h2?-!-s9TE~kNN(xZ zDRjy1Bi~BM(wDfh2#9{?e+{?SZQ?sLB^O@KdjIszCvqBqUvlsAxmb+Tr||#I?2FJ- zY_KNbHIN~$b!hc3tQ&yTn%&KUDev{|;}O!lOfIt~Q*cb;+rgnB3w8p#1hoYep%mw= z7}2j|yEeF@zPLu1bH43jlgMc-vgIJiPj2t1DJQECIAa%mSiKMyeDa~J2m93!`ZEru zyy=f(bP*cA9ga2#1ia_h67D?uh<~pr`q0isQQdV=ArLERAp2EdbH4%({tgH*m61_! z8n_fct00kZuWucJl&r6Rfhae3_szha=xnms<39j0@bQx$T)uXb#2YNn?AM}^yh*$C zQn=9xKRB{xY;ec+t%#)2z7{fMI*I&LvpgE`resXZMvVi8k(o;2U3Khr?pE*~fGql9&2w)!d0#KwGwK*>Aw8<4g%OHEz+D#MdgB73QR97L>tbnRa|pS5xOpw^&9{FU`?6a9O$->56#5t z;Cc>-EB^E9hM`EV$z#xhoIx%cRvqWy-^$^#qOy)AiXMYEQrU?JZ-P{;BX{rKwR6YL zUAuSf+PVAS$r6UyJj7kmq$BRAd@==`)6q)PbqG;dMCkauPsuM{ym(zeR=sNxLmG+h z$)RaT*7zZN%k&r52J-Wd!&&jF_#h;RCvSjdLqoT5P@34AZ>cga{phHPEZYpiv_`I5 z>1(F0-Zbb#0i;AvZ>wP5p%AD8wY7Oj3;Cwq$r``7(%7eh!5%Uyjay>|?Aoz?7yPp; zChkfJA!4|n(WsqZ7}W&rx1kXHP?9M_mtJ;`X`yP<6@RvZ%$ryAbX9d8Kvs;{Ts#hxd1i4h zgql1MK8^Y}p@N9$mXZEV0{e~&ayRcdoq?VLD{%X#1Yrl7y8r-y07*naRLD091Ve^_ zKwG-9YA4@1m2+WZ}uI0fF3M= z7q<){wX>gaNx+IndnO|(gF9Konj)|9N=va6=iS?ZkaEn+IwDj2r@^v6^V9P?ckX24 z`W0n7dnp{#>92zJ=v!MxBcydLn`PRk#I;zr>>?4!=v<2`gp-T9TlkIONLF0G@xKH1 z;(~9vV6dzl;3i|-HXDzP0z5|Y({F5(LugH6E>regR~B_$5{nIC4i|hHmi4q$wg}83 z``c>hDAq3Qv;g0k%G3yE8+bPx$aYORP&kGp->!Y%=O4}$Y z7+_)mIRu$gavTN`V8yp4*gZh-(ojbgvu;H&DnP46 zjS57_?gh0#!QF_xA$ipR7i83ytYJuQho1+CAJ(?lx2h@|-v3&>GPGHv4m03+IRx9v zynj$nRw{VhhV-m26GNRndoG5+HnnPAvSyFj3hx}A6NJ?4-@uh#z_wYz28~-!5zQbD zbgd%i@qR@lyZ%b5fE?@LrC-*PLL(wC(RcPv3NUKk?e4Re#e}&l>Z z)AoucGt7n&p6bpam6iHtqlLm2pJpUB9E)-u`28;KcvJ;q zeDKq*sv|UL;}uX)a7c(hJE)PGeHbp_^r8@?V*50gPjm&p`5!*%tvtSl_tg2LK+nrfJI z2EVyq+#D1IHD&Jao+c}6aXo_zfuhRGKVI9UBCB>F2}TNFI9-y-d*yDV7YVnm{Z-fa z-}wIkqBmnJyY(i^xS&{yU&Sg)NzFW#%w%0xLQ)f}-HhF;@@8yiWq%tj``$ujVhEVx z4=(zsRkfS3Cn6a&djAU)!O0pEY-eZZec?5Hx^`Kl`r>2!N_m+0%Qv)a_mZrbSLG@v z8t~eN5eVs?dHJ0Pw>TBUnlhg~8lfK4l&L7%Jie`pVL%E*&1N1QnuWixiO#?ZQ^Fin zr4;P%WXc2!>&q~AIl3KO%CPYA0R>Z9Y-dieZl z;cga9G?i2X`cBLs)(0Vh?j`Z32U!P_ZA7t`Y*(RzX!+9%dw_$0yqtZ9=`gV+Cs6Re zIS+O;Z0PWrQ!%AgBl94bvr67$VojLVH;(5XLWf=c$eCd;LkDos8&zO+G z9k>G9b7CZk0BS&$zkmkz-7&s3(sKUDgDTL=LvRi0c)Wh7o2o-FefhUt$h4^7$x%5eH2)~Xl`rD~J!^-#AroI*=FYL6 z$gp`D(KxN*a4T*>)F9@#go{gDiV612C z;1hNJA$cZ_vdZbi;-1zrww*}NhgGQZk5?MXN{!qCSEJyJ-(H^Y-lnyOi)CZ?_Q}NU z{=e3cp~ms^V+#?IT^kR(itlb6cQll5XhnA7BEHN24N+4@#l1I)r%Ozkm!}mGYsx4isYybn%+84cNZ<7x z2`IgOq`RDoUh8)40^7E2ABfTYQgRVf@ySUS1x)^7%G}vC5lJ^V_ZBRrx^=lQzyfE= z)9!m&n+{#HHDXF{HF>3$-N%0^AWJd=m^l_X@!be@BM!*hBD0&ZT?laihomBeJ8 zlSa}jFM@h6D=WtpKRi858reT3JMA?}q~=25h!%PXssFJH#_!DM7tQdLdfW~HwLr*V z`TqPWeLcsgc{~A(uVToep#1!p7-ebFc=?un6MHn5lh+tDV8qoi4Lm18 zY}Tr+B2mC37LV9P3x@frG%&!e*0oEo-XYD^wCwH?PX~IWieLP^wU&CD9&1ZMntn?7 zY6sDx0`98*{_f$dxv;!bGt(|)*M<+PGU>MtTA7&rv1#wr@Rss&>U}4#E~_;LKSSz7 z`2D$$rJhs3tnU>dwmc$g3wl^6Y8bbxlC(~P9;B20Dvs53OX%g*jb@tiHlBfDVZr?e z4zSWv7_hY3)eXfN$@9WJk$j`GufGGM#gN7ZXC2v6SWz+apGAa$* zcIeRB(@9ywaMf8bj3@z;A<>jc+%_CZD|rQAb<(yyu4`c19T#9Xxu!n^HD&Uj9F>19fe-=VFj^@ zX{A{o{utZ>N$Z|`Mt40#31fs!89O0UCgrl09BazpZxv;{-W?gaV*YGLbK_1!|IC39 z{9+p5zW_9*K-7{MnDS5PR4?-T;*3Z*M8tEK* z1ap-NdT6dV*g5xh>)+$Nc|Hl6ks%CzlqpU1HJ5AFeqdze#wAmRJ33l-oU-i8kBfc;4-$^ATf6STo1FW* z$4SXGeaU)PR4|tyM?F`yB_d%2bLd)adK`t?U zPmC#p$tg=cuO*G<$EGl8@zO|U6*Xl_d3dago)V1IeP9b-+_aFgU`ktcMcdA>-bC)P ziX7&GjC{zpAU*n=7ur<0^8#2JsqJJ69a+o2g;*%M^jk$9aSttqa~w-z;P?hp@W#bh zee~MXPo6w^ba4kP^{>7Fx=;Kv4{OQ<>8o0`>Pw^sn0DeSaoWAH6&GvQqGJba;*rr3@vG2*%*fp!kP$t8_6?fueaH~CjUy!(QptOq92QH8R;~MXCn3H<*5E339 z0tJaH<(EKLo=TGAl@T&?Y16Sirny}cZ8dBrw+ricKMkkmcehox>qf1d@?#N$aqZ^q zCsJBsSqGG$R_MU3h~j^LCUhLbIYDF_H-x^^ds=;=90PejcsEL9lPbxvuM={6F@M+8Yj0QfrNM!yYWrKA=aD^ zz%-deK@@q;R5DGB-48J-Dw*~h|01f~e&GaDV&rfnWtLO~<7fqV+Rj2qC-Dnz`@+tR z6`aZS*JUMGbyf^^)v^v*K)dhifwo%B`cx|wP_Z!7x`Ayt3?(HnaojM-L&-8EUr;6V z^#mRHz6I)|_T%vcy}YOZN?Qbd0z$;YNtFv%yRk?e|ucQ~n(&@!d9k!H(L#F7zXx=}T{cCfpm zeP}88y_Vqe56tc$-=uXe&clcC@7AvIGD_wTvU#=d&(i_BJmaz+LW_^T;g@rYz*D;@ z&{V1IggvGki zHmqB{X6@RwD?JU=jhc5|xAS0DF{!BV+mbQH$FOPF#SBq5xazaQEOcD^eCIReoDvS% zruo}IbRRcA?ewAj*j8A*8q>VCt+l>}ZR@q0c785onD4iY@c4A#nV_6o1kJ_`wp3{~ z3I;#176S&|7~L@1SHZO9=VJU?DThmzxCk$21nHTzs+X^fSbVv(3ZaIV$rOYN4WCRW z7{QkoI@125w=!fXsGbQxwR!B)aGd@8Ct^JiR0;Arp$#UcJhx9XH6^QHA_HQyJp~`v ztrQ9YUm3^#Mff)^2ZO2HU`iFuAr?fO%CiC*Nw*vYPI6_i{aV(&sj_o8cmcnQg`=0J z-j!jq7V|Ot_6}L3$Zl0gqO3Z;-Q0vwgZK|*Ik}Q)WO4diYeVVggVw?$aa)$u;(4@x z8bW&4vtd&XXMZ2R4E&DYL+_@{m4S>xMe&*mut@ z$Hpj!Y@nAzI0x8|*eH!;w%mm2lpy1Vi3}RH@d`tfIAr5}-#BmBuwfG(eXipODA73F z$*m3KEjm$0W2X3Xn?|VR=&d9VZ&7y#L$c;sH&|09&D&VE&&mY$Vfhz#ZR9lqZh0*) zEy^#XOFzu>gmuygZ94zHmJUNz+ZcZ>`{21yb50p`Az*96D=n@ZJ0nMWAt}QfpUBY8*Hfk31z$V-)0+cP3HV1h`8`#m z={I-DBB_m+X~edi4o1k690VnCTM9xgRp^329lj&ffuK0WOA9sawtzm%dv#71p(zJo z64}4GQTS5uB%nsm=PTuIzJ9z@SZ3g%DA^5MUO6`@W|x>q_*m8G@PM`pn@DHn>~U%{5m zxSh9{T3hY?#%n30z_Zw46e5tBQnq(AyhZQXhLD8p9Hj4IP3&Ga~ z^HWe>RKhYXDS9eGXxSNXPM~fvBB1{DW!d+=wPZEyIwrpOQkC@eYX;5`Il@!JC9LY< z>VeIWwhJ|x#0YzJZ0zN!*LA-@(A3xJu%a-r-?HzyU#pqU(C8Xu-oC9HmU zaeOXj+5+OBBbI3}x(gV7;cHiQ6fz5DO1QXTK6<7BQ-Cqpv?(nqEMvRg)0joDVn>!a zC25=5K$nvEMce-vF>KiA+wWnOon2%my)ygdC7dvI$pW7i zkUq-EemQ&Ouwm1eXMmUp%83)wwqahF&#%alyp((Kj@n9^mc8jkpd?Sux;eP8$xnp# zJt+a79-hJpb2lA@KPs1S$Upp;^;2-txhEi0G~&_ysOfTYmNzn4x8Kz3n^ol+L=(4P zhAhb#ICRUez9d6wW{T35P98RF%$&Dmi=Pre5C6Zt9*w`UB@-c@d#aIU7z-0fsUp|PHmq;j64z|ucBabPaicyx3I8KD-F4xbGAdbCjJ~t zx)~t-KLzboX+1qyQiFnRcKh4o1vOd&nX3D*PmShDEa832;PuUccCNHvd=`7 z&e!J`{Twt6Y~3*d&bH=Gt^23IeZfrr^W(S>)h3={ojY~z9MZXS=UJP;6`)$U_$siz zG9R29B4s1{(9jSJS4%^k#y%Hc!`UiM=JP%+o3;t<9NOO3K(oQ9^~9@y%Dp(y3iq`~ z`o0s%-<9i%w3B{K3Tf-p8k6Pk(LmjJ;Vw8(+_adB>_qBShyXgTRuk{CzW%-cLBR87w;v`d(utG!*z-fwew z0%A&jy}t(+IAPxda@wdiLxBM`1s_Q|wzjdZjJ124u+WeuhB_SwFU7qz?RuoNyw25h zD4{Yqaju^hGVU;w50$OC&`PEfA8{?%E}^a|nE*>&QQ{ zL24v(?H3>*$AijwWo7WsBo93$pD}b0#);2kH(523wQ_3}78YVTCpbuIZxV9aX zf`@TDh~mur{5ivdy@Eozgtjr#Y|v%GrV=9Rl8R-O`?Fg?E$oyvw7uK33keAg3G{E< zZyau$b%UB=`!y&u6bpNxw~LB`){M=UAeT64r$fu_BTGAV>KqapW{RteG=oFKI(H79 zx(0yPbz~1`=8T_zDCcnm@q9&m%Ofi-)z5V?dv`dF8+~5a^;sqe4A9bnX(`&ZMDw z=TU1Ret=|Yq8;MRxkw|mhMsLg+q*Q;we`F6xfC}wexCa@!N#y0Ov5nb-3A4oPtsjn3sFnHk(kYzgATq`Rh3&xv9BBY*}g^PqzKV4meU)Xs! z8*J0EwAPl5<{uMXlA$y+S@#=3VY27m!SWs@pn@FxKf4M7Lh5yx2Cwl!Fe=TTy!J+r zXXV*shOYVm&G16<*=3Mm*!n9erjlv!&&&=Da7rI?u1%O}Wy$Bru%>gDMD`XlmHUl< z2GvX%Dj8XCl2%46U%%zRcVfUpKV_SoxpF*u`SRswiCY77Q_{B2t{vTb^dgz}3bz}( zOaAogS)3*M_!aVyPhO!CQGDq{R8&-SYA(oJUEP-?^U@CO-HuD!b>>pl=Ss5QM(^4g zxo*w!Wy>NWB9<*%b|8TqD-d5Ip_o^A?%1Bl^=nqZ`^$IiJCs2p$dL?!clY8qtXsA` zV&%h^ADK#JBnk8zH)8i3O#lZ7c9^b8;&UEcPKa2(eAVhruf7l~U82&X94Nng?)cVC z>mwqTuZW1ecn4e^DLCIh9^Aft-Rc#%mYa7RO35TsL&-K40n39I_hT{B*6%n+rc!K; za#J2{-@f}jVZLNl`~&ozqOUKuY+Sp1`La`YX$W>f+LH^rkDO-}15v~Hy`(G0wjNF( z^Gz`&lSjpuV)kv?um&>+1J@Tf+~JEbC8b1@uT@+-cHqPfU_u=f3MyXRj$O9~x7z9_ zB&Z;3F7rz+p4ho#%SK!}{s{iW%56vUiN>q7xL*X7l!s@JMkm~d-+&+Ros!&F+alLt zrX9bPL|&9w8S=d1M*O}VTQ>nq2+hmZ@69AZiZJdc95@(z6TVYN(-Y7p%XoWqKmPji z14qF7n>=O-NPTi|!&=;$5!WAoWE0q&;!)-J^6d7dRV!BDGWYI3_8|jA@#UR!+qZ05 zNjl)_wd)?frfW*#%cJV#?XBaOC%Em`Z`!hL%SPIH_nielo-Z%1?AU!cr-n|E2m#%! zDNi`O2UB&C1{fqVKxr;Yf46SM@)c{hrsslG)>cuHRGgK3;=p=b)V@P!Xq_t?lllDo zLF78j&xorJ-m?imGK&EvAUEats)*%lB6oi!osiCs1l;0lvC*qABUi4y_JUrzQhQ;w z0dfjBiLra4qV^?clMO6V80B`smzOx<@VT3`tFl?hzfZ0m$BOu2GC0+;CNue2Uhw7E z-l(XUc;b!)d1zfZUq5bJy=>u@~n55@AL3sBghPv42fB1AyW$0VF^ z{PF|BPgamfI{)6q!#L^Lrypa`*Ee^!Z$Fd;p%vhj;;dJ@ckF(X1(mw9bDXYy7nl!- ztgF$Fm3@yp6cx4qcvcbNFeQLALFU^#_$y~_z$#i*_aW)L8*%%hqV~MaB!@Cd9!hgj z<{O-FFzy;?$?8mde&ZA_?cQ53ScI8YQIvIJKW0E|E*(8-p5OTAA$px;^^u!QcYgdX zoFM#~L{yvlNH8wy3DGYKllFH&Y;m>QF+Yo6DNW++vA(5M&o8mG`atB1)kv#W>|glC z-+_8^=HEeWO#AmCx!2T_uzJ46)TsDBj_Ru!!e19r9THg}33Sy*9O}u9dJ<62(*7Mt zve3#orNzV=0u;S_{`eH#p zj=x=o!Qqg@2qa^*>m)1cSsFw1Fqbqz88kt)=d`_u4*K!DcHkzcDve&5Nls{qa*5PJ z^q~k?zErCf+i<`%!c8n}KRioo1)m&Gz_jtI3ule%7yq#pU$V_aT~|fK26KZ-8kUjz zd>sx)VBsWrun-8Hh7f?5<0nF>(Md%?dJQeAj92{x2WA@PFzHZYj&Ib0s>>tk00vJg z$~kNo1lbVP1L8m=M-+5YPLqgqft1#pHujp>n!Y9i673GktY1;^J`eN*Fs*tn;3s98 zIGrX5g31drtLK38K4qk(xo|SHzNOUy%7L0f!E!*{@K4)8tQ|#2X1feE$g-2p_}JNZ z=-RDom#!Z6=B|M~KadNMs&Y%x>XihDHVsonKs6?dUMI;TCud7Do^9T-?;D3M5mhA% zgYNc?%fyuF8nEh!}_pfM}=u+aOYG{XbI=cGg|ZDoAdk z+CNbZ!i9(yLm)9h9BMXGRZfvIYL0)BAcj8CyrO^q=fKa&%KTQqdWEwf)CqXS4=x^E zx^&6Hg$s9|yg`QqTBCxT?93bzYV03}cs>bpSeVVf@xK5uzA_Ka9_bt2XXxk|&pyH4 zp|C`h73AE#7JEDvj$klE;nF^z`tb7betr7%8-DpAoS=lUoVAL$$F{8Q( z&C_2JFPcqIl)h^Al<+>`oA$&(7b4E6H0jI3v(pCk>CQH|Lla9=A1)n- z^Mud+Gb$UdW~`EZHd64B_4CKCjwULtHYHCDm&X^5_Y3bcc*NAC6cW(2^7}Bos6G#< zl{A*0{KC}r%f|Hy4<9>e)$RAN9a}S3ohLTg`jlp_oj*OiPoE7tPZNirYHKiA8ObqG zdtax4A5YCsR0lirN=iI56j(iGO;lWwSP}%Rr%K%reT$GF;9fhvZBpNUxcYyrj>=;l zwnW|(2VT+Z=ePFnJw*?0i^%~YTSSMbzYdnq6@`0OE(US>V?$1r>kw(pjOVu}VU~sW zJ$8;M++;^%v8Qx9HV_WC)KMvfdgdh{s#bJVC&<0njrxdwhA zVs~@s*SR_GmQEW#derDKW5(bt^LK(LJ1l$=K|8m9EB?x)SrMP%n$0?8fS~df_Fs~R zSDbft-)3CN@PUK39Jxc?r0OgSY|!drTtxsCBF@LV6DEwm_zF%2)Vcm7gqph#_0L<` z1fP?ZPZ*2^efHvABuo^vCe?Wt4(`BA8$WI7$M5xI8Y~x8`&&@yfXL6^8LbQ zOG!)DUD!Vg){f2$G*k1P5`}-O!O7|%Qcfnhf~jq-blQ?o)Dk0o|7DP6lKQf!{)*@~ z{_jKd1XJAV5el*fL#NCe8|JN|XLat?ccOX)_fBsf(5pua_ong)`H&m_KnW3%eRF1= zwu(~NklC|`gej?LuOlafdEn1pJhPX(tfBYZdGors=$p8OVABZ3!%AgEcM<9qHY$)g zZ~U6-o3{v`KX9t>8i?@kczUI?8>U z;AWuSs{8PH^X53|DHwSV{8kRSML;s**HW%+mPQCse|yP(=v22|j2y2ht2b!kyb0Y} zDrq-9_2erVD?s(p*9!A;($dm0GBRuL;85$ zJUmm%NGHhS(2^z5MasgA&U@dsnW3>~&-wFax$9!iEG{F;vLZii<;-E-LITZn)ezD< z@%+be0|}t!9e>}PK1%Y2gD20OJ!@i6$FA2t0fno@f}4|_oq;J!OH0pYFV(Ea!1EIzgbA49^Z~v$CO#dpsJC^}HE|A3&fyD)1im@H z!L*@jmod}kP8_TyCpT!>2}XkD!9aDu(9C^(!P!j5H+=ZKxl@`pM81QUKvX)MT>381 zTtiw~T259*T3Sj;2@an0j)-F=i}ay{^d(ql@kW6(&N<9NdZ9nALNvHZCj1}^6%fiW@eCv&V;KP0o5D2 zG%xpielaU)l0o%DUh*XmBMrZ@EiwHv!V zfh)6XXIiDi3ApKLn839BLV8e{&u}usTQxjP+V6J2z4A*z_#orJ6Z=uqZX=S9; zeBv&Kh?W4B7a+wzI-EU zp!UZ8jsK6pnlj(N!w6K8dQlglnFooFH^WS8XQtydlExu8wRic{h3k@%ABGrdH6IQk zSojbi67qQKNC(Y0NV6QA5hShSokG0yA0L^Ekoq~evITdDk8YZ%)7&GFQJmVX1$6$n zb)>hPQCm7r7Ct>Fi=@|GN+EyohI?u_^jJe*eh@WTUeopid{g|;OhYhj9`2@U6HcEL zChb#^Qi&sZaPPz_l$Y_y$F`A$xv6PuT73x`nVcmo%eY~P(8S&31QWx|4{56DJP=eS znTHj9zCXEVr^c3+MutX>jr447+n#&zBYHtK2*}i%pWnwp!=f$3v0y#Y$c=HlAH=;N?#vWL}*zYj0)dBKbeiDN zZ|+|xBdr(v4jN26zX)iPy^UXmklfx|5GaVEoZKJ&I&PJMyn;?66C*=IEj?ZL_5*Gw z=K*Ds3nW&HfGK+8p((5DIk-?jn8|AVAKBiV`~x9{Lr)<@jac%iP4MJu^yF#t&L=%x z-nDrH+n%t*L=IaPzdhGPQC>q^-`LQwk)eTOtMjOGJDVA_98I6(Jw70fq&8lM z<1NHR3QVU85}WSx)ktG~hdXe9Nc>PrO_`G9v$p0Yac@ewymB51R!b%G^Yu-*6YY6K zFDT9LWUk;gcq0RCEq<#G0MUK0ef+eUvXn`{Sm+vTJp^T?MOEh6`LzQOQj32}j_67< z+GzDlKCT$o&&Jlq$jHdlShuN#%a%A;Wa5!?>?f8C)M#X&-#~vUeJIwHq4rST6K?}m zH7y<7(736aHuqf{eI62lTZA`dX>E-a8`yODS`IXe;}#3{uJy6al`Oi`Cne7ht4S%I zcm>r>zr73FkK1ljv$(jMwQ@5OI8-1}r%}^@cPw(Tx4TOtBV!{YLraq;182Zl@w3Z% zA{FbGbQ>r8roJp1zncVN7F*MQ2bHEwfU&aoq}}*89_iz?f;D9(w{D`E%%p+mP*8d099Xb;e>Or2sT_Mz0B)BR{DK$9RFKrtxDPmKyuWcn zx8XP^w*;0>Hw|qrYtV|sxTCA(`TN(+o;~}|7a0;Skpa+wt@OR4D(VDbrYcGyYHCT> zCJK%{mJt0>KD$#BwPro&s{Wp-?Hf7tE)bBJLA8QdP*oK(rxQ}KPXfipJdB>EqUrRq z5LN}aWVSjr(A;O#il`}FRGalACPi&UU0OF7$yg*6;6J&TX>TC9sPc(duxFf?a>dz1 zzNv5c)fb;iii=CKQV(p7y7OMVDMN=4JU$^Lf8q^U3}O?gDN__;FYDUx&ytdoyxi=4 zGrA+Bbn-cTMVyZxdBpwfsVUWF;vQT?DTF}fhTE!Icb*5sQDu&g2`drOK3%&hBcL&F zIK#a4P05|lRj8o1UtxnoO76sy{F0L5cS$$gbRm+S0H_eZFvbwpVH$4inP;eFsGzAI zbsNm1YOZobqo%|zMo24xT=glDJRz(P_foOyUS-N~-kw%MQuB^IDJ?C{O@0zFrY%CM z>k~*^!M|s;VB_Y@Y}3S~^;G;z`;Yp_j{&N zQsc7W4L%@QHz4x-}+Its!!@go$>;=V+Z3P>mh#f2_z1JCL z=6*TJ49qZh09~Jb_I*D8zg>izo808&ib=9xxFw}rZh6wRO^Qfm z|HCxM!bWF$QX|Yy3T$qy->~hedkICwMa6j;7ydXD`QU?qFns#MKk8_h9ld(dNn30F z*_u?Dyl3@QQNMK;aYyHUes^#w#P6KC`xZ{-kt+gmXV%*2Td3>kZ;X1!$f*?tCGwdi z0Z6UU!&DfC@h9eK>Nv!~S(0$`NH1jCIhztq$V9FhfK(d1Ajh+8M5B`^Z~f$UNX2wX z_|;52dP|DpuAbX{^fs=ve|>ewKC2nWEVL91gfYqguHq0ZcUmx z=Vb;cb8MrqiYh}0QS^59#3|Qa0T0N^x}OfJ%7livYFqbCEh)j=^!drf26d2Cw>hA@ z{uk-_3;z^E;UqIjILY||4ON=-&d00>;UtCGPmZc_(Be~McbDAf5eT#WtwgE}kEk-I z7WYQl_Rlf}bn+2oKC{bktn;~N z-(Wz>EfAz=;n&AKoz2Xf_-+c@-m1CB#&hvdE3*EGIXFYrr1>`ib9iifHRl0kFfiFi z0`>5@Vt}(!1K%t@30%c6`7cguDWKoNae@3PZ7fyl`hk*I3sAM-!m2=3WA`^X8C&O1 z9XV#)wZER>hh(}e^mkJB90NytfHx;F=?=>As7vQC?%POJgeL8O07T=${_yHS_9_iJ zWZ|)FM-3mgWbKZuGN24jd3AO=|ocb)l)zZ|y)27|q+qiqIJw+V? z6%TN)W7uUn>?xH4(O#clj*0e1EVMy(7}CAWcb7Kdp}HaxR47RZGaj0&qkxs?F&~mE znZkp=wc{8%yd}=h+35C+*SZ1jI~~ss*GNTN$^71mmp80 zCIhE@F6PR~@{>VTnGJ)R>DKF;hd)^cT(E7Bhk{Ngm|a*EuwVG!LUoa`ixV&4MeQu& zoE{8gfE{wGs50TRyC6fSH?TWE25!L{Cwy>vg?!qL56Wr=~Fs4QB+jK zBExsmE;4D!A3$_T$dvDx&_zQLJX6|rnw|j?7@n4;JZNO7yZI`((B3nmy{79RQjCn0 zBA}|w{DAtZF1>*OM3v#byIP0CnSAIuQ~X>Pp@AE&;*#ktT(Y$<_Z~G}4(^-LNk_j? z?>;>yPMI+>(3hjAIsXr0WXtMccEi;cvNn{?VFk}mVNG=Y zaqwkVO5A~O9piy)+I%IArMm)eFV;epA*Ge4J!q<{)~vN({{j7{O`X=%td3Q)o=L#(Lk)q16hv^xqDJTC}?pD`++l7~)53|laq5_4v&yJWF*(DY*cee~d>Wy9z6LYH1 zr9M6BYH6;grJ~=cT|BWbs_95bNQ|Z!7F7l*F1z>|XD=>+sqpBm9!Rw*IV+IA5%@g- z%PJxB_S#krgvP8tjeF;M_-b1{Wv#lMU&BBuS=i4389Cf~{v|!_^@5=t6ctqlEF{ss zWK|g$LO`*I6+uYZ@WA!wnHgze^Fve=m751G1}b1BhU(~rA6i-HEj{xRC?hDg(z-LSg2E z-9{!3A4{0aD*}*?YcjCBfKrlfD`wt5riRe8y|>5{sz6FZ#80WMEESxFfeKsBgL}3x zI>34k5)aPst=no8NR6z!mK@b3L>a9~mEjE9avc{^T2h8-^4H#}2pLC_qwb=&7p)Ae z?q`%I9GQv~Egxn8`>`JI0YvhFA2y|%CXo;II!sCx9rxx3x~SL%%!9EEstoh#`W8&I zUAMs>psXrGpR671qGaon4V?=i8=;vzE=beQcgz$AMjzpi!;rWZjf8TyjKposPnv2_|2w9sO{7}@Fr1Z?(dm|6ttq=LN0l;rYxu`ll%B62XU5w z>?W#=kXaStz_Ifo$5kb>{hAoJ8j+rrb0T!SIzsNfr)P1&s*Y7y(e>ET-~E+LJ>I0| z-;Y>rqk$})yS;_Y^4wu=CeD49<`))ZWo2&~+(yGGC^b8$jLwrXpsLJ*zy>N#{;-ur zRGE_3m$W%(#<90d(nWOzg{7xoVfj_vd?N-`Wsc4F!_sr{F}ez5wvBC#lpDl@qLdTd z%2ZiH$J*Lb56=~rEp8DNkadn1EyrJ+R_1W#90M1+pvnk^8%H)nHm$$?m@1S0#8ro* z;t-TcreHzp19Jrwun?l(C7fA-*QWZW)|O@_xbgw3!=WI#f{)mIFwD-0ojXt51%H=3 ztE-_n`2bk4P$CG*xp}#{-`*uo?d7gv=63I69+_a|mB)ZEtxlDB!+=9{kZI=@2P+`^ z$HbP4oj<-Gv|=|-u5h$4F*h?CHf`;?>3*69ZbWHk_@zm6hkEN9m^rw%-n>8D+eX=U z+8>aMO_d@2iA&4hv3QWVj)AqU)1pm>MzuF>=sgX-!54YO!0QLw)}u;^BJ~|@DEi=S zrfS}LDp49UeH$y;_g@BMov1Re&#%ON_eTtzezK}EG~Cm=;q7|PB2lq&{xVfjob%@k zk|dx^lJ)U&LshjgbIviK$FP-BF|TAlZ=!|ztvDk9*G3{z&|h9(UaN+Tj>Ub<&C1Mp z6=|WMI_qd`USV-HBC{ksF#}@b@y@m;3t}1`<)C6E4IgBkgN%A>W zWrQi-_4GZ4P8;0XI^cKMMC4a>i6oVWj9UIQAA57}Av5|kZPs%E3_qE`RPw$rKS6$- zrSni#X3HoqRc+f5apf43?^JMO@FXF1(Z5Faq%-?*iqpxoU#4k=kge=3C&Zv0R$Ag@)IlQ@FHZ+G+&8oK!g{t7s>W0;wp z4NY1O!2>4e$sskQu!{t(#JIB`0^^0<2JiK<3Is&O!!^r()=(9V-2oAiFh1YkR|la9 zVGkMMI}cMeb4wdbGgEVOb6rhUC1rIp3%iI%gaR_sg$~tyQ++rFp2?+nYUE*}Wj+qa z3-pcAxlCc40S5&wJCEPtk_}`b3@X07DVc6aTv^|bqiz%uX#+jsRXL*|UCWl^GKJ~UNC{nuO~M1#66=xJ`yEEvu~ zz^x28{-Os=XWtYE;YOuQITWG;rqAxC$Y=IpTzF9lSIF=}JoW4KoP|>oPcKG_s((Jt z%E`{Se_@ZCosPTTZy7w&zg5c;msb4I%Sy4HXRiqpCQh6*(hwn=cH_x*Ak?aoM0s&m zN+@^@M1Yew_Yeqq;I2$aRT->S3Q3e9kt%b6?8+2#ar+L>@I%J!AhgThm@Q->lK*8z z85y7ogpKs5<1~o4ju*}61vyy-g?PMtuvg(sJpdNsEVeRY&~ zh<_<3W*?=gcdb3GISXL!7JG8C#Zbj=Or{z zMiTOv}ea>A*6BXJ&asgqEY2${jg?AX05-$Q6PAv zgm&`FdAN$D@16A(+DhF5SEn`6%`fBihwF0Zp)oJ1n_ecT4 z&yE_X?{d%*-bAiKNbTfn(H1aM{KS-lmY#)$IEyMnq-fd4C}=ST(X4h?hAtvM-P(eX>Z!M|4#BvwVF*%h@)9(*vhg1Jil*(8 z$?CjD&`aQ-qjzvP8mHgDw2qM&@jFs9eE>T~MLiuQY-JcG&`!auGr2FoW|BgPRyNkd zph1_};%8~ibUFTu;4*LpWj3@FF4OI3Pz_fh!o`X=^Mr%o9+X5`p$6UK*h<)|5-c}46e zCEqT5X{&*{Er5$})v7Y0Y?}vqYT5TAv?J}OwlbIBi(e`Wv{!cMw^9g`MYW~<9q^N# zwa_3qSQKqCRp99#QxM0B1lp_ZWK|G%kb@Ktk(j_`Jm`k?16?)kd*#E4OfAc(#D>Am zk&Xu$(ahD*5Ts=HUOYtB1iNZD4j@*)EX7hi`)=4IeRIcYQznla4ZSv|zc`u5xk1B1E~r%fF|19fntKM=X3@G-4xmrOaRAtv)SQmkWQerJ74Iaq@cNQ2R0r@AjgSndb zqBDgrE@&g?}rgf-m++(32{iUlRtW3a=5p3KsUrw<+KAPx zWhb5%7Upak(Ne*zc|tZ1uNBL)o;TOyShO3Fm{L%fo4P2-Q{Buf9$Z_Cj_{>G&%t@Q zLzd^V?xdr){e)p~%z4{nbC~D#%)rzw zr=C0O-57MBVgT2Lgf6R2!`e+3K}mmZ5PDk{9X zXObc^IQkg2))P)GK^)~1Pjhh9vQoc>j`fBq>LV=IW%N`k^0_10SOqP=An`n{Ssmmv zaUcGz;Nz>)7o)!9TRF%BDH%t=SE@T;D(9BuWCM4u3T&ok+v^)NCcC(li&Ysl ztg}Wu!4DE2-!8)R>xUd6-GGa~ z6?x;)v%G?W$5#(oYop+0;3Y_ODNP1+@8jdsI~Q->&CM@JdUCC0Jb39`>2~%)DnRS@_0?Zj9>o_F7Cw#Kp@mTQxo}>9r8YnBwWp<0^N@8}g+%=I3ED6ciR!GotCf zTS@v0e|vLe)Nt*=lj(VwLWS}7FP^zUEyKjfd0>H*7T0Vm6IWjq^;vTccXU$X(-p(p zBaUI%Ev#G%r*^5|X~rRm422yn6x|1f0x@MZ2Iw^0+PqPo<{Yb*cVB$L^5N*xk%}CX zKc9YsdKbKJUr)7Z-{l#Fg$a=x>)_!K@m!ou79#nust+C!s)K)D|0*RFvuVnkr$-}> z=JJ`0_y}zUG-`8HVNqekl0c+xe(gg()Js0;;tg1PrW*c*2$mmH8<7PuHQDET-cX4bNs?jhm?yvkS|}K4)SheU}|M$ zY<7UXY=r>(-BJWo~Y6ZDpaOsi9TJz{<)J|2b>#P3WoOFY||WGcdHUFf`~kZ2nhR zq=^LL+j|inj!u?VR(5q8hn~32(7{awcF7liCnY5%<5SPbHJoZkFI7q|?O#&g%GTP_ z+|{-HrKewDBoH1-c@pXGv*gw9DLCYc4++bqJSilwMrad3twVl3+m8G%ikhwd+sSM~$P=VZ! zaWe<^w!qY~u&}LXPE*v>+*0Nc_sN*N#5Fc6gPYb$#4%E-tOlJxpd`#VpKwb*Xth=ub0a zeRXvWV>9SYOLxCSxh98HC<`v^TIA$tVP$P;+oZ$6D{#9C<5lDa4Rv)RQ)r~QnW?=~ z%WcPEXdbCD7?2PQY_*)SFtd$(TU?H14wnnzoP^Bo39U7)TYu#;Wy$xvovqEREG?}} zT-*AEUxlx*Xnq8Ax8TO^Nx1&FTKaXg)HQYRFZj=HzwIji^p~B6x}K4#g}J4rc>{01 z!Iz(cg=U3}`}?46EcxlttE5qJa+699AFYA6AX=iI~YHn_0 zZRzgbdiCL(@IgE^ftxjm6jdq?k|sD@M~hFyR)DzQ*Lxgro}@t;SmzQn4`Y~Lp4 zeluxBlJ9IbQ|5G@vKfDl&x5sC+{r~ai$maSSyg664@;c1_B;q-NmV8@F2YPnNzEY<|APO_F9x=zot2%DnwmlH9g8Lk z(Eu0n@S8=Ygh3@osZdaumz|vedq9N0odXiF7N8R|uP7haf|f#SRxvGQq^G8)i*{CO zn5)F8*_pV~sdU3pRveWTiPxE-x)ENQ2s?S2cu_g}Ag# zXpX2fO2@+doXm_2O8J~TB9UqWC0cn&0nS2KptMSY^3n__CM_*JBP%N_os^lDkyU;5 zL?fA-2OUcGiD_wkZV4@ff*gZX(0~QFK3Tco`lk{?EbmIQGPAiPFTbn^s+X2Q->IQD zaZeRPl}KwcvobR&iL&yGut3bs%EH`=)3S5n@Pw&FX+H>IDd9koPhm;@vaBc@1`F8A z0LdzzR|5ezADWOO$p8ReX<>F&j?8944Ja)vgbIiv8jG1zJWMfl@M;cHCa)wv zi`ec+J}$>ypP9`kU4SVKy^u;H1QBqD82t8V)ViXtT z;v{-CRT4rz7boQ870AeD%x?uaOOZ6kl;Vcug1b#tl$RCbEcr#Uhv~v1+}iAHS)yT9 z!3jC}EJQ0Uk|i2}pga%f$<43bwDt=>4OPQQ(rpF`(MeE^fRho?i)1ZTnIgH7UW2Ve zEg(^X)Byo(?^gUJ^@m&trM86GH`QwoNupJ8Spi`8)0*=@=uB1AzrS$?v#M!JHSq| zIanUm3ROn5*lJCbB$4tDK?waT^U(nrAD=ZIE%E5shsa+i$)m$JWhiY&jF798VFjQX@+qWvqgj!cTtDX7(olYq`>p)ZZYBM4rmwSu1T`R3RapD2OL!aV0A% zTmh-9azQ$-9GF>NF7~G~5PMLw{syvc;gDp?>3DrPu9%&_13i9*FdCrg|dQvR=TwWgeDZlU^L={y=!~|Gn z5s5!>mq_)D{MkkFn5LpTE24P({SF3?yfTa>4sKS7nx;~bIIe=qOb~@Z^p)DwnWZo` z9SA0Txx-8vWc*Z_5yce|RMxFBu{uE1PVuZK&LS#IK*I7!rN{@Jb);G;<`U5h&^tAk zBMB&xjaI;dH3xsGfas&pZES^srX{^B{!ajIxYxuswbApWDJ;n_qMZD460NoJLCpXb z5dA9VgdZ86QZLB9FC;cSqMFyp>QdRI|6mzWwerr)#_AQ^S=l?a1X1@zpvwT*Mv{Qc zf~qzU-+QR|TbgJ;P~!g}NN4l&Q}%D&y!Fu8Lf~Dw{ZG%cGG0I2v-@lw>EWNaCnW0P z;`9^S_dNeZ>~Q2(k`*lg{g@TwuCO}+oR9rr=p-6)D$i?@m8;Pt*xzXTwGcoi3X!KS(B8SK@==O z_N$RS+BCMbva&GqY9Dkz0WL%RM3$xCc5c5;4J@oI zO>KJgo&G8n!Y0>PT-CbMETw64hIezavaz`KT<4G(JpdVC4Z!M#?Rx^nygQ!^{vqf=Iem(bx^H3tQ)8WX*HwRiKT zmlYvie*lXxHQ?w71g1y|1PQVn9t@%hcR#-XVx(0h-JA z6Yc*C5Yh?LV|2mYa>sO_qg-8RY>RzX12%W%upBA0nxHdH3&)OblAI z2)h3+x0-7fzwqCM^krdUC7IM-rPdTHDpy%a&pA70Sb!xXXCSK zFC!{J_^B)RVe|QqLecR?0%a<<|=UKXT)0YCKB<;b1F~47ldz+LL|N8(}#Ie5gI-ij+2C4$` zRQT8BLt8ejUrx$dwhYSLbl_wu!@RzIeE9GYBS()KK5Y1i(c{`Xm@3%K-$b9&dh{0jK8?UE52V_>s6WDvT!3i6(95*H z@{>Y$gx!1fKIvV;xDIwm%l_flG6}t;3P{(K=Zy3)x9vFk`G=(V=%bdJsOKEfHBqYT zB|W;fbH^X))J(HV0e=s49!*WSG;h+9yRY9Ty?-#YqXp7!_Bb7`z6pfDv;)pU0%M4II*ADX3uxx$( zX;R|#a4Rh|WF@#(lGAHKVyMPFvTV-QgO@%eC0#waQUjr0i=d+v)dIS8#wwprB%6fUZjf-^)AD@=>&5&Z_N8s*Aq{>i+=4Ypb@7<0WW6hei zSE8SSgJm{Q6S|m)|D5LM*?Q`N9SBkl`TETfYL^;uAE-pPfM@y>HDvelAeaNG}Uql$O2wtA2O>8@hHi{`l7IyPv#-!I+)&WXJaHt5&YSRa&)Wd(1m>SyHx66f~hEW%cy2m+S+PTcoX|Fl`@PEc%;jBF%n!?I0y>y{#wi*5d2G@ZW^kMP4?{{hy+@ zBBXrcjmRwg_-sF9&?*Inmf+2s=ZVRw5M8;xAq`wWJ+GG*W<7rPJiU;Y_vDa@qVCb> zaEXaaTqm7g)C<*dgY_xF&}K&UdoBX0Bgd&m?U8V74npSls6joG=4-%FFlrPO6co@q z0RIRG=zsAk+(l&77x-ifIWoH~LJD01`{1_&0wGV}ka4f71b)nYV2aSd6~uLcjCDN) z5r@JN9!f~Vst;74cVG~dId;KDnY&NL0ZtZ+jzSm#*4cuBItz(CI18^vnglNga#25< z{B&(Sv$JXpLVBjRs7oV+^aJ_;xq`^gttW^UQuxA78O=BX+b0;ur+2pW8U}S@^W8^5 zctBY2_G%s6P6MwbxFW#PUHOj>aFEI$alo9c+9Z{D!i;++2(7saJAxQn1~qR)eYNq) zL5#3)tfv9~&gQG{nc8{C{W~ameL@wXxx^(Jy(3xye$s`87LD$HA#|2)4&4z+zmK`j zu(4NAU|=twHkPL9p1mi1%z+Nbd2v!5p)Ger*Yxge9f8yuzQ~0*WU_^cAyt9J-5ViY zUpgcsSNBmgZdu_>Xt`Jvg03idP-B-w!lDqr3| z%esz1(+=GN0|Wc{b*N|J8vX#Le_3u963$Hd{5mc%8S}xGz8?Bbhk~972TLGsu5Jp( z{nf4q9iD-K_-Eh24`EMH-uAxK!$$|FBBXucJspDlVQyM(14ZFEQ?9Jl)UhKmC0H2> znhLEc|F&>&7ajA4?R)hJ3=Hb->1x|#0H)QeKj-3#wdjO9C$P1WIgTNS&$` z?ra;?sMT=r9z*>I9G+iKU(dOnFD|iPw~n?Z&U>Si88)KT61B9T`qzUv*LvH*j6)a}2y=S0{t9Kak3;$(E1uob< zsUydr^(W%Y953}gT-l(A6!*o7?w0}tSv{?^#j1=HZ+*PJMFHthRfb$FEa>B`XXQIj z2seKraKZ84yW$l#i5f_BnbL2=y=`o4oG-m3ab;^{6A2NvX>c>G1_9|@hB)ZY^0(IO zFdbImwEB#|D|@+_cuc6028|JxjPWwob@Y9kEoAaux|nEA*$zI0s&I%TsFlruIl-PC z0~=ZD%=iQ512K^+d-}riAf)A%kPQK(*yk{MRKm{=YNBE8+3#~P!%O?Cfv(n)V^J$$lCR?&c!jGK82gIrF%sWo5$h!r@+) zA=Lz7psGyvLmLg1=_f>bVaAI{3kBpc3N~^sEbog{?c=iXauM9FWIjEng<0Z)=tGs| zNCQ^ud_EVvvIu_f+DN@Yf9imHT|aj%+rIgXfLm0|Ef@Ydvo}(7N+j2WYaENWwv0m@ zkt#!ttsWm=h!AH^*wu=6@-wpXYO}*26fW)VtS7C?MDHA?qTN`eXx9#stbTXbc%*1{ zn|SwOAO=%+q;7NO30C1sM|H6E2wnwxH2ahf`$AZNEgRev)oDmqL=@k?fY*jsXO=0e z>pT>@Fdy00NUzOklCK)3A~sauK8aWSDs_ z1>y33jda~YaDVVCj7NXr-wLU4k~6#8sJrzmft_&>ECmS=PV#rMk-#JNp+bpplH!R< zNCMjmKi}L|p~`?XDoJ)TL#?Om#=?YzlN8?HI}s^rU3o{2rQn6no$KKhj{2WZ|_Zpa(pGe3BVJ)X92404` zrN!CQ5Ev>zoV$ce3T!xVd9(9$DJpqlg4B~0>hI;Clb(%!7RU<}8p-^gZfU}CZ z_eAQ|A#8FxWZHsgHDuc&Bd)#{3S54cVV`A1s?4(P&ic*9NG1@o8xa27j}KZKage!# zi%Zi{YhWL%T8)i#Coidmxyk;A-?k2QHTD=wd;^P22MWI?Y+tu_&dia`JX&9@$<;69 z5;BE}SDdtvs;#TDQ_~r{h$1E6Qyb*a5YG-1_I|pz9U+tGFW>~dnlAVo5K^ns&=Ic4 zs2PN07T21}(`OO$j2d>%fX8z54ywvz#agLwM(n(WXXU~Y;KTis+aL|+EFlv%wmHYT zE%DSrJpZQLH&;VLHiGuRZaOW7fNak5zuduHG5GDT$W3_fUPvTVVwEoC|--t ziAcb|W7#EPNzA;&!%#`%FOXOm#l0JUUeJ?!q!`L$B5N{ za0f4`xfUmA#d)$&`H`;qg?|!Ks>}>OOU>rN#Iqs@mg2WDMz@Dql}O47Zus*LEU zzN#uy^r4w4@}9O2{v?sHWA;x&3Uw}5?ClE6(^8U?lRp&^w`kQf9Nq5waPMgE?%mtC zIhi-{ICvS1h{;gR46@a?@eJIsVMFNp^`W7m$FITOzPvqms>+;L?5C(@Gk^Vt&``({ z8oK3i64YEkme=@~q$|6%kk-<}upp2(^)Mn;MmWjG(4?^sRAAjYC~RB!SCP%V$ns!K zaC5vCWC*R;t3^O2B;n?fZM+7r$A4}e>aJ4HFN=IU{=`BKQabUB#CC$RdBa=j8+(&I zlIm0$A>HaYFt(d&otF1M71ABCU6WcP^Om2Wr^yjWW_*1e)O#rn&m=o&MXJo|fEMcJ z?rWi)K(!smu23stoOCmMnUj-8-(Eh-2(=HMnVeP#og-)R0frGW2`3g?Idm$(-Fgm! zCtOM@5sEivvR>Z|>CxTWtEGuW!?lN_fhcl{V#Jfg*_|_;T-yfuwc#MtZRC<~*`@TX zTaf?Cqn_FB2bjG-I%uMPt0Kv~BiqKm3qH|f9`0YLh>Z8#d`G55(sS^yfGPXvZDTO^ zNF3p1IqW2%%8c3#dx2%85Y_emzUdrf7?aEFp5Tt^woirckdwQwG3M%=kWf%fs!?U| zR7dQOQ-d3sIJKXV!v`e~*GQ1}-oLq_VIyzcn{y@(^J;3NsqcJ073v_b;}|kkFmOsz zp~}E8D}H@JQvv;UBu)tGqo^h#d+_QY;wu(aX6FcwlEL&98_3uM+)0poWGse=)%T6^ zRn_%+@VN*y8$#-@k59L4>JZc?$Xo-}bq~1l44k^M7DdPY)zAS*%_Jrj907>>3d90b z?B(g@NI`kjybYmiR`l>`(Yep$ciC_&q8f@Zbkqx(^oNHm^&8y&Tp}drj%6RN=_#TK z`(nP6Xw~8My|cl-E$r=@g@#`vhG8|x)qg*zV}+_u<%9H~@Y1?|%6g6@5}>?!pjuE9 zh;MgI)fDIc`3y#nyfOO={~AcCGIRVJs5%7}ig#u5o<*p0&;qhL`7Tukq7rjIyIUx@ zkK0aGa8Eq^9?8XrycH(7hYL&(CkxR`6y` z&st?cRhg4Zdn%~tcI?(2zuz4)^*;TO1mGaDEcIEq5l3U;W-tViJMj=uRc2~eQ!V5A z-El#_et^Cc6SJV4a&iGUBj$jPhS7~L5OBP@hEt`W@O5)r%bmADaHsvXTb-l2?M4!A z=Bv}o5J%~cSXe}pU74~FcTFqbX(XdORR+!$@IMiu{na&G?#9E&=8_}l12cS(p&JAv zVj!;|?NL2-6ucTw^VO*`Yx{aB>sb1A2TJ3H2G7`3NM_%>H<$DfnjHZlRN^k}HC9IT zyvF3nH{l>e5dPNFq4#_+LB%tni>^}FSr8kj%9+&lUDFWaY`+eg0c%Il^QF{BM^q77 ze*=hi|KuhegdDrg0rMLn^CWzxg=+w{X%8LRLZxmuQEUd*n*Au~5J`7Ibb1VEgnx>C3h!K$Z6}q*SaApPKD7bg% z-p#j5BXh%+Bc{fD$b?>%Pcdi}lu|mhg+XT$4XT_h?TTMr)K%on41Yq1Ca3#q57?0s z6_R-OOnV0tbLX}Puf&kLL63k&3%9*ldWSk$VCi&vY$~7Vte_qn*b0LRu#RGS^`4~y z@egtSD^B5`1v{7KuuxcNr+h?OE-BH09GV~ zmQDDD|0pVKWkAB8Toi!RUEY-9Azg+U`2FRz3P}C*E0_X#JT8}qdnluql}?M{oAGa4 z2uzRrO9-*M%FC0lfvrq< z!lCg#52K1iDqdylYDr%j1jQh77q8$;T z`Q-3ygp96z#J!9cg#5z9Gj)){x~L?EU3HTAGJ!|p+@4+5TT#RP3rxL0(bzw* z{$X(aGnB(ZJ!0_7{TOYdfpm%PhD)J?izeWk1fDiF0X1fjYyFwt@+`Py()wHwyQ!N>47TPsA6JYd=tjmJ?T@f?48 zK~JRPhWqdF-tmZIc|Q&2dn{YCo*dRdN;~d=0wwQ!Ll1S2|l z6KrK%h7>_zTrQdBZ*3dQQMVI^TCW-OTr&3PTt!9gb8)$Z)p?ZEU+!#GLK;|zam(Or zvH0CtLnXBMB!v5sB^uRNlCN#V<8I?M_&%->Z4NzjetBv!Qc{0FRO9mePvbk=DC)RA z&6ID;MMgdT`QqFXB^7fx-vk~Yf~GjBsSa`*xQ_WAqR9ib@xdt1{kU`KZ!MZS28@|? zCm~q~z4l{8{+|S&m_Zzw-BI19Q-(k+)4vyVXq3EkP~{BWdXoV!U-F0TFZ??ozQL3O z$G>^6&uSyI`Z8?5Vyp;q&~zL~4*e@TGPu4$yD3tJDHO$Vhg6gdBH_w{2r&mHBL&kK z(YbPVdo!hWllL=XdBN~Y?nOmJM4bJSOXI&(W~>p(Q5&$VS$+-{Y7CR8IQDod4E zQDOG0Ve0jshQ@T)poAezk74h`)4EUlVN4ye>0-%ih=`#c^LR!RyZTOA@vx=R76 z?0t~V2w6m@1gJSq*|0V?y=R3zi+lPoCidymXZz;_Ak9W(c~LynP1ml+0{V99txaHN z^nygGt=FI@&z?Pb81wY$(|cz(swpUM zxJtsgNf4VoPtPv$bjDMgi6 zBp^~{9@?lYPdyG>p@4#yEsRmSu{&`-ZpvLt4w`ZRv?Yv#Q#vY|cT6oKGdWwalmp{W zEKyRoc~nJhmqyvwyJiSY-3?KxYjgVc;?OK5W#=S`CwnHg!TRf-Xpyz@cVTni7RD_h zqH+bIcMez9vU`*XLy8Pf9(xN3M6CYho~^dx{PXW65}+ZOj}Iv#wD2r!m0^^>yQm3j z3YZkjjz`$3!Ox1nbgQSO)wtWsbg>z&7%xvRQ&Q6w+sZImw;@*i9-`W?4nr~o7`Ow` zNUKr6V)&cdEs;-$&*+4Z&bF&?R{pm@M;Sl&kF_(Mo7C^>Km1NY#m!NXDpQ#D_C!R) z`CE^OCAO%lG+$!OWh{uFf0S@wL4KAOrd>K25pnTmJ~2dQZJq>3dU?^EOSrIeU-QVC zRa6)>Hup;cPPlwOo)BGJ0rKP7-Sar<)mJz@uTk-$FC;y?g|o!I20dOP3%#FMKCFeY zeSh%YM29)8Kt|FNoaOpM!lL3Vb>7PJGCKK|)I-{Zl@!wV|!=YzBr>Y7G`|3R^wFUsc=q zXv|l#v=cnKc67(iongB|8z>+HSN~nRcJ0`{{Z3*!Q=A$ewjHOenA97O>X5nXckbM| z{lKwrg#w13HNvO9X5;Q*yLXT4WT#iZ)yqsiEJ~_jzRO`WkM$J#f`y(2Cd$?D{R{$4@)&O_kcIqOqTd$EBURd&}r4d4PJM7*YwgdOt&RyZ>@9~I$ zElW+9IwWw__MKrHmNd1{XgXj)F<*`<3v`B0pA5FlNa4QOdePoi*PyLN?jw$;IWwRKk*=Bty}!8+|~ zXaH7>9+Axt_6kXWu)1*7fQAUwS-HKE)zgZ|7!c&o?bRGY~5q%xd)U)>a@$P??2+NSl-UXr z&niM58{!P1S}mM52>(;?)>#Ge93>YNsK}!gcyM4mey-MX7+JYe&46wI@7)ULLBM>?Q&=zoW;y<7Q8H=8XX;S zxxTRdjn-cVJ(yO2PC9Qdtwu;IG6}>tmnS+kqm7#52j2Szt%nPVl0++gA4R4$lNh2* zvg^0M@E?G*w_hMUFLM88?~dNx{X=d%BYW4R=MF9l>CmBrkGD_HfI$BqzTV#69XfW{ z6q(3mzZl>PDV@6b1_cHBcJ{%4bO;=gmlyvQf>vLKT*RPw}%y_x0}Bv17L$o5CXth_+3tmcMn{DF5!FD#6bV9VV|o zS&^{{sEoLOY-#`Db72QktWs0njf>nG)VEK!uAMt{=;#AY@!oTl?nSd#j}GtM^FyYt z1XB;D^4bn9wsgbzffE)TB!i!B^zMjT(__?g;%AI53S-ax(G{1~xz~vs zpjEId3jmR0=kuEv;lB6r0Sb2{bnZQV4c!Xi7QEZIdUtJC! zJnnTaEP>0(5f|<#-1dM$lfIQP!u(GwrVi=s)3IZxE{k>?&nzNhf~_zLnpBeWV&%NC z`1?M62OPUi6j^@$f{6peE+^ud9^x64l_uJZOnf+YiQpdzMXNOb?Y%`+o6m304kNV( z8>X4}hTX@>1S6LP=#>2J$tgc*U8l}|-GhR9cP5?u0Mw2m{u~uV-(}SNIoP+QhXmIlZ{FxlizfBofP9CU;d(R^PXL zL?203?>YJ%N8f<(5+oM=mT>Fhm|+8Py?wiM zo;82NOHhJYh$atI2E<%G9uWmvAUuHqRhgYmv8m554-5_-w{*AYx;;s!Z=K#c9Sh>4 zciuAMxt~&?EcN-6LBYWj7NrpT+3IT~B0*Wk>S?&JF^@mP4hQ`Vtw3^21WuS9dW4K; zDkrG`=O0=#7AKv1{007~X;f0x?PmB=oMp#_M-@*fG83;h)rQ;5oeqq;aT-u=XRB!U0Z7IX_*TAt>*muP|;aGv)8JkW-?a?(W?Ak2-$YYKBDj^ zHgd+=4;dw7GwpAd`wRaOR8?gdI86YrZe?Xhdp^VChn)(iRKew`_P#_mvt3dV0K#+GY zj~$ggK%7#RaV4^YPXsZm*RG`uWU9S;t|!2@4gK6tCE73i1XNXJ zq?ZYmolE8&J}Vzc1GLu4KO{<{I_|#&Ro0L!9Qhp(lSY;{U=v#TSG8BMYXRv!v)brJ z|1e}W^}Yiva^zRj*0k6UqCAnW; zzam$hAc3UuOCR5gI(+2FsT(oH)YhFmrbGVA%g0BK9J%=ywbK7_rXX5Y6^Lq9^)a<; ztp=j{m0Ujk=aHikskv~bE+EzA6{Oy{T!~AO7*|q=F?tPU61;oyBDa{V-rz4$hG)00 zVG2BY{+>Lmxs*B#ge!hGV4Xplx$Orko#)#|i`DH8~V3(t!NL#Oe z5f3!B!Cn)u1L#Vu?CRxYr^0+4cFEix#>HqOE~T zbZlEqQXmwNctx}k{0sjKq<3W)=Kan6c82DSnzeGPYvkw?l2k~enhVq3J^Ay%&Y=O` z^{kD%j-xK}==NISa{qSrjoiGvyv(fi8+r_RmJT5Ws2%vJO_R0t>UyU>`y0hfV zaNnke)~>DGo0#j@-E{?S6@G7NwVDy+LRe0`l58354rIAa$U^qoU}K75xTy~sDk9|A zk7y=xhcVq`KC*61qsDHnyjt1l>(z7fee@xp=t*+&$N}A@NVyYMwa?%R1MCLBeth%b z_BFkHT3Q(EPTh7LKan^P`H5h+6rsKI>dKzRCPs~$dw66yZ`n7w zOV!5I>ySe3b|zfj-pI<#*~81l*3`zmYs@F&Rhg|Q20j5TjlZ~|p}kWZFRv!n=GrC> z$8Nr+GM5a6s#&T5{Y>(mLye5h?cG{6t7qJ}L-4yi0WPK-3gU)N57aia$E;pYPka12 z5@=oiH5__PeaG0=lC9htP25!e=^?*YTBx zx|VKUt(?qt+w_~7OMJ@6=>ai-M3_QfdRZ$YHOEA9iHJx@{@GQd%}gykyjnFdF|c&& z`Y5IJ2S&la79wrF`sR>>JUS7OQ?i<0mM%~BNhNCdw0y8_Fjrr*U-&PhLX{zI`wL#V z>vMdk5g#pOpSswpv>399^q*k=vLWv6dT%+nwWW@_=h*G=NaUHVIR1W22DxicmU_3o z25LTR3!ilRw?~K65n6Hg?p?;Na*CDQ@9+k|86Ds1}l=>hcBM8|k_A&mwKxFw{%k zx-)U2D&!UCJbMI)jfr{q`01fV1N6;XCFb&^R4_59q)vT)(WjmJsD-PR4fjJzjUSRi zX*ixMp&>}C(Zg)m9!QK@j}T|)ZCJ3fp3{j2Pu_zw5Y;&qy5@KQI3v|Zq0&cEPC=DE(nt2@`9Cvd$~7r zb%xJSqPgt50aqBjQd3PqQ^O+cE^!0HCk7}uiJw2k-$_+n%e><#a;-_O zK&FqseoiL0sTgibtd$aKKXpGO357}bj&<;8=|Vf2)Xcl@Y`EFU)=*j)uP7@HI_+_6 zOzgwQaeHR=HmvLYuBcqV&zm=*Q`_Dn_U>M0hS1pE;78}@t1=>a$$xPAV4t2{FtJ^m zI`$bb{`QMBoRI(SDxSZFEpM2=?vAGE8M?8mF z`fcPYgjDvyH8FM{&5T%;**3PdYp;nhv9Wl#J$e+ES;!OcVeR|$>{^eOEu5W!`5kcO z@Xw~6H{TI!PF5}e?f}LuNW5xqs-&Z?HDqHXeptqZVHm!AP)qk_bVNBi0Y`cHkN8Sf z9P$dI>eTL8!7W<_C&8T`A-IqbG9{m)EtS!z&9~sK^hZuwxI4};K(T6=N=R<(^LI?| zuA-u$(axSC zYCC<+wxmpYWfk5b+Z!yjmX=;DFVqNmd0;n%?TfVm9ng7S;up>s;OOMkyt(_Fy=O$O zgV~Ct6!;o*%+sUO&1BJCr;^Wix_Eem-vjNu8ln0NKMNvNCOZpU2gK}~f{=Mk9v*yP zxp_Zq0#dMglm)^{yjd^kTUVDgGB%YOzqPWhQ*QvB$=39D(QFWiGnSWv*jN_esO1n$ zZf6oXAt-wubMxlSyBUR*&Xia|!@EbV9*mIjjkx^{ zDqpx%xO9vEVK2n3U3^+G06WpbX|E2H+q zR^o0E3H4_4Kn)D{4nSIzxLC7ls-YD&5q3$+n2YvSP^iqTr7w$g?9S!{) z75&$9dTuG1RX#F&8<{RX32t)AX*@~5o5l(XqjyEaLs@eDEf5^Pmrq-wzJ&XAP5dk$#Cj%iFauKvh*|*n*9hu0&mlJoEeT;mh_DrzVna z3JK`C?FC%S3Ga~Wo1yY6Z3l_&1P6f z6L5iwM`v|I`W|11ZYZw@sFw5W&v`ml%{DEcs-f=^57%^|Vi~df6_M&e@WhQ#*ws>V z)RyZ^wbJHa2)d$6zqbd|YJBKXEK*MFSk=0Lj<&7$<5ZqdQ1mH9^OpTCZ&nDpXaT#|&-ISJ4wWjPB@Y^0!jHX$FgK5P#cCwUlhI?|x< zc#`15#R^=@i|axfwjWhWI8|=t2+GU2xa7OrCn70TCa<@Jx=U|xI>{};fAdE<7#cc; z5F;0s0>!&BFI{vL$M1MhCH3pg&3J;}cIz{4av6le%?q$sX%e^)(gZR$hGdgoIdsSTaFZI548Yw-Ca7StwrbG4h!=h=_8fRci@1D%Y#WN zJN~4ey6&}4MHlDxQfdgnhM;q*R!a&M>#-MCHXGNmI{Gk$A#0a6=T|8xn%%7QR$2>? zZD-tTxWtIXfeu}#^2G9m9-#Ac9@-(!e?pa^9Ca;pBtn`;pNPUtS3;Q8&KmVtbV^v5 za`xoOdk=}j8#yy*1%%{k7njFl`1!#tttN#*JSIjIZo=TomvXw-@gXWy0ii9o*d5na zpkk{$>qE4Yk>1P{Y?i+O0Du5VL_t)8_vrWIk1a+py1_Y3ji9li*AHuNOAyK&PnCl#w!-(Z}xYgts4*)XK3m1m!`cs)Zn zh7WQC^n&OeLzOfezM~LHxDThmiwBjcV7YSL#QgVG^n1XmsG%w>H!B9 z40B<{5RZTva|XJbwi(A49eeRcv@z9gGoFu0S`Hxy;{Tk>L5dO2q4uop1OpBMBglT% zL{D|Yt>om>i;;Sh1X$_`VE2iaI^4rbuYTJr&tHWvA8yku@NFJ=gJdh|-wUeBWX2p& zP}Dk-Aoh=3^s8C6eZvFbucloYT)kS>DRSe z0}Z9#YtA!lCxi6XNLdOvkPKcI#X!IuE-oP{YMrL4Rcr=KSbXua3M2XD-SL5*-Nvjb z2GgtWpeQ~5-ZIJ!nYK(5XTvKBtktf&npE+EB&euKy1G$G(cnZvHlHBx^;u&@#kG;J z)m_c-{Dq$dnaJ4g!DJg3l-ycI#)ecPfbMP?hmi5vc;cQE&zwxZ7EH}E^W zU6wI_n76lg?>p~dWXnD66st1V)(=O@O@WmvLC1Vn4|A>7lMYBG$SaKO^fEWL4Cknt z-2DRVMYfrNj{68HRYrCtQ~@d=Zf+f+Y0>U8kKw*M zr;9W;Mt{VV;^Guxj(=m_Ui0xfSh#{MwOwWrDWx(uK$m{?|_RU3HI(K zgMcVV&KU&-R8YYj&zu!=&hgCY%sJqhbIu})V$OQzfJn}wC>bR0F6_?N)jhi`%PgYj z-MjZb|G#r@n3?YBuCA`G?yjzKcdw_RrL!q01pi$|X1dWqYcLnxmvwnu4bWB-q&&8( zZFn*yhy7bh)x6jLh$;i@0{qj~TGg%(1iKIlL8&bxia$*5^1>P$XmlAeedK_4jXWCG zR@dq_VOe!#D;16}56v)e_$?i_kU(24N_uFjirW2t2;L~mUeM1K@icbcii5ut$V$3Z z6tI4RySuxtmg=w-5L$tZ)clc6^mUqy69f0MWiC^&3&6lk1AZ6uv{CoyOLTE)DSpg# z9mMB|@bB^Y9g%@s4D@X7s#0bC>dv{o&6-%-80*`3?z;wZri{j5 z+BuA;VINzuPF&dlsL4;p>k~EA>s*W~6qlv8Fwp9@@*=JcRb`g4E++fgHiY!9$CDj&Cck$BHM>5G;H^^V)X8`LL_D;I1b^j{66~q2#oe9j z^#b;IzH187b_>mg+w@#?LFjoCVke|jyZ-$TidDb=Fj!UQ*&&29_dH1fX#+9%n3a9q zkU2zeEl7=BJ9}t7w|b)&tV;aCh8H2#Rh)ov51f^PJfPmH*a)TSC9I0Hta~vhq-DMl1(0zTZJFIwNTs1 zcycQe@=J&_->lz^HN1zBfvD4s#@bn%yeDZ*{4rUGd6SEI4u}25p?69V0NZ-t%Q9}=0Q(T?4 z!2ukNeU*4Rzu4Q#Gn#lBwhXzRNz&o;!Bo-W)+S#G)6#8=DobKwber!Vd zVwHnDDGmMWX3)ip3r2P|wRApsBZ?-7ys}9Xso2%`#MOtAHR^mfmL9KDoE;`847Q@x z1KfQEZxGA0+CQqw(EUnr`Wt&KG|yjQRZ83eHEnN@NO8aG9^AZtbx$< zJqor3r68v1qQdB=W_oL2fg0AF=yvYD2=!?KDZSxJR> z()%Zuf`T?JoMLHZ@wqh`-ApXVi|A-;GUEtc z%Pi<*qTSaYMnnNoW!4R=r>dpjkn||X%&Y5z1n5Vc90i;sW>OyRwyWEktPE!QnyYnP z5&%3a&XrSTKHT0~g(^cu(7oN$jqE#6%{=P#BBbLEi_Z{DnkWPLCocvh_@~{7PotL*!eoOY;NMY zA||Ftocba1&t+3wo!kdbSR9u@?8CknR9s{}vrtmq9!Te3Jedi-|V*Rs?3&gNZHE&%*DXK zix)0j2)uefhfnAInZ2#`oH~rVc=2Ljz=goTz(*nRj6{gbfvzruoFE%a5wO7o@o4xd z%}sc%r|pLqgs@4G7j;2TN%K@#F7%K}5~?ydR2g7@no#iiPH;fLl>!m7rkA6c&lDjU znkr|?4!XJFp0!cCk;`#ypqhb!!S`MQh40F2FoCcw8sMhp(q{=IQMkcWuF62H=CZOk z$LAv@liOrfW`MoEZL5(|qCI#+WDY0MNbPoyZv+uke4BxS<>sKOq-x>lHe%IDM) z{7+b8a38x3-{C{I5DoFFY1x&8g;E@kiLPLuTkxB%OLvImB-xIn6wCb>btxd=#rx!< z=)f9C{pf2jM5sbm%65c9v)UkJ@(QOY%W7+<>M~#rFe6z~rEe-)Nt0|aHI{5Jfqcjb zIa33nl~*fnF!5o7Y1agIHH&6dY%o#4eiDg~!{mqBtD*rbiBoxoxxaf9Pt|Di3EbIP zgeOD4s@$n1@#Nw-0m}chd;`7^X=7^M9Oh1Y$9UK4G7nb?=MW!u zx23BALONToCeoMX{IaqX;F_(KgB2HV>=5d={34j$5Xy*|f+HX204P%+_R(sIP?*MXY-0w1sUbJuYlNGwa`JAKuV*wj8)oF3J~w4Im?rIE!>LFi`Wjkp_KUkxNrZzM z8n*+E@-Llg8YMyaXFe_aKO;1PVu30;;%(3&!}EICWbL%qr7rm`|ZSvR~LE-k4o?@g-<= zRpj=4pqj35W@}R=v(|J>qCRjXFBJQE)T}>fEdx_k7(Pe0FmfHR5>l423WPkUO+eCP zQ%yAY=vyMqE444d#Xou|nY2iU3RfCNwl}q+wm-V(ZZCWi`8M^UTni0~- zT;0W^QG@!fZfT6$cmi>Heiw<^FZ7~-B|TAX?~l-uidIsDk*^sM#ywbd|hPeM0xXb=BcRM=qpD+PuI za(i%nZM#0p8OdH=ZgS}SQC%80XtZd{q1aDgANe)pv#5mv znvJi@1Vu0w3Zv_)quwjwgn#9^(60@q{{pH!jBTUZc(}h9nyQ>F{Ot5wOgkd|6F2h8 zf%WS&9wT!HnpRAfYBUjAK@Vd`Uc~Cc?4xiPyNtRd7i2D<(4|Y4fqx}b%U0&j=CLZ8 z4TBL+%N zX7~8!N)~P6iCx{ZymrnyZ#lh(CY)1Z(t|fzn@l=_8x=GYUwlqc5*jRxy1D zvaVX7lJx8QGa3l3xe~)byn@PtBcYy(>daHHN%3<*7hjT}9y3SCsoR8*53IRzX+dgS z5}d<)wtof|aMz-t+45rG@a>|rbn&usApz92OyG)Ms7Bq00@&4%;g-^r55%4VYnHEr zj8)NiBKPT9qatK}PRXHKQ)&9>=4MKUO=G?S6J|wSudmLl)2#oaa7nM?=fr>bKt5Kv z<;Xf?aV#9ho_YXo2tRjm)bQ}z0IC$jygns!82j2uwatbE@HrX(-UQLHNPY`P*bo z@~P-Jy{#E0*~T#n9Xs4Ob^@^(y*E?tJt0q;fZ2iWfR*Xflw$?_wF{fO$4_584s ziq4rRqSh7Xo?1H)A+0m7pnVI{ll&KradUGSGIL3c#P}C76Mkr_h3fTOO8)*Duy&HF zirUDXcNmybLY{f?j|O$=(sSan47w~!YXdW+%z=%~4b3cE+KdAcSn(9ahtQWZhIVjm z=&|_E{h7otjc)tCzp)FKd8R)&wjfJp!gUQL@e#qSJV zbcg}|hSt5{KUJrewU3Xla~+)?Qzb6)=-^wFM;C$CQg;n)le1bnEEt>BKi3E;3wnPg6|ClmLDLLOEW@yHnBCaZ|u`R>LL&3 zhxmo_3%Ver{@^pDt$K1qd-a#s0d2g!n>6utHiP=OG=>7S88idyNuU2Z(ZtoVNi*Mu zPBv!FJ{LpFLwHn%WP>Tx3L(EWHyPO>ikkZueH{6lyMdL5Z{vEzMIPvg+_|w@(OV~F zq+x82snwvao4LNx*gp;z!${A-2_{P|q-9LokrHj>^5Y~aSBB(%8CbJ|c2yXCQ3;`S zw-d3fEG>hR0~ms0IN`Q`v@bI4kXNPIFX`9f6+?aP+}-e}9qo-=Tlu~HQpAWs;)GvV zg~@2=0S@K7n>2-zHS1o5xeQ&jI6Ac@LV7RAK~88jO3l)o1;c%TZ@uaQ+nPDy+`PSg z&%dN0-??l0y`ZIve;C-x-B!1baYM`szCO(wy3g8vfjrLsV`zIr8#{c{-qL#L+}(TIA6Yn5loe|kc45tEYZr%R z&3s&4%}t$sPd}%Q4I%IJclWyby6M)g2!8^X7-$Eam{MUW@Qj8?`)o(bzBua#e{ ztc$#v;3Ci0$H%6Y_Qa}P_=o}tDiis+-pp%}abAQk!Sz;;x82pMEVOkqoO~3Wma8p3E zIX+l%+}`Mih1~T-P;VZeTCEQ*@_ei5B9E3#NDetZ*)ahj%eOgTNr%5B$c-Q0+g;BL zOGqCVCtHsWBV)f(7gmb1Qv}NJWf|>=74gpdphnYeK~Whf0+B&0;DK{ba#omC=I97J zt34LsXxz^GBndPbUDqs#3{rZg751!N+4mjB?W-OKRY@TKUsY4J#-m~qCjO7y^amJGp1XkE)zCj zWky7p>c*ApH1lchZg1-7y+`79iz;EzUW2tCFiRlFj}A~lX!*rowle<`xB?fXC!aof;=*M%Z~FtC!e+6HAE;A=n2%4ZUE#@qg=G2+<7lMP?5}pmdhr19X62!c{iwk?^ z+?4`i&{Cz4B9BV*A6^d*h4p7Pf5}67U3Nb>@Wjc}iK#GAQY=BqePQ0y+t&impTXrh zf8oZ*ELta81mXL~cP|B=mnGWuClIh+A<-zvQ&Ca+&EV^a*^r_1bz0h#@E6w}ye8sA zVLmiT_Q%+3mrmjD20w*W3Pw_$g7n1e!I#gRhDT5|_z6tTsqigXP_-@g<-=6cKMd)XR><>*_!F21p1z7AdwOhX!e8IO zAHMS(4ooA;^9 ze43?HXN`LM4D&4h@8OeoMWoLwA`DGZlKBbChx0+V3ANdmX`T_!?&A-=d|!>g1>`p^ zF6#W5Gbc`-i6?9;!}moPdO4;kzd{u3xVZYlVKODC+}$aPLJJ{WzP1{6GHPBP@tx zQpjvpk_P{j6=glVdHwqR=fv|Dn})uS8vhn2c@qN*OjL>D=ce2WzH;siX3kSrZamJH zFh?o>YocVSk}5IunmmN-^pCGjpE!2=O(Mf2IoCh~sjUpzpcmvp7@3=oUzZU5il!72 zPZ_b7*XUb&f8fK{<)k2J8xn;kIUx~@A4%D>KSkg&KYgD71;%RY*N9Oqn_=L2hZMdo zeDUw1?KfziX~}PKL!Z5H=`*1K{Sqxl;`_gFZc!h}ZU$lXqKw4g;G16x*l9p%VcN~$ z;P`ZI4`;vd(^1`Ul0OF7H3PY2!2emuZOh2_21eT1elXld()&MD2%iW zd?>@W*p3{X5Yhw!VyG#zN?FEfma7nW<{^YSN+BT51nEPd8`+Y@pZjL12w-QIbbD&O zFP8+mE>K=!FO`LC!JyU1Ua*vCr2+{-1p=^*tzPjcz!sIW2xO(dI{84^Xp7;7qo%U# z);@bWg0v}=8;m8s$t0N0B;p$jDSe=!CH2IdK`Fpl@}B{yJt;e!otFIw?LO6~aG3)7 zibbU?(by*Act;K}UQ!}Jzu@Dq+4^0G)Hgu1PT zh!e6WnAkECC0bncVZy+Uo^>4^n)$`$3CWU7m6=y4M>S3`RRpc3++q?12hkvZnTnIb zS5Ei~{}AL=8M$^Y9}-|lt`-x>aF2W|{+!NQ89$X>V0v8;yr5y*=rE^zh^lHU)rdUYVrUmTF*4UPm=KdlaE;>tHG-75zN zy(lDUq+I>OrIH2YRVg1au?;Iqel}>pfYrM$-n?|-Mf4Yjn-j<_;n$!uhYp>*NsIz2 zbI^BzC~91&Bs3~OuCL2K{)PV`R8VDz{w=(AXj|L1ZM*gydiR}_tJnrh{}6Ne{DA`} zU=0w&7!ffUiBFb{8r-pM+xDG$9u5FES)hlDNh_CRZ~tR9&TZtx#c`}@#SgSSO;fOQ z{>Yx)yLIp0y$ib9`r~Hf`E< z>=AGe3d|)wDns&4RqxWaR{+WZ#mV!A_J$_t3KZ+owOikQ{SMv&gDRj8C7K|0%Eib1A2VfrP(|=~rD{7+$t&{Zf=I~zK@%;@uPk;phheZ9^00NYM zqw=QGH@^?d;}u_`bxaGpF-(TjmYu8~M=_<*;cxbB-FW{E*!;@04mFt+?U+Aiz@j~n z3)gu#7GnBL5U_n+n>KB`^cZyeEg>>kB$L_}eA+g5Oq;fCJ9Ql!^bl;)tLW@BiKsAj z)7+`JX-15j9g|6HJ4vs}jC{Rj)NGA|by)N7*#`20Y zqcTmH6*Xsg-|j$YkTxS%ku#gProzJe$94_s)&-Ys*u1TADbzYkVQ!p|Z7*0WsYvo4 zt*AWyW;UV>$N%8qT?HEryqf>6^jz;oaim+<%9lk56Sn7?Q5o&{qE zAf!BJ-#rE_;YExnYfO9l8qQt!?A<%Dy+ds~pU5mY*dpz@WRr)(n^Pswkvyxnqq35w zo|&1Mk&%&c(|!cZ4K6E{PP*(CaAu=*FPUQk0t-84>Z8 zmWtv{NG=VFS0MucJ?ndY`|r3sra&?LKTB=gcxKH%!jK_8wxGMVq4kR0dp67)t*TLD z$+2fdu2vMA`E{k|974 z{yr2xjfjdRzD}xwRBwxqj=)Jm!@~2y?h!r|b8Q0;q1win(@b!a4&8K#QN&TSU-7dx z&K%gbZOgjWwGrZNz7EQVbeExw@YTDEaJEI+XDl(lS16YW&B`{6@Ty_sxp~jtrIUKA zYwPd66+s0n!? z@R)k_rX3d?j8$k;vJ=PE$mM|jO`-5pVs!k+G$Dn=i603yCM?cMI(z!`gI5WPw!maS zmr|;r_dkxDwB(5JFd~QFB!8|HcI_Abhrp^bIXQ6N?rU_AE<)?BlXDgfv$~(Fw(DTR z$D&&o4{Y6kE;&1)ua$n2aXa7^mu1$dhDLQ-&Y;)N4o^o)#?RTPs9CK{Ra#Cz#8f4c z6hWfOco;4`OO8iLK>7a2%=XB*5jiROBPdOMP}j&JAOs3pm~_V$AsquVI~yBYTl`~V z>-O6l;-Q#xCdaBWC+6BV`i*s%P~j;I4DZgbF|sswH8<%v530{S@JImDafZnV33RYF z@o=(p>M<8?3ZZTf_Kw3tj;XbS4HV1P7XLcdzZuQxX_OO1LmOF4Ab!CM5^ovt(5m1B z`XFFYcbD6Mc*kGJ5n0P6h~xbK3}TYKIIh?CorA4UG)!8g{z& zHWj9~3iFaj!qv5wHZ7vzBq~TVoGjw7?p>IrhRlxpFBA5uhOaYuo8j68PGWy1d55 z)rW-K_!da+rTMA*cWya(`KDvoUJwJ%8`@a{oQU09N9Pw1` z92{)ztPD+z`;On54sk6x$A@3|_rL}&$jSmC6tJ{6(rge@f_o+(H(Nv?p03rnRAHK( z-_t^;QaDLz8oiLNQ9wkgAZP2s5hF%S zd6i6px>Uso<*LletE@XO5Rp`}Ny8=tMzrb!>RCp75^fIWYEwl+kQN{o*20vI4*CmEf-842EyEL^hz7OPm!G@)dkcpKqhJY;b3|k$ z^#62!2i8$8#+JWB?~8Mu+o&kdIrd5@5EKgpj4;MsRjKa^SjpfVdwu|{DzkAgPv0Si zcppm%dtjr(22#biy?+uOCnjt-n?(jeep=GSfIBpLSY_hS#p<|+JM}bB*NGbvbIBCG zAoFU#^|%b^CefEy+q$=6RS9^%avt0$hz!t1s$1?RGPH@oK`N#|!SIF#-Ig9YKC7p8 z{Xv9e+(Rfm&2iU%w6b=Ch(ZRF6VI$ePA*2uMt72-+PUF@S_nU?)+<(=HS=tAg-LI?6o%Tj1!WAS-opb8}_;-!i~`43iNNY_E^Jdd&>` zOnSAj;9k)6&}5lI(bWKT#Qgrue1vLUk1xc@_yTCe^NV^Kdy;^93ffePN6}v0sn}Z!sK}qN8E^nd0ZuK zq`~1z_pO@JsZ&QQeKj2u`%b_8)~RF1PF+X70VmO4S5NHSsZ*zJUAp!gF!10Va0bEI zDE|>qRc6cRhC21TQBQ+656#29d+inKJcfe@e&Jt3g>aG!dfKbI^(g=q6WBU83j}La4*my(S9wHF2Dr1CrOD|I=kKcwwm6?l> zTHAgDRv*4x2rk{pC{30N7IbxL;0Ie*1MF%xnYLd9KIIg0JRM)pEbLyZet%4|jXmod zw3;GQ=@!ByqpP!&NtfAEH(4y`8$ z2r;RF(Tcuq&b`2)`-r;w9^ zdS2f+RLiyl9z_q0_SNzj3I}o&4109Ee02n?1=_(MSPr@EKLR1%F*5IG#3g4I`Kc*s z4qvpaU&of?*9Bl=fEkTUCQ{JdPyaz4%C%cay*e-GDs(N;p+@3FpBj?Zq5ELxIaF!>Xk7;8KA zrHW~lbGa%(*73vz@g9b#^{m7A1`#~zt*x~u?0$-sjZ(#0J0YDo{?Dfi~22;?FE@s(4%{5K8g z?yat=z33Qqz|SN-*kPbj!@Fg>$ukyh+Pua|2f1{ffM>m;s`jtpd&D9kXJ7;45u0y9 zha-C>f|NUEh&RqZFd`!2{rfQdoBovuR|Q#7Bf;$C&?EcyuADvD-b~fDS^wx<@PLc& zzdE+i(5873T$cJd8TdfNK`dyvIi7Cbr@lO8TF3fk0=%=Km#1O7neeQPs4{!T@YKxC zJ&nYr3XcG!t7SR9%3{Q%U9!A45&M_V+>}-`+ppr@5V)vi5qi z7R9N`(9I%oUUXv%gFR2Pg~^w&7P|FrGW~YcrPWATZO@JHh|ss&*G+3&ugU4h$)FEc zxrsy00pNlAm8-t~p2rZ@Mo4_KzCXL7j-_`r*)AMa-?-5vSTLjXtPIwwW?{D)I#wOK zby>P*%ZlH}sUoFOYcCP1h>tDqiZt~1U49xK{&K58ezF^0&1lJ0AGxhf-sAYM#vMgj&tlG#4IaJ z3p##q+sdVFnwZx#vI}?(tWHf|*@dRGu=+YG9VYIAk)Nx}FcQjRRYq4C&DnQ5GBV=C zo|P><+}0lhH@KxKf7MYzgZ*#g^a2_Hi#BwXt;q>G&G>VaH_~hNu>>a<$6Z~kXXyMc z2Q(%HWCKvr$*3|6SzXHb%~aE^?^+CLd7Yu}86Y17|q_1zPFkh<8f2_K3$*P@ALCC*Q5T}R1xoPQEYGpl{w+TKH= zV&d`&KxKKje-h%U7+cy}T3XrI;Idh+JPT1LtC)2`y>LmQFPrMrz8F+qmUN3GO&OU_cFanuwh{ zT3edqVYut^eXQ$NNpeom4{aLm>DGOb7-|7g9t%G{vO#FrhJb{)=%}cW-cEJu_Fobm zpHw8^t|L`tF0Jl^zq>jR4yRxQ{Lup;HU>Mc{lV3vZA>g&+*=&HaJ`?aM$=)i0s3=Q znHztOLrN-U*0xqAhPWh?j(`t-jH?^_E2--}{Q~lwTYr%OU1f~Bwt=V2JM=UQR0qW* z6y?5kQb$dPvprGadz`8aex0A%(?;FB|FXoyILv9w`*_u;+ao+WHm`_yxs}fYK#h2^ zKRq4Rv8jcnMGwE3mriZgQ&!#k82swS-`;^$m;)~}3co~*@9cq)=H_$IaTHnCQY|O! z$eHDAI};$#|UnV3#gJ2F5m4 zR+iS*&~=Bdggwxm6PhB^CdnWwK$Q`ty|&Uq1J=TE#VX{34DtrM8ECr<$zeMw(Pv7c zI@;E5)qMlVHO0CIrF>r4B_j=_XJ}z#W2J#my`l3y5!TBK3)E9mT72ex6^oA51W|&; z=`Rl93C156pcl;TTF=uDf|$ziIh0;*4Ua>Wf#&+u(nPb-=xs0#5EENm^VR)a^z6IC z5}M$Hw~0#UIVa)0``c>OuKPM0BEd;nkWfkHD`K$_yv-C3_13A^cM+&Yf?`>-U$~R` z%0`1XeCK^eUX`JlanKi}Sf%Pn9w{<|syYdG8uEaBLRFb?qPscHe7}Rre%{L$x zK|qw^B3zEtXNR!*vh_CD%@jsm(N@MCII2u2EEEWtf*2PA<4KfhkOET1R=* z*1M23i6q334JKp6TX-%6bG#5X)F|Y0kb?+9tO!cTqQcy^`UV~YabBMu>~*%Vaf>Udj?^4pq{GM;9=H;zXk3jg#dM5*7SzH;$KGqir(*bsBHD?GQAkcyU@c|! z1JBby-jP+Yl;KM3>0{ubpQB~`hInNM{i|7Kq#IVuv(6A zcvD^1zKdZDDdj^YX}Ksz<-WD$R%QNMV9kCf`luQ@Z&<&+rL}6EHe-uHA*<3p;uroE zNKPX!R8Deh~f*KEQb$)EB#zpw*RHGc*2hdIBb z2de2wE&-z&8`^bWDw2vYEKbu>Qc}JYlZn80;l;s8c-nU<3X}q-rVd(@X2gUh= zoa;23aX`$PTUG_Ije#Ldyso#WVVh|n;;606p3zDgHq}>UXpPdJA5}qU$AixdcgSeK zTEF@_u6`h=xCS1&UiCFB(5jBXyfvFwuU@fY)vC?w7n!Lmjox|-KMD_6&QsI63oc6l z8TU3Lg!VlF^-F;yrMgk+ybjg|-XjTrRWJ|+qQSUdGOE5w!|^+yffNvp)-mhd8Fi$* zkHjU#h(0$T@r+1l$qIOXdJaNHPtwbv0E$PT?}9{?8NxGglGw^H&vuPONa;Z;?9sYu zBfD<%ib6B6Lg zy`x*{G#my~69u+1oEYEC$hOmb!crxp8|vD%hSPQw2PQPqaqdgP&r~l%eoS2rG=c>B z#zf$Md}5`AW}Sqs?Qf!dgNdhnT1J&&HHnyDU4+)(WG%T~9h{0(tzKu4AduB68MApv zLsX;52LaRt|9NayR~4JqMD%ST#(xV=h~@Xg-< zHSNE%c^J~N{(XX7M2L7I&+UV7sxq5x$y3Xg{WBpxb{v(mp~A13_%k^LWFJ})s3gOnvO2j#`c(ws(^A;o>rW8cFm0 z!`d(WElB;!(4)i!zjtt~?cD2GWYU|UZThNc_Q5BlOP1xNe~eE^OiT=Et*=(E&k}qU z9~+nc6^6h2=MSH``y?ST>0!X;+RCWq*e%6mVkgLc-^fhGbLhIHq@?q!1}Q1mx)hoP zoJ~2R_~UO5c*xT^N7ir@P6Qd2-36cDA3A$3G9mH(!;98B$hFJDLJ{U$n4aF>H4!Q4 z?7H?MDJgz_A6Gs5&hhzWidGq+Hu%0Ey^R^qq0dUv)qsPk+!1`bZGh1DZNa#Lv9a-q z1lgp+aE^WC6QUjf&*_~IsNXHnC|ZwhIpng$>DbHs#OFnfd5E$r0?|+q$MQ?t%u;skzH4xzD!C=IIw(_s+!T^ zhaZ3vT-Gh5z~bE#n>%)2AbWpVPZw3w4p^qg1}?=7dEjnbLPC6W*t@xXJdvvX)6YUO zT5uGUU4BTuR}-OOTkbGm7$Hv+QV_vV=h|+gw=p0@jA?wD!ow|NM0TU=ZbkB~}Z{XlNhovXotw?=+*|WBWwr#^5 zCod-AG;wh!_piPF7S}9c#1; zjz7fLaj?rNVNRk2?H<-l&CQQ=gUX`@1-V`N_1wN~_d?z$B}HzS(izosx)G60)!%!2 zXCS09d;57@wp%B*8LO(y+oC9l5QVgt&Y%uRe_WO*`en&5E`)|=wlL=e?VC338qp@ z0w|y7hXvvs<{f$j%n=i_13cyE9DDi+r}_HfMF)FhRL6ex?qj%~SiW95zV+OF*wClN zs6ND?W{Cw~p4YDfXDO!axC_-MYp!(TGWO;ceBZ!#BsnX^j=Pj}aW~c>q!B>OluF4Q zf}a)YW3F!Ba?*>~q@<{4Q(HJ_+P01SiXYK~@}eD+S|f03x0K972;)$-sW7pf4SrJV z;(Ji`XhYBy&>iD^k#60KFC&u@pz#Hu)l zICcC$x(jVpDhl>a_raeTye?3Bhn*p3zH3w)AvK!^iRG3I)J*&S-tjnz=P;s9Q4?~O z%6UV*RPm!d_mdb9cW{qVCh7i8+-r0j`@z9FIK~H$HV&_^=F~o&&^Gd_KTbJeC#c}1 z0mBWZdJ3bc>Mr8Lsi_dPI zTi?yh(!#Pu_bH(%RRtrZ9AA`l$Hmxq(TQhRKvAK_j<28pYH4a>YGw}AgZjen>T|?< zFV`wQ?J76+EOBsh!Nh6Ove)qkp-cryM2!LqC;Hawx&#)JtD(w>OUX#HeN=nbzKie$ z4O0K?=uA^9uTbL4unKBPK^93a(Sow&%y3xqM=vtB>fE*~7&JvyEAc_T3+bk%NRHu=2v0-8`|lftw>Pn{C4;YmUQm zouY*gT1P=HX02CTtACmi5oWM*Y;V_^yf#}sHco)|uH*OiVs zpPwGIG%>pv1|zkUohWZGf{cyRhng5$SejZ)S^)=)6%~w;(Cy2!b6%dF78aIu>v}If zctt2t2%a6AV`yq>ZDWf?1QiY|&b(kiIB@VMtI9;(Xkddy3fX2hH+O63v;71(xuH)> zzb0>AG_{_K1Ab(0Yty!4pTK7c454bp%)SZQa^lV7+nAbpzs-gU(n`{jCqCF`ZfxA3 z_bjp~Q9+eSdbrEN#PM1j?EQl-O`hd{d^T-Z2V-+i4*4)>Hn?@>lgaUS@Qce`X&M=sv%HI11$Vb_0X*$V88C@NPJKxGv4EsJD z(uW~a8A<&rRkI3+#R37lP|PWD;e*x5M+RUbAv38JgF({wb`97;P`n*gDlM~uB`gWB zIHZRxDxwVTgH@m`&FCX88dLxfgiAY=1+^WJzsmvkVPYj0%-LJtEE@piibM~P>UPjQ!Ae6~bk43?5yVXt*EiXFI7dnE;dqG?m~AAN(mH{B zAkLUre7jSVBvR5#Zqg?e8k$b){}xELTs;*&MnpFUB|$%_NIEHB5r6Dbp<4dNvx74X z>vhh?Pb%rYRZDfsj+J-~NW{@K$Pzy1qNA96h9e0~VMqbw??W|d8uauU5Hhw_)s<=GMU!lZ|2)VNN3NmC3dYa) z+V|uEGba3xC>c_X7Q}*7PnC#qu}GMao*Mi5vXv&9y!R0h=UcN8DWp97e+*pe)Gz!G zfJ2p$HjQi_CJ#ii0XXCuP^R;jgIbJIa7j0=G*zPN1XVti2Yaqk0%=;=fevv*OJOI*_Ch3HvbO%z0?&ThT)2P(#cTn{fQsrfa0c+u|Sej zajFA(3RlR1+qUVSg?s_zt0Q0FDk0a`WFL_!boqy>m8+t6WXfDURxe*mW8`W~iXw(z z>1B1mzNqMZ#rs`90tFvoit=-_vT~}edjQIFqFX+tse{|Q8XG!|U3wJGnsN6kMYSZT zKFuf;zpXfpC?=<}86v5_zihCwB?mhFr3EP~$iei?FXSGx<-k@) zP=J$U=gPF2q*7VwY3Z57`lcH7lr~>hCMH^rbQv2se~$8txU*= zOeiVy@^W)>vUBsQKQAsVF0M>wN{8(1?4nAC6n+X=ItxoMo!L*Ykw3PsSo-!r>afqQ1CT7xAJ+Mp9IP(%LcnDD?2|=hixp<VPR-8 zcG-avB33|?F6C!@h}^$v>3}{RMlU#oU#4c21gv@Ep~;;zHSHcG5zm_BY3!5pOtT(+El2(QXb>Z>OPz6*-`AqzTi=EXl7*wM?_(%jV4p>fCIQQ!j$62|^@p+&>` zX66=_W|m9#USKE%K~Na( zITj0G0){F4@M`F9O^hwf%}gCU+xUe-@B$_`EU>n;@&uZiHFw>GFgM?^(L{DE@WtbU zb1G)0qG{{(2Hd16uBup+oB8?5kv~U{?ANZ(EOKadK%L@Hm!Gjd+mjox{C{{9JE}JVUPuYDvFF*f9z*-fAHeZLq4^KH) z_Vv`YZ~yi~eopk`MkcE5ChieSnvw%#v?}`=)z(J4L8n>Ksrk9N$yYC&k0vv`l8hMt zHR1}ea@lC>M?Vf)v~V72wed68Z43PXUN`91KZV|d%vP?% zxh-F{wx5rkmR;u*SkA7LmxTVWFRXR6vhF&>uaR+0O;l0CT6( z(!h7jPgP~;7Ha03vj#ks8Aopx6ck+BJ3|Sn?t75Tz=;O&u8A$QEgL;e&MZia8`{)T zzrmnvxXn=)cDO72v}@IpS<@$D79T%j*3p~K=;{|WV%Rsebxn&FFA}ozb3aUOW2@!T zgT!CtUKk+X5L`R96Uez@`O;;})~;D-p{d+&#d-XoAm#n0@>W|p)2}s8#p3=4IN!rL zOp&G(tsCrN=+y0f%Gdmi=s_OFhRsINbFu}W!!|5kG=0kC@sw{TKo7mB;4lvKK|H@t zd*z~!T2J4XS5WZe$Xr#Vy8j_P5d$aYdezl;@*NkNobxsJ^R0_#!%|>^q(}jg5;QI1 z<%%WqFy*Gtn0YGj{#OVS#9!9Sy{2QQkmUTF$cLWBsvU_>1O=>42XW!mJzLLQeUX=6 z5dQq6i3XN<`+ zHyxLDN=pw%wK@(#?=y(F6uZ%1jcEwekJbCi8=}@oT0WixyGrygxNqhE8 zMe#dpRkZ^z6}q8gmy6ELN2-?L?7@hlw#FKh_rXEX?9lUC2yF!?Zh(lh3lPuf5d^BC zN5|zst8-#@XJqIl^?9fWYyBE^o_>IlltB*EPVmB#-Uz7;nGCh-*~U{%yY|%efnq|M zim!j|;$pfwP+>#`TJx-|)KBT4IUO3^THCQNIc`cw3&4!QdRDEnNKP3qkMI!k>N*k^d-CKd(?}1! z{34OzQe`O7&MxT8tK}sPCpojVm0^o%WKWm5vU(7z;Y?zjR0l*gVhVOH=&hq+*xql< z)G1S^4ejG(;d3>yv?TtL8baG2lbDwb^ZwLa#54ZuvqDxUkPwIb-+xdeq~3x$faIs# z)kny&Wgk*a5JgjeUmZs_s1>O)msG_Y$r z38siYU6m>27w2SWXXoU6%_}G@0p(5tR+Sm%Z8&z@Eum0YTmq3t%b$NA*o+Il=42Pb zm?0?4Dn}w`#U)j`ivETFGpG=_V8;Yso>8lmQY?K0xVwG0yG;f0 zc9R$@6r!@M?iFG%QQx(~*_~{CChp7#Ije#Ut|pM!&7z#{b#<+~FT?$|l+VX~H(*Iu zq-pz}c;h4sASr!4w6wI$E{4LVt59gDDsyMcSXHgYDe@1Qdt1k<)^05I?0R?iRD@Lb zJ_3JY97d5KS73L(nJKUH64*S-%FLwp0Rld}>_5m`)1ntvzl24___G1?`yk{LN@CY? z7LZkCj?XrAX&#l6OTP!_0fIqNGvJ}w#}&kPr9>0uw6<1mGy4R-%+AW-6ODw`$;4nlz~>hW zN=30ZHkw*{$L0fRIE6b^Wr9}^QZ;TtV*-$&unIG)^wVP z5%Keju{`zf@1?BQ5_g-j#2`JSvg%R(2MUfc_5m>zqSAS_Mm;cnV(=3(Yr#34sh1bn_gT=22IqrtNC zpclgYgIKrFR(l_~)YQIZaxpyMYBT`Rn8mv%wL~=?F1`CAC`@W$Z!m1-MLLG%gr2UY zqIxu>I@TUyGUVjyKS<-EA3tER^&m@nmKWzb`;mGvPhXg9yK zW+39}9lakTy)VF{m`HqM;}E1_|2m@#;>(Ie`O#Nu^U%DLzy=(wE&*(ImX!%W@`x99 zaaMO2NS6ATvb0B*Dr(Du6Xo8o0@Me?wkh4)_8Q}Er899a?BJ9_90lOQl!tq@walM= z%$n+D=0O6nAU4Bamk{l7PTfrSQu7-|5Koq$PMwZHs5+90bhpRI=X7ZJ`!!`bI&f# zjy?lzxw^{!FZ{1Xg>aIyyI5#899Yb-;Uo(pE@?uyhhY^g)_@x-gp;Jb?)l*vs`{Qu zd?w@WR)mbM#N>f+DNOJ*MlELShqNRz_S1vYkh1m-;td<*a&b!U2I}hSCV}s&rOMpi zGzzJDNSxyXM8pll-7TY$w(GkrJpAzmxF-rfcp9j9j@tz1(p7>7uTpFq-Sey<=pB{ENn>On|r6VKqg)vz@m|878&pCbWm>? zmN+D-M8^tiP)l|6vOUYE^)@##Gq-g4^W1&%nAU|H^AP9sa5J8I;5j2vSt^6xzp`>5 zs@*6i50n-d*ovZ@b$HEZ93?M6JS;qJ7Js^DZD1A@l@HCPm^~O$LLsz0;x< zpS-AxwN!LZgk>}Q5Njos-%q_Ng&@`3W%~ip1%{JzIv`~GhI+H-r*yX0<{7k%!%s?L z8`VVaBmC*h(ZOq!5O2VeGmK=IsQ`9a?uCUKZ}jf_m^ArC&{t?pLU8j&eLB-046tqpRto5_>83QY;2 zYJO^BtU6%!pX=rivNka_HnCrOG#JuxYVGu9ez>hNYWq9z56%sYaV6^A?#a!NS(A^T zVvz$0>2IxTpnhwJHd%?)Wg#LiCHe8U^$;4j`wl~TPFdPR6U19`IYIW#D(O#(R}}7M zV0b<6zKt*?T6n zMJ6p%A^V@I%0Q$ioUm-=Aa`U??@`2;>`!6yN3_C{YU);?+dr$yFw|jnb_W~1A!}j( zZl;d`Lb@+-XUzD^r>^rOG83;#+5d(A6R4od%<61jqp=^^{08At7;#w>@#da@VYL*F zQZTZr38VzkdCi$Fb605$vjr|3su@Fm&3inKNh3z*xK`F&9*sJDW!#ZMSd|qfuCjM}xu< zjs`YOXF{i}wDm$&nc@%k>S?KH88_H<_Eu(Q<{oe*UgP95a9zq2r;Y7wU&Ew6{>p^m ze(ikg)~Mz3C_ghFPRUDMmB)Uup1Yu2<8105V3 z=j^`1NHv2>VDIOIH8w=9E&KiswS<3vY&%PgubJYHue*5H9W-H9H*YJ|8rFa82oS@4 z1;r8*JKe&RG2NPW@S8lmOJkmL%@GT><&kOg?kPUV)Ej2uRF%nmXQzvLttj^bE(=OD z!RIILHC5FO>iv20dPZjEp+!RxQa?NA&wU##z+ukzQ8S_$s5yG$!kJA`+1= zr=Ph_-S&&&4Up#e9np&34O$Q-pt4F@39NtQa#e;7%0(aj8ro0Z1KV>9li;kTzVsHX z>-|Jk2F6zrBg~HJ-q_gC!56d5=)wJ4G_UiM_nB+tJQx_Uu{qb<~Y*JN_9AUd$EDSTLmeaL2_>f9g=n@Nj6Vv|UJR z?XOKE%v^@UVWo=KWLeO+gq~a1*uiby%&C_8$kesx-N+9NIpj3!#rfK*sNh9&LdrWv?X+!>HS zi&8E#I+n-?JOEsF#8o(@b$v zuLcG!`>ZaIyojF`Vy%Lj_VAhug`ACxdHq=uqr3`e(DLvjJ{HXe;`E>IZpK#NmG}a3 z78iHd_%1C+uBA^-a;n?P2TlWLNTjEK0v8tb;h1zx|J9}p)enVM${%R`z^e3I2Sve>_std-y|Z`vekGW*Sn_?>~0p`0*3QVa#6hK1be^ z!3Ia+7@OMG-TlO*J1h4Z$*fF_y$*65OHQx`WVbaz%_hQ6(gEk3*}ig|_t^7yV#7|% zQ&BOcqwNYz87X}CsIOw%YZ>jPuqmTjv)<^56DJHC(8SWX*X-r5KNCL%MOl@aGR^BC z>lQsHOc*zQ{CHf@xf_m?ZSlM%JuPaujwTOf@0i&g>-SBUAxMJ4`42krb8bm*r0YU` zpRVkfgOhkIhh?>6b31bkToUj=p9H-TeT^{FL?gD`AqmUt9m#Z2ysJL49==I(Ilr?x zr^!h8DHd>{K>2ZwHC2{fc|#blfFufeQwCoUF*$=8>NySC01t3sIsfZpe;qBO;4k23 zPz7m`Gi3xYpAooy7%sB+Lf?5tp9SDxSV14ph}mnM3n9oO%y3h0OQ24qB++ zO6Z1*KS%XMK@~ z{?wF%#_a>za^5|0x6)QMZt*$`%!JJ7bG6k_s~#gJj2}l^=!WBgkWRjjXBTlzscq=34&dX?+RccRTQ^rOG zIlA|oFrK!~aTj0{nNm}R@R~oRi$(vXXNw98i!z=&>Zx{`aTs4sdwLKHX9us@3w-9` z!H#|H>UEsDELgKM6-ZU6A*uv&Dtoy(ZZV&1VLCm(7y2Pn1`Y^@vl8TK5s||b=u|PS zg2Wr^5J&S=WCqTfFBS>%UN%uje8U|g4dx(M^4^+c-fG_E6;_WUeI|OQBdRoF`-#80c25Io&fNUAOw`V&X7`< z5+DQRO#6+06s5j0utpuQemJVuIIb91E%-vj-&l)~?q5k{a+c5I@^A%Z_N%YgeB4f4 zTP4L1tNrfD?F;73^d2+X+uM6c_m-+E)w>QFwfibWhnd~6K`pmQxJG$JMOb`}&g!6U z;+{^0N|uOhFzjB%?#DL`CWj7@~TRrMqAb6^jLBhXHihh z6EY>kn(MocfgP%160f8bTZXw9wweT&aD%OrWDI} ziY$lo`GM7G;oGV9FP;3rxHudtFZd z4X}>D#kD5P8{OK_b=W2`(OKoQkONjYCB-0}TZgvLu^N~Io+%}`TyYOBEL`X_VXQY` zM4uXJ>JILG7j8fGYfTvfnarlPu4gx7JzRw&7Nu?^-_$|s2cLmwmjab4v%vHSE6M`0 zz;u402Qp}pg~#;waBorL-bVqqq!_x|iZwU{=w2G zX_V0Y)7#as9gq!+R|;gZ6m$+L>eM`>Y7&`?ZLDH3#4|pjjnE&#AU5BkPwOIdGDcn$ z!V;GYV)o;(|9fjH@AoI`vIpF}q<6HIA;idrF}w_kHM!g$t)n z96x#tmd;U)^mPnvTaNQt^$`XbKX1w?1dShe=0{DLs)4TLeh%7&P_=_kzFW6x-)H;iDLDj8@WvD>=NlckI7k#w}+XAWUE3EqS$-B89+ZrIpkz3iP z1)rPiq5dn#l8_=(hA4RMwAKdtPNO6nL4*^U>e=*N2D#h-&P zC2kb*gfSAOe{@z?PTe-daR@8G*OqE%;vUd|B*R!sP2{yH0NAc*5L1d$w_i0Wx8Iwa z2OxEm;E#oL8sk&QepRG#Cz!#1Oto^+}?YgKe~J27uHlG^D5iWJj24sn5LxQ=u4zAA@bGquvX_+xlzR zF+7f6d;zB7Ffv0At0MJd&%hTzfjkk=0qusNj#^gz$VmXKl}Qa3QD(RauEf0$L0~GZ zHQHuB1VVJ>ErD=i5Juw7O$g~+i-RfrZ_m#fsH^S1pF-poyj3db7in&B*H$A`{bnNZ zOB1EGG(g=Jk`)$)xw3LF(sQJD80MpkHX5`V=Asme7A?E~)OOf9-}4u^u9pIvYvQ~& zj@8l7^ptsK zT3YJIZUSNWkiA!#u+p}xezBg$wm?|wGHD%5% z?5k$lrAnp@ky?K4$KyD&BNwwtMbONsntC686YK69p>H5BvcSVje^y@=4PL{ll*dPW zt06RfR}lU#Ac5X8--qEOCvQF`?_gg<@)U(!KZI{ZB|#s=HW>1j;>>pkckSAH>UusI z080pfzpq0s<0N;ZfQ?j~O5O*xa;Rb1*!_A;9v%<$cQdzZ(fw%92L_4{Wlnwl5GOew z2(f|Lw#E{`yLWNlu3dXxrNVqJC4d$)KQ$KL@V|JMEX%Xpq;y0Dp24{Vzk(h~LNj~{ z^HWdl-?i(|xlH0V#-{m=e;zVN_VgVVBQB4}C7o{KEv(wq|9o2@6p47yDhd`4Yo=De&9Y_7 z2f7+JbnE-EfMiD7QPBry4LF$VSQrda`3m(40lOJ{{YaeoxJAo+eSMeu0+y`WogrZE zZyANJPgvmR>$|L9`xcry`ZQj*GE1DUS8&s#TA9|c>pFD#azBrz4V}78`$85;xaqGa z_UkZX$dHXmQq*BYr z&(C-1(plq%>mijv^N+zuP0^MU)|APOsgKambuw!`bP^}zh+hqD)OqlvWy}4#I9ph` z4tbXg`;X-3MHy0jd^IWLl!cL+Q`f=EmMsA?LG*Xv{wsr2lw%xieUy8-+!`y60XYgG5PqV6?kwn z5>tk3#@3#?*w5F`uXmfKTDpeIPm{Q~U`mSD_A^5|_9>u1756u#pd-SBCl{A2Uh3<& ztZhRb#Hqi)4-3iCeHVjZN|^`Z2?pV}&{_yhJ{IP8+96n1$y!rFAE(N#~w33 z7tx_-!TOQzNXu~a%w@}#%(2kb?mKHA9cd_J61~p<_8gnnZRZ>X36pG(r{?dy&0e_H zZYIDiUuCvB_+Bxh?1g<@QB9Kx^OpI|pH{D0^-;^t&>XX(z|7iwmo?yI)5-&O6JZtL zH?pNl-Il(~mJe=bQs22}@^``;F(WQW>TO%cv}Io`w*xygwssrxK97oe`HTQ!a9CnW zve$a|L`b!H*M3+zEcf*r(x=1zzu>r($g`_zXzC7~>bGc2FHOC=haP+&yiq_TJE2(g zvAF?4wOv-M@LReRl+A{N*Gfn$<9&h6*pA&t+xA-#zQ8S&rC3=97NPl%eWFn9-h`R=GO}ws4lZ zAyQN3D7N;rT+>UPS6SFuri>Z^G>;kUedfj!l9S^6*g56m zuNxN3I!pGHN-IZt_tWdYW=@@eOTXOzG>x`U!Avv_^O>I(wtUenoMhJe9Us1vCI_CX zkn{VnJL5(SA2DWXNDRzXR8&sMiv;-}_ima66}tH{Swv&w$vwTeclNA}WWcAScoI;t zcpY?M){Lp6MnSFluG{-Ig^q{lP5#N%3s>y8Of-t(&Z`u3Zu!NneIO4bMvR*@b>{TR zBM8Hn?gN(;(3X^-lFw`A&b{`WtSnTL>yLm6bV=T|L#xM(@ftp2?2U&ojR!>`OwM@w zWP{&C%&~ck)_%$b>r82t(dz{%TNclmICeCa^6``AU%nSfgaEp0%A7|5henR@@)|wn z=v~;>t2{f_%qsd4?K5N6UoTR{QtYJ0Pw=VjbLMTM0SJ_3QU+o$;QVf1-i!6a@Ui31 z2E*P)dg^ykYShA6vx47&TUlk5M!+s;@vr#rz|2{+a(4zaLNN=RN%7Z1JLltDKC4f& z$2Ti2Xc-fdqaH8znT2bA+*t3uhp%K72&jShF7)=;5ndy`r#+4Z?|x;X&Sq2adHeEN zGpA1U8a~X+3uI}^%0qOnnV*-qY0j((-XOTRf{36EKluQr(8?Kbl=7t_3I~Mr(ERH0nah6p#`4V;Q zz^r9^@>yoWC%Ifard3^^Gwf6!3v!$HEn)paAD=aQ(qV#u6-A8VLBLNhE zy;*Yk;PzpI2QA%prl{b#rA9U1E8vz+`+{Q^Z9=l1qeeyj0Bf5TQCB7B(8ajX0 z$Rf2?nEG~eS3B&>sU&O#bS?XfdQC?w` z|NYOPD!PC*$E7dG{$^4Bu_~b=@m2DkszAPnkh@SGv_VRvoOUaP{F4e$o*NZ)EgCHb=bf>D_|kQh(1({KmfliLVSBxPV;4CM=)) zlWOwRVH<7ExX1wC!Vwu@{*uKQY7rAg?c6l|d$k|>gsQgHA=rg+$;lDovVDz$2H7xjcS(l9fO#31SD%_EKr6n|&$RO<9nm3=*9sqxi8nPDTbKT4xvpTQw4Aq3)EL}33$ksU9S*Qxyd-Rg4c6#33-Xq zZP?O~u1(l`Ez1}Pas4CH>^L`AYF+2-5RodO&xqL_O!DnoOxv!4pmj7xsp1_> zaHkySLB`7#<-yHc`YzQu3YjcnTKV^gY1@$}ObG!1a$aa@{r<+k1~6rI?cQ0CTa>}X zgozJ4XO4t3+k%-@!OZ#y#y^_zk7WG0%y-&b%hh!ykm;iSzNud&h^wOb%8ksFPYL`x zG%E!=sZW445x6l*-~MH&64R=V|6{JPI=cK^qt_b1bH6@%t7Xd#2XG4Z7d(m%cqk09GCByw8( zE$QqbjKfEc9L9gHKZW&CvNQ}&#XS0JS%=xh&G>+j1>RvTQ+Xq@s`Fil-T6iiLpm^@7TC;^SMB}Bbxf0R0^70!K0LzibM&;7p0l^UkyF{Lk{c{L zOATvak(#8+`TY9Q-rYF2!>6v~QrG<|QGfNA8B%n#4c?ZUOT@x=LCg=FMOq?6ne z7F;~Cf8(aj&&YOze{6jLLh6(f3^pk2a3()XvQPc7YvZP^FWi2y6xGE5A2&a1bH=TlV+`YS4YGmI^qX^R86jD?{d-w$9EiyLx(hT3Q%1bQ&0)0kLG1jlJlRrm4?P zyEd%V%%e{~cQ@S{Cc6TN`Nc4WpB{B@VBWf0f6snhYU*pXAFwJH%Aq7LDU>}>zC4vC zWkDU_zs22bZ(`A|CnlgnbzMyl@11ZmD1N_K7=HWo+NE>aHMQ2&RG)t^gpq7a_)!o7 za~5`Tb8g-lGtJt{(8Ru9_?N;8m`0&c%aGiPeW&zk*`Wu{&7!8BP0POVuoF??<5h$d zJEg8FfS8;#BFdgVqDz}jy)gj|bhKSMj{KO*r=lj#d*82>W!=Ud`}cOQt5sv!3E*25 zjfo$C67Lvn&hXM-bagT@b?WNr(Ym%yovl~FKCXhQl`l6P9B}`bGq`#kv+n)-_v`B3 z&U5M)9z*w+DFj_ky0?E(E#2DfdiCqm$D?VRUg2r*v_gXa9+VKF4AN7MviKN!ys=aB z{(bv(ZRt`?wZ@7=_n4nz8m;K)OY0gM8FuK?uX8io8s^T|Ut|zwmVcOlToiGGuN_^r zaC(a-=Gy8y8?S&%tipwf@@@SGKwh8yx<|+6U3>QP?BijeqS|}h>O5X$jqqOr>&!jS zSk<`elG5K5LtM7HCpl5I0)X8rW{NY$bZcT@(Yn89_lDK0P1_EqOH`qv%Ym9QMZ+Cx z*6Y85p*g@&b+Sw9zwtkfGE?Rmvuc6ZCXZoWGXv){$cHg{&2V#=jecTOBK~|~>w+GG zCSACFv7@1GtH}`dtkjfAe|F5$+~#KVhh&VDkLfuDBC-yW{AjN#QvKrz*)ov!*c48% zcmUrODTN9^caVMxJ?>~}X=c{Q%*+(Sf_xr+n1Yr2`?&Y)3h=j3{FXLT4l*#*P}Cmi zUQd4302`fFW4F+2$LIG#HQe48g3y-~Wqf!?A{a1C;_Z#tGFx#8oa8Gs8bqK0c`1GD z&D)Gv1(Zlm8>5a6u{XDxnOW=$gq?o!?k`e+M8)6Jk`viea-z;Izy$2M{{ep&mSnG( zF<{6vzgt)K)I+LsPePod3aFy0CoSTfi!{^B;m^Lic=W@^Oe1@(7$!H$S_`>(?-2v5 z6)}x~8YUSD5sM~|YGh+$W@gsJ&SA{Vy?H>jAS0XI%wPB#A^=bIhrJjI*O(zE_)MSP z!4=a(NHQ}w$8_1B2_sPji0e}Py**}T=G$+=90bX) zm$km@NE(dr#+qSB+wNs9Y^$kYrI2<5_Ycf7Gq=7H3ujm23v_pV@WB~K#o*5uY)JF` zoLmwGRWWEY{79mZZn(q-C@uM(n_mn<`uf%`OG^uL3rlk|v-&oTM=#j%DGw${lre@7 zEL=Ojm4$^lPKPTDr^TP`hR%V~krSU^UfYaC{lJ4Hc(meLW0_VM;J>MJ`&O7~jVv3w zcl5mS6b`K^`kq72GQn8b+YZ(9AOW;1ng^jw3puvL%-r&P6tp1d$?#`xY!h8HYAbuL z%;G+_22Dof3!#B1$c(%|SeWWFuHUHnYj2$1PyZyFrZ^A>pd3x)G%LG=fJM(c)-L)Ml4 z{)M1BA20g$#=7?{nM!|qWhFv-mtST7c=KdUnK4c4S`LLk5cH^<-}wIuWeZHf%!&iz ztqhZOm_f@Jbw36jVGb}%-f>1FjbRV$!ooesv_@$-N!s&$eR|l^)|u`92}rXSuJp9k zvm1e*;1|KZ!_C88v>JIr&qsTDVNr0v*|TRaf6Ae|w58I^f^P9oy1NPY>zgk4r1btwW(dd*(}IRv9lNuT$pfOUsYpoNE$em2}S(mziJ}Y&9{mE zCF)ls;NlLIDSFvRU3DluhEDl`mC#{`ndcWb=yKGNzU5swBb_!yTF%0GJzUjQk@GM= zIG3wxZA{1m7g|wza2++3X>fuWBOpg707_n(b5v#@4}*&pnKGbZKR?=qnYQL^s5H|u zX&feiumqw{2&X#LGj^N=2^8vgiS_wD)W3laa_l$r*0UEeF|omyj!mDw1&-$@5M!oc zdU&z*5t?#@oHtmJDf7i$m*X;gB@p)f1)=M8b|D|K0TN1KLBuP8 zv{}J=2rat`ri?KAg+(#>+Mk&oBSoqys%5n5tHsA^cdlh7YZ zjX#N2``k_kH66J|TGVqu)Y(ZSen~OTA^qVF+>u{@S9boz|1GHLvbdLpt>+2`^ocTY z{VC8{Ox~xK`l$Q-)A)Bu36{E?PDY&e(_kQ~@GL~-U`?6Pu64|ZtN~)hFuXc`z(4j& z*{OHG@xKjf%4`?rG7p(80pe$3CU_I0vYb(0&TzIf}qr2&7i)aT?B24DGlmxv4fR zNF68VxGVO#C!nUxhrn$bDjGN5D-dxQ;fYA7*@C!6+Ng)`B?g+Jf+s1#d2yHUo7dcc zrCALAr#m$`Xxz5j@PI%7r>+Pg1VZN1KQMVa@55nJ3a6I|sIxzJg1h64%_j#m(eqez z0h$)h2i_&ljyhxG*!jf4wHlhWgFZo5U5TC|<6@xzb`2!nT7wBV70CvvhadwO8Ba_R zr;4UbYREoK71fKcOAWp%q&*-zAWYmy1uX z8e!_t`!zOCskev%P*WzYOD!#r#pHNXnR`G${;SKj_U(@!-mI;me=D(AVj5Ni_En<% zJ#%|oweb2tx{9<%`w-&n3{1v%xk3gPbyQO=v+i@@*~%hOR1uV8SC$V(sPVfSnX82e2f>;`i4#*t8sSY}+hVeY<$@?tt1Xj=!#> z!tsBa{_feGoxAn~N03vwl}%O9X|$sE_BGLD|HoNL5xaKoyndHNfG6jJy*Rf-MbqFJ zneM=t*TbZCry2CF!VIZ7IjME^CIi?Ah^3(YTvo(MYsW4p{a07hs`DsSP=TmZrrp{w z3ZWX;;!DqbR)EyRkXGi#KK^jhS_QMYq+N?Y-rZr{%=5&q`Ko%2Vse4q_|_XZQ&{J6 z0=8X%n2$j_IS6g~3(jq-VBSc?=VDv40FQZ)lqnRCV?BeGGu2iwXgxCokGGyOty39T;3vAQESw|+eI?p5@59q+Lk4$i z)6$?$_3oqQrWeu4h@_^*sMEY7_$wP3``BELir(!6_)bo`&fdOg)TmKYB2qwASFnXw zV#;h)N9tGK%Jj;TL}I${?&!2Gs(LQbX!1N7P(YJOgpvE!?wGxh$+N_ zwjN8)GZiw8zDV%x<$z|E4NVL+3@w9`*zzXa+`!?WQ{iwRIu|k!P3uxezwLM^PlX|e zstP(^BuH;-qG~r1)+_mZ9&kp4yTTG&X^|&zy_skUjKMUYm>!UUa6 z^!2psHv6oI7jJ~n+!N%eb=(aH?=@7{^O`VWK+j%XyLQx5QSn}L92ZNZs4TR%;HL&R zuCCd0$oQe2-MV)5Fw&^jaf~lH2A+vNvlvyY@tC;0M?X4YZ&1tcWSCgF#X#RNv6YU4 zCj{OqgP4s&d0={b=Ybo=;+!VhXz;q5kVN6wnleq4-PNL+#UMO}E@K*%Cu-;f{xQ$O z!a`dWb)OEw(aPNN6@fBs?J(yKlaGjn$qf*i;{Svp0{~%WY?E5ZamXt0-uj+0x1Sw0 zF1OzV-?$1)8Opt)_cx_Y8EEWcCh68%1CzE`EiCV4Vc2R)g|ft&G97DbbeFZ-fdS+d zU!VWk!qURHmUdm|?#cAf$qLH(FM`g`F7dQ#HXYmv6c2KK7W6dX%&_B#gErrKkH15x zEnI_M_9~5gk{P%PIs|#Jrpzc8L-XOd85Ym&Ze!JdGRdb@-TlV@IAlzjKv`2}12c@6 zGOd)EGUf70i8@yYp{}!zf?Valb2UaC=a!i=PY=&VD!SB^Q8rvt2zG(#{!Sglsnfu^ zQ6o!hD=SM&%PHGf%Ye?+-`qb{Th;2uQ@S0g0wo3S&PopK?$SWNuBBV6_Dfc-ajmUB zoCbN}^99hTidGD4Zd`xRdx*1Fkslr?IEcR6rvvr8Nx4;1Rc-U#WVnUfP*FlVn?|Qz z!Z731+)gzb^~wY%&5D#Vv~pW9N;0ITOlp5qeXW{C)>e(ItQuj$yw}386{gm>A3E7t9(o4OH53%4?+ z;rsl8xaSdJ4})fTHq&p|>Mk*--d+!$_ztFwSU9CqZG(2d%#@)Wo;W?qQVWgV zdK-7qG)ON49ELAo%5Zc7-ol*{PNhr!akVHm#i6RQ@_pB z62h_%j}B-cWYv8RJ?J^ae=at`PXMdM^1U*pt>j~{tp=x>RnK^G2KVPD$JMZHbQtDl zBG33C4#&j8rjdC=gpl{{tB_2&tP_3-XLmQQrlW6djb*73RGVwR7a1VaO#a(8){V}- z0;BEttPVA-`h4R97vyV=62|1bveQLF)?I}l4zf#HRN8aW62l`RuN>K9V`|uY{0{0y zE|(br@m~>TMmSs8-XS}>wvK3G+-z)-2qsza&xEk!&JB!=&8<3g@K~{GaRZHND=xx> zmORr+p~#e>-Z;WV{hE$}SYu4uz0E4BwQjxxCp#slW6{!o>eryAwv?!|ZICoTUjDb| z5fKjquJ&na*{J2vcR5^APKCMstDv^a#&J#DrobkTf5MdcMogJaw_tXhm@?wk!y2pp zyeU&S%C(;D&_z4vbZgRO7K!I1{7>NIZ~QwbTVQ&?Y`!LbBxb_5unSBo+Zk^xA%RST zFAQn(uS`9x|iemP$Y;1o&S&HqvS_bpD}3hmIWFWP(tW zfvW|e-EmjCPE*%##cq7(;L52GAm(6bDpOI2L@}9u5Nz;vHMAa@22<~4hSX1(GN~c^ zv=C?IiJ(%Z#ealSQR^h;`Wh|Gnr8yR1F-_8(eC-_;ps?C@6NkokyH$$QsShTRM6ED zHS+W&)vRz4hn$npbFw_y!8%~$%VYRqg>Q&`YwTIf5`$9yNHwMWT?^>!ZO3@STtLq zfQMh2a%U?-8izyEFnMrBq&TOig=+J$+aal<1tuYxUU;x?l7^w>_CrSw9XvRDP;-Q8 z-g*a48M!YmYN~LSTzZ44FTt(v`zv!@j@M?GO_V^8>dt+Y%bzcsBXAxHb0oCm_ z?S{i#Nc8E2NKI$|4O{__4{n%cXayGQ}pZa;N`%? zU0tQATYKf6!?@O#Pws(`+L16YXBE^MWg7QWi+ZYVL9G0GKx4t1Uv+uf7FOaN0%$1(^|HPv3va;lIDGgEWps zkVRX0+9Xh5%8;`Jg&EJx_0CmPeQpsE^R({jikwckBkrLj`OCzAHA8V5wQ|4y9q`5cAIS4we2ag(Qi>+>{U? zm4ux#OuU5|IP+*2z6=XY470$aR_&IfVX!Nr3rv;L%nA;vgrI?fztm@oc}YC7|d zEW6+uBEB-?cjIpY*~4(bPnKcU4z#OQzw1{JRPnB{%{5JXfpR4F!Aeg%eYbHiYWu+f zvGf8{xqz~CXLbIo8-}WA&E?nl3KwjnAIhG2b#5V2sUJxuVDQh-qYIIG?T}>rQUO#w ztHL3#G$5NIfY~8t;;yWzp=;FLqnmsCwjJC%cWiE}YG57w1#^QpyGJ8)r?y=?xwmWA zzKcgsi(2ZJTCzNZ(OJx8pwt#7-o>icbLF4(qJqW>&eHJYbaw;2HseT- zq>wz;l=`tUEEM_)7-ZHFRj*t#e1rw9egnS{Z3L4_YZw&a^TJ_*^irg+rXR z>i1dzSBl@c=%PU@VZH&BUCA2@RWxZo?8jET_VL4@uC+qHp61BF?E?ux4x@L;bd)&v zg}EApUou8ZazgE%+}IzKTn*2Ld?TWhzR1Qr7q-dNnLv37?U2k_6Rlk-uv znx(!n4|jQ2Vlj|w6IyCJmiLvxH@LHVSXwx@D-(4CwU(n{VMtM}QKpI34zxwp9mor1 zm{tlNw-`T|_Hd^PLVpCqrY%L2AH<3k<&SPt*S1+F%CxTCyVtLdJmwr>Xd{)vrKP<% zbvtB&JSi+C3y}bKt)ha28`zXt8}J5yFD~Zd$8T;NS-p;xN7v5n+qQM@)U9P>lj>Go zKS90Aw+9T?lyR@2(POEMuZ(nuO8j!fOwl_VT~1FwcuYZU{`(*lmVD3nUP83Fg3|pB zh-s~5_h_KncH({p+AjW`(Ndq&#}CZzA8elN0@Fw*!^Y!wetmjL6QSPo4>P3i__c)p z#(ylzHe-h~Yv+jTd}hR{%(4}*iK!(XRi!Xfmog}u`5<|oH`q+S%`~vnOOg30Ateu% zc~hUAsew>;(m!Dxl>O$az8ac-2o|kBhxqFtwDu}k8$x=hGdE+-Kv!4Sj`!m$*?-8I zGWWsl_u|X%SgnBnG4!Qm%0!Sis(EeezAMWoQv%v1lV895oCD77X>WoYYoQ+Vj>2Uz z!%vH7tj!s>hj>R;2HF|T>0#A-iBy+d7}HP{P5vWVoE2 zeziShO&JV9N}#E+$*m7%2}2J|L0YB}5T#QA)1c1q|Kj}ESFcH*$UMKemV?lg-S_D2 zKUWMwx(<&?Z*zD?XJpXq?ROE3n-paAGXU0znT%IA?X^{FxA43h1x^?kIjM0GufVtT z@br$Hx~*b}Yx^dzW||GV0WCm)bT$B5W$7XN3>!GTlbW(QGP|={{dS+pSasjzcBpRC zSJ}YA>l=q5b;~EI#bi(^mz|_P2>D|MLbYy?P2F*~HgJ%pe+X=Njy$zUMbm(UrN
    (FmGh!JcEg45ga<>G|v^^8q}VQH5|;I>gn&n7lUxu}bo ztoXYwy6XC_y#k&Q|7C{BO^c6u{T6@8NO~KeM%EdMK2Parp<>_?`%Ot!glXB~M{1kc zy<(*jaBgug731b4xVqrYi|B7;>ga9IaRU{Vxd(zFonqmX#h3erD(YJwK)7#$oF4W@ z3r^9KGXcCe7c~&tar*-U+%9j5F%nazlfIThx8LIIuQBn7aTdk*;yz>0Wx02>>a%?^GP zh6M)(hJ=&#O_uf4#pnK^c{s_OJ+K*&+Mv`pVT!-Z@WgkzJW8Zf%4Gz^-~R*O7%*=q z{D75M$mj8a8Hi(Y?G?XQ7W@*D}$DZ5T8l@V_shy8(VujYjrFmS_XD@ zjcsgf{7%4hXvk5&hSqlW_V$+b8}^&CE(eqwY;VH19-dxX*T~Gy&fdbX)}*!ILqj?d zQoltX+t+~|OlQar9Yy0U7Obz#oelWm^DoObE7Aqm>=);%VI6E_(b&eiapT6ewzeZz zK;(BN{V1#$;m->z$Jp4JV4}_I)fq8w8_rZj0>KCGABW#!Vrge(ZHtR&Yuk9+HR2~E zHy2HZoB45{Ja1Y91!gvZDIq_0Ok-6s9l&g^5}ZUPr#DwXhfT)se1^63#a z^@eYQURGX{(nX)^Yx`jW%xoO2fdE_@=fe+REtx4wo6-k<+ga7e59k;*u(P$bv2nf> z38Pi{J=E-G?1ww?!^a|^RY^1Ld)(FP2x-EGc+NoG@Vb2OX(|YQ|>zkU5U%ICR zWRR?si}IF_@2+pu$lk`(yn*A{Cm#r9yY8yTId@ZHnO#KaIkOcRaR~T#1V> zzJkp%dGDt5ZEn)Y6mzVhWz(Z~!E#cV8v*J2#d+(edDgS2Z*SkYLBqx?4&I^F5_NV7 z6?I(u)|TeRb?VRGe2v%(igTkPHpYcx;Q?o+(bYrR%=b=d-JruXzLcmJr##R@XvEGS z2A(NjYmB5@$c_&i-J^|xp`oR%t-ZY+W}43~=zbm_UQ*xG*tW5qMI&RICY>*Y!7f79 z!CV$(f=9e!uzh3CWn!4%V40R1dr1YMS+Hs>+BDYP%H9+g-`u3G&z1|2K#6R!U0d!u zua3Cw+uB;x#Vo2>&m6wD>9udmf?CG*&vO_omAJ8UVII10fVFC!&ajIAtofi1oPXnVU9Df^b11*aEx#CO`y`h(;T z&$3#*AhD$ZzN2#S1^BwLwiF>C;`BUx!?5F2_yHS~XeIEs`3%voZRucVWmea0U%(4^ z9!9C~mW+s#cvyn!w*3G`DqCk%3GANagkX{whD_is2?Z${YNu=5ZyBZi_MTDrf$=;3 z#8!}i3#L%uZn$DKa2e!6J=NIy&KuAen6@i0iIIpj_1{Vg+zvNv`+kF0mog3htQ-h> zc)~7F=9Fply(LNap<7e6j3k!5oMQfse+tq^D#q|A<9>u`Lgr>TE5ztK zlavw{`QYJ$M~@zbg-1Ml`UHP@`0!yuDvX>&B}H#uzQ8}@-b)`Y!-`&hS_;1P`W=~_ zkXA+_eqvm7baYHEIk2mu8YdFO{r)v7GAgGSa*#X>fB6MjvC&aaABW(#P^w-efbXBe zHBka`onM&n>M4HsRXmJP$>VT6FC#fBD)MnKtjhS_O}QIQcL@M=mx$fqnajuMu{Mi7F6 zL&75?pFW|Fgrwy{E0xQPy~HcXh>DENDk3dSas&St6lK499u@YajA_wt$4@t!75QLGgMHbj_feQTZ$FWV3))ZRe2K)8#)^9Irwn?=pwisvjpR4cuSs3d zjOoRsH&F?nb7V!G9~To9`$4g&Qpyk zx6h-aUyvi3By~^zaPu?pjo5b|sj0#~PCmaTgChQt4SJ@Of$&GfO?ds{W!!tRNF%vU z9?1Qggp(wG0dGYar6J3cleRG4aXN@S#uBKj|rNaBiQ!fwqw_4L-%Zf;gNe z_ATkwWM11F z?9P7>sJH3g!{1H+-vNkYTvnlyYvnG$uu1;nzX|FG%0evT6QOYFhV6sTR0$V((|!S5)& z$lj?uM=?a4hy7C|f?8SEi}NCv%OHT0W@OUJ0D8*u?*odcTT1ymP-OXw(vT}n+1m-b zC_90wa(5L1X9f?;Wkv4Dpkk_|AtnY5Ng^s6!-)xXKa!7#O;HBOjxbH036*9mdB0+L zqVG~RJ@5-4;R&B@Ams>#VpWjM6B4%%BNHU5qJTWX#&t}Y>O7j2q*qY znsoW}vJjHJnrwbV;gnKBH7BT{UlcHimQ*$;La~6VXm~q$KuQvn3n$!BR65Fpvi2_p zDroZ8Sus{{Maw0=q-p%PzumrbIW0C}bnurw>;fMS}VD};(B zeW84QzwyrjOqpG~cjf06N~)%ObxI(2 zU9RGP1oCNRFO+p=Ra1Yz3Z?I*@0NaZ`CC6gRk_{^05u@}`)5#=p`5h)<*z7)Gy&v-Y;XM|74SDv?p17WA#<(jC`%{Lvr5Y(BZQ@? zq#pQzT2nMFNAWYFF85GrGI?88ScQ_xqGG01l9&9lT`6Un@b(0bsX zLDYYuOf9^L3^}-W?Uw!EgGo>97Zdpv7p8ApInmkG*~PirtaXRsI8ibY&dvU?bmAyy zXO~|6$A>4w!s^e7J55!P^mNXkF3!%*E!qq|d+#N@m*%Ei!^(rIkL;8uGY9o*;q2_> z)YNzV@nRly?f80LLSUyR7)}`Y!^Op|UHfhUFUcts<>gcf$dpX^i!Ao_o$dgdIPX5lsfiq}F~o-{SP7fa_-$`Yex!!|{|+R*9&? zLhA~!}tdeVc_ z!`z$U{Cf189vYucL=2e4&;7h&nzxg)i+dN(J1>$LQkL>rNI(spS0SfIb?V^a?CjQ} zlmB_L=?2OVugUxJa_Ue|d~4_!pM(sEuJCg-D+DD>^zG%qR!&%{IXgMSr?YF@_HB;_ z!S=ep(`H3v8(L<>@tWF3LCHXQB~||85DU5MCiR)V<9el|tp5Ojcwmm+KeeL;X0%iD zt;g>{H~7n$@*7IPnlktk999|b&Pg5AYC8E}x^aBnglZZZd+xqv;M`jA&As!Qx-@Uo z+OZl!EhobHk8nhu7{pgpoZ{82zG0Jor*Gc6amjz){N?W;XrzeYruKKMZPaRPz^z-W zyqaqn+J%2E5mOyTKu1fJS2bxP-1Nw{b#&X0S$Z=dVD*HqNUg?I8beiL#C-pf7;y9E zjT<+fhQBC)GawZA8`Ri;b^rLdC7W&p1RUG8QXQdQK8MJ|;=F|WU0n%WoLyX8U2RMd zQaSrv@g6Hmd1gxdqlZDa0s`=>??=bchiDIxmh|f3gZlviKviI540K77RLVha3-ZH) zgA>1g7lUgd(TAeqZL|BiHgDCei77&8_7T|PuIOwM7G!&(`01(jLkCYk9}sZy#Cl^5 z6hfRGw~5+S zuFgvPlJ~KZIG=!kfY`UmQ2wHt>S3@mFZsF7D z84T}j1AGbbaDz#7P#mtn~4<7`v6@7ywyc3jDQpU8T*HOTSm?k2|ZpxD*#@f{6YGp1Ps9f$slZ`}%* z-r2Nf++!+@gskRv_zc!lw5M4#unuw8+9mz3h7}g772C zqLBV9xGC}AT|T{oUJD;MvLPw?BXy+x&jcM+2JN1qu32l1|BZk{>y5P3r)<9qxBiB` z_#0J+WL72{rcA!QJgb4w{!rqV&MxX;Bp=#!D=y4xRaUV-H-7Y~*{GUTGJ7qj zZEdyL$0G4JJ~pTX8Ed8uHM44L>jLvacJ)m<4ch|ekSGd{Esu?ZT~sUw0-18194?xh zryrb~uZU)9Nt|0U5UU0|S63$|r-o*AEt_?@^dy-+uzOk?YzaBxTh7k4jB49=9`QPZ z2gaOovS>Wvw>MztdF!bV{X|Tzi1-D!Zk)Rl8q3QHw^FS(=R_r^{SwH$CV1aOglgRR zz{V$9Gt?X*O>D0@IW-}lPVM@SC$kB1nv@!!yw4rXkgA?BHuCK4Z1oK44E5PpBI)Gv zGovT=Zewcg0E0efdkdom)5$5cB%D=wQ2jZln?6#}#o84Q7@b{!dtHXl!aYpZ(>)wi zJ&4@^#EfpD-+L)JsYp>3FcNZeK8B3!)U=_EBW86|CtFj)2Fp*!h|>dg5Ylg8jf-b* zWmea;;mq}?OIWkuS3)|s?8qY=gjW9vCj$utw4W`Q)WQHE^&4-%HkG%DWg&C-uT8k~ zs}qt&ZG*3UutBO*#|4nY%DQ10sed^++n9mvEhkR63ZKKE*Dv0>aFgqu;L`ap0 zx>GG9Lx-*-e$0Fg3fjI|Z zdiHb3J{^s^f5nsSqoRVjp4O1|r5LfawVRk+yFQ%0EKZm!aA8GF*#{q2*mC3N#m0lXqBu8Xxsy;j2`KCx;! zEk5q~8>L&~sVOtJi=l0grRDEoxkwE$=Aiyd;e6YYx{_L&Q?xMtPQ%b=WtXyx`bNeazO|mADD?$>OF)oR2Z4P>*;oy z2gfE=1=N%|x3r74iF?^jZV3eGFWWU#Gw(R|$jeAu-wziKnZ@h7mK&S`3RVLyuQgxuR-Sz#C+K| zuAR17{~SihD=OmgMOT*%Lz+$KfyEW9B$OF++_%;oG<@q{@SXp~-K1Kxv3v0Ck|Nk{ zys}RtJ^O*=?1!H>G8BR6Gy%Ax^3%f|>KGnqb|4E=S^Xk$v4${9FUqBWcgvE(>3^{1=SvXEz zQ7ib3UkqZ(?An!;17^XZzUG=vgA2jJ1l5@rb6Jane9yy+;vAvO98iPqlf<*F? z?-^H9-+1Ne@eOm_+?tP=p-bG(86~ytJFsWUOb~~=dFk~q9`pPCL9p&^lpKwyMSZ?0pQ95-9g4`D}VB92zT8*p+7+%uY^ z*(jdPPLfXMmqM_jKE0EnuFJ4|SYX15atAcjYdPtF%ySjwMHatACFx80yK>a)c}*Jc z*1GTQxE!jquB{k=P{U}}U}mj`H*w(+qB-{#q@0q1tk%7${uw{PTB!>j_7`Gi0+qD`4;mPEK0aqQc1}A1RqfZ;x zvfOqytfYe zsOOTi%s()2`VD!=m@+;+>+84;2jxagnW8s0wGe0F>1c+u1R}3x;UtATXpx!E&ze-z zuyJlXf5qkt7tVLJs-4HL z$!`!+b%>z{#VIK2&w~aO{PO6eHmbJh7zw&Wsz;RfwwbBX!LU4W&Laba{4T$S&byL| z!`3F`c5lrD#Id**n*o*$6g9J7eLaW1bAy6{0`CQ4o<+yQp{~jlJUc7n+f`lP{%l~- z{riyQe&B--*|-hncC}Qq9kG!xk!2cGnnFHHfenTrXUgoE(n{0R?PgHWoeRfC4sh=| za#3m_tUD+mjfzvr$Cf6j9f<}dAo?Nt)Iw|=UyB7r6u5URr&`?u*Mopyg7<0cVQ4a0 z$wEMC|IwBi*u1z9^@Rb;24Bb-YH488eR?U=BHzH0oFYLdphR=OE*{d>-p&z=U~Q*C zVeg3JKbENU=#~vt8+Dq1^EtN7x2d(hrk+FaC(`&8XGpvG!qsCs+S@hO(a@Z=^)!uh zF8cJit_ElPuKNr%WfpLfqt5f=)S$WRJ*3$k;t6l*C%ULuXj8=M+}3^pC){4 zyZXzdKEgl8?Z+K$uCozpJ=34e%HSu(j}J~os@3l$l4k!S5=jRTPyA;hR5vt}5oEuc z*{>-=)wW*&!j|+l(sk;a2W_7QQ~fb~|NN>;W9>RFqsf{k@wtPX(z{#gOxi=D)G8mo z$eS_(%sD2rZ*6TS&kgwZftj5+)pYC}9qr9bRMoVXT(}P+u1p`(^=9rTcRREFkKvTk zoTvM>RQ1k2CnuJ|2GSokWoQ$6c4N5?s&nE-G6S4vw;F93+eA&XhP{JBV>>&C#*G_0 zcDer!WI#dHu)Z>>Jsov*YSn|%80u(QxBl}jEFm$1%r2&=<;3lvfD}c0mIpOu7JHgj z(=l*xu*U@0V*=dzKKlft-GsY45K=$!GLI?ATsNr~LTD}ts3gB#iyaLXCc4!^Jr|#Z zf=MR2sgWaX%9NCVcfhrk!#OH;FQntp{0fN3>oVi7G*Hu;w+taEVMn>)Cz@rtqDNqyS(S`ZisQv{Kw_MWoqz|*It*u|z!5)BlHfD82V?LVCg;jkx zYFgIzj*T1JIoRPuuE#^u7$&2I5$ZJOAao8tvO1v5l-WPKvx`9cEihJuEYq^bIMmguS*Mg~!+l{|OQH9hq@NaT9obC7vUfhN)40F7SXbv% zw|W?#OAWJcsi715xHq=7oxSo)F4y6pZd3LO!ITLx(nMa{ zAdUo`l{xF{f%I+Sh|MP73abdRDZZR&!`WB3q9(UB_LvK0r-D&-o1PS)fPQjEc34Qg zWQyJgnCLgS^B&x^%V`Xj0O?BsYj)|zd+ceA=w zm_5L;rm6dUeB=D$o=D3QcYOFka4sMc20~Uo9~p?DqY-dRfSQ=I^RQub=N$};cw}t- z$bXW0O{ceoU_Deos>}itS41LJ3mN{$rZv^NkqEbRfr)r*@?!7$*HuC8-rHeou_E%= zs2}&XsUl?S)~*dk3rF0M_gQ!xwlU#yvyri%KxFKrq4a$Unx6!;fBh78TwfJ!y8_)g z)|k-FNXvu;re@_9n3OC=K@@HtkB8-kOcIvN@@UA> zHR{k7S7%#u{r}hAnFrLE^$+~CF`~i960at8yDcgdQdwdQAz_kb4B3WvUdx2+%ls^3 z&8R_xNy#LJ#*D_2ZA7^x%T$;oO8rPuB<**3e&>76b8mO8Ec5=}m-G3f?sK;1Jm;L} zobPka_ndDdERLVcDJQj{{r0rhvM%g2(bwN~3an~WRg(=&5S%P9&5ckAulq5S7nn43 zWh(r8nVPsvg)y~ZwFby!HPv7;I-cmtq=1!DX=OFsCFINQO&x}jwbZJ#xF6agG+I)6nrd; zQzHuw3L*>Yh;Q*=L5t~uY9bJ7Dis9LS9XNf}jZ+x0Wd666GfaG0VIgSqyy! zH?N}}U?ju+XJr+{4gJamb?Eg7CoIl$YikG@16`RaoTKl)=-kZ48-~KSsw+ds(YvQN z8X2}bpIZeZx{k+h2z0AQ&=ikelgL8V-#$od6S4lopoQ?~!6itq)ycbM_%(u4NgpM4 zG(_`t8Lnr%ZB%wJJ-!ldi1hZ|;MD;4&i2&nFsM)huedzCcuc33y=R5VFL5=#81LA^ z@$>ckW%*5WBlL9`%o&{6Fb)~pX7l}#WQ=`thw+;^cu$Fwv?k|HT3XsI6>A+@p!Y5r z)k)9M7p6KWO9z>C>>q%C6y1n6L1@T)r7XQ7XSYs3$oR~CkTGB%LPd_tM+RPWhar({ zbfHlD)$h=s8nD6KJH8617Ih7DcS2^mnm7!ln@=!@7WPHPmiM%);nR^%vcTKcecYl0 zKkeTe78bexz_JM*2CaK$lZ6~UU}c(>zQLlO`SmrO5Ft!fde^;!k>BPM%06_sS~t$h z%*FpD4Er$ZOLg_`97&1;QKp}TzRyZtR|YfeW7KKH3j8A}Yz`K=mK}tbwjuCpzn_{~ z51bFTCSr$_H*d=Y4lrxeWr`wj@r+2&PUI8M@kS_>~ z?29fR+4!!b9nFQ%DF()Z>qJzdd9G_bBZVe=amUrnaBNVVss{&ZzZNasW~%7Q=z>n> zi3<`tAT)IcoOeJdaW_Sy*MKOaBI!x~w?|7fa#aktYpqRfeB)z|I`*e(+@Ukv8e4eD z?Rh`x(F%F5IKsWj$S0HJ-o>42`ZI-wtc<=kCB8OI?fuq*qta$8`r}D1bj113_@j6f zKGLevjP$g$zp^Uj*`ZQq(;8vCv!&QZOnK;U$Vxo6PW~#(bu3H$Q z*n&%oAo{VN79KOmNqps*l;wR)RZ*u z?)AjWq9jqAtBIcF;JG4^C@~=+>mdk08K;8ukX}H@q2we{z{t+6Y`yQ6!l#?0?EXMI z6AQ0-Ny*9I&l+gh?BfgfUP9}qA8O^f{n~-rZ}e42qz<)TI;$M_{Vb$sICt~jq~xT~ zRsS?GYO(8FCTVbzxJ^s&*REZE->BGAmqntpzaChzZZ+77*Y@>AKj1F?9J(Pa3O`V6 z#JZ1+kca;U{H2V)>9NM#C2V zNMFI==`N^^QyeL*6Ne%kS|VGoz;amfRZo|G4!+2UZQY{v@tj&uSzcT-gyw}`!5P1K z^%71=bn=Jh2#s8_3;(=yN%Z7}((9)LEwu0jo(Q#yI(sD%bNRC9N@{5}3=G(7)rfW` zc4LXf+4}a8^13qlZtYPwza{WAmoNXgArP1OyxkYz)t0^po;(sE1FuPQPQ+itrTR-m z@Vd}&(wnM3DJK_Y{^jvOdym=ROLm)c@Nomxm3AzsF+zTUTa%KKqC-}BULO?odu8?oBZMYzjK+CB6!yKRRWlR2A-9XA z^~|=t3Ut)@^AK2>UixF4C^0c1F;OJC@~{{V4cj)Ym(XXqa`+unU6HXf*%hZH3*?hm zwtZ#~q}Sm{dOj`d)w5m$gC?kBqkg`7;fJJ*$-O;+R7SD9Uy(btm45ChvpqWnR7WgIW%C1QIig5 zGfU}q#d9I!5Hh>Q&z`A8R);qA9|QX0EJdG_H}#Y>XzCF6*$A@_I(<4@xzN&;EMlrc z@++(UcDyTU(kA4m6G=&;MWcH+HSM052ZL61(fw_!mmZ5xNctmotb51iF21=hKucIx zCP|Z(90*yn>*z_`p7*Tr*F$LTj#JoOj0@mlvYn}s`;<+|$w@0dv;W}ZUbmltE?u31 zn-1u(FL~+>r^cW?mw3zAyou@LaO}A9$Sqvz%4f;YpG$|g!M?Niz>WlEBhN4IoB%7= zO&!vC^&LKLkiT26iCZ{$VQbq7zuNoqzB`!NHawE5X&HL~_GmNUU!+^0uRQG?#4~#1 zz65=9glaNqea&m3Z`}5oU2&9At6}n+y3jmxPp;eHcOIFZgHKaF15}0XEZN~N^jihN zR4rqV?hJ+Y{n>0zo&h>Xo_%&3cGt5XQACoV)k4!;?Prd?z9ehk#4-%Tiv8B#plOHD zn9E5=cbhje`22s4LQ-#M3JDk}5D08- zZ0te10sj}`%a!|~_2U+i9J_mvr@c^UJ!HbNtU@Y8Kr1bMm_Bo~k5FjSxBsZK=|n|Q z3acg17OD#7jC68x>T{OtsjgFQ#o@89uO9$pPsfjDVtvIYqlRLA@72i>^J#k-E^mJKI9Aw zxh-fN(2_a3YlWjjXB#_wYX{H4etUjS6q8XIdmY*Ol|yHHI~yB;z}nW z?yl=YkHd&89}q+*4vzO3D6kgT2!(^Ze0Lue$>dShpl+L{dkmev1>!1YfSf1CrN{3X zJiry#j-%(GUB6>7PTuEehwowHW5P#y^%GcI;~WkdHa0pwQ=FeN$kBmhSm@NX&w^Fk zvx~Hs|7%0L(b#R%9i5yUJKMtDp`g1)CKYg8(b$1Kf{xw7-6HIVudWh{C67h>9PDfl z-+;kELwu(_d(G;p9;DWAt09%#)AwdE?G1|-`*_0JCxo}phBSfkD`D5V)_H!~)K3Oa zbN2j#Y_d@vap^Bv!ms;B5ABa@4JYa~bWHehIIBss)@aY3CyML>8M3pnvvYLpOf%4R z_>2mU`!(oGMN_x46;7YGA-5R5M|Bl74A^+!%fJ1vF(dI?*t_3|Q>mcfA|{^`DTkIj zx(vx6v%~6zqyZ^3>4us8RGPYr&kb@IF~>b$>HCRVq4_QjC+yqR4L?ocbme zKqV@tPwRQl5+B?V2gkzv9G$YI4WJ?~X_$+X(;)x*bb~nQWhx$=wrFFisU^dAwiS=Q z8jch5ypRQwA8l|_A~$55*@-=T0=|O_{tJi3k!+a-N34fmxCa*+ZBGqaZodRg#Zi_= z{Go8+8}0MVFZw$yDhu6Q2`pfn2MWZI(qyup5`Fwukj4~=o)DP7^m#3yW4@qY^^z}~yMsdJh96;pPWyD6a_OYW+Eue#8ZwRas2QHH@_Fc=IC6rWWLU8qe~DF#$t zm4`=NUeSe`;9D>Bi%tC2_B8xA!9*DbgTY`l3~h4}42oRTE4`JTmY$wnN~{_abwcu^ zqWD%?+RfWw=@y)c+w;Qw93`@{?&cNHlN0#Fs!CzwRYoRkg`%l7gz}Q&^2&zps(UwJ zq6~wSSrw!qlnn*sHl^ zWIa)`$jb(HPbpzNJOC#|PfkC!bGfy32TLn~RYzODh1+4zLLD1UrQ-Yt8KY zZ0B+2Ht4F?xu52pf{8K=27|$1ygo9rWc2i}W9=KGajT->$ZBz+=;Ebdj&?2SmM<9V+PkRK4(1 zOH&WEBh*32sLngn5}~cS}TQSJWZ3;DCrLqQ8csbOXruYVm~%S4&?<*^wI27|$PbLg?rg{gg+$-=^>xBzjO4IUvaiW3p8jEm?gdzy#yhX(+?n6PD-r61hsdYRSE;HgqnQX zHPg+^eY%7sMJ-09A6|y^(2h$_=`CJd+lLU^dWIPHAWV7vTGB|VTEFTWh!*0yI#BgkIAlWBBT%_5j9V|%p3KZ1{<9)=eJEp z`X65_0wc*F{&3u>{Tl)o%s-t9YBy@?z(p6g8yT6Wz@*H31QTT#3?dxf%S|*juw=+_cTex=*sMu^-wBf^j%nMx!|MGaxRHcxiQ>3v-QhgFr3b(?cMVyS zDt&O}>nW4`{iphPz_EM%KAY%|FBYtQ1gG4*`(ry3Wf%+wgTZ(s=;$dce-sh=O<-W) zzSuv(mDmv_{>8r?{9$2W;Ig2Q%pzD@l9DMH$;+JW>o=aco-5;LV-%@@Z&B{`jcakF zHRn?cAPNZpAvrGL_nkd0K3u#%g#%FrWT3K#scRPFJ1<(YeAUK{>z6HFgfAAa-(Em= zg}?J-I}>FX3u{2#)>SFvVUEUf?l002ovPDHLkV1mz) BQM>>E literal 0 HcmV?d00001 diff --git a/docs/zk_kerberos/img_3.png b/docs/zk_kerberos/img_3.png new file mode 100644 index 0000000000000000000000000000000000000000..f15ed55e2483302b66b40b22fb12aff91f402f5b GIT binary patch literal 312993 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�M$g8*r|zOMiHNl*NRkuUuaF+nE*? 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 ^8?SLm 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 BQM>>E literal 0 HcmV?d00001 diff --git a/docs/zk_kerberos/zk支持Kerberos配置文档.md b/docs/zk_kerberos/zk支持Kerberos配置文档.md new file mode 100644 index 00000000..9856ee09 --- /dev/null +++ b/docs/zk_kerberos/zk支持Kerberos配置文档.md @@ -0,0 +1,32 @@ +1、需要修改代码: +位置:src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java +将createZKClient的135行的false改为true +![img.png](img.png) +修改完之后就可以打包编译:打包编译见:参考2.3 后端单独打包 +https://github.com/didi/KnowStreaming/blob/master/docs/install_guide/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85%E6%89%8B%E5%86%8C.md +2、查看kafka的ZK的Acl +首先查看kafka的server.properties的配置的zookeeper.connect的连接,然后使用:zkCli.sh -serve xxxx登录到zk的页面,然后执行命令getAcl /kafka +![img_1.png](img_1.png) +此时就可以看到kafka在zk中的用户的权限,因为我们的集群在server.properties 配置了super.users=User:kafka ,以及zookeeper.set.acl=true ,默认的kafka的权限就是cdrwa。如果没有用户有cdrwa权限的话,需要zk创建用户并授权,授权命令:setAcl +3、在Kerberos的域中创建 kafka/_HOST的keytab,并导出。例如:kafka/dbs-kafka-test-8-53 +4、导出keytab后上传到安装KS的机器的/etc/keytab下。执行 kinit -kt zookeepe.keytab kafka/dbs-kafka-test-8-53 看是否能进行Kerberos登录 +5、可以登录后,配置/opt/zookeeper.jass文件: +Client { +com.sun.security.auth.module.Krb5LoginModule required +useKeyTab=true +storeKey=false +serviceName="zookeeper" +keyTab="/etc/keytab/zookeeper.keytab" +principal="kafka/dbs-kafka-test-8-53@XXX.XXX.XXX"; +}; +6、需要配置KDC-Server对KS的机器开通防火墙,并在KS的机器/etc/host/ 配置 kdc-server的hostname。并将 krb5.conf 导入到/etc下 +7、在/usr/local/KnowStreaming/KnowStreaming/bin/startup.sh中的47行的JAVA_OPT中追加如下设置: +-Dsun.security.krb5.debug=true -Djava.security.krb5.conf=/etc/krb5.conf -Djava.security.auth.login.config=/opt/zookeeper.jaas +8、重启KS集群后再start.out中看到如下信息,证明Kerberos配置成功 +![img_3.png](img_3.png) +![img_2.png](img_2.png) + +9、对于多集群来说如果用的是一样的Kerberos域的话,只需在每个zk中给kafka用户配置crdwa权限即可,这样集群初始化的时候zkclient是都可以认证。 +10、未改进: + 1、需要页面ZK的Kerberos配置化 + 2、多个Kerberos域暂时未适配。 \ No newline at end of file From 590f684d6694092fa6a8ca2ea7b42c4bfd2b5738 Mon Sep 17 00:00:00 2001 From: luhe Date: Wed, 21 Sep 2022 15:59:31 +0800 Subject: [PATCH 003/145] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=94=AF=E6=8C=81ZK-Kerberos=E8=AE=A4=E8=AF=81=E4=B8=8E?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zk_kerberos/zk支持Kerberos配置文档.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/zk_kerberos/zk支持Kerberos配置文档.md b/docs/zk_kerberos/zk支持Kerberos配置文档.md index 9856ee09..0983afd2 100644 --- a/docs/zk_kerberos/zk支持Kerberos配置文档.md +++ b/docs/zk_kerberos/zk支持Kerberos配置文档.md @@ -25,7 +25,6 @@ principal="kafka/dbs-kafka-test-8-53@XXX.XXX.XXX"; 8、重启KS集群后再start.out中看到如下信息,证明Kerberos配置成功 ![img_3.png](img_3.png) ![img_2.png](img_2.png) - 9、对于多集群来说如果用的是一样的Kerberos域的话,只需在每个zk中给kafka用户配置crdwa权限即可,这样集群初始化的时候zkclient是都可以认证。 10、未改进: 1、需要页面ZK的Kerberos配置化 From e5802c7f5091ae4edbd04eb1262bd57159f66971 Mon Sep 17 00:00:00 2001 From: luhe Date: Wed, 21 Sep 2022 16:02:38 +0800 Subject: [PATCH 004/145] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=94=AF=E6=8C=81ZK-Kerberos=E8=AE=A4=E8=AF=81=E4=B8=8E?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zk_kerberos/zk支持Kerberos配置文档.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/zk_kerberos/zk支持Kerberos配置文档.md b/docs/zk_kerberos/zk支持Kerberos配置文档.md index 0983afd2..8ba235fa 100644 --- a/docs/zk_kerberos/zk支持Kerberos配置文档.md +++ b/docs/zk_kerberos/zk支持Kerberos配置文档.md @@ -4,12 +4,16 @@ ![img.png](img.png) 修改完之后就可以打包编译:打包编译见:参考2.3 后端单独打包 https://github.com/didi/KnowStreaming/blob/master/docs/install_guide/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85%E6%89%8B%E5%86%8C.md + 2、查看kafka的ZK的Acl 首先查看kafka的server.properties的配置的zookeeper.connect的连接,然后使用:zkCli.sh -serve xxxx登录到zk的页面,然后执行命令getAcl /kafka ![img_1.png](img_1.png) 此时就可以看到kafka在zk中的用户的权限,因为我们的集群在server.properties 配置了super.users=User:kafka ,以及zookeeper.set.acl=true ,默认的kafka的权限就是cdrwa。如果没有用户有cdrwa权限的话,需要zk创建用户并授权,授权命令:setAcl + 3、在Kerberos的域中创建 kafka/_HOST的keytab,并导出。例如:kafka/dbs-kafka-test-8-53 + 4、导出keytab后上传到安装KS的机器的/etc/keytab下。执行 kinit -kt zookeepe.keytab kafka/dbs-kafka-test-8-53 看是否能进行Kerberos登录 + 5、可以登录后,配置/opt/zookeeper.jass文件: Client { com.sun.security.auth.module.Krb5LoginModule required @@ -19,13 +23,18 @@ serviceName="zookeeper" keyTab="/etc/keytab/zookeeper.keytab" principal="kafka/dbs-kafka-test-8-53@XXX.XXX.XXX"; }; + 6、需要配置KDC-Server对KS的机器开通防火墙,并在KS的机器/etc/host/ 配置 kdc-server的hostname。并将 krb5.conf 导入到/etc下 + 7、在/usr/local/KnowStreaming/KnowStreaming/bin/startup.sh中的47行的JAVA_OPT中追加如下设置: -Dsun.security.krb5.debug=true -Djava.security.krb5.conf=/etc/krb5.conf -Djava.security.auth.login.config=/opt/zookeeper.jaas + 8、重启KS集群后再start.out中看到如下信息,证明Kerberos配置成功 ![img_3.png](img_3.png) ![img_2.png](img_2.png) + 9、对于多集群来说如果用的是一样的Kerberos域的话,只需在每个zk中给kafka用户配置crdwa权限即可,这样集群初始化的时候zkclient是都可以认证。 + 10、未改进: 1、需要页面ZK的Kerberos配置化 2、多个Kerberos域暂时未适配。 \ No newline at end of file From c8806dbb4d831a1b6eb9e33edc654e89dfb95c83 Mon Sep 17 00:00:00 2001 From: luhe Date: Wed, 21 Sep 2022 16:09:04 +0800 Subject: [PATCH 005/145] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=94=AF=E6=8C=81ZK-Kerberos=E8=AE=A4=E8=AF=81=E4=B8=8E?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zk_kerberos/zk支持Kerberos配置文档.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/zk_kerberos/zk支持Kerberos配置文档.md b/docs/zk_kerberos/zk支持Kerberos配置文档.md index 8ba235fa..ad70861c 100644 --- a/docs/zk_kerberos/zk支持Kerberos配置文档.md +++ b/docs/zk_kerberos/zk支持Kerberos配置文档.md @@ -16,12 +16,19 @@ https://github.com/didi/KnowStreaming/blob/master/docs/install_guide/%E6%BA%90%E 5、可以登录后,配置/opt/zookeeper.jass文件: Client { + com.sun.security.auth.module.Krb5LoginModule required + useKeyTab=true + storeKey=false + serviceName="zookeeper" + keyTab="/etc/keytab/zookeeper.keytab" + principal="kafka/dbs-kafka-test-8-53@XXX.XXX.XXX"; + }; 6、需要配置KDC-Server对KS的机器开通防火墙,并在KS的机器/etc/host/ 配置 kdc-server的hostname。并将 krb5.conf 导入到/etc下 From 7b5c2d800fb2945385e42f8d675f7db9d4f90e2c Mon Sep 17 00:00:00 2001 From: zengqiao Date: Thu, 29 Sep 2022 15:13:41 +0800 Subject: [PATCH 006/145] bump version to 3.1.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a810fa4..a168b74c 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ - 3.0.0 + 3.1.0 8 8 From 7ca3d65c421df0f66afc1b7203ec78017c230851 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Sat, 8 Oct 2022 14:15:20 +0800 Subject: [PATCH 007/145] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E6=95=88?= =?UTF-8?q?=E7=9A=84=E5=81=A5=E5=BA=B7=E5=88=86=E8=AE=A1=E7=AE=97=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/enums/health/HealthStateEnum.java | 31 +++++++++++ .../impl/ClusterMetricServiceImpl.java | 6 +-- .../health/score/HealthScoreService.java | 25 ++------- .../score/impl/HealthScoreServiceImpl.java | 54 ------------------- .../metrics/ClusterMetricVersionItems.java | 21 ++++++-- 5 files changed, 55 insertions(+), 82 deletions(-) create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/health/HealthStateEnum.java diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/health/HealthStateEnum.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/health/HealthStateEnum.java new file mode 100644 index 00000000..a9490fb6 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/health/HealthStateEnum.java @@ -0,0 +1,31 @@ +package com.xiaojukeji.know.streaming.km.common.enums.health; + +import lombok.Getter; + + +/** + * 健康状态 + */ +@Getter +public enum HealthStateEnum { + UNKNOWN(-1, "未知"), + + GOOD(0, "好"), + + MEDIUM(1, "中"), + + POOR(2, "差"), + + DEAD(3, "宕机"), + + ; + + private final int dimension; + + private final String message; + + HealthStateEnum(int dimension, String message) { + this.dimension = dimension; + this.message = message; + } +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java index 9fdd9ec0..3d004f78 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java @@ -85,7 +85,7 @@ public class ClusterMetricServiceImpl extends BaseMetricService implements Clust public static final String CLUSTER_METHOD_GET_TOTAL_LOG_SIZE = "getTotalLogSize"; public static final String CLUSTER_METHOD_GET_PARTITION_SIZE = "getPartitionSize"; public static final String CLUSTER_METHOD_GET_PARTITION_NO_LEADER_SIZE = "getPartitionNoLeaderSize"; - public static final String CLUSTER_METHOD_GET_HEALTH_SCORE = "getTopicHealthScore"; + public static final String CLUSTER_METHOD_GET_HEALTH_SCORE = "getClusterHealthScore"; public static final String CLUSTER_METHOD_GET_METRIC_FROM_KAFKA_BY_TOTAL_BROKERS_JMX = "getMetricFromKafkaByTotalBrokersJMX"; public static final String CLUSTER_METHOD_GET_METRIC_FROM_KAFKA_BY_CONTROLLER_JMX = "getMetricFromKafkaByControllerJMX"; public static final String CLUSTER_METHOD_GET_ZK_COUNT = "getZKCount"; @@ -188,7 +188,7 @@ public class ClusterMetricServiceImpl extends BaseMetricService implements Clust registerVCHandler( CLUSTER_METHOD_GET_PARTITION_SIZE, this::getPartitionSize); registerVCHandler( CLUSTER_METHOD_GET_PARTITION_NO_LEADER_SIZE, this::getPartitionNoLeaderSize); - registerVCHandler( CLUSTER_METHOD_GET_HEALTH_SCORE, this::getTopicHealthScore); + registerVCHandler( CLUSTER_METHOD_GET_HEALTH_SCORE, this::getClusterHealthScore); registerVCHandler( CLUSTER_METHOD_GET_METRIC_FROM_KAFKA_BY_TOTAL_BROKERS_JMX, this::getMetricFromKafkaByTotalBrokersJMX); registerVCHandler( CLUSTER_METHOD_GET_METRIC_FROM_KAFKA_BY_CONTROLLER_JMX, this::getMetricFromKafkaByControllerJMX); @@ -364,7 +364,7 @@ public class ClusterMetricServiceImpl extends BaseMetricService implements Clust /** * 获取集群的健康分 */ - private Result getTopicHealthScore(VersionItemParam metricParam){ + private Result getClusterHealthScore(VersionItemParam metricParam){ ClusterMetricParam param = (ClusterMetricParam)metricParam; ClusterMetrics clusterMetrics = healthScoreService.calClusterHealthScore(param.getClusterId()); return Result.buildSuc(clusterMetrics); diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/HealthScoreService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/HealthScoreService.java index 5997edec..48f8933b 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/HealthScoreService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/HealthScoreService.java @@ -15,35 +15,16 @@ public interface HealthScoreService { * @param clusterPhyId 集群ID * @return */ + @Deprecated ClusterMetrics calClusterHealthScore(Long clusterPhyId); - /** - * 获取集群Topics健康分指标 - * @param clusterPhyId 集群ID - * @return - */ - ClusterMetrics calClusterTopicsHealthScore(Long clusterPhyId); - - /** - * 获取集群Brokers健康分指标 - * @param clusterPhyId 集群ID - * @return - */ - ClusterMetrics calClusterBrokersHealthScore(Long clusterPhyId); - - /** - * 获取集群Groups健康分指标 - * @param clusterPhyId 集群ID - * @return - */ - ClusterMetrics calClusterGroupsHealthScore(Long clusterPhyId); - /** * 获取集群健康分指标 * @param clusterPhyId 集群ID * @param topicName Topic名称 * @return */ + @Deprecated TopicMetrics calTopicHealthScore(Long clusterPhyId, String topicName); /** @@ -52,6 +33,7 @@ public interface HealthScoreService { * @param brokerId brokerId * @return */ + @Deprecated BrokerMetrics calBrokerHealthScore(Long clusterPhyId, Integer brokerId); /** @@ -60,6 +42,7 @@ public interface HealthScoreService { * @param groupName group名称 * @return */ + @Deprecated GroupMetrics calGroupHealthScore(Long clusterPhyId, String groupName); /** diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/impl/HealthScoreServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/impl/HealthScoreServiceImpl.java index c443c3bb..6ba01bb9 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/impl/HealthScoreServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/impl/HealthScoreServiceImpl.java @@ -136,60 +136,6 @@ public class HealthScoreServiceImpl implements HealthScoreService { return metrics; } - @Override - public ClusterMetrics calClusterTopicsHealthScore(Long clusterPhyId) { - List healthScoreResultList = this.getDimensionHealthScoreResult(clusterPhyId, HealthCheckDimensionEnum.TOPIC); - - ClusterMetrics metrics = new ClusterMetrics(clusterPhyId); - if (ValidateUtils.isEmptyList(healthScoreResultList)) { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_TOPICS, Constant.MIN_HEALTH_SCORE); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_TOPICS, 0.0f); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_TOPICS, 0.0f); - } else { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_TOPICS, Math.max(this.getDimensionHealthScore(healthScoreResultList), Constant.MIN_HEALTH_SCORE)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_TOPICS, getHealthCheckPassed(healthScoreResultList)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_TOPICS, Float.valueOf(healthScoreResultList.size())); - } - - return metrics; - } - - @Override - public ClusterMetrics calClusterBrokersHealthScore(Long clusterPhyId) { - List healthScoreResultList = this.getDimensionHealthScoreResult(clusterPhyId, HealthCheckDimensionEnum.BROKER); - - ClusterMetrics metrics = new ClusterMetrics(clusterPhyId); - if (ValidateUtils.isEmptyList(healthScoreResultList)) { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_BROKERS, Constant.MIN_HEALTH_SCORE); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_BROKERS, 0.0f); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_BROKERS, 0.0f); - } else { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_BROKERS, Math.max(this.getDimensionHealthScore(healthScoreResultList), Constant.MIN_HEALTH_SCORE)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_BROKERS, getHealthCheckPassed(healthScoreResultList)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_BROKERS, Float.valueOf(healthScoreResultList.size())); - } - - return metrics; - } - - @Override - public ClusterMetrics calClusterGroupsHealthScore(Long clusterPhyId) { - List healthScoreResultList = this.getDimensionHealthScoreResult(clusterPhyId, HealthCheckDimensionEnum.GROUP); - - ClusterMetrics metrics = new ClusterMetrics(clusterPhyId); - if (ValidateUtils.isEmptyList(healthScoreResultList)) { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_GROUPS, Constant.MIN_HEALTH_SCORE); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_GROUPS, 0.0f); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_GROUPS, 0.0f); - } else { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_GROUPS, Math.max(this.getDimensionHealthScore(healthScoreResultList), Constant.MIN_HEALTH_SCORE)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_GROUPS, this.getHealthCheckPassed(healthScoreResultList)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_GROUPS, Float.valueOf(healthScoreResultList.size())); - } - - return metrics; - } - @Override public TopicMetrics calTopicHealthScore(Long clusterPhyId, String topicName) { List healthScoreResultList = this.getResHealthScoreResult(clusterPhyId, HealthCheckDimensionEnum.TOPIC.getDimension(), topicName); diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ClusterMetricVersionItems.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ClusterMetricVersionItems.java index 53b98479..00a5e0cd 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ClusterMetricVersionItems.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ClusterMetricVersionItems.java @@ -20,22 +20,35 @@ import static com.xiaojukeji.know.streaming.km.core.service.cluster.impl.Cluster @Component public class ClusterMetricVersionItems extends BaseMetricVersionMetric { + /** + * 健康分 + */ public static final String CLUSTER_METRIC_HEALTH_SCORE = "HealthScore"; + public static final String CLUSTER_METRIC_HEALTH_SCORE_TOPICS = "HealthScore_Topics"; + public static final String CLUSTER_METRIC_HEALTH_SCORE_BROKERS = "HealthScore_Brokers"; + public static final String CLUSTER_METRIC_HEALTH_SCORE_GROUPS = "HealthScore_Groups"; + public static final String CLUSTER_METRIC_HEALTH_SCORE_CLUSTER = "HealthScore_Cluster"; + + /** + * 健康巡检 + */ public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED = "HealthCheckPassed"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL = "HealthCheckTotal"; - public static final String CLUSTER_METRIC_HEALTH_SCORE_TOPICS = "HealthScore_Topics"; + public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED_TOPICS = "HealthCheckPassed_Topics"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL_TOPICS = "HealthCheckTotal_Topics"; - public static final String CLUSTER_METRIC_HEALTH_SCORE_BROKERS = "HealthScore_Brokers"; + public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED_BROKERS = "HealthCheckPassed_Brokers"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL_BROKERS = "HealthCheckTotal_Brokers"; - public static final String CLUSTER_METRIC_HEALTH_SCORE_GROUPS = "HealthScore_Groups"; + public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED_GROUPS = "HealthCheckPassed_Groups"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL_GROUPS = "HealthCheckTotal_Groups"; - public static final String CLUSTER_METRIC_HEALTH_SCORE_CLUSTER = "HealthScore_Cluster"; + public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED_CLUSTER = "HealthCheckPassed_Cluster"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL_CLUSTER = "HealthCheckTotal_Cluster"; + + public static final String CLUSTER_METRIC_TOTAL_REQ_QUEUE_SIZE = "TotalRequestQueueSize"; public static final String CLUSTER_METRIC_TOTAL_RES_QUEUE_SIZE = "TotalResponseQueueSize"; public static final String CLUSTER_METRIC_EVENT_QUEUE_SIZE = "EventQueueSize"; From 69a7212986b7f957d309aa5948849aa48afba8cc Mon Sep 17 00:00:00 2001 From: zengqiao Date: Sat, 8 Oct 2022 14:52:17 +0800 Subject: [PATCH 008/145] =?UTF-8?q?ZK-=E5=A2=9E=E5=8A=A0=E5=9B=9B=E5=AD=97?= =?UTF-8?q?=E5=91=BD=E4=BB=A4=E4=BF=A1=E6=81=AF=E7=9A=84=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bean/entity/result/ResultStatus.java | 1 + .../BaseFourLetterWordCmdData.java | 9 + .../fourletterword/ConfigCmdData.java | 38 ++++ .../fourletterword/MonitorCmdData.java | 39 +++++ .../fourletterword/ServerCmdData.java | 30 ++++ .../parser/ConfigCmdDataParser.java | 116 +++++++++++++ .../parser/FourLetterWordDataParser.java | 10 ++ .../parser/MonitorCmdDataParser.java | 117 +++++++++++++ .../parser/ServerCmdDataParser.java | 97 +++++++++++ .../utils/zookeeper/FourLetterWordUtil.java | 163 ++++++++++++++++++ .../utils/zookeeper/ZookeeperUtils.java | 59 +++++++ 11 files changed, 679 insertions(+) create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/BaseFourLetterWordCmdData.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ConfigCmdData.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ConfigCmdDataParser.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/FourLetterWordDataParser.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ServerCmdDataParser.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/FourLetterWordUtil.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/ZookeeperUtils.java diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/result/ResultStatus.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/result/ResultStatus.java index 842e1106..252146c9 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/result/ResultStatus.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/result/ResultStatus.java @@ -56,6 +56,7 @@ public enum ResultStatus { KAFKA_OPERATE_FAILED(8010, "Kafka操作失败"), MYSQL_OPERATE_FAILED(8020, "MySQL操作失败"), ZK_OPERATE_FAILED(8030, "ZK操作失败"), + ZK_FOUR_LETTER_CMD_FORBIDDEN(8031, "ZK四字命令被禁止"), ES_OPERATE_ERROR(8040, "ES操作失败"), HTTP_REQ_ERROR(8050, "第三方http请求异常"), diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/BaseFourLetterWordCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/BaseFourLetterWordCmdData.java new file mode 100644 index 00000000..3e5713a8 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/BaseFourLetterWordCmdData.java @@ -0,0 +1,9 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword; + +import java.io.Serializable; + +/** + * 四字命令结果数据的基础类 + */ +public class BaseFourLetterWordCmdData implements Serializable { +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ConfigCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ConfigCmdData.java new file mode 100644 index 00000000..d0982f47 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ConfigCmdData.java @@ -0,0 +1,38 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword; + +import lombok.Data; + + +/** + * clientPort=2183 + * dataDir=/data1/data/zkData2/version-2 + * dataLogDir=/data1/data/zkLog2/version-2 + * tickTime=2000 + * maxClientCnxns=60 + * minSessionTimeout=4000 + * maxSessionTimeout=40000 + * serverId=2 + * initLimit=15 + * syncLimit=10 + * electionAlg=3 + * electionPort=4445 + * quorumPort=4444 + * peerType=0 + */ +@Data +public class ConfigCmdData extends BaseFourLetterWordCmdData { + private Long clientPort; + private String dataDir; + private String dataLogDir; + private Long tickTime; + private Long maxClientCnxns; + private Long minSessionTimeout; + private Long maxSessionTimeout; + private Integer serverId; + private String initLimit; + private Long syncLimit; + private Long electionAlg; + private Long electionPort; + private Long quorumPort; + private Long peerType; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java new file mode 100644 index 00000000..7ea1339b --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java @@ -0,0 +1,39 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword; + +import lombok.Data; + +/** + * zk_version 3.4.6-1569965, built on 02/20/2014 09:09 GMT + * zk_avg_latency 0 + * zk_max_latency 399 + * zk_min_latency 0 + * zk_packets_received 234857 + * zk_packets_sent 234860 + * zk_num_alive_connections 4 + * zk_outstanding_requests 0 + * zk_server_state follower + * zk_znode_count 35566 + * zk_watch_count 39 + * zk_ephemerals_count 10 + * zk_approximate_data_size 3356708 + * zk_open_file_descriptor_count 35 + * zk_max_file_descriptor_count 819200 + */ +@Data +public class MonitorCmdData extends BaseFourLetterWordCmdData { + private String zkVersion; + private Long zkAvgLatency; + private Long zkMaxLatency; + private Long zkMinLatency; + private Long zkPacketsReceived; + private Long zkPacketsSent; + private Long zkNumAliveConnections; + private Long zkOutstandingRequests; + private String zkServerState; + private Long zkZnodeCount; + private Long zkWatchCount; + private Long zkEphemeralsCount; + private Long zkApproximateDataSize; + private Long zkOpenFileDescriptorCount; + private Long zkMaxFileDescriptorCount; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java new file mode 100644 index 00000000..38bd2cf9 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java @@ -0,0 +1,30 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword; + +import lombok.Data; + +/** + * Zookeeper version: 3.5.9-83df9301aa5c2a5d284a9940177808c01bc35cef, built on 01/06/2021 19:49 GMT + * Latency min/avg/max: 0/0/2209 + * Received: 278202469 + * Sent: 279449055 + * Connections: 31 + * Outstanding: 0 + * Zxid: 0x20033fc12 + * Mode: leader + * Node count: 10084 + * Proposal sizes last/min/max: 36/32/31260 leader特有 + */ +@Data +public class ServerCmdData extends BaseFourLetterWordCmdData { + private String zkVersion; + private Long zkAvgLatency; + private Long zkMaxLatency; + private Long zkMinLatency; + private Long zkPacketsReceived; + private Long zkPacketsSent; + private Long zkNumAliveConnections; + private Long zkOutstandingRequests; + private String zkServerState; + private Long zkZnodeCount; + private Long zkZxid; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ConfigCmdDataParser.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ConfigCmdDataParser.java new file mode 100644 index 00000000..35ec153b --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ConfigCmdDataParser.java @@ -0,0 +1,116 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.ConfigCmdData; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * clientPort=2183 + * dataDir=/data1/data/zkData2/version-2 + * dataLogDir=/data1/data/zkLog2/version-2 + * tickTime=2000 + * maxClientCnxns=60 + * minSessionTimeout=4000 + * maxSessionTimeout=40000 + * serverId=2 + * initLimit=15 + * syncLimit=10 + * electionAlg=3 + * electionPort=4445 + * quorumPort=4444 + * peerType=0 + */ +@Data +public class ConfigCmdDataParser implements FourLetterWordDataParser { + private static final ILog LOGGER = LogFactory.getLog(ConfigCmdDataParser.class); + + private Result dataResult = null; + + @Override + public String getCmd() { + return FourLetterWordUtil.ConfigCmd; + } + + @Override + public ConfigCmdData parseAndInitData(Long clusterPhyId, String host, int port, String cmdData) { + Map dataMap = new HashMap<>(); + for (String elem : cmdData.split("\n")) { + if (elem.isEmpty()) { + continue; + } + + int idx = elem.indexOf('='); + if (idx >= 0) { + dataMap.put(elem.substring(0, idx), elem.substring(idx + 1).trim()); + } + } + + ConfigCmdData configCmdData = new ConfigCmdData(); + dataMap.entrySet().stream().forEach(elem -> { + try { + switch (elem.getKey()) { + case "clientPort": + configCmdData.setClientPort(Long.valueOf(elem.getValue())); + break; + case "dataDir": + configCmdData.setDataDir(elem.getValue()); + break; + case "dataLogDir": + configCmdData.setDataLogDir(elem.getValue()); + break; + case "tickTime": + configCmdData.setTickTime(Long.valueOf(elem.getValue())); + break; + case "maxClientCnxns": + configCmdData.setMaxClientCnxns(Long.valueOf(elem.getValue())); + break; + case "minSessionTimeout": + configCmdData.setMinSessionTimeout(Long.valueOf(elem.getValue())); + break; + case "maxSessionTimeout": + configCmdData.setMaxSessionTimeout(Long.valueOf(elem.getValue())); + break; + case "serverId": + configCmdData.setServerId(Integer.valueOf(elem.getValue())); + break; + case "initLimit": + configCmdData.setInitLimit(elem.getValue()); + break; + case "syncLimit": + configCmdData.setSyncLimit(Long.valueOf(elem.getValue())); + break; + case "electionAlg": + configCmdData.setElectionAlg(Long.valueOf(elem.getValue())); + break; + case "electionPort": + configCmdData.setElectionPort(Long.valueOf(elem.getValue())); + break; + case "quorumPort": + configCmdData.setQuorumPort(Long.valueOf(elem.getValue())); + break; + case "peerType": + configCmdData.setPeerType(Long.valueOf(elem.getValue())); + break; + default: + LOGGER.warn( + "class=ConfigCmdDataParser||method=parseAndInitData||name={}||value={}||msg=data not parsed!", + elem.getKey(), elem.getValue() + ); + } + } catch (Exception e) { + LOGGER.error( + "class=ConfigCmdDataParser||method=parseAndInitData||clusterPhyId={}||host={}||port={}||name={}||value={}||errMsg=exception!", + clusterPhyId, host, port, elem.getKey(), elem.getValue(), e + ); + } + }); + + return configCmdData; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/FourLetterWordDataParser.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/FourLetterWordDataParser.java new file mode 100644 index 00000000..58bb2368 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/FourLetterWordDataParser.java @@ -0,0 +1,10 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser; + +/** + * 四字命令结果解析类 + */ +public interface FourLetterWordDataParser { + String getCmd(); + + T parseAndInitData(Long clusterPhyId, String host, int port, String cmdData); +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java new file mode 100644 index 00000000..a33f4da3 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java @@ -0,0 +1,117 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.MonitorCmdData; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * zk_version 3.4.6-1569965, built on 02/20/2014 09:09 GMT + * zk_avg_latency 0 + * zk_max_latency 399 + * zk_min_latency 0 + * zk_packets_received 234857 + * zk_packets_sent 234860 + * zk_num_alive_connections 4 + * zk_outstanding_requests 0 + * zk_server_state follower + * zk_znode_count 35566 + * zk_watch_count 39 + * zk_ephemerals_count 10 + * zk_approximate_data_size 3356708 + * zk_open_file_descriptor_count 35 + * zk_max_file_descriptor_count 819200 + */ +@Data +public class MonitorCmdDataParser implements FourLetterWordDataParser { + private static final ILog LOGGER = LogFactory.getLog(MonitorCmdDataParser.class); + + @Override + public String getCmd() { + return FourLetterWordUtil.MonitorCmd; + } + + @Override + public MonitorCmdData parseAndInitData(Long clusterPhyId, String host, int port, String cmdData) { + Map dataMap = new HashMap<>(); + for (String elem : cmdData.split("\n")) { + if (elem.isEmpty()) { + continue; + } + + int idx = elem.indexOf('\t'); + if (idx >= 0) { + dataMap.put(elem.substring(0, idx), elem.substring(idx + 1).trim()); + } + } + + MonitorCmdData monitorCmdData = new MonitorCmdData(); + dataMap.entrySet().stream().forEach(elem -> { + try { + switch (elem.getKey()) { + case "zk_version": + monitorCmdData.setZkVersion(elem.getValue().split("-")[0]); + break; + case "zk_avg_latency": + monitorCmdData.setZkAvgLatency(Long.valueOf(elem.getValue())); + break; + case "zk_max_latency": + monitorCmdData.setZkMaxLatency(Long.valueOf(elem.getValue())); + break; + case "zk_min_latency": + monitorCmdData.setZkMinLatency(Long.valueOf(elem.getValue())); + break; + case "zk_packets_received": + monitorCmdData.setZkPacketsReceived(Long.valueOf(elem.getValue())); + break; + case "zk_packets_sent": + monitorCmdData.setZkPacketsSent(Long.valueOf(elem.getValue())); + break; + case "zk_num_alive_connections": + monitorCmdData.setZkNumAliveConnections(Long.valueOf(elem.getValue())); + break; + case "zk_outstanding_requests": + monitorCmdData.setZkOutstandingRequests(Long.valueOf(elem.getValue())); + break; + case "zk_server_state": + monitorCmdData.setZkServerState(elem.getValue()); + break; + case "zk_znode_count": + monitorCmdData.setZkZnodeCount(Long.valueOf(elem.getValue())); + break; + case "zk_watch_count": + monitorCmdData.setZkWatchCount(Long.valueOf(elem.getValue())); + break; + case "zk_ephemerals_count": + monitorCmdData.setZkEphemeralsCount(Long.valueOf(elem.getValue())); + break; + case "zk_approximate_data_size": + monitorCmdData.setZkApproximateDataSize(Long.valueOf(elem.getValue())); + break; + case "zk_open_file_descriptor_count": + monitorCmdData.setZkOpenFileDescriptorCount(Long.valueOf(elem.getValue())); + break; + case "zk_max_file_descriptor_count": + monitorCmdData.setZkMaxFileDescriptorCount(Long.valueOf(elem.getValue())); + break; + default: + LOGGER.warn( + "class=MonitorCmdDataParser||method=parseAndInitData||name={}||value={}||msg=data not parsed!", + elem.getKey(), elem.getValue() + ); + } + } catch (Exception e) { + LOGGER.error( + "class=MonitorCmdDataParser||method=parseAndInitData||clusterPhyId={}||host={}||port={}||name={}||value={}||errMsg=exception!", + clusterPhyId, host, port, elem.getKey(), elem.getValue(), e + ); + } + }); + + return monitorCmdData; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ServerCmdDataParser.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ServerCmdDataParser.java new file mode 100644 index 00000000..f91f19a8 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ServerCmdDataParser.java @@ -0,0 +1,97 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.ServerCmdData; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * Zookeeper version: 3.5.9-83df9301aa5c2a5d284a9940177808c01bc35cef, built on 01/06/2021 19:49 GMT + * Latency min/avg/max: 0/0/2209 + * Received: 278202469 + * Sent: 279449055 + * Connections: 31 + * Outstanding: 0 + * Zxid: 0x20033fc12 + * Mode: leader + * Node count: 10084 + * Proposal sizes last/min/max: 36/32/31260 leader特有 + */ +@Data +public class ServerCmdDataParser implements FourLetterWordDataParser { + private static final ILog LOGGER = LogFactory.getLog(ServerCmdDataParser.class); + + @Override + public String getCmd() { + return FourLetterWordUtil.ServerCmd; + } + + @Override + public ServerCmdData parseAndInitData(Long clusterPhyId, String host, int port, String cmdData) { + Map dataMap = new HashMap<>(); + for (String elem : cmdData.split("\n")) { + if (elem.isEmpty()) { + continue; + } + + int idx = elem.indexOf(':'); + if (idx >= 0) { + dataMap.put(elem.substring(0, idx), elem.substring(idx + 1).trim()); + } + } + + ServerCmdData serverCmdData = new ServerCmdData(); + dataMap.entrySet().stream().forEach(elem -> { + try { + switch (elem.getKey()) { + case "Zookeeper version": + serverCmdData.setZkVersion(elem.getValue().split("-")[0]); + break; + case "Latency min/avg/max": + String[] data = elem.getValue().split("/"); + serverCmdData.setZkMinLatency(Long.valueOf(data[0])); + serverCmdData.setZkAvgLatency(Long.valueOf(data[1])); + serverCmdData.setZkMaxLatency(Long.valueOf(data[2])); + break; + case "Received": + serverCmdData.setZkPacketsReceived(Long.valueOf(elem.getValue())); + break; + case "Sent": + serverCmdData.setZkPacketsSent(Long.valueOf(elem.getValue())); + break; + case "Connections": + serverCmdData.setZkNumAliveConnections(Long.valueOf(elem.getValue())); + break; + case "Outstanding": + serverCmdData.setZkOutstandingRequests(Long.valueOf(elem.getValue())); + break; + case "Mode": + serverCmdData.setZkServerState(elem.getValue()); + break; + case "Node count": + serverCmdData.setZkZnodeCount(Long.valueOf(elem.getValue())); + break; + case "Zxid": + serverCmdData.setZkZxid(Long.parseUnsignedLong(elem.getValue().trim().substring(2), 16)); + break; + default: + LOGGER.warn( + "class=ServerCmdDataParser||method=parseAndInitData||name={}||value={}||msg=data not parsed!", + elem.getKey(), elem.getValue() + ); + } + } catch (Exception e) { + LOGGER.error( + "class=ServerCmdDataParser||method=parseAndInitData||clusterPhyId={}||host={}||port={}||name={}||value={}||errMsg=exception!", + clusterPhyId, host, port, elem.getKey(), elem.getValue(), e + ); + } + }); + + return serverCmdData; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/FourLetterWordUtil.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/FourLetterWordUtil.java new file mode 100644 index 00000000..a3ae31af --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/FourLetterWordUtil.java @@ -0,0 +1,163 @@ +package com.xiaojukeji.know.streaming.km.common.utils.zookeeper; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.FourLetterWordDataParser; +import com.xiaojukeji.know.streaming.km.common.utils.BackoffUtils; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; +import org.apache.zookeeper.common.ClientX509Util; +import org.apache.zookeeper.common.X509Exception; +import org.apache.zookeeper.common.X509Util; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.util.HashSet; +import java.util.Set; + +public class FourLetterWordUtil { + private static final ILog LOGGER = LogFactory.getLog(FourLetterWordUtil.class); + + public static final String MonitorCmd = "mntr"; + public static final String ConfigCmd = "conf"; + public static final String ServerCmd = "srvr"; + + private static final Set supportedCommands = new HashSet<>(); + + public static Result executeFourLetterCmd(Long clusterPhyId, + String host, + int port, + boolean secure, + int timeout, + FourLetterWordDataParser dataParser) { + try { + if (!supportedCommands.contains(dataParser.getCmd())) { + return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, String.format("ZK %s命令暂未进行支持", dataParser.getCmd())); + } + + String cmdData = send4LetterWord(host, port, dataParser.getCmd(), secure, timeout); + if (cmdData.contains("not executed because it is not in the whitelist.")) { + return Result.buildFromRSAndMsg(ResultStatus.ZK_FOUR_LETTER_CMD_FORBIDDEN, cmdData); + } + if (ValidateUtils.isBlank(cmdData)) { + return Result.buildFromRSAndMsg(ResultStatus.ZK_OPERATE_FAILED, cmdData); + } + + return Result.buildSuc(dataParser.parseAndInitData(clusterPhyId, host, port, cmdData)); + } catch (Exception e) { + LOGGER.error( + "class=FourLetterWordUtil||method=executeFourLetterCmd||clusterPhyId={}||host={}||port={}||cmd={}||secure={}||timeout={}||errMsg=exception!", + clusterPhyId, host, port, dataParser.getCmd(), secure, timeout, e + ); + + return Result.buildFromRSAndMsg(ResultStatus.ZK_OPERATE_FAILED, e.getMessage()); + } + } + + + /**************************************************** private method ****************************************************/ + + private static String send4LetterWord( + String host, + int port, + String cmd, + boolean secure, + int timeout) throws IOException, X509Exception.SSLContextException { + long startTime = System.currentTimeMillis(); + + LOGGER.info("connecting to {} {}", host, port); + + Socket socket = null; + OutputStream outputStream = null; + BufferedReader bufferedReader = null; + try { + InetSocketAddress hostaddress = host != null + ? new InetSocketAddress(host, port) + : new InetSocketAddress(InetAddress.getByName(null), port); + if (secure) { + LOGGER.info("using secure socket"); + try (X509Util x509Util = new ClientX509Util()) { + SSLContext sslContext = x509Util.getDefaultSSLContext(); + SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + SSLSocket sslSock = (SSLSocket) socketFactory.createSocket(); + sslSock.connect(hostaddress, timeout); + sslSock.startHandshake(); + socket = sslSock; + } + } else { + socket = new Socket(); + socket.connect(hostaddress, timeout); + } + socket.setSoTimeout(timeout); + + outputStream = socket.getOutputStream(); + outputStream.write(cmd.getBytes()); + outputStream.flush(); + + // 等待InputStream有数据 + while (System.currentTimeMillis() - startTime <= timeout && socket.getInputStream().available() <= 0) { + BackoffUtils.backoff(10); + } + + bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = bufferedReader.readLine()) != null) { + sb.append(line).append("\n"); + } + return sb.toString(); + } catch (SocketTimeoutException e) { + throw new IOException("Exception while executing four letter word: " + cmd, e); + } finally { + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + LOGGER.error( + "class=FourLetterWordUtil||method=send4LetterWord||clusterPhyId={}||host={}||port={}||cmd={}||secure={}||timeout={}||errMsg=exception!", + host, port, cmd, secure, timeout, e + ); + } + } + + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (IOException e) { + LOGGER.error( + "class=FourLetterWordUtil||method=send4LetterWord||host={}||port={}||cmd={}||secure={}||timeout={}||errMsg=exception!", + host, port, cmd, secure, timeout, e + ); + } + } + + if (socket != null) { + try { + socket.close(); + } catch (IOException e) { + LOGGER.error( + "class=FourLetterWordUtil||method=send4LetterWord||host={}||port={}||cmd={}||secure={}||timeout={}||errMsg=exception!", + host, port, cmd, secure, timeout, e + ); + } + } + } + } + + static { + supportedCommands.add(MonitorCmd); + supportedCommands.add(ConfigCmd); + supportedCommands.add(ServerCmd); + } + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/ZookeeperUtils.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/ZookeeperUtils.java new file mode 100644 index 00000000..9d8c6c5b --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/ZookeeperUtils.java @@ -0,0 +1,59 @@ +package com.xiaojukeji.know.streaming.km.common.utils.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import org.apache.zookeeper.client.ConnectStringParser; +import org.apache.zookeeper.common.NetUtils; + +import java.util.ArrayList; +import java.util.List; + +import static org.apache.zookeeper.common.StringUtils.split; + +public class ZookeeperUtils { + private static final int DEFAULT_PORT = 2181; + + /** + * 解析ZK地址 + * @see ConnectStringParser + */ + public static List> connectStringParser(String connectString) throws Exception { + List> ipPortList = new ArrayList<>(); + + if (connectString == null) { + return ipPortList; + } + + // parse out chroot, if any + int off = connectString.indexOf('/'); + if (off >= 0) { + connectString = connectString.substring(0, off); + } + + List hostsList = split(connectString, ","); + for (String host : hostsList) { + int port = DEFAULT_PORT; + String[] hostAndPort = NetUtils.getIPV6HostAndPort(host); + if (hostAndPort.length != 0) { + host = hostAndPort[0]; + if (hostAndPort.length == 2) { + port = Integer.parseInt(hostAndPort[1]); + } + } else { + int pidx = host.lastIndexOf(':'); + if (pidx >= 0) { + // otherwise : is at the end of the string, ignore + if (pidx < host.length() - 1) { + port = Integer.parseInt(host.substring(pidx + 1)); + } + host = host.substring(0, pidx); + } + } + + ipPortList.add(new Tuple<>(host, port)); + } + + return ipPortList; + } + + +} From dd61ce9b2a92e184db839018470c27f384c2632f Mon Sep 17 00:00:00 2001 From: zengqiao Date: Sat, 8 Oct 2022 14:58:28 +0800 Subject: [PATCH 009/145] =?UTF-8?q?ZK-=E5=A2=9E=E5=8A=A0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=9A=84=E9=BB=98=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/bean/entity/config/ZKConfig.java | 47 +++++++++++++++++-- .../km/common/constant/Constant.java | 6 ++- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/ZKConfig.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/ZKConfig.java index 39e6fdf5..66a727e5 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/ZKConfig.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/ZKConfig.java @@ -1,8 +1,8 @@ package com.xiaojukeji.know.streaming.km.common.bean.entity.config; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import lombok.Data; import java.io.Serializable; import java.util.Properties; @@ -11,7 +11,6 @@ import java.util.Properties; * @author zengqiao * @date 22/02/24 */ -@Data @ApiModel(description = "ZK配置") public class ZKConfig implements Serializable { @ApiModelProperty(value="ZK的jmx配置") @@ -21,11 +20,51 @@ public class ZKConfig implements Serializable { private Boolean openSecure = false; @ApiModelProperty(value="ZK的Session超时时间", example = "15000") - private Long sessionTimeoutUnitMs = 15000L; + private Integer sessionTimeoutUnitMs = 15000; @ApiModelProperty(value="ZK的Request超时时间", example = "5000") - private Long requestTimeoutUnitMs = 5000L; + private Integer requestTimeoutUnitMs = 5000; @ApiModelProperty(value="ZK的Request超时时间") private Properties otherProps = new Properties(); + + public JmxConfig getJmxConfig() { + return jmxConfig == null? new JmxConfig(): jmxConfig; + } + + public void setJmxConfig(JmxConfig jmxConfig) { + this.jmxConfig = jmxConfig; + } + + public Boolean getOpenSecure() { + return openSecure != null && openSecure; + } + + public void setOpenSecure(Boolean openSecure) { + this.openSecure = openSecure; + } + + public Integer getSessionTimeoutUnitMs() { + return sessionTimeoutUnitMs == null? Constant.DEFAULT_SESSION_TIMEOUT_UNIT_MS: sessionTimeoutUnitMs; + } + + public void setSessionTimeoutUnitMs(Integer sessionTimeoutUnitMs) { + this.sessionTimeoutUnitMs = sessionTimeoutUnitMs; + } + + public Integer getRequestTimeoutUnitMs() { + return requestTimeoutUnitMs == null? Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS: requestTimeoutUnitMs; + } + + public void setRequestTimeoutUnitMs(Integer requestTimeoutUnitMs) { + this.requestTimeoutUnitMs = requestTimeoutUnitMs; + } + + public Properties getOtherProps() { + return otherProps == null? new Properties() : otherProps; + } + + public void setOtherProps(Properties otherProps) { + this.otherProps = otherProps; + } } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java index edd897ff..a91f0809 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java @@ -23,8 +23,8 @@ public class Constant { public static final Integer YES = 1; public static final Integer NO = 0; - public static final Integer ALIVE = 1; - public static final Integer DOWN = 0; + public static final Integer ALIVE = 1; + public static final Integer DOWN = 0; public static final Integer ONE_HUNDRED = 100; @@ -33,6 +33,7 @@ public class Constant { public static final Long B_TO_MB = 1024L * 1024L; public static final Integer DEFAULT_SESSION_TIMEOUT_UNIT_MS = 15000; + public static final Integer DEFAULT_REQUEST_TIMEOUT_UNIT_MS = 5000; public static final Float MIN_HEALTH_SCORE = 10f; @@ -66,4 +67,5 @@ public class Constant { public static final Integer DEFAULT_RETRY_TIME = 3; + public static final Integer ZK_ALIVE_BUT_4_LETTER_FORBIDDEN = 11; } From 7d781712c998fc699a54d86cf53fcd59e6d0218e Mon Sep 17 00:00:00 2001 From: zengqiao Date: Sat, 8 Oct 2022 15:19:09 +0800 Subject: [PATCH 010/145] =?UTF-8?q?ZK-=E5=90=8C=E6=AD=A5ZK=E5=85=83?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E8=87=B3DB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/install_guide/版本升级手册.md | 17 +- .../bean/entity/zookeeper/ZookeeperInfo.java | 42 +++++ .../bean/po/zookeeper/ZookeeperInfoPO.java | 40 +++++ .../km/common/enums/zookeeper/ZKRoleEnum.java | 22 +++ .../service/zookeeper/ZookeeperService.java | 18 +++ .../zookeeper/impl/ZookeeperServiceImpl.java | 147 ++++++++++++++++++ km-dist/init/sql/ddl-ks-km.sql | 16 ++ .../mysql/zookeeper/ZookeeperDAO.java | 9 ++ .../km/task/metadata/SyncZookeeperTask.java | 47 ++++++ 9 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/ZookeeperInfo.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/zookeeper/ZookeeperInfoPO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/zookeeper/ZKRoleEnum.java create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java create mode 100644 km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/zookeeper/ZookeeperDAO.java create mode 100644 km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncZookeeperTask.java diff --git a/docs/install_guide/版本升级手册.md b/docs/install_guide/版本升级手册.md index a75f71fd..efc01399 100644 --- a/docs/install_guide/版本升级手册.md +++ b/docs/install_guide/版本升级手册.md @@ -7,7 +7,22 @@ ### 6.2.0、升级至 `master` 版本 -暂无 +```sql +DROP TABLE IF EXISTS `ks_km_zookeeper`; +CREATE TABLE `ks_km_zookeeper` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '物理集群ID', + `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper主机名', + `port` int(16) NOT NULL DEFAULT '-1' COMMENT 'zookeeper端口', + `role` int(16) NOT NULL DEFAULT '-1' COMMENT '角色, leader follower observer', + `version` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper版本', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态: 1存活,0未存活,11存活但是4字命令使用不了', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_host_port` (`cluster_phy_id`,`host`, `port`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Zookeeper信息表'; +``` ### 6.2.1、升级至 `v3.0.0` 版本 diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/ZookeeperInfo.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/ZookeeperInfo.java new file mode 100644 index 00000000..e943952e --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/ZookeeperInfo.java @@ -0,0 +1,42 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.BaseEntity; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import lombok.Data; + +@Data +public class ZookeeperInfo extends BaseEntity { + /** + * 集群Id + */ + private Long clusterPhyId; + + /** + * 主机 + */ + private String host; + + /** + * 端口 + */ + private Integer port; + + /** + * 角色 + */ + private String role; + + /** + * 版本 + */ + private String version; + + /** + * ZK状态 + */ + private Integer status; + + public boolean alive() { + return !(Constant.DOWN.equals(status)); + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/zookeeper/ZookeeperInfoPO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/zookeeper/ZookeeperInfoPO.java new file mode 100644 index 00000000..69968ef6 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/zookeeper/ZookeeperInfoPO.java @@ -0,0 +1,40 @@ +package com.xiaojukeji.know.streaming.km.common.bean.po.zookeeper; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.xiaojukeji.know.streaming.km.common.bean.po.BasePO; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import lombok.Data; + +@Data +@TableName(Constant.MYSQL_TABLE_NAME_PREFIX + "zookeeper") +public class ZookeeperInfoPO extends BasePO { + /** + * 集群Id + */ + private Long clusterPhyId; + + /** + * 主机 + */ + private String host; + + /** + * 端口 + */ + private Integer port; + + /** + * 角色 + */ + private String role; + + /** + * 版本 + */ + private String version; + + /** + * ZK状态 + */ + private Integer status; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/zookeeper/ZKRoleEnum.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/zookeeper/ZKRoleEnum.java new file mode 100644 index 00000000..fd379dc8 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/zookeeper/ZKRoleEnum.java @@ -0,0 +1,22 @@ +package com.xiaojukeji.know.streaming.km.common.enums.zookeeper; + +import lombok.Getter; + +@Getter +public enum ZKRoleEnum { + LEADER("leader"), + + FOLLOWER("follower"), + + OBSERVER("observer"), + + UNKNOWN("unknown"), + + ; + + private final String role; + + ZKRoleEnum(String role) { + this.role = role; + } +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java new file mode 100644 index 00000000..758247aa --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java @@ -0,0 +1,18 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; + +import java.util.List; + +public interface ZookeeperService { + /** + * 从ZK集群中获取ZK信息 + */ + Result> listFromZookeeper(Long clusterPhyId, String zookeeperAddress, ZKConfig zkConfig); + + void batchReplaceDataInDB(Long clusterPhyId, List infoList); + + List listFromDBByCluster(Long clusterPhyId); +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java new file mode 100644 index 00000000..2f1e318c --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java @@ -0,0 +1,147 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.ServerCmdData; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.ServerCmdDataParser; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.zookeeper.ZKRoleEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.common.bean.po.zookeeper.ZookeeperInfoPO; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.ZookeeperUtils; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import com.xiaojukeji.know.streaming.km.persistence.mysql.zookeeper.ZookeeperDAO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class ZookeeperServiceImpl implements ZookeeperService { + private static final ILog LOGGER = LogFactory.getLog(ZookeeperServiceImpl.class); + + @Autowired + private ZookeeperDAO zookeeperDAO; + + @Override + public Result> listFromZookeeper(Long clusterPhyId, String zookeeperAddress, ZKConfig zkConfig) { + List> addressList = null; + try { + addressList = ZookeeperUtils.connectStringParser(zookeeperAddress); + } catch (Exception e) { + LOGGER.error( + "class=ZookeeperServiceImpl||method=listFromZookeeperCluster||clusterPhyId={}||zookeeperAddress={}||errMsg=exception!", + clusterPhyId, zookeeperAddress, e + ); + + return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, e.getMessage()); + } + + List aliveZKList = new ArrayList<>(); + for (Tuple hostPort: addressList) { + aliveZKList.add(this.getFromZookeeperCluster( + clusterPhyId, + hostPort.getV1(), + hostPort.getV2(), + zkConfig + )); + } + return Result.buildSuc(aliveZKList); + } + + @Override + public void batchReplaceDataInDB(Long clusterPhyId, List infoList) { + // DB 中的信息 + List dbInfoList = this.listRawFromDBByCluster(clusterPhyId); + Map dbMap = new HashMap<>(); + dbInfoList.stream().forEach(elem -> dbMap.put(elem.getHost() + elem.getPort(), elem)); + + // 新获取到的信息 + List newInfoList = ConvertUtil.list2List(infoList, ZookeeperInfoPO.class); + for (ZookeeperInfoPO newInfo: newInfoList) { + try { + ZookeeperInfoPO oldInfo = dbMap.remove(newInfo.getHost() + newInfo.getPort()); + if (oldInfo == null) { + zookeeperDAO.insert(newInfo); + } else if (!Constant.DOWN.equals(newInfo.getStatus())) { + // 存活时,直接使用获取到的数据 + newInfo.setId(oldInfo.getId()); + zookeeperDAO.updateById(newInfo); + } else { + // 如果挂了,则版本和角色信息,使用先前的信息。 + // 挂掉之后,如果角色是leader,则需要调整一下 + newInfo.setId(oldInfo.getId()); + newInfo.setRole(ZKRoleEnum.LEADER.getRole().equals(oldInfo.getRole())? ZKRoleEnum.FOLLOWER.getRole(): oldInfo.getRole()); + newInfo.setVersion(oldInfo.getVersion()); + zookeeperDAO.updateById(newInfo); + } + } catch (Exception e) { + LOGGER.error("class=ZookeeperServiceImpl||method=batchReplaceDataInDB||clusterPhyId={}||newInfo={}||errMsg=exception", clusterPhyId, newInfo, e); + } + } + + // 删除剩余的ZK节点 + dbMap.entrySet().forEach(entry -> { + try { + zookeeperDAO.deleteById(entry.getValue().getId()); + } catch (Exception e) { + LOGGER.error("class=ZookeeperServiceImpl||method=batchReplaceDataInDB||clusterPhyId={}||expiredInfo={}||errMsg=exception", clusterPhyId, entry.getValue(), e); + } + }); + } + + @Override + public List listFromDBByCluster(Long clusterPhyId) { + return ConvertUtil.list2List(this.listRawFromDBByCluster(clusterPhyId), ZookeeperInfo.class); + } + + + /**************************************************** private method ****************************************************/ + + private List listRawFromDBByCluster(Long clusterPhyId) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(ZookeeperInfoPO::getClusterPhyId, clusterPhyId); + + return zookeeperDAO.selectList(lambdaQueryWrapper); + } + + private ZookeeperInfo getFromZookeeperCluster(Long clusterPhyId, String host, Integer port, ZKConfig zkConfig) { + ZookeeperInfo zookeeperInfo = new ZookeeperInfo(); + zookeeperInfo.setClusterPhyId(clusterPhyId); + zookeeperInfo.setHost(host); + zookeeperInfo.setPort(port); + zookeeperInfo.setRole(""); + zookeeperInfo.setVersion(""); + zookeeperInfo.setStatus(Constant.DOWN); + + Result serverCmdDataResult = FourLetterWordUtil.executeFourLetterCmd( + clusterPhyId, + host, + port, + zkConfig != null ? zkConfig.getOpenSecure(): false, + zkConfig != null ? zkConfig.getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, + new ServerCmdDataParser() + ); + if (serverCmdDataResult.hasData()) { + zookeeperInfo.setRole(serverCmdDataResult.getData().getZkServerState()); + zookeeperInfo.setVersion(serverCmdDataResult.getData().getZkVersion()); + zookeeperInfo.setStatus(Constant.ALIVE); + } else if (serverCmdDataResult.getCode().equals(ResultStatus.ZK_FOUR_LETTER_CMD_FORBIDDEN.getCode())) { + zookeeperInfo.setStatus(Constant.ZK_ALIVE_BUT_4_LETTER_FORBIDDEN); + } else { + return zookeeperInfo; + } + + return zookeeperInfo; + } +} diff --git a/km-dist/init/sql/ddl-ks-km.sql b/km-dist/init/sql/ddl-ks-km.sql index d9e4e16c..89f04034 100644 --- a/km-dist/init/sql/ddl-ks-km.sql +++ b/km-dist/init/sql/ddl-ks-km.sql @@ -355,3 +355,19 @@ CREATE TABLE `ks_km_app_node` ( PRIMARY KEY (`id`), KEY `idx_app_host` (`app_name`,`host_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='km集群部署的node信息'; + + +DROP TABLE IF EXISTS `ks_km_zookeeper`; +CREATE TABLE `ks_km_zookeeper` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '物理集群ID', + `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper主机名', + `port` int(16) NOT NULL DEFAULT '-1' COMMENT 'zookeeper端口', + `role` int(16) NOT NULL DEFAULT '-1' COMMENT '角色, leader follower observer', + `version` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper版本', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态: 1存活,0未存活,11存活但是4字命令使用不了', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_host_port` (`cluster_phy_id`,`host`, `port`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Zookeeper信息表'; \ No newline at end of file diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/zookeeper/ZookeeperDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/zookeeper/ZookeeperDAO.java new file mode 100644 index 00000000..73a177ae --- /dev/null +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/zookeeper/ZookeeperDAO.java @@ -0,0 +1,9 @@ +package com.xiaojukeji.know.streaming.km.persistence.mysql.zookeeper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xiaojukeji.know.streaming.km.common.bean.po.zookeeper.ZookeeperInfoPO; +import org.springframework.stereotype.Repository; + +@Repository +public interface ZookeeperDAO extends BaseMapper { +} diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncZookeeperTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncZookeeperTask.java new file mode 100644 index 00000000..5af37be2 --- /dev/null +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncZookeeperTask.java @@ -0,0 +1,47 @@ +package com.xiaojukeji.know.streaming.km.task.metadata; + +import com.didiglobal.logi.job.annotation.Task; +import com.didiglobal.logi.job.common.TaskResult; +import com.didiglobal.logi.job.core.consensual.ConsensualEnum; +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + + +@Task(name = "SyncZookeeperTask", + description = "ZK信息同步到DB", + cron = "0 0/1 * * * ? *", + autoRegister = true, + consensual = ConsensualEnum.BROADCAST, + timeout = 2 * 60) +public class SyncZookeeperTask extends AbstractAsyncMetadataDispatchTask { + private static final ILog log = LogFactory.getLog(SyncZookeeperTask.class); + + @Autowired + private ZookeeperService zookeeperService; + + @Override + public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { + Result> infoResult = zookeeperService.listFromZookeeper( + clusterPhy.getId(), + clusterPhy.getZookeeper(), + ConvertUtil.str2ObjByJson(clusterPhy.getZkProperties(), ZKConfig.class) + ); + + if (infoResult.failed()) { + return new TaskResult(TaskResult.FAIL_CODE, infoResult.getMessage()); + } + + zookeeperService.batchReplaceDataInDB(clusterPhy.getId(), infoResult.getData()); + + return TaskResult.SUCCESS; + } +} From b4cc31c459683727cc9986a4b4a27c0f0ccc441d Mon Sep 17 00:00:00 2001 From: zengqiao Date: Sat, 8 Oct 2022 15:31:59 +0800 Subject: [PATCH 011/145] =?UTF-8?q?ZK-=E6=8C=87=E6=A0=87=E9=87=87=E9=9B=86?= =?UTF-8?q?=E5=85=A5ES?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../metric/ZookeeperMetricCollector.java | 122 ++++++++ .../sink/ZookeeperMetricESSender.java | 28 ++ .../bean/entity/metrics/ZookeeperMetrics.java | 28 ++ .../param/metric/ZookeeperMetricParam.java | 47 +++ .../version/VersionMetricControlItem.java | 2 + .../bean/event/metric/BaseMetricEvent.java | 2 - .../event/metric/ZookeeperMetricEvent.java | 20 ++ .../bean/po/metrice/ZookeeperMetricPO.java | 24 ++ .../vo/metrics/line/MetricMultiLinesVO.java | 19 -- .../km/common/constant/ESConstant.java | 2 + .../km/common/constant/ESIndexConstant.java | 85 ++++++ .../enums/version/VersionItemTypeEnum.java | 4 +- .../streaming/km/common/jmx/JmxAttribute.java | 6 + .../know/streaming/km/common/jmx/JmxName.java | 6 + .../broker/impl/BrokerServiceImpl.java | 12 +- .../metrics/ZookeeperMetricVersionItems.java | 141 +++++++++ .../zookeeper/ZookeeperMetricService.java | 21 ++ .../impl/ZookeeperMetricServiceImpl.java | 281 ++++++++++++++++++ .../init/template/ks_kafka_zookeeper_metric | 85 ++++++ .../persistence/es/dao/BaseMetricESDAO.java | 3 +- .../es/dao/ZookeeperMetricESDAO.java | 106 +++++++ .../km/persistence/es/dsls/DslsConstant.java | 2 + .../streaming/km/persistence/jmx/JmxDAO.java | 4 +- .../km/persistence/jmx/impl/JmxDAOImpl.java | 41 ++- .../getAggListZookeeperMetrics | 44 +++ .../metrics/ZookeeperMetricCollectorTask.java | 33 ++ 26 files changed, 1126 insertions(+), 42 deletions(-) create mode 100644 km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ZookeeperMetricCollector.java create mode 100644 km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/sink/ZookeeperMetricESSender.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/metrics/ZookeeperMetrics.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/param/metric/ZookeeperMetricParam.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/ZookeeperMetricEvent.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/metrice/ZookeeperMetricPO.java create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ZookeeperMetricVersionItems.java create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperMetricService.java create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java create mode 100644 km-dist/init/template/ks_kafka_zookeeper_metric create mode 100644 km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ZookeeperMetricESDAO.java create mode 100644 km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics create mode 100644 km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ZookeeperMetricCollectorTask.java diff --git a/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ZookeeperMetricCollector.java b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ZookeeperMetricCollector.java new file mode 100644 index 00000000..37f86d4e --- /dev/null +++ b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ZookeeperMetricCollector.java @@ -0,0 +1,122 @@ +package com.xiaojukeji.know.streaming.km.collector.metric; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.kafkacontroller.KafkaController; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric.ZookeeperMetricParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionControlItem; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; +import com.xiaojukeji.know.streaming.km.common.bean.event.metric.ZookeeperMetricEvent; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.utils.EnvUtil; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ZookeeperMetricPO; +import com.xiaojukeji.know.streaming.km.core.service.kafkacontroller.KafkaControllerService; +import com.xiaojukeji.know.streaming.km.core.service.version.VersionControlService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperMetricService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum.METRIC_ZOOKEEPER; + +/** + * @author didi + */ +@Component +public class ZookeeperMetricCollector extends AbstractMetricCollector { + protected static final ILog LOGGER = LogFactory.getLog("METRIC_LOGGER"); + + @Autowired + private VersionControlService versionControlService; + + @Autowired + private ZookeeperMetricService zookeeperMetricService; + + @Autowired + private ZookeeperService zookeeperService; + + @Autowired + private KafkaControllerService kafkaControllerService; + + @Override + public void collectMetrics(ClusterPhy clusterPhy) { + Long startTime = System.currentTimeMillis(); + Long clusterPhyId = clusterPhy.getId(); + List items = versionControlService.listVersionControlItem(clusterPhyId, collectorType().getCode()); + List aliveZKList = zookeeperService.listFromDBByCluster(clusterPhyId) + .stream() + .filter(elem -> Constant.ALIVE.equals(elem.getStatus())) + .collect(Collectors.toList()); + KafkaController kafkaController = kafkaControllerService.getKafkaControllerFromDB(clusterPhyId); + + ZookeeperMetrics metrics = ZookeeperMetrics.initWithMetric(clusterPhyId, Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, (float)Constant.INVALID_CODE); + if (ValidateUtils.isEmptyList(aliveZKList)) { + // 没有存活的ZK时,发布事件,然后直接返回 + publishMetric(new ZookeeperMetricEvent(this, Arrays.asList(metrics))); + return; + } + + // 构造参数 + ZookeeperMetricParam param = new ZookeeperMetricParam( + clusterPhyId, + aliveZKList.stream().map(elem -> new Tuple(elem.getHost(), elem.getPort())).collect(Collectors.toList()), + ConvertUtil.str2ObjByJson(clusterPhy.getZkProperties(), ZKConfig.class), + kafkaController == null? Constant.INVALID_CODE: kafkaController.getBrokerId(), + null + ); + + for(VersionControlItem v : items) { + try { + if(null != metrics.getMetrics().get(v.getName())) { + continue; + } + param.setMetricName(v.getName()); + + Result ret = zookeeperMetricService.collectMetricsFromZookeeper(param); + if(null == ret || ret.failed() || null == ret.getData()){ + continue; + } + + metrics.putMetric(ret.getData().getMetrics()); + + if(!EnvUtil.isOnline()){ + LOGGER.info( + "class=ZookeeperMetricCollector||method=collectMetrics||clusterPhyId={}||metricName={}||metricValue={}", + clusterPhyId, v.getName(), ConvertUtil.obj2Json(ret.getData().getMetrics()) + ); + } + } catch (Exception e){ + LOGGER.error( + "class=ZookeeperMetricCollector||method=collectMetrics||clusterPhyId={}||metricName={}||errMsg=exception!", + clusterPhyId, v.getName(), e + ); + } + } + + metrics.putMetric(Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, (System.currentTimeMillis() - startTime) / 1000.0f); + + publishMetric(new ZookeeperMetricEvent(this, Arrays.asList(metrics))); + + LOGGER.info( + "class=ZookeeperMetricCollector||method=collectMetrics||clusterPhyId={}||startTime={}||costTime={}||msg=msg=collect finished.", + clusterPhyId, startTime, System.currentTimeMillis() - startTime + ); + } + + @Override + public VersionItemTypeEnum collectorType() { + return METRIC_ZOOKEEPER; + } +} diff --git a/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/sink/ZookeeperMetricESSender.java b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/sink/ZookeeperMetricESSender.java new file mode 100644 index 00000000..4f9dad53 --- /dev/null +++ b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/sink/ZookeeperMetricESSender.java @@ -0,0 +1,28 @@ +package com.xiaojukeji.know.streaming.km.collector.sink; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.bean.event.metric.ZookeeperMetricEvent; +import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ZookeeperMetricPO; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +import static com.xiaojukeji.know.streaming.km.common.constant.ESIndexConstant.ZOOKEEPER_INDEX; + +@Component +public class ZookeeperMetricESSender extends AbstractMetricESSender implements ApplicationListener { + protected static final ILog LOGGER = LogFactory.getLog("METRIC_LOGGER"); + + @PostConstruct + public void init(){ + LOGGER.info("class=ZookeeperMetricESSender||method=init||msg=init finished"); + } + + @Override + public void onApplicationEvent(ZookeeperMetricEvent event) { + send2es(ZOOKEEPER_INDEX, ConvertUtil.list2List(event.getZookeeperMetrics(), ZookeeperMetricPO.class)); + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/metrics/ZookeeperMetrics.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/metrics/ZookeeperMetrics.java new file mode 100644 index 00000000..823125b5 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/metrics/ZookeeperMetrics.java @@ -0,0 +1,28 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.metrics; + +import lombok.Data; +import lombok.ToString; + +/** + * @author zengqiao + * @date 20/6/17 + */ +@Data +@ToString +public class ZookeeperMetrics extends BaseMetrics { + public ZookeeperMetrics(Long clusterPhyId) { + super(clusterPhyId); + } + + public static ZookeeperMetrics initWithMetric(Long clusterPhyId, String metric, Float value) { + ZookeeperMetrics metrics = new ZookeeperMetrics(clusterPhyId); + metrics.setClusterPhyId( clusterPhyId ); + metrics.putMetric(metric, value); + return metrics; + } + + @Override + public String unique() { + return "ZK@" + clusterPhyId; + } +} \ No newline at end of file diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/param/metric/ZookeeperMetricParam.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/param/metric/ZookeeperMetricParam.java new file mode 100644 index 00000000..ef2b09c8 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/param/metric/ZookeeperMetricParam.java @@ -0,0 +1,47 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author didi + */ +@Data +@NoArgsConstructor +public class ZookeeperMetricParam extends MetricParam { + private Long clusterPhyId; + + private List> zkAddressList; + + private ZKConfig zkConfig; + + private String metricName; + + private Integer kafkaControllerId; + + public ZookeeperMetricParam(Long clusterPhyId, + List> zkAddressList, + ZKConfig zkConfig, + String metricName) { + this.clusterPhyId = clusterPhyId; + this.zkAddressList = zkAddressList; + this.zkConfig = zkConfig; + this.metricName = metricName; + } + + public ZookeeperMetricParam(Long clusterPhyId, + List> zkAddressList, + ZKConfig zkConfig, + Integer kafkaControllerId, + String metricName) { + this.clusterPhyId = clusterPhyId; + this.zkAddressList = zkAddressList; + this.zkConfig = zkConfig; + this.kafkaControllerId = kafkaControllerId; + this.metricName = metricName; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/version/VersionMetricControlItem.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/version/VersionMetricControlItem.java index c7409104..5c3f6506 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/version/VersionMetricControlItem.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/version/VersionMetricControlItem.java @@ -23,6 +23,8 @@ public class VersionMetricControlItem extends VersionControlItem{ public static final String CATEGORY_PERFORMANCE = "Performance"; public static final String CATEGORY_FLOW = "Flow"; + public static final String CATEGORY_CLIENT = "Client"; + /** * 指标单位名称,非指标的没有 */ diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/BaseMetricEvent.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/BaseMetricEvent.java index df1fe834..cfe5995a 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/BaseMetricEvent.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/BaseMetricEvent.java @@ -8,8 +8,6 @@ import org.springframework.context.ApplicationEvent; */ @Getter public class BaseMetricEvent extends ApplicationEvent { - - public BaseMetricEvent(Object source) { super( source ); } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/ZookeeperMetricEvent.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/ZookeeperMetricEvent.java new file mode 100644 index 00000000..19279d53 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/ZookeeperMetricEvent.java @@ -0,0 +1,20 @@ +package com.xiaojukeji.know.streaming.km.common.bean.event.metric; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import lombok.Getter; + +import java.util.List; + +/** + * @author didi + */ +@Getter +public class ZookeeperMetricEvent extends BaseMetricEvent { + + private List zookeeperMetrics; + + public ZookeeperMetricEvent(Object source, List zookeeperMetrics) { + super( source ); + this.zookeeperMetrics = zookeeperMetrics; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/metrice/ZookeeperMetricPO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/metrice/ZookeeperMetricPO.java new file mode 100644 index 00000000..96921739 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/metrice/ZookeeperMetricPO.java @@ -0,0 +1,24 @@ +package com.xiaojukeji.know.streaming.km.common.bean.po.metrice; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import static com.xiaojukeji.know.streaming.km.common.utils.CommonUtils.monitorTimestamp2min; + +@Data +@NoArgsConstructor +public class ZookeeperMetricPO extends BaseMetricESPO { + public ZookeeperMetricPO(Long clusterPhyId){ + super(clusterPhyId); + } + + @Override + public String getKey() { + return "ZK@" + clusterPhyId + "@" + monitorTimestamp2min(timestamp); + } + + @Override + public String getRoutingValue() { + return String.valueOf(clusterPhyId); + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/metrics/line/MetricMultiLinesVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/metrics/line/MetricMultiLinesVO.java index a3874292..917769d2 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/metrics/line/MetricMultiLinesVO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/metrics/line/MetricMultiLinesVO.java @@ -1,16 +1,12 @@ package com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line; -import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; /** * @author didi @@ -26,19 +22,4 @@ public class MetricMultiLinesVO { @ApiModelProperty(value = "指标名称对应的指标线") private List metricLines; - - public List getMetricPoints(String resName) { - if (ValidateUtils.isNull(metricLines)) { - return new ArrayList<>(); - } - - List voList = metricLines.stream().filter(elem -> elem.getName().equals(resName)).collect(Collectors.toList()); - if (ValidateUtils.isEmptyList(voList)) { - return new ArrayList<>(); - } - - // 仅获取idx=0的指标 - return voList.get(0).getMetricPoints(); - } - } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESConstant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESConstant.java index af8bd2c3..1b8a7740 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESConstant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESConstant.java @@ -34,6 +34,8 @@ public class ESConstant { public static final String TOTAL = "total"; + public static final Integer DEFAULT_RETRY_TIME = 3; + private ESConstant() { } } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java index 0de516f7..64aef24f 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java @@ -644,4 +644,89 @@ public class ESIndexConstant { " \"aliases\" : { }\n" + " }"; + public final static String ZOOKEEPER_INDEX = "ks_kafka_zookeeper_metric"; + public final static String ZOOKEEPER_TEMPLATE = "{\n" + + " \"order\" : 10,\n" + + " \"index_patterns\" : [\n" + + " \"ks_kafka_zookeeper_metric*\"\n" + + " ],\n" + + " \"settings\" : {\n" + + " \"index\" : {\n" + + " \"number_of_shards\" : \"10\"\n" + + " }\n" + + " },\n" + + " \"mappings\" : {\n" + + " \"properties\" : {\n" + + " \"routingValue\" : {\n" + + " \"type\" : \"text\",\n" + + " \"fields\" : {\n" + + " \"keyword\" : {\n" + + " \"ignore_above\" : 256,\n" + + " \"type\" : \"keyword\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"clusterPhyId\" : {\n" + + " \"type\" : \"long\"\n" + + " },\n" + + " \"metrics\" : {\n" + + " \"properties\" : {\n" + + " \"AvgRequestLatency\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"MinRequestLatency\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"MaxRequestLatency\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"OutstandingRequests\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"NodeCount\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"WatchCount\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"NumAliveConnections\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"PacketsReceived\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"PacketsSent\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"EphemeralsCount\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"ApproximateDataSize\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"OpenFileDescriptorCount\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"MaxFileDescriptorCount\" : {\n" + + " \"type\" : \"double\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"key\" : {\n" + + " \"type\" : \"text\",\n" + + " \"fields\" : {\n" + + " \"keyword\" : {\n" + + " \"ignore_above\" : 256,\n" + + " \"type\" : \"keyword\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"timestamp\" : {\n" + + " \"format\" : \"yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis\",\n" + + " \"type\" : \"date\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"aliases\" : { }\n" + + " }"; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/version/VersionItemTypeEnum.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/version/VersionItemTypeEnum.java index 15f13175..004dad6d 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/version/VersionItemTypeEnum.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/version/VersionItemTypeEnum.java @@ -9,7 +9,9 @@ public enum VersionItemTypeEnum { METRIC_GROUP(102, "group_metric"), METRIC_BROKER(103, "broker_metric"), METRIC_PARTITION(104, "partition_metric"), - METRIC_REPLICATION (105, "replication_metric"), + METRIC_REPLICATION(105, "replication_metric"), + + METRIC_ZOOKEEPER(110, "zookeeper_metric"), /** * 服务端查询 diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxAttribute.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxAttribute.java index cc7bfcb4..a9bea1c3 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxAttribute.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxAttribute.java @@ -22,6 +22,12 @@ public class JmxAttribute { public static final String PERCENTILE_99 = "99thPercentile"; + public static final String MAX = "Max"; + + public static final String MEAN = "Mean"; + + public static final String MIN = "Min"; + public static final String VALUE = "Value"; public static final String CONNECTION_COUNT = "connection-count"; diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxName.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxName.java index d2d1651e..db8b3197 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxName.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxName.java @@ -63,6 +63,12 @@ public class JmxName { /*********************************************************** cluster ***********************************************************/ public static final String JMX_CLUSTER_PARTITION_UNDER_REPLICATED = "kafka.cluster:type=Partition,name=UnderReplicated"; + /*********************************************************** zookeeper ***********************************************************/ + + public static final String JMX_ZK_REQUEST_LATENCY_MS = "kafka.server:type=ZooKeeperClientMetrics,name=ZooKeeperRequestLatencyMs"; + public static final String JMX_ZK_SYNC_CONNECTS_PER_SEC = "kafka.server:type=SessionExpireListener,name=ZooKeeperSyncConnectsPerSec"; + public static final String JMX_ZK_DISCONNECTORS_PER_SEC = "kafka.server:type=SessionExpireListener,name=ZooKeeperDisconnectsPerSec"; + private JmxName() { } } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java index fbede23c..7fc4f4f2 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java @@ -343,17 +343,9 @@ public class BrokerServiceImpl extends BaseVersionControlService implements Brok private Broker getStartTimeAndBuildBroker(Long clusterPhyId, Node newNode, JmxConfig jmxConfig) { try { - Object object = jmxDAO.getJmxValue( - clusterPhyId, - newNode.id(), - newNode.host(), - null, - jmxConfig, - new ObjectName("java.lang:type=Runtime"), - "StartTime" - ); + Long startTime = jmxDAO.getServerStartTime(clusterPhyId, newNode.host(), null, jmxConfig); - return Broker.buildFrom(clusterPhyId, newNode, object != null? (Long) object: null); + return Broker.buildFrom(clusterPhyId, newNode, startTime); } catch (Exception e) { log.error("class=BrokerServiceImpl||method=getStartTimeAndBuildBroker||clusterPhyId={}||brokerNode={}||jmxConfig={}||errMsg=exception!", clusterPhyId, newNode, jmxConfig, e); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ZookeeperMetricVersionItems.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ZookeeperMetricVersionItems.java new file mode 100644 index 00000000..9b0d4d2b --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ZookeeperMetricVersionItems.java @@ -0,0 +1,141 @@ +package com.xiaojukeji.know.streaming.km.core.service.version.metrics; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionMetricControlItem; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +import static com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionMetricControlItem.*; +import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum.METRIC_ZOOKEEPER; +import static com.xiaojukeji.know.streaming.km.common.jmx.JmxAttribute.*; +import static com.xiaojukeji.know.streaming.km.common.jmx.JmxName.*; +import static com.xiaojukeji.know.streaming.km.core.service.zookeeper.impl.ZookeeperMetricServiceImpl.*; + +@Component +public class ZookeeperMetricVersionItems extends BaseMetricVersionMetric { + + /** + * 性能 + */ + public static final String ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY = "AvgRequestLatency"; + public static final String ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY = "MinRequestLatency"; + public static final String ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY = "MaxRequestLatency"; + public static final String ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS = "OutstandingRequests"; + public static final String ZOOKEEPER_METRIC_NODE_COUNT = "NodeCount"; + public static final String ZOOKEEPER_METRIC_WATCH_COUNT = "WatchCount"; + public static final String ZOOKEEPER_METRIC_NUM_ALIVE_CONNECTIONS = "NumAliveConnections"; + public static final String ZOOKEEPER_METRIC_PACKETS_RECEIVED = "PacketsReceived"; + public static final String ZOOKEEPER_METRIC_PACKETS_SENT = "PacketsSent"; + public static final String ZOOKEEPER_METRIC_EPHEMERALS_COUNT = "EphemeralsCount"; + public static final String ZOOKEEPER_METRIC_APPROXIMATE_DATA_SIZE = "ApproximateDataSize"; + public static final String ZOOKEEPER_METRIC_OPEN_FILE_DESCRIPTOR_COUNT = "OpenFileDescriptorCount"; + public static final String ZOOKEEPER_METRIC_MAX_FILE_DESCRIPTOR_COUNT = "MaxFileDescriptorCount"; + + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_DISCONNECTS_PER_SEC = "KafkaZKDisconnectsPerSec"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_SYNC_CONNECTS_PER_SEC = "KafkaZKSyncConnectsPerSec"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_99TH = "KafkaZKRequestLatencyMs_99thPercentile"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MAX = "KafkaZKRequestLatencyMs_Max"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MEAN = "KafkaZKRequestLatencyMs_Mean"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MIN = "KafkaZKRequestLatencyMs_Min"; + + + public static final String ZOOKEEPER_METRIC_COLLECT_COST_TIME = Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME; + + @Override + public int versionItemType() { + return METRIC_ZOOKEEPER.getCode(); + } + + @Override + public List init(){ + List items = new ArrayList<>(); + + // 性能指标 + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY).unit("ms").desc("平均响应延迟").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY).unit("ms").desc("最小响应延迟").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY).unit("ms").desc("最大响应延迟").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS).unit("个").desc("堆积请求数").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_NODE_COUNT).unit("个").desc("ZNode数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_WATCH_COUNT).unit("个").desc("Watch数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_NUM_ALIVE_CONNECTIONS).unit("个").desc("客户端连接数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_PACKETS_RECEIVED).unit("个").desc("接受包的数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_PACKETS_SENT).unit("个").desc("发送包的数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_EPHEMERALS_COUNT).unit("个").desc("临时节点数").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_APPROXIMATE_DATA_SIZE).unit("byte").desc("文件大小(近似值)").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_OPEN_FILE_DESCRIPTOR_COUNT).unit("个").desc("已打开的文件描述符数").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_MAX_FILE_DESCRIPTOR_COUNT).unit("个").desc("允许打开的最大文件描述符数").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + // JMX指标 + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_99TH).unit("ms").desc("ZK请求99分位延迟").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_REQUEST_LATENCY_MS ).jmxAttribute(PERCENTILE_99))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MAX).unit("ms").desc("ZK请求最大延迟").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_REQUEST_LATENCY_MS ).jmxAttribute(MAX))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MIN).unit("ms").desc("ZK请求最小延迟").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_REQUEST_LATENCY_MS ).jmxAttribute(MIN))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MEAN).unit("ms").desc("ZK请求平均延迟").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_REQUEST_LATENCY_MS ).jmxAttribute(MEAN))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_DISCONNECTS_PER_SEC).unit("个").desc("断开连接数").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_DISCONNECTORS_PER_SEC ).jmxAttribute(RATE_MIN_1))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_SYNC_CONNECTS_PER_SEC).unit("个").desc("同步连接数").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_SYNC_CONNECTS_PER_SEC ).jmxAttribute(RATE_MIN_1))); + return items; + } +} + diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperMetricService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperMetricService.java new file mode 100644 index 00000000..2dc48851 --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperMetricService.java @@ -0,0 +1,21 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric.ZookeeperMetricParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line.MetricLineVO; + +import java.util.List; + +public interface ZookeeperMetricService { + /** + * ZK指标获取 + * @param param 参数,因为ZK 四字命令在使用时,是短连接,所以参数内容会复杂一些,后续可以考虑优化为长连接 + * @return + */ + Result collectMetricsFromZookeeper(ZookeeperMetricParam param); + Result batchCollectMetricsFromZookeeper(Long clusterPhyId, List metricNameList); + + Result> listMetricsFromES(Long clusterPhyId, MetricDTO dto); +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java new file mode 100644 index 00000000..dea1d877 --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java @@ -0,0 +1,281 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper.impl; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.VersionItemParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric.ZookeeperMetricParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionJmxInfo; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.ServerCmdData; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.MonitorCmdDataParser; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.ServerCmdDataParser; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line.MetricLineVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; +import com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum; +import com.xiaojukeji.know.streaming.km.common.exception.VCHandlerNotExistException; +import com.xiaojukeji.know.streaming.km.common.jmx.JmxConnectorWrap; +import com.xiaojukeji.know.streaming.km.common.utils.*; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.MonitorCmdData; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ZookeeperMetricPO; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; +import com.xiaojukeji.know.streaming.km.core.service.kafkacontroller.KafkaControllerService; +import com.xiaojukeji.know.streaming.km.core.service.version.BaseMetricService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperMetricService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import com.xiaojukeji.know.streaming.km.persistence.es.dao.ZookeeperMetricESDAO; +import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaJMXClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.management.ObjectName; +import java.util.*; +import java.util.stream.Collectors; + +import static com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus.*; +import static com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus.VC_JMX_CONNECT_ERROR; +import static com.xiaojukeji.know.streaming.km.core.service.version.metrics.ZookeeperMetricVersionItems.*; + + +@Service +public class ZookeeperMetricServiceImpl extends BaseMetricService implements ZookeeperMetricService { + private static final ILog LOGGER = LogFactory.getLog(ZookeeperMetricServiceImpl.class); + + public static final String ZOOKEEPER_METHOD_DO_NOTHING = "doNothing"; + public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD = "getMetricFromMonitorCmd"; + public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD = "getMetricFromServerCmd"; + public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX = "getMetricFromKafkaByJMX"; + + @Autowired + private ClusterPhyService clusterPhyService; + + @Autowired + private ZookeeperService zookeeperService; + + @Autowired + private ZookeeperMetricESDAO zookeeperMetricESDAO; + + @Autowired + private KafkaJMXClient kafkaJMXClient; + + @Autowired + private KafkaControllerService kafkaControllerService; + + @Override + protected VersionItemTypeEnum getVersionItemType() { + return VersionItemTypeEnum.METRIC_ZOOKEEPER; + } + + @Override + protected List listMetricPOFields(){ + return BeanUtil.listBeanFields(ZookeeperMetricPO.class); + } + + @Override + protected void initRegisterVCHandler(){ + registerVCHandler( ZOOKEEPER_METHOD_DO_NOTHING, this::doNothing); + registerVCHandler( ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD, this::getMetricFromMonitorCmd); + registerVCHandler( ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD, this::getMetricFromServerCmd); + registerVCHandler( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX, this::getMetricFromKafkaByJMX); + } + + @Override + public Result collectMetricsFromZookeeper(ZookeeperMetricParam param) { + try { + return (Result)doVCHandler(param.getClusterPhyId(), param.getMetricName(), param); + } catch (VCHandlerNotExistException e) { + return Result.buildFailure(VC_HANDLE_NOT_EXIST); + } + } + + @Override + public Result batchCollectMetricsFromZookeeper(Long clusterPhyId, List metricNameList) { + ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(clusterPhyId); + if (null == clusterPhy) { + return Result.buildFromRSAndMsg(ResultStatus.CLUSTER_NOT_EXIST, MsgConstant.getClusterPhyNotExist(clusterPhyId)); + } + + List aliveZKList = zookeeperService.listFromDBByCluster(clusterPhyId).stream() + .filter(elem -> Constant.ALIVE.equals(elem.getStatus())) + .collect(Collectors.toList()); + + if (ValidateUtils.isEmptyList(aliveZKList)) { + // 没有指标可以获取 + return Result.buildSuc(new ZookeeperMetrics(clusterPhyId)); + } + + // 构造参数 + ZookeeperMetricParam param = new ZookeeperMetricParam( + clusterPhyId, + aliveZKList.stream().map(elem -> new Tuple(elem.getHost(), elem.getPort())).collect(Collectors.toList()), + ConvertUtil.str2ObjByJson(clusterPhy.getZkProperties(), ZKConfig.class), + null + ); + + ZookeeperMetrics metrics = new ZookeeperMetrics(clusterPhyId); + for(String metricName : metricNameList) { + try { + if(metrics.getMetrics().containsKey(metricName)) { + continue; + } + param.setMetricName(metricName); + + Result ret = this.collectMetricsFromZookeeper(param); + if(null == ret || ret.failed() || null == ret.getData()){ + continue; + } + + metrics.putMetric(ret.getData().getMetrics()); + } catch (Exception e){ + LOGGER.error( + "class=ZookeeperMetricServiceImpl||method=collectMetricsFromZookeeper||clusterPhyId={}||metricName={}||errMsg=exception!", + clusterPhyId, metricName, e + ); + } + } + + return Result.buildSuc(metrics); + } + + @Override + public Result> listMetricsFromES(Long clusterPhyId, MetricDTO dto) { + Map> pointVOMap = zookeeperMetricESDAO.listMetricsByClusterPhyId( + clusterPhyId, + dto.getMetricsNames(), + dto.getAggType(), + dto.getStartTime(), + dto.getEndTime() + ); + + // 格式转化 + List voList = new ArrayList<>(); + pointVOMap.entrySet().stream().forEach(entry -> + voList.add(new MetricLineVO(String.valueOf(clusterPhyId), entry.getKey(), entry.getValue())) + ); + return Result.buildSuc(voList); + } + + + /**************************************************** private method ****************************************************/ + + private Result getMetricFromServerCmd(VersionItemParam metricParam) { + ZookeeperMetricParam param = (ZookeeperMetricParam)metricParam; + + Result rz = null; + for (Tuple hostPort: param.getZkAddressList()) { + Result cmdDataResult = FourLetterWordUtil.executeFourLetterCmd( + param.getClusterPhyId(), + hostPort.getV1(), + hostPort.getV2(), + param.getZkConfig() != null ? param.getZkConfig().getOpenSecure(): false, + param.getZkConfig() != null ? param.getZkConfig().getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, + new ServerCmdDataParser() + ); + + if (cmdDataResult.failed()) { + rz = Result.buildFromIgnoreData(cmdDataResult); + continue; + } + + ServerCmdData cmdData = cmdDataResult.getData(); + + ZookeeperMetrics metrics = new ZookeeperMetrics(param.getClusterPhyId()); + metrics.putMetric(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY, cmdData.getZkAvgLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY, cmdData.getZkMinLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY, cmdData.getZkMaxLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS, cmdData.getZkOutstandingRequests().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_NODE_COUNT, cmdData.getZkZnodeCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_NUM_ALIVE_CONNECTIONS, cmdData.getZkNumAliveConnections().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_PACKETS_RECEIVED, cmdData.getZkPacketsReceived().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_PACKETS_SENT, cmdData.getZkPacketsSent().floatValue()); + + return Result.buildSuc(metrics); + } + + return rz != null? rz: Result.buildSuc(new ZookeeperMetrics(param.getClusterPhyId())); + } + + private Result getMetricFromMonitorCmd(VersionItemParam metricParam) { + ZookeeperMetricParam param = (ZookeeperMetricParam)metricParam; + + Result rz = null; + for (Tuple hostPort: param.getZkAddressList()) { + Result cmdDataResult = FourLetterWordUtil.executeFourLetterCmd( + param.getClusterPhyId(), + hostPort.getV1(), + hostPort.getV2(), + param.getZkConfig() != null ? param.getZkConfig().getOpenSecure(): false, + param.getZkConfig() != null ? param.getZkConfig().getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, + new MonitorCmdDataParser() + ); + + if (cmdDataResult.failed()) { + rz = Result.buildFromIgnoreData(cmdDataResult); + continue; + } + + MonitorCmdData cmdData = cmdDataResult.getData(); + + ZookeeperMetrics metrics = new ZookeeperMetrics(param.getClusterPhyId()); + metrics.putMetric(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY, cmdData.getZkAvgLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY, cmdData.getZkMinLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY, cmdData.getZkMaxLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS, cmdData.getZkOutstandingRequests().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_NODE_COUNT, cmdData.getZkZnodeCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_WATCH_COUNT, cmdData.getZkWatchCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_NUM_ALIVE_CONNECTIONS, cmdData.getZkNumAliveConnections().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_PACKETS_RECEIVED, cmdData.getZkPacketsReceived().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_PACKETS_SENT, cmdData.getZkPacketsSent().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_EPHEMERALS_COUNT, cmdData.getZkEphemeralsCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_APPROXIMATE_DATA_SIZE, cmdData.getZkApproximateDataSize().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_OPEN_FILE_DESCRIPTOR_COUNT, cmdData.getZkOpenFileDescriptorCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_MAX_FILE_DESCRIPTOR_COUNT, cmdData.getZkMaxFileDescriptorCount().floatValue()); + + return Result.buildSuc(metrics); + } + + return rz != null? rz: Result.buildSuc(new ZookeeperMetrics(param.getClusterPhyId())); + } + + private Result doNothing(VersionItemParam metricParam) { + ZookeeperMetricParam param = (ZookeeperMetricParam)metricParam; + return Result.buildSuc(new ZookeeperMetrics(param.getClusterPhyId())); + } + + private Result getMetricFromKafkaByJMX(VersionItemParam metricParam) { + ZookeeperMetricParam param = (ZookeeperMetricParam)metricParam; + + String metricName = param.getMetricName(); + Long clusterPhyId = param.getClusterPhyId(); + Integer kafkaControllerId = param.getKafkaControllerId(); + + //1、获取jmx的属性信息 + VersionJmxInfo jmxInfo = getJMXInfo(clusterPhyId, metricName); + if(null == jmxInfo) { + return Result.buildFailure(VC_ITEM_JMX_NOT_EXIST); + } + + //2、获取jmx连接 + JmxConnectorWrap jmxConnectorWrap = kafkaJMXClient.getClientWithCheck(clusterPhyId, kafkaControllerId); + if (ValidateUtils.isNull(jmxConnectorWrap)) { + return Result.buildFailure(VC_JMX_INIT_ERROR); + } + + try { + //2、获取jmx指标 + String value = jmxConnectorWrap.getAttribute(new ObjectName(jmxInfo.getJmxObjectName()), jmxInfo.getJmxAttribute()).toString(); + + return Result.buildSuc(ZookeeperMetrics.initWithMetric(clusterPhyId, metricName, Float.valueOf(value))); + } catch (Exception e) { + return Result.buildFailure(VC_JMX_CONNECT_ERROR); + } + } +} diff --git a/km-dist/init/template/ks_kafka_zookeeper_metric b/km-dist/init/template/ks_kafka_zookeeper_metric new file mode 100644 index 00000000..abb54a61 --- /dev/null +++ b/km-dist/init/template/ks_kafka_zookeeper_metric @@ -0,0 +1,85 @@ +PUT _template/ks_kafka_zookeeper_metric +{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + } \ No newline at end of file diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BaseMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BaseMetricESDAO.java index a6615fbc..faeb64cb 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BaseMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BaseMetricESDAO.java @@ -40,8 +40,7 @@ public class BaseMetricESDAO extends BaseESDAO { /** * 不同维度 kafka 监控数据 */ - private static Map ariusStatsEsDaoMap = Maps - .newConcurrentMap(); + private static Map ariusStatsEsDaoMap = Maps.newConcurrentMap(); /** * 检查 es 索引是否存在,不存在则创建索引 diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ZookeeperMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ZookeeperMetricESDAO.java new file mode 100644 index 00000000..8b391a3a --- /dev/null +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ZookeeperMetricESDAO.java @@ -0,0 +1,106 @@ +package com.xiaojukeji.know.streaming.km.persistence.es.dao; + +import com.didiglobal.logi.elasticsearch.client.response.query.query.ESQueryResponse; +import com.didiglobal.logi.elasticsearch.client.response.query.query.aggs.ESAggr; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; +import com.xiaojukeji.know.streaming.km.common.constant.ESConstant; +import com.xiaojukeji.know.streaming.km.common.utils.MetricsUtils; +import com.xiaojukeji.know.streaming.km.persistence.es.dsls.DslsConstant; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.xiaojukeji.know.streaming.km.common.constant.ESConstant.*; +import static com.xiaojukeji.know.streaming.km.common.constant.ESIndexConstant.ZOOKEEPER_INDEX; +import static com.xiaojukeji.know.streaming.km.common.constant.ESIndexConstant.ZOOKEEPER_TEMPLATE; + +@Component +public class ZookeeperMetricESDAO extends BaseMetricESDAO { + + @PostConstruct + public void init() { + super.indexName = ZOOKEEPER_INDEX; + super.indexTemplate = ZOOKEEPER_TEMPLATE; + checkCurrentDayIndexExist(); + BaseMetricESDAO.register(indexName, this); + } + + /** + * 获取指定集群,指定指标,一段时间内的值 + */ + public Map> listMetricsByClusterPhyId(Long clusterPhyId, + List metricNameList, + String aggType, + Long startTime, + Long endTime) { + //1、获取需要查下的索引 + String realIndex = realIndex(startTime, endTime); + + //2、根据查询的时间区间大小来确定指标点的聚合区间大小 + String interval = MetricsUtils.getInterval(endTime - startTime); + + //3、构造agg查询条件 + String aggDsl = buildAggsDSL(metricNameList, aggType); + + //4、构造dsl查询条件,开始查询 + try { + String dsl = dslLoaderUtil.getFormatDslByFileName( + DslsConstant.GET_ZOOKEEPER_AGG_LIST_METRICS, clusterPhyId, startTime, endTime, interval, aggDsl); + + return esOpClient.performRequestWithRouting( + String.valueOf(clusterPhyId), + realIndex, + dsl, + s -> handleListESQueryResponse(s, metricNameList, aggType), + ESConstant.DEFAULT_RETRY_TIME + ); + } catch (Exception e){ + LOGGER.error("class=ZookeeperMetricESDAO||method=listMetricsByClusterPhyId||clusterPhyId={}||errMsg=exception!", + clusterPhyId, e + ); + } + + return new HashMap<>(); + } + + /**************************************************** private method ****************************************************/ + + private Map> handleListESQueryResponse(ESQueryResponse response, List metrics, String aggType){ + Map esAggrMap = checkBucketsAndHitsOfResponseAggs(response); + if(null == esAggrMap) { + return new HashMap<>(); + } + + Map> metricMap = new HashMap<>(); + for(String metric : metrics){ + List metricPoints = new ArrayList<>(); + + esAggrMap.get(HIST).getBucketList().forEach( esBucket -> { + try { + if (null != esBucket.getUnusedMap().get(KEY)) { + Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); + String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + + MetricPointVO metricPoint = new MetricPointVO(); + metricPoint.setAggType(aggType); + metricPoint.setTimeStamp(timestamp); + metricPoint.setValue(value); + metricPoint.setName(metric); + + metricPoints.add(metricPoint); + } + }catch (Exception e){ + LOGGER.error("method=handleESQueryResponse||metric={}||errMsg=exception!", metric, e); + } + } ); + + metricMap.put(metric, optimizeMetricPoints(metricPoints)); + } + + return metricMap; + } +} diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java index 3f158f36..94a8698e 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java @@ -80,4 +80,6 @@ public class DslsConstant { public static final String COUNT_GROUP_NOT_METRIC_VALUE = "GroupMetricESDAO/countGroupNotMetricValue"; + /**************************************************** Zookeeper ****************************************************/ + public static final String GET_ZOOKEEPER_AGG_LIST_METRICS = "ZookeeperMetricESDAO/getAggListZookeeperMetrics"; } diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/JmxDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/JmxDAO.java index a3747c0a..017bcf04 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/JmxDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/JmxDAO.java @@ -12,5 +12,7 @@ import javax.management.ObjectName; public interface JmxDAO { Object getJmxValue(String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute); - Object getJmxValue(Long clusterPhyId, Integer brokerId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute); + Object getJmxValue(Long clusterPhyId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute); + + Long getServerStartTime(Long clusterPhyId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig); } diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/impl/JmxDAOImpl.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/impl/JmxDAOImpl.java index ec8349cc..77eb3252 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/impl/JmxDAOImpl.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/impl/JmxDAOImpl.java @@ -19,24 +19,28 @@ public class JmxDAOImpl implements JmxDAO { @Override public Object getJmxValue(String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute) { - return this.getJmxValue(null, null, jmxHost, jmxPort, jmxConfig, objectName, attribute); + return this.getJmxValue(null, jmxHost, jmxPort, jmxConfig, objectName, attribute); } @Override - public Object getJmxValue(Long clusterPhyId, Integer brokerId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute) { + public Object getJmxValue(Long clusterPhyId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute) { JmxConnectorWrap jmxConnectorWrap = null; try { - jmxConnectorWrap = new JmxConnectorWrap(clusterPhyId, brokerId, null, jmxHost, jmxPort, jmxConfig); + jmxConnectorWrap = new JmxConnectorWrap(clusterPhyId, null, null, jmxHost, jmxPort, jmxConfig); if (!jmxConnectorWrap.checkJmxConnectionAndInitIfNeed()) { - log.error("method=getJmxValue||clusterPhyId={}||brokerId={}||jmxHost={}||jmxPort={}||jmxConfig={}||errMgs=create jmx client failed", - clusterPhyId, brokerId, jmxHost, jmxPort, jmxConfig); + log.error( + "method=getJmxValue||clusterPhyId={}||jmxHost={}||jmxPort={}||jmxConfig={}||errMgs=create jmx client failed", + clusterPhyId, jmxHost, jmxPort, jmxConfig + ); return null; } return jmxConnectorWrap.getAttribute(objectName, attribute); } catch (Exception e) { - log.error("method=getJmxValue||clusterPhyId={}||brokerId={}||jmxHost={}||jmxPort={}||jmxConfig={}||objectName={}||attribute={}||msg=get attribute failed||errMsg={}", - clusterPhyId, brokerId, jmxHost, jmxPort, jmxConfig, objectName, attribute, e); + log.error( + "method=getJmxValue||clusterPhyId={}||jmxHost={}||jmxPort={}||jmxConfig={}||objectName={}||attribute={}||msg=get attribute failed||errMsg=exception!", + clusterPhyId, jmxHost, jmxPort, jmxConfig, objectName, attribute, e + ); } finally { if (jmxConnectorWrap != null) { jmxConnectorWrap.close(); @@ -45,4 +49,27 @@ public class JmxDAOImpl implements JmxDAO { return null; } + + @Override + public Long getServerStartTime(Long clusterPhyId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig) { + try { + Object object = this.getJmxValue( + clusterPhyId, + jmxHost, + jmxPort, + jmxConfig, + new ObjectName("java.lang:type=Runtime"), + "StartTime" + ); + + return object == null? null: (Long) object; + } catch (Exception e) { + log.error( + "class=JmxDAOImpl||method=getServerStartTime||clusterPhyId={}||jmxHost={}||jmxPort={}||jmxConfig={}||errMsg=exception!", + clusterPhyId, jmxHost, jmxPort, jmxConfig, e + ); + } + + return null; + } } diff --git a/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics b/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics new file mode 100644 index 00000000..c05c221d --- /dev/null +++ b/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics @@ -0,0 +1,44 @@ +{ + "size": 0, + "query": { + "bool": { + "must": [ + { + "term": { + "clusterPhyId": { + "value": %d + } + } + }, + { + "term": { + "brokerId": { + "value": %d + } + } + }, + { + "range": { + "timestamp": { + "gte": %d, + "lte": %d + } + } + } + ] + } + }, + "aggs": { + "hist": { + "date_histogram": { + "field": "timestamp", + "fixed_interval": "%s", + "time_zone": "Asia/Shanghai", + "min_doc_count": 0 + }, + "aggs": { + %s + } + } + } +} \ No newline at end of file diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ZookeeperMetricCollectorTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ZookeeperMetricCollectorTask.java new file mode 100644 index 00000000..f533a30a --- /dev/null +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ZookeeperMetricCollectorTask.java @@ -0,0 +1,33 @@ +package com.xiaojukeji.know.streaming.km.task.metrics; + +import com.didiglobal.logi.job.annotation.Task; +import com.didiglobal.logi.job.common.TaskResult; +import com.didiglobal.logi.job.core.consensual.ConsensualEnum; +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.collector.metric.ZookeeperMetricCollector; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author didi + */ +@Task(name = "ZookeeperMetricCollectorTask", + description = "Zookeeper指标采集任务", + cron = "0 0/1 * * * ? *", + autoRegister = true, + consensual = ConsensualEnum.BROADCAST, + timeout = 2 * 60) +public class ZookeeperMetricCollectorTask extends AbstractAsyncMetricsDispatchTask { + private static final ILog log = LogFactory.getLog(ZookeeperMetricCollectorTask.class); + + @Autowired + private ZookeeperMetricCollector zookeeperMetricCollector; + + @Override + public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception { + zookeeperMetricCollector.collectMetrics(clusterPhy); + + return TaskResult.SUCCESS; + } +} From 6c610427b6e1fe975070f47875419af65378cfd3 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Sat, 8 Oct 2022 15:46:18 +0800 Subject: [PATCH 012/145] =?UTF-8?q?ZK-=E5=A2=9E=E5=8A=A0ZK=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../biz/cluster/ClusterZookeepersManager.java | 19 +++ .../impl/ClusterZookeepersManagerImpl.java | 137 ++++++++++++++++++ .../cluster/ClusterZookeepersOverviewDTO.java | 13 ++ .../common/bean/entity/zookeeper/Znode.java | 19 +++ .../ClusterZookeepersOverviewVO.java | 26 ++++ .../zookeeper/ClusterZookeepersStateVO.java | 47 ++++++ .../common/bean/vo/zookeeper/ZnodeStatVO.java | 44 ++++++ .../km/common/bean/vo/zookeeper/ZnodeVO.java | 22 +++ .../km/common/converter/ZnodeConverter.java | 19 +++ .../core/service/zookeeper/ZnodeService.java | 13 ++ .../zookeeper/impl/ZnodeServiceImpl.java | 81 +++++++++++ .../cluster/ClusterZookeepersController.java | 63 ++++++++ .../api/v3/zk/ZookeeperMetricsController.java | 52 +++++++ 13 files changed, 555 insertions(+) create mode 100644 km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterZookeepersManager.java create mode 100644 km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterZookeepersManagerImpl.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterZookeepersOverviewDTO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/Znode.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersStateVO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeStatVO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeVO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/ZnodeConverter.java create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZnodeService.java create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZnodeServiceImpl.java create mode 100644 km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterZookeepersController.java create mode 100644 km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/zk/ZookeeperMetricsController.java diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterZookeepersManager.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterZookeepersManager.java new file mode 100644 index 00000000..8219cd7e --- /dev/null +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterZookeepersManager.java @@ -0,0 +1,19 @@ +package com.xiaojukeji.know.streaming.km.biz.cluster; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterZookeepersOverviewDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersOverviewVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersStateVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ZnodeVO; + +/** + * 多集群总体状态 + */ +public interface ClusterZookeepersManager { + Result getClusterPhyZookeepersState(Long clusterPhyId); + + PaginationResult getClusterPhyZookeepersOverview(Long clusterPhyId, ClusterZookeepersOverviewDTO dto); + + Result getZnodeVO(Long clusterPhyId, String path); +} diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterZookeepersManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterZookeepersManagerImpl.java new file mode 100644 index 00000000..b285cac9 --- /dev/null +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterZookeepersManagerImpl.java @@ -0,0 +1,137 @@ +package com.xiaojukeji.know.streaming.km.biz.cluster.impl; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.biz.cluster.ClusterZookeepersManager; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterZookeepersOverviewDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric.ZookeeperMetricParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.Znode; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersOverviewVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersStateVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ZnodeVO; +import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; +import com.xiaojukeji.know.streaming.km.common.enums.zookeeper.ZKRoleEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.utils.PaginationUtil; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; +import com.xiaojukeji.know.streaming.km.core.service.version.metrics.ZookeeperMetricVersionItems; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZnodeService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperMetricService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + + +@Service +public class ClusterZookeepersManagerImpl implements ClusterZookeepersManager { + private static final ILog LOGGER = LogFactory.getLog(ClusterZookeepersManagerImpl.class); + + @Autowired + private ClusterPhyService clusterPhyService; + + @Autowired + private ZookeeperService zookeeperService; + + @Autowired + private ZookeeperMetricService zookeeperMetricService; + + @Autowired + private ZnodeService znodeService; + + @Override + public Result getClusterPhyZookeepersState(Long clusterPhyId) { + ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(clusterPhyId); + if (clusterPhy == null) { + return Result.buildFromRSAndMsg(ResultStatus.CLUSTER_NOT_EXIST, MsgConstant.getClusterPhyNotExist(clusterPhyId)); + } + +// // TODO +// private Integer healthState; +// private Integer healthCheckPassed; +// private Integer healthCheckTotal; + + List infoList = zookeeperService.listFromDBByCluster(clusterPhyId); + + ClusterZookeepersStateVO vo = new ClusterZookeepersStateVO(); + vo.setTotalServerCount(infoList.size()); + vo.setAliveFollowerCount(0); + vo.setTotalFollowerCount(0); + vo.setAliveObserverCount(0); + vo.setTotalObserverCount(0); + vo.setAliveServerCount(0); + for (ZookeeperInfo info: infoList) { + if (info.getRole().equals(ZKRoleEnum.LEADER.getRole())) { + vo.setLeaderNode(info.getHost()); + } + + if (info.getRole().equals(ZKRoleEnum.FOLLOWER.getRole())) { + vo.setTotalFollowerCount(vo.getTotalFollowerCount() + 1); + vo.setAliveFollowerCount(info.alive()? vo.getAliveFollowerCount() + 1: vo.getAliveFollowerCount()); + } + + if (info.getRole().equals(ZKRoleEnum.OBSERVER.getRole())) { + vo.setTotalObserverCount(vo.getTotalObserverCount() + 1); + vo.setAliveObserverCount(info.alive()? vo.getAliveObserverCount() + 1: vo.getAliveObserverCount()); + } + + if (info.alive()) { + vo.setAliveServerCount(vo.getAliveServerCount() + 1); + } + } + + Result metricsResult = zookeeperMetricService.collectMetricsFromZookeeper(new ZookeeperMetricParam( + clusterPhyId, + infoList.stream().filter(elem -> elem.alive()).map(item -> new Tuple(item.getHost(), item.getPort())).collect(Collectors.toList()), + ConvertUtil.str2ObjByJson(clusterPhy.getZkProperties(), ZKConfig.class), + ZookeeperMetricVersionItems.ZOOKEEPER_METRIC_WATCH_COUNT + )); + if (metricsResult.failed()) { + LOGGER.error( + "class=ClusterZookeepersManagerImpl||method=getClusterPhyZookeepersState||clusterPhyId={}||errMsg={}", + clusterPhyId, metricsResult.getMessage() + ); + return Result.buildSuc(vo); + } + Float watchCount = metricsResult.getData().getMetric(ZookeeperMetricVersionItems.ZOOKEEPER_METRIC_WATCH_COUNT); + vo.setWatchCount(watchCount != null? watchCount.intValue(): null); + + return Result.buildSuc(vo); + } + + @Override + public PaginationResult getClusterPhyZookeepersOverview(Long clusterPhyId, ClusterZookeepersOverviewDTO dto) { + //获取集群zookeeper列表 + List clusterZookeepersOverviewVOList = ConvertUtil.list2List(zookeeperService.listFromDBByCluster(clusterPhyId), ClusterZookeepersOverviewVO.class); + + //搜索 + clusterZookeepersOverviewVOList = PaginationUtil.pageByFuzzyFilter(clusterZookeepersOverviewVOList, dto.getSearchKeywords(), Arrays.asList("host")); + + //分页 + PaginationResult paginationResult = PaginationUtil.pageBySubData(clusterZookeepersOverviewVOList, dto); + + return paginationResult; + } + + @Override + public Result getZnodeVO(Long clusterPhyId, String path) { + Result result = znodeService.getZnode(clusterPhyId, path); + if (result.failed()) { + return Result.buildFromIgnoreData(result); + } + return Result.buildSuc(ConvertUtil.obj2ObjByJSON(result.getData(), ZnodeVO.class)); + } + + /**************************************************** private method ****************************************************/ + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterZookeepersOverviewDTO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterZookeepersOverviewDTO.java new file mode 100644 index 00000000..2b3a6e9d --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterZookeepersOverviewDTO.java @@ -0,0 +1,13 @@ +package com.xiaojukeji.know.streaming.km.common.bean.dto.cluster; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; +import lombok.Data; + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +public class ClusterZookeepersOverviewDTO extends PaginationBaseDTO { + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/Znode.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/Znode.java new file mode 100644 index 00000000..0bcb56d2 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/Znode.java @@ -0,0 +1,19 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper; + + +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.apache.zookeeper.data.Stat; + +@Data +public class Znode { + @ApiModelProperty(value = "节点名称", example = "broker") + private String name; + + @ApiModelProperty(value = "节点数据", example = "saassad") + private String data; + + @ApiModelProperty(value = "节点属性", example = "") + private Stat stat; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java new file mode 100644 index 00000000..960b5d5a --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java @@ -0,0 +1,26 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +@ApiModel(description = "Zookeeper信息概览") +public class ClusterZookeepersOverviewVO { + @ApiModelProperty(value = "主机ip", example = "121.0.0.1") + private String host; + + @ApiModelProperty(value = "端口号", example = "2416") + private Integer port; + + @ApiModelProperty(value = "版本", example = "1.1.2") + private String version; + + @ApiModelProperty(value = "角色", example = "Leader") + private String role; + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersStateVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersStateVO.java new file mode 100644 index 00000000..ceb2041f --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersStateVO.java @@ -0,0 +1,47 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +@ApiModel(description = "ZK状态信息") +public class ClusterZookeepersStateVO { + @ApiModelProperty(value = "健康检查状态", example = "1") + private Integer healthState; + + @ApiModelProperty(value = "健康检查通过数", example = "1") + private Integer healthCheckPassed; + + @ApiModelProperty(value = "健康检查总数", example = "1") + private Integer healthCheckTotal; + + @ApiModelProperty(value = "ZK的Leader机器", example = "127.0.0.1") + private String leaderNode; + + @ApiModelProperty(value = "Watch数", example = "123456") + private Integer watchCount; + + @ApiModelProperty(value = "节点存活数", example = "8") + private Integer aliveServerCount; + + @ApiModelProperty(value = "总节点数", example = "10") + private Integer totalServerCount; + + @ApiModelProperty(value = "Follower角色存活数", example = "8") + private Integer aliveFollowerCount; + + @ApiModelProperty(value = "Follower角色总数", example = "10") + private Integer totalFollowerCount; + + @ApiModelProperty(value = "Observer角色存活数", example = "3") + private Integer aliveObserverCount; + + @ApiModelProperty(value = "Observer角色总数", example = "3") + private Integer totalObserverCount; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeStatVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeStatVO.java new file mode 100644 index 00000000..c5cd0aa9 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeStatVO.java @@ -0,0 +1,44 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +public class ZnodeStatVO { + @ApiModelProperty(value = "节点被创建时的事物的ID", example = "0x1f09") + private Long czxid; + + @ApiModelProperty(value = "创建时间", example = "Sat Mar 16 15:38:34 CST 2019") + private Long ctime; + + @ApiModelProperty(value = "节点最后一次被修改时的事物的ID", example = "0x1f09") + private Long mzxid; + + @ApiModelProperty(value = "最后一次修改时间", example = "Sat Mar 16 15:38:34 CST 2019") + private Long mtime; + + @ApiModelProperty(value = "子节点列表最近一次呗修改的事物ID", example = "0x31") + private Long pzxid; + + @ApiModelProperty(value = "子节点版本号", example = "0") + private Integer cversion; + + @ApiModelProperty(value = "数据版本号", example = "0") + private Integer version; + + @ApiModelProperty(value = "ACL版本号", example = "0") + private Integer aversion; + + @ApiModelProperty(value = "创建临时节点的事物ID,持久节点事物为0", example = "0") + private Long ephemeralOwner; + + @ApiModelProperty(value = "数据长度,每个节点都可保存数据", example = "22") + private Integer dataLength; + + @ApiModelProperty(value = "子节点的个数", example = "6") + private Integer numChildren; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeVO.java new file mode 100644 index 00000000..b00a5ff7 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeVO.java @@ -0,0 +1,22 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +public class ZnodeVO { + + @ApiModelProperty(value = "节点名称", example = "broker") + private String name; + + @ApiModelProperty(value = "节点数据", example = "saassad") + private String data; + + @ApiModelProperty(value = "节点属性", example = "") + private ZnodeStatVO stat; + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/ZnodeConverter.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/ZnodeConverter.java new file mode 100644 index 00000000..9b197358 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/ZnodeConverter.java @@ -0,0 +1,19 @@ +package com.xiaojukeji.know.streaming.km.common.converter; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.Znode; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import org.apache.zookeeper.data.Stat; + +public class ZnodeConverter { + ZnodeConverter(){ + + } + + public static Znode convert2Znode(Tuple dataAndStat, String path) { + Znode znode = new Znode(); + znode.setStat(dataAndStat.getV2()); + znode.setData(dataAndStat.getV1() == null ? null : new String(dataAndStat.getV1())); + znode.setName(path.substring(path.lastIndexOf('/') + 1)); + return znode; + } +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZnodeService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZnodeService.java new file mode 100644 index 00000000..43e7744d --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZnodeService.java @@ -0,0 +1,13 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.Znode; + +import java.util.List; + +public interface ZnodeService { + + Result> listZnodeChildren(Long clusterPhyId, String path, String keyword); + + Result getZnode(Long clusterPhyId, String path); +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZnodeServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZnodeServiceImpl.java new file mode 100644 index 00000000..9b9a70ef --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZnodeServiceImpl.java @@ -0,0 +1,81 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper.impl; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.Znode; +import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; +import com.xiaojukeji.know.streaming.km.common.converter.ZnodeConverter; +import com.xiaojukeji.know.streaming.km.common.exception.NotExistException; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZnodeService; +import com.xiaojukeji.know.streaming.km.persistence.kafka.zookeeper.service.KafkaZKDAO; +import org.apache.zookeeper.data.Stat; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import java.util.List; +import java.util.stream.Collectors; + + +@Service +public class ZnodeServiceImpl implements ZnodeService { + private static final ILog LOGGER = LogFactory.getLog(ZnodeServiceImpl.class); + + @Autowired + private KafkaZKDAO kafkaZKDAO; + + @Autowired + private ClusterPhyService clusterPhyService; + + + + @Override + public Result> listZnodeChildren(Long clusterPhyId, String path, String keyword) { + ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(clusterPhyId); + if (clusterPhy == null) { + return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getClusterPhyNotExist(clusterPhyId)); + } + + List children; + try { + children = kafkaZKDAO.getChildren(clusterPhyId, path, false); + } catch (NotExistException e) { + LOGGER.error("class=ZnodeServiceImpl||method=listZnodeChildren||clusterPhyId={}||errMsg={}", clusterPhyId, "create ZK client create failed"); + return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, "ZK客户端创建失败"); + } catch (Exception e) { + LOGGER.error("class=ZnodeServiceImpl||method=listZnodeChildren||clusterPhyId={}||errMsg={}", clusterPhyId, "ZK operate failed"); + return Result.buildFromRSAndMsg(ResultStatus.ZK_OPERATE_FAILED, "ZK操作失败"); + } + + //关键字搜索 + if (keyword != null) { + children = children.stream().filter(elem -> elem.contains(keyword)).collect(Collectors.toList()); + } + return Result.buildSuc(children); + } + + @Override + public Result getZnode(Long clusterPhyId, String path) { + ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(clusterPhyId); + if (clusterPhy == null) { + return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getClusterPhyNotExist(clusterPhyId)); + } + + //获取zookeeper上的原始数据 + Tuple dataAndStat; + try { + dataAndStat = kafkaZKDAO.getDataAndStat(clusterPhyId, path); + } catch (NotExistException e) { + LOGGER.error("class=ZnodeServiceImpl||method=getZnode||clusterPhyId={}||errMsg={}", clusterPhyId, "create ZK client create failed"); + return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, "ZK客户端创建失败"); + } catch (Exception e) { + LOGGER.error("class=ZnodeServiceImpl||method=getZnode||clusterPhyId={}||errMsg={}", clusterPhyId, "ZK operate failed"); + return Result.buildFromRSAndMsg(ResultStatus.ZK_OPERATE_FAILED, "ZK操作失败"); + } + + return Result.buildSuc(ZnodeConverter.convert2Znode(dataAndStat, path)); + } +} diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterZookeepersController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterZookeepersController.java new file mode 100644 index 00000000..99faa832 --- /dev/null +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterZookeepersController.java @@ -0,0 +1,63 @@ +package com.xiaojukeji.know.streaming.km.rest.api.v3.cluster; + +import com.xiaojukeji.know.streaming.km.biz.cluster.ClusterZookeepersManager; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersOverviewVO; +import com.xiaojukeji.know.streaming.km.common.constant.ApiPrefix; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterZookeepersOverviewDTO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersStateVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ZnodeVO; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZnodeService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + + +/** + * @author zengqiao + * @date 22/09/19 + */ +@Api(tags = Constant.SWAGGER_API_TAG_PREFIX + "集群ZK-相关接口(REST)") +@RestController +@RequestMapping(ApiPrefix.API_V3_PREFIX) +public class ClusterZookeepersController { + @Autowired + private ClusterZookeepersManager clusterZookeepersManager; + + @Autowired + private ZnodeService znodeService; + + @ApiOperation("集群Zookeeper状态信息") + @GetMapping(value = "clusters/{clusterPhyId}/zookeepers-state") + public Result getClusterZookeepersState(@PathVariable Long clusterPhyId) { + return clusterZookeepersManager.getClusterPhyZookeepersState(clusterPhyId); + } + + @ApiOperation("集群Zookeeper信息列表") + @PostMapping(value = "clusters/{clusterPhyId}/zookeepers-overview") + public PaginationResult getClusterZookeepersOverview(@PathVariable Long clusterPhyId, + @RequestBody ClusterZookeepersOverviewDTO dto) { + return clusterZookeepersManager.getClusterPhyZookeepersOverview(clusterPhyId, dto); + } + + @ApiOperation("Zookeeper节点数据") + @GetMapping(value = "clusters/{clusterPhyId}/znode-data") + public Result getClusterZookeeperData(@PathVariable Long clusterPhyId, + @RequestParam String path) { + return clusterZookeepersManager.getZnodeVO(clusterPhyId, path); + } + + @ApiOperation("Zookeeper节点列表") + @GetMapping(value = "clusters/{clusterPhyId}/znode-children") + public Result> getClusterZookeeperChild(@PathVariable Long clusterPhyId, + @RequestParam String path, + @RequestParam(required = false) String keyword) { + return znodeService.listZnodeChildren(clusterPhyId, path, keyword); + } + +} diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/zk/ZookeeperMetricsController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/zk/ZookeeperMetricsController.java new file mode 100644 index 00000000..bb2ea098 --- /dev/null +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/zk/ZookeeperMetricsController.java @@ -0,0 +1,52 @@ +package com.xiaojukeji.know.streaming.km.rest.api.v3.zk; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.BaseMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line.MetricLineVO; +import com.xiaojukeji.know.streaming.km.common.constant.ApiPrefix; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperMetricService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + + +/** + * @author zengqiao + * @date 22/09/19 + */ +@Api(tags = Constant.SWAGGER_API_TAG_PREFIX + "ZKMetrics-相关接口(REST)") +@RestController +@RequestMapping(ApiPrefix.API_V3_PREFIX) +public class ZookeeperMetricsController { + private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperMetricsController.class); + + @Autowired + private ZookeeperMetricService zookeeperMetricService; + + @ApiOperation(value = "ZK-最近指标", notes = "") + @PostMapping(value = "clusters/{clusterPhyId}/zookeeper-latest-metrics") + @ResponseBody + public Result getLatestMetrics(@PathVariable Long clusterPhyId, @RequestBody List metricsNames) { + Result metricsResult = zookeeperMetricService.batchCollectMetricsFromZookeeper(clusterPhyId, metricsNames); + if (metricsResult.failed()) { + return Result.buildFromIgnoreData(metricsResult); + } + + return Result.buildSuc(metricsResult.getData()); + } + + @ApiOperation(value = "ZK-多指标历史信息", notes = "多条指标线") + @PostMapping(value = "clusters/{clusterPhyId}/zookeeper-metrics") + @ResponseBody + public Result> getMetricsLine(@PathVariable Long clusterPhyId, @RequestBody MetricDTO dto) { + return zookeeperMetricService.listMetricsFromES(clusterPhyId, dto); + } +} From d15974639113e569d682a07f88613c15c3c6e06a Mon Sep 17 00:00:00 2001 From: zengqiao Date: Sat, 8 Oct 2022 17:00:08 +0800 Subject: [PATCH 013/145] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=8E=A5=E5=85=A5?= =?UTF-8?q?=E5=B8=A6Kerberos=E8=AE=A4=E8=AF=81=E7=9A=84ZK=E9=9B=86?= =?UTF-8?q?=E7=BE=A4=E7=9A=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support_kerberos_zk/need_modify_code.png} | Bin .../assets/support_kerberos_zk/success_1.png} | Bin .../assets/support_kerberos_zk/success_2.png} | Bin .../support_kerberos_zk/watch_user_acl.png} | Bin docs/dev_guide/支持Kerberos认证的ZK.md | 69 ++++++++++++++++++ docs/zk_kerberos/zk支持Kerberos配置文档.md | 47 ------------ 6 files changed, 69 insertions(+), 47 deletions(-) rename docs/{zk_kerberos/img.png => dev_guide/assets/support_kerberos_zk/need_modify_code.png} (100%) rename docs/{zk_kerberos/img_2.png => dev_guide/assets/support_kerberos_zk/success_1.png} (100%) rename docs/{zk_kerberos/img_3.png => dev_guide/assets/support_kerberos_zk/success_2.png} (100%) rename docs/{zk_kerberos/img_1.png => dev_guide/assets/support_kerberos_zk/watch_user_acl.png} (100%) create mode 100644 docs/dev_guide/支持Kerberos认证的ZK.md delete mode 100644 docs/zk_kerberos/zk支持Kerberos配置文档.md diff --git a/docs/zk_kerberos/img.png b/docs/dev_guide/assets/support_kerberos_zk/need_modify_code.png similarity index 100% rename from docs/zk_kerberos/img.png rename to docs/dev_guide/assets/support_kerberos_zk/need_modify_code.png diff --git a/docs/zk_kerberos/img_2.png b/docs/dev_guide/assets/support_kerberos_zk/success_1.png similarity index 100% rename from docs/zk_kerberos/img_2.png rename to docs/dev_guide/assets/support_kerberos_zk/success_1.png diff --git a/docs/zk_kerberos/img_3.png b/docs/dev_guide/assets/support_kerberos_zk/success_2.png similarity index 100% rename from docs/zk_kerberos/img_3.png rename to docs/dev_guide/assets/support_kerberos_zk/success_2.png diff --git a/docs/zk_kerberos/img_1.png b/docs/dev_guide/assets/support_kerberos_zk/watch_user_acl.png similarity index 100% rename from docs/zk_kerberos/img_1.png rename to docs/dev_guide/assets/support_kerberos_zk/watch_user_acl.png diff --git a/docs/dev_guide/支持Kerberos认证的ZK.md b/docs/dev_guide/支持Kerberos认证的ZK.md new file mode 100644 index 00000000..116643ba --- /dev/null +++ b/docs/dev_guide/支持Kerberos认证的ZK.md @@ -0,0 +1,69 @@ + +## 支持Kerberos认证的ZK + + +### 1、修改 KnowStreaming 代码 + +代码位置:`src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java` + +将 `createZKClient` 的 `135行 的 false 改为 true +![need_modify_code.png](assets/support_kerberos_zk/need_modify_code.png) + + +修改完后重新进行打包编译,打包编译见:[打包编译](https://github.com/didi/KnowStreaming/blob/master/docs/install_guide/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85%E6%89%8B%E5%86%8C.md +) + + + +### 2、查看用户在ZK的ACL + +假设我们使用的用户是 `kafka` 这个用户。 + +- 1、查看 server.properties 的配置的 zookeeper.connect 的地址; +- 2、使用 `zkCli.sh -serve zookeeper.connect的地址` 登录到ZK页面; +- 3、ZK页面上,执行命令 `getAcl /kafka` 查看 `kafka` 用户的权限; + +此时,我们可以看到如下信息: +![watch_user_acl.png](assets/support_kerberos_zk/watch_user_acl.png) + +`kafka` 用户需要的权限是 `cdrwa`。如果用户没有 `cdrwa` 权限的话,需要创建用户并授权,授权命令为:`setAcl` + + +### 3、创建Kerberos的keytab并修改 KnowStreaming 主机 + +- 1、在 Kerberos 的域中创建 `kafka/_HOST` 的 `keytab`,并导出。例如:`kafka/dbs-kafka-test-8-53`; +- 2、导出 keytab 后上传到安装 KS 的机器的 `/etc/keytab` 下; +- 3、在 KS 机器上,执行 `kinit -kt zookeepe.keytab kafka/dbs-kafka-test-8-53` 看是否能进行 `Kerberos` 登录; +- 4、可以登录后,配置 `/opt/zookeeper.jaas` 文件,例子如下: +```sql +Client { + com.sun.security.auth.module.Krb5LoginModule required + useKeyTab=true + storeKey=false + serviceName="zookeeper" + keyTab="/etc/keytab/zookeeper.keytab" + principal="kafka/dbs-kafka-test-8-53@XXX.XXX.XXX"; +}; +``` +- 5、需要配置 `KDC-Server` 对 `KnowStreaming` 的机器开通防火墙,并在KS的机器 `/etc/host/` 配置 `kdc-server` 的 `hostname`。并将 `krb5.conf` 导入到 `/etc` 下; + + +### 4、修改 KnowStreaming 的配置 + +- 1、在 `/usr/local/KnowStreaming/KnowStreaming/bin/startup.sh` 中的47行的JAVA_OPT中追加如下设置 +```bash +-Dsun.security.krb5.debug=true -Djava.security.krb5.conf=/etc/krb5.conf -Djava.security.auth.login.config=/opt/zookeeper.jaas +``` + +- 2、重启KS集群后再 start.out 中看到如下信息,则证明Kerberos配置成功; + +![success_1.png](assets/support_kerberos_zk/success_1.png) + +![success_2.png](assets/support_kerberos_zk/success_2.png) + + +### 5、补充说明 + +- 1、多Kafka集群如果用的是一样的Kerberos域的话,只需在每个`ZK`中给`kafka`用户配置`crdwa`权限即可,这样集群初始化的时候`zkclient`是都可以认证; +- 2、当前需要修改代码重新打包才可以支持,后续考虑通过页面支持Kerberos认证的ZK接入; +- 3、多个Kerberos域暂时未适配; \ No newline at end of file diff --git a/docs/zk_kerberos/zk支持Kerberos配置文档.md b/docs/zk_kerberos/zk支持Kerberos配置文档.md deleted file mode 100644 index ad70861c..00000000 --- a/docs/zk_kerberos/zk支持Kerberos配置文档.md +++ /dev/null @@ -1,47 +0,0 @@ -1、需要修改代码: -位置:src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java -将createZKClient的135行的false改为true -![img.png](img.png) -修改完之后就可以打包编译:打包编译见:参考2.3 后端单独打包 -https://github.com/didi/KnowStreaming/blob/master/docs/install_guide/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85%E6%89%8B%E5%86%8C.md - -2、查看kafka的ZK的Acl -首先查看kafka的server.properties的配置的zookeeper.connect的连接,然后使用:zkCli.sh -serve xxxx登录到zk的页面,然后执行命令getAcl /kafka -![img_1.png](img_1.png) -此时就可以看到kafka在zk中的用户的权限,因为我们的集群在server.properties 配置了super.users=User:kafka ,以及zookeeper.set.acl=true ,默认的kafka的权限就是cdrwa。如果没有用户有cdrwa权限的话,需要zk创建用户并授权,授权命令:setAcl - -3、在Kerberos的域中创建 kafka/_HOST的keytab,并导出。例如:kafka/dbs-kafka-test-8-53 - -4、导出keytab后上传到安装KS的机器的/etc/keytab下。执行 kinit -kt zookeepe.keytab kafka/dbs-kafka-test-8-53 看是否能进行Kerberos登录 - -5、可以登录后,配置/opt/zookeeper.jass文件: -Client { - -com.sun.security.auth.module.Krb5LoginModule required - -useKeyTab=true - -storeKey=false - -serviceName="zookeeper" - -keyTab="/etc/keytab/zookeeper.keytab" - -principal="kafka/dbs-kafka-test-8-53@XXX.XXX.XXX"; - -}; - -6、需要配置KDC-Server对KS的机器开通防火墙,并在KS的机器/etc/host/ 配置 kdc-server的hostname。并将 krb5.conf 导入到/etc下 - -7、在/usr/local/KnowStreaming/KnowStreaming/bin/startup.sh中的47行的JAVA_OPT中追加如下设置: --Dsun.security.krb5.debug=true -Djava.security.krb5.conf=/etc/krb5.conf -Djava.security.auth.login.config=/opt/zookeeper.jaas - -8、重启KS集群后再start.out中看到如下信息,证明Kerberos配置成功 -![img_3.png](img_3.png) -![img_2.png](img_2.png) - -9、对于多集群来说如果用的是一样的Kerberos域的话,只需在每个zk中给kafka用户配置crdwa权限即可,这样集群初始化的时候zkclient是都可以认证。 - -10、未改进: - 1、需要页面ZK的Kerberos配置化 - 2、多个Kerberos域暂时未适配。 \ No newline at end of file From 224698355c70c469dbb63ae729e660348ac3b3f7 Mon Sep 17 00:00:00 2001 From: EricZeng Date: Sun, 9 Oct 2022 10:38:36 +0800 Subject: [PATCH 014/145] =?UTF-8?q?=E6=81=A2=E5=A4=8D=E4=B8=BA=E5=8E=9F?= =?UTF-8?q?=E5=85=88=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 恢复为原先代码 --- .../streaming/km/persistence/kafka/KafkaAdminZKClient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java index 0b824ddb..e6275a60 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java @@ -132,9 +132,9 @@ public class KafkaAdminZKClient extends AbstractClusterLoadedChangedHandler impl kafkaZkClient = KafkaZkClient.apply( zookeeperAddress, -// false, + false, // 添加支持zk的Kerberos认证 - true, +// true, Constant.DEFAULT_SESSION_TIMEOUT_UNIT_MS, Constant.DEFAULT_SESSION_TIMEOUT_UNIT_MS, 5, From 6237b0182f576541b70ce1c6464f4c18dc97928b Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Sun, 9 Oct 2022 12:27:27 +0800 Subject: [PATCH 015/145] issue template --- .github/ISSUE_TEMPLATE.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..afbe0a05 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1 @@ +## Issue 模板 \ No newline at end of file From 56726b703f0d35e4c6401b257260a973f8985431 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Sun, 9 Oct 2022 13:56:44 +0800 Subject: [PATCH 016/145] issue template --- .github/ISSUE_TEMPLATE/bug_report.md | 41 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/discussion.md | 0 .github/ISSUE_TEMPLATE/feature_request.md | 15 +++++++++ .github/ISSUE_TEMPLATE/question.md | 12 +++++++ 4 files changed, 68 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/discussion.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/question.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..b36d9d6a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,41 @@ +--- +name: 报告Bug +about: 报告KnowStreaming的相关Bug +title: '' +labels: type/bug +assignees: '' + +--- + +- [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 + +### 环境信息 + +* KnowStreaming version: xxx +* Operating System version: xxx +* Java version: xxx + +### 重现该问题的步骤 + +1. xxx +2. xxx +3. xxx + + + +### 预期结果 + + + +### 实际结果 + + + + +--- + +如果有异常,请附上异常Trace: + +``` +Just put your stack trace here! +``` diff --git a/.github/ISSUE_TEMPLATE/discussion.md b/.github/ISSUE_TEMPLATE/discussion.md new file mode 100644 index 00000000..e69de29b diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..0da4616d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,15 @@ +--- +name: 提议新功能/需求 +about: 给KnowStreaming提一个功能需求 +title: '' +labels: type/feature +assignees: '' + +--- + +- [ ] 我在 [issues](https://github.com/didi/KnowStreaming/issues) 中并未搜索到与此相关的功能需求。 +- [ ] 我在 [release notes](https://github.com/didi/KnowStreaming/releases)已经发布的版本中并没有搜到相关功能. + +## Describe the feature + + diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 00000000..581115cc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,12 @@ +--- +name: 问题/Question +about: 问KnowStreaming相关问题 +title: '' +labels: type/question +assignees: '' + +--- + +- [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 + +## 在这里提出你的问题 From 7c05899dbd8a7d47b830c0b38c85d75104c77693 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Sun, 9 Oct 2022 15:26:57 +0800 Subject: [PATCH 017/145] issue template --- .github/ISSUE_TEMPLATE/bug_report.md | 13 +++++++++---- .github/ISSUE_TEMPLATE/discussion.md | 11 +++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 8 ++++---- .github/ISSUE_TEMPLATE/question.md | 4 ++-- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b36d9d6a..959a0795 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -2,7 +2,7 @@ name: 报告Bug about: 报告KnowStreaming的相关Bug title: '' -labels: type/bug +labels: bug assignees: '' --- @@ -11,14 +11,19 @@ assignees: '' ### 环境信息 -* KnowStreaming version: xxx -* Operating System version: xxx -* Java version: xxx +* KnowStreaming version : xxx +* Operating System version : xxx +* Java version : xxx ### 重现该问题的步骤 1. xxx + + + 2. xxx + + 3. xxx diff --git a/.github/ISSUE_TEMPLATE/discussion.md b/.github/ISSUE_TEMPLATE/discussion.md index e69de29b..7c658e51 100644 --- a/.github/ISSUE_TEMPLATE/discussion.md +++ b/.github/ISSUE_TEMPLATE/discussion.md @@ -0,0 +1,11 @@ +--- +name: 讨论 +about: 开启一个关于KnowStreaming的讨论 +title: '' +labels: discussion +assignees: '' +--- + +## 讨论主题 + +... diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 0da4616d..fe7e88fb 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,14 +2,14 @@ name: 提议新功能/需求 about: 给KnowStreaming提一个功能需求 title: '' -labels: type/feature +labels: feature assignees: '' --- - [ ] 我在 [issues](https://github.com/didi/KnowStreaming/issues) 中并未搜索到与此相关的功能需求。 -- [ ] 我在 [release notes](https://github.com/didi/KnowStreaming/releases)已经发布的版本中并没有搜到相关功能. +- [ ] 我在 [release notes] (https://github.com/didi/KnowStreaming/releases)已经发布的版本中并没有搜到相关功能. -## Describe the feature - +## 这里描述需求 + diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 581115cc..784dfbec 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,8 +1,8 @@ --- name: 问题/Question -about: 问KnowStreaming相关问题 +about: 问KnowStreaming相关问题, 如果没有得到及时回复可以加V: shiyanzu001 , 进交流群 title: '' -labels: type/question +labels: question assignees: '' --- From 14652e7f7a35df9027a235179c7f0a9ecbc27641 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Sun, 9 Oct 2022 15:39:20 +0800 Subject: [PATCH 018/145] issue template --- .github/ISSUE_TEMPLATE/discussion.md | 1 + .github/ISSUE_TEMPLATE/question.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/discussion.md b/.github/ISSUE_TEMPLATE/discussion.md index 7c658e51..4a3a2108 100644 --- a/.github/ISSUE_TEMPLATE/discussion.md +++ b/.github/ISSUE_TEMPLATE/discussion.md @@ -4,6 +4,7 @@ about: 开启一个关于KnowStreaming的讨论 title: '' labels: discussion assignees: '' + --- ## 讨论主题 diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 784dfbec..739f6255 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,5 +1,5 @@ --- -name: 问题/Question +name: 问题 about: 问KnowStreaming相关问题, 如果没有得到及时回复可以加V: shiyanzu001 , 进交流群 title: '' labels: question From e01427aa4f43c74eec818692facf499ade90db62 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Sun, 9 Oct 2022 15:42:40 +0800 Subject: [PATCH 019/145] issue template --- .github/ISSUE_TEMPLATE/discussion.md | 2 +- .github/ISSUE_TEMPLATE/question.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/discussion.md b/.github/ISSUE_TEMPLATE/discussion.md index 4a3a2108..bf2b8359 100644 --- a/.github/ISSUE_TEMPLATE/discussion.md +++ b/.github/ISSUE_TEMPLATE/discussion.md @@ -1,5 +1,5 @@ --- -name: 讨论 +name: 讨论/discussion about: 开启一个关于KnowStreaming的讨论 title: '' labels: discussion diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 739f6255..02789241 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,6 +1,6 @@ --- name: 问题 -about: 问KnowStreaming相关问题, 如果没有得到及时回复可以加V: shiyanzu001 , 进交流群 +about: 问KnowStreaming相关问题 title: '' labels: question assignees: '' From 321125caee5c157af195e1005a1b01687d19a99f Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Sun, 9 Oct 2022 15:47:13 +0800 Subject: [PATCH 020/145] issue template --- .github/ISSUE_TEMPLATE/config.yml | 5 +++++ .github/ISSUE_TEMPLATE/question.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..30e38e30 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: KnowStreaming官网 + url: https://knowstreaming.com/ + about: KnowStreaming website diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 02789241..e9bf5c05 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,5 +1,5 @@ --- -name: 问题 +name: 提个问题 about: 问KnowStreaming相关问题 title: '' labels: question From 35d4888afb3a471333610162d61b930d3094a0dc Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Sun, 9 Oct 2022 17:03:46 +0800 Subject: [PATCH 021/145] =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E8=80=85=E8=A7=84?= =?UTF-8?q?=E7=BA=A6=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CODE_OF_CONDUCT.md | 74 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..a70c8889 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at shirenchuang@didiglobal.com . All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org From 7e92553017300e7dd57963c59d4d3dbe0547d168 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 11:42:04 +0800 Subject: [PATCH 022/145] =?UTF-8?q?PR=20=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/PULL_REQUEST_TEMPLATE.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..9ca3226e --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,22 @@ +请不要在没有先创建Issue的情况下创建Pull Request。 + +## 变更的目的是什么 + +XXXXX + +## 简短的更新日志 + +XX + +## 验证这一变化 + +XXXX + +请遵循此清单,以帮助我们快速轻松地整合您的贡献: + +* [ ] 确保有针对更改提交的 Github issue(通常在您开始处理之前)。诸如拼写错误之类的琐碎更改不需要 Github issue。您的Pull Request应该只解决这个问题,而不需要进行其他更改—— 一个 PR 解决一个问题。 +* [ ] 格式化 Pull Request 标题,如[ISSUE #123] support Confluent Schema Registry。 Pull Request 中的每个提交都应该有一个有意义的主题行和正文。 +* [ ] 编写足够详细的Pull Request描述,以了解Pull Request的作用、方式和原因。 +* [ ] 编写必要的单元测试来验证您的逻辑更正。如果提交了新功能或重大更改,请记住在test 模块中添加 integration-test +* [ ] 确保编译通过,集成测试通过 + From bd43ae1b5dd12dce04a7da005cb7f7c40b910e24 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 12:57:53 +0800 Subject: [PATCH 023/145] =?UTF-8?q?Issue=20=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/detail_optimizing.md | 22 +++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/detail_optimizing.md diff --git a/.github/ISSUE_TEMPLATE/detail_optimizing.md b/.github/ISSUE_TEMPLATE/detail_optimizing.md new file mode 100644 index 00000000..a531ac8a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/detail_optimizing.md @@ -0,0 +1,22 @@ +--- +name: 优化建议 +about: 相关功能优化建议 +title: '' +labels: Optimization Suggestions +assignees: '' + +--- + +- [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 + +### 环境信息 + +* KnowStreaming version : xxx +* Operating System version : xxx +* Java version : xxx + +### 需要优化的功能点 + + +### 建议如何优化 + From 8f1a02185172d1b9660c1d0ee4fc39516c11c00f Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 13:46:14 +0800 Subject: [PATCH 024/145] readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 1ae6ca59..cccf3960 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,11 @@ PS: 提问请尽量把问题一次性描述清楚,并告知环境信息情况 微信加群:添加`mike_zhangliang`、`PenceXie`的微信号备注KnowStreaming加群。
      + +加群之前有劳点一下 star,一个小小的 star 是对KnowStreaming作者们努力建设社区的动力。 + +感谢感谢!!! + wx ## Star History From 76503322528f9ab312bd16b3ed5b537dcb274954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=B3=E8=87=BB=E8=87=BB=E7=9A=84=E6=9D=82=E8=B4=A7?= =?UTF-8?q?=E9=93=BA?= Date: Mon, 10 Oct 2022 13:50:55 +0800 Subject: [PATCH 025/145] Update CONTRIBUTING.md --- CONTRIBUTING.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8a8b38a9..7601be61 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,4 +25,6 @@ Following information can help us to resolve the issue faster. * API version. * Logs. * Screenshots. -* Steps to reproduce the issue. \ No newline at end of file +* Steps to reproduce the issue. + +0 From 479f983b098787d22f7a1852800995256051c91a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=B3=E8=87=BB=E8=87=BB=E7=9A=84=E6=9D=82=E8=B4=A7?= =?UTF-8?q?=E9=93=BA?= Date: Mon, 10 Oct 2022 13:58:35 +0800 Subject: [PATCH 026/145] Update CONTRIBUTING.md --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7601be61..e2690d71 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,3 +28,4 @@ Following information can help us to resolve the issue faster. * Steps to reproduce the issue. 0 +1 From edd3f95fc4d9c7ffe9eece1f1bdd731540793691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=B3=E8=87=BB=E8=87=BB=E7=9A=84=E6=9D=82=E8=B4=A7?= =?UTF-8?q?=E9=93=BA?= Date: Mon, 10 Oct 2022 14:22:24 +0800 Subject: [PATCH 027/145] Update CONTRIBUTING.md --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e2690d71..683294cd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,3 +29,4 @@ Following information can help us to resolve the issue faster. 0 1 +4 From 7275030971f9b174b4a88fe4ee0149132d703dbc Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 15:50:16 +0800 Subject: [PATCH 028/145] =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E8=80=85=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 3 - docs/contributer_guide/代码规范.md | 1 + docs/contributer_guide/开发者名单.md | 7 ++ docs/contributer_guide/贡献流程.md | 117 +++++++++++++++++++++ docs/contributer_guide/贡献源码.md | 149 +++++++++++++++++++++++++++ 5 files changed, 274 insertions(+), 3 deletions(-) create mode 100644 docs/contributer_guide/代码规范.md create mode 100644 docs/contributer_guide/开发者名单.md create mode 100644 docs/contributer_guide/贡献流程.md create mode 100644 docs/contributer_guide/贡献源码.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 683294cd..5560642a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,6 +27,3 @@ Following information can help us to resolve the issue faster. * Screenshots. * Steps to reproduce the issue. -0 -1 -4 diff --git a/docs/contributer_guide/代码规范.md b/docs/contributer_guide/代码规范.md new file mode 100644 index 00000000..be0bcfd2 --- /dev/null +++ b/docs/contributer_guide/代码规范.md @@ -0,0 +1 @@ +TODO. \ No newline at end of file diff --git a/docs/contributer_guide/开发者名单.md b/docs/contributer_guide/开发者名单.md new file mode 100644 index 00000000..b5c05427 --- /dev/null +++ b/docs/contributer_guide/开发者名单.md @@ -0,0 +1,7 @@ + +开源贡献者证书发放名单(定期更新) + + +|姓名|Github|角色|发放日期| +|--|--|--|--| +|szz|@szz|PMC|2022/?/?| \ No newline at end of file diff --git a/docs/contributer_guide/贡献流程.md b/docs/contributer_guide/贡献流程.md new file mode 100644 index 00000000..4f2a5b5a --- /dev/null +++ b/docs/contributer_guide/贡献流程.md @@ -0,0 +1,117 @@ +@[TOC] + +### 贡献流程 + + + +#### 1. fork didi/KnowStreaming项目到您的github库 + +找到你要Fork的项目,例如 [KnowStreaming](https://github.com/didi/KnowStreaming) ,点击Fork按钮。 +![在这里插入图片描述](https://img-blog.csdnimg.cn/ac7bfef9ccde49d587c30e702a615ef5.png) + + +#### 2. 克隆或下载您fork的Nacos代码仓库到您本地 + +```sh + +git clone { your fork knowstreaming repo address } + +cd KnowStreaming + +``` + +#### 3. 添加 didi/KnowStreaming仓库为upstream仓库 + + +```sh + +git remote add upstream https://github.com/didi/KnowStreaming + +git remote -v + + origin ${your fork KnowStreaming repo address} (fetch) + origin ${your fork KnowStreaming repo address} (push) + upstream https://github.com/didi/KnowStreaming(fetch) + upstream https://github.com/didi/KnowStreaming (push) + +git fetch origin +git fetch upstream + +``` +上面是将didi/KnowStreaming添加为远程仓库, 当前就会有2个远程仓库 + +1. origin : 你Fork出来的分叉仓库 +2. upstream : 源仓库 + +git fetch 获取远程仓库的基本信息, 比如 **源仓库**的所有分支就获取到了 + + +#### 4. 同步源仓库开发分支到本地分叉仓库中 + +一般开源项目都会有一个给贡献者提交代码的分支,例如 KnowStreaming的分支是 `dev`; + + +首先我们要将 **源仓库**的开发分支(`dev`) 拉取到本地仓库中 +```sh + +git checkout -b dev upstream/dev +``` +**或者IDEA的形式创建** + +![在这里插入图片描述](https://img-blog.csdnimg.cn/c95f2601a9af41889a5fc20b2a9724a5.png) + +#### 5. 在本地新建的开发分支上进行修改 + +首先请保证您阅读并正确设置KnowStreaming code style, 相关内容请阅读[KnowStreaming 代码规约 ]()。 + +修改时请保证该分支上的修改仅和issue相关,并尽量细化,做到 + +一个分支只修改一件事,一个PR只修改一件事。 + +同时,您的提交记录请尽量描述清楚,主要以谓 + 宾进行描述,如:Fix xxx problem/bug。少量简单的提交可以使用For xxx来描述,如:For codestyle。 如果该提交和某个ISSUE相关,可以添加ISSUE号作为前缀,如:For #10000, Fix xxx problem/bug。 + + +#### 6. Rebase 基础分支和开发分支 + +您修改的时候,可能别人的修改已经提交并被合并,此时可能会有冲突,这里请使用rebase命令进行合并解决,主要有2个好处: + +1. 您的提交记录将会非常优雅,不会出现Merge xxxx branch 等字样 +2. rebase后您分支的提交日志也是一条单链,基本不会出现各种分支交错的情况,回查时更轻松 + +```sh +git fetch upstream + +git rebase -i upstream/dev + +``` +**或者在IDEA的操作如下** + +![在这里插入图片描述](https://img-blog.csdnimg.cn/d75addcfa9564d3d9e1d226a2f7f4d64.png) +选择 源仓库的开发分支 +![在这里插入图片描述](https://img-blog.csdnimg.cn/4e85714df13b44bcb10f1e655450cb72.png) + +推荐使用IDEA的方式, 有冲突的时候更容易解决冲突问题。 + +#### 7. 将您开发完成rebase后的分支,上传到您fork的仓库 + +```sh +git push origin dev +``` + +#### 8. 按照PR模板中的清单创建Pull Request + + + +![在这里插入图片描述](https://img-blog.csdnimg.cn/1dab060aed314666970e3910e05f2205.png) + +选择自己的分支合并到模板分支。 + + +#### 9. 等待合并代码 + +提交了PR之后,需要等待PMC、Commiter 来Review代码,如果有问题需要配合修改重新提交。 + +如果没有问题会直接合并到开发分支`dev`中。 + +注: 如何长时间没有review, 则可以多催促社区来Review代码! + diff --git a/docs/contributer_guide/贡献源码.md b/docs/contributer_guide/贡献源码.md new file mode 100644 index 00000000..78f815e9 --- /dev/null +++ b/docs/contributer_guide/贡献源码.md @@ -0,0 +1,149 @@ + + + +# 为KnowStreaming做贡献 + + +欢迎👏🏻来到KnowStreaming!本文档是关于如何为KnowStreaming做出贡献的指南。 + +如果您发现不正确或遗漏的内容, 请留下意见/建议。 + +## 行为守则 +请务必阅读并遵守我们的 [行为准则](./CODE_OF_CONDUCT.md). + + + +## 贡献 + +**KnowStreaming** 欢迎任何角色的新参与者,包括 **User** 、**Contributor**、**Committer**、**PMC** 。 + +我们鼓励新人积极加入 **KnowStreaming** 项目,从User到Contributor、Committer ,甚至是 PMC 角色。 + +为了做到这一点,新人需要积极地为 **KnowStreaming** 项目做出贡献。以下介绍如何对 **KnowStreaming** 进行贡献。 + + +### 创建/打开 Issue + +如果您在文档中发现拼写错误、在代码中**发现错误**或想要**新功能**或想要**提供建议**,您可以在 GitHub 上[创建一个Issue](https://github.com/didi/KnowStreaming/issues/new/choose) 进行报告。 + + +如果您想直接贡献, 您可以选择下面标签的问题。 + +- [contribution welcome](https://github.com/didi/KnowStreaming/labels/contribution%20welcome) : 非常需要解决/新增 的Issues +- [good first issue](https://github.com/didi/KnowStreaming/labels/good%20first%20issue): 对新人比较友好, 新人可以拿这个Issue来练练手热热身。 + + 请注意,任何 PR 都必须与有效issue相关联。否则,PR 将被拒绝。 + + + +### 开始你的贡献 + +**分支介绍** + +我们将 `dev`分支作为开发分支, 说明这是一个不稳定的分支。 + +此外,我们的分支模型符合 [https://nvie.com/posts/a-successful-git-branching-model/](https://nvie.com/posts/a-successful-git-branching-model/). 我们强烈建议新人在创建PR之前先阅读上述文章。 + + + +**贡献流程** + +为方便描述,我们这里定义一下2个名词: + +自己Fork出来的仓库是私人仓库, 我们这里称之为 :**分叉仓库** +Fork的源项目,我们称之为:**源仓库** + + +现在,如果您准备好创建PR, 以下是贡献者的工作流程: + +1. Fork [KnowStreaming](https://github.com/didi/KnowStreaming) 项目到自己的仓库 + +2. 从源仓库的`dev`拉取并创建自己的本地分支,例如: `dev` +3. 在本地分支上对代码进行修改 +4. Rebase 开发分支, 并解决冲突 +5. commit 并 push 您的更改到您自己的**分叉仓库** +6. 创建一个 Pull Request 到**源仓库**的`dev`分支中。 +7. 等待回复。如果回复的慢,请无情的催促。 + + + +创建Pull Request时: + +1. 请遵循 PR的 [模板](./PULL_REQUEST_TEMPLATE.md) +2. 请确保 PR 有相应的issue。 +3. 如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档(在对应的issue中)。 +4. 注意单个 PR 不能太大。如果需要进行大量更改,最好将更改分成几个单独的 PR。 +5. 在合并PR之前,尽量的将最终的提交信息清晰简洁, 将多次修改的提交尽可能的合并为一次提交。 +6. 创建 PR 后,将为PR分配一个或多个reviewers。 + + +如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档。 + + +# 代码审查指南 + +Commiter将轮流review代码,以确保在合并前至少有一名Commiter + +一些原则: + +- 可读性——重要的代码应该有详细的文档。API 应该有 Javadoc。代码风格应与现有风格保持一致。 +- 优雅:新的函数、类或组件应该设计得很好。 +- 可测试性——单元测试用例应该覆盖 80% 的新代码。 +- 可维护性 - 遵守我们的编码规范。 + + +# 开发者 + +## 成为Contributor + +只要成功提交并合并PR , 则为Contributor + +名单请看:[开发者名单](../开发者名单.md) + +## 尝试成为Commiter + +一般来说, 贡献8个重要的补丁并至少让三个不同的人来Review他们(您需要3个Commiter的支持)。 +然后请人给你提名, 您需要展示您的 + +1. 至少8个重要的PR和项目的相关问题 +2. 与团队合作的能力 +3. 了解项目的代码库和编码风格 +4. 编写好代码的能力 + +当前的Commiter可以通过在KnowStreaming中的Issue标签 `nomination`(提名)来提名您 + +1. 你的名字和姓氏 +2. 指向您的Git个人资料的链接 +3. 解释为什么你应该成为Commiter +4. 详细说明提名人与您合作的3个PR以及相关问题,这些问题可以证明您的能力。 + +另外2个Commiter需要支持您的**提名**,如果5个工作日内没有人反对,您就是提交者,如果有人反对或者想要更多的信息,Commiter会讨论并通常达成共识(5个工作日内) 。 + + +# 开源奖励计划 + + +我们非常欢迎开发者们为KnowStreaming开源项目贡献一份力量,相应也将给予贡献者激励以表认可与感谢。 + + +## 参与贡献 + +1. 积极参与 Issue 的讨论,如答疑解惑、提供想法或报告无法解决的错误(Issue) +2. 撰写和改进项目的文档(Wiki) +3. 提交补丁优化代码(Coding) + + +## 你将获得 + +1. 加入KnowStreaming开源项目贡献者名单并展示 +2. KnowStreaming开源贡献者证书(纸质&电子版) +3. KnowStreaming贡献者精美大礼包(KnowStreamin/滴滴 周边) + + +## 相关规则 + +- Contributer和Commiter都会有对应的证书和对应的礼包 +- 每季度有KnowStreaming项目团队评选出杰出贡献者,颁发相应证书。 +- 年末进行年度评选 + +贡献者名单请看:[贡献者名单](../开发者名单.md) \ No newline at end of file From 975370b593ba031ff834d8277a94ed09fc0b2af0 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 15:57:07 +0800 Subject: [PATCH 029/145] =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E8=80=85=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 156 +++++++++++++++++++++++++---- docs/contributer_guide/贡献流程.md | 7 +- docs/contributer_guide/贡献源码.md | 4 +- 3 files changed, 145 insertions(+), 22 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5560642a..e163ccd3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,29 +1,149 @@ -# Contribution Guideline -Thanks for considering to contribute this project. All issues and pull requests are highly appreciated. -## Pull Requests -Before sending pull request to this project, please read and follow guidelines below. +# 为KnowStreaming做贡献 -1. Branch: We only accept pull request on `dev` branch. -2. Coding style: Follow the coding style used in LogiKM. -3. Commit message: Use English and be aware of your spell. -4. Test: Make sure to test your code. -Add device mode, API version, related log, screenshots and other related information in your pull request if possible. +欢迎👏🏻来到KnowStreaming!本文档是关于如何为KnowStreaming做出贡献的指南。 -NOTE: We assume all your contribution can be licensed under the [AGPL-3.0](LICENSE). +如果您发现不正确或遗漏的内容, 请留下意见/建议。 -## Issues +## 行为守则 +请务必阅读并遵守我们的 [行为准则](./CODE_OF_CONDUCT.md). -We love clearly described issues. :) -Following information can help us to resolve the issue faster. -* Device mode and hardware information. -* API version. -* Logs. -* Screenshots. -* Steps to reproduce the issue. +## 贡献 +**KnowStreaming** 欢迎任何角色的新参与者,包括 **User** 、**Contributor**、**Committer**、**PMC** 。 + +我们鼓励新人积极加入 **KnowStreaming** 项目,从User到Contributor、Committer ,甚至是 PMC 角色。 + +为了做到这一点,新人需要积极地为 **KnowStreaming** 项目做出贡献。以下介绍如何对 **KnowStreaming** 进行贡献。 + + +### 创建/打开 Issue + +如果您在文档中发现拼写错误、在代码中**发现错误**或想要**新功能**或想要**提供建议**,您可以在 GitHub 上[创建一个Issue](https://github.com/didi/KnowStreaming/issues/new/choose) 进行报告。 + + +如果您想直接贡献, 您可以选择下面标签的问题。 + +- [contribution welcome](https://github.com/didi/KnowStreaming/labels/contribution%20welcome) : 非常需要解决/新增 的Issues +- [good first issue](https://github.com/didi/KnowStreaming/labels/good%20first%20issue): 对新人比较友好, 新人可以拿这个Issue来练练手热热身。 + + 请注意,任何 PR 都必须与有效issue相关联。否则,PR 将被拒绝。 + + + +### 开始你的贡献 + +**分支介绍** + +我们将 `dev`分支作为开发分支, 说明这是一个不稳定的分支。 + +此外,我们的分支模型符合 [https://nvie.com/posts/a-successful-git-branching-model/](https://nvie.com/posts/a-successful-git-branching-model/). 我们强烈建议新人在创建PR之前先阅读上述文章。 + + + +**贡献流程** + +为方便描述,我们这里定义一下2个名词: + +自己Fork出来的仓库是私人仓库, 我们这里称之为 :**分叉仓库** +Fork的源项目,我们称之为:**源仓库** + + +现在,如果您准备好创建PR, 以下是贡献者的工作流程: + +1. Fork [KnowStreaming](https://github.com/didi/KnowStreaming) 项目到自己的仓库 + +2. 从源仓库的`dev`拉取并创建自己的本地分支,例如: `dev` +3. 在本地分支上对代码进行修改 +4. Rebase 开发分支, 并解决冲突 +5. commit 并 push 您的更改到您自己的**分叉仓库** +6. 创建一个 Pull Request 到**源仓库**的`dev`分支中。 +7. 等待回复。如果回复的慢,请无情的催促。 + + + +创建Pull Request时: + +1. 请遵循 PR的 [模板](./PULL_REQUEST_TEMPLATE.md) +2. 请确保 PR 有相应的issue。 +3. 如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档(在对应的issue中)。 +4. 注意单个 PR 不能太大。如果需要进行大量更改,最好将更改分成几个单独的 PR。 +5. 在合并PR之前,尽量的将最终的提交信息清晰简洁, 将多次修改的提交尽可能的合并为一次提交。 +6. 创建 PR 后,将为PR分配一个或多个reviewers。 + + +如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档。 + + +# 代码审查指南 + +Commiter将轮流review代码,以确保在合并前至少有一名Commiter + +一些原则: + +- 可读性——重要的代码应该有详细的文档。API 应该有 Javadoc。代码风格应与现有风格保持一致。 +- 优雅:新的函数、类或组件应该设计得很好。 +- 可测试性——单元测试用例应该覆盖 80% 的新代码。 +- 可维护性 - 遵守我们的编码规范。 + + +# 开发者 + +## 成为Contributor + +只要成功提交并合并PR , 则为Contributor + +名单请看:[开发者名单](../开发者名单.md) + +## 尝试成为Commiter + +一般来说, 贡献8个重要的补丁并至少让三个不同的人来Review他们(您需要3个Commiter的支持)。 +然后请人给你提名, 您需要展示您的 + +1. 至少8个重要的PR和项目的相关问题 +2. 与团队合作的能力 +3. 了解项目的代码库和编码风格 +4. 编写好代码的能力 + +当前的Commiter可以通过在KnowStreaming中的Issue标签 `nomination`(提名)来提名您 + +1. 你的名字和姓氏 +2. 指向您的Git个人资料的链接 +3. 解释为什么你应该成为Commiter +4. 详细说明提名人与您合作的3个PR以及相关问题,这些问题可以证明您的能力。 + +另外2个Commiter需要支持您的**提名**,如果5个工作日内没有人反对,您就是提交者,如果有人反对或者想要更多的信息,Commiter会讨论并通常达成共识(5个工作日内) 。 + + +# 开源奖励计划 + + +我们非常欢迎开发者们为KnowStreaming开源项目贡献一份力量,相应也将给予贡献者激励以表认可与感谢。 + + +## 参与贡献 + +1. 积极参与 Issue 的讨论,如答疑解惑、提供想法或报告无法解决的错误(Issue) +2. 撰写和改进项目的文档(Wiki) +3. 提交补丁优化代码(Coding) + + +## 你将获得 + +1. 加入KnowStreaming开源项目贡献者名单并展示 +2. KnowStreaming开源贡献者证书(纸质&电子版) +3. KnowStreaming贡献者精美大礼包(KnowStreamin/滴滴 周边) + + +## 相关规则 + +- Contributer和Commiter都会有对应的证书和对应的礼包 +- 每季度有KnowStreaming项目团队评选出杰出贡献者,颁发相应证书。 +- 年末进行年度评选 + +贡献者名单请看:[贡献者名单](./docs/contributer_guide/开发者名单.md) \ No newline at end of file diff --git a/docs/contributer_guide/贡献流程.md b/docs/contributer_guide/贡献流程.md index 4f2a5b5a..5ceffeef 100644 --- a/docs/contributer_guide/贡献流程.md +++ b/docs/contributer_guide/贡献流程.md @@ -1,4 +1,3 @@ -@[TOC] ### 贡献流程 @@ -7,6 +6,7 @@ #### 1. fork didi/KnowStreaming项目到您的github库 找到你要Fork的项目,例如 [KnowStreaming](https://github.com/didi/KnowStreaming) ,点击Fork按钮。 + ![在这里插入图片描述](https://img-blog.csdnimg.cn/ac7bfef9ccde49d587c30e702a615ef5.png) @@ -25,15 +25,18 @@ cd KnowStreaming ```sh +### 添加源仓库 git remote add upstream https://github.com/didi/KnowStreaming +### 查看是否添加成功 git remote -v origin ${your fork KnowStreaming repo address} (fetch) origin ${your fork KnowStreaming repo address} (push) upstream https://github.com/didi/KnowStreaming(fetch) upstream https://github.com/didi/KnowStreaming (push) - + +### 获取源仓库的基本信息 git fetch origin git fetch upstream diff --git a/docs/contributer_guide/贡献源码.md b/docs/contributer_guide/贡献源码.md index 78f815e9..7ef952a6 100644 --- a/docs/contributer_guide/贡献源码.md +++ b/docs/contributer_guide/贡献源码.md @@ -98,7 +98,7 @@ Commiter将轮流review代码,以确保在合并前至少有一名Commiter 只要成功提交并合并PR , 则为Contributor -名单请看:[开发者名单](../开发者名单.md) +名单请看:[开发者名单](./开发者名单.md) ## 尝试成为Commiter @@ -146,4 +146,4 @@ Commiter将轮流review代码,以确保在合并前至少有一名Commiter - 每季度有KnowStreaming项目团队评选出杰出贡献者,颁发相应证书。 - 年末进行年度评选 -贡献者名单请看:[贡献者名单](../开发者名单.md) \ No newline at end of file +贡献者名单请看:[贡献者名单](./开发者名单.md) \ No newline at end of file From b76959431a01637a29886747de153654afe62d6b Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 16:55:33 +0800 Subject: [PATCH 030/145] =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E8=80=85=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE.md | 1 - CONTRIBUTING.md | 4 +- docs/contributer_guide/开发者名单.md | 38 ++++++- docs/contributer_guide/贡献流程.md | 5 +- docs/contributer_guide/贡献源码.md | 149 --------------------------- 5 files changed, 42 insertions(+), 155 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE.md delete mode 100644 docs/contributer_guide/贡献源码.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index afbe0a05..00000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1 +0,0 @@ -## Issue 模板 \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e163ccd3..4c115eda 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,7 +69,7 @@ Fork的源项目,我们称之为:**源仓库** 创建Pull Request时: -1. 请遵循 PR的 [模板](./PULL_REQUEST_TEMPLATE.md) +1. 请遵循 PR的 [模板](./.github/PULL_REQUEST_TEMPLATE.md) 2. 请确保 PR 有相应的issue。 3. 如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档(在对应的issue中)。 4. 注意单个 PR 不能太大。如果需要进行大量更改,最好将更改分成几个单独的 PR。 @@ -98,7 +98,7 @@ Commiter将轮流review代码,以确保在合并前至少有一名Commiter 只要成功提交并合并PR , 则为Contributor -名单请看:[开发者名单](../开发者名单.md) +贡献者名单请看:[贡献者名单](./docs/contributer_guide/开发者名单.md) ## 尝试成为Commiter diff --git a/docs/contributer_guide/开发者名单.md b/docs/contributer_guide/开发者名单.md index b5c05427..704ffc5c 100644 --- a/docs/contributer_guide/开发者名单.md +++ b/docs/contributer_guide/开发者名单.md @@ -2,6 +2,42 @@ 开源贡献者证书发放名单(定期更新) +贡献者名单请看:[贡献者名单]() + + + |姓名|Github|角色|发放日期| |--|--|--|--| -|szz|@szz|PMC|2022/?/?| \ No newline at end of file +|张亮 | [@zhangliangboy](https://github.com/zhangliangboy)||| +|谢鹏|[@PenceXie](https://github.com/PenceXie)||| +|石臻臻 | [@shirenchuang](https://github.com/shirenchuang)||| +|周宇航|[@GraceWalk](https://github.com/GraceWalk)||| +|曾巧|[@ZQKC](https://github.com/ZQKC)||| +|赵寅锐|[@ZHAOYINRUI](https://github.com/ZHAOYINRUI)||| +|王东方|[@wangdongfang-aden](https://github.com/wangdongfang-aden)||| +|haoqi123|[@[haoqi123]](https://github.com/haoqi123)||| +|17hao|[@17hao](https://github.com/17hao)||| +|Huyueeer|[@Huyueeer](https://github.com/Huyueeer)||| +|杨光|[@yaangvipguang](https://github.com/yangvipguang)| +|王亚聪|[@wangyacongi](https://github.com/wangyacongi)| +|WYAOBO|[@WYAOBO](https://github.com/WYAOBO) +| Super .Wein(星痕)| [@superspeedone](https://github.com/superspeedone)||| +| Yang Jing| [@yangbajing](https://github.com/yangbajing)||| +| 刘新元 Liu XinYuan| [@Liu-XinYuan](https://github.com/Liu-XinYuan)||| +|Joker | [@LiubeyJokerQueue](https://github.com/JokerQueue)||| +|Eason Lau | [@Liubey](https://github.com/Liubey)||| +| hailanxin| [@hailanxin](https://github.com/hailanxin)||| +| Qi Zhang| [@zzzhangqi](https://github.com/zzzhangqi)||| +|Hongten | [@Hongten](https://github.com/Hongten)||| +|fengxsong | [@fengxsong](https://github.com/fengxsong)||| +|f1558 | [@f1558](https://github.com/f1558)||| +| 谢晓东| [@Strangevy](https://github.com/Strangevy)||| +| ZhaoXinlong| [@ZhaoXinlong](https://github.com/ZhaoXinlong)||| +|xuehaipeng | [@xuehaipeng](https://github.com/xuehaipeng)||| +|mrazkong | [@mrazkong](https://github.com/mrazkong)||| +|xuzhengxi | [@hyper-xx)](https://github.com/hyper-xx)||| +|pierre xiong | [@pierre94](https://github.com/pierre94)||| + + + + diff --git a/docs/contributer_guide/贡献流程.md b/docs/contributer_guide/贡献流程.md index 5ceffeef..b6ec2a9a 100644 --- a/docs/contributer_guide/贡献流程.md +++ b/docs/contributer_guide/贡献流程.md @@ -1,7 +1,7 @@ ### 贡献流程 - +[贡献源码细则](../CONTRIBUTING.md) #### 1. fork didi/KnowStreaming项目到您的github库 @@ -116,5 +116,6 @@ git push origin dev 如果没有问题会直接合并到开发分支`dev`中。 -注: 如何长时间没有review, 则可以多催促社区来Review代码! +注: 如果长时间没有review, 则可以多催促社区来Review代码! + diff --git a/docs/contributer_guide/贡献源码.md b/docs/contributer_guide/贡献源码.md deleted file mode 100644 index 7ef952a6..00000000 --- a/docs/contributer_guide/贡献源码.md +++ /dev/null @@ -1,149 +0,0 @@ - - - -# 为KnowStreaming做贡献 - - -欢迎👏🏻来到KnowStreaming!本文档是关于如何为KnowStreaming做出贡献的指南。 - -如果您发现不正确或遗漏的内容, 请留下意见/建议。 - -## 行为守则 -请务必阅读并遵守我们的 [行为准则](./CODE_OF_CONDUCT.md). - - - -## 贡献 - -**KnowStreaming** 欢迎任何角色的新参与者,包括 **User** 、**Contributor**、**Committer**、**PMC** 。 - -我们鼓励新人积极加入 **KnowStreaming** 项目,从User到Contributor、Committer ,甚至是 PMC 角色。 - -为了做到这一点,新人需要积极地为 **KnowStreaming** 项目做出贡献。以下介绍如何对 **KnowStreaming** 进行贡献。 - - -### 创建/打开 Issue - -如果您在文档中发现拼写错误、在代码中**发现错误**或想要**新功能**或想要**提供建议**,您可以在 GitHub 上[创建一个Issue](https://github.com/didi/KnowStreaming/issues/new/choose) 进行报告。 - - -如果您想直接贡献, 您可以选择下面标签的问题。 - -- [contribution welcome](https://github.com/didi/KnowStreaming/labels/contribution%20welcome) : 非常需要解决/新增 的Issues -- [good first issue](https://github.com/didi/KnowStreaming/labels/good%20first%20issue): 对新人比较友好, 新人可以拿这个Issue来练练手热热身。 - - 请注意,任何 PR 都必须与有效issue相关联。否则,PR 将被拒绝。 - - - -### 开始你的贡献 - -**分支介绍** - -我们将 `dev`分支作为开发分支, 说明这是一个不稳定的分支。 - -此外,我们的分支模型符合 [https://nvie.com/posts/a-successful-git-branching-model/](https://nvie.com/posts/a-successful-git-branching-model/). 我们强烈建议新人在创建PR之前先阅读上述文章。 - - - -**贡献流程** - -为方便描述,我们这里定义一下2个名词: - -自己Fork出来的仓库是私人仓库, 我们这里称之为 :**分叉仓库** -Fork的源项目,我们称之为:**源仓库** - - -现在,如果您准备好创建PR, 以下是贡献者的工作流程: - -1. Fork [KnowStreaming](https://github.com/didi/KnowStreaming) 项目到自己的仓库 - -2. 从源仓库的`dev`拉取并创建自己的本地分支,例如: `dev` -3. 在本地分支上对代码进行修改 -4. Rebase 开发分支, 并解决冲突 -5. commit 并 push 您的更改到您自己的**分叉仓库** -6. 创建一个 Pull Request 到**源仓库**的`dev`分支中。 -7. 等待回复。如果回复的慢,请无情的催促。 - - - -创建Pull Request时: - -1. 请遵循 PR的 [模板](./PULL_REQUEST_TEMPLATE.md) -2. 请确保 PR 有相应的issue。 -3. 如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档(在对应的issue中)。 -4. 注意单个 PR 不能太大。如果需要进行大量更改,最好将更改分成几个单独的 PR。 -5. 在合并PR之前,尽量的将最终的提交信息清晰简洁, 将多次修改的提交尽可能的合并为一次提交。 -6. 创建 PR 后,将为PR分配一个或多个reviewers。 - - -如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档。 - - -# 代码审查指南 - -Commiter将轮流review代码,以确保在合并前至少有一名Commiter - -一些原则: - -- 可读性——重要的代码应该有详细的文档。API 应该有 Javadoc。代码风格应与现有风格保持一致。 -- 优雅:新的函数、类或组件应该设计得很好。 -- 可测试性——单元测试用例应该覆盖 80% 的新代码。 -- 可维护性 - 遵守我们的编码规范。 - - -# 开发者 - -## 成为Contributor - -只要成功提交并合并PR , 则为Contributor - -名单请看:[开发者名单](./开发者名单.md) - -## 尝试成为Commiter - -一般来说, 贡献8个重要的补丁并至少让三个不同的人来Review他们(您需要3个Commiter的支持)。 -然后请人给你提名, 您需要展示您的 - -1. 至少8个重要的PR和项目的相关问题 -2. 与团队合作的能力 -3. 了解项目的代码库和编码风格 -4. 编写好代码的能力 - -当前的Commiter可以通过在KnowStreaming中的Issue标签 `nomination`(提名)来提名您 - -1. 你的名字和姓氏 -2. 指向您的Git个人资料的链接 -3. 解释为什么你应该成为Commiter -4. 详细说明提名人与您合作的3个PR以及相关问题,这些问题可以证明您的能力。 - -另外2个Commiter需要支持您的**提名**,如果5个工作日内没有人反对,您就是提交者,如果有人反对或者想要更多的信息,Commiter会讨论并通常达成共识(5个工作日内) 。 - - -# 开源奖励计划 - - -我们非常欢迎开发者们为KnowStreaming开源项目贡献一份力量,相应也将给予贡献者激励以表认可与感谢。 - - -## 参与贡献 - -1. 积极参与 Issue 的讨论,如答疑解惑、提供想法或报告无法解决的错误(Issue) -2. 撰写和改进项目的文档(Wiki) -3. 提交补丁优化代码(Coding) - - -## 你将获得 - -1. 加入KnowStreaming开源项目贡献者名单并展示 -2. KnowStreaming开源贡献者证书(纸质&电子版) -3. KnowStreaming贡献者精美大礼包(KnowStreamin/滴滴 周边) - - -## 相关规则 - -- Contributer和Commiter都会有对应的证书和对应的礼包 -- 每季度有KnowStreaming项目团队评选出杰出贡献者,颁发相应证书。 -- 年末进行年度评选 - -贡献者名单请看:[贡献者名单](./开发者名单.md) \ No newline at end of file From f009f8b7bac74950267a5e5bed20dcf4e3a7fa38 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 17:21:21 +0800 Subject: [PATCH 031/145] =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E8=80=85=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 1 + README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4c115eda..06577128 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -66,6 +66,7 @@ Fork的源项目,我们称之为:**源仓库** 7. 等待回复。如果回复的慢,请无情的催促。 +更为详细的贡献流程请看:[贡献流程](./docs/contributer_guide/贡献流程.md) 创建Pull Request时: diff --git a/README.md b/README.md index cccf3960..5b630fb0 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ 点击 [这里](CONTRIBUTING.md),了解如何成为 Know Streaming 的贡献者 - +获取KnowStreaming开源社区证书。 ## 加入技术交流群 From 0221fb3a4a7c536dfabbe82c5497af133e7b2c1d Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 18:02:19 +0800 Subject: [PATCH 032/145] =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E8=80=85=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/contributer_guide/贡献流程.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributer_guide/贡献流程.md b/docs/contributer_guide/贡献流程.md index b6ec2a9a..c93f8476 100644 --- a/docs/contributer_guide/贡献流程.md +++ b/docs/contributer_guide/贡献流程.md @@ -1,7 +1,7 @@ ### 贡献流程 -[贡献源码细则](../CONTRIBUTING.md) +[贡献源码细则](./././CONTRIBUTING.md) #### 1. fork didi/KnowStreaming项目到您的github库 From e79342acf51a12ee24e11e55dcdbd0bed20a7a04 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Mon, 10 Oct 2022 19:19:05 +0800 Subject: [PATCH 033/145] =?UTF-8?q?=E4=BF=AE=E5=A4=8DDSL=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E5=AF=BC=E8=87=B4ZK=E6=8C=87=E6=A0=87=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../streaming/km/persistence/es/dsls/DslsConstant.java | 2 +- .../dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java index 94a8698e..f15fe7a8 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java @@ -81,5 +81,5 @@ public class DslsConstant { public static final String COUNT_GROUP_NOT_METRIC_VALUE = "GroupMetricESDAO/countGroupNotMetricValue"; /**************************************************** Zookeeper ****************************************************/ - public static final String GET_ZOOKEEPER_AGG_LIST_METRICS = "ZookeeperMetricESDAO/getAggListZookeeperMetrics"; + public static final String GET_ZOOKEEPER_AGG_LIST_METRICS = "ZookeeperMetricESDAO/getAggListZookeeperMetrics"; } diff --git a/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics b/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics index c05c221d..c498368b 100644 --- a/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics +++ b/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics @@ -10,13 +10,6 @@ } } }, - { - "term": { - "brokerId": { - "value": %d - } - } - }, { "range": { "timestamp": { From 66dd82f4fdddb619da7f716952934d78188652c1 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Mon, 10 Oct 2022 19:49:22 +0800 Subject: [PATCH 034/145] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=B4=A1=E7=8C=AE?= =?UTF-8?q?=E8=80=85=E5=90=8D=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/contributer_guide/开发者名单.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/contributer_guide/开发者名单.md b/docs/contributer_guide/开发者名单.md index 704ffc5c..ea147bdc 100644 --- a/docs/contributer_guide/开发者名单.md +++ b/docs/contributer_guide/开发者名单.md @@ -9,9 +9,12 @@ |姓名|Github|角色|发放日期| |--|--|--|--| |张亮 | [@zhangliangboy](https://github.com/zhangliangboy)||| +|赵情融 | [@zqrferrari](https://github.com/zqrferrari)||| |谢鹏|[@PenceXie](https://github.com/PenceXie)||| +|孙超|[@lucasun](https://github.com/lucasun)||| +|许喆 | [@potaaaaaato](https://github.com/potaaaaaato)||| |石臻臻 | [@shirenchuang](https://github.com/shirenchuang)||| -|周宇航|[@GraceWalk](https://github.com/GraceWalk)||| +|郭宇航|[@GraceWalk](https://github.com/GraceWalk)||| |曾巧|[@ZQKC](https://github.com/ZQKC)||| |赵寅锐|[@ZHAOYINRUI](https://github.com/ZHAOYINRUI)||| |王东方|[@wangdongfang-aden](https://github.com/wangdongfang-aden)||| @@ -20,7 +23,7 @@ |Huyueeer|[@Huyueeer](https://github.com/Huyueeer)||| |杨光|[@yaangvipguang](https://github.com/yangvipguang)| |王亚聪|[@wangyacongi](https://github.com/wangyacongi)| -|WYAOBO|[@WYAOBO](https://github.com/WYAOBO) +|王耀波|[@WYAOBO](https://github.com/WYAOBO) | Super .Wein(星痕)| [@superspeedone](https://github.com/superspeedone)||| | Yang Jing| [@yangbajing](https://github.com/yangbajing)||| | 刘新元 Liu XinYuan| [@Liu-XinYuan](https://github.com/Liu-XinYuan)||| @@ -34,8 +37,8 @@ | 谢晓东| [@Strangevy](https://github.com/Strangevy)||| | ZhaoXinlong| [@ZhaoXinlong](https://github.com/ZhaoXinlong)||| |xuehaipeng | [@xuehaipeng](https://github.com/xuehaipeng)||| -|mrazkong | [@mrazkong](https://github.com/mrazkong)||| -|xuzhengxi | [@hyper-xx)](https://github.com/hyper-xx)||| +|孔令续 | [@mrazkong](https://github.com/mrazkong)||| +|徐正熙 | [@hyper-xx)](https://github.com/hyper-xx)||| |pierre xiong | [@pierre94](https://github.com/pierre94)||| From 87cd058fd8b6510ea5680fcb1bae4bbceb64dc27 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Mon, 10 Oct 2022 19:54:47 +0800 Subject: [PATCH 035/145] =?UTF-8?q?Broker=E5=A2=9E=E5=8A=A0=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E6=98=AF=E5=90=A6=E5=AD=98=E6=B4=BB=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../km/core/service/broker/BrokerService.java | 4 ++++ .../broker/impl/BrokerServiceImpl.java | 22 +++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/BrokerService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/BrokerService.java index 62f03e65..c8c300a0 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/BrokerService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/BrokerService.java @@ -67,4 +67,8 @@ public interface BrokerService { * 获取总的Broker数 */ Integer countAllBrokers(); + + boolean allServerDown(Long clusterPhyId); + + boolean existServerDown(Long clusterPhyId); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java index 7fc4f4f2..3fd74ee5 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java @@ -262,14 +262,32 @@ public class BrokerServiceImpl extends BaseVersionControlService implements Brok return version; } - - @Override public Integer countAllBrokers() { LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); return brokerDAO.selectCount(lambdaQueryWrapper); } + @Override + public boolean allServerDown(Long clusterPhyId) { + List poList = this.getAllBrokerPOsFromDB(clusterPhyId); + if (ValidateUtils.isEmptyList(poList)) { + return false; + } + + return poList.stream().filter(elem -> elem.getStatus().equals(Constant.DOWN)).count() == poList.size(); + } + + @Override + public boolean existServerDown(Long clusterPhyId) { + List poList = this.getAllBrokerPOsFromDB(clusterPhyId); + if (ValidateUtils.isEmptyList(poList)) { + return false; + } + + return poList.stream().filter(elem -> elem.getStatus().equals(Constant.DOWN)).count() > 0; + } + /**************************************************** private method ****************************************************/ private List listAllBrokersAndUpdateCache(Long clusterPhyId) { From 780fdea2cc1bb6863265ad1078ef7c5224ead4f6 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Tue, 11 Oct 2022 16:54:39 +0800 Subject: [PATCH 036/145] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=8E=B7=E5=8F=96Top?= =?UTF-8?q?N=E7=9A=84Broker=E6=8C=87=E6=A0=87=E6=97=B6=EF=BC=8C=E4=BC=9A?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E9=83=A8=E5=88=86=E6=8C=87=E6=A0=87=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java index edc186f4..83145381 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java @@ -92,7 +92,7 @@ public class BrokerMetricESDAO extends BaseMetricESDAO { Table> table = HashBasedTable.create(); //2、查询指标 - for(String metric : metricBrokerIds.keySet()){ + for(String metric : metrics) { table.putAll( this.listBrokerMetricsByBrokerIds( clusterPhyId, From 79f0a2381314fd15c2a12a76c64287ce618e67e3 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Tue, 11 Oct 2022 17:38:15 +0800 Subject: [PATCH 037/145] update contribuer document --- README.md | 6 +- docs/contributer_guide/开发者名单.md | 42 +--------- docs/contributer_guide/贡献流程.md | 121 +-------------------------- 3 files changed, 9 insertions(+), 160 deletions(-) diff --git a/README.md b/README.md index 5b630fb0..1c08c7c4 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,11 @@ ## 成为社区贡献者 -点击 [这里](CONTRIBUTING.md),了解如何成为 Know Streaming 的贡献者 +1. [贡献源码](https://doc.knowstreaming.com/product/10-contribution) 了解如何成为 Know Streaming 的贡献者 +2. [具体贡献流程](https://doc.knowstreaming.com/product/10-contribution#102-贡献流程) +3. [开源激励计划](https://doc.knowstreaming.com/product/10-contribution#105-开源激励计划) +4. [贡献者名单](https://doc.knowstreaming.com/product/10-contribution#106-贡献者名单) + 获取KnowStreaming开源社区证书。 diff --git a/docs/contributer_guide/开发者名单.md b/docs/contributer_guide/开发者名单.md index ea147bdc..3f2c708d 100644 --- a/docs/contributer_guide/开发者名单.md +++ b/docs/contributer_guide/开发者名单.md @@ -2,45 +2,5 @@ 开源贡献者证书发放名单(定期更新) -贡献者名单请看:[贡献者名单]() - - - -|姓名|Github|角色|发放日期| -|--|--|--|--| -|张亮 | [@zhangliangboy](https://github.com/zhangliangboy)||| -|赵情融 | [@zqrferrari](https://github.com/zqrferrari)||| -|谢鹏|[@PenceXie](https://github.com/PenceXie)||| -|孙超|[@lucasun](https://github.com/lucasun)||| -|许喆 | [@potaaaaaato](https://github.com/potaaaaaato)||| -|石臻臻 | [@shirenchuang](https://github.com/shirenchuang)||| -|郭宇航|[@GraceWalk](https://github.com/GraceWalk)||| -|曾巧|[@ZQKC](https://github.com/ZQKC)||| -|赵寅锐|[@ZHAOYINRUI](https://github.com/ZHAOYINRUI)||| -|王东方|[@wangdongfang-aden](https://github.com/wangdongfang-aden)||| -|haoqi123|[@[haoqi123]](https://github.com/haoqi123)||| -|17hao|[@17hao](https://github.com/17hao)||| -|Huyueeer|[@Huyueeer](https://github.com/Huyueeer)||| -|杨光|[@yaangvipguang](https://github.com/yangvipguang)| -|王亚聪|[@wangyacongi](https://github.com/wangyacongi)| -|王耀波|[@WYAOBO](https://github.com/WYAOBO) -| Super .Wein(星痕)| [@superspeedone](https://github.com/superspeedone)||| -| Yang Jing| [@yangbajing](https://github.com/yangbajing)||| -| 刘新元 Liu XinYuan| [@Liu-XinYuan](https://github.com/Liu-XinYuan)||| -|Joker | [@LiubeyJokerQueue](https://github.com/JokerQueue)||| -|Eason Lau | [@Liubey](https://github.com/Liubey)||| -| hailanxin| [@hailanxin](https://github.com/hailanxin)||| -| Qi Zhang| [@zzzhangqi](https://github.com/zzzhangqi)||| -|Hongten | [@Hongten](https://github.com/Hongten)||| -|fengxsong | [@fengxsong](https://github.com/fengxsong)||| -|f1558 | [@f1558](https://github.com/f1558)||| -| 谢晓东| [@Strangevy](https://github.com/Strangevy)||| -| ZhaoXinlong| [@ZhaoXinlong](https://github.com/ZhaoXinlong)||| -|xuehaipeng | [@xuehaipeng](https://github.com/xuehaipeng)||| -|孔令续 | [@mrazkong](https://github.com/mrazkong)||| -|徐正熙 | [@hyper-xx)](https://github.com/hyper-xx)||| -|pierre xiong | [@pierre94](https://github.com/pierre94)||| - - - +贡献者名单请看:[贡献者名单](https://doc.knowstreaming.com/product/10-contribution#106-贡献者名单) diff --git a/docs/contributer_guide/贡献流程.md b/docs/contributer_guide/贡献流程.md index c93f8476..42679379 100644 --- a/docs/contributer_guide/贡献流程.md +++ b/docs/contributer_guide/贡献流程.md @@ -1,121 +1,6 @@ -### 贡献流程 - -[贡献源码细则](./././CONTRIBUTING.md) - -#### 1. fork didi/KnowStreaming项目到您的github库 - -找到你要Fork的项目,例如 [KnowStreaming](https://github.com/didi/KnowStreaming) ,点击Fork按钮。 - -![在这里插入图片描述](https://img-blog.csdnimg.cn/ac7bfef9ccde49d587c30e702a615ef5.png) - - -#### 2. 克隆或下载您fork的Nacos代码仓库到您本地 - -```sh - -git clone { your fork knowstreaming repo address } - -cd KnowStreaming - -``` - -#### 3. 添加 didi/KnowStreaming仓库为upstream仓库 - - -```sh - -### 添加源仓库 -git remote add upstream https://github.com/didi/KnowStreaming - -### 查看是否添加成功 -git remote -v - - origin ${your fork KnowStreaming repo address} (fetch) - origin ${your fork KnowStreaming repo address} (push) - upstream https://github.com/didi/KnowStreaming(fetch) - upstream https://github.com/didi/KnowStreaming (push) - -### 获取源仓库的基本信息 -git fetch origin -git fetch upstream - -``` -上面是将didi/KnowStreaming添加为远程仓库, 当前就会有2个远程仓库 - -1. origin : 你Fork出来的分叉仓库 -2. upstream : 源仓库 - -git fetch 获取远程仓库的基本信息, 比如 **源仓库**的所有分支就获取到了 - - -#### 4. 同步源仓库开发分支到本地分叉仓库中 - -一般开源项目都会有一个给贡献者提交代码的分支,例如 KnowStreaming的分支是 `dev`; - - -首先我们要将 **源仓库**的开发分支(`dev`) 拉取到本地仓库中 -```sh - -git checkout -b dev upstream/dev -``` -**或者IDEA的形式创建** - -![在这里插入图片描述](https://img-blog.csdnimg.cn/c95f2601a9af41889a5fc20b2a9724a5.png) - -#### 5. 在本地新建的开发分支上进行修改 - -首先请保证您阅读并正确设置KnowStreaming code style, 相关内容请阅读[KnowStreaming 代码规约 ]()。 - -修改时请保证该分支上的修改仅和issue相关,并尽量细化,做到 - -一个分支只修改一件事,一个PR只修改一件事。 - -同时,您的提交记录请尽量描述清楚,主要以谓 + 宾进行描述,如:Fix xxx problem/bug。少量简单的提交可以使用For xxx来描述,如:For codestyle。 如果该提交和某个ISSUE相关,可以添加ISSUE号作为前缀,如:For #10000, Fix xxx problem/bug。 - - -#### 6. Rebase 基础分支和开发分支 - -您修改的时候,可能别人的修改已经提交并被合并,此时可能会有冲突,这里请使用rebase命令进行合并解决,主要有2个好处: - -1. 您的提交记录将会非常优雅,不会出现Merge xxxx branch 等字样 -2. rebase后您分支的提交日志也是一条单链,基本不会出现各种分支交错的情况,回查时更轻松 - -```sh -git fetch upstream - -git rebase -i upstream/dev - -``` -**或者在IDEA的操作如下** - -![在这里插入图片描述](https://img-blog.csdnimg.cn/d75addcfa9564d3d9e1d226a2f7f4d64.png) -选择 源仓库的开发分支 -![在这里插入图片描述](https://img-blog.csdnimg.cn/4e85714df13b44bcb10f1e655450cb72.png) - -推荐使用IDEA的方式, 有冲突的时候更容易解决冲突问题。 - -#### 7. 将您开发完成rebase后的分支,上传到您fork的仓库 - -```sh -git push origin dev -``` - -#### 8. 按照PR模板中的清单创建Pull Request - - - -![在这里插入图片描述](https://img-blog.csdnimg.cn/1dab060aed314666970e3910e05f2205.png) - -选择自己的分支合并到模板分支。 - - -#### 9. 等待合并代码 - -提交了PR之后,需要等待PMC、Commiter 来Review代码,如果有问题需要配合修改重新提交。 - -如果没有问题会直接合并到开发分支`dev`中。 - -注: 如果长时间没有review, 则可以多催促社区来Review代码! +
      +
      +请点击:[贡献流程](https://doc.knowstreaming.com/product/10-contribution#102-贡献流程) \ No newline at end of file From beadde3e06cbabb82ecafd2ce5e1e4ea6baf8dc3 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Tue, 11 Oct 2022 18:46:16 +0800 Subject: [PATCH 038/145] =?UTF-8?q?=E5=A2=9E=E5=8A=A0float=E8=BD=ACinteger?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../know/streaming/km/common/utils/ConvertUtil.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ConvertUtil.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ConvertUtil.java index b20a069c..71b611fd 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ConvertUtil.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ConvertUtil.java @@ -389,4 +389,16 @@ public class ConvertUtil { } return null; } + + public static Integer float2Integer(Float f) { + if (null == f) { + return null; + } + try { + return f.intValue(); + } catch (Exception e) { + // ignore exception + } + return null; + } } From c5caf7c0d64a072570ae52d349348daf472ee110 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Wed, 12 Oct 2022 11:02:41 +0800 Subject: [PATCH 039/145] =?UTF-8?q?ZookeeperService=E4=B8=AD=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=9C=8D=E5=8A=A1=E5=AD=98=E6=B4=BB=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/zookeeper/ZookeeperService.java | 12 ++++++++++ .../zookeeper/impl/ZookeeperServiceImpl.java | 23 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java index 758247aa..8d3a78b1 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java @@ -15,4 +15,16 @@ public interface ZookeeperService { void batchReplaceDataInDB(Long clusterPhyId, List infoList); List listFromDBByCluster(Long clusterPhyId); + + /** + * 所有服务挂掉 + * @return + */ + boolean allServerDown(Long clusterPhyId); + + /** + * 存在服务挂掉 + * @return + */ + boolean existServerDown(Long clusterPhyId); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java index 2f1e318c..84d7eb4c 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java @@ -14,6 +14,7 @@ import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; import com.xiaojukeji.know.streaming.km.common.utils.Tuple; import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; import com.xiaojukeji.know.streaming.km.common.bean.po.zookeeper.ZookeeperInfoPO; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.ZookeeperUtils; import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; @@ -105,6 +106,28 @@ public class ZookeeperServiceImpl implements ZookeeperService { return ConvertUtil.list2List(this.listRawFromDBByCluster(clusterPhyId), ZookeeperInfo.class); } + @Override + public boolean allServerDown(Long clusterPhyId) { + List infoList = this.listFromDBByCluster(clusterPhyId); + if (ValidateUtils.isEmptyList(infoList)) { + return false; + } + + // 所有服务挂掉 + return infoList.stream().filter(elem -> !elem.alive()).count() == infoList.size(); + } + + @Override + public boolean existServerDown(Long clusterPhyId) { + List infoList = this.listFromDBByCluster(clusterPhyId); + if (ValidateUtils.isEmptyList(infoList)) { + // 不存在挂掉的服务 + return false; + } + + // 存在挂掉的服务 + return infoList.stream().filter(elem -> !elem.alive()).count() > 0; + } /**************************************************** private method ****************************************************/ From 63fbe728c45bf976e11999a56c33f85539107634 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Wed, 12 Oct 2022 11:11:25 +0800 Subject: [PATCH 040/145] =?UTF-8?q?=E5=A2=9E=E5=8A=A0ZK=E6=8C=87=E6=A0=87?= =?UTF-8?q?=E4=B8=8A=E6=8A=A5=E6=99=AE=E7=BD=97=E7=B1=B3=E4=BF=AE=E6=96=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/AbstractMonitorSinkService.java | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/km-extends/km-monitor/src/main/java/com/xiaojukeji/know/streaming/km/monitor/component/AbstractMonitorSinkService.java b/km-extends/km-monitor/src/main/java/com/xiaojukeji/know/streaming/km/monitor/component/AbstractMonitorSinkService.java index b4fd1986..b2ca9283 100644 --- a/km-extends/km-monitor/src/main/java/com/xiaojukeji/know/streaming/km/monitor/component/AbstractMonitorSinkService.java +++ b/km-extends/km-monitor/src/main/java/com/xiaojukeji/know/streaming/km/monitor/component/AbstractMonitorSinkService.java @@ -37,29 +37,32 @@ public abstract class AbstractMonitorSinkService implements ApplicationListener< @Override public void onApplicationEvent(BaseMetricEvent event) { executor.execute( () -> { - if(event instanceof BrokerMetricEvent){ + if (event instanceof BrokerMetricEvent) { BrokerMetricEvent brokerMetricEvent = (BrokerMetricEvent)event; sinkMetrics(brokerMetric2SinkPoint(brokerMetricEvent.getBrokerMetrics())); - }else if(event instanceof ClusterMetricEvent){ + } else if(event instanceof ClusterMetricEvent) { ClusterMetricEvent clusterMetricEvent = (ClusterMetricEvent)event; sinkMetrics(clusterMetric2SinkPoint(clusterMetricEvent.getClusterMetrics())); - }else if(event instanceof TopicMetricEvent){ + } else if(event instanceof TopicMetricEvent) { TopicMetricEvent topicMetricEvent = (TopicMetricEvent)event; sinkMetrics(topicMetric2SinkPoint(topicMetricEvent.getTopicMetrics())); - }else if(event instanceof PartitionMetricEvent){ + } else if(event instanceof PartitionMetricEvent) { PartitionMetricEvent partitionMetricEvent = (PartitionMetricEvent)event; sinkMetrics(partitionMetric2SinkPoint(partitionMetricEvent.getPartitionMetrics())); - }else if(event instanceof GroupMetricEvent){ + } else if(event instanceof GroupMetricEvent) { GroupMetricEvent groupMetricEvent = (GroupMetricEvent)event; sinkMetrics(groupMetric2SinkPoint(groupMetricEvent.getGroupMetrics())); - }else if(event instanceof ReplicaMetricEvent){ + } else if(event instanceof ReplicaMetricEvent) { ReplicaMetricEvent replicaMetricEvent = (ReplicaMetricEvent)event; sinkMetrics(replicationMetric2SinkPoint(replicaMetricEvent.getReplicationMetrics())); + } else if(event instanceof ZookeeperMetricEvent) { + ZookeeperMetricEvent zookeeperMetricEvent = (ZookeeperMetricEvent)event; + sinkMetrics(zookeeperMetric2SinkPoint(zookeeperMetricEvent.getZookeeperMetrics())); } } ); } @@ -72,6 +75,7 @@ public abstract class AbstractMonitorSinkService implements ApplicationListener< public abstract Boolean sinkMetrics(List pointList); /**************************************************** private method ****************************************************/ + private List brokerMetric2SinkPoint(List brokerMetrics){ List pointList = new ArrayList<>(); @@ -161,8 +165,23 @@ public abstract class AbstractMonitorSinkService implements ApplicationListener< return pointList; } - private List genSinkPoint(String metricPre, Map metrics, - long timeStamp, Map tagsMap){ + private List zookeeperMetric2SinkPoint(List zookeeperMetricsList){ + List pointList = new ArrayList<>(); + + for(ZookeeperMetrics z : zookeeperMetricsList){ + Map tagsMap = new HashMap<>(); + tagsMap.put(CLUSTER_ID.getName(), z.getClusterPhyId()); + + pointList.addAll(genSinkPoint("Zookeeper", z.getMetrics(), z.getTimestamp(), tagsMap)); + } + + return pointList; + } + + private List genSinkPoint(String metricPre, + Map metrics, + long timeStamp, + Map tagsMap) { List pointList = new ArrayList<>(); for(String metricName : metrics.keySet()){ From 177bb80f3120e8e2c5dccd8a2e16a0bca83c84e2 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Wed, 12 Oct 2022 16:36:04 +0800 Subject: [PATCH 041/145] =?UTF-8?q?application.yml=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=B8=AD=E5=A2=9E=E5=8A=A0ES=E7=94=A8=E6=88=B7=E5=90=8D?= =?UTF-8?q?=E5=AF=86=E7=A0=81=E7=9A=84=E9=85=8D=E7=BD=AE=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-rest/src/main/resources/application.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/km-rest/src/main/resources/application.yml b/km-rest/src/main/resources/application.yml index 08cac4af..4a4b7f1c 100644 --- a/km-rest/src/main/resources/application.yml +++ b/km-rest/src/main/resources/application.yml @@ -84,7 +84,8 @@ client-pool: es: client: address: 127.0.0.1:8091,127.0.0.1:8061,127.0.0.1:8061 - client-cnt: 10 + pass: # ES账号密码,如果有账号密码,按照 username:password 的格式填写,没有则不需要填写 + client-cnt: 10 # 创建的ES客户端数 io-thread-cnt: 2 max-retry-cnt: 5 From 2b600e96eba64a95cd136afc24fcaa3d7cb09a8d Mon Sep 17 00:00:00 2001 From: zengqiao Date: Wed, 12 Oct 2022 16:41:27 +0800 Subject: [PATCH 042/145] =?UTF-8?q?=E5=81=A5=E5=BA=B7=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/health/AbstractHealthCheckTask.java | 115 ++++++++++++++++++ .../km/task/health/BrokerHealthCheckTask.java | 109 +---------------- .../task/health/ClusterHealthCheckTask.java | 109 +---------------- .../km/task/health/GroupHealthCheckTask.java | 107 +--------------- .../km/task/health/TopicHealthCheckTask.java | 108 +--------------- 5 files changed, 127 insertions(+), 421 deletions(-) create mode 100644 km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java new file mode 100644 index 00000000..1f6c83ff --- /dev/null +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java @@ -0,0 +1,115 @@ +package com.xiaojukeji.know.streaming.km.task.health; + +import com.didiglobal.logi.job.common.TaskResult; +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; +import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; +import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; +import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +public abstract class AbstractHealthCheckTask extends AbstractAsyncMetricsDispatchTask { + private static final ILog log = LogFactory.getLog(AbstractHealthCheckTask.class); + + @Autowired + private HealthCheckResultService healthCheckResultService; + + public abstract AbstractHealthCheckService getCheckService(); + + @Override + public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { + return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); + } + + private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { + // 获取配置,<配置名,配置信息> + Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); + + // 检查结果 + List resultList = new ArrayList<>(); + + // 遍历Check-Service + List paramList = this.getCheckService().getResList(clusterPhy.getId()); + if (ValidateUtils.isEmptyList(paramList)) { + // 当前无该维度的资源,则直接设置为 + resultList.addAll(this.getNoResResult(clusterPhy.getId(), this.getCheckService(), healthConfigMap)); + } + + // 遍历资源 + for (ClusterPhyParam clusterPhyParam: paramList) { + resultList.addAll(this.checkAndGetResult(clusterPhyParam, healthConfigMap)); + } + + for (HealthCheckResult checkResult: resultList) { + try { + healthCheckResultService.replace(checkResult); + } catch (Exception e) { + log.error("class=AbstractHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); + } + } + + // 删除10分钟之前的检查结果 + try { + healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); + } catch (Exception e) { + log.error("class=AbstractHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); + } + + return TaskResult.SUCCESS; + } + + private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { + List resultList = new ArrayList<>(); + + // 进行检查 + for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { + HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); + if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { + // 类型不匹配 + continue; + } + + // 记录 + HealthCheckResult checkResult = new HealthCheckResult( + dimensionEnum.getDimension(), + clusterHealthConfig.getCheckNameEnum().getConfigName(), + clusterPhyId, + "-1" + ); + checkResult.setPassed(Constant.YES); + resultList.add(checkResult); + } + + return resultList; + } + + private List checkAndGetResult(ClusterPhyParam clusterPhyParam, + Map healthConfigMap) { + List resultList = new ArrayList<>(); + + // 进行检查 + for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { + HealthCheckResult healthCheckResult = this.getCheckService().checkAndGetResult(clusterPhyParam, clusterHealthConfig); + if (healthCheckResult == null) { + continue; + } + + // 记录 + resultList.add(healthCheckResult); + } + + return resultList; + } +} diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/BrokerHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/BrokerHealthCheckTask.java index 7b611823..ef02be8e 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/BrokerHealthCheckTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/BrokerHealthCheckTask.java @@ -1,30 +1,13 @@ package com.xiaojukeji.know.streaming.km.task.health; import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.didiglobal.logi.log.ILog; -import com.didiglobal.logi.log.LogFactory; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; -import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; -import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; import com.xiaojukeji.know.streaming.km.core.service.health.checker.broker.HealthCheckBrokerService; -import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; -import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; - @NoArgsConstructor @AllArgsConstructor @Task(name = "BrokerHealthCheckTask", @@ -33,98 +16,12 @@ import java.util.Map; autoRegister = true, consensual = ConsensualEnum.BROADCAST, timeout = 2 * 60) -public class BrokerHealthCheckTask extends AbstractAsyncMetricsDispatchTask { - private static final ILog log = LogFactory.getLog(BrokerHealthCheckTask.class); - - @Autowired - private HealthCheckResultService healthCheckResultService; - +public class BrokerHealthCheckTask extends AbstractHealthCheckTask { @Autowired private HealthCheckBrokerService healthCheckBrokerService; @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); - } - - private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - // 获取配置,<配置名,配置信息> - Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); - - // 检查结果 - List resultList = new ArrayList<>(); - - // 遍历Check-Service - List paramList = healthCheckBrokerService.getResList(clusterPhy.getId()); - if (ValidateUtils.isEmptyList(paramList)) { - // 当前无该维度的资源,则直接设置为 - resultList.addAll(this.getNoResResult(clusterPhy.getId(), healthCheckBrokerService, healthConfigMap)); - } - - // 遍历资源 - for (ClusterPhyParam clusterPhyParam: paramList) { - resultList.addAll(this.checkAndGetResult(healthCheckBrokerService, clusterPhyParam, healthConfigMap)); - } - - for (HealthCheckResult checkResult: resultList) { - try { - healthCheckResultService.replace(checkResult); - } catch (Exception e) { - log.error("class=BrokerHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); - } - } - - // 删除10分钟之前的检查结果 - try { - healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); - } catch (Exception e) { - log.error("class=BrokerHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); - } - - return TaskResult.SUCCESS; - } - - private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); - if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { - // 类型不匹配 - continue; - } - - // 记录 - HealthCheckResult checkResult = new HealthCheckResult( - dimensionEnum.getDimension(), - clusterHealthConfig.getCheckNameEnum().getConfigName(), - clusterPhyId, - "-1" - ); - checkResult.setPassed(Constant.YES); - resultList.add(checkResult); - } - - return resultList; - } - - private List checkAndGetResult(AbstractHealthCheckService healthCheckService, - ClusterPhyParam clusterPhyParam, - Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckResult healthCheckResult = healthCheckService.checkAndGetResult(clusterPhyParam, clusterHealthConfig); - if (healthCheckResult == null) { - continue; - } - - // 记录 - resultList.add(healthCheckResult); - } - - return resultList; + public AbstractHealthCheckService getCheckService() { + return healthCheckBrokerService; } } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/ClusterHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/ClusterHealthCheckTask.java index cb7f78b2..43c16cb8 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/ClusterHealthCheckTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/ClusterHealthCheckTask.java @@ -1,30 +1,13 @@ package com.xiaojukeji.know.streaming.km.task.health; import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.didiglobal.logi.log.ILog; -import com.didiglobal.logi.log.LogFactory; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; -import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; -import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; import com.xiaojukeji.know.streaming.km.core.service.health.checker.cluster.HealthCheckClusterService; -import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; -import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; - @NoArgsConstructor @AllArgsConstructor @Task(name = "ClusterHealthCheckTask", @@ -33,98 +16,12 @@ import java.util.Map; autoRegister = true, consensual = ConsensualEnum.BROADCAST, timeout = 2 * 60) -public class ClusterHealthCheckTask extends AbstractAsyncMetricsDispatchTask { - private static final ILog log = LogFactory.getLog(ClusterHealthCheckTask.class); - - @Autowired - private HealthCheckResultService healthCheckResultService; - +public class ClusterHealthCheckTask extends AbstractHealthCheckTask { @Autowired private HealthCheckClusterService healthCheckClusterService; @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); - } - - private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - // 获取配置,<配置名,配置信息> - Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); - - // 检查结果 - List resultList = new ArrayList<>(); - - // 遍历Check-Service - List paramList = healthCheckClusterService.getResList(clusterPhy.getId()); - if (ValidateUtils.isEmptyList(paramList)) { - // 当前无该维度的资源,则直接设置为 - resultList.addAll(this.getNoResResult(clusterPhy.getId(), healthCheckClusterService, healthConfigMap)); - } - - // 遍历资源 - for (ClusterPhyParam clusterPhyParam: paramList) { - resultList.addAll(this.checkAndGetResult(healthCheckClusterService, clusterPhyParam, healthConfigMap)); - } - - for (HealthCheckResult checkResult: resultList) { - try { - healthCheckResultService.replace(checkResult); - } catch (Exception e) { - log.error("class=ClusterHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); - } - } - - // 删除10分钟之前的检查结果 - try { - healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); - } catch (Exception e) { - log.error("class=ClusterHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); - } - - return TaskResult.SUCCESS; - } - - private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); - if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { - // 类型不匹配 - continue; - } - - // 记录 - HealthCheckResult checkResult = new HealthCheckResult( - dimensionEnum.getDimension(), - clusterHealthConfig.getCheckNameEnum().getConfigName(), - clusterPhyId, - "-1" - ); - checkResult.setPassed(Constant.YES); - resultList.add(checkResult); - } - - return resultList; - } - - private List checkAndGetResult(AbstractHealthCheckService healthCheckService, - ClusterPhyParam clusterPhyParam, - Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckResult healthCheckResult = healthCheckService.checkAndGetResult(clusterPhyParam, clusterHealthConfig); - if (healthCheckResult == null) { - continue; - } - - // 记录 - resultList.add(healthCheckResult); - } - - return resultList; + public AbstractHealthCheckService getCheckService() { + return healthCheckClusterService; } } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/GroupHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/GroupHealthCheckTask.java index 581a679a..d24f981d 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/GroupHealthCheckTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/GroupHealthCheckTask.java @@ -1,29 +1,13 @@ package com.xiaojukeji.know.streaming.km.task.health; import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.didiglobal.logi.log.ILog; -import com.didiglobal.logi.log.LogFactory; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; -import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; -import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; import com.xiaojukeji.know.streaming.km.core.service.health.checker.group.HealthCheckGroupService; -import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; -import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; @NoArgsConstructor @AllArgsConstructor @@ -33,98 +17,13 @@ import java.util.Map; autoRegister = true, consensual = ConsensualEnum.BROADCAST, timeout = 2 * 60) -public class GroupHealthCheckTask extends AbstractAsyncMetricsDispatchTask { - private static final ILog log = LogFactory.getLog(GroupHealthCheckTask.class); - - @Autowired - private HealthCheckResultService healthCheckResultService; +public class GroupHealthCheckTask extends AbstractHealthCheckTask { @Autowired private HealthCheckGroupService healthCheckGroupService; @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); - } - - private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - // 获取配置,<配置名,配置信息> - Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); - - // 检查结果 - List resultList = new ArrayList<>(); - - // 遍历Check-Service - List paramList = healthCheckGroupService.getResList(clusterPhy.getId()); - if (ValidateUtils.isEmptyList(paramList)) { - // 当前无该维度的资源,则直接设置为 - resultList.addAll(this.getNoResResult(clusterPhy.getId(), healthCheckGroupService, healthConfigMap)); - } - - // 遍历资源 - for (ClusterPhyParam clusterPhyParam: paramList) { - resultList.addAll(this.checkAndGetResult(healthCheckGroupService, clusterPhyParam, healthConfigMap)); - } - - for (HealthCheckResult checkResult: resultList) { - try { - healthCheckResultService.replace(checkResult); - } catch (Exception e) { - log.error("class=GroupHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); - } - } - - // 删除10分钟之前的检查结果 - try { - healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); - } catch (Exception e) { - log.error("class=GroupHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); - } - - return TaskResult.SUCCESS; - } - - private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); - if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { - // 类型不匹配 - continue; - } - - // 记录 - HealthCheckResult checkResult = new HealthCheckResult( - dimensionEnum.getDimension(), - clusterHealthConfig.getCheckNameEnum().getConfigName(), - clusterPhyId, - "-1" - ); - checkResult.setPassed(Constant.YES); - resultList.add(checkResult); - } - - return resultList; - } - - private List checkAndGetResult(AbstractHealthCheckService healthCheckService, - ClusterPhyParam clusterPhyParam, - Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckResult healthCheckResult = healthCheckService.checkAndGetResult(clusterPhyParam, clusterHealthConfig); - if (healthCheckResult == null) { - continue; - } - - // 记录 - resultList.add(healthCheckResult); - } - - return resultList; + public AbstractHealthCheckService getCheckService() { + return healthCheckGroupService; } } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/TopicHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/TopicHealthCheckTask.java index 8badae99..25a1e531 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/TopicHealthCheckTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/TopicHealthCheckTask.java @@ -1,30 +1,13 @@ package com.xiaojukeji.know.streaming.km.task.health; import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.didiglobal.logi.log.ILog; -import com.didiglobal.logi.log.LogFactory; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; -import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; -import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; import com.xiaojukeji.know.streaming.km.core.service.health.checker.topic.HealthCheckTopicService; -import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; -import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; - @NoArgsConstructor @AllArgsConstructor @Task(name = "TopicHealthCheckTask", @@ -33,98 +16,13 @@ import java.util.Map; autoRegister = true, consensual = ConsensualEnum.BROADCAST, timeout = 2 * 60) -public class TopicHealthCheckTask extends AbstractAsyncMetricsDispatchTask { - private static final ILog log = LogFactory.getLog(TopicHealthCheckTask.class); - - @Autowired - private HealthCheckResultService healthCheckResultService; +public class TopicHealthCheckTask extends AbstractHealthCheckTask { @Autowired private HealthCheckTopicService healthCheckTopicService; @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); - } - - private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - // 获取配置,<配置名,配置信息> - Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); - - // 检查结果 - List resultList = new ArrayList<>(); - - // 遍历Check-Service - List paramList = healthCheckTopicService.getResList(clusterPhy.getId()); - if (ValidateUtils.isEmptyList(paramList)) { - // 当前无该维度的资源,则直接设置为 - resultList.addAll(this.getNoResResult(clusterPhy.getId(), healthCheckTopicService, healthConfigMap)); - } - - // 遍历资源 - for (ClusterPhyParam clusterPhyParam: paramList) { - resultList.addAll(this.checkAndGetResult(healthCheckTopicService, clusterPhyParam, healthConfigMap)); - } - - for (HealthCheckResult checkResult: resultList) { - try { - healthCheckResultService.replace(checkResult); - } catch (Exception e) { - log.error("class=TopicHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); - } - } - - // 删除10分钟之前的检查结果 - try { - healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); - } catch (Exception e) { - log.error("class=TopicHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); - } - - return TaskResult.SUCCESS; - } - - private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); - if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { - // 类型不匹配 - continue; - } - - // 记录 - HealthCheckResult checkResult = new HealthCheckResult( - dimensionEnum.getDimension(), - clusterHealthConfig.getCheckNameEnum().getConfigName(), - clusterPhyId, - "-1" - ); - checkResult.setPassed(Constant.YES); - resultList.add(checkResult); - } - - return resultList; - } - - private List checkAndGetResult(AbstractHealthCheckService healthCheckService, - ClusterPhyParam clusterPhyParam, - Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckResult healthCheckResult = healthCheckService.checkAndGetResult(clusterPhyParam, clusterHealthConfig); - if (healthCheckResult == null) { - continue; - } - - // 记录 - resultList.add(healthCheckResult); - } - - return resultList; + public AbstractHealthCheckService getCheckService() { + return healthCheckTopicService; } } From a6dcbcd35b1f30ccbd3ce55fe4171f7d97ababc6 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Wed, 12 Oct 2022 16:43:16 +0800 Subject: [PATCH 043/145] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=9C=AA=E8=A2=AB?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84import?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../know/streaming/km/rest/api/v3/version/VersionController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/version/VersionController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/version/VersionController.java index 52cc4807..f8e00430 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/version/VersionController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/version/VersionController.java @@ -15,7 +15,6 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; import java.util.List; import java.util.Map; import java.util.SortedMap; From 442f34278c531efb1b5391387c40f13cdbb2c722 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Wed, 12 Oct 2022 16:44:07 +0800 Subject: [PATCH 044/145] =?UTF-8?q?=E6=8C=87=E6=A0=87=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E4=B8=AD=EF=BC=8C=E5=A2=9E=E5=8A=A0=E8=BF=94=E5=9B=9EZK?= =?UTF-8?q?=E7=9A=84=E6=8C=87=E6=A0=87=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../km/biz/version/impl/VersionControlManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java index 52a91520..0460b601 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java @@ -14,7 +14,6 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionControlItem; import com.xiaojukeji.know.streaming.km.common.bean.vo.config.metric.UserMetricConfigVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.version.VersionItemVO; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; import com.xiaojukeji.know.streaming.km.common.enums.version.VersionEnum; import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; import com.xiaojukeji.know.streaming.km.common.utils.VersionUtil; @@ -108,6 +107,7 @@ public class VersionControlManagerImpl implements VersionControlManager { allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_BROKER.getCode()), VersionItemVO.class)); allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_PARTITION.getCode()), VersionItemVO.class)); allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_REPLICATION.getCode()), VersionItemVO.class)); + allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_ZOOKEEPER.getCode()), VersionItemVO.class)); allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(WEB_OP.getCode()), VersionItemVO.class)); Map map = allVersionItemVO.stream().collect( From dc1899a1cdc33d74e8be2765f06e7c0164400763 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Wed, 12 Oct 2022 16:45:47 +0800 Subject: [PATCH 045/145] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=9B=86=E7=BE=A4ZK?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E4=B8=AD=E7=BC=BA=E5=B0=91=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=8A=B6=E6=80=81=E5=AD=97=E6=AE=B5=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java index 960b5d5a..477b3bf4 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java @@ -14,6 +14,9 @@ public class ClusterZookeepersOverviewVO { @ApiModelProperty(value = "主机ip", example = "121.0.0.1") private String host; + @ApiModelProperty(value = "主机存活状态,1:Live,0:Down", example = "1") + private Integer status; + @ApiModelProperty(value = "端口号", example = "2416") private Integer port; From abb064d9d10ee5d3ad1d6bbe621e4e1b369ce067 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Wed, 12 Oct 2022 19:15:19 +0800 Subject: [PATCH 046/145] update readme add who's using know streaming --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c08c7c4..9cc19762 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,14 @@ ## `Know Streaming` 简介 -`Know Streaming`是一套云原生的Kafka管控平台,脱胎于众多互联网内部多年的Kafka运营实践经验,专注于Kafka运维管控、监控告警、资源治理、多活容灾等核心场景。在用户体验、监控、运维管控上进行了平台化、可视化、智能化的建设,提供一系列特色的功能,极大地方便了用户和运维人员的日常使用,让普通运维人员都能成为Kafka专家。整体具有以下特点: +`Know Streaming`是一套云原生的Kafka管控平台,脱胎于众多互联网内部多年的Kafka运营实践经验,专注于Kafka运维管控、监控告警、资源治理、多活容灾等核心场景。在用户体验、监控、运维管控上进行了平台化、可视化、智能化的建设,提供一系列特色的功能,极大地方便了用户和运维人员的日常使用,让普通运维人员都能成为Kafka专家。 + +我们现在正在收集 Know Streaming 用户信息,以帮助我们进一步改进 Know Streaming。 +请在 [issue#663](https://github.com/didi/KnowStreaming/issues/663) 上提供您的使用信息来支持我们:[谁在使用 Know Streaming](https://github.com/didi/KnowStreaming/issues/663) + + + +整体具有以下特点: - 👀  **零侵入、全覆盖** - 无需侵入改造 `Apache Kafka` ,一键便能纳管 `0.10.x` ~ `3.x.x` 众多版本的Kafka,包括 `ZK` 或 `Raft` 运行模式的版本,同时在兼容架构上具备良好的扩展性,帮助您提升集群管理水平; From aced504d2abaa5087ffc1a1e22910ca178e0df5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=A4=E6=9C=88?= <974226358@qq.com> Date: Wed, 12 Oct 2022 22:08:29 +0800 Subject: [PATCH 047/145] Update faq.md --- docs/user_guide/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user_guide/faq.md b/docs/user_guide/faq.md index 98dfbf83..a91cdf79 100644 --- a/docs/user_guide/faq.md +++ b/docs/user_guide/faq.md @@ -37,7 +37,7 @@ ## 8.4、`Jmx`连接失败如何解决? -- 参看 [Jmx 连接配置&问题解决](./9-attachment#jmx-连接失败问题解决) 说明。 +- 参看 [Jmx 连接配置&问题解决](https://doc.knowstreaming.com/product/9-attachment#91jmx-%E8%BF%9E%E6%8E%A5%E5%A4%B1%E8%B4%A5%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3) 说明。   From bb167b9f8d77bce52ddcbd0783596d654a633823 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Thu, 13 Oct 2022 15:31:34 +0800 Subject: [PATCH 048/145] update readme --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++++ .github/ISSUE_TEMPLATE/config.yml | 3 +++ .github/ISSUE_TEMPLATE/detail_optimizing.md | 2 ++ .github/ISSUE_TEMPLATE/discussion.md | 12 ------------ .github/ISSUE_TEMPLATE/feature_request.md | 2 ++ 5 files changed, 11 insertions(+), 12 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/discussion.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 959a0795..7ce18733 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -9,12 +9,16 @@ assignees: '' - [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 +- [ ] 你是否希望来认领这个Bug。 + + ### 环境信息 * KnowStreaming version : xxx * Operating System version : xxx * Java version : xxx + ### 重现该问题的步骤 1. xxx diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 30e38e30..3bedae4a 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,8 @@ blank_issues_enabled: true contact_links: + - name: 讨论问题 + url: https://github.com/didi/KnowStreaming/discussions/new + about: 发起问题、讨论 等等 - name: KnowStreaming官网 url: https://knowstreaming.com/ about: KnowStreaming website diff --git a/.github/ISSUE_TEMPLATE/detail_optimizing.md b/.github/ISSUE_TEMPLATE/detail_optimizing.md index a531ac8a..2f95116d 100644 --- a/.github/ISSUE_TEMPLATE/detail_optimizing.md +++ b/.github/ISSUE_TEMPLATE/detail_optimizing.md @@ -8,6 +8,8 @@ assignees: '' --- - [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 +- [ ] 你是否希望来认领这个优化建议。 + ### 环境信息 diff --git a/.github/ISSUE_TEMPLATE/discussion.md b/.github/ISSUE_TEMPLATE/discussion.md deleted file mode 100644 index bf2b8359..00000000 --- a/.github/ISSUE_TEMPLATE/discussion.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: 讨论/discussion -about: 开启一个关于KnowStreaming的讨论 -title: '' -labels: discussion -assignees: '' - ---- - -## 讨论主题 - -... diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index fe7e88fb..49262909 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -9,6 +9,8 @@ assignees: '' - [ ] 我在 [issues](https://github.com/didi/KnowStreaming/issues) 中并未搜索到与此相关的功能需求。 - [ ] 我在 [release notes] (https://github.com/didi/KnowStreaming/releases)已经发布的版本中并没有搜到相关功能. +- [ ] 你是否希望来认领这个Feature。 + ## 这里描述需求 From 9ad72694af6f5adbeae6f8d9d7d5f941810395b9 Mon Sep 17 00:00:00 2001 From: Richard <49510754+f1558@users.noreply.github.com> Date: Thu, 13 Oct 2022 18:00:43 +0800 Subject: [PATCH 049/145] fix issue: * [issue #666] Fix the type of role phase in ks_km_zookeeper table --- km-dist/init/sql/ddl-ks-km.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/km-dist/init/sql/ddl-ks-km.sql b/km-dist/init/sql/ddl-ks-km.sql index 89f04034..57d1cdb2 100644 --- a/km-dist/init/sql/ddl-ks-km.sql +++ b/km-dist/init/sql/ddl-ks-km.sql @@ -363,11 +363,11 @@ CREATE TABLE `ks_km_zookeeper` ( `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '物理集群ID', `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper主机名', `port` int(16) NOT NULL DEFAULT '-1' COMMENT 'zookeeper端口', - `role` int(16) NOT NULL DEFAULT '-1' COMMENT '角色, leader follower observer', + `role` varchar(16) NOT NULL DEFAULT '-1' COMMENT '角色, leader follower observer', `version` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper版本', `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态: 1存活,0未存活,11存活但是4字命令使用不了', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', PRIMARY KEY (`id`), UNIQUE KEY `uniq_cluster_phy_id_host_port` (`cluster_phy_id`,`host`, `port`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Zookeeper信息表'; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Zookeeper信息表'; From e9cc380a2e59b11e9d1c2ac04f23fba3206c3dc9 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Thu, 13 Oct 2022 18:30:13 +0800 Subject: [PATCH 050/145] update readme --- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 49262909..57d66909 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -8,7 +8,7 @@ assignees: '' --- - [ ] 我在 [issues](https://github.com/didi/KnowStreaming/issues) 中并未搜索到与此相关的功能需求。 -- [ ] 我在 [release notes] (https://github.com/didi/KnowStreaming/releases)已经发布的版本中并没有搜到相关功能. +- [ ] 我在 [release note](https://github.com/didi/KnowStreaming/releases) 已经发布的版本中并没有搜到相关功能. - [ ] 你是否希望来认领这个Feature。 From 3ba447fac21739afef1a75ecfe59c3f2925d54b0 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Thu, 13 Oct 2022 18:49:06 +0800 Subject: [PATCH 051/145] update readme --- .github/ISSUE_TEMPLATE/bug_report.md | 3 ++- .github/ISSUE_TEMPLATE/detail_optimizing.md | 4 +++- .github/ISSUE_TEMPLATE/feature_request.md | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 7ce18733..651a9d95 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -9,8 +9,9 @@ assignees: '' - [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 -- [ ] 你是否希望来认领这个Bug。 + 你是否希望来认领这个Bug。 + 「 Y / N 」 ### 环境信息 diff --git a/.github/ISSUE_TEMPLATE/detail_optimizing.md b/.github/ISSUE_TEMPLATE/detail_optimizing.md index 2f95116d..bbf168f1 100644 --- a/.github/ISSUE_TEMPLATE/detail_optimizing.md +++ b/.github/ISSUE_TEMPLATE/detail_optimizing.md @@ -8,8 +8,10 @@ assignees: '' --- - [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 -- [ ] 你是否希望来认领这个优化建议。 + 你是否希望来认领这个优化建议。 + + 「 Y / N 」 ### 环境信息 diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 57d66909..7bfc5d9b 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -9,7 +9,10 @@ assignees: '' - [ ] 我在 [issues](https://github.com/didi/KnowStreaming/issues) 中并未搜索到与此相关的功能需求。 - [ ] 我在 [release note](https://github.com/didi/KnowStreaming/releases) 已经发布的版本中并没有搜到相关功能. -- [ ] 你是否希望来认领这个Feature。 + +你是否希望来认领这个Feature。 + +「 Y / N 」 ## 这里描述需求 From 41ff914dc3df6d3b7efd15f188ac6d9e74afec35 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Thu, 13 Oct 2022 18:50:41 +0800 Subject: [PATCH 052/145] =?UTF-8?q?=E4=BF=AE=E5=A4=8DZK=E5=85=83=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E8=A1=A8role=E5=AD=97=E6=AE=B5=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/install_guide/版本升级手册.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install_guide/版本升级手册.md b/docs/install_guide/版本升级手册.md index efc01399..903b71b3 100644 --- a/docs/install_guide/版本升级手册.md +++ b/docs/install_guide/版本升级手册.md @@ -14,7 +14,7 @@ CREATE TABLE `ks_km_zookeeper` ( `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '物理集群ID', `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper主机名', `port` int(16) NOT NULL DEFAULT '-1' COMMENT 'zookeeper端口', - `role` int(16) NOT NULL DEFAULT '-1' COMMENT '角色, leader follower observer', + `role` varchar(16) NOT NULL DEFAULT '' COMMENT '角色, leader follower observer', `version` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper版本', `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态: 1存活,0未存活,11存活但是4字命令使用不了', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', From 78d56a49fe2d0057d19e7ec31b00e02e89d4f42e Mon Sep 17 00:00:00 2001 From: _haoqi <1148648445@qq.com> Date: Fri, 14 Oct 2022 11:53:48 +0800 Subject: [PATCH 053/145] =?UTF-8?q?=E4=BF=AE=E6=94=B9zk-Latency=20avg?= =?UTF-8?q?=E4=B8=BA=E5=B0=8F=E6=95=B0=E6=97=B6=E7=9A=84=E6=95=B0=E5=80=BC?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E5=BC=82=E5=B8=B8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bean/entity/zookeeper/fourletterword/MonitorCmdData.java | 2 +- .../bean/entity/zookeeper/fourletterword/ServerCmdData.java | 2 +- .../zookeeper/fourletterword/parser/MonitorCmdDataParser.java | 2 +- .../zookeeper/fourletterword/parser/ServerCmdDataParser.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java index 7ea1339b..2fb3c9da 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java @@ -22,7 +22,7 @@ import lombok.Data; @Data public class MonitorCmdData extends BaseFourLetterWordCmdData { private String zkVersion; - private Long zkAvgLatency; + private Float zkAvgLatency; private Long zkMaxLatency; private Long zkMinLatency; private Long zkPacketsReceived; diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java index 38bd2cf9..883231d6 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java @@ -17,7 +17,7 @@ import lombok.Data; @Data public class ServerCmdData extends BaseFourLetterWordCmdData { private String zkVersion; - private Long zkAvgLatency; + private Float zkAvgLatency; private Long zkMaxLatency; private Long zkMinLatency; private Long zkPacketsReceived; diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java index a33f4da3..55921c12 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java @@ -57,7 +57,7 @@ public class MonitorCmdDataParser implements FourLetterWordDataParser Date: Fri, 14 Oct 2022 11:16:51 +0800 Subject: [PATCH 054/145] fix issue: * [issue #662] Fix deadlocks caused by adding data using MySQL's REPLACE method --- .../streaming/km/common/constant/Constant.java | 1 + .../checkresult/HealthCheckResultService.java | 2 ++ .../impl/HealthCheckResultServiceImpl.java | 15 +++++++++++++++ .../mysql/health/HealthCheckResultDAO.java | 4 ++++ .../resources/mybatis/HealthCheckResultMapper.xml | 12 ++++++++++++ .../km/task/health/AbstractHealthCheckTask.java | 10 ++++------ 6 files changed, 38 insertions(+), 6 deletions(-) diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java index a91f0809..639ad0f3 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java @@ -43,6 +43,7 @@ public class Constant { */ public static final Integer DEFAULT_CLUSTER_HEALTH_SCORE = 90; + public static final Integer PER_BATCH_MAX_VALUE = 100; public static final String DEFAULT_USER_NAME = "know-streaming-app"; diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/HealthCheckResultService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/HealthCheckResultService.java index 19cb292a..6aaddcdb 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/HealthCheckResultService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/HealthCheckResultService.java @@ -20,4 +20,6 @@ public interface HealthCheckResultService { List getResHealthCheckResult(Long clusterPhyId, Integer dimension, String resNme); Map getClusterHealthConfig(Long clusterPhyId); + + void batchReplace(Long clusterPhyId, List healthCheckResults); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/impl/HealthCheckResultServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/impl/HealthCheckResultServiceImpl.java index 09c30a1b..cad2f396 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/impl/HealthCheckResultServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/impl/HealthCheckResultServiceImpl.java @@ -3,10 +3,12 @@ package com.xiaojukeji.know.streaming.km.core.service.health.checkresult.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; +import com.google.common.collect.Lists; import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; import com.xiaojukeji.know.streaming.km.common.bean.po.config.PlatformClusterConfigPO; import com.xiaojukeji.know.streaming.km.common.bean.po.health.HealthCheckResultPO; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; import com.xiaojukeji.know.streaming.km.common.enums.config.ConfigGroupEnum; import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckNameEnum; import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; @@ -88,4 +90,17 @@ public class HealthCheckResultServiceImpl implements HealthCheckResultService { } return configMap; } + + @Override + public void batchReplace(Long clusterPhyId, List healthCheckResults) { + List> healthCheckResultPartitions = Lists.partition(healthCheckResults, Constant.PER_BATCH_MAX_VALUE); + for (List checkResultPartition : healthCheckResultPartitions) { + List healthCheckResultPos = ConvertUtil.list2List(checkResultPartition, HealthCheckResultPO.class); + try { + healthCheckResultDAO.batchReplace(healthCheckResultPos); + } catch (Exception e) { + log.error("method=batchReplace||clusterPhyId={}||checkResultList={}||errMsg=exception!", clusterPhyId, healthCheckResultPos, e); + } + } + } } diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/health/HealthCheckResultDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/health/HealthCheckResultDAO.java index 225437d7..64830fd1 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/health/HealthCheckResultDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/health/HealthCheckResultDAO.java @@ -4,7 +4,11 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.xiaojukeji.know.streaming.km.common.bean.po.health.HealthCheckResultPO; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface HealthCheckResultDAO extends BaseMapper { int replace(HealthCheckResultPO healthCheckResultPO); + + int batchReplace(List healthCheckResultPos); } diff --git a/km-persistence/src/main/resources/mybatis/HealthCheckResultMapper.xml b/km-persistence/src/main/resources/mybatis/HealthCheckResultMapper.xml index bc1bf8ca..076b7522 100644 --- a/km-persistence/src/main/resources/mybatis/HealthCheckResultMapper.xml +++ b/km-persistence/src/main/resources/mybatis/HealthCheckResultMapper.xml @@ -20,4 +20,16 @@ VALUES (#{dimension}, #{configName}, #{clusterPhyId}, #{resName}, #{passed}) + + + insert into ks_km_health_check_result (dimension, config_name, cluster_phy_id, res_name, passed) + values + + (#{item.dimension}, #{item.configName}, #{item.clusterPhyId}, #{item.resName}, #{item.passed}) + + on duplicate key update + dimension = dimension, config_name = config_name, cluster_phy_id = cluster_phy_id, + res_name = res_name, passed = passed + + diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java index 1f6c83ff..4d614881 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java @@ -52,12 +52,10 @@ public abstract class AbstractHealthCheckTask extends AbstractAsyncMetricsDispat resultList.addAll(this.checkAndGetResult(clusterPhyParam, healthConfigMap)); } - for (HealthCheckResult checkResult: resultList) { - try { - healthCheckResultService.replace(checkResult); - } catch (Exception e) { - log.error("class=AbstractHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); - } + try { + healthCheckResultService.batchReplace(clusterPhy.getId(), resultList); + } catch (Exception e) { + log.error("class=AbstractHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); } // 删除10分钟之前的检查结果 From f49206b31662e2c4701437d7d1f560ee0b99fd3a Mon Sep 17 00:00:00 2001 From: chenzy Date: Sun, 16 Oct 2022 22:57:50 +0800 Subject: [PATCH 055/145] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E6=9C=89=E8=AF=AF=E7=9A=84bug=EF=BC=8C?= =?UTF-8?q?=E7=94=B1=E5=8E=9F=E5=85=88=E7=9A=8412=E5=B0=8F=E6=97=B6?= =?UTF-8?q?=E5=88=B6=E6=94=B9=E4=B8=BA24=E5=B0=8F=E6=97=B6=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layout-clusters-fe/src/components/CardBar/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/km-console/packages/layout-clusters-fe/src/components/CardBar/index.tsx b/km-console/packages/layout-clusters-fe/src/components/CardBar/index.tsx index 954839cd..0de8e813 100644 --- a/km-console/packages/layout-clusters-fe/src/components/CardBar/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/components/CardBar/index.tsx @@ -138,7 +138,7 @@ const CardBar = (props: CardBarProps) => { dataIndex: 'updateTime', key: 'updateTime', render: (value: number) => { - return moment(value).format('YYYY-MM-DD hh:mm:ss'); + return moment(value).format('YYYY-MM-DD HH:mm:ss'); }, }, { From ef719cedbc1f71ede8a75345ff10d0f3e7237f50 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Mon, 17 Oct 2022 10:34:21 +0800 Subject: [PATCH 056/145] =?UTF-8?q?=E8=A1=A5=E5=85=85Kafka-Group=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/install_guide/版本升级手册.md | 23 +++++++++++++++++++++++ km-dist/init/sql/ddl-ks-km.sql | 18 ++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/docs/install_guide/版本升级手册.md b/docs/install_guide/版本升级手册.md index 903b71b3..dfa4a8e2 100644 --- a/docs/install_guide/版本升级手册.md +++ b/docs/install_guide/版本升级手册.md @@ -7,6 +7,8 @@ ### 6.2.0、升级至 `master` 版本 +**SQL 变更** + ```sql DROP TABLE IF EXISTS `ks_km_zookeeper`; CREATE TABLE `ks_km_zookeeper` ( @@ -22,8 +24,29 @@ CREATE TABLE `ks_km_zookeeper` ( PRIMARY KEY (`id`), UNIQUE KEY `uniq_cluster_phy_id_host_port` (`cluster_phy_id`,`host`, `port`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Zookeeper信息表'; + + +DROP TABLE IF EXISTS `ks_km_group`; +CREATE TABLE `ks_km_group` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `name` varchar(192) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Group名称', + `member_count` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '成员数', + `topic_members` text CHARACTER SET utf8 COMMENT 'group消费的topic列表', + `partition_assignor` varchar(255) CHARACTER SET utf8 NOT NULL COMMENT '分配策略', + `coordinator_id` int(11) NOT NULL COMMENT 'group协调器brokerId', + `type` int(11) NOT NULL COMMENT 'group类型 0:consumer 1:connector', + `state` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '状态', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_name` (`cluster_phy_id`,`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Group信息表'; + ``` +--- + ### 6.2.1、升级至 `v3.0.0` 版本 diff --git a/km-dist/init/sql/ddl-ks-km.sql b/km-dist/init/sql/ddl-ks-km.sql index 57d1cdb2..907ff355 100644 --- a/km-dist/init/sql/ddl-ks-km.sql +++ b/km-dist/init/sql/ddl-ks-km.sql @@ -371,3 +371,21 @@ CREATE TABLE `ks_km_zookeeper` ( PRIMARY KEY (`id`), UNIQUE KEY `uniq_cluster_phy_id_host_port` (`cluster_phy_id`,`host`, `port`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Zookeeper信息表'; + + +DROP TABLE IF EXISTS `ks_km_group`; +CREATE TABLE `ks_km_group` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `name` varchar(192) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Group名称', + `member_count` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '成员数', + `topic_members` text CHARACTER SET utf8 COMMENT 'group消费的topic列表', + `partition_assignor` varchar(255) CHARACTER SET utf8 NOT NULL COMMENT '分配策略', + `coordinator_id` int(11) NOT NULL COMMENT 'group协调器brokerId', + `type` int(11) NOT NULL COMMENT 'group类型 0:consumer 1:connector', + `state` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '状态', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_name` (`cluster_phy_id`,`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Group信息表'; \ No newline at end of file From ec204a16058dabce98f13b287c0296246c313743 Mon Sep 17 00:00:00 2001 From: "night.liang" Date: Tue, 18 Oct 2022 20:16:40 +0800 Subject: [PATCH 057/145] fix ldap bug --- .../km/common/utils/ValidateUtils.java | 15 ++++- .../login/ldap/remote/LdapAuthentication.java | 55 ++++++++++++++----- 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ValidateUtils.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ValidateUtils.java index 5060e7ea..fbe94674 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ValidateUtils.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ValidateUtils.java @@ -2,6 +2,7 @@ package com.xiaojukeji.know.streaming.km.common.utils; import org.apache.commons.lang.StringUtils; +import java.lang.reflect.Array; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -56,6 +57,18 @@ public class ValidateUtils { return false; } + public static boolean isNotEmpty(T[] array) { + return !isEmpty(array); + } + + public static boolean isEmpty(Object[] array) { + return getLength(array) == 0; + } + + public static int getLength(Object array) { + return array == null ? 0 : Array.getLength(array); + } + /** * 是空字符串 */ @@ -65,7 +78,7 @@ public class ValidateUtils { } else if (isNull(seq1) || isNull(seq2) || seq1.size() != seq2.size()) { return false; } - for (Object elem: seq1) { + for (Object elem : seq1) { if (!seq2.contains(elem)) { return false; } diff --git a/km-extends/km-account/src/main/java/com/xiaojukeji/know/streaming/km/account/login/ldap/remote/LdapAuthentication.java b/km-extends/km-account/src/main/java/com/xiaojukeji/know/streaming/km/account/login/ldap/remote/LdapAuthentication.java index 82043877..8f907dbe 100644 --- a/km-extends/km-account/src/main/java/com/xiaojukeji/know/streaming/km/account/login/ldap/remote/LdapAuthentication.java +++ b/km-extends/km-account/src/main/java/com/xiaojukeji/know/streaming/km/account/login/ldap/remote/LdapAuthentication.java @@ -5,6 +5,7 @@ import com.didiglobal.logi.security.exception.LogiSecurityException; import com.xiaojukeji.know.streaming.km.account.KmAccountConfig; import com.xiaojukeji.know.streaming.km.account.common.ldap.LdapPrincipal; import com.xiaojukeji.know.streaming.km.account.common.ldap.exception.LdapException; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -12,6 +13,8 @@ import org.springframework.stereotype.Component; import javax.naming.Context; import javax.naming.NamingEnumeration; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.ldap.InitialLdapContext; @@ -71,7 +74,7 @@ public class LdapAuthentication { env.put(Context.SECURITY_PRINCIPAL, kmAccountConfig.getSecurityPrincipal()); env.put(Context.SECURITY_CREDENTIALS, kmAccountConfig.getSecurityCredentials()); try { - return new InitialLdapContext(env, null); + return new InitialLdapContext(env, null); } catch (Exception e) { LOGGER.error("method=getLdapContext||errMsg=exception", e); @@ -101,18 +104,21 @@ public class LdapAuthentication { // maybe more than one element while (en.hasMoreElements()) { - Object obj = en.nextElement(); - if (obj instanceof SearchResult) { - SearchResult si = (SearchResult) obj; - + SearchResult obj = en.nextElement(); + if (!ValidateUtils.isNull(obj)) { // 携带LDAP更多元信息以填充用户元信息 LdapPrincipal ldapPrincipal = new LdapPrincipal(); - ldapPrincipal.setUserDN(si.getName() + "," + kmAccountConfig.getLdapBaseDN()); - ldapPrincipal.setSAMAccountName(this.keyValueSplit(si.getAttributes().get("samaccountname").toString())); - ldapPrincipal.setDepartment(this.keyValueSplit(si.getAttributes().get("department").toString())); - ldapPrincipal.setCompany(this.keyValueSplit(si.getAttributes().get("company").toString())); - ldapPrincipal.setDisplayName(this.keyValueSplit(si.getAttributes().get("displayname").toString())); - ldapPrincipal.setMail(this.keyValueSplit(si.getAttributes().get("mail").toString())); + ldapPrincipal.setUserDN(obj.getName() + "," + kmAccountConfig.getLdapBaseDN()); + + Attributes attributes = obj.getAttributes(); + //校验成功后 在获取值 + if (!ValidateUtils.isNull(attributes)) { + ldapPrincipal.setSAMAccountName(getStringValueFromAttributes(attributes, "samaccountname")); + ldapPrincipal.setDepartment(getStringValueFromAttributes(attributes, "department")); + ldapPrincipal.setCompany(getStringValueFromAttributes(attributes, "company")); + ldapPrincipal.setDisplayName(getStringValueFromAttributes(attributes, "displayname")); + ldapPrincipal.setMail(getStringValueFromAttributes(attributes, "mail")); + } return ldapPrincipal; } } @@ -126,6 +132,29 @@ public class LdapAuthentication { } } + private String getStringValueFromAttributes(Attributes attributes, String attrId) { + //增加 多重校验 + int two = 2; + Attribute attribute = attributes.get(attrId); + if (ValidateUtils.isNull(attribute)) { + return ""; + } + + String str = attribute.toString(); + if (ValidateUtils.isBlank(str)) { + return ""; + } + //分割字符串 + String[] split = str.split(":\\s+"); + if (ValidateUtils.isNotEmpty(split)) { + if (split.length >= two) { + return split[1]; + } + } + + return ""; + } + private void closeLdapContext(LdapContext ctx) { if (ctx == null) { return; @@ -137,8 +166,4 @@ public class LdapAuthentication { LOGGER.error("method=closeLdapContext||errMsg=exception", e); } } - - public String keyValueSplit(String keyValue){ - return keyValue.split(":\\s+")[1]; - } } From cc226d552e7fca88d71375e8df760c639f6e1e4f Mon Sep 17 00:00:00 2001 From: dianyang12138 <52749802+dianyang12138@users.noreply.github.com> Date: Fri, 14 Oct 2022 16:44:38 +0800 Subject: [PATCH 058/145] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8Des=E6=A8=A1?= =?UTF-8?q?=E7=89=88=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/init_es_template.sh | 117 ++++++++++++++---- .../km/common/constant/ESIndexConstant.java | 25 +--- km-dist/docker/manager/es_template_create.sh | 111 +++++++++++++---- .../init/template/ks_kafka_replication_metric | 45 ++++++- km-dist/init/template/template.sh | 117 ++++++++++++++---- 5 files changed, 312 insertions(+), 103 deletions(-) diff --git a/bin/init_es_template.sh b/bin/init_es_template.sh index e6beba96..86fcfb66 100644 --- a/bin/init_es_template.sh +++ b/bin/init_es_template.sh @@ -439,7 +439,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esaddr}:${port}/_template/ks_kafka_replication_metric -d '{ "order" : 10, "index_patterns" : [ - "ks_kafka_partition_metric*" + "ks_kafka_replication_metric*" ], "settings" : { "index" : { @@ -500,30 +500,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }[root@10-255-0-23 template]# cat ks_kafka_replication_metric -PUT _template/ks_kafka_replication_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_replication_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - }' + }' curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esaddr}:${port}/_template/ks_kafka_topic_metric -d '{ "order" : 10, @@ -640,7 +617,92 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }' + }' + +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_zookeeper_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + }' for i in {0..6}; do @@ -650,6 +712,7 @@ do curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_group_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_partition_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_replication_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_zookeeper_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_topic_metric${logdate} || \ exit 2 -done \ No newline at end of file +done diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java index 64aef24f..1f5654d0 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java @@ -558,7 +558,7 @@ public class ESIndexConstant { public final static String REPLICATION_TEMPLATE = "{\n" + " \"order\" : 10,\n" + " \"index_patterns\" : [\n" + - " \"ks_kafka_partition_metric*\"\n" + + " \"ks_kafka_replication_metric*\"\n" + " ],\n" + " \"settings\" : {\n" + " \"index\" : {\n" + @@ -619,29 +619,6 @@ public class ESIndexConstant { " }\n" + " },\n" + " \"aliases\" : { }\n" + - " }[root@10-255-0-23 template]# cat ks_kafka_replication_metric\n" + - "PUT _template/ks_kafka_replication_metric\n" + - "{\n" + - " \"order\" : 10,\n" + - " \"index_patterns\" : [\n" + - " \"ks_kafka_replication_metric*\"\n" + - " ],\n" + - " \"settings\" : {\n" + - " \"index\" : {\n" + - " \"number_of_shards\" : \"10\"\n" + - " }\n" + - " },\n" + - " \"mappings\" : {\n" + - " \"properties\" : {\n" + - " \"timestamp\" : {\n" + - " \"format\" : \"yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis\",\n" + - " \"index\" : true,\n" + - " \"type\" : \"date\",\n" + - " \"doc_values\" : true\n" + - " }\n" + - " }\n" + - " },\n" + - " \"aliases\" : { }\n" + " }"; public final static String ZOOKEEPER_INDEX = "ks_kafka_zookeeper_metric"; diff --git a/km-dist/docker/manager/es_template_create.sh b/km-dist/docker/manager/es_template_create.sh index 615bf54d..b52d4291 100644 --- a/km-dist/docker/manager/es_template_create.sh +++ b/km-dist/docker/manager/es_template_create.sh @@ -443,7 +443,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_replication_metric -d '{ "order" : 10, "index_patterns" : [ - "ks_kafka_partition_metric*" + "ks_kafka_replication_metric*" ], "settings" : { "index" : { @@ -504,29 +504,6 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }[root@10-255-0-23 template]# cat ks_kafka_replication_metric -PUT _template/ks_kafka_replication_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_replication_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } }' curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_topic_metric -d '{ @@ -646,6 +623,91 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl "aliases" : { } }' +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_zookeeper_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + }' + for i in {0..6}; do logdate=_$(date -d "${i} day ago" +%Y-%m-%d) @@ -654,6 +716,7 @@ do curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_group_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_partition_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_replication_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_zookeeper_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_topic_metric${logdate} || \ exit 2 done diff --git a/km-dist/init/template/ks_kafka_replication_metric b/km-dist/init/template/ks_kafka_replication_metric index b7beda54..c9c254be 100644 --- a/km-dist/init/template/ks_kafka_replication_metric +++ b/km-dist/init/template/ks_kafka_replication_metric @@ -11,6 +11,49 @@ PUT _template/ks_kafka_replication_metric }, "mappings" : { "properties" : { + "brokerId" : { + "type" : "long" + }, + "partitionId" : { + "type" : "long" + }, + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "topic" : { + "type" : "keyword" + }, + "metrics" : { + "properties" : { + "LogStartOffset" : { + "type" : "float" + }, + "Messages" : { + "type" : "float" + }, + "LogEndOffset" : { + "type" : "float" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, "timestamp" : { "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", "index" : true, @@ -20,4 +63,4 @@ PUT _template/ks_kafka_replication_metric } }, "aliases" : { } - } \ No newline at end of file + } diff --git a/km-dist/init/template/template.sh b/km-dist/init/template/template.sh index e6beba96..86fcfb66 100644 --- a/km-dist/init/template/template.sh +++ b/km-dist/init/template/template.sh @@ -439,7 +439,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esaddr}:${port}/_template/ks_kafka_replication_metric -d '{ "order" : 10, "index_patterns" : [ - "ks_kafka_partition_metric*" + "ks_kafka_replication_metric*" ], "settings" : { "index" : { @@ -500,30 +500,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }[root@10-255-0-23 template]# cat ks_kafka_replication_metric -PUT _template/ks_kafka_replication_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_replication_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - }' + }' curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esaddr}:${port}/_template/ks_kafka_topic_metric -d '{ "order" : 10, @@ -640,7 +617,92 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }' + }' + +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_zookeeper_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + }' for i in {0..6}; do @@ -650,6 +712,7 @@ do curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_group_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_partition_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_replication_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_zookeeper_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_topic_metric${logdate} || \ exit 2 -done \ No newline at end of file +done From ff26a8d46c36eefb1fc9171093fb8260ee789758 Mon Sep 17 00:00:00 2001 From: Richard <49510754+f1558@users.noreply.github.com> Date: Wed, 19 Oct 2022 13:52:51 +0800 Subject: [PATCH 059/145] fix issue: * [issue #700] Adjust the prompt and replace the Arrays.asList() with the Collections.singletonList() --- .../know/streaming/km/biz/group/impl/GroupManagerImpl.java | 2 +- .../streaming/km/core/service/group/impl/GroupServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java index 5ccc3e98..ff1f476b 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java @@ -172,7 +172,7 @@ public class GroupManagerImpl implements GroupManager { } if (!ConsumerGroupState.EMPTY.equals(description.state()) && !ConsumerGroupState.DEAD.equals(description.state())) { - return Result.buildFromRSAndMsg(ResultStatus.KAFKA_OPERATE_FAILED, String.format("group处于%s, 重置失败(仅Empty情况可重置)", GroupStateEnum.getByRawState(description.state()).getState())); + return Result.buildFromRSAndMsg(ResultStatus.KAFKA_OPERATE_FAILED, String.format("group处于%s, 重置失败(仅Empty | Dead 情况可重置)", GroupStateEnum.getByRawState(description.state()).getState())); } // 获取offset diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java index 4cf29d2a..1789671b 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java @@ -104,7 +104,7 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group try { DescribeConsumerGroupsResult describeConsumerGroupsResult = adminClient.describeConsumerGroups( - Arrays.asList(groupName), + Collections.singletonList(groupName), new DescribeConsumerGroupsOptions().timeoutMs(KafkaConstant.ADMIN_CLIENT_REQUEST_TIME_OUT_UNIT_MS).includeAuthorizedOperations(false) ); From 79864955e1f493a0a8aab2da47bd1ae64514e542 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Thu, 20 Oct 2022 11:48:27 +0800 Subject: [PATCH 060/145] =?UTF-8?q?[Feature]=20=E9=9B=86=E7=BE=A4Group?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=8C=89=E7=85=A7Group=E7=BB=B4=E5=BA=A6?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=B1=95=E7=A4=BA=20(#580)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../streaming/km/biz/group/GroupManager.java | 9 + .../km/biz/group/impl/GroupManagerImpl.java | 122 ++++++++-- .../km/biz/topic/TopicStateManager.java | 6 +- .../biz/topic/impl/TopicStateManagerImpl.java | 25 ++ .../dto/cluster/ClusterGroupSummaryDTO.java | 18 ++ .../km/common/bean/entity/group/Group.java | 74 ++++++ .../bean/entity/group/GroupTopicMember.java | 27 +++ .../common/bean/po/group/GroupMemberPO.java | 14 +- .../km/common/bean/po/group/GroupPO.java | 61 +++++ .../common/bean/vo/group/GroupOverviewVO.java | 27 +++ .../bean/vo/group/GroupTopicOverviewVO.java | 2 +- .../common/constant/PaginationConstant.java | 10 + .../km/common/converter/GroupConverter.java | 62 +++++ .../km/common/enums/group/GroupTypeEnum.java | 36 +++ .../km/core/service/group/GroupService.java | 57 +++-- .../group/impl/GroupMetricServiceImpl.java | 3 +- .../service/group/impl/GroupServiceImpl.java | 226 +++++++++++++----- .../km/persistence/mysql/group/GroupDAO.java | 9 + .../v3/cluster/ClusterGroupsController.java | 22 +- .../km/rest/api/v3/group/GroupController.java | 2 +- .../api/v3/topic/TopicStateController.java | 15 +- .../km/task/metadata/SyncKafkaGroupTask.java | 123 +++------- 22 files changed, 744 insertions(+), 206 deletions(-) create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterGroupSummaryDTO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/Group.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/GroupTopicMember.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupPO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupOverviewVO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/GroupConverter.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/group/GroupTypeEnum.java create mode 100644 km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/group/GroupDAO.java diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/GroupManager.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/GroupManager.java index 5c1518ca..a3686c03 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/GroupManager.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/GroupManager.java @@ -1,11 +1,14 @@ package com.xiaojukeji.know.streaming.km.biz.group; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterGroupSummaryDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.group.GroupOffsetResetDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.TopicPartitionKS; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicConsumedDetailVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException; @@ -22,6 +25,10 @@ public interface GroupManager { String searchGroupKeyword, PaginationBaseDTO dto); + PaginationResult pagingGroupTopicMembers(Long clusterPhyId, String groupName, PaginationBaseDTO dto); + + PaginationResult pagingClusterGroupsOverview(Long clusterPhyId, ClusterGroupSummaryDTO dto); + PaginationResult pagingGroupTopicConsumedMetrics(Long clusterPhyId, String topicName, String groupName, @@ -31,4 +38,6 @@ public interface GroupManager { Result> listClusterPhyGroupPartitions(Long clusterPhyId, String groupName, Long startTime, Long endTime); Result resetGroupOffsets(GroupOffsetResetDTO dto, String operator) throws Exception; + + List getGroupTopicOverviewVOList (Long clusterPhyId, List groupMemberPOList); } diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java index ff1f476b..97d464ed 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java @@ -3,11 +3,14 @@ package com.xiaojukeji.know.streaming.km.biz.group.impl; import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; import com.xiaojukeji.know.streaming.km.biz.group.GroupManager; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterGroupSummaryDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.group.GroupOffsetResetDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.partition.PartitionOffsetDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; import com.xiaojukeji.know.streaming.km.common.bean.entity.group.GroupTopic; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.GroupTopicMember; import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.GroupMetrics; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; @@ -15,11 +18,15 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.Topic; import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.TopicPartitionKS; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicConsumedDetailVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; +import com.xiaojukeji.know.streaming.km.common.constant.PaginationConstant; +import com.xiaojukeji.know.streaming.km.common.converter.GroupConverter; import com.xiaojukeji.know.streaming.km.common.enums.AggTypeEnum; import com.xiaojukeji.know.streaming.km.common.enums.OffsetTypeEnum; +import com.xiaojukeji.know.streaming.km.common.enums.SortTypeEnum; import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException; import com.xiaojukeji.know.streaming.km.common.exception.NotExistException; @@ -71,30 +78,60 @@ public class GroupManagerImpl implements GroupManager { String searchGroupKeyword, PaginationBaseDTO dto) { PaginationResult paginationResult = groupService.pagingGroupMembers(clusterPhyId, topicName, groupName, searchTopicKeyword, searchGroupKeyword, dto); - if (paginationResult.failed()) { - return PaginationResult.buildFailure(paginationResult, dto); - } if (!paginationResult.hasData()) { return PaginationResult.buildSuc(new ArrayList<>(), paginationResult); } - // 获取指标 - Result> metricsListResult = groupMetricService.listLatestMetricsAggByGroupTopicFromES( - clusterPhyId, - paginationResult.getData().getBizData().stream().map(elem -> new GroupTopic(elem.getGroupName(), elem.getTopicName())).collect(Collectors.toList()), - Arrays.asList(GroupMetricVersionItems.GROUP_METRIC_LAG), - AggTypeEnum.MAX - ); - if (metricsListResult.failed()) { - // 如果查询失败,则输出错误信息,但是依旧进行已有数据的返回 - log.error("method=pagingGroupMembers||clusterPhyId={}||topicName={}||groupName={}||result={}||errMsg=search es failed", clusterPhyId, topicName, groupName, metricsListResult); + List groupTopicVOList = this.getGroupTopicOverviewVOList(clusterPhyId, paginationResult.getData().getBizData()); + + return PaginationResult.buildSuc(groupTopicVOList, paginationResult); + } + + @Override + public PaginationResult pagingGroupTopicMembers(Long clusterPhyId, String groupName, PaginationBaseDTO dto) { + Group group = groupService.getGroupFromDB(clusterPhyId, groupName); + + //没有topicMember则直接返回 + if (group == null || ValidateUtils.isEmptyList(group.getTopicMembers())) { + return PaginationResult.buildSuc(dto); } - return PaginationResult.buildSuc( - this.convert2GroupTopicOverviewVOList(paginationResult.getData().getBizData(), metricsListResult.getData()), - paginationResult - ); + //排序 + List groupTopicMembers = PaginationUtil.pageBySort(group.getTopicMembers(), PaginationConstant.DEFAULT_GROUP_TOPIC_SORTED_FIELD, SortTypeEnum.DESC.getSortType()); + + //分页 + PaginationResult paginationResult = PaginationUtil.pageBySubData(groupTopicMembers, dto); + + List groupMemberPOList = paginationResult.getData().getBizData().stream().map(elem -> new GroupMemberPO(clusterPhyId, elem.getTopicName(), groupName, group.getState().getState(), elem.getMemberCount())).collect(Collectors.toList()); + + return PaginationResult.buildSuc(this.getGroupTopicOverviewVOList(clusterPhyId, groupMemberPOList), paginationResult); + } + + @Override + public PaginationResult pagingClusterGroupsOverview(Long clusterPhyId, ClusterGroupSummaryDTO dto) { + List groupList = groupService.listClusterGroups(clusterPhyId); + + // 类型转化 + List voList = groupList.stream().map(elem -> GroupConverter.convert2GroupOverviewVO(elem)).collect(Collectors.toList()); + + // 搜索groupName + voList = PaginationUtil.pageByFuzzyFilter(voList, dto.getSearchGroupName(), Arrays.asList("name")); + + //搜索topic + if (!ValidateUtils.isBlank(dto.getSearchTopicName())) { + voList = voList.stream().filter(elem -> { + for (String topicName : elem.getTopicNameList()) { + if (topicName.contains(dto.getSearchTopicName())) { + return true; + } + } + return false; + }).collect(Collectors.toList()); + } + + // 分页 后 返回 + return PaginationUtil.pageBySubData(voList, dto); } @Override @@ -104,7 +141,7 @@ public class GroupManagerImpl implements GroupManager { List latestMetricNames, PaginationSortDTO dto) throws NotExistException, AdminOperateException { // 获取消费组消费的TopicPartition列表 - Map consumedOffsetMap = groupService.getGroupOffset(clusterPhyId, groupName); + Map consumedOffsetMap = groupService.getGroupOffsetFromKafka(clusterPhyId, groupName); List partitionList = consumedOffsetMap.keySet() .stream() .filter(elem -> elem.topic().equals(topicName)) @@ -113,7 +150,7 @@ public class GroupManagerImpl implements GroupManager { Collections.sort(partitionList); // 获取消费组当前运行信息 - ConsumerGroupDescription groupDescription = groupService.getGroupDescription(clusterPhyId, groupName); + ConsumerGroupDescription groupDescription = groupService.getGroupDescriptionFromKafka(clusterPhyId, groupName); // 转换存储格式 Map tpMemberMap = new HashMap<>(); @@ -166,13 +203,13 @@ public class GroupManagerImpl implements GroupManager { return rv; } - ConsumerGroupDescription description = groupService.getGroupDescription(dto.getClusterId(), dto.getGroupName()); + ConsumerGroupDescription description = groupService.getGroupDescriptionFromKafka(dto.getClusterId(), dto.getGroupName()); if (ConsumerGroupState.DEAD.equals(description.state()) && !dto.isCreateIfNotExist()) { return Result.buildFromRSAndMsg(ResultStatus.KAFKA_OPERATE_FAILED, "group不存在, 重置失败"); } if (!ConsumerGroupState.EMPTY.equals(description.state()) && !ConsumerGroupState.DEAD.equals(description.state())) { - return Result.buildFromRSAndMsg(ResultStatus.KAFKA_OPERATE_FAILED, String.format("group处于%s, 重置失败(仅Empty | Dead 情况可重置)", GroupStateEnum.getByRawState(description.state()).getState())); + return Result.buildFromRSAndMsg(ResultStatus.KAFKA_OPERATE_FAILED, String.format("group处于%s, 重置失败(仅Empty情况可重置)", GroupStateEnum.getByRawState(description.state()).getState())); } // 获取offset @@ -185,6 +222,22 @@ public class GroupManagerImpl implements GroupManager { return groupService.resetGroupOffsets(dto.getClusterId(), dto.getGroupName(), offsetMapResult.getData(), operator); } + @Override + public List getGroupTopicOverviewVOList(Long clusterPhyId, List groupMemberPOList) { + // 获取指标 + Result> metricsListResult = groupMetricService.listLatestMetricsAggByGroupTopicFromES( + clusterPhyId, + groupMemberPOList.stream().map(elem -> new GroupTopic(elem.getGroupName(), elem.getTopicName())).collect(Collectors.toList()), + Arrays.asList(GroupMetricVersionItems.GROUP_METRIC_LAG), + AggTypeEnum.MAX + ); + if (metricsListResult.failed()) { + // 如果查询失败,则输出错误信息,但是依旧进行已有数据的返回 + log.error("method=completeMetricData||clusterPhyId={}||result={}||errMsg=search es failed", clusterPhyId, metricsListResult); + } + return this.convert2GroupTopicOverviewVOList(groupMemberPOList, metricsListResult.getData()); + } + /**************************************************** private method ****************************************************/ @@ -293,4 +346,31 @@ public class GroupManagerImpl implements GroupManager { ); } + private List convert2GroupTopicOverviewVOList(String groupName, String state, List groupTopicList, List metricsList) { + if (metricsList == null) { + metricsList = new ArrayList<>(); + } + + // + Map metricsMap = new HashMap<>(); + for (GroupMetrics metrics : metricsList) { + if (!groupName.equals(metrics.getGroup())) continue; + metricsMap.put(metrics.getTopic(), metrics); + } + + List voList = new ArrayList<>(); + for (GroupTopicMember po : groupTopicList) { + GroupTopicOverviewVO vo = ConvertUtil.obj2Obj(po, GroupTopicOverviewVO.class); + vo.setGroupName(groupName); + vo.setState(state); + GroupMetrics metrics = metricsMap.get(po.getTopicName()); + if (metrics != null) { + vo.setMaxLag(ConvertUtil.Float2Long(metrics.getMetrics().get(GroupMetricVersionItems.GROUP_METRIC_LAG))); + } + + voList.add(vo); + } + return voList; + } + } diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java index ec3a3207..f2c05300 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java @@ -1,8 +1,10 @@ package com.xiaojukeji.know.streaming.km.biz.topic; -import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicRecordDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicBrokersPartitionsSummaryVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicRecordVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicStateVO; @@ -23,4 +25,6 @@ public interface TopicStateManager { Result> getTopicPartitions(Long clusterPhyId, String topicName, List metricsNames); Result getTopicBrokersPartitionsSummary(Long clusterPhyId, String topicName); + + PaginationResult pagingTopicGroupsOverview(Long clusterPhyId, String topicName, String searchGroupName, PaginationBaseDTO dto); } diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java index 9c03737a..afc907da 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java @@ -2,17 +2,22 @@ package com.xiaojukeji.know.streaming.km.biz.topic.impl; import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.biz.group.GroupManager; import com.xiaojukeji.know.streaming.km.biz.topic.TopicStateManager; +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicRecordDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.broker.Broker; import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.PartitionMetrics; import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.TopicMetrics; import com.xiaojukeji.know.streaming.km.common.bean.entity.partition.Partition; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.Topic; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; import com.xiaojukeji.know.streaming.km.common.bean.vo.broker.BrokerReplicaSummaryVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicBrokersPartitionsSummaryVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicRecordVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicStateVO; @@ -32,6 +37,7 @@ import com.xiaojukeji.know.streaming.km.common.utils.PaginationUtil; import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.broker.BrokerService; import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; +import com.xiaojukeji.know.streaming.km.core.service.group.GroupService; import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionMetricService; import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionService; import com.xiaojukeji.know.streaming.km.core.service.topic.TopicConfigService; @@ -77,6 +83,12 @@ public class TopicStateManagerImpl implements TopicStateManager { @Autowired private TopicConfigService topicConfigService; + @Autowired + private GroupService groupService; + + @Autowired + private GroupManager groupManager; + @Override public TopicBrokerAllVO getTopicBrokerAll(Long clusterPhyId, String topicName, String searchBrokerHost) throws NotExistException { Topic topic = topicService.getTopic(clusterPhyId, topicName); @@ -346,6 +358,19 @@ public class TopicStateManagerImpl implements TopicStateManager { return Result.buildSuc(vo); } + @Override + public PaginationResult pagingTopicGroupsOverview(Long clusterPhyId, String topicName, String searchGroupName, PaginationBaseDTO dto) { + PaginationResult paginationResult = groupService.pagingGroupMembers(clusterPhyId, topicName, "", "", searchGroupName, dto); + + if (!paginationResult.hasData()) { + return PaginationResult.buildSuc(new ArrayList<>(), paginationResult); + } + + List groupTopicVOList = groupManager.getGroupTopicOverviewVOList(clusterPhyId, paginationResult.getData().getBizData()); + + return PaginationResult.buildSuc(groupTopicVOList, paginationResult); + } + /**************************************************** private method ****************************************************/ private boolean checkIfIgnore(ConsumerRecord consumerRecord, String filterKey, String filterValue) { diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterGroupSummaryDTO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterGroupSummaryDTO.java new file mode 100644 index 00000000..d199e0d8 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterGroupSummaryDTO.java @@ -0,0 +1,18 @@ +package com.xiaojukeji.know.streaming.km.common.bean.dto.cluster; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author wyb + * @date 2022/10/17 + */ +@Data +public class ClusterGroupSummaryDTO extends PaginationBaseDTO { + @ApiModelProperty("查找该Topic") + private String searchTopicName; + + @ApiModelProperty("查找该Group") + private String searchGroupName; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/Group.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/Group.java new file mode 100644 index 00000000..3b2e22e9 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/Group.java @@ -0,0 +1,74 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.group; + +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.kafka.clients.admin.ConsumerGroupDescription; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author wyb + * @date 2022/10/10 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Group { + /** + * 集群id + */ + private Long clusterPhyId; + + /** + * group类型 + * @see GroupTypeEnum + */ + private GroupTypeEnum type; + + /** + * group名称 + */ + private String name; + + /** + * group状态 + * @see GroupStateEnum + */ + private GroupStateEnum state; + + /** + * group成员数量 + */ + private Integer memberCount; + + /** + * group消费的topic列表 + */ + private List topicMembers; + + /** + * group分配策略 + */ + private String partitionAssignor; + + /** + * group协调器brokerId + */ + private int coordinatorId; + + public Group(Long clusterPhyId, String groupName, ConsumerGroupDescription groupDescription) { + this.clusterPhyId = clusterPhyId; + this.type = groupDescription.isSimpleConsumerGroup()? GroupTypeEnum.CONSUMER: GroupTypeEnum.CONNECTOR; + this.name = groupName; + this.state = GroupStateEnum.getByRawState(groupDescription.state()); + this.memberCount = groupDescription.members() == null? 0: groupDescription.members().size(); + this.topicMembers = new ArrayList<>(); + this.partitionAssignor = groupDescription.partitionAssignor(); + this.coordinatorId = groupDescription.coordinator() == null? Constant.INVALID_CODE: groupDescription.coordinator().id(); + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/GroupTopicMember.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/GroupTopicMember.java new file mode 100644 index 00000000..5fe960b1 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/GroupTopicMember.java @@ -0,0 +1,27 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.group; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author wyb + * @date 2022/10/10 + */ +@Data +@NoArgsConstructor +public class GroupTopicMember { + /** + * Topic名称 + */ + private String topicName; + + /** + * 消费此Topic的成员数量 + */ + private Integer memberCount; + + public GroupTopicMember(String topicName, Integer memberCount) { + this.topicName = topicName; + this.memberCount = memberCount; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupMemberPO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupMemberPO.java index 3d999952..7992ac17 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupMemberPO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupMemberPO.java @@ -3,7 +3,6 @@ package com.xiaojukeji.know.streaming.km.common.bean.po.group; import com.baomidou.mybatisplus.annotation.TableName; import com.xiaojukeji.know.streaming.km.common.bean.po.BasePO; import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; import lombok.Data; import lombok.NoArgsConstructor; @@ -23,12 +22,19 @@ public class GroupMemberPO extends BasePO { private Integer memberCount; - public GroupMemberPO(Long clusterPhyId, String topicName, String groupName, Date updateTime) { + public GroupMemberPO(Long clusterPhyId, String topicName, String groupName, String state, Integer memberCount) { this.clusterPhyId = clusterPhyId; this.topicName = topicName; this.groupName = groupName; - this.state = GroupStateEnum.UNKNOWN.getState(); - this.memberCount = 0; + this.state = state; + this.memberCount = memberCount; + } + public GroupMemberPO(Long clusterPhyId, String topicName, String groupName, String state, Integer memberCount, Date updateTime) { + this.clusterPhyId = clusterPhyId; + this.topicName = topicName; + this.groupName = groupName; + this.state = state; + this.memberCount = memberCount; this.updateTime = updateTime; } } \ No newline at end of file diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupPO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupPO.java new file mode 100644 index 00000000..49ac5bf3 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupPO.java @@ -0,0 +1,61 @@ +package com.xiaojukeji.know.streaming.km.common.bean.po.group; + + +import com.baomidou.mybatisplus.annotation.TableName; +import com.xiaojukeji.know.streaming.km.common.bean.po.BasePO; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupTypeEnum; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@NoArgsConstructor +@TableName(Constant.MYSQL_TABLE_NAME_PREFIX + "group") +public class GroupPO extends BasePO { + /** + * 集群id + */ + private Long clusterPhyId; + + /** + * group类型 + * + * @see GroupTypeEnum + */ + private Integer type; + + /** + * group名称 + */ + private String name; + + /** + * group状态 + * + * @see GroupStateEnum + */ + private String state; + + /** + * group成员数量 + */ + private Integer memberCount; + + /** + * group消费的topic列表 + */ + private String topicMembers; + + /** + * group分配策略 + */ + private String partitionAssignor; + + /** + * group协调器brokerId + */ + private int coordinatorId; + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupOverviewVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupOverviewVO.java new file mode 100644 index 00000000..df976643 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupOverviewVO.java @@ -0,0 +1,27 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.group; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * @author wyb + * @date 2022/10/9 + */ +@Data +@ApiModel(value = "Group信息") +public class GroupOverviewVO { + @ApiModelProperty(value = "Group名称", example = "group-know-streaming-test") + private String name; + + @ApiModelProperty(value = "Group状态", example = "Empty") + private String state; + + @ApiModelProperty(value = "group的成员数", example = "12") + private Integer memberCount; + + @ApiModelProperty(value = "Topic列表", example = "[topic1,topic2]") + private List topicNameList; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupTopicOverviewVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupTopicOverviewVO.java index 205fb923..40d2f652 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupTopicOverviewVO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupTopicOverviewVO.java @@ -10,7 +10,7 @@ import lombok.Data; */ @Data @ApiModel(value = "GroupTopic信息") -public class GroupTopicOverviewVO extends GroupTopicBasicVO{ +public class GroupTopicOverviewVO extends GroupTopicBasicVO { @ApiModelProperty(value = "最大Lag", example = "12345678") private Long maxLag; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/PaginationConstant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/PaginationConstant.java index 68dd9358..9b8def80 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/PaginationConstant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/PaginationConstant.java @@ -18,4 +18,14 @@ public class PaginationConstant { * 默认页大小 */ public static final Integer DEFAULT_PAGE_SIZE = 10; + + /** + * group列表的默认排序规则 + */ + public static final String DEFAULT_GROUP_SORTED_FIELD = "name"; + + /** + * groupTopic列表的默认排序规则 + */ + public static final String DEFAULT_GROUP_TOPIC_SORTED_FIELD = "topicName"; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/GroupConverter.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/GroupConverter.java new file mode 100644 index 00000000..131bd243 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/GroupConverter.java @@ -0,0 +1,62 @@ +package com.xiaojukeji.know.streaming.km.common.converter; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.GroupTopicMember; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupOverviewVO; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupTypeEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; + +import java.util.ArrayList; +import java.util.stream.Collectors; + +/** + * @author wyb + * @date 2022/10/10 + */ +public class GroupConverter { + + private GroupConverter() { + + } + + public static GroupOverviewVO convert2GroupOverviewVO(Group group) { + GroupOverviewVO vo = ConvertUtil.obj2Obj(group, GroupOverviewVO.class); + + vo.setState(group.getState().getState()); + vo.setTopicNameList(group.getTopicMembers().stream().map(elem -> elem.getTopicName()).collect(Collectors.toList())); + + return vo; + } + + public static Group convert2Group(GroupPO po) { + if (po == null) { + return null; + } + + Group group = ConvertUtil.obj2Obj(po, Group.class); + if (!ValidateUtils.isBlank(po.getTopicMembers())) { + group.setTopicMembers(ConvertUtil.str2ObjArrayByJson(po.getTopicMembers(), GroupTopicMember.class)); + } else { + group.setTopicMembers(new ArrayList<>()); + } + + group.setType(GroupTypeEnum.getTypeByCode(po.getType())); + group.setState(GroupStateEnum.getByState(po.getState())); + return group; + } + + public static GroupPO convert2GroupPO(Group group) { + if (group == null) { + return null; + } + + GroupPO po = ConvertUtil.obj2Obj(group, GroupPO.class); + po.setTopicMembers(ConvertUtil.obj2Json(group.getTopicMembers())); + po.setType(group.getType().getCode()); + po.setState(group.getState().getState()); + return po; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/group/GroupTypeEnum.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/group/GroupTypeEnum.java new file mode 100644 index 00000000..ebb91ea1 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/group/GroupTypeEnum.java @@ -0,0 +1,36 @@ +package com.xiaojukeji.know.streaming.km.common.enums.group; + +import lombok.Getter; + +/** + * @author wyb + * @date 2022/10/11 + */ +@Getter +public enum GroupTypeEnum { + + UNKNOWN(-1, "Unknown"), + + CONSUMER(0, "Consumer客户端的消费组"), + + CONNECTOR(1, "Connector的消费组"); + + private final Integer code; + + private final String msg; + + GroupTypeEnum(Integer code, String msg) { + this.code = code; + this.msg = msg; + } + + public static GroupTypeEnum getTypeByCode(Integer code) { + if (code == null) return UNKNOWN; + for (GroupTypeEnum groupTypeEnum : GroupTypeEnum.values()) { + if (groupTypeEnum.code.equals(code)) { + return groupTypeEnum; + } + } + return UNKNOWN; + } +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/GroupService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/GroupService.java index 790a7c47..8dc1c535 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/GroupService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/GroupService.java @@ -1,6 +1,7 @@ package com.xiaojukeji.know.streaming.km.core.service.group; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; @@ -16,27 +17,47 @@ import java.util.Map; public interface GroupService { /** - * 从Kafka中获取消费组 - * @param clusterPhyId 集群ID - * @return - * @throws NotExistException - * @throws AdminOperateException + * 从Kafka中获取消费组名称列表 */ List listGroupsFromKafka(Long clusterPhyId) throws NotExistException, AdminOperateException; - Map getGroupOffset(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; + /** + * 从Kafka中获取消费组详细信息 + */ + Group getGroupFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; - ConsumerGroupDescription getGroupDescription(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; + Map getGroupOffsetFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; - int replaceDBData(GroupMemberPO groupMemberPO); + ConsumerGroupDescription getGroupDescriptionFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; - void batchReplace(List newGroupMemberList); + Result resetGroupOffsets(Long clusterPhyId, String groupName, Map offsetMap, String operator) throws NotExistException, AdminOperateException; + /** + * 批量更新DB + */ + void batchReplaceGroupsAndMembers(Long clusterPhyId, List newGroupList, long updateTime); + + int deleteByUpdateTimeBeforeInDB(Long clusterPhyId, Date beforeTime); + + /** + * DB-Group相关接口 + */ GroupStateEnum getGroupStateFromDB(Long clusterPhyId, String groupName); - List listGroupByTopic(Long clusterPhyId, String topicName); + Group getGroupFromDB(Long clusterPhyId, String groupName); - List listGroup(Long clusterPhyId); + List listClusterGroups(Long clusterPhyId); + + List getGroupsFromDB(Long clusterPhyId); + + Integer calGroupCount(Long clusterPhyId); + + Integer calGroupStatCount(Long clusterPhyId, GroupStateEnum stateEnum); + + /** + * DB-GroupTopic相关接口 + */ + List listGroupByTopic(Long clusterPhyId, String topicName); PaginationResult pagingGroupMembers(Long clusterPhyId, String topicName, @@ -45,15 +66,5 @@ public interface GroupService { String searchGroupKeyword, PaginationBaseDTO dto); - int deleteByUpdateTimeBeforeInDB(Long clusterPhyId, Date beforeTime); - - List getGroupsFromDB(Long clusterPhyId); - - GroupMemberPO getGroupFromDB(Long clusterPhyId, String groupName, String topicName); - - Integer calGroupCount(Long clusterPhyId); - - Integer calGroupStatCount(Long clusterPhyId, GroupStateEnum stateEnum); - - Result resetGroupOffsets(Long clusterPhyId, String groupName, Map offsetMap, String operator) throws NotExistException, AdminOperateException; -} + GroupMemberPO getGroupTopicFromDB(Long clusterPhyId, String groupName, String topicName); +} \ No newline at end of file diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupMetricServiceImpl.java index 427edc2c..936897a3 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupMetricServiceImpl.java @@ -24,7 +24,6 @@ import com.xiaojukeji.know.streaming.km.core.service.health.score.HealthScoreSer import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionService; import com.xiaojukeji.know.streaming.km.core.service.version.BaseMetricService; import com.xiaojukeji.know.streaming.km.persistence.es.dao.GroupMetricESDAO; -import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaAdminClient; import org.apache.kafka.clients.admin.OffsetSpec; import org.apache.kafka.common.TopicPartition; import org.springframework.beans.factory.annotation.Autowired; @@ -183,7 +182,7 @@ public class GroupMetricServiceImpl extends BaseMetricService implements GroupMe List metricsList = new ArrayList<>(); try { - Map groupOffsetMap = groupService.getGroupOffset(clusterId, groupName); + Map groupOffsetMap = groupService.getGroupOffsetFromKafka(clusterId, groupName); // 组织 GROUP_METRIC_OFFSET_CONSUMED 指标 for (Map.Entry entry: groupOffsetMap.entrySet()) { diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java index 1789671b..1a923f21 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java @@ -7,11 +7,15 @@ import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; import com.didiglobal.logi.security.common.dto.oplog.OplogDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.GroupTopicMember; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupPO; import com.xiaojukeji.know.streaming.km.common.constant.KafkaConstant; +import com.xiaojukeji.know.streaming.km.common.converter.GroupConverter; import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; import com.xiaojukeji.know.streaming.km.common.enums.operaterecord.ModuleEnum; import com.xiaojukeji.know.streaming.km.common.enums.operaterecord.OperationEnum; @@ -24,6 +28,7 @@ import com.xiaojukeji.know.streaming.km.core.service.group.GroupService; import com.xiaojukeji.know.streaming.km.core.service.oprecord.OpLogWrapService; import com.xiaojukeji.know.streaming.km.core.service.version.BaseVersionControlService; import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaAdminClient; +import com.xiaojukeji.know.streaming.km.persistence.mysql.group.GroupDAO; import com.xiaojukeji.know.streaming.km.persistence.mysql.group.GroupMemberDAO; import org.apache.kafka.clients.admin.*; import org.apache.kafka.clients.consumer.OffsetAndMetadata; @@ -41,6 +46,9 @@ import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemT public class GroupServiceImpl extends BaseVersionControlService implements GroupService { private static final ILog log = LogFactory.getLog(GroupServiceImpl.class); + @Autowired + private GroupDAO groupDAO; + @Autowired private GroupMemberDAO groupMemberDAO; @@ -79,7 +87,43 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group } @Override - public Map getGroupOffset(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { + public Group getGroupFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { + // 获取消费组的详细信息 + ConsumerGroupDescription groupDescription = this.getGroupDescriptionFromKafka(clusterPhyId, groupName); + if (groupDescription == null) { + return null; + } + + Group group = new Group(clusterPhyId, groupName, groupDescription); + + // 获取消费组消费过哪些Topic + Map memberMap = new HashMap<>(); + for (TopicPartition tp : this.getGroupOffsetFromKafka(clusterPhyId, groupName).keySet()) { + memberMap.putIfAbsent(tp.topic(), new GroupTopicMember(tp.topic(), 0)); + } + + // 记录成员信息 + for (MemberDescription memberDescription : groupDescription.members()) { + Set partitionList = new HashSet<>(); + if (!ValidateUtils.isNull(memberDescription.assignment().topicPartitions())) { + partitionList = memberDescription.assignment().topicPartitions(); + } + + Set topicNameSet = partitionList.stream().map(elem -> elem.topic()).collect(Collectors.toSet()); + for (String topicName : topicNameSet) { + memberMap.putIfAbsent(topicName, new GroupTopicMember(topicName, 0)); + + GroupTopicMember member = memberMap.get(topicName); + member.setMemberCount(member.getMemberCount() + 1); + } + } + group.setTopicMembers(memberMap.values().stream().collect(Collectors.toList())); + + return group; + } + + @Override + public Map getGroupOffsetFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { AdminClient adminClient = kafkaAdminClient.getClient(clusterPhyId); Map offsetMap = new HashMap<>(); @@ -99,12 +143,12 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group } @Override - public ConsumerGroupDescription getGroupDescription(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { + public ConsumerGroupDescription getGroupDescriptionFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { AdminClient adminClient = kafkaAdminClient.getClient(clusterPhyId); try { DescribeConsumerGroupsResult describeConsumerGroupsResult = adminClient.describeConsumerGroups( - Collections.singletonList(groupName), + Arrays.asList(groupName), new DescribeConsumerGroupsOptions().timeoutMs(KafkaConstant.ADMIN_CLIENT_REQUEST_TIME_OUT_UNIT_MS).includeAuthorizedOperations(false) ); @@ -117,40 +161,12 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group } @Override - public int replaceDBData(GroupMemberPO groupMemberPO) { - return groupMemberDAO.replace(groupMemberPO); - } - - @Override - public void batchReplace(List newGroupMemberList) { - if (newGroupMemberList == null || newGroupMemberList.isEmpty()) { - return; - } - - Long clusterPhyId = newGroupMemberList.get(0).getClusterPhyId(); - if (clusterPhyId == null) { - return; - } - - List dbGroupMemberList = listGroup(clusterPhyId); - - - Map dbGroupMemberMap = dbGroupMemberList.stream().collect(Collectors.toMap(elem -> elem.getGroupName() + elem.getTopicName(), Function.identity())); - for (GroupMemberPO groupMemberPO : newGroupMemberList) { - GroupMemberPO po = dbGroupMemberMap.remove(groupMemberPO.getGroupName() + groupMemberPO.getTopicName()); - try { - if (po != null) { - groupMemberPO.setId(po.getId()); - groupMemberDAO.updateById(groupMemberPO); - } else { - groupMemberDAO.insert(groupMemberPO); - } - } catch (Exception e) { - log.error("method=batchReplace||clusterPhyId={}||groupName={}||errMsg=exception", clusterPhyId, groupMemberPO.getGroupName(), e); - } - - } + public void batchReplaceGroupsAndMembers(Long clusterPhyId, List newGroupList, long updateTime) { + // 更新Group信息 + this.batchReplaceGroups(clusterPhyId, newGroupList, updateTime); + // 更新Group-Topic信息 + this.batchReplaceGroupMembers(clusterPhyId, newGroupList, updateTime); } @Override @@ -176,14 +192,6 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group return groupMemberDAO.selectList(lambdaQueryWrapper); } - @Override - public List listGroup(Long clusterPhyId) { - LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); - - return groupMemberDAO.selectList(lambdaQueryWrapper); - } - @Override public PaginationResult pagingGroupMembers(Long clusterPhyId, String topicName, @@ -208,8 +216,33 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group return PaginationResult.buildSuc(iPage.getRecords(), iPage); } + @Override + public Group getGroupFromDB(Long clusterPhyId, String groupName) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + lambdaQueryWrapper.eq(GroupPO::getName, groupName); + + GroupPO groupPO = groupDAO.selectOne(lambdaQueryWrapper); + return GroupConverter.convert2Group(groupPO); + } + + @Override + public List listClusterGroups(Long clusterPhyId) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + + return groupDAO.selectList(lambdaQueryWrapper).stream().map(elem -> GroupConverter.convert2Group(elem)).collect(Collectors.toList()); + } + @Override public int deleteByUpdateTimeBeforeInDB(Long clusterPhyId, Date beforeTime) { + // 删除过期Group信息 + LambdaQueryWrapper groupPOLambdaQueryWrapper = new LambdaQueryWrapper<>(); + groupPOLambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + groupPOLambdaQueryWrapper.le(GroupPO::getUpdateTime, beforeTime); + groupDAO.delete(groupPOLambdaQueryWrapper); + + // 删除过期GroupMember信息 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); queryWrapper.le(GroupMemberPO::getUpdateTime, beforeTime); @@ -218,17 +251,19 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group @Override public List getGroupsFromDB(Long clusterPhyId) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); - List poList = groupMemberDAO.selectList(queryWrapper); + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + + List poList = groupDAO.selectList(lambdaQueryWrapper); if (poList == null) { poList = new ArrayList<>(); } - return new ArrayList<>(poList.stream().map(elem -> elem.getGroupName()).collect(Collectors.toSet())); + + return new ArrayList<>(poList.stream().map(elem -> elem.getName()).collect(Collectors.toSet())); } @Override - public GroupMemberPO getGroupFromDB(Long clusterPhyId, String groupName, String topicName) { + public GroupMemberPO getGroupTopicFromDB(Long clusterPhyId, String groupName, String topicName) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); queryWrapper.eq(GroupMemberPO::getTopicName, topicName); @@ -239,28 +274,19 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group @Override public Integer calGroupCount(Long clusterPhyId) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); - List poList = groupMemberDAO.selectList(queryWrapper); - if (poList == null) { - poList = new ArrayList<>(); - } + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); - return poList.stream().map(elem -> elem.getGroupName()).collect(Collectors.toSet()).size(); + return groupDAO.selectCount(lambdaQueryWrapper); } @Override public Integer calGroupStatCount(Long clusterPhyId, GroupStateEnum stateEnum) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); - queryWrapper.eq(GroupMemberPO::getState, stateEnum.getState()); + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + lambdaQueryWrapper.eq(GroupPO::getState, stateEnum.getState()); - List poList = groupMemberDAO.selectList(queryWrapper); - if (poList == null) { - poList = new ArrayList<>(); - } - - return poList.stream().map(elem -> elem.getGroupName()).collect(Collectors.toSet()).size(); + return groupDAO.selectCount(lambdaQueryWrapper); } @Override @@ -303,4 +329,74 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group /**************************************************** private method ****************************************************/ + private void batchReplaceGroupMembers(Long clusterPhyId, List newGroupList, long updateTime) { + if (ValidateUtils.isEmptyList(newGroupList)) { + return; + } + + List dbPOList = this.listClusterGroupsMemberPO(clusterPhyId); + Map dbPOMap = dbPOList.stream().collect(Collectors.toMap(elem -> elem.getGroupName() + elem.getTopicName(), Function.identity())); + + for (Group group: newGroupList) { + for (GroupTopicMember member : group.getTopicMembers()) { + try { + GroupMemberPO newPO = new GroupMemberPO(clusterPhyId, member.getTopicName(), group.getName(), group.getState().getState(), member.getMemberCount(), new Date(updateTime)); + + GroupMemberPO dbPO = dbPOMap.remove(newPO.getGroupName() + newPO.getTopicName()); + if (dbPO != null) { + newPO.setId(dbPO.getId()); + groupMemberDAO.updateById(newPO); + continue; + } + + groupMemberDAO.insert(newPO); + } catch (Exception e) { + log.error( + "method=batchReplaceGroupMembers||clusterPhyId={}||groupName={}||topicName={}||errMsg=exception", + clusterPhyId, group.getName(), member.getTopicName(), e + ); + } + } + } + } + + private void batchReplaceGroups(Long clusterPhyId, List newGroupList, long updateTime) { + if (ValidateUtils.isEmptyList(newGroupList)) { + return; + } + + List dbGroupList = this.listClusterGroupsPO(clusterPhyId); + Map dbGroupMap = dbGroupList.stream().collect(Collectors.toMap(elem -> elem.getName(), Function.identity())); + + for (Group newGroup: newGroupList) { + try { + GroupPO newPO = GroupConverter.convert2GroupPO(newGroup); + newPO.setUpdateTime(new Date(updateTime)); + + GroupPO dbPO = dbGroupMap.remove(newGroup.getName()); + if (dbPO != null) { + newPO.setId(dbPO.getId()); + groupDAO.updateById(newPO); + continue; + } + + groupDAO.insert(newPO); + } catch (Exception e) { + log.error("method=batchGroupReplace||clusterPhyId={}||groupName={}||errMsg=exception", clusterPhyId, newGroup.getName(), e); + } + } + } + + private List listClusterGroupsPO(Long clusterPhyId) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + return groupDAO.selectList(lambdaQueryWrapper); + } + + private List listClusterGroupsMemberPO(Long clusterPhyId) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); + + return groupMemberDAO.selectList(lambdaQueryWrapper); + } } diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/group/GroupDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/group/GroupDAO.java new file mode 100644 index 00000000..eb4465c3 --- /dev/null +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/group/GroupDAO.java @@ -0,0 +1,9 @@ +package com.xiaojukeji.know.streaming.km.persistence.mysql.group; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupPO; +import org.springframework.stereotype.Repository; + +@Repository +public interface GroupDAO extends BaseMapper { +} diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterGroupsController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterGroupsController.java index 4515d695..b035ea02 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterGroupsController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterGroupsController.java @@ -1,12 +1,15 @@ package com.xiaojukeji.know.streaming.km.rest.api.v3.cluster; import com.xiaojukeji.know.streaming.km.biz.group.GroupManager; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterGroupSummaryDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterGroupsOverviewDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricGroupPartitionDTO; +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.field.PaginationFuzzySearchFieldDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.TopicPartitionKS; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line.MetricMultiLinesVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.constant.ApiPrefix; @@ -37,7 +40,8 @@ public class ClusterGroupsController { @Autowired private GroupMetricService groupMetricService; - @ApiOperation(value = "集群Groups信息列表") + @Deprecated + @ApiOperation(value = "集群Groups信息列表", notes = "废弃, 下一个版本删除") @PostMapping(value = "clusters/{clusterPhyId}/groups-overview") @ResponseBody public PaginationResult getClusterPhyGroupsOverview(@PathVariable Long clusterPhyId, @@ -53,6 +57,13 @@ public class ClusterGroupsController { ); } + @ApiOperation(value = "集群Groups信息列表") + @GetMapping(value = "clusters/{clusterPhyId}/groups-overview") + @ResponseBody + public PaginationResult getGroupsOverview(@PathVariable Long clusterPhyId, ClusterGroupSummaryDTO dto) { + return groupManager.pagingClusterGroupsOverview(clusterPhyId, dto); + } + @ApiOperation(value = "集群Groups指标信息") @PostMapping(value = "clusters/{clusterPhyId}/group-metrics") @ResponseBody @@ -70,8 +81,17 @@ public class ClusterGroupsController { return groupManager.listClusterPhyGroupPartitions(clusterPhyId, groupName, startTime, endTime); } + @ApiOperation(value = "Group的Topic列表") + @GetMapping(value = "clusters/{clusterPhyId}/groups/{groupName}/topics-overview") + public PaginationResult getGroupTopicsOverview(@PathVariable Long clusterPhyId, + @PathVariable String groupName, + PaginationBaseDTO dto) { + return groupManager.pagingGroupTopicMembers(clusterPhyId, groupName, dto); + } + /**************************************************** private method ****************************************************/ + @Deprecated private Tuple getSearchKeyWords(ClusterGroupsOverviewDTO dto) { if (ValidateUtils.isEmptyList(dto.getFuzzySearchDTOList())) { return new Tuple<>("", ""); diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/group/GroupController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/group/GroupController.java index 17986b16..55e7e778 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/group/GroupController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/group/GroupController.java @@ -55,7 +55,7 @@ public class GroupController { public Result getGroupMetadataCombineExist(@PathVariable Long clusterPhyId, @PathVariable String groupName, @PathVariable String topicName) { - GroupMemberPO po = groupService.getGroupFromDB(clusterPhyId, groupName, topicName); + GroupMemberPO po = groupService.getGroupTopicFromDB(clusterPhyId, groupName, topicName); if (po == null) { return Result.buildSuc(new GroupMetadataCombineExistVO(clusterPhyId, groupName, topicName, false)); } diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java index d1e09e66..b0371537 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java @@ -3,7 +3,6 @@ package com.xiaojukeji.know.streaming.km.rest.api.v3.topic; import com.xiaojukeji.know.streaming.km.biz.topic.TopicStateManager; import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; -import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicRecordDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.BaseMetrics; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; @@ -11,6 +10,7 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.po.KafkaAclPO; import com.xiaojukeji.know.streaming.km.common.bean.vo.acl.AclBindingVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicBasicVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicBrokersPartitionsSummaryVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicStateVO; @@ -136,8 +136,17 @@ public class TopicStateController { @ApiOperation(value = "TopicGroups基本信息列表") @GetMapping(value = "clusters/{clusterPhyId}/topics/{topicName}/groups-basic") @ResponseBody - public Result> getTopicGroupsBasic(@PathVariable Long clusterPhyId, - @PathVariable String topicName) { + public Result> getTopicGroupsBasic(@PathVariable Long clusterPhyId, @PathVariable String topicName) { return Result.buildSuc(ConvertUtil.list2List(groupService.listGroupByTopic(clusterPhyId, topicName), GroupTopicBasicVO.class)); } + + @ApiOperation("Topic的Group列表") + @GetMapping(value = "clusters/{clusterPhyId}/topics/{topicName}/groups-overview") + public PaginationResult getTopicGroupsOverview(@PathVariable Long clusterPhyId, + @PathVariable String topicName, + @RequestParam(required = false) String searchGroupName, + PaginationBaseDTO dto) { + return topicStateManager.pagingTopicGroupsOverview(clusterPhyId, topicName, searchGroupName, dto); + } + } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncKafkaGroupTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncKafkaGroupTask.java index e2f749fe..cbec5bd2 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncKafkaGroupTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncKafkaGroupTask.java @@ -6,15 +6,10 @@ import com.didiglobal.logi.job.core.consensual.ConsensualEnum; import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; -import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; -import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException; -import com.xiaojukeji.know.streaming.km.common.exception.NotExistException; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.group.GroupService; import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService; -import org.apache.kafka.clients.admin.*; -import org.apache.kafka.common.TopicPartition; import org.springframework.beans.factory.annotation.Autowired; import java.util.*; @@ -38,98 +33,58 @@ public class SyncKafkaGroupTask extends AbstractAsyncMetadataDispatchTask { @Override public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception { - + // 获取集群的Group列表 List groupNameList = groupService.listGroupsFromKafka(clusterPhy.getId()); - TaskResult tr = updateGroupMembersTask(clusterPhy, groupNameList, triggerTimeUnitMs); - if (!TaskResult.SUCCESS.equals(tr)) { - return tr; + TaskResult allSuccess = TaskResult.SUCCESS; + + // 获取Group详细信息 + List groupList = new ArrayList<>(); + for (String groupName : groupNameList) { + try { + Group group = groupService.getGroupFromKafka(clusterPhy.getId(), groupName); + if (group == null) { + continue; + } + + groupList.add(group); + } catch (Exception e) { + log.error("method=processClusterTask||clusterPhyId={}||groupName={}||errMsg=exception", clusterPhy.getId(), groupName, e); + allSuccess = TaskResult.FAIL; + } + } + + // 过滤掉无效的Topic + this.filterTopicIfTopicNotExist(clusterPhy.getId(), groupList); + + // 更新DB中的Group信息 + groupService.batchReplaceGroupsAndMembers(clusterPhy.getId(), groupList, triggerTimeUnitMs); + + // 如果存在错误,则直接返回 + if (!TaskResult.SUCCESS.equals(allSuccess)) { + return allSuccess; } // 删除历史的Group groupService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 5 * 60 * 1000)); - return tr; + return allSuccess; } - - private TaskResult updateGroupMembersTask(ClusterPhy clusterPhy, List groupNameList, long triggerTimeUnitMs) { - List groupMemberPOList = new ArrayList<>(); - TaskResult tr = TaskResult.SUCCESS; - - for (String groupName : groupNameList) { - try { - List poList = this.getGroupMembers(clusterPhy.getId(), groupName, new Date(triggerTimeUnitMs)); - groupMemberPOList.addAll(poList); - } catch (Exception e) { - log.error("method=updateGroupMembersTask||clusterPhyId={}||groupName={}||errMsg=exception", clusterPhy.getId(), groupName, e); - tr = TaskResult.FAIL; - } - } - - groupMemberPOList = this.filterGroupIfTopicNotExist(clusterPhy.getId(), groupMemberPOList); - groupService.batchReplace(groupMemberPOList); - - return tr; - } - - private List getGroupMembers(Long clusterPhyId, String groupName, Date updateTime) throws NotExistException, AdminOperateException { - Map groupMap = new HashMap<>(); - - // 获取消费组消费过哪些Topic - Map offsetMap = groupService.getGroupOffset(clusterPhyId, groupName); - for (TopicPartition topicPartition : offsetMap.keySet()) { - GroupMemberPO po = groupMap.get(topicPartition.topic()); - if (po == null) { - po = new GroupMemberPO(clusterPhyId, topicPartition.topic(), groupName, updateTime); - } - groupMap.put(topicPartition.topic(), po); - } - - // 在上面的基础上,补充消费组的详细信息 - ConsumerGroupDescription consumerGroupDescription = groupService.getGroupDescription(clusterPhyId, groupName); - if (consumerGroupDescription == null) { - return new ArrayList<>(groupMap.values()); - } - - groupMap.forEach((key, val) -> val.setState(GroupStateEnum.getByRawState(consumerGroupDescription.state()).getState())); - - for (MemberDescription memberDescription : consumerGroupDescription.members()) { - Set partitionList = new HashSet<>(); - if (!ValidateUtils.isNull(memberDescription.assignment().topicPartitions())) { - partitionList = memberDescription.assignment().topicPartitions(); - } - - Set topicNameSet = partitionList.stream().map(elem -> elem.topic()).collect(Collectors.toSet()); - for (String topicName : topicNameSet) { - groupMap.putIfAbsent(topicName, new GroupMemberPO(clusterPhyId, topicName, groupName, updateTime)); - - GroupMemberPO po = groupMap.get(topicName); - po.setMemberCount(po.getMemberCount() + 1); - po.setState(GroupStateEnum.getByRawState(consumerGroupDescription.state()).getState()); - } - } - - // 如果该消费组没有正在消费任何Topic的特殊情况,但是这个Group存在 - if (groupMap.isEmpty()) { - GroupMemberPO po = new GroupMemberPO(clusterPhyId, "", groupName, updateTime); - po.setState(GroupStateEnum.getByRawState(consumerGroupDescription.state()).getState()); - groupMap.put("", po); - } - - return new ArrayList<>(groupMap.values()); - } - - private List filterGroupIfTopicNotExist(Long clusterPhyId, List poList) { - if (poList.isEmpty()) { - return poList; + private void filterTopicIfTopicNotExist(Long clusterPhyId, List groupList) { + if (ValidateUtils.isEmptyList(groupList)) { + return; } // 集群Topic集合 Set dbTopicSet = topicService.listTopicsFromDB(clusterPhyId).stream().map(elem -> elem.getTopicName()).collect(Collectors.toSet()); dbTopicSet.add(""); //兼容没有消费Topic的group - + // 过滤Topic不存在的消费组 - return poList.stream().filter(elem -> dbTopicSet.contains(elem.getTopicName())).collect(Collectors.toList()); + for (Group group: groupList) { + group.setTopicMembers( + group.getTopicMembers().stream().filter(elem -> dbTopicSet.contains(elem.getTopicName())).collect(Collectors.toList()) + ); + } } } From 4510c62ebd1ce9d2563782b109a02d5f10ddd4d7 Mon Sep 17 00:00:00 2001 From: _haoqi <1148648445@qq.com> Date: Thu, 20 Oct 2022 14:39:44 +0800 Subject: [PATCH 061/145] =?UTF-8?q?[ISSUE=20#677]=20=E9=87=8D=E5=90=AF?= =?UTF-8?q?=E4=BC=9A=E5=AF=BC=E8=87=B4=E9=83=A8=E5=88=86=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E9=87=87=E9=9B=86=E6=8A=9B=E5=87=BA=E7=A9=BA=E6=8C=87=E9=92=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/es/dao/BrokerMetricESDAO.java | 17 +++--- .../es/dao/ClusterMetricESDAO.java | 10 ++-- .../persistence/es/dao/GroupMetricESDAO.java | 10 ++-- .../persistence/es/dao/TopicMetricESDAO.java | 5 +- .../es/ClusterMetricESDAOTest.java | 53 +++++++++++++++++-- .../es/ReplicationMetricESDAOTest.java | 23 +++++++- .../persistence/es/TopicMetricESDAOTest.java | 33 +++++++++--- 7 files changed, 123 insertions(+), 28 deletions(-) diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java index 83145381..7ee76a3e 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java @@ -207,11 +207,12 @@ public class BrokerMetricESDAO extends BaseMetricESDAO { } for(String metric : metrics){ - String value = esAggrMap.get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esAggrMap.get(metric).getUnusedMap().get(VALUE); + if(null == value){continue;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricMap.put(metric, metricPoint); @@ -243,12 +244,13 @@ public class BrokerMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE); + if(null == value){return;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); metricPoint.setTimeStamp(timestamp); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricPoints.add(metricPoint); @@ -290,13 +292,14 @@ public class BrokerMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long brokerId = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - Double value = Double.valueOf(esBucket.getAggrMap().get(HIST).getBucketList().get(0).getAggrMap() - .get(metric).getUnusedMap().get(VALUE).toString()); + Object value = esBucket.getAggrMap().get(HIST).getBucketList().get(0).getAggrMap() + .get(metric).getUnusedMap().get(VALUE); + if(null == value){return;} List> brokerValue = (null == metricBrokerValueMap.get(metric)) ? new ArrayList<>() : metricBrokerValueMap.get(metric); - brokerValue.add(new Tuple<>(brokerId, value)); + brokerValue.add(new Tuple<>(brokerId, Double.valueOf(value.toString()))); metricBrokerValueMap.put(metric, brokerValue); } }catch (Exception e){ diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ClusterMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ClusterMetricESDAO.java index 82a86253..d53f83bf 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ClusterMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ClusterMetricESDAO.java @@ -169,11 +169,12 @@ public class ClusterMetricESDAO extends BaseMetricESDAO { } for(String metric : metrics){ - String value = esAggrMap.get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esAggrMap.get(metric).getUnusedMap().get(VALUE); + if(null == value){continue;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricMap.put(metric, metricPoint); @@ -194,12 +195,13 @@ public class ClusterMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE); + if(null == value){return;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); metricPoint.setTimeStamp(timestamp); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricPoints.add(metricPoint); diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/GroupMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/GroupMetricESDAO.java index cf65e6ef..782adc2f 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/GroupMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/GroupMetricESDAO.java @@ -173,8 +173,9 @@ public class GroupMetricESDAO extends BaseMetricESDAO { } for(String metric : metrics){ - String value = esAggrMap.get(metric).getUnusedMap().get(VALUE).toString(); - groupMetricPO.getMetrics().put(metric, Float.valueOf(value)); + Object value = esAggrMap.get(metric).getUnusedMap().get(VALUE); + if(value == null){continue;} + groupMetricPO.getMetrics().put(metric, Float.parseFloat(value.toString())); } return groupMetricPO; @@ -192,12 +193,13 @@ public class GroupMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE); + if(value == null){return;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); metricPoint.setTimeStamp(timestamp); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricPoints.add(metricPoint); diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/TopicMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/TopicMetricESDAO.java index e9089c17..e70f2656 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/TopicMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/TopicMetricESDAO.java @@ -337,12 +337,13 @@ public class TopicMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE); + if(value == null){return;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); metricPoint.setTimeStamp(timestamp); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricPoints.add(metricPoint); diff --git a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ClusterMetricESDAOTest.java b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ClusterMetricESDAOTest.java index c69f7129..d0f96bff 100644 --- a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ClusterMetricESDAOTest.java +++ b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ClusterMetricESDAOTest.java @@ -5,13 +5,13 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.search.SearchTerm; import com.xiaojukeji.know.streaming.km.common.bean.entity.search.SearchPage; import com.xiaojukeji.know.streaming.km.common.bean.entity.search.SearchRange; import com.xiaojukeji.know.streaming.km.common.bean.entity.search.SearchSort; +import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ClusterMetricPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; import com.xiaojukeji.know.streaming.km.persistence.es.dao.ClusterMetricESDAO; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; public class ClusterMetricESDAOTest extends KnowStreamApplicationTest { @@ -28,6 +28,53 @@ public class ClusterMetricESDAOTest extends KnowStreamApplicationTest { clusterMetricESDAO.listClusterMetricsByClusterIds(metrics, "avg", clusterIds, startTime, endTime); } + /** + * 测试 + * 获取集群 clusterPhyId 中每个 metric 在指定时间[startTime、endTime]区间内聚合计算(avg、max)之后的统计值 + */ + @Test + public void getClusterMetricsPointTest(){ + Long clusterId = 1L; + List metrics = Arrays.asList( + "Connections", "BytesIn_min_15", "PartitionURP", + "HealthScore_Topics", "EventQueueSize", "ActiveControllerCount", + "GroupDeads", "BytesIn_min_5", "HealthCheckTotal_Topics", + "Partitions", "BytesOut", "Groups", + "BytesOut_min_15", "TotalRequestQueueSize", "HealthCheckPassed_Groups", + "TotalProduceRequests", "HealthCheckPassed", "TotalLogSize", + "GroupEmptys", "PartitionNoLeader", "HealthScore_Brokers", + "Messages", "Topics", "PartitionMinISR_E", + "HealthCheckTotal", "Brokers", "Replicas", + "HealthCheckTotal_Groups", "GroupRebalances", "MessageIn", + "HealthScore", "HealthCheckPassed_Topics", "HealthCheckTotal_Brokers", + "PartitionMinISR_S", "BytesIn", "BytesOut_min_5", + "GroupActives", "MessagesIn", "GroupReBalances", + "HealthCheckPassed_Brokers", "HealthScore_Groups", "TotalResponseQueueSize", + "Zookeepers", "LeaderMessages", "HealthScore_Cluster", + "HealthCheckPassed_Cluster", "HealthCheckTotal_Cluster"); + Long endTime = System.currentTimeMillis(); + Long startTime = endTime - 4 * 60 * 60 * 1000; + + Map metricPointVOS = clusterMetricESDAO.getClusterMetricsPoint( + clusterId, metrics, "avg", startTime, endTime); + + assert null != metricPointVOS; + } + + /** + * 测试 + * 获取集群 clusterId 最新的统计指标 + */ + @Test + public void getClusterLatestMetricsTest(){ + Long clusterId = 1L; + List metrics = Collections.emptyList(); + + ClusterMetricPO clusterLatestMetrics = clusterMetricESDAO.getClusterLatestMetrics(clusterId, metrics); + + assert null != clusterLatestMetrics; + } + @Test public void pagingClusterWithLatestMetricsTest(){ List clusterIds = new ArrayList<>(); diff --git a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ReplicationMetricESDAOTest.java b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ReplicationMetricESDAOTest.java index 6fe0ab4e..98224a3d 100644 --- a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ReplicationMetricESDAOTest.java +++ b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ReplicationMetricESDAOTest.java @@ -2,11 +2,14 @@ package com.xiaojukeji.know.streaming.km.persistence.es; import com.xiaojukeji.know.streaming.km.KnowStreamApplicationTest; import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ReplicationMetricPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; import com.xiaojukeji.know.streaming.km.persistence.es.dao.ReplicationMetricESDAO; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import java.util.ArrayList; +import java.util.Collections; +import java.util.Map; public class ReplicationMetricESDAOTest extends KnowStreamApplicationTest { @@ -15,7 +18,7 @@ public class ReplicationMetricESDAOTest extends KnowStreamApplicationTest { @Test public void getReplicationLatestMetricsTest(){ - Long clusterPhyId = 2l; + Long clusterPhyId = 2L; Integer brokerId = 1; String topic = "know-streaming-test-251"; Integer partitionId = 1; @@ -24,4 +27,22 @@ public class ReplicationMetricESDAOTest extends KnowStreamApplicationTest { assert null != replicationMetricPO; } + + /** + * 测试 + * 获取集群 clusterPhyId 中每个 metric 的指定 partitionId 在指定时间[startTime、endTime]区间内聚合计算(avg、max)之后的统计值 + */ + @Test + public void getReplicationMetricsPointTest(){ + Long clusterPhyId = 2L; + Integer brokerId = 1; + String topic = "know-streaming-test-251"; + Integer partitionId = 1; + Long endTime = System.currentTimeMillis(); + Long startTime = endTime - 4 * 60 * 60 * 1000; + Map metricPointVOMap = replicationMetricESDAO.getReplicationMetricsPoint( + clusterPhyId, topic, brokerId, partitionId, Collections.emptyList(), "avg", startTime, endTime); + + assert null != metricPointVOMap; + } } diff --git a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/TopicMetricESDAOTest.java b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/TopicMetricESDAOTest.java index e3da2f2c..09db0971 100644 --- a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/TopicMetricESDAOTest.java +++ b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/TopicMetricESDAOTest.java @@ -15,7 +15,6 @@ import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; public class TopicMetricESDAOTest extends KnowStreamApplicationTest { @@ -38,14 +37,20 @@ public class TopicMetricESDAOTest extends KnowStreamApplicationTest { @Test public void getTopicsAggsMetricsValueTest(){ Long clusterId = 2L; - String topic = "know-streaming-test-251"; - String topic1 = "topic_test01"; - List metrics = Arrays.asList("BytesIn", "BytesIn_min_5"); + List topicList = Arrays.asList("know-streaming-test-251", "topic_test01"); + List metrics = Arrays.asList( + "Messages", "BytesIn_min_15", "BytesRejected", + "PartitionURP", "HealthCheckTotal", "ReplicationCount", + "CollectMetricsCostTimeUnitSec", "FailedFetchRequests", "BytesIn_min_5", + "HealthScore", "LogSize", "BytesOut", + "FailedProduceRequests", "BytesOut_min_15", "BytesIn", + "BytesOut_min_5", "MessagesIn", "TotalProduceRequests", + "HealthCheckPassed"); Long endTime = System.currentTimeMillis(); Long startTime = endTime - 4 * 60 * 60 * 1000; Table ret = topicMetricESDAO.getTopicsAggsMetricsValue( - clusterId, Arrays.asList(topic, topic1), metrics, "max", startTime, endTime); + clusterId, topicList, metrics, "max", startTime, endTime); assert null != ret; } @@ -90,7 +95,14 @@ public class TopicMetricESDAOTest extends KnowStreamApplicationTest { String topic = "know-streaming-test-251"; String topic1 = "know-streaming-123"; String topic2 = "1209test"; - List metrics = Arrays.asList("BytesIn", "BytesIn_min_5"); + List metrics = Arrays.asList( + "Messages", "BytesIn_min_15", "BytesRejected", + "PartitionURP", "HealthCheckTotal", "ReplicationCount", + "CollectMetricsCostTimeUnitSec", "FailedFetchRequests", "BytesIn_min_5", + "HealthScore", "LogSize", "BytesOut", + "FailedProduceRequests", "BytesOut_min_15", "BytesIn", + "BytesOut_min_5", "MessagesIn", "TotalProduceRequests", + "HealthCheckPassed"); List topicMetricPO = topicMetricESDAO.listTopicLatestMetric(clusterId, Arrays.asList(topic,topic1,topic2), metrics); @@ -101,7 +113,14 @@ public class TopicMetricESDAOTest extends KnowStreamApplicationTest { @Test public void listBrokerMetricsByTopicsTest(){ Long clusterId = 2L; - List metrics = Arrays.asList("BytesIn", "BytesIn_min_5"); + List metrics = Arrays.asList( + "Messages", "BytesIn_min_15", "BytesRejected", + "PartitionURP", "HealthCheckTotal", "ReplicationCount", + "CollectMetricsCostTimeUnitSec", "FailedFetchRequests", "BytesIn_min_5", + "HealthScore", "LogSize", "BytesOut", + "FailedProduceRequests", "BytesOut_min_15", "BytesIn", + "BytesOut_min_5", "MessagesIn", "TotalProduceRequests", + "HealthCheckPassed"); List topics = Arrays.asList("QAtest_1_13", "__consumer_offsets"); Long endTime = System.currentTimeMillis(); Long startTime = endTime - 4 * 60 * 60 * 1000; From e8f77a456b35b1f33f8b8f5da16df477a8351c64 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Thu, 20 Oct 2022 19:16:43 +0800 Subject: [PATCH 062/145] =?UTF-8?q?[Optimize]=20=E4=BC=98=E5=8C=96ZK?= =?UTF-8?q?=E6=8C=87=E6=A0=87=E7=9A=84=E8=8E=B7=E5=8F=96=EF=BC=8C=E5=87=8F?= =?UTF-8?q?=E5=B0=91=E9=87=8D=E5=A4=8D=E9=87=87=E9=9B=86=E7=9A=84=E5=87=BA?= =?UTF-8?q?=E7=8E=B0=20(#709)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、避免不同集群,相同的ZK地址时,指标重复获取的情况; 2、避免集群某个ZK地址获取指标失败时,下一个周期还会继续尝试从该地址获取指标; --- .../km/core/cache/ZookeeperLocalCache.java | 46 ++++++++++ .../impl/ZookeeperMetricServiceImpl.java | 84 ++++++++++++------- 2 files changed, 100 insertions(+), 30 deletions(-) create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/ZookeeperLocalCache.java diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/ZookeeperLocalCache.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/ZookeeperLocalCache.java new file mode 100644 index 00000000..24f6c7f2 --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/ZookeeperLocalCache.java @@ -0,0 +1,46 @@ +package com.xiaojukeji.know.streaming.km.core.cache; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.BaseFourLetterWordCmdData; + +import java.util.concurrent.TimeUnit; + +public class ZookeeperLocalCache { + private static final Cache fourLetterCmdFailedServerCache = Caffeine.newBuilder() + .expireAfterWrite(10, TimeUnit.MINUTES) + .maximumSize(10000) + .build(); + + private static final Cache fourLetterCmdDataCache = Caffeine.newBuilder() + .expireAfterWrite(60, TimeUnit.SECONDS) + .maximumSize(10000) + .build(); + + public static boolean canUse(String host, int port, String cmd) { + String data = fourLetterCmdFailedServerCache.getIfPresent(gen4lwFailedKey(host, port, cmd)); + + return data == null; + } + + public static void setFailed(String host, int port, String cmd) { + fourLetterCmdFailedServerCache.put(gen4lwFailedKey(host, port, cmd), ""); + } + + public static BaseFourLetterWordCmdData getData(String host, int port, String cmd) { + return fourLetterCmdDataCache.getIfPresent(gen4lwFailedKey(host, port, cmd)); + } + + public static void putData(String host, int port, String cmd, BaseFourLetterWordCmdData cmdData) { + fourLetterCmdDataCache.put(gen4lwFailedKey(host, port, cmd), cmdData); + } + + /**************************************************** private method ****************************************************/ + + private static String gen4lwFailedKey(String host, int port, String cmd) { + return host + "@" + port + "@" + cmd; + } + + + +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java index dea1d877..212513aa 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java @@ -10,6 +10,7 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric.Zookeepe import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionJmxInfo; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.BaseFourLetterWordCmdData; import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.ServerCmdData; import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.MonitorCmdDataParser; import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.ServerCmdDataParser; @@ -26,8 +27,8 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterw import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ZookeeperMetricPO; import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import com.xiaojukeji.know.streaming.km.core.cache.ZookeeperLocalCache; import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; -import com.xiaojukeji.know.streaming.km.core.service.kafkacontroller.KafkaControllerService; import com.xiaojukeji.know.streaming.km.core.service.version.BaseMetricService; import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperMetricService; import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; @@ -53,6 +54,7 @@ public class ZookeeperMetricServiceImpl extends BaseMetricService implements Zoo public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD = "getMetricFromMonitorCmd"; public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD = "getMetricFromServerCmd"; public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX = "getMetricFromKafkaByJMX"; + public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_HEALTH_SERVICE = "getMetricFromHealthService"; @Autowired private ClusterPhyService clusterPhyService; @@ -66,9 +68,6 @@ public class ZookeeperMetricServiceImpl extends BaseMetricService implements Zoo @Autowired private KafkaJMXClient kafkaJMXClient; - @Autowired - private KafkaControllerService kafkaControllerService; - @Override protected VersionItemTypeEnum getVersionItemType() { return VersionItemTypeEnum.METRIC_ZOOKEEPER; @@ -171,24 +170,37 @@ public class ZookeeperMetricServiceImpl extends BaseMetricService implements Zoo Result rz = null; for (Tuple hostPort: param.getZkAddressList()) { - Result cmdDataResult = FourLetterWordUtil.executeFourLetterCmd( - param.getClusterPhyId(), - hostPort.getV1(), - hostPort.getV2(), - param.getZkConfig() != null ? param.getZkConfig().getOpenSecure(): false, - param.getZkConfig() != null ? param.getZkConfig().getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, - new ServerCmdDataParser() - ); + ServerCmdData cmdData = null; - if (cmdDataResult.failed()) { - rz = Result.buildFromIgnoreData(cmdDataResult); + BaseFourLetterWordCmdData baseCmdData = ZookeeperLocalCache.getData(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.ServerCmd); + if (baseCmdData != null) { + cmdData = (ServerCmdData) baseCmdData; + } else if (ZookeeperLocalCache.canUse(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.ServerCmd)) { + Result cmdDataResult = FourLetterWordUtil.executeFourLetterCmd( + param.getClusterPhyId(), + hostPort.getV1(), + hostPort.getV2(), + param.getZkConfig() != null ? param.getZkConfig().getOpenSecure(): false, + param.getZkConfig() != null ? param.getZkConfig().getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, + new ServerCmdDataParser() + ); + + if (cmdDataResult.failed()) { + ZookeeperLocalCache.setFailed(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.ServerCmd); + + rz = Result.buildFromIgnoreData(cmdDataResult); + continue; + } + + cmdData = cmdDataResult.getData(); + ZookeeperLocalCache.putData(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.ServerCmd, cmdData); + } else { + // baseCmdData为空 且 当前地址不可使用 continue; } - ServerCmdData cmdData = cmdDataResult.getData(); - ZookeeperMetrics metrics = new ZookeeperMetrics(param.getClusterPhyId()); - metrics.putMetric(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY, cmdData.getZkAvgLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY, cmdData.getZkAvgLatency()); metrics.putMetric(ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY, cmdData.getZkMinLatency().floatValue()); metrics.putMetric(ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY, cmdData.getZkMaxLatency().floatValue()); metrics.putMetric(ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS, cmdData.getZkOutstandingRequests().floatValue()); @@ -208,24 +220,36 @@ public class ZookeeperMetricServiceImpl extends BaseMetricService implements Zoo Result rz = null; for (Tuple hostPort: param.getZkAddressList()) { - Result cmdDataResult = FourLetterWordUtil.executeFourLetterCmd( - param.getClusterPhyId(), - hostPort.getV1(), - hostPort.getV2(), - param.getZkConfig() != null ? param.getZkConfig().getOpenSecure(): false, - param.getZkConfig() != null ? param.getZkConfig().getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, - new MonitorCmdDataParser() - ); + MonitorCmdData cmdData = null; - if (cmdDataResult.failed()) { - rz = Result.buildFromIgnoreData(cmdDataResult); + BaseFourLetterWordCmdData baseCmdData = ZookeeperLocalCache.getData(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.MonitorCmd); + if (baseCmdData != null) { + cmdData = (MonitorCmdData) baseCmdData; + } else if (ZookeeperLocalCache.canUse(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.MonitorCmd)) { + Result cmdDataResult = FourLetterWordUtil.executeFourLetterCmd( + param.getClusterPhyId(), + hostPort.getV1(), + hostPort.getV2(), + param.getZkConfig() != null ? param.getZkConfig().getOpenSecure(): false, + param.getZkConfig() != null ? param.getZkConfig().getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, + new MonitorCmdDataParser() + ); + + if (cmdDataResult.failed()) { + ZookeeperLocalCache.setFailed(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.MonitorCmd); + + rz = Result.buildFromIgnoreData(cmdDataResult); + continue; + } + + cmdData = cmdDataResult.getData(); + ZookeeperLocalCache.putData(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.MonitorCmd, cmdData); + } else { continue; } - MonitorCmdData cmdData = cmdDataResult.getData(); - ZookeeperMetrics metrics = new ZookeeperMetrics(param.getClusterPhyId()); - metrics.putMetric(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY, cmdData.getZkAvgLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY, cmdData.getZkAvgLatency()); metrics.putMetric(ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY, cmdData.getZkMinLatency().floatValue()); metrics.putMetric(ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY, cmdData.getZkMaxLatency().floatValue()); metrics.putMetric(ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS, cmdData.getZkOutstandingRequests().floatValue()); From cafd665a2d3a492a3855af336e347dbaa95005bc Mon Sep 17 00:00:00 2001 From: zengqiao Date: Fri, 21 Oct 2022 11:47:28 +0800 Subject: [PATCH 063/145] =?UTF-8?q?[Optimize]=20=E5=88=A0=E9=99=A4Replica?= =?UTF-8?q?=E6=8C=87=E6=A0=87=E9=87=87=E9=9B=86=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、当集群存在较多副本时,指标采集的性能会严重降低; 2、Replica的指标基本上都是在实时获取时才需要,因此当前先将Replica指标采集任务关闭,后续依据产品需要再看是否开启; --- .../metric/ReplicaMetricCollector.java | 2 +- .../cache/CollectedMetricsLocalCache.java | 16 ----- .../broker/impl/BrokerMetricServiceImpl.java | 39 +++++++++-- .../service/replica/ReplicaMetricService.java | 4 +- .../impl/ReplicaMetricServiceImpl.java | 55 ++++++++-------- .../v3/replica/ReplicaMetricsController.java | 3 +- .../metrics/ReplicaMetricCollectorTask.java | 64 +++++++++---------- 7 files changed, 100 insertions(+), 83 deletions(-) diff --git a/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ReplicaMetricCollector.java b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ReplicaMetricCollector.java index 5f712f93..3f9e0035 100644 --- a/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ReplicaMetricCollector.java +++ b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ReplicaMetricCollector.java @@ -91,7 +91,7 @@ public class ReplicaMetricCollector extends AbstractMetricCollector ret = replicaMetricService.collectReplicaMetricsFromKafkaWithCache( + Result ret = replicaMetricService.collectReplicaMetricsFromKafka( clusterPhyId, metrics.getTopic(), metrics.getBrokerId(), diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/CollectedMetricsLocalCache.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/CollectedMetricsLocalCache.java index bc5b1c34..2fc0a4ff 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/CollectedMetricsLocalCache.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/CollectedMetricsLocalCache.java @@ -24,11 +24,6 @@ public class CollectedMetricsLocalCache { .maximumSize(10000) .build(); - private static final Cache replicaMetricsValueCache = Caffeine.newBuilder() - .expireAfterWrite(90, TimeUnit.SECONDS) - .maximumSize(20000) - .build(); - public static Float getBrokerMetrics(String brokerMetricKey) { return brokerMetricsCache.getIfPresent(brokerMetricKey); } @@ -64,17 +59,6 @@ public class CollectedMetricsLocalCache { partitionMetricsCache.put(partitionMetricsKey, metricsList); } - public static Float getReplicaMetrics(String replicaMetricsKey) { - return replicaMetricsValueCache.getIfPresent(replicaMetricsKey); - } - - public static void putReplicaMetrics(String replicaMetricsKey, Float value) { - if (value == null) { - return; - } - replicaMetricsValueCache.put(replicaMetricsKey, value); - } - public static String genBrokerMetricKey(Long clusterPhyId, Integer brokerId, String metricName) { return clusterPhyId + "@" + brokerId + "@" + metricName; } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerMetricServiceImpl.java index 93c343ff..e82882e1 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerMetricServiceImpl.java @@ -37,6 +37,8 @@ import com.xiaojukeji.know.streaming.km.core.service.version.metrics.BrokerMetri import com.xiaojukeji.know.streaming.km.core.service.version.metrics.ReplicaMetricVersionItems; import com.xiaojukeji.know.streaming.km.persistence.es.dao.BrokerMetricESDAO; import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaJMXClient; +import org.apache.kafka.clients.admin.LogDirDescription; +import org.apache.kafka.clients.admin.ReplicaInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -49,6 +51,7 @@ import java.util.*; import java.util.stream.Collectors; import static com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus.*; +import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionEnum.*; /** * @author didi @@ -105,7 +108,11 @@ public class BrokerMetricServiceImpl extends BaseMetricService implements Broker registerVCHandler( BROKER_METHOD_GET_HEALTH_SCORE, this::getMetricHealthScore); registerVCHandler( BROKER_METHOD_GET_PARTITIONS_SKEW, this::getPartitionsSkew); registerVCHandler( BROKER_METHOD_GET_LEADERS_SKEW, this::getLeadersSkew); - registerVCHandler( BROKER_METHOD_GET_LOG_SIZE, this::getLogSize); +// registerVCHandler( BROKER_METHOD_GET_LOG_SIZE, this::getLogSize); + + registerVCHandler( BROKER_METHOD_GET_LOG_SIZE, V_0_10_0_0, V_1_0_0, "getLogSizeFromJmx", this::getLogSizeFromJmx); + registerVCHandler( BROKER_METHOD_GET_LOG_SIZE, V_1_0_0, V_MAX, "getLogSizeFromClient", this::getLogSizeFromClient); + registerVCHandler( BROKER_METHOD_IS_BROKER_ALIVE, this::isBrokerAlive); } @@ -351,7 +358,7 @@ public class BrokerMetricServiceImpl extends BaseMetricService implements Broker ); } - private Result getLogSize(VersionItemParam metricParam) { + private Result getLogSizeFromJmx(VersionItemParam metricParam) { BrokerMetricParam param = (BrokerMetricParam)metricParam; String metric = param.getMetric(); @@ -360,19 +367,17 @@ public class BrokerMetricServiceImpl extends BaseMetricService implements Broker List partitions = partitionService.listPartitionByBroker(clusterId, brokerId); - JmxConnectorWrap jmxConnectorWrap = kafkaJMXClient.getClientWithCheck(clusterId, brokerId); - if (ValidateUtils.isNull(jmxConnectorWrap)){return Result.buildFailure(VC_JMX_INIT_ERROR);} - Float logSizeSum = 0f; for(Partition p : partitions) { try { - Result metricsResult = replicaMetricService.collectReplicaMetricsFromKafkaWithCache( + Result metricsResult = replicaMetricService.collectReplicaMetricsFromKafka( clusterId, p.getTopicName(), brokerId, p.getPartitionId(), ReplicaMetricVersionItems.REPLICATION_METRIC_LOG_SIZE ); + if(null == metricsResult || metricsResult.failed() || null == metricsResult.getData()) { continue; } @@ -391,6 +396,28 @@ public class BrokerMetricServiceImpl extends BaseMetricService implements Broker return Result.buildSuc(BrokerMetrics.initWithMetric(clusterId, brokerId, metric, logSizeSum)); } + private Result getLogSizeFromClient(VersionItemParam metricParam) { + BrokerMetricParam param = (BrokerMetricParam)metricParam; + + String metric = param.getMetric(); + Long clusterId = param.getClusterId(); + Integer brokerId = param.getBrokerId(); + + Result> descriptionMapResult = brokerService.getBrokerLogDirDescFromKafka(clusterId, brokerId); + if(null == descriptionMapResult || descriptionMapResult.failed() || null == descriptionMapResult.getData()) { + return Result.buildFromIgnoreData(descriptionMapResult); + } + + Float logSizeSum = 0f; + for (LogDirDescription logDirDescription: descriptionMapResult.getData().values()) { + for (ReplicaInfo replicaInfo: logDirDescription.replicaInfos().values()) { + logSizeSum += replicaInfo.size(); + } + } + + return Result.buildSuc(BrokerMetrics.initWithMetric(clusterId, brokerId, metric, logSizeSum)); + } + private Result getLeadersSkew(VersionItemParam metricParam) { BrokerMetricParam param = (BrokerMetricParam)metricParam; diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/ReplicaMetricService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/ReplicaMetricService.java index 987303f8..c0a44586 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/ReplicaMetricService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/ReplicaMetricService.java @@ -13,12 +13,14 @@ public interface ReplicaMetricService { * 从kafka中采集指标 */ Result collectReplicaMetricsFromKafka(Long clusterId, String topic, Integer partitionId, Integer brokerId, String metric); - Result collectReplicaMetricsFromKafkaWithCache(Long clusterPhyId, String topic, Integer brokerId, Integer partitionId, String metric); + Result collectReplicaMetricsFromKafka(Long clusterId, String topicName, Integer partitionId, Integer brokerId, List metricNameList); /** * 从ES中获取指标 */ + @Deprecated Result> getMetricPointsFromES(Long clusterPhyId, Integer brokerId, String topicName, Integer partitionId, MetricDTO dto); + @Deprecated Result getLatestMetricsFromES(Long clusterPhyId, Integer brokerId, String topicName, Integer partitionId, List metricNames); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/impl/ReplicaMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/impl/ReplicaMetricServiceImpl.java index 460e6520..848c8601 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/impl/ReplicaMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/impl/ReplicaMetricServiceImpl.java @@ -17,7 +17,6 @@ import com.xiaojukeji.know.streaming.km.common.jmx.JmxConnectorWrap; import com.xiaojukeji.know.streaming.km.common.utils.BeanUtil; import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; -import com.xiaojukeji.know.streaming.km.core.cache.CollectedMetricsLocalCache; import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionService; import com.xiaojukeji.know.streaming.km.core.service.replica.ReplicaMetricService; import com.xiaojukeji.know.streaming.km.core.service.version.BaseMetricService; @@ -77,32 +76,36 @@ public class ReplicaMetricServiceImpl extends BaseMetricService implements Repli } @Override - public Result collectReplicaMetricsFromKafkaWithCache(Long clusterPhyId, - String topic, - Integer brokerId, - Integer partitionId, - String metric) { - String replicaMetricsKey = CollectedMetricsLocalCache.genReplicaMetricCacheKey(clusterPhyId, brokerId, topic, partitionId, metric); + public Result collectReplicaMetricsFromKafka(Long clusterId, String topicName, Integer partitionId, Integer brokerId, List metricNameList) { + ReplicationMetrics metrics = new ReplicationMetrics(clusterId, topicName, brokerId, partitionId); + for (String metricName: metricNameList) { + try { + if (metrics.getMetrics().containsKey(metricName)) { + continue; + } - Float keyValue = CollectedMetricsLocalCache.getReplicaMetrics(replicaMetricsKey); - if(null != keyValue){ - ReplicationMetrics replicationMetrics = new ReplicationMetrics(clusterPhyId, topic, partitionId, brokerId); - replicationMetrics.putMetric(metric, keyValue); - return Result.buildSuc(replicationMetrics); + Result ret = this.collectReplicaMetricsFromKafka( + clusterId, + metrics.getTopic(), + metrics.getBrokerId(), + metrics.getPartitionId(), + metricName + ); + + if (null == ret || ret.failed() || null == ret.getData()) { + continue; + } + + metrics.putMetric(ret.getData().getMetrics()); + } catch (Exception e) { + LOGGER.error( + "method=collectReplicaMetricsFromKafka||clusterPhyId={}||topicName={}||partition={}||brokerId={}||metricName={}||errMsg=exception!", + clusterId, topicName, partitionId, brokerId, e + ); + } } - Result ret = collectReplicaMetricsFromKafka(clusterPhyId, topic, partitionId, brokerId, metric); - if(null == ret || ret.failed() || null == ret.getData()){return ret;} - - // 更新cache - ret.getData().getMetrics().entrySet().stream().forEach( - metricNameAndValueEntry -> CollectedMetricsLocalCache.putReplicaMetrics( - replicaMetricsKey, - metricNameAndValueEntry.getValue() - ) - ); - - return ret; + return Result.buildSuc(metrics); } @Override @@ -167,8 +170,8 @@ public class ReplicaMetricServiceImpl extends BaseMetricService implements Repli Integer brokerId = metricParam.getBrokerId(); Integer partitionId = metricParam.getPartitionId(); - Result endRet = this.collectReplicaMetricsFromKafkaWithCache(clusterId, topic, brokerId, partitionId, REPLICATION_METRIC_LOG_END_OFFSET); - Result startRet = this.collectReplicaMetricsFromKafkaWithCache(clusterId, topic, brokerId, partitionId, REPLICATION_METRIC_LOG_START_OFFSET); + Result endRet = this.collectReplicaMetricsFromKafka(clusterId, topic, brokerId, partitionId, REPLICATION_METRIC_LOG_END_OFFSET); + Result startRet = this.collectReplicaMetricsFromKafka(clusterId, topic, brokerId, partitionId, REPLICATION_METRIC_LOG_START_OFFSET); ReplicationMetrics replicationMetrics = new ReplicationMetrics(clusterId, topic, brokerId, partitionId); if(null != endRet && endRet.successful() && null != startRet && startRet.successful()){ diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/replica/ReplicaMetricsController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/replica/ReplicaMetricsController.java index 13e2c855..7e276aff 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/replica/ReplicaMetricsController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/replica/ReplicaMetricsController.java @@ -26,6 +26,7 @@ public class ReplicaMetricsController { @Autowired private ReplicaMetricService replicationMetricService; + @Deprecated @ApiOperation(value = "Replica指标-单个Replica") @PostMapping(value = "clusters/{clusterPhyId}/brokers/{brokerId}/topics/{topicName}/partitions/{partitionId}/metric-points") @ResponseBody @@ -45,7 +46,7 @@ public class ReplicaMetricsController { @PathVariable String topicName, @PathVariable Integer partitionId, @RequestBody List metricsNames) { - Result metricsResult = replicationMetricService.getLatestMetricsFromES(clusterPhyId, brokerId, topicName, partitionId, metricsNames); + Result metricsResult = replicationMetricService.collectReplicaMetricsFromKafka(clusterPhyId, topicName, partitionId, brokerId, metricsNames); if (metricsResult.failed()) { return Result.buildFromIgnoreData(metricsResult); } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ReplicaMetricCollectorTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ReplicaMetricCollectorTask.java index 6b93e324..7e52c2f4 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ReplicaMetricCollectorTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ReplicaMetricCollectorTask.java @@ -1,32 +1,32 @@ -package com.xiaojukeji.know.streaming.km.task.metrics; - -import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; -import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.xiaojukeji.know.streaming.km.collector.metric.ReplicaMetricCollector; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; - -/** - * @author didi - */ -@Slf4j -@Task(name = "ReplicaMetricCollectorTask", - description = "Replica指标采集任务", - cron = "0 0/1 * * * ? *", - autoRegister = true, - consensual = ConsensualEnum.BROADCAST, - timeout = 2 * 60) -public class ReplicaMetricCollectorTask extends AbstractAsyncMetricsDispatchTask { - - @Autowired - private ReplicaMetricCollector replicaMetricCollector; - - @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception { - replicaMetricCollector.collectMetrics(clusterPhy); - - return TaskResult.SUCCESS; - } -} +//package com.xiaojukeji.know.streaming.km.task.metrics; +// +//import com.didiglobal.logi.job.annotation.Task; +//import com.didiglobal.logi.job.common.TaskResult; +//import com.didiglobal.logi.job.core.consensual.ConsensualEnum; +//import com.xiaojukeji.know.streaming.km.collector.metric.ReplicaMetricCollector; +//import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.beans.factory.annotation.Autowired; +// +///** +// * @author didi +// */ +//@Slf4j +//@Task(name = "ReplicaMetricCollectorTask", +// description = "Replica指标采集任务", +// cron = "0 0/1 * * * ? *", +// autoRegister = true, +// consensual = ConsensualEnum.BROADCAST, +// timeout = 2 * 60) +//public class ReplicaMetricCollectorTask extends AbstractAsyncMetricsDispatchTask { +// +// @Autowired +// private ReplicaMetricCollector replicaMetricCollector; +// +// @Override +// public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception { +// replicaMetricCollector.collectMetrics(clusterPhy); +// +// return TaskResult.SUCCESS; +// } +//} From fa0ae5e474bb2be2f053adf5e31bae6bd7e0dd09 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Fri, 21 Oct 2022 11:58:57 +0800 Subject: [PATCH 064/145] =?UTF-8?q?[Optimize]=20=E9=9B=86=E7=BE=A4Broker?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E4=B8=AD=EF=BC=8C=E8=A1=A5=E5=85=85Jmx?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E6=88=90=E5=8A=9F=E8=BF=9E=E6=8E=A5=E7=9A=84?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、当前页面无数据时,一部分的原因是JMX连接失败导致; 2、Broker列表中增加是否连接成功的信息,便于问题的排查; --- .../impl/ClusterBrokersManagerImpl.java | 24 ++++++++++++++----- .../cluster/res/ClusterBrokersOverviewVO.java | 3 +++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java index 50c3596d..6b180126 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java @@ -24,6 +24,7 @@ import com.xiaojukeji.know.streaming.km.core.service.broker.BrokerMetricService; import com.xiaojukeji.know.streaming.km.core.service.broker.BrokerService; import com.xiaojukeji.know.streaming.km.core.service.kafkacontroller.KafkaControllerService; import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService; +import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaJMXClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -51,6 +52,9 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { @Autowired private KafkaControllerService kafkaControllerService; + @Autowired + private KafkaJMXClient kafkaJMXClient; + @Override public PaginationResult getClusterPhyBrokersOverview(Long clusterPhyId, ClusterBrokersOverviewDTO dto) { // 获取集群Broker列表 @@ -75,6 +79,10 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { //获取controller信息 KafkaController kafkaController = kafkaControllerService.getKafkaControllerFromDB(clusterPhyId); + //获取jmx状态信息 + Map jmxConnectedMap = new HashMap<>(); + brokerList.forEach(elem -> jmxConnectedMap.put(elem.getBrokerId(), kafkaJMXClient.getClientWithCheck(clusterPhyId, elem.getBrokerId()) != null)); + // 格式转换 return PaginationResult.buildSuc( this.convert2ClusterBrokersOverviewVOList( @@ -83,7 +91,8 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { metricsResult.getData(), groupTopic, transactionTopic, - kafkaController + kafkaController, + jmxConnectedMap ), paginationResult ); @@ -165,22 +174,24 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { List metricsList, Topic groupTopic, Topic transactionTopic, - KafkaController kafkaController) { - Map metricsMap = metricsList == null? new HashMap<>(): metricsList.stream().collect(Collectors.toMap(BrokerMetrics::getBrokerId, Function.identity())); + KafkaController kafkaController, + Map jmxConnectedMap) { + Map metricsMap = metricsList == null ? new HashMap<>() : metricsList.stream().collect(Collectors.toMap(BrokerMetrics::getBrokerId, Function.identity())); - Map brokerMap = brokerList == null? new HashMap<>(): brokerList.stream().collect(Collectors.toMap(Broker::getBrokerId, Function.identity())); + Map brokerMap = brokerList == null ? new HashMap<>() : brokerList.stream().collect(Collectors.toMap(Broker::getBrokerId, Function.identity())); List voList = new ArrayList<>(pagedBrokerIdList.size()); for (Integer brokerId : pagedBrokerIdList) { Broker broker = brokerMap.get(brokerId); BrokerMetrics brokerMetrics = metricsMap.get(brokerId); + Boolean jmxConnected = jmxConnectedMap.get(brokerId); - voList.add(this.convert2ClusterBrokersOverviewVO(brokerId, broker, brokerMetrics, groupTopic, transactionTopic, kafkaController)); + voList.add(this.convert2ClusterBrokersOverviewVO(brokerId, broker, brokerMetrics, groupTopic, transactionTopic, kafkaController, jmxConnected)); } return voList; } - private ClusterBrokersOverviewVO convert2ClusterBrokersOverviewVO(Integer brokerId, Broker broker, BrokerMetrics brokerMetrics, Topic groupTopic, Topic transactionTopic, KafkaController kafkaController) { + private ClusterBrokersOverviewVO convert2ClusterBrokersOverviewVO(Integer brokerId, Broker broker, BrokerMetrics brokerMetrics, Topic groupTopic, Topic transactionTopic, KafkaController kafkaController, Boolean jmxConnected) { ClusterBrokersOverviewVO clusterBrokersOverviewVO = new ClusterBrokersOverviewVO(); clusterBrokersOverviewVO.setBrokerId(brokerId); if (broker != null) { @@ -203,6 +214,7 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { } clusterBrokersOverviewVO.setLatestMetrics(brokerMetrics); + clusterBrokersOverviewVO.setJmxConnected(jmxConnected); return clusterBrokersOverviewVO; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/cluster/res/ClusterBrokersOverviewVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/cluster/res/ClusterBrokersOverviewVO.java index be1b529d..b172403c 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/cluster/res/ClusterBrokersOverviewVO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/cluster/res/ClusterBrokersOverviewVO.java @@ -31,6 +31,9 @@ public class ClusterBrokersOverviewVO extends BrokerMetadataVO { @ApiModelProperty(value = "jmx端口") private Integer jmxPort; + @ApiModelProperty(value = "jmx连接状态 true:连接成功 false:连接失败") + private Boolean jmxConnected; + @ApiModelProperty(value = "是否存活 true:存活 false:不存活") private Boolean alive; } From 6a5efce874a94dfc8c02e6d690547e294d749d07 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Fri, 21 Oct 2022 12:06:22 +0800 Subject: [PATCH 065/145] =?UTF-8?q?[Bugfix]=20=E4=BF=AE=E5=A4=8D=E6=8C=87?= =?UTF-8?q?=E6=A0=87=E7=89=88=E6=9C=AC=E4=BF=A1=E6=81=AFlist=E8=BD=ACmap?= =?UTF-8?q?=E6=97=B6=E5=87=BA=E7=8E=B0key=E5=86=B2=E7=AA=81=E4=BB=8E?= =?UTF-8?q?=E8=80=8C=E6=8A=9B=E5=87=BA=E5=BC=82=E5=B8=B8=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../km/biz/version/impl/VersionControlManagerImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java index 0460b601..70f4814b 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java @@ -111,7 +111,11 @@ public class VersionControlManagerImpl implements VersionControlManager { allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(WEB_OP.getCode()), VersionItemVO.class)); Map map = allVersionItemVO.stream().collect( - Collectors.toMap(u -> u.getType() + "@" + u.getName(), Function.identity() )); + Collectors.toMap( + u -> u.getType() + "@" + u.getName(), + Function.identity(), + (v1, v2) -> v1) + ); return Result.buildSuc(map); } From 83df02783c49a0e1219fb75667be97a667536310 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Fri, 21 Oct 2022 14:32:07 +0800 Subject: [PATCH 066/145] =?UTF-8?q?=E5=AE=89=E8=A3=85=E5=8C=85=E4=B8=AD?= =?UTF-8?q?=EF=BC=8C=E5=8E=BB=E9=99=A4docs=E7=9B=B8=E5=85=B3=E7=9A=84?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-dist/README.md | 3 --- km-dist/ReleaseKnowStreaming.xml | 8 -------- 2 files changed, 11 deletions(-) diff --git a/km-dist/README.md b/km-dist/README.md index 5c6d192a..f5a71758 100644 --- a/km-dist/README.md +++ b/km-dist/README.md @@ -11,9 +11,6 @@ - logback-spring.xml:日志配置 -- docs:产品相关文档 - - - helm:安装KnowStreaming的Helm相关文件 diff --git a/km-dist/ReleaseKnowStreaming.xml b/km-dist/ReleaseKnowStreaming.xml index 80503225..046a5cfd 100755 --- a/km-dist/ReleaseKnowStreaming.xml +++ b/km-dist/ReleaseKnowStreaming.xml @@ -17,14 +17,6 @@ logback-spring.xml - - ../docs - docs - - * - */* - - ../bin bin From 811fc9b40029130d0e83d038bd512ba516d358f0 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Fri, 21 Oct 2022 14:32:57 +0800 Subject: [PATCH 067/145] =?UTF-8?q?=E8=A1=A5=E5=85=85v3.0.1=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=8D=87=E7=BA=A7=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/install_guide/版本升级手册.md | 107 +++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 5 deletions(-) diff --git a/docs/install_guide/版本升级手册.md b/docs/install_guide/版本升级手册.md index dfa4a8e2..2fef58f0 100644 --- a/docs/install_guide/版本升级手册.md +++ b/docs/install_guide/版本升级手册.md @@ -4,9 +4,106 @@ - 如果想升级至具体版本,需要将你当前版本至你期望使用版本的变更统统执行一遍,然后才能正常使用。 - 如果中间某个版本没有升级信息,则表示该版本直接替换安装包即可从前一个版本升级至当前版本。 - ### 6.2.0、升级至 `master` 版本 +暂无 + +### 6.2.1、升级至 `v3.0.1` 版本 + +**ES 索引模版** +```bash +# 新增 ks_kafka_zookeeper_metric 索引模版。 +# 可通过再次执行 bin/init_es_template.sh 脚本,创建该索引模版。 + +# 索引模版内容 +PUT _template/ks_kafka_zookeeper_metric +{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + } +``` + + **SQL 变更** ```sql @@ -48,7 +145,7 @@ CREATE TABLE `ks_km_group` ( --- -### 6.2.1、升级至 `v3.0.0` 版本 +### 6.2.2、升级至 `v3.0.0` 版本 **SQL 变更** @@ -60,7 +157,7 @@ ADD COLUMN `zk_properties` TEXT NULL COMMENT 'ZK配置' AFTER `jmx_properties`; --- -### 6.2.2、升级至 `v3.0.0-beta.2`版本 +### 6.2.3、升级至 `v3.0.0-beta.2`版本 **配置变更** @@ -131,7 +228,7 @@ ALTER TABLE `logi_security_oplog` --- -### 6.2.3、升级至 `v3.0.0-beta.1`版本 +### 6.2.4、升级至 `v3.0.0-beta.1`版本 **SQL 变更** @@ -150,7 +247,7 @@ ALTER COLUMN `operation_methods` set default ''; --- -### 6.2.4、`2.x`版本 升级至 `v3.0.0-beta.0`版本 +### 6.2.5、`2.x`版本 升级至 `v3.0.0-beta.0`版本 **升级步骤:** From df655a250c6d156fec853c7e24464d57fdf7cd78 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Fri, 21 Oct 2022 14:36:29 +0800 Subject: [PATCH 068/145] =?UTF-8?q?=E5=A2=9E=E5=8A=A0v3.0.1=E5=8F=98?= =?UTF-8?q?=E6=9B=B4=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Releases_Notes.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/Releases_Notes.md b/Releases_Notes.md index f453b582..a3df746f 100644 --- a/Releases_Notes.md +++ b/Releases_Notes.md @@ -1,4 +1,36 @@ +## v3.0.1 + +**Bug修复** +- 修复重置 Group Offset 时,提示信息中缺少 Dead 状态也可进行重置的信息; +- 修复 Ldap 某个属性不存在时,会直接抛出空指针导致登陆失败的问题; +- 修复集群 Topic 列表页,健康分详情信息中,检查时间展示错误的问题; +- 修复更新健康检查结果时,出现死锁的问题; +- 修复 Replica 索引模版错误的问题; +- 修复 FAQ 文档中的错误链接; +- 修复 Broker 的 TopN 指标不存在时,页面数据不展示的问题; +- 修复 Group 详情页,图表时间范围选择不生效的问题; + + +**体验优化** +- 集群 Group 列表按照 Group 维度进行展示; +- 优化避免因 ES 中该指标不存在,导致日志中出现大量空指针的问题; +- 优化全局 Message & Notification 展示效果; +- 优化 Topic 扩分区名称 & 描述展示; + + +**新增** +- Broker 列表页面,新增 JMX 是否成功连接的信息; + + +**ZK 部分(未完全发布)** +- 后端补充 Kafka ZK 指标采集,Kafka ZK 信息获取相关功能; +- 增加本地缓存,避免同一采集周期内 ZK 指标重复采集; +- 增加 ZK 节点采集失败跳过策略,避免不断对存在问题的节点不断尝试; +- 修复 zkAvgLatency 指标转 Long 时抛出异常问题; +- 修复 ks_km_zookeeper 表中,role 字段类型错误问题; + +--- ## v3.0.0 @@ -25,7 +57,7 @@ - 集群信息中,新增 Kafka 集群运行模式字段 - 新增 docker-compose 的部署方式 - +--- ## v3.0.0-beta.3 From b4580277a93640ea33224af9e88b23427b62edca Mon Sep 17 00:00:00 2001 From: luhe Date: Wed, 21 Sep 2022 15:54:30 +0800 Subject: [PATCH 069/145] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=94=AF=E6=8C=81ZK-Kerberos=E8=AE=A4=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../streaming/km/persistence/kafka/KafkaAdminZKClient.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java index c8849ee7..0b824ddb 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java @@ -132,7 +132,9 @@ public class KafkaAdminZKClient extends AbstractClusterLoadedChangedHandler impl kafkaZkClient = KafkaZkClient.apply( zookeeperAddress, - false, +// false, +// 添加支持zk的Kerberos认证 + true, Constant.DEFAULT_SESSION_TIMEOUT_UNIT_MS, Constant.DEFAULT_SESSION_TIMEOUT_UNIT_MS, 5, From fb21d8135cceb28af32d8d1f28189fe1ebfd38c7 Mon Sep 17 00:00:00 2001 From: luhe Date: Wed, 21 Sep 2022 15:58:59 +0800 Subject: [PATCH 070/145] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=94=AF=E6=8C=81ZK-Kerberos=E8=AE=A4=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zk_kerberos/img.png | Bin 0 -> 64697 bytes docs/zk_kerberos/img_1.png | Bin 0 -> 17428 bytes docs/zk_kerberos/img_2.png | Bin 0 -> 312993 bytes docs/zk_kerberos/img_3.png | Bin 0 -> 312993 bytes docs/zk_kerberos/zk支持Kerberos配置文档.md | 32 +++++++++++++++++++++ 5 files changed, 32 insertions(+) create mode 100644 docs/zk_kerberos/img.png create mode 100644 docs/zk_kerberos/img_1.png create mode 100644 docs/zk_kerberos/img_2.png create mode 100644 docs/zk_kerberos/img_3.png create mode 100644 docs/zk_kerberos/zk支持Kerberos配置文档.md diff --git a/docs/zk_kerberos/img.png b/docs/zk_kerberos/img.png new file mode 100644 index 0000000000000000000000000000000000000000..c51c1c00ebb07f4d75844729e8d32cbc2ab0e395 GIT binary patch literal 64697 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 literal 0 HcmV?d00001 diff --git a/docs/zk_kerberos/img_2.png b/docs/zk_kerberos/img_2.png new file mode 100644 index 0000000000000000000000000000000000000000..f15ed55e2483302b66b40b22fb12aff91f402f5b GIT binary patch literal 312993 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�M$g8*r|zOMiHNl*NRkuUuaF+nE*? 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 ^8?SLm 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 BQM>>E literal 0 HcmV?d00001 diff --git a/docs/zk_kerberos/img_3.png b/docs/zk_kerberos/img_3.png new file mode 100644 index 0000000000000000000000000000000000000000..f15ed55e2483302b66b40b22fb12aff91f402f5b GIT binary patch literal 312993 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�M$g8*r|zOMiHNl*NRkuUuaF+nE*? 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 ^8?SLm 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 BQM>>E literal 0 HcmV?d00001 diff --git a/docs/zk_kerberos/zk支持Kerberos配置文档.md b/docs/zk_kerberos/zk支持Kerberos配置文档.md new file mode 100644 index 00000000..9856ee09 --- /dev/null +++ b/docs/zk_kerberos/zk支持Kerberos配置文档.md @@ -0,0 +1,32 @@ +1、需要修改代码: +位置:src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java +将createZKClient的135行的false改为true +![img.png](img.png) +修改完之后就可以打包编译:打包编译见:参考2.3 后端单独打包 +https://github.com/didi/KnowStreaming/blob/master/docs/install_guide/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85%E6%89%8B%E5%86%8C.md +2、查看kafka的ZK的Acl +首先查看kafka的server.properties的配置的zookeeper.connect的连接,然后使用:zkCli.sh -serve xxxx登录到zk的页面,然后执行命令getAcl /kafka +![img_1.png](img_1.png) +此时就可以看到kafka在zk中的用户的权限,因为我们的集群在server.properties 配置了super.users=User:kafka ,以及zookeeper.set.acl=true ,默认的kafka的权限就是cdrwa。如果没有用户有cdrwa权限的话,需要zk创建用户并授权,授权命令:setAcl +3、在Kerberos的域中创建 kafka/_HOST的keytab,并导出。例如:kafka/dbs-kafka-test-8-53 +4、导出keytab后上传到安装KS的机器的/etc/keytab下。执行 kinit -kt zookeepe.keytab kafka/dbs-kafka-test-8-53 看是否能进行Kerberos登录 +5、可以登录后,配置/opt/zookeeper.jass文件: +Client { +com.sun.security.auth.module.Krb5LoginModule required +useKeyTab=true +storeKey=false +serviceName="zookeeper" +keyTab="/etc/keytab/zookeeper.keytab" +principal="kafka/dbs-kafka-test-8-53@XXX.XXX.XXX"; +}; +6、需要配置KDC-Server对KS的机器开通防火墙,并在KS的机器/etc/host/ 配置 kdc-server的hostname。并将 krb5.conf 导入到/etc下 +7、在/usr/local/KnowStreaming/KnowStreaming/bin/startup.sh中的47行的JAVA_OPT中追加如下设置: +-Dsun.security.krb5.debug=true -Djava.security.krb5.conf=/etc/krb5.conf -Djava.security.auth.login.config=/opt/zookeeper.jaas +8、重启KS集群后再start.out中看到如下信息,证明Kerberos配置成功 +![img_3.png](img_3.png) +![img_2.png](img_2.png) + +9、对于多集群来说如果用的是一样的Kerberos域的话,只需在每个zk中给kafka用户配置crdwa权限即可,这样集群初始化的时候zkclient是都可以认证。 +10、未改进: + 1、需要页面ZK的Kerberos配置化 + 2、多个Kerberos域暂时未适配。 \ No newline at end of file From 4386181304c5efa4f09785aa787d8d5ff8dba003 Mon Sep 17 00:00:00 2001 From: luhe Date: Wed, 21 Sep 2022 15:59:31 +0800 Subject: [PATCH 071/145] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=94=AF=E6=8C=81ZK-Kerberos=E8=AE=A4=E8=AF=81=E4=B8=8E?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zk_kerberos/zk支持Kerberos配置文档.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/zk_kerberos/zk支持Kerberos配置文档.md b/docs/zk_kerberos/zk支持Kerberos配置文档.md index 9856ee09..0983afd2 100644 --- a/docs/zk_kerberos/zk支持Kerberos配置文档.md +++ b/docs/zk_kerberos/zk支持Kerberos配置文档.md @@ -25,7 +25,6 @@ principal="kafka/dbs-kafka-test-8-53@XXX.XXX.XXX"; 8、重启KS集群后再start.out中看到如下信息,证明Kerberos配置成功 ![img_3.png](img_3.png) ![img_2.png](img_2.png) - 9、对于多集群来说如果用的是一样的Kerberos域的话,只需在每个zk中给kafka用户配置crdwa权限即可,这样集群初始化的时候zkclient是都可以认证。 10、未改进: 1、需要页面ZK的Kerberos配置化 From 341bd58d5167769b0d5d1d157a51017df1e8815d Mon Sep 17 00:00:00 2001 From: luhe Date: Wed, 21 Sep 2022 16:02:38 +0800 Subject: [PATCH 072/145] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=94=AF=E6=8C=81ZK-Kerberos=E8=AE=A4=E8=AF=81=E4=B8=8E?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zk_kerberos/zk支持Kerberos配置文档.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/zk_kerberos/zk支持Kerberos配置文档.md b/docs/zk_kerberos/zk支持Kerberos配置文档.md index 0983afd2..8ba235fa 100644 --- a/docs/zk_kerberos/zk支持Kerberos配置文档.md +++ b/docs/zk_kerberos/zk支持Kerberos配置文档.md @@ -4,12 +4,16 @@ ![img.png](img.png) 修改完之后就可以打包编译:打包编译见:参考2.3 后端单独打包 https://github.com/didi/KnowStreaming/blob/master/docs/install_guide/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85%E6%89%8B%E5%86%8C.md + 2、查看kafka的ZK的Acl 首先查看kafka的server.properties的配置的zookeeper.connect的连接,然后使用:zkCli.sh -serve xxxx登录到zk的页面,然后执行命令getAcl /kafka ![img_1.png](img_1.png) 此时就可以看到kafka在zk中的用户的权限,因为我们的集群在server.properties 配置了super.users=User:kafka ,以及zookeeper.set.acl=true ,默认的kafka的权限就是cdrwa。如果没有用户有cdrwa权限的话,需要zk创建用户并授权,授权命令:setAcl + 3、在Kerberos的域中创建 kafka/_HOST的keytab,并导出。例如:kafka/dbs-kafka-test-8-53 + 4、导出keytab后上传到安装KS的机器的/etc/keytab下。执行 kinit -kt zookeepe.keytab kafka/dbs-kafka-test-8-53 看是否能进行Kerberos登录 + 5、可以登录后,配置/opt/zookeeper.jass文件: Client { com.sun.security.auth.module.Krb5LoginModule required @@ -19,13 +23,18 @@ serviceName="zookeeper" keyTab="/etc/keytab/zookeeper.keytab" principal="kafka/dbs-kafka-test-8-53@XXX.XXX.XXX"; }; + 6、需要配置KDC-Server对KS的机器开通防火墙,并在KS的机器/etc/host/ 配置 kdc-server的hostname。并将 krb5.conf 导入到/etc下 + 7、在/usr/local/KnowStreaming/KnowStreaming/bin/startup.sh中的47行的JAVA_OPT中追加如下设置: -Dsun.security.krb5.debug=true -Djava.security.krb5.conf=/etc/krb5.conf -Djava.security.auth.login.config=/opt/zookeeper.jaas + 8、重启KS集群后再start.out中看到如下信息,证明Kerberos配置成功 ![img_3.png](img_3.png) ![img_2.png](img_2.png) + 9、对于多集群来说如果用的是一样的Kerberos域的话,只需在每个zk中给kafka用户配置crdwa权限即可,这样集群初始化的时候zkclient是都可以认证。 + 10、未改进: 1、需要页面ZK的Kerberos配置化 2、多个Kerberos域暂时未适配。 \ No newline at end of file From dfb9b6136baf6171ede0b2a9a2df392c391bda8b Mon Sep 17 00:00:00 2001 From: luhe Date: Wed, 21 Sep 2022 16:09:04 +0800 Subject: [PATCH 073/145] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=94=AF=E6=8C=81ZK-Kerberos=E8=AE=A4=E8=AF=81=E4=B8=8E?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zk_kerberos/zk支持Kerberos配置文档.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/zk_kerberos/zk支持Kerberos配置文档.md b/docs/zk_kerberos/zk支持Kerberos配置文档.md index 8ba235fa..ad70861c 100644 --- a/docs/zk_kerberos/zk支持Kerberos配置文档.md +++ b/docs/zk_kerberos/zk支持Kerberos配置文档.md @@ -16,12 +16,19 @@ https://github.com/didi/KnowStreaming/blob/master/docs/install_guide/%E6%BA%90%E 5、可以登录后,配置/opt/zookeeper.jass文件: Client { + com.sun.security.auth.module.Krb5LoginModule required + useKeyTab=true + storeKey=false + serviceName="zookeeper" + keyTab="/etc/keytab/zookeeper.keytab" + principal="kafka/dbs-kafka-test-8-53@XXX.XXX.XXX"; + }; 6、需要配置KDC-Server对KS的机器开通防火墙,并在KS的机器/etc/host/ 配置 kdc-server的hostname。并将 krb5.conf 导入到/etc下 From c73cfce7805f02acbf1bd0320d35f009c9ead600 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Thu, 29 Sep 2022 15:13:41 +0800 Subject: [PATCH 074/145] bump version to 3.1.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a810fa4..a168b74c 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ - 3.0.0 + 3.1.0 8 8 From a4abb4069d9a4982b81d16008133288185ffbecf Mon Sep 17 00:00:00 2001 From: zengqiao Date: Sat, 8 Oct 2022 14:15:20 +0800 Subject: [PATCH 075/145] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E6=95=88?= =?UTF-8?q?=E7=9A=84=E5=81=A5=E5=BA=B7=E5=88=86=E8=AE=A1=E7=AE=97=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/enums/health/HealthStateEnum.java | 31 +++++++++++ .../impl/ClusterMetricServiceImpl.java | 6 +-- .../health/score/HealthScoreService.java | 25 ++------- .../score/impl/HealthScoreServiceImpl.java | 54 ------------------- .../metrics/ClusterMetricVersionItems.java | 21 ++++++-- 5 files changed, 55 insertions(+), 82 deletions(-) create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/health/HealthStateEnum.java diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/health/HealthStateEnum.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/health/HealthStateEnum.java new file mode 100644 index 00000000..a9490fb6 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/health/HealthStateEnum.java @@ -0,0 +1,31 @@ +package com.xiaojukeji.know.streaming.km.common.enums.health; + +import lombok.Getter; + + +/** + * 健康状态 + */ +@Getter +public enum HealthStateEnum { + UNKNOWN(-1, "未知"), + + GOOD(0, "好"), + + MEDIUM(1, "中"), + + POOR(2, "差"), + + DEAD(3, "宕机"), + + ; + + private final int dimension; + + private final String message; + + HealthStateEnum(int dimension, String message) { + this.dimension = dimension; + this.message = message; + } +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java index 9fdd9ec0..3d004f78 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java @@ -85,7 +85,7 @@ public class ClusterMetricServiceImpl extends BaseMetricService implements Clust public static final String CLUSTER_METHOD_GET_TOTAL_LOG_SIZE = "getTotalLogSize"; public static final String CLUSTER_METHOD_GET_PARTITION_SIZE = "getPartitionSize"; public static final String CLUSTER_METHOD_GET_PARTITION_NO_LEADER_SIZE = "getPartitionNoLeaderSize"; - public static final String CLUSTER_METHOD_GET_HEALTH_SCORE = "getTopicHealthScore"; + public static final String CLUSTER_METHOD_GET_HEALTH_SCORE = "getClusterHealthScore"; public static final String CLUSTER_METHOD_GET_METRIC_FROM_KAFKA_BY_TOTAL_BROKERS_JMX = "getMetricFromKafkaByTotalBrokersJMX"; public static final String CLUSTER_METHOD_GET_METRIC_FROM_KAFKA_BY_CONTROLLER_JMX = "getMetricFromKafkaByControllerJMX"; public static final String CLUSTER_METHOD_GET_ZK_COUNT = "getZKCount"; @@ -188,7 +188,7 @@ public class ClusterMetricServiceImpl extends BaseMetricService implements Clust registerVCHandler( CLUSTER_METHOD_GET_PARTITION_SIZE, this::getPartitionSize); registerVCHandler( CLUSTER_METHOD_GET_PARTITION_NO_LEADER_SIZE, this::getPartitionNoLeaderSize); - registerVCHandler( CLUSTER_METHOD_GET_HEALTH_SCORE, this::getTopicHealthScore); + registerVCHandler( CLUSTER_METHOD_GET_HEALTH_SCORE, this::getClusterHealthScore); registerVCHandler( CLUSTER_METHOD_GET_METRIC_FROM_KAFKA_BY_TOTAL_BROKERS_JMX, this::getMetricFromKafkaByTotalBrokersJMX); registerVCHandler( CLUSTER_METHOD_GET_METRIC_FROM_KAFKA_BY_CONTROLLER_JMX, this::getMetricFromKafkaByControllerJMX); @@ -364,7 +364,7 @@ public class ClusterMetricServiceImpl extends BaseMetricService implements Clust /** * 获取集群的健康分 */ - private Result getTopicHealthScore(VersionItemParam metricParam){ + private Result getClusterHealthScore(VersionItemParam metricParam){ ClusterMetricParam param = (ClusterMetricParam)metricParam; ClusterMetrics clusterMetrics = healthScoreService.calClusterHealthScore(param.getClusterId()); return Result.buildSuc(clusterMetrics); diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/HealthScoreService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/HealthScoreService.java index 5997edec..48f8933b 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/HealthScoreService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/HealthScoreService.java @@ -15,35 +15,16 @@ public interface HealthScoreService { * @param clusterPhyId 集群ID * @return */ + @Deprecated ClusterMetrics calClusterHealthScore(Long clusterPhyId); - /** - * 获取集群Topics健康分指标 - * @param clusterPhyId 集群ID - * @return - */ - ClusterMetrics calClusterTopicsHealthScore(Long clusterPhyId); - - /** - * 获取集群Brokers健康分指标 - * @param clusterPhyId 集群ID - * @return - */ - ClusterMetrics calClusterBrokersHealthScore(Long clusterPhyId); - - /** - * 获取集群Groups健康分指标 - * @param clusterPhyId 集群ID - * @return - */ - ClusterMetrics calClusterGroupsHealthScore(Long clusterPhyId); - /** * 获取集群健康分指标 * @param clusterPhyId 集群ID * @param topicName Topic名称 * @return */ + @Deprecated TopicMetrics calTopicHealthScore(Long clusterPhyId, String topicName); /** @@ -52,6 +33,7 @@ public interface HealthScoreService { * @param brokerId brokerId * @return */ + @Deprecated BrokerMetrics calBrokerHealthScore(Long clusterPhyId, Integer brokerId); /** @@ -60,6 +42,7 @@ public interface HealthScoreService { * @param groupName group名称 * @return */ + @Deprecated GroupMetrics calGroupHealthScore(Long clusterPhyId, String groupName); /** diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/impl/HealthScoreServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/impl/HealthScoreServiceImpl.java index c443c3bb..6ba01bb9 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/impl/HealthScoreServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/score/impl/HealthScoreServiceImpl.java @@ -136,60 +136,6 @@ public class HealthScoreServiceImpl implements HealthScoreService { return metrics; } - @Override - public ClusterMetrics calClusterTopicsHealthScore(Long clusterPhyId) { - List healthScoreResultList = this.getDimensionHealthScoreResult(clusterPhyId, HealthCheckDimensionEnum.TOPIC); - - ClusterMetrics metrics = new ClusterMetrics(clusterPhyId); - if (ValidateUtils.isEmptyList(healthScoreResultList)) { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_TOPICS, Constant.MIN_HEALTH_SCORE); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_TOPICS, 0.0f); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_TOPICS, 0.0f); - } else { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_TOPICS, Math.max(this.getDimensionHealthScore(healthScoreResultList), Constant.MIN_HEALTH_SCORE)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_TOPICS, getHealthCheckPassed(healthScoreResultList)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_TOPICS, Float.valueOf(healthScoreResultList.size())); - } - - return metrics; - } - - @Override - public ClusterMetrics calClusterBrokersHealthScore(Long clusterPhyId) { - List healthScoreResultList = this.getDimensionHealthScoreResult(clusterPhyId, HealthCheckDimensionEnum.BROKER); - - ClusterMetrics metrics = new ClusterMetrics(clusterPhyId); - if (ValidateUtils.isEmptyList(healthScoreResultList)) { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_BROKERS, Constant.MIN_HEALTH_SCORE); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_BROKERS, 0.0f); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_BROKERS, 0.0f); - } else { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_BROKERS, Math.max(this.getDimensionHealthScore(healthScoreResultList), Constant.MIN_HEALTH_SCORE)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_BROKERS, getHealthCheckPassed(healthScoreResultList)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_BROKERS, Float.valueOf(healthScoreResultList.size())); - } - - return metrics; - } - - @Override - public ClusterMetrics calClusterGroupsHealthScore(Long clusterPhyId) { - List healthScoreResultList = this.getDimensionHealthScoreResult(clusterPhyId, HealthCheckDimensionEnum.GROUP); - - ClusterMetrics metrics = new ClusterMetrics(clusterPhyId); - if (ValidateUtils.isEmptyList(healthScoreResultList)) { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_GROUPS, Constant.MIN_HEALTH_SCORE); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_GROUPS, 0.0f); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_GROUPS, 0.0f); - } else { - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_SCORE_GROUPS, Math.max(this.getDimensionHealthScore(healthScoreResultList), Constant.MIN_HEALTH_SCORE)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_PASSED_GROUPS, this.getHealthCheckPassed(healthScoreResultList)); - metrics.getMetrics().put(CLUSTER_METRIC_HEALTH_CHECK_TOTAL_GROUPS, Float.valueOf(healthScoreResultList.size())); - } - - return metrics; - } - @Override public TopicMetrics calTopicHealthScore(Long clusterPhyId, String topicName) { List healthScoreResultList = this.getResHealthScoreResult(clusterPhyId, HealthCheckDimensionEnum.TOPIC.getDimension(), topicName); diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ClusterMetricVersionItems.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ClusterMetricVersionItems.java index 53b98479..00a5e0cd 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ClusterMetricVersionItems.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ClusterMetricVersionItems.java @@ -20,22 +20,35 @@ import static com.xiaojukeji.know.streaming.km.core.service.cluster.impl.Cluster @Component public class ClusterMetricVersionItems extends BaseMetricVersionMetric { + /** + * 健康分 + */ public static final String CLUSTER_METRIC_HEALTH_SCORE = "HealthScore"; + public static final String CLUSTER_METRIC_HEALTH_SCORE_TOPICS = "HealthScore_Topics"; + public static final String CLUSTER_METRIC_HEALTH_SCORE_BROKERS = "HealthScore_Brokers"; + public static final String CLUSTER_METRIC_HEALTH_SCORE_GROUPS = "HealthScore_Groups"; + public static final String CLUSTER_METRIC_HEALTH_SCORE_CLUSTER = "HealthScore_Cluster"; + + /** + * 健康巡检 + */ public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED = "HealthCheckPassed"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL = "HealthCheckTotal"; - public static final String CLUSTER_METRIC_HEALTH_SCORE_TOPICS = "HealthScore_Topics"; + public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED_TOPICS = "HealthCheckPassed_Topics"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL_TOPICS = "HealthCheckTotal_Topics"; - public static final String CLUSTER_METRIC_HEALTH_SCORE_BROKERS = "HealthScore_Brokers"; + public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED_BROKERS = "HealthCheckPassed_Brokers"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL_BROKERS = "HealthCheckTotal_Brokers"; - public static final String CLUSTER_METRIC_HEALTH_SCORE_GROUPS = "HealthScore_Groups"; + public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED_GROUPS = "HealthCheckPassed_Groups"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL_GROUPS = "HealthCheckTotal_Groups"; - public static final String CLUSTER_METRIC_HEALTH_SCORE_CLUSTER = "HealthScore_Cluster"; + public static final String CLUSTER_METRIC_HEALTH_CHECK_PASSED_CLUSTER = "HealthCheckPassed_Cluster"; public static final String CLUSTER_METRIC_HEALTH_CHECK_TOTAL_CLUSTER = "HealthCheckTotal_Cluster"; + + public static final String CLUSTER_METRIC_TOTAL_REQ_QUEUE_SIZE = "TotalRequestQueueSize"; public static final String CLUSTER_METRIC_TOTAL_RES_QUEUE_SIZE = "TotalResponseQueueSize"; public static final String CLUSTER_METRIC_EVENT_QUEUE_SIZE = "EventQueueSize"; From 20d5b27bb687e74b5c21c95668df2ff6feaadf78 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Sat, 8 Oct 2022 14:52:17 +0800 Subject: [PATCH 076/145] =?UTF-8?q?ZK-=E5=A2=9E=E5=8A=A0=E5=9B=9B=E5=AD=97?= =?UTF-8?q?=E5=91=BD=E4=BB=A4=E4=BF=A1=E6=81=AF=E7=9A=84=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bean/entity/result/ResultStatus.java | 1 + .../BaseFourLetterWordCmdData.java | 9 + .../fourletterword/ConfigCmdData.java | 38 ++++ .../fourletterword/MonitorCmdData.java | 39 +++++ .../fourletterword/ServerCmdData.java | 30 ++++ .../parser/ConfigCmdDataParser.java | 116 +++++++++++++ .../parser/FourLetterWordDataParser.java | 10 ++ .../parser/MonitorCmdDataParser.java | 117 +++++++++++++ .../parser/ServerCmdDataParser.java | 97 +++++++++++ .../utils/zookeeper/FourLetterWordUtil.java | 163 ++++++++++++++++++ .../utils/zookeeper/ZookeeperUtils.java | 59 +++++++ 11 files changed, 679 insertions(+) create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/BaseFourLetterWordCmdData.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ConfigCmdData.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ConfigCmdDataParser.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/FourLetterWordDataParser.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ServerCmdDataParser.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/FourLetterWordUtil.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/ZookeeperUtils.java diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/result/ResultStatus.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/result/ResultStatus.java index 842e1106..252146c9 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/result/ResultStatus.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/result/ResultStatus.java @@ -56,6 +56,7 @@ public enum ResultStatus { KAFKA_OPERATE_FAILED(8010, "Kafka操作失败"), MYSQL_OPERATE_FAILED(8020, "MySQL操作失败"), ZK_OPERATE_FAILED(8030, "ZK操作失败"), + ZK_FOUR_LETTER_CMD_FORBIDDEN(8031, "ZK四字命令被禁止"), ES_OPERATE_ERROR(8040, "ES操作失败"), HTTP_REQ_ERROR(8050, "第三方http请求异常"), diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/BaseFourLetterWordCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/BaseFourLetterWordCmdData.java new file mode 100644 index 00000000..3e5713a8 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/BaseFourLetterWordCmdData.java @@ -0,0 +1,9 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword; + +import java.io.Serializable; + +/** + * 四字命令结果数据的基础类 + */ +public class BaseFourLetterWordCmdData implements Serializable { +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ConfigCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ConfigCmdData.java new file mode 100644 index 00000000..d0982f47 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ConfigCmdData.java @@ -0,0 +1,38 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword; + +import lombok.Data; + + +/** + * clientPort=2183 + * dataDir=/data1/data/zkData2/version-2 + * dataLogDir=/data1/data/zkLog2/version-2 + * tickTime=2000 + * maxClientCnxns=60 + * minSessionTimeout=4000 + * maxSessionTimeout=40000 + * serverId=2 + * initLimit=15 + * syncLimit=10 + * electionAlg=3 + * electionPort=4445 + * quorumPort=4444 + * peerType=0 + */ +@Data +public class ConfigCmdData extends BaseFourLetterWordCmdData { + private Long clientPort; + private String dataDir; + private String dataLogDir; + private Long tickTime; + private Long maxClientCnxns; + private Long minSessionTimeout; + private Long maxSessionTimeout; + private Integer serverId; + private String initLimit; + private Long syncLimit; + private Long electionAlg; + private Long electionPort; + private Long quorumPort; + private Long peerType; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java new file mode 100644 index 00000000..7ea1339b --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java @@ -0,0 +1,39 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword; + +import lombok.Data; + +/** + * zk_version 3.4.6-1569965, built on 02/20/2014 09:09 GMT + * zk_avg_latency 0 + * zk_max_latency 399 + * zk_min_latency 0 + * zk_packets_received 234857 + * zk_packets_sent 234860 + * zk_num_alive_connections 4 + * zk_outstanding_requests 0 + * zk_server_state follower + * zk_znode_count 35566 + * zk_watch_count 39 + * zk_ephemerals_count 10 + * zk_approximate_data_size 3356708 + * zk_open_file_descriptor_count 35 + * zk_max_file_descriptor_count 819200 + */ +@Data +public class MonitorCmdData extends BaseFourLetterWordCmdData { + private String zkVersion; + private Long zkAvgLatency; + private Long zkMaxLatency; + private Long zkMinLatency; + private Long zkPacketsReceived; + private Long zkPacketsSent; + private Long zkNumAliveConnections; + private Long zkOutstandingRequests; + private String zkServerState; + private Long zkZnodeCount; + private Long zkWatchCount; + private Long zkEphemeralsCount; + private Long zkApproximateDataSize; + private Long zkOpenFileDescriptorCount; + private Long zkMaxFileDescriptorCount; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java new file mode 100644 index 00000000..38bd2cf9 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java @@ -0,0 +1,30 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword; + +import lombok.Data; + +/** + * Zookeeper version: 3.5.9-83df9301aa5c2a5d284a9940177808c01bc35cef, built on 01/06/2021 19:49 GMT + * Latency min/avg/max: 0/0/2209 + * Received: 278202469 + * Sent: 279449055 + * Connections: 31 + * Outstanding: 0 + * Zxid: 0x20033fc12 + * Mode: leader + * Node count: 10084 + * Proposal sizes last/min/max: 36/32/31260 leader特有 + */ +@Data +public class ServerCmdData extends BaseFourLetterWordCmdData { + private String zkVersion; + private Long zkAvgLatency; + private Long zkMaxLatency; + private Long zkMinLatency; + private Long zkPacketsReceived; + private Long zkPacketsSent; + private Long zkNumAliveConnections; + private Long zkOutstandingRequests; + private String zkServerState; + private Long zkZnodeCount; + private Long zkZxid; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ConfigCmdDataParser.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ConfigCmdDataParser.java new file mode 100644 index 00000000..35ec153b --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ConfigCmdDataParser.java @@ -0,0 +1,116 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.ConfigCmdData; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * clientPort=2183 + * dataDir=/data1/data/zkData2/version-2 + * dataLogDir=/data1/data/zkLog2/version-2 + * tickTime=2000 + * maxClientCnxns=60 + * minSessionTimeout=4000 + * maxSessionTimeout=40000 + * serverId=2 + * initLimit=15 + * syncLimit=10 + * electionAlg=3 + * electionPort=4445 + * quorumPort=4444 + * peerType=0 + */ +@Data +public class ConfigCmdDataParser implements FourLetterWordDataParser { + private static final ILog LOGGER = LogFactory.getLog(ConfigCmdDataParser.class); + + private Result dataResult = null; + + @Override + public String getCmd() { + return FourLetterWordUtil.ConfigCmd; + } + + @Override + public ConfigCmdData parseAndInitData(Long clusterPhyId, String host, int port, String cmdData) { + Map dataMap = new HashMap<>(); + for (String elem : cmdData.split("\n")) { + if (elem.isEmpty()) { + continue; + } + + int idx = elem.indexOf('='); + if (idx >= 0) { + dataMap.put(elem.substring(0, idx), elem.substring(idx + 1).trim()); + } + } + + ConfigCmdData configCmdData = new ConfigCmdData(); + dataMap.entrySet().stream().forEach(elem -> { + try { + switch (elem.getKey()) { + case "clientPort": + configCmdData.setClientPort(Long.valueOf(elem.getValue())); + break; + case "dataDir": + configCmdData.setDataDir(elem.getValue()); + break; + case "dataLogDir": + configCmdData.setDataLogDir(elem.getValue()); + break; + case "tickTime": + configCmdData.setTickTime(Long.valueOf(elem.getValue())); + break; + case "maxClientCnxns": + configCmdData.setMaxClientCnxns(Long.valueOf(elem.getValue())); + break; + case "minSessionTimeout": + configCmdData.setMinSessionTimeout(Long.valueOf(elem.getValue())); + break; + case "maxSessionTimeout": + configCmdData.setMaxSessionTimeout(Long.valueOf(elem.getValue())); + break; + case "serverId": + configCmdData.setServerId(Integer.valueOf(elem.getValue())); + break; + case "initLimit": + configCmdData.setInitLimit(elem.getValue()); + break; + case "syncLimit": + configCmdData.setSyncLimit(Long.valueOf(elem.getValue())); + break; + case "electionAlg": + configCmdData.setElectionAlg(Long.valueOf(elem.getValue())); + break; + case "electionPort": + configCmdData.setElectionPort(Long.valueOf(elem.getValue())); + break; + case "quorumPort": + configCmdData.setQuorumPort(Long.valueOf(elem.getValue())); + break; + case "peerType": + configCmdData.setPeerType(Long.valueOf(elem.getValue())); + break; + default: + LOGGER.warn( + "class=ConfigCmdDataParser||method=parseAndInitData||name={}||value={}||msg=data not parsed!", + elem.getKey(), elem.getValue() + ); + } + } catch (Exception e) { + LOGGER.error( + "class=ConfigCmdDataParser||method=parseAndInitData||clusterPhyId={}||host={}||port={}||name={}||value={}||errMsg=exception!", + clusterPhyId, host, port, elem.getKey(), elem.getValue(), e + ); + } + }); + + return configCmdData; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/FourLetterWordDataParser.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/FourLetterWordDataParser.java new file mode 100644 index 00000000..58bb2368 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/FourLetterWordDataParser.java @@ -0,0 +1,10 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser; + +/** + * 四字命令结果解析类 + */ +public interface FourLetterWordDataParser { + String getCmd(); + + T parseAndInitData(Long clusterPhyId, String host, int port, String cmdData); +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java new file mode 100644 index 00000000..a33f4da3 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java @@ -0,0 +1,117 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.MonitorCmdData; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * zk_version 3.4.6-1569965, built on 02/20/2014 09:09 GMT + * zk_avg_latency 0 + * zk_max_latency 399 + * zk_min_latency 0 + * zk_packets_received 234857 + * zk_packets_sent 234860 + * zk_num_alive_connections 4 + * zk_outstanding_requests 0 + * zk_server_state follower + * zk_znode_count 35566 + * zk_watch_count 39 + * zk_ephemerals_count 10 + * zk_approximate_data_size 3356708 + * zk_open_file_descriptor_count 35 + * zk_max_file_descriptor_count 819200 + */ +@Data +public class MonitorCmdDataParser implements FourLetterWordDataParser { + private static final ILog LOGGER = LogFactory.getLog(MonitorCmdDataParser.class); + + @Override + public String getCmd() { + return FourLetterWordUtil.MonitorCmd; + } + + @Override + public MonitorCmdData parseAndInitData(Long clusterPhyId, String host, int port, String cmdData) { + Map dataMap = new HashMap<>(); + for (String elem : cmdData.split("\n")) { + if (elem.isEmpty()) { + continue; + } + + int idx = elem.indexOf('\t'); + if (idx >= 0) { + dataMap.put(elem.substring(0, idx), elem.substring(idx + 1).trim()); + } + } + + MonitorCmdData monitorCmdData = new MonitorCmdData(); + dataMap.entrySet().stream().forEach(elem -> { + try { + switch (elem.getKey()) { + case "zk_version": + monitorCmdData.setZkVersion(elem.getValue().split("-")[0]); + break; + case "zk_avg_latency": + monitorCmdData.setZkAvgLatency(Long.valueOf(elem.getValue())); + break; + case "zk_max_latency": + monitorCmdData.setZkMaxLatency(Long.valueOf(elem.getValue())); + break; + case "zk_min_latency": + monitorCmdData.setZkMinLatency(Long.valueOf(elem.getValue())); + break; + case "zk_packets_received": + monitorCmdData.setZkPacketsReceived(Long.valueOf(elem.getValue())); + break; + case "zk_packets_sent": + monitorCmdData.setZkPacketsSent(Long.valueOf(elem.getValue())); + break; + case "zk_num_alive_connections": + monitorCmdData.setZkNumAliveConnections(Long.valueOf(elem.getValue())); + break; + case "zk_outstanding_requests": + monitorCmdData.setZkOutstandingRequests(Long.valueOf(elem.getValue())); + break; + case "zk_server_state": + monitorCmdData.setZkServerState(elem.getValue()); + break; + case "zk_znode_count": + monitorCmdData.setZkZnodeCount(Long.valueOf(elem.getValue())); + break; + case "zk_watch_count": + monitorCmdData.setZkWatchCount(Long.valueOf(elem.getValue())); + break; + case "zk_ephemerals_count": + monitorCmdData.setZkEphemeralsCount(Long.valueOf(elem.getValue())); + break; + case "zk_approximate_data_size": + monitorCmdData.setZkApproximateDataSize(Long.valueOf(elem.getValue())); + break; + case "zk_open_file_descriptor_count": + monitorCmdData.setZkOpenFileDescriptorCount(Long.valueOf(elem.getValue())); + break; + case "zk_max_file_descriptor_count": + monitorCmdData.setZkMaxFileDescriptorCount(Long.valueOf(elem.getValue())); + break; + default: + LOGGER.warn( + "class=MonitorCmdDataParser||method=parseAndInitData||name={}||value={}||msg=data not parsed!", + elem.getKey(), elem.getValue() + ); + } + } catch (Exception e) { + LOGGER.error( + "class=MonitorCmdDataParser||method=parseAndInitData||clusterPhyId={}||host={}||port={}||name={}||value={}||errMsg=exception!", + clusterPhyId, host, port, elem.getKey(), elem.getValue(), e + ); + } + }); + + return monitorCmdData; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ServerCmdDataParser.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ServerCmdDataParser.java new file mode 100644 index 00000000..f91f19a8 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/ServerCmdDataParser.java @@ -0,0 +1,97 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.ServerCmdData; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * Zookeeper version: 3.5.9-83df9301aa5c2a5d284a9940177808c01bc35cef, built on 01/06/2021 19:49 GMT + * Latency min/avg/max: 0/0/2209 + * Received: 278202469 + * Sent: 279449055 + * Connections: 31 + * Outstanding: 0 + * Zxid: 0x20033fc12 + * Mode: leader + * Node count: 10084 + * Proposal sizes last/min/max: 36/32/31260 leader特有 + */ +@Data +public class ServerCmdDataParser implements FourLetterWordDataParser { + private static final ILog LOGGER = LogFactory.getLog(ServerCmdDataParser.class); + + @Override + public String getCmd() { + return FourLetterWordUtil.ServerCmd; + } + + @Override + public ServerCmdData parseAndInitData(Long clusterPhyId, String host, int port, String cmdData) { + Map dataMap = new HashMap<>(); + for (String elem : cmdData.split("\n")) { + if (elem.isEmpty()) { + continue; + } + + int idx = elem.indexOf(':'); + if (idx >= 0) { + dataMap.put(elem.substring(0, idx), elem.substring(idx + 1).trim()); + } + } + + ServerCmdData serverCmdData = new ServerCmdData(); + dataMap.entrySet().stream().forEach(elem -> { + try { + switch (elem.getKey()) { + case "Zookeeper version": + serverCmdData.setZkVersion(elem.getValue().split("-")[0]); + break; + case "Latency min/avg/max": + String[] data = elem.getValue().split("/"); + serverCmdData.setZkMinLatency(Long.valueOf(data[0])); + serverCmdData.setZkAvgLatency(Long.valueOf(data[1])); + serverCmdData.setZkMaxLatency(Long.valueOf(data[2])); + break; + case "Received": + serverCmdData.setZkPacketsReceived(Long.valueOf(elem.getValue())); + break; + case "Sent": + serverCmdData.setZkPacketsSent(Long.valueOf(elem.getValue())); + break; + case "Connections": + serverCmdData.setZkNumAliveConnections(Long.valueOf(elem.getValue())); + break; + case "Outstanding": + serverCmdData.setZkOutstandingRequests(Long.valueOf(elem.getValue())); + break; + case "Mode": + serverCmdData.setZkServerState(elem.getValue()); + break; + case "Node count": + serverCmdData.setZkZnodeCount(Long.valueOf(elem.getValue())); + break; + case "Zxid": + serverCmdData.setZkZxid(Long.parseUnsignedLong(elem.getValue().trim().substring(2), 16)); + break; + default: + LOGGER.warn( + "class=ServerCmdDataParser||method=parseAndInitData||name={}||value={}||msg=data not parsed!", + elem.getKey(), elem.getValue() + ); + } + } catch (Exception e) { + LOGGER.error( + "class=ServerCmdDataParser||method=parseAndInitData||clusterPhyId={}||host={}||port={}||name={}||value={}||errMsg=exception!", + clusterPhyId, host, port, elem.getKey(), elem.getValue(), e + ); + } + }); + + return serverCmdData; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/FourLetterWordUtil.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/FourLetterWordUtil.java new file mode 100644 index 00000000..a3ae31af --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/FourLetterWordUtil.java @@ -0,0 +1,163 @@ +package com.xiaojukeji.know.streaming.km.common.utils.zookeeper; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.FourLetterWordDataParser; +import com.xiaojukeji.know.streaming.km.common.utils.BackoffUtils; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; +import org.apache.zookeeper.common.ClientX509Util; +import org.apache.zookeeper.common.X509Exception; +import org.apache.zookeeper.common.X509Util; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.util.HashSet; +import java.util.Set; + +public class FourLetterWordUtil { + private static final ILog LOGGER = LogFactory.getLog(FourLetterWordUtil.class); + + public static final String MonitorCmd = "mntr"; + public static final String ConfigCmd = "conf"; + public static final String ServerCmd = "srvr"; + + private static final Set supportedCommands = new HashSet<>(); + + public static Result executeFourLetterCmd(Long clusterPhyId, + String host, + int port, + boolean secure, + int timeout, + FourLetterWordDataParser dataParser) { + try { + if (!supportedCommands.contains(dataParser.getCmd())) { + return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, String.format("ZK %s命令暂未进行支持", dataParser.getCmd())); + } + + String cmdData = send4LetterWord(host, port, dataParser.getCmd(), secure, timeout); + if (cmdData.contains("not executed because it is not in the whitelist.")) { + return Result.buildFromRSAndMsg(ResultStatus.ZK_FOUR_LETTER_CMD_FORBIDDEN, cmdData); + } + if (ValidateUtils.isBlank(cmdData)) { + return Result.buildFromRSAndMsg(ResultStatus.ZK_OPERATE_FAILED, cmdData); + } + + return Result.buildSuc(dataParser.parseAndInitData(clusterPhyId, host, port, cmdData)); + } catch (Exception e) { + LOGGER.error( + "class=FourLetterWordUtil||method=executeFourLetterCmd||clusterPhyId={}||host={}||port={}||cmd={}||secure={}||timeout={}||errMsg=exception!", + clusterPhyId, host, port, dataParser.getCmd(), secure, timeout, e + ); + + return Result.buildFromRSAndMsg(ResultStatus.ZK_OPERATE_FAILED, e.getMessage()); + } + } + + + /**************************************************** private method ****************************************************/ + + private static String send4LetterWord( + String host, + int port, + String cmd, + boolean secure, + int timeout) throws IOException, X509Exception.SSLContextException { + long startTime = System.currentTimeMillis(); + + LOGGER.info("connecting to {} {}", host, port); + + Socket socket = null; + OutputStream outputStream = null; + BufferedReader bufferedReader = null; + try { + InetSocketAddress hostaddress = host != null + ? new InetSocketAddress(host, port) + : new InetSocketAddress(InetAddress.getByName(null), port); + if (secure) { + LOGGER.info("using secure socket"); + try (X509Util x509Util = new ClientX509Util()) { + SSLContext sslContext = x509Util.getDefaultSSLContext(); + SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + SSLSocket sslSock = (SSLSocket) socketFactory.createSocket(); + sslSock.connect(hostaddress, timeout); + sslSock.startHandshake(); + socket = sslSock; + } + } else { + socket = new Socket(); + socket.connect(hostaddress, timeout); + } + socket.setSoTimeout(timeout); + + outputStream = socket.getOutputStream(); + outputStream.write(cmd.getBytes()); + outputStream.flush(); + + // 等待InputStream有数据 + while (System.currentTimeMillis() - startTime <= timeout && socket.getInputStream().available() <= 0) { + BackoffUtils.backoff(10); + } + + bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = bufferedReader.readLine()) != null) { + sb.append(line).append("\n"); + } + return sb.toString(); + } catch (SocketTimeoutException e) { + throw new IOException("Exception while executing four letter word: " + cmd, e); + } finally { + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + LOGGER.error( + "class=FourLetterWordUtil||method=send4LetterWord||clusterPhyId={}||host={}||port={}||cmd={}||secure={}||timeout={}||errMsg=exception!", + host, port, cmd, secure, timeout, e + ); + } + } + + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (IOException e) { + LOGGER.error( + "class=FourLetterWordUtil||method=send4LetterWord||host={}||port={}||cmd={}||secure={}||timeout={}||errMsg=exception!", + host, port, cmd, secure, timeout, e + ); + } + } + + if (socket != null) { + try { + socket.close(); + } catch (IOException e) { + LOGGER.error( + "class=FourLetterWordUtil||method=send4LetterWord||host={}||port={}||cmd={}||secure={}||timeout={}||errMsg=exception!", + host, port, cmd, secure, timeout, e + ); + } + } + } + } + + static { + supportedCommands.add(MonitorCmd); + supportedCommands.add(ConfigCmd); + supportedCommands.add(ServerCmd); + } + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/ZookeeperUtils.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/ZookeeperUtils.java new file mode 100644 index 00000000..9d8c6c5b --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/zookeeper/ZookeeperUtils.java @@ -0,0 +1,59 @@ +package com.xiaojukeji.know.streaming.km.common.utils.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import org.apache.zookeeper.client.ConnectStringParser; +import org.apache.zookeeper.common.NetUtils; + +import java.util.ArrayList; +import java.util.List; + +import static org.apache.zookeeper.common.StringUtils.split; + +public class ZookeeperUtils { + private static final int DEFAULT_PORT = 2181; + + /** + * 解析ZK地址 + * @see ConnectStringParser + */ + public static List> connectStringParser(String connectString) throws Exception { + List> ipPortList = new ArrayList<>(); + + if (connectString == null) { + return ipPortList; + } + + // parse out chroot, if any + int off = connectString.indexOf('/'); + if (off >= 0) { + connectString = connectString.substring(0, off); + } + + List hostsList = split(connectString, ","); + for (String host : hostsList) { + int port = DEFAULT_PORT; + String[] hostAndPort = NetUtils.getIPV6HostAndPort(host); + if (hostAndPort.length != 0) { + host = hostAndPort[0]; + if (hostAndPort.length == 2) { + port = Integer.parseInt(hostAndPort[1]); + } + } else { + int pidx = host.lastIndexOf(':'); + if (pidx >= 0) { + // otherwise : is at the end of the string, ignore + if (pidx < host.length() - 1) { + port = Integer.parseInt(host.substring(pidx + 1)); + } + host = host.substring(0, pidx); + } + } + + ipPortList.add(new Tuple<>(host, port)); + } + + return ipPortList; + } + + +} From 34b7c6746b8517ae753b46db4b6693ff690c99cb Mon Sep 17 00:00:00 2001 From: zengqiao Date: Sat, 8 Oct 2022 14:58:28 +0800 Subject: [PATCH 077/145] =?UTF-8?q?ZK-=E5=A2=9E=E5=8A=A0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=9A=84=E9=BB=98=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/bean/entity/config/ZKConfig.java | 47 +++++++++++++++++-- .../km/common/constant/Constant.java | 6 ++- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/ZKConfig.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/ZKConfig.java index 39e6fdf5..66a727e5 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/ZKConfig.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/ZKConfig.java @@ -1,8 +1,8 @@ package com.xiaojukeji.know.streaming.km.common.bean.entity.config; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import lombok.Data; import java.io.Serializable; import java.util.Properties; @@ -11,7 +11,6 @@ import java.util.Properties; * @author zengqiao * @date 22/02/24 */ -@Data @ApiModel(description = "ZK配置") public class ZKConfig implements Serializable { @ApiModelProperty(value="ZK的jmx配置") @@ -21,11 +20,51 @@ public class ZKConfig implements Serializable { private Boolean openSecure = false; @ApiModelProperty(value="ZK的Session超时时间", example = "15000") - private Long sessionTimeoutUnitMs = 15000L; + private Integer sessionTimeoutUnitMs = 15000; @ApiModelProperty(value="ZK的Request超时时间", example = "5000") - private Long requestTimeoutUnitMs = 5000L; + private Integer requestTimeoutUnitMs = 5000; @ApiModelProperty(value="ZK的Request超时时间") private Properties otherProps = new Properties(); + + public JmxConfig getJmxConfig() { + return jmxConfig == null? new JmxConfig(): jmxConfig; + } + + public void setJmxConfig(JmxConfig jmxConfig) { + this.jmxConfig = jmxConfig; + } + + public Boolean getOpenSecure() { + return openSecure != null && openSecure; + } + + public void setOpenSecure(Boolean openSecure) { + this.openSecure = openSecure; + } + + public Integer getSessionTimeoutUnitMs() { + return sessionTimeoutUnitMs == null? Constant.DEFAULT_SESSION_TIMEOUT_UNIT_MS: sessionTimeoutUnitMs; + } + + public void setSessionTimeoutUnitMs(Integer sessionTimeoutUnitMs) { + this.sessionTimeoutUnitMs = sessionTimeoutUnitMs; + } + + public Integer getRequestTimeoutUnitMs() { + return requestTimeoutUnitMs == null? Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS: requestTimeoutUnitMs; + } + + public void setRequestTimeoutUnitMs(Integer requestTimeoutUnitMs) { + this.requestTimeoutUnitMs = requestTimeoutUnitMs; + } + + public Properties getOtherProps() { + return otherProps == null? new Properties() : otherProps; + } + + public void setOtherProps(Properties otherProps) { + this.otherProps = otherProps; + } } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java index edd897ff..a91f0809 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java @@ -23,8 +23,8 @@ public class Constant { public static final Integer YES = 1; public static final Integer NO = 0; - public static final Integer ALIVE = 1; - public static final Integer DOWN = 0; + public static final Integer ALIVE = 1; + public static final Integer DOWN = 0; public static final Integer ONE_HUNDRED = 100; @@ -33,6 +33,7 @@ public class Constant { public static final Long B_TO_MB = 1024L * 1024L; public static final Integer DEFAULT_SESSION_TIMEOUT_UNIT_MS = 15000; + public static final Integer DEFAULT_REQUEST_TIMEOUT_UNIT_MS = 5000; public static final Float MIN_HEALTH_SCORE = 10f; @@ -66,4 +67,5 @@ public class Constant { public static final Integer DEFAULT_RETRY_TIME = 3; + public static final Integer ZK_ALIVE_BUT_4_LETTER_FORBIDDEN = 11; } From 1bc725bd62518e7540cdc36d9980f242f83d82b0 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Sat, 8 Oct 2022 15:19:09 +0800 Subject: [PATCH 078/145] =?UTF-8?q?ZK-=E5=90=8C=E6=AD=A5ZK=E5=85=83?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E8=87=B3DB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/install_guide/版本升级手册.md | 17 +- .../bean/entity/zookeeper/ZookeeperInfo.java | 42 +++++ .../bean/po/zookeeper/ZookeeperInfoPO.java | 40 +++++ .../km/common/enums/zookeeper/ZKRoleEnum.java | 22 +++ .../service/zookeeper/ZookeeperService.java | 18 +++ .../zookeeper/impl/ZookeeperServiceImpl.java | 147 ++++++++++++++++++ km-dist/init/sql/ddl-ks-km.sql | 16 ++ .../mysql/zookeeper/ZookeeperDAO.java | 9 ++ .../km/task/metadata/SyncZookeeperTask.java | 47 ++++++ 9 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/ZookeeperInfo.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/zookeeper/ZookeeperInfoPO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/zookeeper/ZKRoleEnum.java create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java create mode 100644 km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/zookeeper/ZookeeperDAO.java create mode 100644 km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncZookeeperTask.java diff --git a/docs/install_guide/版本升级手册.md b/docs/install_guide/版本升级手册.md index a75f71fd..efc01399 100644 --- a/docs/install_guide/版本升级手册.md +++ b/docs/install_guide/版本升级手册.md @@ -7,7 +7,22 @@ ### 6.2.0、升级至 `master` 版本 -暂无 +```sql +DROP TABLE IF EXISTS `ks_km_zookeeper`; +CREATE TABLE `ks_km_zookeeper` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '物理集群ID', + `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper主机名', + `port` int(16) NOT NULL DEFAULT '-1' COMMENT 'zookeeper端口', + `role` int(16) NOT NULL DEFAULT '-1' COMMENT '角色, leader follower observer', + `version` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper版本', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态: 1存活,0未存活,11存活但是4字命令使用不了', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_host_port` (`cluster_phy_id`,`host`, `port`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Zookeeper信息表'; +``` ### 6.2.1、升级至 `v3.0.0` 版本 diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/ZookeeperInfo.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/ZookeeperInfo.java new file mode 100644 index 00000000..e943952e --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/ZookeeperInfo.java @@ -0,0 +1,42 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.BaseEntity; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import lombok.Data; + +@Data +public class ZookeeperInfo extends BaseEntity { + /** + * 集群Id + */ + private Long clusterPhyId; + + /** + * 主机 + */ + private String host; + + /** + * 端口 + */ + private Integer port; + + /** + * 角色 + */ + private String role; + + /** + * 版本 + */ + private String version; + + /** + * ZK状态 + */ + private Integer status; + + public boolean alive() { + return !(Constant.DOWN.equals(status)); + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/zookeeper/ZookeeperInfoPO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/zookeeper/ZookeeperInfoPO.java new file mode 100644 index 00000000..69968ef6 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/zookeeper/ZookeeperInfoPO.java @@ -0,0 +1,40 @@ +package com.xiaojukeji.know.streaming.km.common.bean.po.zookeeper; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.xiaojukeji.know.streaming.km.common.bean.po.BasePO; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import lombok.Data; + +@Data +@TableName(Constant.MYSQL_TABLE_NAME_PREFIX + "zookeeper") +public class ZookeeperInfoPO extends BasePO { + /** + * 集群Id + */ + private Long clusterPhyId; + + /** + * 主机 + */ + private String host; + + /** + * 端口 + */ + private Integer port; + + /** + * 角色 + */ + private String role; + + /** + * 版本 + */ + private String version; + + /** + * ZK状态 + */ + private Integer status; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/zookeeper/ZKRoleEnum.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/zookeeper/ZKRoleEnum.java new file mode 100644 index 00000000..fd379dc8 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/zookeeper/ZKRoleEnum.java @@ -0,0 +1,22 @@ +package com.xiaojukeji.know.streaming.km.common.enums.zookeeper; + +import lombok.Getter; + +@Getter +public enum ZKRoleEnum { + LEADER("leader"), + + FOLLOWER("follower"), + + OBSERVER("observer"), + + UNKNOWN("unknown"), + + ; + + private final String role; + + ZKRoleEnum(String role) { + this.role = role; + } +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java new file mode 100644 index 00000000..758247aa --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java @@ -0,0 +1,18 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; + +import java.util.List; + +public interface ZookeeperService { + /** + * 从ZK集群中获取ZK信息 + */ + Result> listFromZookeeper(Long clusterPhyId, String zookeeperAddress, ZKConfig zkConfig); + + void batchReplaceDataInDB(Long clusterPhyId, List infoList); + + List listFromDBByCluster(Long clusterPhyId); +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java new file mode 100644 index 00000000..2f1e318c --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java @@ -0,0 +1,147 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.ServerCmdData; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.ServerCmdDataParser; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.zookeeper.ZKRoleEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.common.bean.po.zookeeper.ZookeeperInfoPO; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.ZookeeperUtils; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import com.xiaojukeji.know.streaming.km.persistence.mysql.zookeeper.ZookeeperDAO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class ZookeeperServiceImpl implements ZookeeperService { + private static final ILog LOGGER = LogFactory.getLog(ZookeeperServiceImpl.class); + + @Autowired + private ZookeeperDAO zookeeperDAO; + + @Override + public Result> listFromZookeeper(Long clusterPhyId, String zookeeperAddress, ZKConfig zkConfig) { + List> addressList = null; + try { + addressList = ZookeeperUtils.connectStringParser(zookeeperAddress); + } catch (Exception e) { + LOGGER.error( + "class=ZookeeperServiceImpl||method=listFromZookeeperCluster||clusterPhyId={}||zookeeperAddress={}||errMsg=exception!", + clusterPhyId, zookeeperAddress, e + ); + + return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, e.getMessage()); + } + + List aliveZKList = new ArrayList<>(); + for (Tuple hostPort: addressList) { + aliveZKList.add(this.getFromZookeeperCluster( + clusterPhyId, + hostPort.getV1(), + hostPort.getV2(), + zkConfig + )); + } + return Result.buildSuc(aliveZKList); + } + + @Override + public void batchReplaceDataInDB(Long clusterPhyId, List infoList) { + // DB 中的信息 + List dbInfoList = this.listRawFromDBByCluster(clusterPhyId); + Map dbMap = new HashMap<>(); + dbInfoList.stream().forEach(elem -> dbMap.put(elem.getHost() + elem.getPort(), elem)); + + // 新获取到的信息 + List newInfoList = ConvertUtil.list2List(infoList, ZookeeperInfoPO.class); + for (ZookeeperInfoPO newInfo: newInfoList) { + try { + ZookeeperInfoPO oldInfo = dbMap.remove(newInfo.getHost() + newInfo.getPort()); + if (oldInfo == null) { + zookeeperDAO.insert(newInfo); + } else if (!Constant.DOWN.equals(newInfo.getStatus())) { + // 存活时,直接使用获取到的数据 + newInfo.setId(oldInfo.getId()); + zookeeperDAO.updateById(newInfo); + } else { + // 如果挂了,则版本和角色信息,使用先前的信息。 + // 挂掉之后,如果角色是leader,则需要调整一下 + newInfo.setId(oldInfo.getId()); + newInfo.setRole(ZKRoleEnum.LEADER.getRole().equals(oldInfo.getRole())? ZKRoleEnum.FOLLOWER.getRole(): oldInfo.getRole()); + newInfo.setVersion(oldInfo.getVersion()); + zookeeperDAO.updateById(newInfo); + } + } catch (Exception e) { + LOGGER.error("class=ZookeeperServiceImpl||method=batchReplaceDataInDB||clusterPhyId={}||newInfo={}||errMsg=exception", clusterPhyId, newInfo, e); + } + } + + // 删除剩余的ZK节点 + dbMap.entrySet().forEach(entry -> { + try { + zookeeperDAO.deleteById(entry.getValue().getId()); + } catch (Exception e) { + LOGGER.error("class=ZookeeperServiceImpl||method=batchReplaceDataInDB||clusterPhyId={}||expiredInfo={}||errMsg=exception", clusterPhyId, entry.getValue(), e); + } + }); + } + + @Override + public List listFromDBByCluster(Long clusterPhyId) { + return ConvertUtil.list2List(this.listRawFromDBByCluster(clusterPhyId), ZookeeperInfo.class); + } + + + /**************************************************** private method ****************************************************/ + + private List listRawFromDBByCluster(Long clusterPhyId) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(ZookeeperInfoPO::getClusterPhyId, clusterPhyId); + + return zookeeperDAO.selectList(lambdaQueryWrapper); + } + + private ZookeeperInfo getFromZookeeperCluster(Long clusterPhyId, String host, Integer port, ZKConfig zkConfig) { + ZookeeperInfo zookeeperInfo = new ZookeeperInfo(); + zookeeperInfo.setClusterPhyId(clusterPhyId); + zookeeperInfo.setHost(host); + zookeeperInfo.setPort(port); + zookeeperInfo.setRole(""); + zookeeperInfo.setVersion(""); + zookeeperInfo.setStatus(Constant.DOWN); + + Result serverCmdDataResult = FourLetterWordUtil.executeFourLetterCmd( + clusterPhyId, + host, + port, + zkConfig != null ? zkConfig.getOpenSecure(): false, + zkConfig != null ? zkConfig.getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, + new ServerCmdDataParser() + ); + if (serverCmdDataResult.hasData()) { + zookeeperInfo.setRole(serverCmdDataResult.getData().getZkServerState()); + zookeeperInfo.setVersion(serverCmdDataResult.getData().getZkVersion()); + zookeeperInfo.setStatus(Constant.ALIVE); + } else if (serverCmdDataResult.getCode().equals(ResultStatus.ZK_FOUR_LETTER_CMD_FORBIDDEN.getCode())) { + zookeeperInfo.setStatus(Constant.ZK_ALIVE_BUT_4_LETTER_FORBIDDEN); + } else { + return zookeeperInfo; + } + + return zookeeperInfo; + } +} diff --git a/km-dist/init/sql/ddl-ks-km.sql b/km-dist/init/sql/ddl-ks-km.sql index d9e4e16c..89f04034 100644 --- a/km-dist/init/sql/ddl-ks-km.sql +++ b/km-dist/init/sql/ddl-ks-km.sql @@ -355,3 +355,19 @@ CREATE TABLE `ks_km_app_node` ( PRIMARY KEY (`id`), KEY `idx_app_host` (`app_name`,`host_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='km集群部署的node信息'; + + +DROP TABLE IF EXISTS `ks_km_zookeeper`; +CREATE TABLE `ks_km_zookeeper` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '物理集群ID', + `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper主机名', + `port` int(16) NOT NULL DEFAULT '-1' COMMENT 'zookeeper端口', + `role` int(16) NOT NULL DEFAULT '-1' COMMENT '角色, leader follower observer', + `version` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper版本', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态: 1存活,0未存活,11存活但是4字命令使用不了', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_host_port` (`cluster_phy_id`,`host`, `port`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Zookeeper信息表'; \ No newline at end of file diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/zookeeper/ZookeeperDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/zookeeper/ZookeeperDAO.java new file mode 100644 index 00000000..73a177ae --- /dev/null +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/zookeeper/ZookeeperDAO.java @@ -0,0 +1,9 @@ +package com.xiaojukeji.know.streaming.km.persistence.mysql.zookeeper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xiaojukeji.know.streaming.km.common.bean.po.zookeeper.ZookeeperInfoPO; +import org.springframework.stereotype.Repository; + +@Repository +public interface ZookeeperDAO extends BaseMapper { +} diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncZookeeperTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncZookeeperTask.java new file mode 100644 index 00000000..5af37be2 --- /dev/null +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncZookeeperTask.java @@ -0,0 +1,47 @@ +package com.xiaojukeji.know.streaming.km.task.metadata; + +import com.didiglobal.logi.job.annotation.Task; +import com.didiglobal.logi.job.common.TaskResult; +import com.didiglobal.logi.job.core.consensual.ConsensualEnum; +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + + +@Task(name = "SyncZookeeperTask", + description = "ZK信息同步到DB", + cron = "0 0/1 * * * ? *", + autoRegister = true, + consensual = ConsensualEnum.BROADCAST, + timeout = 2 * 60) +public class SyncZookeeperTask extends AbstractAsyncMetadataDispatchTask { + private static final ILog log = LogFactory.getLog(SyncZookeeperTask.class); + + @Autowired + private ZookeeperService zookeeperService; + + @Override + public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { + Result> infoResult = zookeeperService.listFromZookeeper( + clusterPhy.getId(), + clusterPhy.getZookeeper(), + ConvertUtil.str2ObjByJson(clusterPhy.getZkProperties(), ZKConfig.class) + ); + + if (infoResult.failed()) { + return new TaskResult(TaskResult.FAIL_CODE, infoResult.getMessage()); + } + + zookeeperService.batchReplaceDataInDB(clusterPhy.getId(), infoResult.getData()); + + return TaskResult.SUCCESS; + } +} From c4910964dbcffab49294251e1b41e0e315ed7995 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Sat, 8 Oct 2022 15:31:59 +0800 Subject: [PATCH 079/145] =?UTF-8?q?ZK-=E6=8C=87=E6=A0=87=E9=87=87=E9=9B=86?= =?UTF-8?q?=E5=85=A5ES?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../metric/ZookeeperMetricCollector.java | 122 ++++++++ .../sink/ZookeeperMetricESSender.java | 28 ++ .../bean/entity/metrics/ZookeeperMetrics.java | 28 ++ .../param/metric/ZookeeperMetricParam.java | 47 +++ .../version/VersionMetricControlItem.java | 2 + .../bean/event/metric/BaseMetricEvent.java | 2 - .../event/metric/ZookeeperMetricEvent.java | 20 ++ .../bean/po/metrice/ZookeeperMetricPO.java | 24 ++ .../vo/metrics/line/MetricMultiLinesVO.java | 19 -- .../km/common/constant/ESConstant.java | 2 + .../km/common/constant/ESIndexConstant.java | 85 ++++++ .../enums/version/VersionItemTypeEnum.java | 4 +- .../streaming/km/common/jmx/JmxAttribute.java | 6 + .../know/streaming/km/common/jmx/JmxName.java | 6 + .../broker/impl/BrokerServiceImpl.java | 12 +- .../metrics/ZookeeperMetricVersionItems.java | 141 +++++++++ .../zookeeper/ZookeeperMetricService.java | 21 ++ .../impl/ZookeeperMetricServiceImpl.java | 281 ++++++++++++++++++ .../init/template/ks_kafka_zookeeper_metric | 85 ++++++ .../persistence/es/dao/BaseMetricESDAO.java | 3 +- .../es/dao/ZookeeperMetricESDAO.java | 106 +++++++ .../km/persistence/es/dsls/DslsConstant.java | 2 + .../streaming/km/persistence/jmx/JmxDAO.java | 4 +- .../km/persistence/jmx/impl/JmxDAOImpl.java | 41 ++- .../getAggListZookeeperMetrics | 44 +++ .../metrics/ZookeeperMetricCollectorTask.java | 33 ++ 26 files changed, 1126 insertions(+), 42 deletions(-) create mode 100644 km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ZookeeperMetricCollector.java create mode 100644 km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/sink/ZookeeperMetricESSender.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/metrics/ZookeeperMetrics.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/param/metric/ZookeeperMetricParam.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/ZookeeperMetricEvent.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/metrice/ZookeeperMetricPO.java create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ZookeeperMetricVersionItems.java create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperMetricService.java create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java create mode 100644 km-dist/init/template/ks_kafka_zookeeper_metric create mode 100644 km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ZookeeperMetricESDAO.java create mode 100644 km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics create mode 100644 km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ZookeeperMetricCollectorTask.java diff --git a/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ZookeeperMetricCollector.java b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ZookeeperMetricCollector.java new file mode 100644 index 00000000..37f86d4e --- /dev/null +++ b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ZookeeperMetricCollector.java @@ -0,0 +1,122 @@ +package com.xiaojukeji.know.streaming.km.collector.metric; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.kafkacontroller.KafkaController; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric.ZookeeperMetricParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionControlItem; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; +import com.xiaojukeji.know.streaming.km.common.bean.event.metric.ZookeeperMetricEvent; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.utils.EnvUtil; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ZookeeperMetricPO; +import com.xiaojukeji.know.streaming.km.core.service.kafkacontroller.KafkaControllerService; +import com.xiaojukeji.know.streaming.km.core.service.version.VersionControlService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperMetricService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum.METRIC_ZOOKEEPER; + +/** + * @author didi + */ +@Component +public class ZookeeperMetricCollector extends AbstractMetricCollector { + protected static final ILog LOGGER = LogFactory.getLog("METRIC_LOGGER"); + + @Autowired + private VersionControlService versionControlService; + + @Autowired + private ZookeeperMetricService zookeeperMetricService; + + @Autowired + private ZookeeperService zookeeperService; + + @Autowired + private KafkaControllerService kafkaControllerService; + + @Override + public void collectMetrics(ClusterPhy clusterPhy) { + Long startTime = System.currentTimeMillis(); + Long clusterPhyId = clusterPhy.getId(); + List items = versionControlService.listVersionControlItem(clusterPhyId, collectorType().getCode()); + List aliveZKList = zookeeperService.listFromDBByCluster(clusterPhyId) + .stream() + .filter(elem -> Constant.ALIVE.equals(elem.getStatus())) + .collect(Collectors.toList()); + KafkaController kafkaController = kafkaControllerService.getKafkaControllerFromDB(clusterPhyId); + + ZookeeperMetrics metrics = ZookeeperMetrics.initWithMetric(clusterPhyId, Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, (float)Constant.INVALID_CODE); + if (ValidateUtils.isEmptyList(aliveZKList)) { + // 没有存活的ZK时,发布事件,然后直接返回 + publishMetric(new ZookeeperMetricEvent(this, Arrays.asList(metrics))); + return; + } + + // 构造参数 + ZookeeperMetricParam param = new ZookeeperMetricParam( + clusterPhyId, + aliveZKList.stream().map(elem -> new Tuple(elem.getHost(), elem.getPort())).collect(Collectors.toList()), + ConvertUtil.str2ObjByJson(clusterPhy.getZkProperties(), ZKConfig.class), + kafkaController == null? Constant.INVALID_CODE: kafkaController.getBrokerId(), + null + ); + + for(VersionControlItem v : items) { + try { + if(null != metrics.getMetrics().get(v.getName())) { + continue; + } + param.setMetricName(v.getName()); + + Result ret = zookeeperMetricService.collectMetricsFromZookeeper(param); + if(null == ret || ret.failed() || null == ret.getData()){ + continue; + } + + metrics.putMetric(ret.getData().getMetrics()); + + if(!EnvUtil.isOnline()){ + LOGGER.info( + "class=ZookeeperMetricCollector||method=collectMetrics||clusterPhyId={}||metricName={}||metricValue={}", + clusterPhyId, v.getName(), ConvertUtil.obj2Json(ret.getData().getMetrics()) + ); + } + } catch (Exception e){ + LOGGER.error( + "class=ZookeeperMetricCollector||method=collectMetrics||clusterPhyId={}||metricName={}||errMsg=exception!", + clusterPhyId, v.getName(), e + ); + } + } + + metrics.putMetric(Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME, (System.currentTimeMillis() - startTime) / 1000.0f); + + publishMetric(new ZookeeperMetricEvent(this, Arrays.asList(metrics))); + + LOGGER.info( + "class=ZookeeperMetricCollector||method=collectMetrics||clusterPhyId={}||startTime={}||costTime={}||msg=msg=collect finished.", + clusterPhyId, startTime, System.currentTimeMillis() - startTime + ); + } + + @Override + public VersionItemTypeEnum collectorType() { + return METRIC_ZOOKEEPER; + } +} diff --git a/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/sink/ZookeeperMetricESSender.java b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/sink/ZookeeperMetricESSender.java new file mode 100644 index 00000000..4f9dad53 --- /dev/null +++ b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/sink/ZookeeperMetricESSender.java @@ -0,0 +1,28 @@ +package com.xiaojukeji.know.streaming.km.collector.sink; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.bean.event.metric.ZookeeperMetricEvent; +import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ZookeeperMetricPO; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +import static com.xiaojukeji.know.streaming.km.common.constant.ESIndexConstant.ZOOKEEPER_INDEX; + +@Component +public class ZookeeperMetricESSender extends AbstractMetricESSender implements ApplicationListener { + protected static final ILog LOGGER = LogFactory.getLog("METRIC_LOGGER"); + + @PostConstruct + public void init(){ + LOGGER.info("class=ZookeeperMetricESSender||method=init||msg=init finished"); + } + + @Override + public void onApplicationEvent(ZookeeperMetricEvent event) { + send2es(ZOOKEEPER_INDEX, ConvertUtil.list2List(event.getZookeeperMetrics(), ZookeeperMetricPO.class)); + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/metrics/ZookeeperMetrics.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/metrics/ZookeeperMetrics.java new file mode 100644 index 00000000..823125b5 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/metrics/ZookeeperMetrics.java @@ -0,0 +1,28 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.metrics; + +import lombok.Data; +import lombok.ToString; + +/** + * @author zengqiao + * @date 20/6/17 + */ +@Data +@ToString +public class ZookeeperMetrics extends BaseMetrics { + public ZookeeperMetrics(Long clusterPhyId) { + super(clusterPhyId); + } + + public static ZookeeperMetrics initWithMetric(Long clusterPhyId, String metric, Float value) { + ZookeeperMetrics metrics = new ZookeeperMetrics(clusterPhyId); + metrics.setClusterPhyId( clusterPhyId ); + metrics.putMetric(metric, value); + return metrics; + } + + @Override + public String unique() { + return "ZK@" + clusterPhyId; + } +} \ No newline at end of file diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/param/metric/ZookeeperMetricParam.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/param/metric/ZookeeperMetricParam.java new file mode 100644 index 00000000..ef2b09c8 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/param/metric/ZookeeperMetricParam.java @@ -0,0 +1,47 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author didi + */ +@Data +@NoArgsConstructor +public class ZookeeperMetricParam extends MetricParam { + private Long clusterPhyId; + + private List> zkAddressList; + + private ZKConfig zkConfig; + + private String metricName; + + private Integer kafkaControllerId; + + public ZookeeperMetricParam(Long clusterPhyId, + List> zkAddressList, + ZKConfig zkConfig, + String metricName) { + this.clusterPhyId = clusterPhyId; + this.zkAddressList = zkAddressList; + this.zkConfig = zkConfig; + this.metricName = metricName; + } + + public ZookeeperMetricParam(Long clusterPhyId, + List> zkAddressList, + ZKConfig zkConfig, + Integer kafkaControllerId, + String metricName) { + this.clusterPhyId = clusterPhyId; + this.zkAddressList = zkAddressList; + this.zkConfig = zkConfig; + this.kafkaControllerId = kafkaControllerId; + this.metricName = metricName; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/version/VersionMetricControlItem.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/version/VersionMetricControlItem.java index c7409104..5c3f6506 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/version/VersionMetricControlItem.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/version/VersionMetricControlItem.java @@ -23,6 +23,8 @@ public class VersionMetricControlItem extends VersionControlItem{ public static final String CATEGORY_PERFORMANCE = "Performance"; public static final String CATEGORY_FLOW = "Flow"; + public static final String CATEGORY_CLIENT = "Client"; + /** * 指标单位名称,非指标的没有 */ diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/BaseMetricEvent.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/BaseMetricEvent.java index df1fe834..cfe5995a 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/BaseMetricEvent.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/BaseMetricEvent.java @@ -8,8 +8,6 @@ import org.springframework.context.ApplicationEvent; */ @Getter public class BaseMetricEvent extends ApplicationEvent { - - public BaseMetricEvent(Object source) { super( source ); } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/ZookeeperMetricEvent.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/ZookeeperMetricEvent.java new file mode 100644 index 00000000..19279d53 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/event/metric/ZookeeperMetricEvent.java @@ -0,0 +1,20 @@ +package com.xiaojukeji.know.streaming.km.common.bean.event.metric; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import lombok.Getter; + +import java.util.List; + +/** + * @author didi + */ +@Getter +public class ZookeeperMetricEvent extends BaseMetricEvent { + + private List zookeeperMetrics; + + public ZookeeperMetricEvent(Object source, List zookeeperMetrics) { + super( source ); + this.zookeeperMetrics = zookeeperMetrics; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/metrice/ZookeeperMetricPO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/metrice/ZookeeperMetricPO.java new file mode 100644 index 00000000..96921739 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/metrice/ZookeeperMetricPO.java @@ -0,0 +1,24 @@ +package com.xiaojukeji.know.streaming.km.common.bean.po.metrice; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import static com.xiaojukeji.know.streaming.km.common.utils.CommonUtils.monitorTimestamp2min; + +@Data +@NoArgsConstructor +public class ZookeeperMetricPO extends BaseMetricESPO { + public ZookeeperMetricPO(Long clusterPhyId){ + super(clusterPhyId); + } + + @Override + public String getKey() { + return "ZK@" + clusterPhyId + "@" + monitorTimestamp2min(timestamp); + } + + @Override + public String getRoutingValue() { + return String.valueOf(clusterPhyId); + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/metrics/line/MetricMultiLinesVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/metrics/line/MetricMultiLinesVO.java index a3874292..917769d2 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/metrics/line/MetricMultiLinesVO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/metrics/line/MetricMultiLinesVO.java @@ -1,16 +1,12 @@ package com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line; -import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; /** * @author didi @@ -26,19 +22,4 @@ public class MetricMultiLinesVO { @ApiModelProperty(value = "指标名称对应的指标线") private List metricLines; - - public List getMetricPoints(String resName) { - if (ValidateUtils.isNull(metricLines)) { - return new ArrayList<>(); - } - - List voList = metricLines.stream().filter(elem -> elem.getName().equals(resName)).collect(Collectors.toList()); - if (ValidateUtils.isEmptyList(voList)) { - return new ArrayList<>(); - } - - // 仅获取idx=0的指标 - return voList.get(0).getMetricPoints(); - } - } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESConstant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESConstant.java index af8bd2c3..1b8a7740 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESConstant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESConstant.java @@ -34,6 +34,8 @@ public class ESConstant { public static final String TOTAL = "total"; + public static final Integer DEFAULT_RETRY_TIME = 3; + private ESConstant() { } } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java index 0de516f7..64aef24f 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java @@ -644,4 +644,89 @@ public class ESIndexConstant { " \"aliases\" : { }\n" + " }"; + public final static String ZOOKEEPER_INDEX = "ks_kafka_zookeeper_metric"; + public final static String ZOOKEEPER_TEMPLATE = "{\n" + + " \"order\" : 10,\n" + + " \"index_patterns\" : [\n" + + " \"ks_kafka_zookeeper_metric*\"\n" + + " ],\n" + + " \"settings\" : {\n" + + " \"index\" : {\n" + + " \"number_of_shards\" : \"10\"\n" + + " }\n" + + " },\n" + + " \"mappings\" : {\n" + + " \"properties\" : {\n" + + " \"routingValue\" : {\n" + + " \"type\" : \"text\",\n" + + " \"fields\" : {\n" + + " \"keyword\" : {\n" + + " \"ignore_above\" : 256,\n" + + " \"type\" : \"keyword\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"clusterPhyId\" : {\n" + + " \"type\" : \"long\"\n" + + " },\n" + + " \"metrics\" : {\n" + + " \"properties\" : {\n" + + " \"AvgRequestLatency\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"MinRequestLatency\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"MaxRequestLatency\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"OutstandingRequests\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"NodeCount\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"WatchCount\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"NumAliveConnections\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"PacketsReceived\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"PacketsSent\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"EphemeralsCount\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"ApproximateDataSize\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"OpenFileDescriptorCount\" : {\n" + + " \"type\" : \"double\"\n" + + " },\n" + + " \"MaxFileDescriptorCount\" : {\n" + + " \"type\" : \"double\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"key\" : {\n" + + " \"type\" : \"text\",\n" + + " \"fields\" : {\n" + + " \"keyword\" : {\n" + + " \"ignore_above\" : 256,\n" + + " \"type\" : \"keyword\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"timestamp\" : {\n" + + " \"format\" : \"yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis\",\n" + + " \"type\" : \"date\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"aliases\" : { }\n" + + " }"; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/version/VersionItemTypeEnum.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/version/VersionItemTypeEnum.java index 15f13175..004dad6d 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/version/VersionItemTypeEnum.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/version/VersionItemTypeEnum.java @@ -9,7 +9,9 @@ public enum VersionItemTypeEnum { METRIC_GROUP(102, "group_metric"), METRIC_BROKER(103, "broker_metric"), METRIC_PARTITION(104, "partition_metric"), - METRIC_REPLICATION (105, "replication_metric"), + METRIC_REPLICATION(105, "replication_metric"), + + METRIC_ZOOKEEPER(110, "zookeeper_metric"), /** * 服务端查询 diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxAttribute.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxAttribute.java index cc7bfcb4..a9bea1c3 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxAttribute.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxAttribute.java @@ -22,6 +22,12 @@ public class JmxAttribute { public static final String PERCENTILE_99 = "99thPercentile"; + public static final String MAX = "Max"; + + public static final String MEAN = "Mean"; + + public static final String MIN = "Min"; + public static final String VALUE = "Value"; public static final String CONNECTION_COUNT = "connection-count"; diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxName.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxName.java index d2d1651e..db8b3197 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxName.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxName.java @@ -63,6 +63,12 @@ public class JmxName { /*********************************************************** cluster ***********************************************************/ public static final String JMX_CLUSTER_PARTITION_UNDER_REPLICATED = "kafka.cluster:type=Partition,name=UnderReplicated"; + /*********************************************************** zookeeper ***********************************************************/ + + public static final String JMX_ZK_REQUEST_LATENCY_MS = "kafka.server:type=ZooKeeperClientMetrics,name=ZooKeeperRequestLatencyMs"; + public static final String JMX_ZK_SYNC_CONNECTS_PER_SEC = "kafka.server:type=SessionExpireListener,name=ZooKeeperSyncConnectsPerSec"; + public static final String JMX_ZK_DISCONNECTORS_PER_SEC = "kafka.server:type=SessionExpireListener,name=ZooKeeperDisconnectsPerSec"; + private JmxName() { } } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java index fbede23c..7fc4f4f2 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java @@ -343,17 +343,9 @@ public class BrokerServiceImpl extends BaseVersionControlService implements Brok private Broker getStartTimeAndBuildBroker(Long clusterPhyId, Node newNode, JmxConfig jmxConfig) { try { - Object object = jmxDAO.getJmxValue( - clusterPhyId, - newNode.id(), - newNode.host(), - null, - jmxConfig, - new ObjectName("java.lang:type=Runtime"), - "StartTime" - ); + Long startTime = jmxDAO.getServerStartTime(clusterPhyId, newNode.host(), null, jmxConfig); - return Broker.buildFrom(clusterPhyId, newNode, object != null? (Long) object: null); + return Broker.buildFrom(clusterPhyId, newNode, startTime); } catch (Exception e) { log.error("class=BrokerServiceImpl||method=getStartTimeAndBuildBroker||clusterPhyId={}||brokerNode={}||jmxConfig={}||errMsg=exception!", clusterPhyId, newNode, jmxConfig, e); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ZookeeperMetricVersionItems.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ZookeeperMetricVersionItems.java new file mode 100644 index 00000000..9b0d4d2b --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/version/metrics/ZookeeperMetricVersionItems.java @@ -0,0 +1,141 @@ +package com.xiaojukeji.know.streaming.km.core.service.version.metrics; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionMetricControlItem; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +import static com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionMetricControlItem.*; +import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum.METRIC_ZOOKEEPER; +import static com.xiaojukeji.know.streaming.km.common.jmx.JmxAttribute.*; +import static com.xiaojukeji.know.streaming.km.common.jmx.JmxName.*; +import static com.xiaojukeji.know.streaming.km.core.service.zookeeper.impl.ZookeeperMetricServiceImpl.*; + +@Component +public class ZookeeperMetricVersionItems extends BaseMetricVersionMetric { + + /** + * 性能 + */ + public static final String ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY = "AvgRequestLatency"; + public static final String ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY = "MinRequestLatency"; + public static final String ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY = "MaxRequestLatency"; + public static final String ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS = "OutstandingRequests"; + public static final String ZOOKEEPER_METRIC_NODE_COUNT = "NodeCount"; + public static final String ZOOKEEPER_METRIC_WATCH_COUNT = "WatchCount"; + public static final String ZOOKEEPER_METRIC_NUM_ALIVE_CONNECTIONS = "NumAliveConnections"; + public static final String ZOOKEEPER_METRIC_PACKETS_RECEIVED = "PacketsReceived"; + public static final String ZOOKEEPER_METRIC_PACKETS_SENT = "PacketsSent"; + public static final String ZOOKEEPER_METRIC_EPHEMERALS_COUNT = "EphemeralsCount"; + public static final String ZOOKEEPER_METRIC_APPROXIMATE_DATA_SIZE = "ApproximateDataSize"; + public static final String ZOOKEEPER_METRIC_OPEN_FILE_DESCRIPTOR_COUNT = "OpenFileDescriptorCount"; + public static final String ZOOKEEPER_METRIC_MAX_FILE_DESCRIPTOR_COUNT = "MaxFileDescriptorCount"; + + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_DISCONNECTS_PER_SEC = "KafkaZKDisconnectsPerSec"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_SYNC_CONNECTS_PER_SEC = "KafkaZKSyncConnectsPerSec"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_99TH = "KafkaZKRequestLatencyMs_99thPercentile"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MAX = "KafkaZKRequestLatencyMs_Max"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MEAN = "KafkaZKRequestLatencyMs_Mean"; + public static final String ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MIN = "KafkaZKRequestLatencyMs_Min"; + + + public static final String ZOOKEEPER_METRIC_COLLECT_COST_TIME = Constant.COLLECT_METRICS_COST_TIME_METRICS_NAME; + + @Override + public int versionItemType() { + return METRIC_ZOOKEEPER.getCode(); + } + + @Override + public List init(){ + List items = new ArrayList<>(); + + // 性能指标 + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY).unit("ms").desc("平均响应延迟").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY).unit("ms").desc("最小响应延迟").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY).unit("ms").desc("最大响应延迟").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS).unit("个").desc("堆积请求数").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_NODE_COUNT).unit("个").desc("ZNode数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_WATCH_COUNT).unit("个").desc("Watch数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_NUM_ALIVE_CONNECTIONS).unit("个").desc("客户端连接数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_PACKETS_RECEIVED).unit("个").desc("接受包的数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_PACKETS_SENT).unit("个").desc("发送包的数量").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_EPHEMERALS_COUNT).unit("个").desc("临时节点数").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_APPROXIMATE_DATA_SIZE).unit("byte").desc("文件大小(近似值)").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_OPEN_FILE_DESCRIPTOR_COUNT).unit("个").desc("已打开的文件描述符数").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_MAX_FILE_DESCRIPTOR_COUNT).unit("个").desc("允许打开的最大文件描述符数").category(CATEGORY_PERFORMANCE) + .extendMethod(ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD)); + + // JMX指标 + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_99TH).unit("ms").desc("ZK请求99分位延迟").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_REQUEST_LATENCY_MS ).jmxAttribute(PERCENTILE_99))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MAX).unit("ms").desc("ZK请求最大延迟").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_REQUEST_LATENCY_MS ).jmxAttribute(MAX))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MIN).unit("ms").desc("ZK请求最小延迟").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_REQUEST_LATENCY_MS ).jmxAttribute(MIN))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_REQUEST_LATENCY_MEAN).unit("ms").desc("ZK请求平均延迟").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_REQUEST_LATENCY_MS ).jmxAttribute(MEAN))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_DISCONNECTS_PER_SEC).unit("个").desc("断开连接数").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_DISCONNECTORS_PER_SEC ).jmxAttribute(RATE_MIN_1))); + + items.add(buildAllVersionsItem() + .name(ZOOKEEPER_METRIC_KAFKA_ZK_SYNC_CONNECTS_PER_SEC).unit("个").desc("同步连接数").category(CATEGORY_CLIENT) + .extend( buildJMXMethodExtend( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX ) + .jmxObjectName( JMX_ZK_SYNC_CONNECTS_PER_SEC ).jmxAttribute(RATE_MIN_1))); + return items; + } +} + diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperMetricService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperMetricService.java new file mode 100644 index 00000000..2dc48851 --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperMetricService.java @@ -0,0 +1,21 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric.ZookeeperMetricParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line.MetricLineVO; + +import java.util.List; + +public interface ZookeeperMetricService { + /** + * ZK指标获取 + * @param param 参数,因为ZK 四字命令在使用时,是短连接,所以参数内容会复杂一些,后续可以考虑优化为长连接 + * @return + */ + Result collectMetricsFromZookeeper(ZookeeperMetricParam param); + Result batchCollectMetricsFromZookeeper(Long clusterPhyId, List metricNameList); + + Result> listMetricsFromES(Long clusterPhyId, MetricDTO dto); +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java new file mode 100644 index 00000000..dea1d877 --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java @@ -0,0 +1,281 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper.impl; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.VersionItemParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric.ZookeeperMetricParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionJmxInfo; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.ServerCmdData; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.MonitorCmdDataParser; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.ServerCmdDataParser; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line.MetricLineVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; +import com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemTypeEnum; +import com.xiaojukeji.know.streaming.km.common.exception.VCHandlerNotExistException; +import com.xiaojukeji.know.streaming.km.common.jmx.JmxConnectorWrap; +import com.xiaojukeji.know.streaming.km.common.utils.*; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.MonitorCmdData; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ZookeeperMetricPO; +import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; +import com.xiaojukeji.know.streaming.km.core.service.kafkacontroller.KafkaControllerService; +import com.xiaojukeji.know.streaming.km.core.service.version.BaseMetricService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperMetricService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import com.xiaojukeji.know.streaming.km.persistence.es.dao.ZookeeperMetricESDAO; +import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaJMXClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.management.ObjectName; +import java.util.*; +import java.util.stream.Collectors; + +import static com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus.*; +import static com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus.VC_JMX_CONNECT_ERROR; +import static com.xiaojukeji.know.streaming.km.core.service.version.metrics.ZookeeperMetricVersionItems.*; + + +@Service +public class ZookeeperMetricServiceImpl extends BaseMetricService implements ZookeeperMetricService { + private static final ILog LOGGER = LogFactory.getLog(ZookeeperMetricServiceImpl.class); + + public static final String ZOOKEEPER_METHOD_DO_NOTHING = "doNothing"; + public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD = "getMetricFromMonitorCmd"; + public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD = "getMetricFromServerCmd"; + public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX = "getMetricFromKafkaByJMX"; + + @Autowired + private ClusterPhyService clusterPhyService; + + @Autowired + private ZookeeperService zookeeperService; + + @Autowired + private ZookeeperMetricESDAO zookeeperMetricESDAO; + + @Autowired + private KafkaJMXClient kafkaJMXClient; + + @Autowired + private KafkaControllerService kafkaControllerService; + + @Override + protected VersionItemTypeEnum getVersionItemType() { + return VersionItemTypeEnum.METRIC_ZOOKEEPER; + } + + @Override + protected List listMetricPOFields(){ + return BeanUtil.listBeanFields(ZookeeperMetricPO.class); + } + + @Override + protected void initRegisterVCHandler(){ + registerVCHandler( ZOOKEEPER_METHOD_DO_NOTHING, this::doNothing); + registerVCHandler( ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD, this::getMetricFromMonitorCmd); + registerVCHandler( ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD, this::getMetricFromServerCmd); + registerVCHandler( ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX, this::getMetricFromKafkaByJMX); + } + + @Override + public Result collectMetricsFromZookeeper(ZookeeperMetricParam param) { + try { + return (Result)doVCHandler(param.getClusterPhyId(), param.getMetricName(), param); + } catch (VCHandlerNotExistException e) { + return Result.buildFailure(VC_HANDLE_NOT_EXIST); + } + } + + @Override + public Result batchCollectMetricsFromZookeeper(Long clusterPhyId, List metricNameList) { + ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(clusterPhyId); + if (null == clusterPhy) { + return Result.buildFromRSAndMsg(ResultStatus.CLUSTER_NOT_EXIST, MsgConstant.getClusterPhyNotExist(clusterPhyId)); + } + + List aliveZKList = zookeeperService.listFromDBByCluster(clusterPhyId).stream() + .filter(elem -> Constant.ALIVE.equals(elem.getStatus())) + .collect(Collectors.toList()); + + if (ValidateUtils.isEmptyList(aliveZKList)) { + // 没有指标可以获取 + return Result.buildSuc(new ZookeeperMetrics(clusterPhyId)); + } + + // 构造参数 + ZookeeperMetricParam param = new ZookeeperMetricParam( + clusterPhyId, + aliveZKList.stream().map(elem -> new Tuple(elem.getHost(), elem.getPort())).collect(Collectors.toList()), + ConvertUtil.str2ObjByJson(clusterPhy.getZkProperties(), ZKConfig.class), + null + ); + + ZookeeperMetrics metrics = new ZookeeperMetrics(clusterPhyId); + for(String metricName : metricNameList) { + try { + if(metrics.getMetrics().containsKey(metricName)) { + continue; + } + param.setMetricName(metricName); + + Result ret = this.collectMetricsFromZookeeper(param); + if(null == ret || ret.failed() || null == ret.getData()){ + continue; + } + + metrics.putMetric(ret.getData().getMetrics()); + } catch (Exception e){ + LOGGER.error( + "class=ZookeeperMetricServiceImpl||method=collectMetricsFromZookeeper||clusterPhyId={}||metricName={}||errMsg=exception!", + clusterPhyId, metricName, e + ); + } + } + + return Result.buildSuc(metrics); + } + + @Override + public Result> listMetricsFromES(Long clusterPhyId, MetricDTO dto) { + Map> pointVOMap = zookeeperMetricESDAO.listMetricsByClusterPhyId( + clusterPhyId, + dto.getMetricsNames(), + dto.getAggType(), + dto.getStartTime(), + dto.getEndTime() + ); + + // 格式转化 + List voList = new ArrayList<>(); + pointVOMap.entrySet().stream().forEach(entry -> + voList.add(new MetricLineVO(String.valueOf(clusterPhyId), entry.getKey(), entry.getValue())) + ); + return Result.buildSuc(voList); + } + + + /**************************************************** private method ****************************************************/ + + private Result getMetricFromServerCmd(VersionItemParam metricParam) { + ZookeeperMetricParam param = (ZookeeperMetricParam)metricParam; + + Result rz = null; + for (Tuple hostPort: param.getZkAddressList()) { + Result cmdDataResult = FourLetterWordUtil.executeFourLetterCmd( + param.getClusterPhyId(), + hostPort.getV1(), + hostPort.getV2(), + param.getZkConfig() != null ? param.getZkConfig().getOpenSecure(): false, + param.getZkConfig() != null ? param.getZkConfig().getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, + new ServerCmdDataParser() + ); + + if (cmdDataResult.failed()) { + rz = Result.buildFromIgnoreData(cmdDataResult); + continue; + } + + ServerCmdData cmdData = cmdDataResult.getData(); + + ZookeeperMetrics metrics = new ZookeeperMetrics(param.getClusterPhyId()); + metrics.putMetric(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY, cmdData.getZkAvgLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY, cmdData.getZkMinLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY, cmdData.getZkMaxLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS, cmdData.getZkOutstandingRequests().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_NODE_COUNT, cmdData.getZkZnodeCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_NUM_ALIVE_CONNECTIONS, cmdData.getZkNumAliveConnections().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_PACKETS_RECEIVED, cmdData.getZkPacketsReceived().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_PACKETS_SENT, cmdData.getZkPacketsSent().floatValue()); + + return Result.buildSuc(metrics); + } + + return rz != null? rz: Result.buildSuc(new ZookeeperMetrics(param.getClusterPhyId())); + } + + private Result getMetricFromMonitorCmd(VersionItemParam metricParam) { + ZookeeperMetricParam param = (ZookeeperMetricParam)metricParam; + + Result rz = null; + for (Tuple hostPort: param.getZkAddressList()) { + Result cmdDataResult = FourLetterWordUtil.executeFourLetterCmd( + param.getClusterPhyId(), + hostPort.getV1(), + hostPort.getV2(), + param.getZkConfig() != null ? param.getZkConfig().getOpenSecure(): false, + param.getZkConfig() != null ? param.getZkConfig().getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, + new MonitorCmdDataParser() + ); + + if (cmdDataResult.failed()) { + rz = Result.buildFromIgnoreData(cmdDataResult); + continue; + } + + MonitorCmdData cmdData = cmdDataResult.getData(); + + ZookeeperMetrics metrics = new ZookeeperMetrics(param.getClusterPhyId()); + metrics.putMetric(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY, cmdData.getZkAvgLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY, cmdData.getZkMinLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY, cmdData.getZkMaxLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS, cmdData.getZkOutstandingRequests().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_NODE_COUNT, cmdData.getZkZnodeCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_WATCH_COUNT, cmdData.getZkWatchCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_NUM_ALIVE_CONNECTIONS, cmdData.getZkNumAliveConnections().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_PACKETS_RECEIVED, cmdData.getZkPacketsReceived().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_PACKETS_SENT, cmdData.getZkPacketsSent().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_EPHEMERALS_COUNT, cmdData.getZkEphemeralsCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_APPROXIMATE_DATA_SIZE, cmdData.getZkApproximateDataSize().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_OPEN_FILE_DESCRIPTOR_COUNT, cmdData.getZkOpenFileDescriptorCount().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_MAX_FILE_DESCRIPTOR_COUNT, cmdData.getZkMaxFileDescriptorCount().floatValue()); + + return Result.buildSuc(metrics); + } + + return rz != null? rz: Result.buildSuc(new ZookeeperMetrics(param.getClusterPhyId())); + } + + private Result doNothing(VersionItemParam metricParam) { + ZookeeperMetricParam param = (ZookeeperMetricParam)metricParam; + return Result.buildSuc(new ZookeeperMetrics(param.getClusterPhyId())); + } + + private Result getMetricFromKafkaByJMX(VersionItemParam metricParam) { + ZookeeperMetricParam param = (ZookeeperMetricParam)metricParam; + + String metricName = param.getMetricName(); + Long clusterPhyId = param.getClusterPhyId(); + Integer kafkaControllerId = param.getKafkaControllerId(); + + //1、获取jmx的属性信息 + VersionJmxInfo jmxInfo = getJMXInfo(clusterPhyId, metricName); + if(null == jmxInfo) { + return Result.buildFailure(VC_ITEM_JMX_NOT_EXIST); + } + + //2、获取jmx连接 + JmxConnectorWrap jmxConnectorWrap = kafkaJMXClient.getClientWithCheck(clusterPhyId, kafkaControllerId); + if (ValidateUtils.isNull(jmxConnectorWrap)) { + return Result.buildFailure(VC_JMX_INIT_ERROR); + } + + try { + //2、获取jmx指标 + String value = jmxConnectorWrap.getAttribute(new ObjectName(jmxInfo.getJmxObjectName()), jmxInfo.getJmxAttribute()).toString(); + + return Result.buildSuc(ZookeeperMetrics.initWithMetric(clusterPhyId, metricName, Float.valueOf(value))); + } catch (Exception e) { + return Result.buildFailure(VC_JMX_CONNECT_ERROR); + } + } +} diff --git a/km-dist/init/template/ks_kafka_zookeeper_metric b/km-dist/init/template/ks_kafka_zookeeper_metric new file mode 100644 index 00000000..abb54a61 --- /dev/null +++ b/km-dist/init/template/ks_kafka_zookeeper_metric @@ -0,0 +1,85 @@ +PUT _template/ks_kafka_zookeeper_metric +{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + } \ No newline at end of file diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BaseMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BaseMetricESDAO.java index a6615fbc..faeb64cb 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BaseMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BaseMetricESDAO.java @@ -40,8 +40,7 @@ public class BaseMetricESDAO extends BaseESDAO { /** * 不同维度 kafka 监控数据 */ - private static Map ariusStatsEsDaoMap = Maps - .newConcurrentMap(); + private static Map ariusStatsEsDaoMap = Maps.newConcurrentMap(); /** * 检查 es 索引是否存在,不存在则创建索引 diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ZookeeperMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ZookeeperMetricESDAO.java new file mode 100644 index 00000000..8b391a3a --- /dev/null +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ZookeeperMetricESDAO.java @@ -0,0 +1,106 @@ +package com.xiaojukeji.know.streaming.km.persistence.es.dao; + +import com.didiglobal.logi.elasticsearch.client.response.query.query.ESQueryResponse; +import com.didiglobal.logi.elasticsearch.client.response.query.query.aggs.ESAggr; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; +import com.xiaojukeji.know.streaming.km.common.constant.ESConstant; +import com.xiaojukeji.know.streaming.km.common.utils.MetricsUtils; +import com.xiaojukeji.know.streaming.km.persistence.es.dsls.DslsConstant; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.xiaojukeji.know.streaming.km.common.constant.ESConstant.*; +import static com.xiaojukeji.know.streaming.km.common.constant.ESIndexConstant.ZOOKEEPER_INDEX; +import static com.xiaojukeji.know.streaming.km.common.constant.ESIndexConstant.ZOOKEEPER_TEMPLATE; + +@Component +public class ZookeeperMetricESDAO extends BaseMetricESDAO { + + @PostConstruct + public void init() { + super.indexName = ZOOKEEPER_INDEX; + super.indexTemplate = ZOOKEEPER_TEMPLATE; + checkCurrentDayIndexExist(); + BaseMetricESDAO.register(indexName, this); + } + + /** + * 获取指定集群,指定指标,一段时间内的值 + */ + public Map> listMetricsByClusterPhyId(Long clusterPhyId, + List metricNameList, + String aggType, + Long startTime, + Long endTime) { + //1、获取需要查下的索引 + String realIndex = realIndex(startTime, endTime); + + //2、根据查询的时间区间大小来确定指标点的聚合区间大小 + String interval = MetricsUtils.getInterval(endTime - startTime); + + //3、构造agg查询条件 + String aggDsl = buildAggsDSL(metricNameList, aggType); + + //4、构造dsl查询条件,开始查询 + try { + String dsl = dslLoaderUtil.getFormatDslByFileName( + DslsConstant.GET_ZOOKEEPER_AGG_LIST_METRICS, clusterPhyId, startTime, endTime, interval, aggDsl); + + return esOpClient.performRequestWithRouting( + String.valueOf(clusterPhyId), + realIndex, + dsl, + s -> handleListESQueryResponse(s, metricNameList, aggType), + ESConstant.DEFAULT_RETRY_TIME + ); + } catch (Exception e){ + LOGGER.error("class=ZookeeperMetricESDAO||method=listMetricsByClusterPhyId||clusterPhyId={}||errMsg=exception!", + clusterPhyId, e + ); + } + + return new HashMap<>(); + } + + /**************************************************** private method ****************************************************/ + + private Map> handleListESQueryResponse(ESQueryResponse response, List metrics, String aggType){ + Map esAggrMap = checkBucketsAndHitsOfResponseAggs(response); + if(null == esAggrMap) { + return new HashMap<>(); + } + + Map> metricMap = new HashMap<>(); + for(String metric : metrics){ + List metricPoints = new ArrayList<>(); + + esAggrMap.get(HIST).getBucketList().forEach( esBucket -> { + try { + if (null != esBucket.getUnusedMap().get(KEY)) { + Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); + String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + + MetricPointVO metricPoint = new MetricPointVO(); + metricPoint.setAggType(aggType); + metricPoint.setTimeStamp(timestamp); + metricPoint.setValue(value); + metricPoint.setName(metric); + + metricPoints.add(metricPoint); + } + }catch (Exception e){ + LOGGER.error("method=handleESQueryResponse||metric={}||errMsg=exception!", metric, e); + } + } ); + + metricMap.put(metric, optimizeMetricPoints(metricPoints)); + } + + return metricMap; + } +} diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java index 3f158f36..94a8698e 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java @@ -80,4 +80,6 @@ public class DslsConstant { public static final String COUNT_GROUP_NOT_METRIC_VALUE = "GroupMetricESDAO/countGroupNotMetricValue"; + /**************************************************** Zookeeper ****************************************************/ + public static final String GET_ZOOKEEPER_AGG_LIST_METRICS = "ZookeeperMetricESDAO/getAggListZookeeperMetrics"; } diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/JmxDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/JmxDAO.java index a3747c0a..017bcf04 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/JmxDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/JmxDAO.java @@ -12,5 +12,7 @@ import javax.management.ObjectName; public interface JmxDAO { Object getJmxValue(String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute); - Object getJmxValue(Long clusterPhyId, Integer brokerId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute); + Object getJmxValue(Long clusterPhyId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute); + + Long getServerStartTime(Long clusterPhyId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig); } diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/impl/JmxDAOImpl.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/impl/JmxDAOImpl.java index ec8349cc..77eb3252 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/impl/JmxDAOImpl.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/jmx/impl/JmxDAOImpl.java @@ -19,24 +19,28 @@ public class JmxDAOImpl implements JmxDAO { @Override public Object getJmxValue(String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute) { - return this.getJmxValue(null, null, jmxHost, jmxPort, jmxConfig, objectName, attribute); + return this.getJmxValue(null, jmxHost, jmxPort, jmxConfig, objectName, attribute); } @Override - public Object getJmxValue(Long clusterPhyId, Integer brokerId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute) { + public Object getJmxValue(Long clusterPhyId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig, ObjectName objectName, String attribute) { JmxConnectorWrap jmxConnectorWrap = null; try { - jmxConnectorWrap = new JmxConnectorWrap(clusterPhyId, brokerId, null, jmxHost, jmxPort, jmxConfig); + jmxConnectorWrap = new JmxConnectorWrap(clusterPhyId, null, null, jmxHost, jmxPort, jmxConfig); if (!jmxConnectorWrap.checkJmxConnectionAndInitIfNeed()) { - log.error("method=getJmxValue||clusterPhyId={}||brokerId={}||jmxHost={}||jmxPort={}||jmxConfig={}||errMgs=create jmx client failed", - clusterPhyId, brokerId, jmxHost, jmxPort, jmxConfig); + log.error( + "method=getJmxValue||clusterPhyId={}||jmxHost={}||jmxPort={}||jmxConfig={}||errMgs=create jmx client failed", + clusterPhyId, jmxHost, jmxPort, jmxConfig + ); return null; } return jmxConnectorWrap.getAttribute(objectName, attribute); } catch (Exception e) { - log.error("method=getJmxValue||clusterPhyId={}||brokerId={}||jmxHost={}||jmxPort={}||jmxConfig={}||objectName={}||attribute={}||msg=get attribute failed||errMsg={}", - clusterPhyId, brokerId, jmxHost, jmxPort, jmxConfig, objectName, attribute, e); + log.error( + "method=getJmxValue||clusterPhyId={}||jmxHost={}||jmxPort={}||jmxConfig={}||objectName={}||attribute={}||msg=get attribute failed||errMsg=exception!", + clusterPhyId, jmxHost, jmxPort, jmxConfig, objectName, attribute, e + ); } finally { if (jmxConnectorWrap != null) { jmxConnectorWrap.close(); @@ -45,4 +49,27 @@ public class JmxDAOImpl implements JmxDAO { return null; } + + @Override + public Long getServerStartTime(Long clusterPhyId, String jmxHost, Integer jmxPort, JmxConfig jmxConfig) { + try { + Object object = this.getJmxValue( + clusterPhyId, + jmxHost, + jmxPort, + jmxConfig, + new ObjectName("java.lang:type=Runtime"), + "StartTime" + ); + + return object == null? null: (Long) object; + } catch (Exception e) { + log.error( + "class=JmxDAOImpl||method=getServerStartTime||clusterPhyId={}||jmxHost={}||jmxPort={}||jmxConfig={}||errMsg=exception!", + clusterPhyId, jmxHost, jmxPort, jmxConfig, e + ); + } + + return null; + } } diff --git a/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics b/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics new file mode 100644 index 00000000..c05c221d --- /dev/null +++ b/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics @@ -0,0 +1,44 @@ +{ + "size": 0, + "query": { + "bool": { + "must": [ + { + "term": { + "clusterPhyId": { + "value": %d + } + } + }, + { + "term": { + "brokerId": { + "value": %d + } + } + }, + { + "range": { + "timestamp": { + "gte": %d, + "lte": %d + } + } + } + ] + } + }, + "aggs": { + "hist": { + "date_histogram": { + "field": "timestamp", + "fixed_interval": "%s", + "time_zone": "Asia/Shanghai", + "min_doc_count": 0 + }, + "aggs": { + %s + } + } + } +} \ No newline at end of file diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ZookeeperMetricCollectorTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ZookeeperMetricCollectorTask.java new file mode 100644 index 00000000..f533a30a --- /dev/null +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ZookeeperMetricCollectorTask.java @@ -0,0 +1,33 @@ +package com.xiaojukeji.know.streaming.km.task.metrics; + +import com.didiglobal.logi.job.annotation.Task; +import com.didiglobal.logi.job.common.TaskResult; +import com.didiglobal.logi.job.core.consensual.ConsensualEnum; +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.collector.metric.ZookeeperMetricCollector; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author didi + */ +@Task(name = "ZookeeperMetricCollectorTask", + description = "Zookeeper指标采集任务", + cron = "0 0/1 * * * ? *", + autoRegister = true, + consensual = ConsensualEnum.BROADCAST, + timeout = 2 * 60) +public class ZookeeperMetricCollectorTask extends AbstractAsyncMetricsDispatchTask { + private static final ILog log = LogFactory.getLog(ZookeeperMetricCollectorTask.class); + + @Autowired + private ZookeeperMetricCollector zookeeperMetricCollector; + + @Override + public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception { + zookeeperMetricCollector.collectMetrics(clusterPhy); + + return TaskResult.SUCCESS; + } +} From bc32c71048b74d8563b247c53a759cffc8a6af46 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Sat, 8 Oct 2022 15:46:18 +0800 Subject: [PATCH 080/145] =?UTF-8?q?ZK-=E5=A2=9E=E5=8A=A0ZK=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../biz/cluster/ClusterZookeepersManager.java | 19 +++ .../impl/ClusterZookeepersManagerImpl.java | 137 ++++++++++++++++++ .../cluster/ClusterZookeepersOverviewDTO.java | 13 ++ .../common/bean/entity/zookeeper/Znode.java | 19 +++ .../ClusterZookeepersOverviewVO.java | 26 ++++ .../zookeeper/ClusterZookeepersStateVO.java | 47 ++++++ .../common/bean/vo/zookeeper/ZnodeStatVO.java | 44 ++++++ .../km/common/bean/vo/zookeeper/ZnodeVO.java | 22 +++ .../km/common/converter/ZnodeConverter.java | 19 +++ .../core/service/zookeeper/ZnodeService.java | 13 ++ .../zookeeper/impl/ZnodeServiceImpl.java | 81 +++++++++++ .../cluster/ClusterZookeepersController.java | 63 ++++++++ .../api/v3/zk/ZookeeperMetricsController.java | 52 +++++++ 13 files changed, 555 insertions(+) create mode 100644 km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterZookeepersManager.java create mode 100644 km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterZookeepersManagerImpl.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterZookeepersOverviewDTO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/Znode.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersStateVO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeStatVO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeVO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/ZnodeConverter.java create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZnodeService.java create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZnodeServiceImpl.java create mode 100644 km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterZookeepersController.java create mode 100644 km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/zk/ZookeeperMetricsController.java diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterZookeepersManager.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterZookeepersManager.java new file mode 100644 index 00000000..8219cd7e --- /dev/null +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterZookeepersManager.java @@ -0,0 +1,19 @@ +package com.xiaojukeji.know.streaming.km.biz.cluster; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterZookeepersOverviewDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersOverviewVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersStateVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ZnodeVO; + +/** + * 多集群总体状态 + */ +public interface ClusterZookeepersManager { + Result getClusterPhyZookeepersState(Long clusterPhyId); + + PaginationResult getClusterPhyZookeepersOverview(Long clusterPhyId, ClusterZookeepersOverviewDTO dto); + + Result getZnodeVO(Long clusterPhyId, String path); +} diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterZookeepersManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterZookeepersManagerImpl.java new file mode 100644 index 00000000..b285cac9 --- /dev/null +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterZookeepersManagerImpl.java @@ -0,0 +1,137 @@ +package com.xiaojukeji.know.streaming.km.biz.cluster.impl; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.biz.cluster.ClusterZookeepersManager; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterZookeepersOverviewDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.ZKConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric.ZookeeperMetricParam; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.Znode; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersOverviewVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersStateVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ZnodeVO; +import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; +import com.xiaojukeji.know.streaming.km.common.enums.zookeeper.ZKRoleEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.utils.PaginationUtil; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; +import com.xiaojukeji.know.streaming.km.core.service.version.metrics.ZookeeperMetricVersionItems; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZnodeService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperMetricService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + + +@Service +public class ClusterZookeepersManagerImpl implements ClusterZookeepersManager { + private static final ILog LOGGER = LogFactory.getLog(ClusterZookeepersManagerImpl.class); + + @Autowired + private ClusterPhyService clusterPhyService; + + @Autowired + private ZookeeperService zookeeperService; + + @Autowired + private ZookeeperMetricService zookeeperMetricService; + + @Autowired + private ZnodeService znodeService; + + @Override + public Result getClusterPhyZookeepersState(Long clusterPhyId) { + ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(clusterPhyId); + if (clusterPhy == null) { + return Result.buildFromRSAndMsg(ResultStatus.CLUSTER_NOT_EXIST, MsgConstant.getClusterPhyNotExist(clusterPhyId)); + } + +// // TODO +// private Integer healthState; +// private Integer healthCheckPassed; +// private Integer healthCheckTotal; + + List infoList = zookeeperService.listFromDBByCluster(clusterPhyId); + + ClusterZookeepersStateVO vo = new ClusterZookeepersStateVO(); + vo.setTotalServerCount(infoList.size()); + vo.setAliveFollowerCount(0); + vo.setTotalFollowerCount(0); + vo.setAliveObserverCount(0); + vo.setTotalObserverCount(0); + vo.setAliveServerCount(0); + for (ZookeeperInfo info: infoList) { + if (info.getRole().equals(ZKRoleEnum.LEADER.getRole())) { + vo.setLeaderNode(info.getHost()); + } + + if (info.getRole().equals(ZKRoleEnum.FOLLOWER.getRole())) { + vo.setTotalFollowerCount(vo.getTotalFollowerCount() + 1); + vo.setAliveFollowerCount(info.alive()? vo.getAliveFollowerCount() + 1: vo.getAliveFollowerCount()); + } + + if (info.getRole().equals(ZKRoleEnum.OBSERVER.getRole())) { + vo.setTotalObserverCount(vo.getTotalObserverCount() + 1); + vo.setAliveObserverCount(info.alive()? vo.getAliveObserverCount() + 1: vo.getAliveObserverCount()); + } + + if (info.alive()) { + vo.setAliveServerCount(vo.getAliveServerCount() + 1); + } + } + + Result metricsResult = zookeeperMetricService.collectMetricsFromZookeeper(new ZookeeperMetricParam( + clusterPhyId, + infoList.stream().filter(elem -> elem.alive()).map(item -> new Tuple(item.getHost(), item.getPort())).collect(Collectors.toList()), + ConvertUtil.str2ObjByJson(clusterPhy.getZkProperties(), ZKConfig.class), + ZookeeperMetricVersionItems.ZOOKEEPER_METRIC_WATCH_COUNT + )); + if (metricsResult.failed()) { + LOGGER.error( + "class=ClusterZookeepersManagerImpl||method=getClusterPhyZookeepersState||clusterPhyId={}||errMsg={}", + clusterPhyId, metricsResult.getMessage() + ); + return Result.buildSuc(vo); + } + Float watchCount = metricsResult.getData().getMetric(ZookeeperMetricVersionItems.ZOOKEEPER_METRIC_WATCH_COUNT); + vo.setWatchCount(watchCount != null? watchCount.intValue(): null); + + return Result.buildSuc(vo); + } + + @Override + public PaginationResult getClusterPhyZookeepersOverview(Long clusterPhyId, ClusterZookeepersOverviewDTO dto) { + //获取集群zookeeper列表 + List clusterZookeepersOverviewVOList = ConvertUtil.list2List(zookeeperService.listFromDBByCluster(clusterPhyId), ClusterZookeepersOverviewVO.class); + + //搜索 + clusterZookeepersOverviewVOList = PaginationUtil.pageByFuzzyFilter(clusterZookeepersOverviewVOList, dto.getSearchKeywords(), Arrays.asList("host")); + + //分页 + PaginationResult paginationResult = PaginationUtil.pageBySubData(clusterZookeepersOverviewVOList, dto); + + return paginationResult; + } + + @Override + public Result getZnodeVO(Long clusterPhyId, String path) { + Result result = znodeService.getZnode(clusterPhyId, path); + if (result.failed()) { + return Result.buildFromIgnoreData(result); + } + return Result.buildSuc(ConvertUtil.obj2ObjByJSON(result.getData(), ZnodeVO.class)); + } + + /**************************************************** private method ****************************************************/ + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterZookeepersOverviewDTO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterZookeepersOverviewDTO.java new file mode 100644 index 00000000..2b3a6e9d --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterZookeepersOverviewDTO.java @@ -0,0 +1,13 @@ +package com.xiaojukeji.know.streaming.km.common.bean.dto.cluster; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; +import lombok.Data; + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +public class ClusterZookeepersOverviewDTO extends PaginationBaseDTO { + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/Znode.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/Znode.java new file mode 100644 index 00000000..0bcb56d2 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/Znode.java @@ -0,0 +1,19 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper; + + +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.apache.zookeeper.data.Stat; + +@Data +public class Znode { + @ApiModelProperty(value = "节点名称", example = "broker") + private String name; + + @ApiModelProperty(value = "节点数据", example = "saassad") + private String data; + + @ApiModelProperty(value = "节点属性", example = "") + private Stat stat; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java new file mode 100644 index 00000000..960b5d5a --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java @@ -0,0 +1,26 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +@ApiModel(description = "Zookeeper信息概览") +public class ClusterZookeepersOverviewVO { + @ApiModelProperty(value = "主机ip", example = "121.0.0.1") + private String host; + + @ApiModelProperty(value = "端口号", example = "2416") + private Integer port; + + @ApiModelProperty(value = "版本", example = "1.1.2") + private String version; + + @ApiModelProperty(value = "角色", example = "Leader") + private String role; + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersStateVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersStateVO.java new file mode 100644 index 00000000..ceb2041f --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersStateVO.java @@ -0,0 +1,47 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +@ApiModel(description = "ZK状态信息") +public class ClusterZookeepersStateVO { + @ApiModelProperty(value = "健康检查状态", example = "1") + private Integer healthState; + + @ApiModelProperty(value = "健康检查通过数", example = "1") + private Integer healthCheckPassed; + + @ApiModelProperty(value = "健康检查总数", example = "1") + private Integer healthCheckTotal; + + @ApiModelProperty(value = "ZK的Leader机器", example = "127.0.0.1") + private String leaderNode; + + @ApiModelProperty(value = "Watch数", example = "123456") + private Integer watchCount; + + @ApiModelProperty(value = "节点存活数", example = "8") + private Integer aliveServerCount; + + @ApiModelProperty(value = "总节点数", example = "10") + private Integer totalServerCount; + + @ApiModelProperty(value = "Follower角色存活数", example = "8") + private Integer aliveFollowerCount; + + @ApiModelProperty(value = "Follower角色总数", example = "10") + private Integer totalFollowerCount; + + @ApiModelProperty(value = "Observer角色存活数", example = "3") + private Integer aliveObserverCount; + + @ApiModelProperty(value = "Observer角色总数", example = "3") + private Integer totalObserverCount; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeStatVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeStatVO.java new file mode 100644 index 00000000..c5cd0aa9 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeStatVO.java @@ -0,0 +1,44 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +public class ZnodeStatVO { + @ApiModelProperty(value = "节点被创建时的事物的ID", example = "0x1f09") + private Long czxid; + + @ApiModelProperty(value = "创建时间", example = "Sat Mar 16 15:38:34 CST 2019") + private Long ctime; + + @ApiModelProperty(value = "节点最后一次被修改时的事物的ID", example = "0x1f09") + private Long mzxid; + + @ApiModelProperty(value = "最后一次修改时间", example = "Sat Mar 16 15:38:34 CST 2019") + private Long mtime; + + @ApiModelProperty(value = "子节点列表最近一次呗修改的事物ID", example = "0x31") + private Long pzxid; + + @ApiModelProperty(value = "子节点版本号", example = "0") + private Integer cversion; + + @ApiModelProperty(value = "数据版本号", example = "0") + private Integer version; + + @ApiModelProperty(value = "ACL版本号", example = "0") + private Integer aversion; + + @ApiModelProperty(value = "创建临时节点的事物ID,持久节点事物为0", example = "0") + private Long ephemeralOwner; + + @ApiModelProperty(value = "数据长度,每个节点都可保存数据", example = "22") + private Integer dataLength; + + @ApiModelProperty(value = "子节点的个数", example = "6") + private Integer numChildren; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeVO.java new file mode 100644 index 00000000..b00a5ff7 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ZnodeVO.java @@ -0,0 +1,22 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author wyc + * @date 2022/9/23 + */ +@Data +public class ZnodeVO { + + @ApiModelProperty(value = "节点名称", example = "broker") + private String name; + + @ApiModelProperty(value = "节点数据", example = "saassad") + private String data; + + @ApiModelProperty(value = "节点属性", example = "") + private ZnodeStatVO stat; + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/ZnodeConverter.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/ZnodeConverter.java new file mode 100644 index 00000000..9b197358 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/ZnodeConverter.java @@ -0,0 +1,19 @@ +package com.xiaojukeji.know.streaming.km.common.converter; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.Znode; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import org.apache.zookeeper.data.Stat; + +public class ZnodeConverter { + ZnodeConverter(){ + + } + + public static Znode convert2Znode(Tuple dataAndStat, String path) { + Znode znode = new Znode(); + znode.setStat(dataAndStat.getV2()); + znode.setData(dataAndStat.getV1() == null ? null : new String(dataAndStat.getV1())); + znode.setName(path.substring(path.lastIndexOf('/') + 1)); + return znode; + } +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZnodeService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZnodeService.java new file mode 100644 index 00000000..43e7744d --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZnodeService.java @@ -0,0 +1,13 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.Znode; + +import java.util.List; + +public interface ZnodeService { + + Result> listZnodeChildren(Long clusterPhyId, String path, String keyword); + + Result getZnode(Long clusterPhyId, String path); +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZnodeServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZnodeServiceImpl.java new file mode 100644 index 00000000..9b9a70ef --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZnodeServiceImpl.java @@ -0,0 +1,81 @@ +package com.xiaojukeji.know.streaming.km.core.service.zookeeper.impl; + +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.Znode; +import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; +import com.xiaojukeji.know.streaming.km.common.converter.ZnodeConverter; +import com.xiaojukeji.know.streaming.km.common.exception.NotExistException; +import com.xiaojukeji.know.streaming.km.common.utils.Tuple; +import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZnodeService; +import com.xiaojukeji.know.streaming.km.persistence.kafka.zookeeper.service.KafkaZKDAO; +import org.apache.zookeeper.data.Stat; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import java.util.List; +import java.util.stream.Collectors; + + +@Service +public class ZnodeServiceImpl implements ZnodeService { + private static final ILog LOGGER = LogFactory.getLog(ZnodeServiceImpl.class); + + @Autowired + private KafkaZKDAO kafkaZKDAO; + + @Autowired + private ClusterPhyService clusterPhyService; + + + + @Override + public Result> listZnodeChildren(Long clusterPhyId, String path, String keyword) { + ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(clusterPhyId); + if (clusterPhy == null) { + return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getClusterPhyNotExist(clusterPhyId)); + } + + List children; + try { + children = kafkaZKDAO.getChildren(clusterPhyId, path, false); + } catch (NotExistException e) { + LOGGER.error("class=ZnodeServiceImpl||method=listZnodeChildren||clusterPhyId={}||errMsg={}", clusterPhyId, "create ZK client create failed"); + return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, "ZK客户端创建失败"); + } catch (Exception e) { + LOGGER.error("class=ZnodeServiceImpl||method=listZnodeChildren||clusterPhyId={}||errMsg={}", clusterPhyId, "ZK operate failed"); + return Result.buildFromRSAndMsg(ResultStatus.ZK_OPERATE_FAILED, "ZK操作失败"); + } + + //关键字搜索 + if (keyword != null) { + children = children.stream().filter(elem -> elem.contains(keyword)).collect(Collectors.toList()); + } + return Result.buildSuc(children); + } + + @Override + public Result getZnode(Long clusterPhyId, String path) { + ClusterPhy clusterPhy = clusterPhyService.getClusterByCluster(clusterPhyId); + if (clusterPhy == null) { + return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getClusterPhyNotExist(clusterPhyId)); + } + + //获取zookeeper上的原始数据 + Tuple dataAndStat; + try { + dataAndStat = kafkaZKDAO.getDataAndStat(clusterPhyId, path); + } catch (NotExistException e) { + LOGGER.error("class=ZnodeServiceImpl||method=getZnode||clusterPhyId={}||errMsg={}", clusterPhyId, "create ZK client create failed"); + return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, "ZK客户端创建失败"); + } catch (Exception e) { + LOGGER.error("class=ZnodeServiceImpl||method=getZnode||clusterPhyId={}||errMsg={}", clusterPhyId, "ZK operate failed"); + return Result.buildFromRSAndMsg(ResultStatus.ZK_OPERATE_FAILED, "ZK操作失败"); + } + + return Result.buildSuc(ZnodeConverter.convert2Znode(dataAndStat, path)); + } +} diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterZookeepersController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterZookeepersController.java new file mode 100644 index 00000000..99faa832 --- /dev/null +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterZookeepersController.java @@ -0,0 +1,63 @@ +package com.xiaojukeji.know.streaming.km.rest.api.v3.cluster; + +import com.xiaojukeji.know.streaming.km.biz.cluster.ClusterZookeepersManager; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersOverviewVO; +import com.xiaojukeji.know.streaming.km.common.constant.ApiPrefix; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterZookeepersOverviewDTO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ClusterZookeepersStateVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.zookeeper.ZnodeVO; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZnodeService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + + +/** + * @author zengqiao + * @date 22/09/19 + */ +@Api(tags = Constant.SWAGGER_API_TAG_PREFIX + "集群ZK-相关接口(REST)") +@RestController +@RequestMapping(ApiPrefix.API_V3_PREFIX) +public class ClusterZookeepersController { + @Autowired + private ClusterZookeepersManager clusterZookeepersManager; + + @Autowired + private ZnodeService znodeService; + + @ApiOperation("集群Zookeeper状态信息") + @GetMapping(value = "clusters/{clusterPhyId}/zookeepers-state") + public Result getClusterZookeepersState(@PathVariable Long clusterPhyId) { + return clusterZookeepersManager.getClusterPhyZookeepersState(clusterPhyId); + } + + @ApiOperation("集群Zookeeper信息列表") + @PostMapping(value = "clusters/{clusterPhyId}/zookeepers-overview") + public PaginationResult getClusterZookeepersOverview(@PathVariable Long clusterPhyId, + @RequestBody ClusterZookeepersOverviewDTO dto) { + return clusterZookeepersManager.getClusterPhyZookeepersOverview(clusterPhyId, dto); + } + + @ApiOperation("Zookeeper节点数据") + @GetMapping(value = "clusters/{clusterPhyId}/znode-data") + public Result getClusterZookeeperData(@PathVariable Long clusterPhyId, + @RequestParam String path) { + return clusterZookeepersManager.getZnodeVO(clusterPhyId, path); + } + + @ApiOperation("Zookeeper节点列表") + @GetMapping(value = "clusters/{clusterPhyId}/znode-children") + public Result> getClusterZookeeperChild(@PathVariable Long clusterPhyId, + @RequestParam String path, + @RequestParam(required = false) String keyword) { + return znodeService.listZnodeChildren(clusterPhyId, path, keyword); + } + +} diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/zk/ZookeeperMetricsController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/zk/ZookeeperMetricsController.java new file mode 100644 index 00000000..bb2ea098 --- /dev/null +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/zk/ZookeeperMetricsController.java @@ -0,0 +1,52 @@ +package com.xiaojukeji.know.streaming.km.rest.api.v3.zk; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.BaseMetrics; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line.MetricLineVO; +import com.xiaojukeji.know.streaming.km.common.constant.ApiPrefix; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; +import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperMetricService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + + +/** + * @author zengqiao + * @date 22/09/19 + */ +@Api(tags = Constant.SWAGGER_API_TAG_PREFIX + "ZKMetrics-相关接口(REST)") +@RestController +@RequestMapping(ApiPrefix.API_V3_PREFIX) +public class ZookeeperMetricsController { + private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperMetricsController.class); + + @Autowired + private ZookeeperMetricService zookeeperMetricService; + + @ApiOperation(value = "ZK-最近指标", notes = "") + @PostMapping(value = "clusters/{clusterPhyId}/zookeeper-latest-metrics") + @ResponseBody + public Result getLatestMetrics(@PathVariable Long clusterPhyId, @RequestBody List metricsNames) { + Result metricsResult = zookeeperMetricService.batchCollectMetricsFromZookeeper(clusterPhyId, metricsNames); + if (metricsResult.failed()) { + return Result.buildFromIgnoreData(metricsResult); + } + + return Result.buildSuc(metricsResult.getData()); + } + + @ApiOperation(value = "ZK-多指标历史信息", notes = "多条指标线") + @PostMapping(value = "clusters/{clusterPhyId}/zookeeper-metrics") + @ResponseBody + public Result> getMetricsLine(@PathVariable Long clusterPhyId, @RequestBody MetricDTO dto) { + return zookeeperMetricService.listMetricsFromES(clusterPhyId, dto); + } +} From fbc4d4a54023f54efe0e9b6981f6cd83c666cb9e Mon Sep 17 00:00:00 2001 From: zengqiao Date: Sat, 8 Oct 2022 17:00:08 +0800 Subject: [PATCH 081/145] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=8E=A5=E5=85=A5?= =?UTF-8?q?=E5=B8=A6Kerberos=E8=AE=A4=E8=AF=81=E7=9A=84ZK=E9=9B=86?= =?UTF-8?q?=E7=BE=A4=E7=9A=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support_kerberos_zk/need_modify_code.png} | Bin .../assets/support_kerberos_zk/success_1.png} | Bin .../assets/support_kerberos_zk/success_2.png} | Bin .../support_kerberos_zk/watch_user_acl.png} | Bin docs/dev_guide/支持Kerberos认证的ZK.md | 69 ++++++++++++++++++ docs/zk_kerberos/zk支持Kerberos配置文档.md | 47 ------------ 6 files changed, 69 insertions(+), 47 deletions(-) rename docs/{zk_kerberos/img.png => dev_guide/assets/support_kerberos_zk/need_modify_code.png} (100%) rename docs/{zk_kerberos/img_2.png => dev_guide/assets/support_kerberos_zk/success_1.png} (100%) rename docs/{zk_kerberos/img_3.png => dev_guide/assets/support_kerberos_zk/success_2.png} (100%) rename docs/{zk_kerberos/img_1.png => dev_guide/assets/support_kerberos_zk/watch_user_acl.png} (100%) create mode 100644 docs/dev_guide/支持Kerberos认证的ZK.md delete mode 100644 docs/zk_kerberos/zk支持Kerberos配置文档.md diff --git a/docs/zk_kerberos/img.png b/docs/dev_guide/assets/support_kerberos_zk/need_modify_code.png similarity index 100% rename from docs/zk_kerberos/img.png rename to docs/dev_guide/assets/support_kerberos_zk/need_modify_code.png diff --git a/docs/zk_kerberos/img_2.png b/docs/dev_guide/assets/support_kerberos_zk/success_1.png similarity index 100% rename from docs/zk_kerberos/img_2.png rename to docs/dev_guide/assets/support_kerberos_zk/success_1.png diff --git a/docs/zk_kerberos/img_3.png b/docs/dev_guide/assets/support_kerberos_zk/success_2.png similarity index 100% rename from docs/zk_kerberos/img_3.png rename to docs/dev_guide/assets/support_kerberos_zk/success_2.png diff --git a/docs/zk_kerberos/img_1.png b/docs/dev_guide/assets/support_kerberos_zk/watch_user_acl.png similarity index 100% rename from docs/zk_kerberos/img_1.png rename to docs/dev_guide/assets/support_kerberos_zk/watch_user_acl.png diff --git a/docs/dev_guide/支持Kerberos认证的ZK.md b/docs/dev_guide/支持Kerberos认证的ZK.md new file mode 100644 index 00000000..116643ba --- /dev/null +++ b/docs/dev_guide/支持Kerberos认证的ZK.md @@ -0,0 +1,69 @@ + +## 支持Kerberos认证的ZK + + +### 1、修改 KnowStreaming 代码 + +代码位置:`src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java` + +将 `createZKClient` 的 `135行 的 false 改为 true +![need_modify_code.png](assets/support_kerberos_zk/need_modify_code.png) + + +修改完后重新进行打包编译,打包编译见:[打包编译](https://github.com/didi/KnowStreaming/blob/master/docs/install_guide/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85%E6%89%8B%E5%86%8C.md +) + + + +### 2、查看用户在ZK的ACL + +假设我们使用的用户是 `kafka` 这个用户。 + +- 1、查看 server.properties 的配置的 zookeeper.connect 的地址; +- 2、使用 `zkCli.sh -serve zookeeper.connect的地址` 登录到ZK页面; +- 3、ZK页面上,执行命令 `getAcl /kafka` 查看 `kafka` 用户的权限; + +此时,我们可以看到如下信息: +![watch_user_acl.png](assets/support_kerberos_zk/watch_user_acl.png) + +`kafka` 用户需要的权限是 `cdrwa`。如果用户没有 `cdrwa` 权限的话,需要创建用户并授权,授权命令为:`setAcl` + + +### 3、创建Kerberos的keytab并修改 KnowStreaming 主机 + +- 1、在 Kerberos 的域中创建 `kafka/_HOST` 的 `keytab`,并导出。例如:`kafka/dbs-kafka-test-8-53`; +- 2、导出 keytab 后上传到安装 KS 的机器的 `/etc/keytab` 下; +- 3、在 KS 机器上,执行 `kinit -kt zookeepe.keytab kafka/dbs-kafka-test-8-53` 看是否能进行 `Kerberos` 登录; +- 4、可以登录后,配置 `/opt/zookeeper.jaas` 文件,例子如下: +```sql +Client { + com.sun.security.auth.module.Krb5LoginModule required + useKeyTab=true + storeKey=false + serviceName="zookeeper" + keyTab="/etc/keytab/zookeeper.keytab" + principal="kafka/dbs-kafka-test-8-53@XXX.XXX.XXX"; +}; +``` +- 5、需要配置 `KDC-Server` 对 `KnowStreaming` 的机器开通防火墙,并在KS的机器 `/etc/host/` 配置 `kdc-server` 的 `hostname`。并将 `krb5.conf` 导入到 `/etc` 下; + + +### 4、修改 KnowStreaming 的配置 + +- 1、在 `/usr/local/KnowStreaming/KnowStreaming/bin/startup.sh` 中的47行的JAVA_OPT中追加如下设置 +```bash +-Dsun.security.krb5.debug=true -Djava.security.krb5.conf=/etc/krb5.conf -Djava.security.auth.login.config=/opt/zookeeper.jaas +``` + +- 2、重启KS集群后再 start.out 中看到如下信息,则证明Kerberos配置成功; + +![success_1.png](assets/support_kerberos_zk/success_1.png) + +![success_2.png](assets/support_kerberos_zk/success_2.png) + + +### 5、补充说明 + +- 1、多Kafka集群如果用的是一样的Kerberos域的话,只需在每个`ZK`中给`kafka`用户配置`crdwa`权限即可,这样集群初始化的时候`zkclient`是都可以认证; +- 2、当前需要修改代码重新打包才可以支持,后续考虑通过页面支持Kerberos认证的ZK接入; +- 3、多个Kerberos域暂时未适配; \ No newline at end of file diff --git a/docs/zk_kerberos/zk支持Kerberos配置文档.md b/docs/zk_kerberos/zk支持Kerberos配置文档.md deleted file mode 100644 index ad70861c..00000000 --- a/docs/zk_kerberos/zk支持Kerberos配置文档.md +++ /dev/null @@ -1,47 +0,0 @@ -1、需要修改代码: -位置:src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java -将createZKClient的135行的false改为true -![img.png](img.png) -修改完之后就可以打包编译:打包编译见:参考2.3 后端单独打包 -https://github.com/didi/KnowStreaming/blob/master/docs/install_guide/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85%E6%89%8B%E5%86%8C.md - -2、查看kafka的ZK的Acl -首先查看kafka的server.properties的配置的zookeeper.connect的连接,然后使用:zkCli.sh -serve xxxx登录到zk的页面,然后执行命令getAcl /kafka -![img_1.png](img_1.png) -此时就可以看到kafka在zk中的用户的权限,因为我们的集群在server.properties 配置了super.users=User:kafka ,以及zookeeper.set.acl=true ,默认的kafka的权限就是cdrwa。如果没有用户有cdrwa权限的话,需要zk创建用户并授权,授权命令:setAcl - -3、在Kerberos的域中创建 kafka/_HOST的keytab,并导出。例如:kafka/dbs-kafka-test-8-53 - -4、导出keytab后上传到安装KS的机器的/etc/keytab下。执行 kinit -kt zookeepe.keytab kafka/dbs-kafka-test-8-53 看是否能进行Kerberos登录 - -5、可以登录后,配置/opt/zookeeper.jass文件: -Client { - -com.sun.security.auth.module.Krb5LoginModule required - -useKeyTab=true - -storeKey=false - -serviceName="zookeeper" - -keyTab="/etc/keytab/zookeeper.keytab" - -principal="kafka/dbs-kafka-test-8-53@XXX.XXX.XXX"; - -}; - -6、需要配置KDC-Server对KS的机器开通防火墙,并在KS的机器/etc/host/ 配置 kdc-server的hostname。并将 krb5.conf 导入到/etc下 - -7、在/usr/local/KnowStreaming/KnowStreaming/bin/startup.sh中的47行的JAVA_OPT中追加如下设置: --Dsun.security.krb5.debug=true -Djava.security.krb5.conf=/etc/krb5.conf -Djava.security.auth.login.config=/opt/zookeeper.jaas - -8、重启KS集群后再start.out中看到如下信息,证明Kerberos配置成功 -![img_3.png](img_3.png) -![img_2.png](img_2.png) - -9、对于多集群来说如果用的是一样的Kerberos域的话,只需在每个zk中给kafka用户配置crdwa权限即可,这样集群初始化的时候zkclient是都可以认证。 - -10、未改进: - 1、需要页面ZK的Kerberos配置化 - 2、多个Kerberos域暂时未适配。 \ No newline at end of file From d7986ad8ddd711a7297bd7de6321b0f92c0be7fb Mon Sep 17 00:00:00 2001 From: EricZeng Date: Sun, 9 Oct 2022 10:38:36 +0800 Subject: [PATCH 082/145] =?UTF-8?q?=E6=81=A2=E5=A4=8D=E4=B8=BA=E5=8E=9F?= =?UTF-8?q?=E5=85=88=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 恢复为原先代码 --- .../streaming/km/persistence/kafka/KafkaAdminZKClient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java index 0b824ddb..e6275a60 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaAdminZKClient.java @@ -132,9 +132,9 @@ public class KafkaAdminZKClient extends AbstractClusterLoadedChangedHandler impl kafkaZkClient = KafkaZkClient.apply( zookeeperAddress, -// false, + false, // 添加支持zk的Kerberos认证 - true, +// true, Constant.DEFAULT_SESSION_TIMEOUT_UNIT_MS, Constant.DEFAULT_SESSION_TIMEOUT_UNIT_MS, 5, From d510640e439f2054850468a619372d019128c625 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Sun, 9 Oct 2022 12:27:27 +0800 Subject: [PATCH 083/145] issue template --- .github/ISSUE_TEMPLATE.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..afbe0a05 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1 @@ +## Issue 模板 \ No newline at end of file From 3744c0e97df33b9425ccf8fd772e90f42534535f Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Sun, 9 Oct 2022 13:56:44 +0800 Subject: [PATCH 084/145] issue template --- .github/ISSUE_TEMPLATE/bug_report.md | 41 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/discussion.md | 0 .github/ISSUE_TEMPLATE/feature_request.md | 15 +++++++++ .github/ISSUE_TEMPLATE/question.md | 12 +++++++ 4 files changed, 68 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/discussion.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/question.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..b36d9d6a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,41 @@ +--- +name: 报告Bug +about: 报告KnowStreaming的相关Bug +title: '' +labels: type/bug +assignees: '' + +--- + +- [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 + +### 环境信息 + +* KnowStreaming version: xxx +* Operating System version: xxx +* Java version: xxx + +### 重现该问题的步骤 + +1. xxx +2. xxx +3. xxx + + + +### 预期结果 + + + +### 实际结果 + + + + +--- + +如果有异常,请附上异常Trace: + +``` +Just put your stack trace here! +``` diff --git a/.github/ISSUE_TEMPLATE/discussion.md b/.github/ISSUE_TEMPLATE/discussion.md new file mode 100644 index 00000000..e69de29b diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..0da4616d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,15 @@ +--- +name: 提议新功能/需求 +about: 给KnowStreaming提一个功能需求 +title: '' +labels: type/feature +assignees: '' + +--- + +- [ ] 我在 [issues](https://github.com/didi/KnowStreaming/issues) 中并未搜索到与此相关的功能需求。 +- [ ] 我在 [release notes](https://github.com/didi/KnowStreaming/releases)已经发布的版本中并没有搜到相关功能. + +## Describe the feature + + diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 00000000..581115cc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,12 @@ +--- +name: 问题/Question +about: 问KnowStreaming相关问题 +title: '' +labels: type/question +assignees: '' + +--- + +- [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 + +## 在这里提出你的问题 From efa253fac84fc5a0c9ead0627390fbad298fdfc5 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Sun, 9 Oct 2022 15:26:57 +0800 Subject: [PATCH 085/145] issue template --- .github/ISSUE_TEMPLATE/bug_report.md | 13 +++++++++---- .github/ISSUE_TEMPLATE/discussion.md | 11 +++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 8 ++++---- .github/ISSUE_TEMPLATE/question.md | 4 ++-- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b36d9d6a..959a0795 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -2,7 +2,7 @@ name: 报告Bug about: 报告KnowStreaming的相关Bug title: '' -labels: type/bug +labels: bug assignees: '' --- @@ -11,14 +11,19 @@ assignees: '' ### 环境信息 -* KnowStreaming version: xxx -* Operating System version: xxx -* Java version: xxx +* KnowStreaming version : xxx +* Operating System version : xxx +* Java version : xxx ### 重现该问题的步骤 1. xxx + + + 2. xxx + + 3. xxx diff --git a/.github/ISSUE_TEMPLATE/discussion.md b/.github/ISSUE_TEMPLATE/discussion.md index e69de29b..7c658e51 100644 --- a/.github/ISSUE_TEMPLATE/discussion.md +++ b/.github/ISSUE_TEMPLATE/discussion.md @@ -0,0 +1,11 @@ +--- +name: 讨论 +about: 开启一个关于KnowStreaming的讨论 +title: '' +labels: discussion +assignees: '' +--- + +## 讨论主题 + +... diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 0da4616d..fe7e88fb 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,14 +2,14 @@ name: 提议新功能/需求 about: 给KnowStreaming提一个功能需求 title: '' -labels: type/feature +labels: feature assignees: '' --- - [ ] 我在 [issues](https://github.com/didi/KnowStreaming/issues) 中并未搜索到与此相关的功能需求。 -- [ ] 我在 [release notes](https://github.com/didi/KnowStreaming/releases)已经发布的版本中并没有搜到相关功能. +- [ ] 我在 [release notes] (https://github.com/didi/KnowStreaming/releases)已经发布的版本中并没有搜到相关功能. -## Describe the feature - +## 这里描述需求 + diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 581115cc..784dfbec 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,8 +1,8 @@ --- name: 问题/Question -about: 问KnowStreaming相关问题 +about: 问KnowStreaming相关问题, 如果没有得到及时回复可以加V: shiyanzu001 , 进交流群 title: '' -labels: type/question +labels: question assignees: '' --- From 8aa877071c33cf8f4d2106190710552383d93596 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Sun, 9 Oct 2022 15:39:20 +0800 Subject: [PATCH 086/145] issue template --- .github/ISSUE_TEMPLATE/discussion.md | 1 + .github/ISSUE_TEMPLATE/question.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/discussion.md b/.github/ISSUE_TEMPLATE/discussion.md index 7c658e51..4a3a2108 100644 --- a/.github/ISSUE_TEMPLATE/discussion.md +++ b/.github/ISSUE_TEMPLATE/discussion.md @@ -4,6 +4,7 @@ about: 开启一个关于KnowStreaming的讨论 title: '' labels: discussion assignees: '' + --- ## 讨论主题 diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 784dfbec..739f6255 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,5 +1,5 @@ --- -name: 问题/Question +name: 问题 about: 问KnowStreaming相关问题, 如果没有得到及时回复可以加V: shiyanzu001 , 进交流群 title: '' labels: question From ddd5d1b8927003488ad5d3f5da311b5ff11ae334 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Sun, 9 Oct 2022 15:42:40 +0800 Subject: [PATCH 087/145] issue template --- .github/ISSUE_TEMPLATE/discussion.md | 2 +- .github/ISSUE_TEMPLATE/question.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/discussion.md b/.github/ISSUE_TEMPLATE/discussion.md index 4a3a2108..bf2b8359 100644 --- a/.github/ISSUE_TEMPLATE/discussion.md +++ b/.github/ISSUE_TEMPLATE/discussion.md @@ -1,5 +1,5 @@ --- -name: 讨论 +name: 讨论/discussion about: 开启一个关于KnowStreaming的讨论 title: '' labels: discussion diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 739f6255..02789241 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,6 +1,6 @@ --- name: 问题 -about: 问KnowStreaming相关问题, 如果没有得到及时回复可以加V: shiyanzu001 , 进交流群 +about: 问KnowStreaming相关问题 title: '' labels: question assignees: '' From 91e21898646b4cd16c9c2b03a008007e2567aaba Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Sun, 9 Oct 2022 15:47:13 +0800 Subject: [PATCH 088/145] issue template --- .github/ISSUE_TEMPLATE/config.yml | 5 +++++ .github/ISSUE_TEMPLATE/question.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..30e38e30 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: KnowStreaming官网 + url: https://knowstreaming.com/ + about: KnowStreaming website diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 02789241..e9bf5c05 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,5 +1,5 @@ --- -name: 问题 +name: 提个问题 about: 问KnowStreaming相关问题 title: '' labels: question From b3ad6a71ca60eb63ec1d34f7af7898b25312e861 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Sun, 9 Oct 2022 17:03:46 +0800 Subject: [PATCH 089/145] =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E8=80=85=E8=A7=84?= =?UTF-8?q?=E7=BA=A6=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CODE_OF_CONDUCT.md | 74 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..a70c8889 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at shirenchuang@didiglobal.com . All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org From ebd4e4735d72b5e4590ff67d1b8f9727531a43c4 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 11:42:04 +0800 Subject: [PATCH 090/145] =?UTF-8?q?PR=20=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/PULL_REQUEST_TEMPLATE.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..9ca3226e --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,22 @@ +请不要在没有先创建Issue的情况下创建Pull Request。 + +## 变更的目的是什么 + +XXXXX + +## 简短的更新日志 + +XX + +## 验证这一变化 + +XXXX + +请遵循此清单,以帮助我们快速轻松地整合您的贡献: + +* [ ] 确保有针对更改提交的 Github issue(通常在您开始处理之前)。诸如拼写错误之类的琐碎更改不需要 Github issue。您的Pull Request应该只解决这个问题,而不需要进行其他更改—— 一个 PR 解决一个问题。 +* [ ] 格式化 Pull Request 标题,如[ISSUE #123] support Confluent Schema Registry。 Pull Request 中的每个提交都应该有一个有意义的主题行和正文。 +* [ ] 编写足够详细的Pull Request描述,以了解Pull Request的作用、方式和原因。 +* [ ] 编写必要的单元测试来验证您的逻辑更正。如果提交了新功能或重大更改,请记住在test 模块中添加 integration-test +* [ ] 确保编译通过,集成测试通过 + From b75e630bac5d221bd430c4a0097a4b4d4eefd128 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 12:57:53 +0800 Subject: [PATCH 091/145] =?UTF-8?q?Issue=20=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/detail_optimizing.md | 22 +++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/detail_optimizing.md diff --git a/.github/ISSUE_TEMPLATE/detail_optimizing.md b/.github/ISSUE_TEMPLATE/detail_optimizing.md new file mode 100644 index 00000000..a531ac8a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/detail_optimizing.md @@ -0,0 +1,22 @@ +--- +name: 优化建议 +about: 相关功能优化建议 +title: '' +labels: Optimization Suggestions +assignees: '' + +--- + +- [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 + +### 环境信息 + +* KnowStreaming version : xxx +* Operating System version : xxx +* Java version : xxx + +### 需要优化的功能点 + + +### 建议如何优化 + From bd48bc6a3dc62564e1bf67233c4ef2d81fbc6c78 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 13:46:14 +0800 Subject: [PATCH 092/145] readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 1ae6ca59..cccf3960 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,11 @@ PS: 提问请尽量把问题一次性描述清楚,并告知环境信息情况 微信加群:添加`mike_zhangliang`、`PenceXie`的微信号备注KnowStreaming加群。
          + +加群之前有劳点一下 star,一个小小的 star 是对KnowStreaming作者们努力建设社区的动力。 + +感谢感谢!!! + wx ## Star History From 9c67afd170c1da79c964a971eee66dc1011d91d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=B3=E8=87=BB=E8=87=BB=E7=9A=84=E6=9D=82=E8=B4=A7?= =?UTF-8?q?=E9=93=BA?= Date: Mon, 10 Oct 2022 13:50:55 +0800 Subject: [PATCH 093/145] Update CONTRIBUTING.md --- CONTRIBUTING.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8a8b38a9..7601be61 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,4 +25,6 @@ Following information can help us to resolve the issue faster. * API version. * Logs. * Screenshots. -* Steps to reproduce the issue. \ No newline at end of file +* Steps to reproduce the issue. + +0 From dc8604ad81cfbccd676ddfdbd9008ada58ba510a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=B3=E8=87=BB=E8=87=BB=E7=9A=84=E6=9D=82=E8=B4=A7?= =?UTF-8?q?=E9=93=BA?= Date: Mon, 10 Oct 2022 13:58:35 +0800 Subject: [PATCH 094/145] Update CONTRIBUTING.md --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7601be61..e2690d71 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,3 +28,4 @@ Following information can help us to resolve the issue faster. * Steps to reproduce the issue. 0 +1 From 2fb3aa1c14145ab771d43054d28d1a2ecc7d6ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=B3=E8=87=BB=E8=87=BB=E7=9A=84=E6=9D=82=E8=B4=A7?= =?UTF-8?q?=E9=93=BA?= Date: Mon, 10 Oct 2022 14:22:24 +0800 Subject: [PATCH 095/145] Update CONTRIBUTING.md --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e2690d71..683294cd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,3 +29,4 @@ Following information can help us to resolve the issue faster. 0 1 +4 From 7163c74cba149dc48b00b56d357871187efc3c8c Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 15:50:16 +0800 Subject: [PATCH 096/145] =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E8=80=85=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 3 - docs/contributer_guide/代码规范.md | 1 + docs/contributer_guide/开发者名单.md | 7 ++ docs/contributer_guide/贡献流程.md | 117 +++++++++++++++++++++ docs/contributer_guide/贡献源码.md | 149 +++++++++++++++++++++++++++ 5 files changed, 274 insertions(+), 3 deletions(-) create mode 100644 docs/contributer_guide/代码规范.md create mode 100644 docs/contributer_guide/开发者名单.md create mode 100644 docs/contributer_guide/贡献流程.md create mode 100644 docs/contributer_guide/贡献源码.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 683294cd..5560642a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,6 +27,3 @@ Following information can help us to resolve the issue faster. * Screenshots. * Steps to reproduce the issue. -0 -1 -4 diff --git a/docs/contributer_guide/代码规范.md b/docs/contributer_guide/代码规范.md new file mode 100644 index 00000000..be0bcfd2 --- /dev/null +++ b/docs/contributer_guide/代码规范.md @@ -0,0 +1 @@ +TODO. \ No newline at end of file diff --git a/docs/contributer_guide/开发者名单.md b/docs/contributer_guide/开发者名单.md new file mode 100644 index 00000000..b5c05427 --- /dev/null +++ b/docs/contributer_guide/开发者名单.md @@ -0,0 +1,7 @@ + +开源贡献者证书发放名单(定期更新) + + +|姓名|Github|角色|发放日期| +|--|--|--|--| +|szz|@szz|PMC|2022/?/?| \ No newline at end of file diff --git a/docs/contributer_guide/贡献流程.md b/docs/contributer_guide/贡献流程.md new file mode 100644 index 00000000..4f2a5b5a --- /dev/null +++ b/docs/contributer_guide/贡献流程.md @@ -0,0 +1,117 @@ +@[TOC] + +### 贡献流程 + + + +#### 1. fork didi/KnowStreaming项目到您的github库 + +找到你要Fork的项目,例如 [KnowStreaming](https://github.com/didi/KnowStreaming) ,点击Fork按钮。 +![在这里插入图片描述](https://img-blog.csdnimg.cn/ac7bfef9ccde49d587c30e702a615ef5.png) + + +#### 2. 克隆或下载您fork的Nacos代码仓库到您本地 + +```sh + +git clone { your fork knowstreaming repo address } + +cd KnowStreaming + +``` + +#### 3. 添加 didi/KnowStreaming仓库为upstream仓库 + + +```sh + +git remote add upstream https://github.com/didi/KnowStreaming + +git remote -v + + origin ${your fork KnowStreaming repo address} (fetch) + origin ${your fork KnowStreaming repo address} (push) + upstream https://github.com/didi/KnowStreaming(fetch) + upstream https://github.com/didi/KnowStreaming (push) + +git fetch origin +git fetch upstream + +``` +上面是将didi/KnowStreaming添加为远程仓库, 当前就会有2个远程仓库 + +1. origin : 你Fork出来的分叉仓库 +2. upstream : 源仓库 + +git fetch 获取远程仓库的基本信息, 比如 **源仓库**的所有分支就获取到了 + + +#### 4. 同步源仓库开发分支到本地分叉仓库中 + +一般开源项目都会有一个给贡献者提交代码的分支,例如 KnowStreaming的分支是 `dev`; + + +首先我们要将 **源仓库**的开发分支(`dev`) 拉取到本地仓库中 +```sh + +git checkout -b dev upstream/dev +``` +**或者IDEA的形式创建** + +![在这里插入图片描述](https://img-blog.csdnimg.cn/c95f2601a9af41889a5fc20b2a9724a5.png) + +#### 5. 在本地新建的开发分支上进行修改 + +首先请保证您阅读并正确设置KnowStreaming code style, 相关内容请阅读[KnowStreaming 代码规约 ]()。 + +修改时请保证该分支上的修改仅和issue相关,并尽量细化,做到 + +一个分支只修改一件事,一个PR只修改一件事。 + +同时,您的提交记录请尽量描述清楚,主要以谓 + 宾进行描述,如:Fix xxx problem/bug。少量简单的提交可以使用For xxx来描述,如:For codestyle。 如果该提交和某个ISSUE相关,可以添加ISSUE号作为前缀,如:For #10000, Fix xxx problem/bug。 + + +#### 6. Rebase 基础分支和开发分支 + +您修改的时候,可能别人的修改已经提交并被合并,此时可能会有冲突,这里请使用rebase命令进行合并解决,主要有2个好处: + +1. 您的提交记录将会非常优雅,不会出现Merge xxxx branch 等字样 +2. rebase后您分支的提交日志也是一条单链,基本不会出现各种分支交错的情况,回查时更轻松 + +```sh +git fetch upstream + +git rebase -i upstream/dev + +``` +**或者在IDEA的操作如下** + +![在这里插入图片描述](https://img-blog.csdnimg.cn/d75addcfa9564d3d9e1d226a2f7f4d64.png) +选择 源仓库的开发分支 +![在这里插入图片描述](https://img-blog.csdnimg.cn/4e85714df13b44bcb10f1e655450cb72.png) + +推荐使用IDEA的方式, 有冲突的时候更容易解决冲突问题。 + +#### 7. 将您开发完成rebase后的分支,上传到您fork的仓库 + +```sh +git push origin dev +``` + +#### 8. 按照PR模板中的清单创建Pull Request + + + +![在这里插入图片描述](https://img-blog.csdnimg.cn/1dab060aed314666970e3910e05f2205.png) + +选择自己的分支合并到模板分支。 + + +#### 9. 等待合并代码 + +提交了PR之后,需要等待PMC、Commiter 来Review代码,如果有问题需要配合修改重新提交。 + +如果没有问题会直接合并到开发分支`dev`中。 + +注: 如何长时间没有review, 则可以多催促社区来Review代码! + diff --git a/docs/contributer_guide/贡献源码.md b/docs/contributer_guide/贡献源码.md new file mode 100644 index 00000000..78f815e9 --- /dev/null +++ b/docs/contributer_guide/贡献源码.md @@ -0,0 +1,149 @@ + + + +# 为KnowStreaming做贡献 + + +欢迎👏🏻来到KnowStreaming!本文档是关于如何为KnowStreaming做出贡献的指南。 + +如果您发现不正确或遗漏的内容, 请留下意见/建议。 + +## 行为守则 +请务必阅读并遵守我们的 [行为准则](./CODE_OF_CONDUCT.md). + + + +## 贡献 + +**KnowStreaming** 欢迎任何角色的新参与者,包括 **User** 、**Contributor**、**Committer**、**PMC** 。 + +我们鼓励新人积极加入 **KnowStreaming** 项目,从User到Contributor、Committer ,甚至是 PMC 角色。 + +为了做到这一点,新人需要积极地为 **KnowStreaming** 项目做出贡献。以下介绍如何对 **KnowStreaming** 进行贡献。 + + +### 创建/打开 Issue + +如果您在文档中发现拼写错误、在代码中**发现错误**或想要**新功能**或想要**提供建议**,您可以在 GitHub 上[创建一个Issue](https://github.com/didi/KnowStreaming/issues/new/choose) 进行报告。 + + +如果您想直接贡献, 您可以选择下面标签的问题。 + +- [contribution welcome](https://github.com/didi/KnowStreaming/labels/contribution%20welcome) : 非常需要解决/新增 的Issues +- [good first issue](https://github.com/didi/KnowStreaming/labels/good%20first%20issue): 对新人比较友好, 新人可以拿这个Issue来练练手热热身。 + + 请注意,任何 PR 都必须与有效issue相关联。否则,PR 将被拒绝。 + + + +### 开始你的贡献 + +**分支介绍** + +我们将 `dev`分支作为开发分支, 说明这是一个不稳定的分支。 + +此外,我们的分支模型符合 [https://nvie.com/posts/a-successful-git-branching-model/](https://nvie.com/posts/a-successful-git-branching-model/). 我们强烈建议新人在创建PR之前先阅读上述文章。 + + + +**贡献流程** + +为方便描述,我们这里定义一下2个名词: + +自己Fork出来的仓库是私人仓库, 我们这里称之为 :**分叉仓库** +Fork的源项目,我们称之为:**源仓库** + + +现在,如果您准备好创建PR, 以下是贡献者的工作流程: + +1. Fork [KnowStreaming](https://github.com/didi/KnowStreaming) 项目到自己的仓库 + +2. 从源仓库的`dev`拉取并创建自己的本地分支,例如: `dev` +3. 在本地分支上对代码进行修改 +4. Rebase 开发分支, 并解决冲突 +5. commit 并 push 您的更改到您自己的**分叉仓库** +6. 创建一个 Pull Request 到**源仓库**的`dev`分支中。 +7. 等待回复。如果回复的慢,请无情的催促。 + + + +创建Pull Request时: + +1. 请遵循 PR的 [模板](./PULL_REQUEST_TEMPLATE.md) +2. 请确保 PR 有相应的issue。 +3. 如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档(在对应的issue中)。 +4. 注意单个 PR 不能太大。如果需要进行大量更改,最好将更改分成几个单独的 PR。 +5. 在合并PR之前,尽量的将最终的提交信息清晰简洁, 将多次修改的提交尽可能的合并为一次提交。 +6. 创建 PR 后,将为PR分配一个或多个reviewers。 + + +如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档。 + + +# 代码审查指南 + +Commiter将轮流review代码,以确保在合并前至少有一名Commiter + +一些原则: + +- 可读性——重要的代码应该有详细的文档。API 应该有 Javadoc。代码风格应与现有风格保持一致。 +- 优雅:新的函数、类或组件应该设计得很好。 +- 可测试性——单元测试用例应该覆盖 80% 的新代码。 +- 可维护性 - 遵守我们的编码规范。 + + +# 开发者 + +## 成为Contributor + +只要成功提交并合并PR , 则为Contributor + +名单请看:[开发者名单](../开发者名单.md) + +## 尝试成为Commiter + +一般来说, 贡献8个重要的补丁并至少让三个不同的人来Review他们(您需要3个Commiter的支持)。 +然后请人给你提名, 您需要展示您的 + +1. 至少8个重要的PR和项目的相关问题 +2. 与团队合作的能力 +3. 了解项目的代码库和编码风格 +4. 编写好代码的能力 + +当前的Commiter可以通过在KnowStreaming中的Issue标签 `nomination`(提名)来提名您 + +1. 你的名字和姓氏 +2. 指向您的Git个人资料的链接 +3. 解释为什么你应该成为Commiter +4. 详细说明提名人与您合作的3个PR以及相关问题,这些问题可以证明您的能力。 + +另外2个Commiter需要支持您的**提名**,如果5个工作日内没有人反对,您就是提交者,如果有人反对或者想要更多的信息,Commiter会讨论并通常达成共识(5个工作日内) 。 + + +# 开源奖励计划 + + +我们非常欢迎开发者们为KnowStreaming开源项目贡献一份力量,相应也将给予贡献者激励以表认可与感谢。 + + +## 参与贡献 + +1. 积极参与 Issue 的讨论,如答疑解惑、提供想法或报告无法解决的错误(Issue) +2. 撰写和改进项目的文档(Wiki) +3. 提交补丁优化代码(Coding) + + +## 你将获得 + +1. 加入KnowStreaming开源项目贡献者名单并展示 +2. KnowStreaming开源贡献者证书(纸质&电子版) +3. KnowStreaming贡献者精美大礼包(KnowStreamin/滴滴 周边) + + +## 相关规则 + +- Contributer和Commiter都会有对应的证书和对应的礼包 +- 每季度有KnowStreaming项目团队评选出杰出贡献者,颁发相应证书。 +- 年末进行年度评选 + +贡献者名单请看:[贡献者名单](../开发者名单.md) \ No newline at end of file From 0fea002142b60b968d0bcd470c555a9dd78e2208 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 15:57:07 +0800 Subject: [PATCH 097/145] =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E8=80=85=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 156 +++++++++++++++++++++++++---- docs/contributer_guide/贡献流程.md | 7 +- docs/contributer_guide/贡献源码.md | 4 +- 3 files changed, 145 insertions(+), 22 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5560642a..e163ccd3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,29 +1,149 @@ -# Contribution Guideline -Thanks for considering to contribute this project. All issues and pull requests are highly appreciated. -## Pull Requests -Before sending pull request to this project, please read and follow guidelines below. +# 为KnowStreaming做贡献 -1. Branch: We only accept pull request on `dev` branch. -2. Coding style: Follow the coding style used in LogiKM. -3. Commit message: Use English and be aware of your spell. -4. Test: Make sure to test your code. -Add device mode, API version, related log, screenshots and other related information in your pull request if possible. +欢迎👏🏻来到KnowStreaming!本文档是关于如何为KnowStreaming做出贡献的指南。 -NOTE: We assume all your contribution can be licensed under the [AGPL-3.0](LICENSE). +如果您发现不正确或遗漏的内容, 请留下意见/建议。 -## Issues +## 行为守则 +请务必阅读并遵守我们的 [行为准则](./CODE_OF_CONDUCT.md). -We love clearly described issues. :) -Following information can help us to resolve the issue faster. -* Device mode and hardware information. -* API version. -* Logs. -* Screenshots. -* Steps to reproduce the issue. +## 贡献 +**KnowStreaming** 欢迎任何角色的新参与者,包括 **User** 、**Contributor**、**Committer**、**PMC** 。 + +我们鼓励新人积极加入 **KnowStreaming** 项目,从User到Contributor、Committer ,甚至是 PMC 角色。 + +为了做到这一点,新人需要积极地为 **KnowStreaming** 项目做出贡献。以下介绍如何对 **KnowStreaming** 进行贡献。 + + +### 创建/打开 Issue + +如果您在文档中发现拼写错误、在代码中**发现错误**或想要**新功能**或想要**提供建议**,您可以在 GitHub 上[创建一个Issue](https://github.com/didi/KnowStreaming/issues/new/choose) 进行报告。 + + +如果您想直接贡献, 您可以选择下面标签的问题。 + +- [contribution welcome](https://github.com/didi/KnowStreaming/labels/contribution%20welcome) : 非常需要解决/新增 的Issues +- [good first issue](https://github.com/didi/KnowStreaming/labels/good%20first%20issue): 对新人比较友好, 新人可以拿这个Issue来练练手热热身。 + + 请注意,任何 PR 都必须与有效issue相关联。否则,PR 将被拒绝。 + + + +### 开始你的贡献 + +**分支介绍** + +我们将 `dev`分支作为开发分支, 说明这是一个不稳定的分支。 + +此外,我们的分支模型符合 [https://nvie.com/posts/a-successful-git-branching-model/](https://nvie.com/posts/a-successful-git-branching-model/). 我们强烈建议新人在创建PR之前先阅读上述文章。 + + + +**贡献流程** + +为方便描述,我们这里定义一下2个名词: + +自己Fork出来的仓库是私人仓库, 我们这里称之为 :**分叉仓库** +Fork的源项目,我们称之为:**源仓库** + + +现在,如果您准备好创建PR, 以下是贡献者的工作流程: + +1. Fork [KnowStreaming](https://github.com/didi/KnowStreaming) 项目到自己的仓库 + +2. 从源仓库的`dev`拉取并创建自己的本地分支,例如: `dev` +3. 在本地分支上对代码进行修改 +4. Rebase 开发分支, 并解决冲突 +5. commit 并 push 您的更改到您自己的**分叉仓库** +6. 创建一个 Pull Request 到**源仓库**的`dev`分支中。 +7. 等待回复。如果回复的慢,请无情的催促。 + + + +创建Pull Request时: + +1. 请遵循 PR的 [模板](./PULL_REQUEST_TEMPLATE.md) +2. 请确保 PR 有相应的issue。 +3. 如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档(在对应的issue中)。 +4. 注意单个 PR 不能太大。如果需要进行大量更改,最好将更改分成几个单独的 PR。 +5. 在合并PR之前,尽量的将最终的提交信息清晰简洁, 将多次修改的提交尽可能的合并为一次提交。 +6. 创建 PR 后,将为PR分配一个或多个reviewers。 + + +如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档。 + + +# 代码审查指南 + +Commiter将轮流review代码,以确保在合并前至少有一名Commiter + +一些原则: + +- 可读性——重要的代码应该有详细的文档。API 应该有 Javadoc。代码风格应与现有风格保持一致。 +- 优雅:新的函数、类或组件应该设计得很好。 +- 可测试性——单元测试用例应该覆盖 80% 的新代码。 +- 可维护性 - 遵守我们的编码规范。 + + +# 开发者 + +## 成为Contributor + +只要成功提交并合并PR , 则为Contributor + +名单请看:[开发者名单](../开发者名单.md) + +## 尝试成为Commiter + +一般来说, 贡献8个重要的补丁并至少让三个不同的人来Review他们(您需要3个Commiter的支持)。 +然后请人给你提名, 您需要展示您的 + +1. 至少8个重要的PR和项目的相关问题 +2. 与团队合作的能力 +3. 了解项目的代码库和编码风格 +4. 编写好代码的能力 + +当前的Commiter可以通过在KnowStreaming中的Issue标签 `nomination`(提名)来提名您 + +1. 你的名字和姓氏 +2. 指向您的Git个人资料的链接 +3. 解释为什么你应该成为Commiter +4. 详细说明提名人与您合作的3个PR以及相关问题,这些问题可以证明您的能力。 + +另外2个Commiter需要支持您的**提名**,如果5个工作日内没有人反对,您就是提交者,如果有人反对或者想要更多的信息,Commiter会讨论并通常达成共识(5个工作日内) 。 + + +# 开源奖励计划 + + +我们非常欢迎开发者们为KnowStreaming开源项目贡献一份力量,相应也将给予贡献者激励以表认可与感谢。 + + +## 参与贡献 + +1. 积极参与 Issue 的讨论,如答疑解惑、提供想法或报告无法解决的错误(Issue) +2. 撰写和改进项目的文档(Wiki) +3. 提交补丁优化代码(Coding) + + +## 你将获得 + +1. 加入KnowStreaming开源项目贡献者名单并展示 +2. KnowStreaming开源贡献者证书(纸质&电子版) +3. KnowStreaming贡献者精美大礼包(KnowStreamin/滴滴 周边) + + +## 相关规则 + +- Contributer和Commiter都会有对应的证书和对应的礼包 +- 每季度有KnowStreaming项目团队评选出杰出贡献者,颁发相应证书。 +- 年末进行年度评选 + +贡献者名单请看:[贡献者名单](./docs/contributer_guide/开发者名单.md) \ No newline at end of file diff --git a/docs/contributer_guide/贡献流程.md b/docs/contributer_guide/贡献流程.md index 4f2a5b5a..5ceffeef 100644 --- a/docs/contributer_guide/贡献流程.md +++ b/docs/contributer_guide/贡献流程.md @@ -1,4 +1,3 @@ -@[TOC] ### 贡献流程 @@ -7,6 +6,7 @@ #### 1. fork didi/KnowStreaming项目到您的github库 找到你要Fork的项目,例如 [KnowStreaming](https://github.com/didi/KnowStreaming) ,点击Fork按钮。 + ![在这里插入图片描述](https://img-blog.csdnimg.cn/ac7bfef9ccde49d587c30e702a615ef5.png) @@ -25,15 +25,18 @@ cd KnowStreaming ```sh +### 添加源仓库 git remote add upstream https://github.com/didi/KnowStreaming +### 查看是否添加成功 git remote -v origin ${your fork KnowStreaming repo address} (fetch) origin ${your fork KnowStreaming repo address} (push) upstream https://github.com/didi/KnowStreaming(fetch) upstream https://github.com/didi/KnowStreaming (push) - + +### 获取源仓库的基本信息 git fetch origin git fetch upstream diff --git a/docs/contributer_guide/贡献源码.md b/docs/contributer_guide/贡献源码.md index 78f815e9..7ef952a6 100644 --- a/docs/contributer_guide/贡献源码.md +++ b/docs/contributer_guide/贡献源码.md @@ -98,7 +98,7 @@ Commiter将轮流review代码,以确保在合并前至少有一名Commiter 只要成功提交并合并PR , 则为Contributor -名单请看:[开发者名单](../开发者名单.md) +名单请看:[开发者名单](./开发者名单.md) ## 尝试成为Commiter @@ -146,4 +146,4 @@ Commiter将轮流review代码,以确保在合并前至少有一名Commiter - 每季度有KnowStreaming项目团队评选出杰出贡献者,颁发相应证书。 - 年末进行年度评选 -贡献者名单请看:[贡献者名单](../开发者名单.md) \ No newline at end of file +贡献者名单请看:[贡献者名单](./开发者名单.md) \ No newline at end of file From 750da7c9d792e097643438d4c3beb41f7dd18586 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 16:55:33 +0800 Subject: [PATCH 098/145] =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E8=80=85=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE.md | 1 - CONTRIBUTING.md | 4 +- docs/contributer_guide/开发者名单.md | 38 ++++++- docs/contributer_guide/贡献流程.md | 5 +- docs/contributer_guide/贡献源码.md | 149 --------------------------- 5 files changed, 42 insertions(+), 155 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE.md delete mode 100644 docs/contributer_guide/贡献源码.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index afbe0a05..00000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1 +0,0 @@ -## Issue 模板 \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e163ccd3..4c115eda 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,7 +69,7 @@ Fork的源项目,我们称之为:**源仓库** 创建Pull Request时: -1. 请遵循 PR的 [模板](./PULL_REQUEST_TEMPLATE.md) +1. 请遵循 PR的 [模板](./.github/PULL_REQUEST_TEMPLATE.md) 2. 请确保 PR 有相应的issue。 3. 如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档(在对应的issue中)。 4. 注意单个 PR 不能太大。如果需要进行大量更改,最好将更改分成几个单独的 PR。 @@ -98,7 +98,7 @@ Commiter将轮流review代码,以确保在合并前至少有一名Commiter 只要成功提交并合并PR , 则为Contributor -名单请看:[开发者名单](../开发者名单.md) +贡献者名单请看:[贡献者名单](./docs/contributer_guide/开发者名单.md) ## 尝试成为Commiter diff --git a/docs/contributer_guide/开发者名单.md b/docs/contributer_guide/开发者名单.md index b5c05427..704ffc5c 100644 --- a/docs/contributer_guide/开发者名单.md +++ b/docs/contributer_guide/开发者名单.md @@ -2,6 +2,42 @@ 开源贡献者证书发放名单(定期更新) +贡献者名单请看:[贡献者名单]() + + + |姓名|Github|角色|发放日期| |--|--|--|--| -|szz|@szz|PMC|2022/?/?| \ No newline at end of file +|张亮 | [@zhangliangboy](https://github.com/zhangliangboy)||| +|谢鹏|[@PenceXie](https://github.com/PenceXie)||| +|石臻臻 | [@shirenchuang](https://github.com/shirenchuang)||| +|周宇航|[@GraceWalk](https://github.com/GraceWalk)||| +|曾巧|[@ZQKC](https://github.com/ZQKC)||| +|赵寅锐|[@ZHAOYINRUI](https://github.com/ZHAOYINRUI)||| +|王东方|[@wangdongfang-aden](https://github.com/wangdongfang-aden)||| +|haoqi123|[@[haoqi123]](https://github.com/haoqi123)||| +|17hao|[@17hao](https://github.com/17hao)||| +|Huyueeer|[@Huyueeer](https://github.com/Huyueeer)||| +|杨光|[@yaangvipguang](https://github.com/yangvipguang)| +|王亚聪|[@wangyacongi](https://github.com/wangyacongi)| +|WYAOBO|[@WYAOBO](https://github.com/WYAOBO) +| Super .Wein(星痕)| [@superspeedone](https://github.com/superspeedone)||| +| Yang Jing| [@yangbajing](https://github.com/yangbajing)||| +| 刘新元 Liu XinYuan| [@Liu-XinYuan](https://github.com/Liu-XinYuan)||| +|Joker | [@LiubeyJokerQueue](https://github.com/JokerQueue)||| +|Eason Lau | [@Liubey](https://github.com/Liubey)||| +| hailanxin| [@hailanxin](https://github.com/hailanxin)||| +| Qi Zhang| [@zzzhangqi](https://github.com/zzzhangqi)||| +|Hongten | [@Hongten](https://github.com/Hongten)||| +|fengxsong | [@fengxsong](https://github.com/fengxsong)||| +|f1558 | [@f1558](https://github.com/f1558)||| +| 谢晓东| [@Strangevy](https://github.com/Strangevy)||| +| ZhaoXinlong| [@ZhaoXinlong](https://github.com/ZhaoXinlong)||| +|xuehaipeng | [@xuehaipeng](https://github.com/xuehaipeng)||| +|mrazkong | [@mrazkong](https://github.com/mrazkong)||| +|xuzhengxi | [@hyper-xx)](https://github.com/hyper-xx)||| +|pierre xiong | [@pierre94](https://github.com/pierre94)||| + + + + diff --git a/docs/contributer_guide/贡献流程.md b/docs/contributer_guide/贡献流程.md index 5ceffeef..b6ec2a9a 100644 --- a/docs/contributer_guide/贡献流程.md +++ b/docs/contributer_guide/贡献流程.md @@ -1,7 +1,7 @@ ### 贡献流程 - +[贡献源码细则](../CONTRIBUTING.md) #### 1. fork didi/KnowStreaming项目到您的github库 @@ -116,5 +116,6 @@ git push origin dev 如果没有问题会直接合并到开发分支`dev`中。 -注: 如何长时间没有review, 则可以多催促社区来Review代码! +注: 如果长时间没有review, 则可以多催促社区来Review代码! + diff --git a/docs/contributer_guide/贡献源码.md b/docs/contributer_guide/贡献源码.md deleted file mode 100644 index 7ef952a6..00000000 --- a/docs/contributer_guide/贡献源码.md +++ /dev/null @@ -1,149 +0,0 @@ - - - -# 为KnowStreaming做贡献 - - -欢迎👏🏻来到KnowStreaming!本文档是关于如何为KnowStreaming做出贡献的指南。 - -如果您发现不正确或遗漏的内容, 请留下意见/建议。 - -## 行为守则 -请务必阅读并遵守我们的 [行为准则](./CODE_OF_CONDUCT.md). - - - -## 贡献 - -**KnowStreaming** 欢迎任何角色的新参与者,包括 **User** 、**Contributor**、**Committer**、**PMC** 。 - -我们鼓励新人积极加入 **KnowStreaming** 项目,从User到Contributor、Committer ,甚至是 PMC 角色。 - -为了做到这一点,新人需要积极地为 **KnowStreaming** 项目做出贡献。以下介绍如何对 **KnowStreaming** 进行贡献。 - - -### 创建/打开 Issue - -如果您在文档中发现拼写错误、在代码中**发现错误**或想要**新功能**或想要**提供建议**,您可以在 GitHub 上[创建一个Issue](https://github.com/didi/KnowStreaming/issues/new/choose) 进行报告。 - - -如果您想直接贡献, 您可以选择下面标签的问题。 - -- [contribution welcome](https://github.com/didi/KnowStreaming/labels/contribution%20welcome) : 非常需要解决/新增 的Issues -- [good first issue](https://github.com/didi/KnowStreaming/labels/good%20first%20issue): 对新人比较友好, 新人可以拿这个Issue来练练手热热身。 - - 请注意,任何 PR 都必须与有效issue相关联。否则,PR 将被拒绝。 - - - -### 开始你的贡献 - -**分支介绍** - -我们将 `dev`分支作为开发分支, 说明这是一个不稳定的分支。 - -此外,我们的分支模型符合 [https://nvie.com/posts/a-successful-git-branching-model/](https://nvie.com/posts/a-successful-git-branching-model/). 我们强烈建议新人在创建PR之前先阅读上述文章。 - - - -**贡献流程** - -为方便描述,我们这里定义一下2个名词: - -自己Fork出来的仓库是私人仓库, 我们这里称之为 :**分叉仓库** -Fork的源项目,我们称之为:**源仓库** - - -现在,如果您准备好创建PR, 以下是贡献者的工作流程: - -1. Fork [KnowStreaming](https://github.com/didi/KnowStreaming) 项目到自己的仓库 - -2. 从源仓库的`dev`拉取并创建自己的本地分支,例如: `dev` -3. 在本地分支上对代码进行修改 -4. Rebase 开发分支, 并解决冲突 -5. commit 并 push 您的更改到您自己的**分叉仓库** -6. 创建一个 Pull Request 到**源仓库**的`dev`分支中。 -7. 等待回复。如果回复的慢,请无情的催促。 - - - -创建Pull Request时: - -1. 请遵循 PR的 [模板](./PULL_REQUEST_TEMPLATE.md) -2. 请确保 PR 有相应的issue。 -3. 如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档(在对应的issue中)。 -4. 注意单个 PR 不能太大。如果需要进行大量更改,最好将更改分成几个单独的 PR。 -5. 在合并PR之前,尽量的将最终的提交信息清晰简洁, 将多次修改的提交尽可能的合并为一次提交。 -6. 创建 PR 后,将为PR分配一个或多个reviewers。 - - -如果您的 PR 包含较大的更改,例如组件重构或新组件,请编写有关其设计和使用的详细文档。 - - -# 代码审查指南 - -Commiter将轮流review代码,以确保在合并前至少有一名Commiter - -一些原则: - -- 可读性——重要的代码应该有详细的文档。API 应该有 Javadoc。代码风格应与现有风格保持一致。 -- 优雅:新的函数、类或组件应该设计得很好。 -- 可测试性——单元测试用例应该覆盖 80% 的新代码。 -- 可维护性 - 遵守我们的编码规范。 - - -# 开发者 - -## 成为Contributor - -只要成功提交并合并PR , 则为Contributor - -名单请看:[开发者名单](./开发者名单.md) - -## 尝试成为Commiter - -一般来说, 贡献8个重要的补丁并至少让三个不同的人来Review他们(您需要3个Commiter的支持)。 -然后请人给你提名, 您需要展示您的 - -1. 至少8个重要的PR和项目的相关问题 -2. 与团队合作的能力 -3. 了解项目的代码库和编码风格 -4. 编写好代码的能力 - -当前的Commiter可以通过在KnowStreaming中的Issue标签 `nomination`(提名)来提名您 - -1. 你的名字和姓氏 -2. 指向您的Git个人资料的链接 -3. 解释为什么你应该成为Commiter -4. 详细说明提名人与您合作的3个PR以及相关问题,这些问题可以证明您的能力。 - -另外2个Commiter需要支持您的**提名**,如果5个工作日内没有人反对,您就是提交者,如果有人反对或者想要更多的信息,Commiter会讨论并通常达成共识(5个工作日内) 。 - - -# 开源奖励计划 - - -我们非常欢迎开发者们为KnowStreaming开源项目贡献一份力量,相应也将给予贡献者激励以表认可与感谢。 - - -## 参与贡献 - -1. 积极参与 Issue 的讨论,如答疑解惑、提供想法或报告无法解决的错误(Issue) -2. 撰写和改进项目的文档(Wiki) -3. 提交补丁优化代码(Coding) - - -## 你将获得 - -1. 加入KnowStreaming开源项目贡献者名单并展示 -2. KnowStreaming开源贡献者证书(纸质&电子版) -3. KnowStreaming贡献者精美大礼包(KnowStreamin/滴滴 周边) - - -## 相关规则 - -- Contributer和Commiter都会有对应的证书和对应的礼包 -- 每季度有KnowStreaming项目团队评选出杰出贡献者,颁发相应证书。 -- 年末进行年度评选 - -贡献者名单请看:[贡献者名单](./开发者名单.md) \ No newline at end of file From 103db39460c633aa49a44afbcf0bbf54e24e9a8f Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 17:21:21 +0800 Subject: [PATCH 099/145] =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E8=80=85=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 1 + README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4c115eda..06577128 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -66,6 +66,7 @@ Fork的源项目,我们称之为:**源仓库** 7. 等待回复。如果回复的慢,请无情的催促。 +更为详细的贡献流程请看:[贡献流程](./docs/contributer_guide/贡献流程.md) 创建Pull Request时: diff --git a/README.md b/README.md index cccf3960..5b630fb0 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ 点击 [这里](CONTRIBUTING.md),了解如何成为 Know Streaming 的贡献者 - +获取KnowStreaming开源社区证书。 ## 加入技术交流群 From e13d77c81de0aaa5f6a4f769248f8028b3ff9379 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Mon, 10 Oct 2022 18:02:19 +0800 Subject: [PATCH 100/145] =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E8=80=85=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/contributer_guide/贡献流程.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributer_guide/贡献流程.md b/docs/contributer_guide/贡献流程.md index b6ec2a9a..c93f8476 100644 --- a/docs/contributer_guide/贡献流程.md +++ b/docs/contributer_guide/贡献流程.md @@ -1,7 +1,7 @@ ### 贡献流程 -[贡献源码细则](../CONTRIBUTING.md) +[贡献源码细则](./././CONTRIBUTING.md) #### 1. fork didi/KnowStreaming项目到您的github库 From 5355c5c1f38a6b8e31be1eba52501e7913f43abd Mon Sep 17 00:00:00 2001 From: zengqiao Date: Mon, 10 Oct 2022 19:19:05 +0800 Subject: [PATCH 101/145] =?UTF-8?q?=E4=BF=AE=E5=A4=8DDSL=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E5=AF=BC=E8=87=B4ZK=E6=8C=87=E6=A0=87=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../streaming/km/persistence/es/dsls/DslsConstant.java | 2 +- .../dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java index 94a8698e..f15fe7a8 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dsls/DslsConstant.java @@ -81,5 +81,5 @@ public class DslsConstant { public static final String COUNT_GROUP_NOT_METRIC_VALUE = "GroupMetricESDAO/countGroupNotMetricValue"; /**************************************************** Zookeeper ****************************************************/ - public static final String GET_ZOOKEEPER_AGG_LIST_METRICS = "ZookeeperMetricESDAO/getAggListZookeeperMetrics"; + public static final String GET_ZOOKEEPER_AGG_LIST_METRICS = "ZookeeperMetricESDAO/getAggListZookeeperMetrics"; } diff --git a/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics b/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics index c05c221d..c498368b 100644 --- a/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics +++ b/km-persistence/src/main/resources/dsl/ZookeeperMetricESDAO/getAggListZookeeperMetrics @@ -10,13 +10,6 @@ } } }, - { - "term": { - "brokerId": { - "value": %d - } - } - }, { "range": { "timestamp": { From 215602bb847166ded8a5d268433ba0cc22aa50b9 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Mon, 10 Oct 2022 19:49:22 +0800 Subject: [PATCH 102/145] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=B4=A1=E7=8C=AE?= =?UTF-8?q?=E8=80=85=E5=90=8D=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/contributer_guide/开发者名单.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/contributer_guide/开发者名单.md b/docs/contributer_guide/开发者名单.md index 704ffc5c..ea147bdc 100644 --- a/docs/contributer_guide/开发者名单.md +++ b/docs/contributer_guide/开发者名单.md @@ -9,9 +9,12 @@ |姓名|Github|角色|发放日期| |--|--|--|--| |张亮 | [@zhangliangboy](https://github.com/zhangliangboy)||| +|赵情融 | [@zqrferrari](https://github.com/zqrferrari)||| |谢鹏|[@PenceXie](https://github.com/PenceXie)||| +|孙超|[@lucasun](https://github.com/lucasun)||| +|许喆 | [@potaaaaaato](https://github.com/potaaaaaato)||| |石臻臻 | [@shirenchuang](https://github.com/shirenchuang)||| -|周宇航|[@GraceWalk](https://github.com/GraceWalk)||| +|郭宇航|[@GraceWalk](https://github.com/GraceWalk)||| |曾巧|[@ZQKC](https://github.com/ZQKC)||| |赵寅锐|[@ZHAOYINRUI](https://github.com/ZHAOYINRUI)||| |王东方|[@wangdongfang-aden](https://github.com/wangdongfang-aden)||| @@ -20,7 +23,7 @@ |Huyueeer|[@Huyueeer](https://github.com/Huyueeer)||| |杨光|[@yaangvipguang](https://github.com/yangvipguang)| |王亚聪|[@wangyacongi](https://github.com/wangyacongi)| -|WYAOBO|[@WYAOBO](https://github.com/WYAOBO) +|王耀波|[@WYAOBO](https://github.com/WYAOBO) | Super .Wein(星痕)| [@superspeedone](https://github.com/superspeedone)||| | Yang Jing| [@yangbajing](https://github.com/yangbajing)||| | 刘新元 Liu XinYuan| [@Liu-XinYuan](https://github.com/Liu-XinYuan)||| @@ -34,8 +37,8 @@ | 谢晓东| [@Strangevy](https://github.com/Strangevy)||| | ZhaoXinlong| [@ZhaoXinlong](https://github.com/ZhaoXinlong)||| |xuehaipeng | [@xuehaipeng](https://github.com/xuehaipeng)||| -|mrazkong | [@mrazkong](https://github.com/mrazkong)||| -|xuzhengxi | [@hyper-xx)](https://github.com/hyper-xx)||| +|孔令续 | [@mrazkong](https://github.com/mrazkong)||| +|徐正熙 | [@hyper-xx)](https://github.com/hyper-xx)||| |pierre xiong | [@pierre94](https://github.com/pierre94)||| From 12ebc32cecabf48b25580c6348149ab227f00205 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Mon, 10 Oct 2022 19:54:47 +0800 Subject: [PATCH 103/145] =?UTF-8?q?Broker=E5=A2=9E=E5=8A=A0=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E6=98=AF=E5=90=A6=E5=AD=98=E6=B4=BB=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../km/core/service/broker/BrokerService.java | 4 ++++ .../broker/impl/BrokerServiceImpl.java | 22 +++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/BrokerService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/BrokerService.java index 62f03e65..c8c300a0 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/BrokerService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/BrokerService.java @@ -67,4 +67,8 @@ public interface BrokerService { * 获取总的Broker数 */ Integer countAllBrokers(); + + boolean allServerDown(Long clusterPhyId); + + boolean existServerDown(Long clusterPhyId); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java index 7fc4f4f2..3fd74ee5 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java @@ -262,14 +262,32 @@ public class BrokerServiceImpl extends BaseVersionControlService implements Brok return version; } - - @Override public Integer countAllBrokers() { LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); return brokerDAO.selectCount(lambdaQueryWrapper); } + @Override + public boolean allServerDown(Long clusterPhyId) { + List poList = this.getAllBrokerPOsFromDB(clusterPhyId); + if (ValidateUtils.isEmptyList(poList)) { + return false; + } + + return poList.stream().filter(elem -> elem.getStatus().equals(Constant.DOWN)).count() == poList.size(); + } + + @Override + public boolean existServerDown(Long clusterPhyId) { + List poList = this.getAllBrokerPOsFromDB(clusterPhyId); + if (ValidateUtils.isEmptyList(poList)) { + return false; + } + + return poList.stream().filter(elem -> elem.getStatus().equals(Constant.DOWN)).count() > 0; + } + /**************************************************** private method ****************************************************/ private List listAllBrokersAndUpdateCache(Long clusterPhyId) { From 50482c40d5d710ace8a6cdc282dd4d478d5e2f26 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Tue, 11 Oct 2022 16:54:39 +0800 Subject: [PATCH 104/145] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=8E=B7=E5=8F=96Top?= =?UTF-8?q?N=E7=9A=84Broker=E6=8C=87=E6=A0=87=E6=97=B6=EF=BC=8C=E4=BC=9A?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E9=83=A8=E5=88=86=E6=8C=87=E6=A0=87=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java index edc186f4..83145381 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java @@ -92,7 +92,7 @@ public class BrokerMetricESDAO extends BaseMetricESDAO { Table> table = HashBasedTable.create(); //2、查询指标 - for(String metric : metricBrokerIds.keySet()){ + for(String metric : metrics) { table.putAll( this.listBrokerMetricsByBrokerIds( clusterPhyId, From 9340e0766297078265acb8f7d4b65a77fe77c7a5 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Tue, 11 Oct 2022 17:38:15 +0800 Subject: [PATCH 105/145] update contribuer document --- README.md | 6 +- docs/contributer_guide/开发者名单.md | 42 +--------- docs/contributer_guide/贡献流程.md | 121 +-------------------------- 3 files changed, 9 insertions(+), 160 deletions(-) diff --git a/README.md b/README.md index 5b630fb0..1c08c7c4 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,11 @@ ## 成为社区贡献者 -点击 [这里](CONTRIBUTING.md),了解如何成为 Know Streaming 的贡献者 +1. [贡献源码](https://doc.knowstreaming.com/product/10-contribution) 了解如何成为 Know Streaming 的贡献者 +2. [具体贡献流程](https://doc.knowstreaming.com/product/10-contribution#102-贡献流程) +3. [开源激励计划](https://doc.knowstreaming.com/product/10-contribution#105-开源激励计划) +4. [贡献者名单](https://doc.knowstreaming.com/product/10-contribution#106-贡献者名单) + 获取KnowStreaming开源社区证书。 diff --git a/docs/contributer_guide/开发者名单.md b/docs/contributer_guide/开发者名单.md index ea147bdc..3f2c708d 100644 --- a/docs/contributer_guide/开发者名单.md +++ b/docs/contributer_guide/开发者名单.md @@ -2,45 +2,5 @@ 开源贡献者证书发放名单(定期更新) -贡献者名单请看:[贡献者名单]() - - - -|姓名|Github|角色|发放日期| -|--|--|--|--| -|张亮 | [@zhangliangboy](https://github.com/zhangliangboy)||| -|赵情融 | [@zqrferrari](https://github.com/zqrferrari)||| -|谢鹏|[@PenceXie](https://github.com/PenceXie)||| -|孙超|[@lucasun](https://github.com/lucasun)||| -|许喆 | [@potaaaaaato](https://github.com/potaaaaaato)||| -|石臻臻 | [@shirenchuang](https://github.com/shirenchuang)||| -|郭宇航|[@GraceWalk](https://github.com/GraceWalk)||| -|曾巧|[@ZQKC](https://github.com/ZQKC)||| -|赵寅锐|[@ZHAOYINRUI](https://github.com/ZHAOYINRUI)||| -|王东方|[@wangdongfang-aden](https://github.com/wangdongfang-aden)||| -|haoqi123|[@[haoqi123]](https://github.com/haoqi123)||| -|17hao|[@17hao](https://github.com/17hao)||| -|Huyueeer|[@Huyueeer](https://github.com/Huyueeer)||| -|杨光|[@yaangvipguang](https://github.com/yangvipguang)| -|王亚聪|[@wangyacongi](https://github.com/wangyacongi)| -|王耀波|[@WYAOBO](https://github.com/WYAOBO) -| Super .Wein(星痕)| [@superspeedone](https://github.com/superspeedone)||| -| Yang Jing| [@yangbajing](https://github.com/yangbajing)||| -| 刘新元 Liu XinYuan| [@Liu-XinYuan](https://github.com/Liu-XinYuan)||| -|Joker | [@LiubeyJokerQueue](https://github.com/JokerQueue)||| -|Eason Lau | [@Liubey](https://github.com/Liubey)||| -| hailanxin| [@hailanxin](https://github.com/hailanxin)||| -| Qi Zhang| [@zzzhangqi](https://github.com/zzzhangqi)||| -|Hongten | [@Hongten](https://github.com/Hongten)||| -|fengxsong | [@fengxsong](https://github.com/fengxsong)||| -|f1558 | [@f1558](https://github.com/f1558)||| -| 谢晓东| [@Strangevy](https://github.com/Strangevy)||| -| ZhaoXinlong| [@ZhaoXinlong](https://github.com/ZhaoXinlong)||| -|xuehaipeng | [@xuehaipeng](https://github.com/xuehaipeng)||| -|孔令续 | [@mrazkong](https://github.com/mrazkong)||| -|徐正熙 | [@hyper-xx)](https://github.com/hyper-xx)||| -|pierre xiong | [@pierre94](https://github.com/pierre94)||| - - - +贡献者名单请看:[贡献者名单](https://doc.knowstreaming.com/product/10-contribution#106-贡献者名单) diff --git a/docs/contributer_guide/贡献流程.md b/docs/contributer_guide/贡献流程.md index c93f8476..42679379 100644 --- a/docs/contributer_guide/贡献流程.md +++ b/docs/contributer_guide/贡献流程.md @@ -1,121 +1,6 @@ -### 贡献流程 - -[贡献源码细则](./././CONTRIBUTING.md) - -#### 1. fork didi/KnowStreaming项目到您的github库 - -找到你要Fork的项目,例如 [KnowStreaming](https://github.com/didi/KnowStreaming) ,点击Fork按钮。 - -![在这里插入图片描述](https://img-blog.csdnimg.cn/ac7bfef9ccde49d587c30e702a615ef5.png) - - -#### 2. 克隆或下载您fork的Nacos代码仓库到您本地 - -```sh - -git clone { your fork knowstreaming repo address } - -cd KnowStreaming - -``` - -#### 3. 添加 didi/KnowStreaming仓库为upstream仓库 - - -```sh - -### 添加源仓库 -git remote add upstream https://github.com/didi/KnowStreaming - -### 查看是否添加成功 -git remote -v - - origin ${your fork KnowStreaming repo address} (fetch) - origin ${your fork KnowStreaming repo address} (push) - upstream https://github.com/didi/KnowStreaming(fetch) - upstream https://github.com/didi/KnowStreaming (push) - -### 获取源仓库的基本信息 -git fetch origin -git fetch upstream - -``` -上面是将didi/KnowStreaming添加为远程仓库, 当前就会有2个远程仓库 - -1. origin : 你Fork出来的分叉仓库 -2. upstream : 源仓库 - -git fetch 获取远程仓库的基本信息, 比如 **源仓库**的所有分支就获取到了 - - -#### 4. 同步源仓库开发分支到本地分叉仓库中 - -一般开源项目都会有一个给贡献者提交代码的分支,例如 KnowStreaming的分支是 `dev`; - - -首先我们要将 **源仓库**的开发分支(`dev`) 拉取到本地仓库中 -```sh - -git checkout -b dev upstream/dev -``` -**或者IDEA的形式创建** - -![在这里插入图片描述](https://img-blog.csdnimg.cn/c95f2601a9af41889a5fc20b2a9724a5.png) - -#### 5. 在本地新建的开发分支上进行修改 - -首先请保证您阅读并正确设置KnowStreaming code style, 相关内容请阅读[KnowStreaming 代码规约 ]()。 - -修改时请保证该分支上的修改仅和issue相关,并尽量细化,做到 - -一个分支只修改一件事,一个PR只修改一件事。 - -同时,您的提交记录请尽量描述清楚,主要以谓 + 宾进行描述,如:Fix xxx problem/bug。少量简单的提交可以使用For xxx来描述,如:For codestyle。 如果该提交和某个ISSUE相关,可以添加ISSUE号作为前缀,如:For #10000, Fix xxx problem/bug。 - - -#### 6. Rebase 基础分支和开发分支 - -您修改的时候,可能别人的修改已经提交并被合并,此时可能会有冲突,这里请使用rebase命令进行合并解决,主要有2个好处: - -1. 您的提交记录将会非常优雅,不会出现Merge xxxx branch 等字样 -2. rebase后您分支的提交日志也是一条单链,基本不会出现各种分支交错的情况,回查时更轻松 - -```sh -git fetch upstream - -git rebase -i upstream/dev - -``` -**或者在IDEA的操作如下** - -![在这里插入图片描述](https://img-blog.csdnimg.cn/d75addcfa9564d3d9e1d226a2f7f4d64.png) -选择 源仓库的开发分支 -![在这里插入图片描述](https://img-blog.csdnimg.cn/4e85714df13b44bcb10f1e655450cb72.png) - -推荐使用IDEA的方式, 有冲突的时候更容易解决冲突问题。 - -#### 7. 将您开发完成rebase后的分支,上传到您fork的仓库 - -```sh -git push origin dev -``` - -#### 8. 按照PR模板中的清单创建Pull Request - - - -![在这里插入图片描述](https://img-blog.csdnimg.cn/1dab060aed314666970e3910e05f2205.png) - -选择自己的分支合并到模板分支。 - - -#### 9. 等待合并代码 - -提交了PR之后,需要等待PMC、Commiter 来Review代码,如果有问题需要配合修改重新提交。 - -如果没有问题会直接合并到开发分支`dev`中。 - -注: 如果长时间没有review, 则可以多催促社区来Review代码! +
          +
          +请点击:[贡献流程](https://doc.knowstreaming.com/product/10-contribution#102-贡献流程) \ No newline at end of file From f3b64ca4638d4603d9264704a97ab555e356133c Mon Sep 17 00:00:00 2001 From: zengqiao Date: Tue, 11 Oct 2022 18:46:16 +0800 Subject: [PATCH 106/145] =?UTF-8?q?=E5=A2=9E=E5=8A=A0float=E8=BD=ACinteger?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../know/streaming/km/common/utils/ConvertUtil.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ConvertUtil.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ConvertUtil.java index b20a069c..71b611fd 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ConvertUtil.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ConvertUtil.java @@ -389,4 +389,16 @@ public class ConvertUtil { } return null; } + + public static Integer float2Integer(Float f) { + if (null == f) { + return null; + } + try { + return f.intValue(); + } catch (Exception e) { + // ignore exception + } + return null; + } } From 6ad29b95658df40c3d3f53facdc76c9e4c6d19db Mon Sep 17 00:00:00 2001 From: zengqiao Date: Wed, 12 Oct 2022 11:02:41 +0800 Subject: [PATCH 107/145] =?UTF-8?q?ZookeeperService=E4=B8=AD=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=9C=8D=E5=8A=A1=E5=AD=98=E6=B4=BB=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/zookeeper/ZookeeperService.java | 12 ++++++++++ .../zookeeper/impl/ZookeeperServiceImpl.java | 23 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java index 758247aa..8d3a78b1 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/ZookeeperService.java @@ -15,4 +15,16 @@ public interface ZookeeperService { void batchReplaceDataInDB(Long clusterPhyId, List infoList); List listFromDBByCluster(Long clusterPhyId); + + /** + * 所有服务挂掉 + * @return + */ + boolean allServerDown(Long clusterPhyId); + + /** + * 存在服务挂掉 + * @return + */ + boolean existServerDown(Long clusterPhyId); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java index 2f1e318c..84d7eb4c 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperServiceImpl.java @@ -14,6 +14,7 @@ import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; import com.xiaojukeji.know.streaming.km.common.utils.Tuple; import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.ZookeeperInfo; import com.xiaojukeji.know.streaming.km.common.bean.po.zookeeper.ZookeeperInfoPO; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.ZookeeperUtils; import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; @@ -105,6 +106,28 @@ public class ZookeeperServiceImpl implements ZookeeperService { return ConvertUtil.list2List(this.listRawFromDBByCluster(clusterPhyId), ZookeeperInfo.class); } + @Override + public boolean allServerDown(Long clusterPhyId) { + List infoList = this.listFromDBByCluster(clusterPhyId); + if (ValidateUtils.isEmptyList(infoList)) { + return false; + } + + // 所有服务挂掉 + return infoList.stream().filter(elem -> !elem.alive()).count() == infoList.size(); + } + + @Override + public boolean existServerDown(Long clusterPhyId) { + List infoList = this.listFromDBByCluster(clusterPhyId); + if (ValidateUtils.isEmptyList(infoList)) { + // 不存在挂掉的服务 + return false; + } + + // 存在挂掉的服务 + return infoList.stream().filter(elem -> !elem.alive()).count() > 0; + } /**************************************************** private method ****************************************************/ From 92d6214f4f0e2fdddf8dca0d0865f464c02938bf Mon Sep 17 00:00:00 2001 From: zengqiao Date: Wed, 12 Oct 2022 11:11:25 +0800 Subject: [PATCH 108/145] =?UTF-8?q?=E5=A2=9E=E5=8A=A0ZK=E6=8C=87=E6=A0=87?= =?UTF-8?q?=E4=B8=8A=E6=8A=A5=E6=99=AE=E7=BD=97=E7=B1=B3=E4=BF=AE=E6=96=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/AbstractMonitorSinkService.java | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/km-extends/km-monitor/src/main/java/com/xiaojukeji/know/streaming/km/monitor/component/AbstractMonitorSinkService.java b/km-extends/km-monitor/src/main/java/com/xiaojukeji/know/streaming/km/monitor/component/AbstractMonitorSinkService.java index b4fd1986..b2ca9283 100644 --- a/km-extends/km-monitor/src/main/java/com/xiaojukeji/know/streaming/km/monitor/component/AbstractMonitorSinkService.java +++ b/km-extends/km-monitor/src/main/java/com/xiaojukeji/know/streaming/km/monitor/component/AbstractMonitorSinkService.java @@ -37,29 +37,32 @@ public abstract class AbstractMonitorSinkService implements ApplicationListener< @Override public void onApplicationEvent(BaseMetricEvent event) { executor.execute( () -> { - if(event instanceof BrokerMetricEvent){ + if (event instanceof BrokerMetricEvent) { BrokerMetricEvent brokerMetricEvent = (BrokerMetricEvent)event; sinkMetrics(brokerMetric2SinkPoint(brokerMetricEvent.getBrokerMetrics())); - }else if(event instanceof ClusterMetricEvent){ + } else if(event instanceof ClusterMetricEvent) { ClusterMetricEvent clusterMetricEvent = (ClusterMetricEvent)event; sinkMetrics(clusterMetric2SinkPoint(clusterMetricEvent.getClusterMetrics())); - }else if(event instanceof TopicMetricEvent){ + } else if(event instanceof TopicMetricEvent) { TopicMetricEvent topicMetricEvent = (TopicMetricEvent)event; sinkMetrics(topicMetric2SinkPoint(topicMetricEvent.getTopicMetrics())); - }else if(event instanceof PartitionMetricEvent){ + } else if(event instanceof PartitionMetricEvent) { PartitionMetricEvent partitionMetricEvent = (PartitionMetricEvent)event; sinkMetrics(partitionMetric2SinkPoint(partitionMetricEvent.getPartitionMetrics())); - }else if(event instanceof GroupMetricEvent){ + } else if(event instanceof GroupMetricEvent) { GroupMetricEvent groupMetricEvent = (GroupMetricEvent)event; sinkMetrics(groupMetric2SinkPoint(groupMetricEvent.getGroupMetrics())); - }else if(event instanceof ReplicaMetricEvent){ + } else if(event instanceof ReplicaMetricEvent) { ReplicaMetricEvent replicaMetricEvent = (ReplicaMetricEvent)event; sinkMetrics(replicationMetric2SinkPoint(replicaMetricEvent.getReplicationMetrics())); + } else if(event instanceof ZookeeperMetricEvent) { + ZookeeperMetricEvent zookeeperMetricEvent = (ZookeeperMetricEvent)event; + sinkMetrics(zookeeperMetric2SinkPoint(zookeeperMetricEvent.getZookeeperMetrics())); } } ); } @@ -72,6 +75,7 @@ public abstract class AbstractMonitorSinkService implements ApplicationListener< public abstract Boolean sinkMetrics(List pointList); /**************************************************** private method ****************************************************/ + private List brokerMetric2SinkPoint(List brokerMetrics){ List pointList = new ArrayList<>(); @@ -161,8 +165,23 @@ public abstract class AbstractMonitorSinkService implements ApplicationListener< return pointList; } - private List genSinkPoint(String metricPre, Map metrics, - long timeStamp, Map tagsMap){ + private List zookeeperMetric2SinkPoint(List zookeeperMetricsList){ + List pointList = new ArrayList<>(); + + for(ZookeeperMetrics z : zookeeperMetricsList){ + Map tagsMap = new HashMap<>(); + tagsMap.put(CLUSTER_ID.getName(), z.getClusterPhyId()); + + pointList.addAll(genSinkPoint("Zookeeper", z.getMetrics(), z.getTimestamp(), tagsMap)); + } + + return pointList; + } + + private List genSinkPoint(String metricPre, + Map metrics, + long timeStamp, + Map tagsMap) { List pointList = new ArrayList<>(); for(String metricName : metrics.keySet()){ From 0c6475b063b6fa381ec9f56df35f979a01ee6170 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Wed, 12 Oct 2022 16:36:04 +0800 Subject: [PATCH 109/145] =?UTF-8?q?application.yml=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=B8=AD=E5=A2=9E=E5=8A=A0ES=E7=94=A8=E6=88=B7=E5=90=8D?= =?UTF-8?q?=E5=AF=86=E7=A0=81=E7=9A=84=E9=85=8D=E7=BD=AE=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-rest/src/main/resources/application.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/km-rest/src/main/resources/application.yml b/km-rest/src/main/resources/application.yml index 08cac4af..4a4b7f1c 100644 --- a/km-rest/src/main/resources/application.yml +++ b/km-rest/src/main/resources/application.yml @@ -84,7 +84,8 @@ client-pool: es: client: address: 127.0.0.1:8091,127.0.0.1:8061,127.0.0.1:8061 - client-cnt: 10 + pass: # ES账号密码,如果有账号密码,按照 username:password 的格式填写,没有则不需要填写 + client-cnt: 10 # 创建的ES客户端数 io-thread-cnt: 2 max-retry-cnt: 5 From facae65f618dbecd55276abceadac443271662b6 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Wed, 12 Oct 2022 16:41:27 +0800 Subject: [PATCH 110/145] =?UTF-8?q?=E5=81=A5=E5=BA=B7=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/health/AbstractHealthCheckTask.java | 115 ++++++++++++++++++ .../km/task/health/BrokerHealthCheckTask.java | 109 +---------------- .../task/health/ClusterHealthCheckTask.java | 109 +---------------- .../km/task/health/GroupHealthCheckTask.java | 107 +--------------- .../km/task/health/TopicHealthCheckTask.java | 108 +--------------- 5 files changed, 127 insertions(+), 421 deletions(-) create mode 100644 km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java new file mode 100644 index 00000000..1f6c83ff --- /dev/null +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java @@ -0,0 +1,115 @@ +package com.xiaojukeji.know.streaming.km.task.health; + +import com.didiglobal.logi.job.common.TaskResult; +import com.didiglobal.logi.log.ILog; +import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; +import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; +import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; +import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; +import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; +import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +public abstract class AbstractHealthCheckTask extends AbstractAsyncMetricsDispatchTask { + private static final ILog log = LogFactory.getLog(AbstractHealthCheckTask.class); + + @Autowired + private HealthCheckResultService healthCheckResultService; + + public abstract AbstractHealthCheckService getCheckService(); + + @Override + public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { + return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); + } + + private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { + // 获取配置,<配置名,配置信息> + Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); + + // 检查结果 + List resultList = new ArrayList<>(); + + // 遍历Check-Service + List paramList = this.getCheckService().getResList(clusterPhy.getId()); + if (ValidateUtils.isEmptyList(paramList)) { + // 当前无该维度的资源,则直接设置为 + resultList.addAll(this.getNoResResult(clusterPhy.getId(), this.getCheckService(), healthConfigMap)); + } + + // 遍历资源 + for (ClusterPhyParam clusterPhyParam: paramList) { + resultList.addAll(this.checkAndGetResult(clusterPhyParam, healthConfigMap)); + } + + for (HealthCheckResult checkResult: resultList) { + try { + healthCheckResultService.replace(checkResult); + } catch (Exception e) { + log.error("class=AbstractHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); + } + } + + // 删除10分钟之前的检查结果 + try { + healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); + } catch (Exception e) { + log.error("class=AbstractHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); + } + + return TaskResult.SUCCESS; + } + + private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { + List resultList = new ArrayList<>(); + + // 进行检查 + for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { + HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); + if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { + // 类型不匹配 + continue; + } + + // 记录 + HealthCheckResult checkResult = new HealthCheckResult( + dimensionEnum.getDimension(), + clusterHealthConfig.getCheckNameEnum().getConfigName(), + clusterPhyId, + "-1" + ); + checkResult.setPassed(Constant.YES); + resultList.add(checkResult); + } + + return resultList; + } + + private List checkAndGetResult(ClusterPhyParam clusterPhyParam, + Map healthConfigMap) { + List resultList = new ArrayList<>(); + + // 进行检查 + for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { + HealthCheckResult healthCheckResult = this.getCheckService().checkAndGetResult(clusterPhyParam, clusterHealthConfig); + if (healthCheckResult == null) { + continue; + } + + // 记录 + resultList.add(healthCheckResult); + } + + return resultList; + } +} diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/BrokerHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/BrokerHealthCheckTask.java index 7b611823..ef02be8e 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/BrokerHealthCheckTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/BrokerHealthCheckTask.java @@ -1,30 +1,13 @@ package com.xiaojukeji.know.streaming.km.task.health; import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.didiglobal.logi.log.ILog; -import com.didiglobal.logi.log.LogFactory; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; -import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; -import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; import com.xiaojukeji.know.streaming.km.core.service.health.checker.broker.HealthCheckBrokerService; -import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; -import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; - @NoArgsConstructor @AllArgsConstructor @Task(name = "BrokerHealthCheckTask", @@ -33,98 +16,12 @@ import java.util.Map; autoRegister = true, consensual = ConsensualEnum.BROADCAST, timeout = 2 * 60) -public class BrokerHealthCheckTask extends AbstractAsyncMetricsDispatchTask { - private static final ILog log = LogFactory.getLog(BrokerHealthCheckTask.class); - - @Autowired - private HealthCheckResultService healthCheckResultService; - +public class BrokerHealthCheckTask extends AbstractHealthCheckTask { @Autowired private HealthCheckBrokerService healthCheckBrokerService; @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); - } - - private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - // 获取配置,<配置名,配置信息> - Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); - - // 检查结果 - List resultList = new ArrayList<>(); - - // 遍历Check-Service - List paramList = healthCheckBrokerService.getResList(clusterPhy.getId()); - if (ValidateUtils.isEmptyList(paramList)) { - // 当前无该维度的资源,则直接设置为 - resultList.addAll(this.getNoResResult(clusterPhy.getId(), healthCheckBrokerService, healthConfigMap)); - } - - // 遍历资源 - for (ClusterPhyParam clusterPhyParam: paramList) { - resultList.addAll(this.checkAndGetResult(healthCheckBrokerService, clusterPhyParam, healthConfigMap)); - } - - for (HealthCheckResult checkResult: resultList) { - try { - healthCheckResultService.replace(checkResult); - } catch (Exception e) { - log.error("class=BrokerHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); - } - } - - // 删除10分钟之前的检查结果 - try { - healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); - } catch (Exception e) { - log.error("class=BrokerHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); - } - - return TaskResult.SUCCESS; - } - - private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); - if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { - // 类型不匹配 - continue; - } - - // 记录 - HealthCheckResult checkResult = new HealthCheckResult( - dimensionEnum.getDimension(), - clusterHealthConfig.getCheckNameEnum().getConfigName(), - clusterPhyId, - "-1" - ); - checkResult.setPassed(Constant.YES); - resultList.add(checkResult); - } - - return resultList; - } - - private List checkAndGetResult(AbstractHealthCheckService healthCheckService, - ClusterPhyParam clusterPhyParam, - Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckResult healthCheckResult = healthCheckService.checkAndGetResult(clusterPhyParam, clusterHealthConfig); - if (healthCheckResult == null) { - continue; - } - - // 记录 - resultList.add(healthCheckResult); - } - - return resultList; + public AbstractHealthCheckService getCheckService() { + return healthCheckBrokerService; } } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/ClusterHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/ClusterHealthCheckTask.java index cb7f78b2..43c16cb8 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/ClusterHealthCheckTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/ClusterHealthCheckTask.java @@ -1,30 +1,13 @@ package com.xiaojukeji.know.streaming.km.task.health; import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.didiglobal.logi.log.ILog; -import com.didiglobal.logi.log.LogFactory; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; -import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; -import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; import com.xiaojukeji.know.streaming.km.core.service.health.checker.cluster.HealthCheckClusterService; -import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; -import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; - @NoArgsConstructor @AllArgsConstructor @Task(name = "ClusterHealthCheckTask", @@ -33,98 +16,12 @@ import java.util.Map; autoRegister = true, consensual = ConsensualEnum.BROADCAST, timeout = 2 * 60) -public class ClusterHealthCheckTask extends AbstractAsyncMetricsDispatchTask { - private static final ILog log = LogFactory.getLog(ClusterHealthCheckTask.class); - - @Autowired - private HealthCheckResultService healthCheckResultService; - +public class ClusterHealthCheckTask extends AbstractHealthCheckTask { @Autowired private HealthCheckClusterService healthCheckClusterService; @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); - } - - private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - // 获取配置,<配置名,配置信息> - Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); - - // 检查结果 - List resultList = new ArrayList<>(); - - // 遍历Check-Service - List paramList = healthCheckClusterService.getResList(clusterPhy.getId()); - if (ValidateUtils.isEmptyList(paramList)) { - // 当前无该维度的资源,则直接设置为 - resultList.addAll(this.getNoResResult(clusterPhy.getId(), healthCheckClusterService, healthConfigMap)); - } - - // 遍历资源 - for (ClusterPhyParam clusterPhyParam: paramList) { - resultList.addAll(this.checkAndGetResult(healthCheckClusterService, clusterPhyParam, healthConfigMap)); - } - - for (HealthCheckResult checkResult: resultList) { - try { - healthCheckResultService.replace(checkResult); - } catch (Exception e) { - log.error("class=ClusterHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); - } - } - - // 删除10分钟之前的检查结果 - try { - healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); - } catch (Exception e) { - log.error("class=ClusterHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); - } - - return TaskResult.SUCCESS; - } - - private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); - if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { - // 类型不匹配 - continue; - } - - // 记录 - HealthCheckResult checkResult = new HealthCheckResult( - dimensionEnum.getDimension(), - clusterHealthConfig.getCheckNameEnum().getConfigName(), - clusterPhyId, - "-1" - ); - checkResult.setPassed(Constant.YES); - resultList.add(checkResult); - } - - return resultList; - } - - private List checkAndGetResult(AbstractHealthCheckService healthCheckService, - ClusterPhyParam clusterPhyParam, - Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckResult healthCheckResult = healthCheckService.checkAndGetResult(clusterPhyParam, clusterHealthConfig); - if (healthCheckResult == null) { - continue; - } - - // 记录 - resultList.add(healthCheckResult); - } - - return resultList; + public AbstractHealthCheckService getCheckService() { + return healthCheckClusterService; } } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/GroupHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/GroupHealthCheckTask.java index 581a679a..d24f981d 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/GroupHealthCheckTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/GroupHealthCheckTask.java @@ -1,29 +1,13 @@ package com.xiaojukeji.know.streaming.km.task.health; import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.didiglobal.logi.log.ILog; -import com.didiglobal.logi.log.LogFactory; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; -import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; -import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; import com.xiaojukeji.know.streaming.km.core.service.health.checker.group.HealthCheckGroupService; -import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; -import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; @NoArgsConstructor @AllArgsConstructor @@ -33,98 +17,13 @@ import java.util.Map; autoRegister = true, consensual = ConsensualEnum.BROADCAST, timeout = 2 * 60) -public class GroupHealthCheckTask extends AbstractAsyncMetricsDispatchTask { - private static final ILog log = LogFactory.getLog(GroupHealthCheckTask.class); - - @Autowired - private HealthCheckResultService healthCheckResultService; +public class GroupHealthCheckTask extends AbstractHealthCheckTask { @Autowired private HealthCheckGroupService healthCheckGroupService; @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); - } - - private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - // 获取配置,<配置名,配置信息> - Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); - - // 检查结果 - List resultList = new ArrayList<>(); - - // 遍历Check-Service - List paramList = healthCheckGroupService.getResList(clusterPhy.getId()); - if (ValidateUtils.isEmptyList(paramList)) { - // 当前无该维度的资源,则直接设置为 - resultList.addAll(this.getNoResResult(clusterPhy.getId(), healthCheckGroupService, healthConfigMap)); - } - - // 遍历资源 - for (ClusterPhyParam clusterPhyParam: paramList) { - resultList.addAll(this.checkAndGetResult(healthCheckGroupService, clusterPhyParam, healthConfigMap)); - } - - for (HealthCheckResult checkResult: resultList) { - try { - healthCheckResultService.replace(checkResult); - } catch (Exception e) { - log.error("class=GroupHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); - } - } - - // 删除10分钟之前的检查结果 - try { - healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); - } catch (Exception e) { - log.error("class=GroupHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); - } - - return TaskResult.SUCCESS; - } - - private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); - if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { - // 类型不匹配 - continue; - } - - // 记录 - HealthCheckResult checkResult = new HealthCheckResult( - dimensionEnum.getDimension(), - clusterHealthConfig.getCheckNameEnum().getConfigName(), - clusterPhyId, - "-1" - ); - checkResult.setPassed(Constant.YES); - resultList.add(checkResult); - } - - return resultList; - } - - private List checkAndGetResult(AbstractHealthCheckService healthCheckService, - ClusterPhyParam clusterPhyParam, - Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckResult healthCheckResult = healthCheckService.checkAndGetResult(clusterPhyParam, clusterHealthConfig); - if (healthCheckResult == null) { - continue; - } - - // 记录 - resultList.add(healthCheckResult); - } - - return resultList; + public AbstractHealthCheckService getCheckService() { + return healthCheckGroupService; } } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/TopicHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/TopicHealthCheckTask.java index 8badae99..25a1e531 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/TopicHealthCheckTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/TopicHealthCheckTask.java @@ -1,30 +1,13 @@ package com.xiaojukeji.know.streaming.km.task.health; import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.didiglobal.logi.log.ILog; -import com.didiglobal.logi.log.LogFactory; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; -import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; -import com.xiaojukeji.know.streaming.km.common.bean.entity.param.cluster.ClusterPhyParam; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckDimensionEnum; -import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.health.checker.AbstractHealthCheckService; import com.xiaojukeji.know.streaming.km.core.service.health.checker.topic.HealthCheckTopicService; -import com.xiaojukeji.know.streaming.km.core.service.health.checkresult.HealthCheckResultService; -import com.xiaojukeji.know.streaming.km.task.metrics.AbstractAsyncMetricsDispatchTask; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; - @NoArgsConstructor @AllArgsConstructor @Task(name = "TopicHealthCheckTask", @@ -33,98 +16,13 @@ import java.util.Map; autoRegister = true, consensual = ConsensualEnum.BROADCAST, timeout = 2 * 60) -public class TopicHealthCheckTask extends AbstractAsyncMetricsDispatchTask { - private static final ILog log = LogFactory.getLog(TopicHealthCheckTask.class); - - @Autowired - private HealthCheckResultService healthCheckResultService; +public class TopicHealthCheckTask extends AbstractHealthCheckTask { @Autowired private HealthCheckTopicService healthCheckTopicService; @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - return this.calAndUpdateHealthCheckResult(clusterPhy, triggerTimeUnitMs); - } - - private TaskResult calAndUpdateHealthCheckResult(ClusterPhy clusterPhy, long triggerTimeUnitMs) { - // 获取配置,<配置名,配置信息> - Map healthConfigMap = healthCheckResultService.getClusterHealthConfig(clusterPhy.getId()); - - // 检查结果 - List resultList = new ArrayList<>(); - - // 遍历Check-Service - List paramList = healthCheckTopicService.getResList(clusterPhy.getId()); - if (ValidateUtils.isEmptyList(paramList)) { - // 当前无该维度的资源,则直接设置为 - resultList.addAll(this.getNoResResult(clusterPhy.getId(), healthCheckTopicService, healthConfigMap)); - } - - // 遍历资源 - for (ClusterPhyParam clusterPhyParam: paramList) { - resultList.addAll(this.checkAndGetResult(healthCheckTopicService, clusterPhyParam, healthConfigMap)); - } - - for (HealthCheckResult checkResult: resultList) { - try { - healthCheckResultService.replace(checkResult); - } catch (Exception e) { - log.error("class=TopicHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); - } - } - - // 删除10分钟之前的检查结果 - try { - healthCheckResultService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 10 * 60 * 1000)); - } catch (Exception e) { - log.error("class=TopicHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); - } - - return TaskResult.SUCCESS; - } - - private List getNoResResult(Long clusterPhyId, AbstractHealthCheckService healthCheckService, Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckDimensionEnum dimensionEnum = healthCheckService.getHealthCheckDimensionEnum(); - if (!clusterHealthConfig.getCheckNameEnum().getDimensionEnum().equals(dimensionEnum)) { - // 类型不匹配 - continue; - } - - // 记录 - HealthCheckResult checkResult = new HealthCheckResult( - dimensionEnum.getDimension(), - clusterHealthConfig.getCheckNameEnum().getConfigName(), - clusterPhyId, - "-1" - ); - checkResult.setPassed(Constant.YES); - resultList.add(checkResult); - } - - return resultList; - } - - private List checkAndGetResult(AbstractHealthCheckService healthCheckService, - ClusterPhyParam clusterPhyParam, - Map healthConfigMap) { - List resultList = new ArrayList<>(); - - // 进行检查 - for (BaseClusterHealthConfig clusterHealthConfig: healthConfigMap.values()) { - HealthCheckResult healthCheckResult = healthCheckService.checkAndGetResult(clusterPhyParam, clusterHealthConfig); - if (healthCheckResult == null) { - continue; - } - - // 记录 - resultList.add(healthCheckResult); - } - - return resultList; + public AbstractHealthCheckService getCheckService() { + return healthCheckTopicService; } } From a8c779675ae8bf59f43df54c3bd5f41e98e65c3f Mon Sep 17 00:00:00 2001 From: zengqiao Date: Wed, 12 Oct 2022 16:43:16 +0800 Subject: [PATCH 111/145] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=9C=AA=E8=A2=AB?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84import?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../know/streaming/km/rest/api/v3/version/VersionController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/version/VersionController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/version/VersionController.java index 52cc4807..f8e00430 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/version/VersionController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/version/VersionController.java @@ -15,7 +15,6 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; import java.util.List; import java.util.Map; import java.util.SortedMap; From 7294aba59fd85f61935ef95c0a61bbc37e9395d9 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Wed, 12 Oct 2022 16:44:07 +0800 Subject: [PATCH 112/145] =?UTF-8?q?=E6=8C=87=E6=A0=87=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E4=B8=AD=EF=BC=8C=E5=A2=9E=E5=8A=A0=E8=BF=94=E5=9B=9EZK?= =?UTF-8?q?=E7=9A=84=E6=8C=87=E6=A0=87=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../km/biz/version/impl/VersionControlManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java index 52a91520..0460b601 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java @@ -14,7 +14,6 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionControlItem; import com.xiaojukeji.know.streaming.km.common.bean.vo.config.metric.UserMetricConfigVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.version.VersionItemVO; -import com.xiaojukeji.know.streaming.km.common.constant.Constant; import com.xiaojukeji.know.streaming.km.common.enums.version.VersionEnum; import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; import com.xiaojukeji.know.streaming.km.common.utils.VersionUtil; @@ -108,6 +107,7 @@ public class VersionControlManagerImpl implements VersionControlManager { allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_BROKER.getCode()), VersionItemVO.class)); allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_PARTITION.getCode()), VersionItemVO.class)); allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_REPLICATION.getCode()), VersionItemVO.class)); + allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(METRIC_ZOOKEEPER.getCode()), VersionItemVO.class)); allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(WEB_OP.getCode()), VersionItemVO.class)); Map map = allVersionItemVO.stream().collect( From 75e53a96173a9012f30f5d4a4f595d4800ca6fd6 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Wed, 12 Oct 2022 16:45:47 +0800 Subject: [PATCH 113/145] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=9B=86=E7=BE=A4ZK?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E4=B8=AD=E7=BC=BA=E5=B0=91=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=8A=B6=E6=80=81=E5=AD=97=E6=AE=B5=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java index 960b5d5a..477b3bf4 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/zookeeper/ClusterZookeepersOverviewVO.java @@ -14,6 +14,9 @@ public class ClusterZookeepersOverviewVO { @ApiModelProperty(value = "主机ip", example = "121.0.0.1") private String host; + @ApiModelProperty(value = "主机存活状态,1:Live,0:Down", example = "1") + private Integer status; + @ApiModelProperty(value = "端口号", example = "2416") private Integer port; From 8892b5250e774faebda18aac08cea5498035f8bc Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Wed, 12 Oct 2022 19:15:19 +0800 Subject: [PATCH 114/145] update readme add who's using know streaming --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c08c7c4..9cc19762 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,14 @@ ## `Know Streaming` 简介 -`Know Streaming`是一套云原生的Kafka管控平台,脱胎于众多互联网内部多年的Kafka运营实践经验,专注于Kafka运维管控、监控告警、资源治理、多活容灾等核心场景。在用户体验、监控、运维管控上进行了平台化、可视化、智能化的建设,提供一系列特色的功能,极大地方便了用户和运维人员的日常使用,让普通运维人员都能成为Kafka专家。整体具有以下特点: +`Know Streaming`是一套云原生的Kafka管控平台,脱胎于众多互联网内部多年的Kafka运营实践经验,专注于Kafka运维管控、监控告警、资源治理、多活容灾等核心场景。在用户体验、监控、运维管控上进行了平台化、可视化、智能化的建设,提供一系列特色的功能,极大地方便了用户和运维人员的日常使用,让普通运维人员都能成为Kafka专家。 + +我们现在正在收集 Know Streaming 用户信息,以帮助我们进一步改进 Know Streaming。 +请在 [issue#663](https://github.com/didi/KnowStreaming/issues/663) 上提供您的使用信息来支持我们:[谁在使用 Know Streaming](https://github.com/didi/KnowStreaming/issues/663) + + + +整体具有以下特点: - 👀  **零侵入、全覆盖** - 无需侵入改造 `Apache Kafka` ,一键便能纳管 `0.10.x` ~ `3.x.x` 众多版本的Kafka,包括 `ZK` 或 `Raft` 运行模式的版本,同时在兼容架构上具备良好的扩展性,帮助您提升集群管理水平; From 7a29e58453e0d2088a9097a7d58fbdd9c5d91a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=A4=E6=9C=88?= <974226358@qq.com> Date: Wed, 12 Oct 2022 22:08:29 +0800 Subject: [PATCH 115/145] Update faq.md --- docs/user_guide/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user_guide/faq.md b/docs/user_guide/faq.md index 98dfbf83..a91cdf79 100644 --- a/docs/user_guide/faq.md +++ b/docs/user_guide/faq.md @@ -37,7 +37,7 @@ ## 8.4、`Jmx`连接失败如何解决? -- 参看 [Jmx 连接配置&问题解决](./9-attachment#jmx-连接失败问题解决) 说明。 +- 参看 [Jmx 连接配置&问题解决](https://doc.knowstreaming.com/product/9-attachment#91jmx-%E8%BF%9E%E6%8E%A5%E5%A4%B1%E8%B4%A5%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3) 说明。   From 55b34d08ddd883ffb4801808fafa3d4e3b002cf5 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Thu, 13 Oct 2022 15:31:34 +0800 Subject: [PATCH 116/145] update readme --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++++ .github/ISSUE_TEMPLATE/config.yml | 3 +++ .github/ISSUE_TEMPLATE/detail_optimizing.md | 2 ++ .github/ISSUE_TEMPLATE/discussion.md | 12 ------------ .github/ISSUE_TEMPLATE/feature_request.md | 2 ++ 5 files changed, 11 insertions(+), 12 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/discussion.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 959a0795..7ce18733 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -9,12 +9,16 @@ assignees: '' - [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 +- [ ] 你是否希望来认领这个Bug。 + + ### 环境信息 * KnowStreaming version : xxx * Operating System version : xxx * Java version : xxx + ### 重现该问题的步骤 1. xxx diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 30e38e30..3bedae4a 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,8 @@ blank_issues_enabled: true contact_links: + - name: 讨论问题 + url: https://github.com/didi/KnowStreaming/discussions/new + about: 发起问题、讨论 等等 - name: KnowStreaming官网 url: https://knowstreaming.com/ about: KnowStreaming website diff --git a/.github/ISSUE_TEMPLATE/detail_optimizing.md b/.github/ISSUE_TEMPLATE/detail_optimizing.md index a531ac8a..2f95116d 100644 --- a/.github/ISSUE_TEMPLATE/detail_optimizing.md +++ b/.github/ISSUE_TEMPLATE/detail_optimizing.md @@ -8,6 +8,8 @@ assignees: '' --- - [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 +- [ ] 你是否希望来认领这个优化建议。 + ### 环境信息 diff --git a/.github/ISSUE_TEMPLATE/discussion.md b/.github/ISSUE_TEMPLATE/discussion.md deleted file mode 100644 index bf2b8359..00000000 --- a/.github/ISSUE_TEMPLATE/discussion.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: 讨论/discussion -about: 开启一个关于KnowStreaming的讨论 -title: '' -labels: discussion -assignees: '' - ---- - -## 讨论主题 - -... diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index fe7e88fb..49262909 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -9,6 +9,8 @@ assignees: '' - [ ] 我在 [issues](https://github.com/didi/KnowStreaming/issues) 中并未搜索到与此相关的功能需求。 - [ ] 我在 [release notes] (https://github.com/didi/KnowStreaming/releases)已经发布的版本中并没有搜到相关功能. +- [ ] 你是否希望来认领这个Feature。 + ## 这里描述需求 From d071e311062599659012e9e43a9a525902ba9d7a Mon Sep 17 00:00:00 2001 From: Richard <49510754+f1558@users.noreply.github.com> Date: Thu, 13 Oct 2022 18:00:43 +0800 Subject: [PATCH 117/145] fix issue: * [issue #666] Fix the type of role phase in ks_km_zookeeper table --- km-dist/init/sql/ddl-ks-km.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/km-dist/init/sql/ddl-ks-km.sql b/km-dist/init/sql/ddl-ks-km.sql index 89f04034..57d1cdb2 100644 --- a/km-dist/init/sql/ddl-ks-km.sql +++ b/km-dist/init/sql/ddl-ks-km.sql @@ -363,11 +363,11 @@ CREATE TABLE `ks_km_zookeeper` ( `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '物理集群ID', `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper主机名', `port` int(16) NOT NULL DEFAULT '-1' COMMENT 'zookeeper端口', - `role` int(16) NOT NULL DEFAULT '-1' COMMENT '角色, leader follower observer', + `role` varchar(16) NOT NULL DEFAULT '-1' COMMENT '角色, leader follower observer', `version` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper版本', `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态: 1存活,0未存活,11存活但是4字命令使用不了', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', PRIMARY KEY (`id`), UNIQUE KEY `uniq_cluster_phy_id_host_port` (`cluster_phy_id`,`host`, `port`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Zookeeper信息表'; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Zookeeper信息表'; From 99be2d704f9a6473b61e8f26e76ecd47c037dcc5 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Thu, 13 Oct 2022 18:30:13 +0800 Subject: [PATCH 118/145] update readme --- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 49262909..57d66909 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -8,7 +8,7 @@ assignees: '' --- - [ ] 我在 [issues](https://github.com/didi/KnowStreaming/issues) 中并未搜索到与此相关的功能需求。 -- [ ] 我在 [release notes] (https://github.com/didi/KnowStreaming/releases)已经发布的版本中并没有搜到相关功能. +- [ ] 我在 [release note](https://github.com/didi/KnowStreaming/releases) 已经发布的版本中并没有搜到相关功能. - [ ] 你是否希望来认领这个Feature。 From 656dfc2285cac7d1acb7aec5f968904439d6ca42 Mon Sep 17 00:00:00 2001 From: shirenchuang Date: Thu, 13 Oct 2022 18:49:06 +0800 Subject: [PATCH 119/145] update readme --- .github/ISSUE_TEMPLATE/bug_report.md | 3 ++- .github/ISSUE_TEMPLATE/detail_optimizing.md | 4 +++- .github/ISSUE_TEMPLATE/feature_request.md | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 7ce18733..651a9d95 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -9,8 +9,9 @@ assignees: '' - [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 -- [ ] 你是否希望来认领这个Bug。 + 你是否希望来认领这个Bug。 + 「 Y / N 」 ### 环境信息 diff --git a/.github/ISSUE_TEMPLATE/detail_optimizing.md b/.github/ISSUE_TEMPLATE/detail_optimizing.md index 2f95116d..bbf168f1 100644 --- a/.github/ISSUE_TEMPLATE/detail_optimizing.md +++ b/.github/ISSUE_TEMPLATE/detail_optimizing.md @@ -8,8 +8,10 @@ assignees: '' --- - [ ] 我已经在 [issues](https://github.com/didi/KnowStreaming/issues) 搜索过相关问题了,并没有重复的。 -- [ ] 你是否希望来认领这个优化建议。 + 你是否希望来认领这个优化建议。 + + 「 Y / N 」 ### 环境信息 diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 57d66909..7bfc5d9b 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -9,7 +9,10 @@ assignees: '' - [ ] 我在 [issues](https://github.com/didi/KnowStreaming/issues) 中并未搜索到与此相关的功能需求。 - [ ] 我在 [release note](https://github.com/didi/KnowStreaming/releases) 已经发布的版本中并没有搜到相关功能. -- [ ] 你是否希望来认领这个Feature。 + +你是否希望来认领这个Feature。 + +「 Y / N 」 ## 这里描述需求 From d5079a1b7581677f184aab32ac5bfe49370558b6 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Thu, 13 Oct 2022 18:50:41 +0800 Subject: [PATCH 120/145] =?UTF-8?q?=E4=BF=AE=E5=A4=8DZK=E5=85=83=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E8=A1=A8role=E5=AD=97=E6=AE=B5=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/install_guide/版本升级手册.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install_guide/版本升级手册.md b/docs/install_guide/版本升级手册.md index efc01399..903b71b3 100644 --- a/docs/install_guide/版本升级手册.md +++ b/docs/install_guide/版本升级手册.md @@ -14,7 +14,7 @@ CREATE TABLE `ks_km_zookeeper` ( `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '物理集群ID', `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper主机名', `port` int(16) NOT NULL DEFAULT '-1' COMMENT 'zookeeper端口', - `role` int(16) NOT NULL DEFAULT '-1' COMMENT '角色, leader follower observer', + `role` varchar(16) NOT NULL DEFAULT '' COMMENT '角色, leader follower observer', `version` varchar(128) NOT NULL DEFAULT '' COMMENT 'zookeeper版本', `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态: 1存活,0未存活,11存活但是4字命令使用不了', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', From 5f21e5a728580d91a028b39888de91ad33ffec86 Mon Sep 17 00:00:00 2001 From: _haoqi <1148648445@qq.com> Date: Fri, 14 Oct 2022 11:53:48 +0800 Subject: [PATCH 121/145] =?UTF-8?q?=E4=BF=AE=E6=94=B9zk-Latency=20avg?= =?UTF-8?q?=E4=B8=BA=E5=B0=8F=E6=95=B0=E6=97=B6=E7=9A=84=E6=95=B0=E5=80=BC?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E5=BC=82=E5=B8=B8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bean/entity/zookeeper/fourletterword/MonitorCmdData.java | 2 +- .../bean/entity/zookeeper/fourletterword/ServerCmdData.java | 2 +- .../zookeeper/fourletterword/parser/MonitorCmdDataParser.java | 2 +- .../zookeeper/fourletterword/parser/ServerCmdDataParser.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java index 7ea1339b..2fb3c9da 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/MonitorCmdData.java @@ -22,7 +22,7 @@ import lombok.Data; @Data public class MonitorCmdData extends BaseFourLetterWordCmdData { private String zkVersion; - private Long zkAvgLatency; + private Float zkAvgLatency; private Long zkMaxLatency; private Long zkMinLatency; private Long zkPacketsReceived; diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java index 38bd2cf9..883231d6 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/ServerCmdData.java @@ -17,7 +17,7 @@ import lombok.Data; @Data public class ServerCmdData extends BaseFourLetterWordCmdData { private String zkVersion; - private Long zkAvgLatency; + private Float zkAvgLatency; private Long zkMaxLatency; private Long zkMinLatency; private Long zkPacketsReceived; diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java index a33f4da3..55921c12 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/zookeeper/fourletterword/parser/MonitorCmdDataParser.java @@ -57,7 +57,7 @@ public class MonitorCmdDataParser implements FourLetterWordDataParser Date: Fri, 14 Oct 2022 11:16:51 +0800 Subject: [PATCH 122/145] fix issue: * [issue #662] Fix deadlocks caused by adding data using MySQL's REPLACE method --- .../streaming/km/common/constant/Constant.java | 1 + .../checkresult/HealthCheckResultService.java | 2 ++ .../impl/HealthCheckResultServiceImpl.java | 15 +++++++++++++++ .../mysql/health/HealthCheckResultDAO.java | 4 ++++ .../resources/mybatis/HealthCheckResultMapper.xml | 12 ++++++++++++ .../km/task/health/AbstractHealthCheckTask.java | 10 ++++------ 6 files changed, 38 insertions(+), 6 deletions(-) diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java index a91f0809..639ad0f3 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java @@ -43,6 +43,7 @@ public class Constant { */ public static final Integer DEFAULT_CLUSTER_HEALTH_SCORE = 90; + public static final Integer PER_BATCH_MAX_VALUE = 100; public static final String DEFAULT_USER_NAME = "know-streaming-app"; diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/HealthCheckResultService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/HealthCheckResultService.java index 19cb292a..6aaddcdb 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/HealthCheckResultService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/HealthCheckResultService.java @@ -20,4 +20,6 @@ public interface HealthCheckResultService { List getResHealthCheckResult(Long clusterPhyId, Integer dimension, String resNme); Map getClusterHealthConfig(Long clusterPhyId); + + void batchReplace(Long clusterPhyId, List healthCheckResults); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/impl/HealthCheckResultServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/impl/HealthCheckResultServiceImpl.java index 09c30a1b..cad2f396 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/impl/HealthCheckResultServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/health/checkresult/impl/HealthCheckResultServiceImpl.java @@ -3,10 +3,12 @@ package com.xiaojukeji.know.streaming.km.core.service.health.checkresult.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; +import com.google.common.collect.Lists; import com.xiaojukeji.know.streaming.km.common.bean.entity.config.healthcheck.BaseClusterHealthConfig; import com.xiaojukeji.know.streaming.km.common.bean.entity.health.HealthCheckResult; import com.xiaojukeji.know.streaming.km.common.bean.po.config.PlatformClusterConfigPO; import com.xiaojukeji.know.streaming.km.common.bean.po.health.HealthCheckResultPO; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; import com.xiaojukeji.know.streaming.km.common.enums.config.ConfigGroupEnum; import com.xiaojukeji.know.streaming.km.common.enums.health.HealthCheckNameEnum; import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; @@ -88,4 +90,17 @@ public class HealthCheckResultServiceImpl implements HealthCheckResultService { } return configMap; } + + @Override + public void batchReplace(Long clusterPhyId, List healthCheckResults) { + List> healthCheckResultPartitions = Lists.partition(healthCheckResults, Constant.PER_BATCH_MAX_VALUE); + for (List checkResultPartition : healthCheckResultPartitions) { + List healthCheckResultPos = ConvertUtil.list2List(checkResultPartition, HealthCheckResultPO.class); + try { + healthCheckResultDAO.batchReplace(healthCheckResultPos); + } catch (Exception e) { + log.error("method=batchReplace||clusterPhyId={}||checkResultList={}||errMsg=exception!", clusterPhyId, healthCheckResultPos, e); + } + } + } } diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/health/HealthCheckResultDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/health/HealthCheckResultDAO.java index 225437d7..64830fd1 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/health/HealthCheckResultDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/health/HealthCheckResultDAO.java @@ -4,7 +4,11 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.xiaojukeji.know.streaming.km.common.bean.po.health.HealthCheckResultPO; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface HealthCheckResultDAO extends BaseMapper { int replace(HealthCheckResultPO healthCheckResultPO); + + int batchReplace(List healthCheckResultPos); } diff --git a/km-persistence/src/main/resources/mybatis/HealthCheckResultMapper.xml b/km-persistence/src/main/resources/mybatis/HealthCheckResultMapper.xml index bc1bf8ca..076b7522 100644 --- a/km-persistence/src/main/resources/mybatis/HealthCheckResultMapper.xml +++ b/km-persistence/src/main/resources/mybatis/HealthCheckResultMapper.xml @@ -20,4 +20,16 @@ VALUES (#{dimension}, #{configName}, #{clusterPhyId}, #{resName}, #{passed}) + + + insert into ks_km_health_check_result (dimension, config_name, cluster_phy_id, res_name, passed) + values + + (#{item.dimension}, #{item.configName}, #{item.clusterPhyId}, #{item.resName}, #{item.passed}) + + on duplicate key update + dimension = dimension, config_name = config_name, cluster_phy_id = cluster_phy_id, + res_name = res_name, passed = passed + + diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java index 1f6c83ff..4d614881 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/health/AbstractHealthCheckTask.java @@ -52,12 +52,10 @@ public abstract class AbstractHealthCheckTask extends AbstractAsyncMetricsDispat resultList.addAll(this.checkAndGetResult(clusterPhyParam, healthConfigMap)); } - for (HealthCheckResult checkResult: resultList) { - try { - healthCheckResultService.replace(checkResult); - } catch (Exception e) { - log.error("class=AbstractHealthCheckTask||method=processSubTask||clusterPhyId={}||checkResult={}||errMsg=exception!", clusterPhy.getId(), checkResult, e); - } + try { + healthCheckResultService.batchReplace(clusterPhy.getId(), resultList); + } catch (Exception e) { + log.error("class=AbstractHealthCheckTask||method=processSubTask||clusterPhyId={}||errMsg=exception!", clusterPhy.getId(), e); } // 删除10分钟之前的检查结果 From 2f0b18b005fd026b711194cb517a3d4620fdaaf3 Mon Sep 17 00:00:00 2001 From: chenzy Date: Sun, 16 Oct 2022 22:57:50 +0800 Subject: [PATCH 123/145] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E6=9C=89=E8=AF=AF=E7=9A=84bug=EF=BC=8C?= =?UTF-8?q?=E7=94=B1=E5=8E=9F=E5=85=88=E7=9A=8412=E5=B0=8F=E6=97=B6?= =?UTF-8?q?=E5=88=B6=E6=94=B9=E4=B8=BA24=E5=B0=8F=E6=97=B6=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layout-clusters-fe/src/components/CardBar/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/km-console/packages/layout-clusters-fe/src/components/CardBar/index.tsx b/km-console/packages/layout-clusters-fe/src/components/CardBar/index.tsx index 954839cd..0de8e813 100644 --- a/km-console/packages/layout-clusters-fe/src/components/CardBar/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/components/CardBar/index.tsx @@ -138,7 +138,7 @@ const CardBar = (props: CardBarProps) => { dataIndex: 'updateTime', key: 'updateTime', render: (value: number) => { - return moment(value).format('YYYY-MM-DD hh:mm:ss'); + return moment(value).format('YYYY-MM-DD HH:mm:ss'); }, }, { From 4133981048e4f2dd4c5026d779cecb5e067b970d Mon Sep 17 00:00:00 2001 From: zengqiao Date: Mon, 17 Oct 2022 10:34:21 +0800 Subject: [PATCH 124/145] =?UTF-8?q?=E8=A1=A5=E5=85=85Kafka-Group=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/install_guide/版本升级手册.md | 23 +++++++++++++++++++++++ km-dist/init/sql/ddl-ks-km.sql | 18 ++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/docs/install_guide/版本升级手册.md b/docs/install_guide/版本升级手册.md index 903b71b3..dfa4a8e2 100644 --- a/docs/install_guide/版本升级手册.md +++ b/docs/install_guide/版本升级手册.md @@ -7,6 +7,8 @@ ### 6.2.0、升级至 `master` 版本 +**SQL 变更** + ```sql DROP TABLE IF EXISTS `ks_km_zookeeper`; CREATE TABLE `ks_km_zookeeper` ( @@ -22,8 +24,29 @@ CREATE TABLE `ks_km_zookeeper` ( PRIMARY KEY (`id`), UNIQUE KEY `uniq_cluster_phy_id_host_port` (`cluster_phy_id`,`host`, `port`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Zookeeper信息表'; + + +DROP TABLE IF EXISTS `ks_km_group`; +CREATE TABLE `ks_km_group` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `name` varchar(192) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Group名称', + `member_count` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '成员数', + `topic_members` text CHARACTER SET utf8 COMMENT 'group消费的topic列表', + `partition_assignor` varchar(255) CHARACTER SET utf8 NOT NULL COMMENT '分配策略', + `coordinator_id` int(11) NOT NULL COMMENT 'group协调器brokerId', + `type` int(11) NOT NULL COMMENT 'group类型 0:consumer 1:connector', + `state` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '状态', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_name` (`cluster_phy_id`,`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Group信息表'; + ``` +--- + ### 6.2.1、升级至 `v3.0.0` 版本 diff --git a/km-dist/init/sql/ddl-ks-km.sql b/km-dist/init/sql/ddl-ks-km.sql index 57d1cdb2..907ff355 100644 --- a/km-dist/init/sql/ddl-ks-km.sql +++ b/km-dist/init/sql/ddl-ks-km.sql @@ -371,3 +371,21 @@ CREATE TABLE `ks_km_zookeeper` ( PRIMARY KEY (`id`), UNIQUE KEY `uniq_cluster_phy_id_host_port` (`cluster_phy_id`,`host`, `port`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Zookeeper信息表'; + + +DROP TABLE IF EXISTS `ks_km_group`; +CREATE TABLE `ks_km_group` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `name` varchar(192) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Group名称', + `member_count` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '成员数', + `topic_members` text CHARACTER SET utf8 COMMENT 'group消费的topic列表', + `partition_assignor` varchar(255) CHARACTER SET utf8 NOT NULL COMMENT '分配策略', + `coordinator_id` int(11) NOT NULL COMMENT 'group协调器brokerId', + `type` int(11) NOT NULL COMMENT 'group类型 0:consumer 1:connector', + `state` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '状态', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_name` (`cluster_phy_id`,`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Group信息表'; \ No newline at end of file From 13d8fd55c8f6563f08d1a9e1011a4659eeb98167 Mon Sep 17 00:00:00 2001 From: "night.liang" Date: Tue, 18 Oct 2022 20:16:40 +0800 Subject: [PATCH 125/145] fix ldap bug --- .../km/common/utils/ValidateUtils.java | 15 ++++- .../login/ldap/remote/LdapAuthentication.java | 55 ++++++++++++++----- 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ValidateUtils.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ValidateUtils.java index 5060e7ea..fbe94674 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ValidateUtils.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/utils/ValidateUtils.java @@ -2,6 +2,7 @@ package com.xiaojukeji.know.streaming.km.common.utils; import org.apache.commons.lang.StringUtils; +import java.lang.reflect.Array; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -56,6 +57,18 @@ public class ValidateUtils { return false; } + public static boolean isNotEmpty(T[] array) { + return !isEmpty(array); + } + + public static boolean isEmpty(Object[] array) { + return getLength(array) == 0; + } + + public static int getLength(Object array) { + return array == null ? 0 : Array.getLength(array); + } + /** * 是空字符串 */ @@ -65,7 +78,7 @@ public class ValidateUtils { } else if (isNull(seq1) || isNull(seq2) || seq1.size() != seq2.size()) { return false; } - for (Object elem: seq1) { + for (Object elem : seq1) { if (!seq2.contains(elem)) { return false; } diff --git a/km-extends/km-account/src/main/java/com/xiaojukeji/know/streaming/km/account/login/ldap/remote/LdapAuthentication.java b/km-extends/km-account/src/main/java/com/xiaojukeji/know/streaming/km/account/login/ldap/remote/LdapAuthentication.java index 82043877..8f907dbe 100644 --- a/km-extends/km-account/src/main/java/com/xiaojukeji/know/streaming/km/account/login/ldap/remote/LdapAuthentication.java +++ b/km-extends/km-account/src/main/java/com/xiaojukeji/know/streaming/km/account/login/ldap/remote/LdapAuthentication.java @@ -5,6 +5,7 @@ import com.didiglobal.logi.security.exception.LogiSecurityException; import com.xiaojukeji.know.streaming.km.account.KmAccountConfig; import com.xiaojukeji.know.streaming.km.account.common.ldap.LdapPrincipal; import com.xiaojukeji.know.streaming.km.account.common.ldap.exception.LdapException; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -12,6 +13,8 @@ import org.springframework.stereotype.Component; import javax.naming.Context; import javax.naming.NamingEnumeration; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.ldap.InitialLdapContext; @@ -71,7 +74,7 @@ public class LdapAuthentication { env.put(Context.SECURITY_PRINCIPAL, kmAccountConfig.getSecurityPrincipal()); env.put(Context.SECURITY_CREDENTIALS, kmAccountConfig.getSecurityCredentials()); try { - return new InitialLdapContext(env, null); + return new InitialLdapContext(env, null); } catch (Exception e) { LOGGER.error("method=getLdapContext||errMsg=exception", e); @@ -101,18 +104,21 @@ public class LdapAuthentication { // maybe more than one element while (en.hasMoreElements()) { - Object obj = en.nextElement(); - if (obj instanceof SearchResult) { - SearchResult si = (SearchResult) obj; - + SearchResult obj = en.nextElement(); + if (!ValidateUtils.isNull(obj)) { // 携带LDAP更多元信息以填充用户元信息 LdapPrincipal ldapPrincipal = new LdapPrincipal(); - ldapPrincipal.setUserDN(si.getName() + "," + kmAccountConfig.getLdapBaseDN()); - ldapPrincipal.setSAMAccountName(this.keyValueSplit(si.getAttributes().get("samaccountname").toString())); - ldapPrincipal.setDepartment(this.keyValueSplit(si.getAttributes().get("department").toString())); - ldapPrincipal.setCompany(this.keyValueSplit(si.getAttributes().get("company").toString())); - ldapPrincipal.setDisplayName(this.keyValueSplit(si.getAttributes().get("displayname").toString())); - ldapPrincipal.setMail(this.keyValueSplit(si.getAttributes().get("mail").toString())); + ldapPrincipal.setUserDN(obj.getName() + "," + kmAccountConfig.getLdapBaseDN()); + + Attributes attributes = obj.getAttributes(); + //校验成功后 在获取值 + if (!ValidateUtils.isNull(attributes)) { + ldapPrincipal.setSAMAccountName(getStringValueFromAttributes(attributes, "samaccountname")); + ldapPrincipal.setDepartment(getStringValueFromAttributes(attributes, "department")); + ldapPrincipal.setCompany(getStringValueFromAttributes(attributes, "company")); + ldapPrincipal.setDisplayName(getStringValueFromAttributes(attributes, "displayname")); + ldapPrincipal.setMail(getStringValueFromAttributes(attributes, "mail")); + } return ldapPrincipal; } } @@ -126,6 +132,29 @@ public class LdapAuthentication { } } + private String getStringValueFromAttributes(Attributes attributes, String attrId) { + //增加 多重校验 + int two = 2; + Attribute attribute = attributes.get(attrId); + if (ValidateUtils.isNull(attribute)) { + return ""; + } + + String str = attribute.toString(); + if (ValidateUtils.isBlank(str)) { + return ""; + } + //分割字符串 + String[] split = str.split(":\\s+"); + if (ValidateUtils.isNotEmpty(split)) { + if (split.length >= two) { + return split[1]; + } + } + + return ""; + } + private void closeLdapContext(LdapContext ctx) { if (ctx == null) { return; @@ -137,8 +166,4 @@ public class LdapAuthentication { LOGGER.error("method=closeLdapContext||errMsg=exception", e); } } - - public String keyValueSplit(String keyValue){ - return keyValue.split(":\\s+")[1]; - } } From d8aa3d64dfb979f7e4469f53cb7fc3ce76fd3b43 Mon Sep 17 00:00:00 2001 From: dianyang12138 <52749802+dianyang12138@users.noreply.github.com> Date: Fri, 14 Oct 2022 16:44:38 +0800 Subject: [PATCH 126/145] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8Des=E6=A8=A1?= =?UTF-8?q?=E7=89=88=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/init_es_template.sh | 117 ++++++++++++++---- .../km/common/constant/ESIndexConstant.java | 25 +--- km-dist/docker/manager/es_template_create.sh | 111 +++++++++++++---- .../init/template/ks_kafka_replication_metric | 45 ++++++- km-dist/init/template/template.sh | 117 ++++++++++++++---- 5 files changed, 312 insertions(+), 103 deletions(-) diff --git a/bin/init_es_template.sh b/bin/init_es_template.sh index e6beba96..86fcfb66 100644 --- a/bin/init_es_template.sh +++ b/bin/init_es_template.sh @@ -439,7 +439,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esaddr}:${port}/_template/ks_kafka_replication_metric -d '{ "order" : 10, "index_patterns" : [ - "ks_kafka_partition_metric*" + "ks_kafka_replication_metric*" ], "settings" : { "index" : { @@ -500,30 +500,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }[root@10-255-0-23 template]# cat ks_kafka_replication_metric -PUT _template/ks_kafka_replication_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_replication_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - }' + }' curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esaddr}:${port}/_template/ks_kafka_topic_metric -d '{ "order" : 10, @@ -640,7 +617,92 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }' + }' + +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_zookeeper_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + }' for i in {0..6}; do @@ -650,6 +712,7 @@ do curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_group_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_partition_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_replication_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_zookeeper_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_topic_metric${logdate} || \ exit 2 -done \ No newline at end of file +done diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java index 64aef24f..1f5654d0 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/ESIndexConstant.java @@ -558,7 +558,7 @@ public class ESIndexConstant { public final static String REPLICATION_TEMPLATE = "{\n" + " \"order\" : 10,\n" + " \"index_patterns\" : [\n" + - " \"ks_kafka_partition_metric*\"\n" + + " \"ks_kafka_replication_metric*\"\n" + " ],\n" + " \"settings\" : {\n" + " \"index\" : {\n" + @@ -619,29 +619,6 @@ public class ESIndexConstant { " }\n" + " },\n" + " \"aliases\" : { }\n" + - " }[root@10-255-0-23 template]# cat ks_kafka_replication_metric\n" + - "PUT _template/ks_kafka_replication_metric\n" + - "{\n" + - " \"order\" : 10,\n" + - " \"index_patterns\" : [\n" + - " \"ks_kafka_replication_metric*\"\n" + - " ],\n" + - " \"settings\" : {\n" + - " \"index\" : {\n" + - " \"number_of_shards\" : \"10\"\n" + - " }\n" + - " },\n" + - " \"mappings\" : {\n" + - " \"properties\" : {\n" + - " \"timestamp\" : {\n" + - " \"format\" : \"yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis\",\n" + - " \"index\" : true,\n" + - " \"type\" : \"date\",\n" + - " \"doc_values\" : true\n" + - " }\n" + - " }\n" + - " },\n" + - " \"aliases\" : { }\n" + " }"; public final static String ZOOKEEPER_INDEX = "ks_kafka_zookeeper_metric"; diff --git a/km-dist/docker/manager/es_template_create.sh b/km-dist/docker/manager/es_template_create.sh index 615bf54d..b52d4291 100644 --- a/km-dist/docker/manager/es_template_create.sh +++ b/km-dist/docker/manager/es_template_create.sh @@ -443,7 +443,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_replication_metric -d '{ "order" : 10, "index_patterns" : [ - "ks_kafka_partition_metric*" + "ks_kafka_replication_metric*" ], "settings" : { "index" : { @@ -504,29 +504,6 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }[root@10-255-0-23 template]# cat ks_kafka_replication_metric -PUT _template/ks_kafka_replication_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_replication_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } }' curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_topic_metric -d '{ @@ -646,6 +623,91 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl "aliases" : { } }' +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_zookeeper_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + }' + for i in {0..6}; do logdate=_$(date -d "${i} day ago" +%Y-%m-%d) @@ -654,6 +716,7 @@ do curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_group_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_partition_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_replication_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_zookeeper_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_topic_metric${logdate} || \ exit 2 done diff --git a/km-dist/init/template/ks_kafka_replication_metric b/km-dist/init/template/ks_kafka_replication_metric index b7beda54..c9c254be 100644 --- a/km-dist/init/template/ks_kafka_replication_metric +++ b/km-dist/init/template/ks_kafka_replication_metric @@ -11,6 +11,49 @@ PUT _template/ks_kafka_replication_metric }, "mappings" : { "properties" : { + "brokerId" : { + "type" : "long" + }, + "partitionId" : { + "type" : "long" + }, + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "topic" : { + "type" : "keyword" + }, + "metrics" : { + "properties" : { + "LogStartOffset" : { + "type" : "float" + }, + "Messages" : { + "type" : "float" + }, + "LogEndOffset" : { + "type" : "float" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, "timestamp" : { "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", "index" : true, @@ -20,4 +63,4 @@ PUT _template/ks_kafka_replication_metric } }, "aliases" : { } - } \ No newline at end of file + } diff --git a/km-dist/init/template/template.sh b/km-dist/init/template/template.sh index e6beba96..86fcfb66 100644 --- a/km-dist/init/template/template.sh +++ b/km-dist/init/template/template.sh @@ -439,7 +439,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esaddr}:${port}/_template/ks_kafka_replication_metric -d '{ "order" : 10, "index_patterns" : [ - "ks_kafka_partition_metric*" + "ks_kafka_replication_metric*" ], "settings" : { "index" : { @@ -500,30 +500,7 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }[root@10-255-0-23 template]# cat ks_kafka_replication_metric -PUT _template/ks_kafka_replication_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_replication_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - }' + }' curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esaddr}:${port}/_template/ks_kafka_topic_metric -d '{ "order" : 10, @@ -640,7 +617,92 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }' + }' + +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_zookeeper_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + }' for i in {0..6}; do @@ -650,6 +712,7 @@ do curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_group_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_partition_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_replication_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_zookeeper_metric${logdate} && \ curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_topic_metric${logdate} || \ exit 2 -done \ No newline at end of file +done From 586b37caa0696a2e3504602a7023224087b9c4ad Mon Sep 17 00:00:00 2001 From: Richard <49510754+f1558@users.noreply.github.com> Date: Wed, 19 Oct 2022 13:52:51 +0800 Subject: [PATCH 127/145] fix issue: * [issue #700] Adjust the prompt and replace the Arrays.asList() with the Collections.singletonList() --- .../know/streaming/km/biz/group/impl/GroupManagerImpl.java | 2 +- .../streaming/km/core/service/group/impl/GroupServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java index 5ccc3e98..ff1f476b 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java @@ -172,7 +172,7 @@ public class GroupManagerImpl implements GroupManager { } if (!ConsumerGroupState.EMPTY.equals(description.state()) && !ConsumerGroupState.DEAD.equals(description.state())) { - return Result.buildFromRSAndMsg(ResultStatus.KAFKA_OPERATE_FAILED, String.format("group处于%s, 重置失败(仅Empty情况可重置)", GroupStateEnum.getByRawState(description.state()).getState())); + return Result.buildFromRSAndMsg(ResultStatus.KAFKA_OPERATE_FAILED, String.format("group处于%s, 重置失败(仅Empty | Dead 情况可重置)", GroupStateEnum.getByRawState(description.state()).getState())); } // 获取offset diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java index 4cf29d2a..1789671b 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java @@ -104,7 +104,7 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group try { DescribeConsumerGroupsResult describeConsumerGroupsResult = adminClient.describeConsumerGroups( - Arrays.asList(groupName), + Collections.singletonList(groupName), new DescribeConsumerGroupsOptions().timeoutMs(KafkaConstant.ADMIN_CLIENT_REQUEST_TIME_OUT_UNIT_MS).includeAuthorizedOperations(false) ); From 05c52cd67280ab6874b1f053d264169362e824ed Mon Sep 17 00:00:00 2001 From: zengqiao Date: Thu, 20 Oct 2022 11:48:27 +0800 Subject: [PATCH 128/145] =?UTF-8?q?[Feature]=20=E9=9B=86=E7=BE=A4Group?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=8C=89=E7=85=A7Group=E7=BB=B4=E5=BA=A6?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=B1=95=E7=A4=BA=20(#580)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../streaming/km/biz/group/GroupManager.java | 9 + .../km/biz/group/impl/GroupManagerImpl.java | 122 ++++++++-- .../km/biz/topic/TopicStateManager.java | 6 +- .../biz/topic/impl/TopicStateManagerImpl.java | 25 ++ .../dto/cluster/ClusterGroupSummaryDTO.java | 18 ++ .../km/common/bean/entity/group/Group.java | 74 ++++++ .../bean/entity/group/GroupTopicMember.java | 27 +++ .../common/bean/po/group/GroupMemberPO.java | 14 +- .../km/common/bean/po/group/GroupPO.java | 61 +++++ .../common/bean/vo/group/GroupOverviewVO.java | 27 +++ .../bean/vo/group/GroupTopicOverviewVO.java | 2 +- .../common/constant/PaginationConstant.java | 10 + .../km/common/converter/GroupConverter.java | 62 +++++ .../km/common/enums/group/GroupTypeEnum.java | 36 +++ .../km/core/service/group/GroupService.java | 57 +++-- .../group/impl/GroupMetricServiceImpl.java | 3 +- .../service/group/impl/GroupServiceImpl.java | 226 +++++++++++++----- .../km/persistence/mysql/group/GroupDAO.java | 9 + .../v3/cluster/ClusterGroupsController.java | 22 +- .../km/rest/api/v3/group/GroupController.java | 2 +- .../api/v3/topic/TopicStateController.java | 15 +- .../km/task/metadata/SyncKafkaGroupTask.java | 123 +++------- 22 files changed, 744 insertions(+), 206 deletions(-) create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterGroupSummaryDTO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/Group.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/GroupTopicMember.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupPO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupOverviewVO.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/GroupConverter.java create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/group/GroupTypeEnum.java create mode 100644 km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/group/GroupDAO.java diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/GroupManager.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/GroupManager.java index 5c1518ca..a3686c03 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/GroupManager.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/GroupManager.java @@ -1,11 +1,14 @@ package com.xiaojukeji.know.streaming.km.biz.group; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterGroupSummaryDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.group.GroupOffsetResetDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.TopicPartitionKS; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicConsumedDetailVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException; @@ -22,6 +25,10 @@ public interface GroupManager { String searchGroupKeyword, PaginationBaseDTO dto); + PaginationResult pagingGroupTopicMembers(Long clusterPhyId, String groupName, PaginationBaseDTO dto); + + PaginationResult pagingClusterGroupsOverview(Long clusterPhyId, ClusterGroupSummaryDTO dto); + PaginationResult pagingGroupTopicConsumedMetrics(Long clusterPhyId, String topicName, String groupName, @@ -31,4 +38,6 @@ public interface GroupManager { Result> listClusterPhyGroupPartitions(Long clusterPhyId, String groupName, Long startTime, Long endTime); Result resetGroupOffsets(GroupOffsetResetDTO dto, String operator) throws Exception; + + List getGroupTopicOverviewVOList (Long clusterPhyId, List groupMemberPOList); } diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java index ff1f476b..97d464ed 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java @@ -3,11 +3,14 @@ package com.xiaojukeji.know.streaming.km.biz.group.impl; import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; import com.xiaojukeji.know.streaming.km.biz.group.GroupManager; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterGroupSummaryDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.group.GroupOffsetResetDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.partition.PartitionOffsetDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; import com.xiaojukeji.know.streaming.km.common.bean.entity.group.GroupTopic; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.GroupTopicMember; import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.GroupMetrics; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; @@ -15,11 +18,15 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.Topic; import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.TopicPartitionKS; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicConsumedDetailVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; +import com.xiaojukeji.know.streaming.km.common.constant.PaginationConstant; +import com.xiaojukeji.know.streaming.km.common.converter.GroupConverter; import com.xiaojukeji.know.streaming.km.common.enums.AggTypeEnum; import com.xiaojukeji.know.streaming.km.common.enums.OffsetTypeEnum; +import com.xiaojukeji.know.streaming.km.common.enums.SortTypeEnum; import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException; import com.xiaojukeji.know.streaming.km.common.exception.NotExistException; @@ -71,30 +78,60 @@ public class GroupManagerImpl implements GroupManager { String searchGroupKeyword, PaginationBaseDTO dto) { PaginationResult paginationResult = groupService.pagingGroupMembers(clusterPhyId, topicName, groupName, searchTopicKeyword, searchGroupKeyword, dto); - if (paginationResult.failed()) { - return PaginationResult.buildFailure(paginationResult, dto); - } if (!paginationResult.hasData()) { return PaginationResult.buildSuc(new ArrayList<>(), paginationResult); } - // 获取指标 - Result> metricsListResult = groupMetricService.listLatestMetricsAggByGroupTopicFromES( - clusterPhyId, - paginationResult.getData().getBizData().stream().map(elem -> new GroupTopic(elem.getGroupName(), elem.getTopicName())).collect(Collectors.toList()), - Arrays.asList(GroupMetricVersionItems.GROUP_METRIC_LAG), - AggTypeEnum.MAX - ); - if (metricsListResult.failed()) { - // 如果查询失败,则输出错误信息,但是依旧进行已有数据的返回 - log.error("method=pagingGroupMembers||clusterPhyId={}||topicName={}||groupName={}||result={}||errMsg=search es failed", clusterPhyId, topicName, groupName, metricsListResult); + List groupTopicVOList = this.getGroupTopicOverviewVOList(clusterPhyId, paginationResult.getData().getBizData()); + + return PaginationResult.buildSuc(groupTopicVOList, paginationResult); + } + + @Override + public PaginationResult pagingGroupTopicMembers(Long clusterPhyId, String groupName, PaginationBaseDTO dto) { + Group group = groupService.getGroupFromDB(clusterPhyId, groupName); + + //没有topicMember则直接返回 + if (group == null || ValidateUtils.isEmptyList(group.getTopicMembers())) { + return PaginationResult.buildSuc(dto); } - return PaginationResult.buildSuc( - this.convert2GroupTopicOverviewVOList(paginationResult.getData().getBizData(), metricsListResult.getData()), - paginationResult - ); + //排序 + List groupTopicMembers = PaginationUtil.pageBySort(group.getTopicMembers(), PaginationConstant.DEFAULT_GROUP_TOPIC_SORTED_FIELD, SortTypeEnum.DESC.getSortType()); + + //分页 + PaginationResult paginationResult = PaginationUtil.pageBySubData(groupTopicMembers, dto); + + List groupMemberPOList = paginationResult.getData().getBizData().stream().map(elem -> new GroupMemberPO(clusterPhyId, elem.getTopicName(), groupName, group.getState().getState(), elem.getMemberCount())).collect(Collectors.toList()); + + return PaginationResult.buildSuc(this.getGroupTopicOverviewVOList(clusterPhyId, groupMemberPOList), paginationResult); + } + + @Override + public PaginationResult pagingClusterGroupsOverview(Long clusterPhyId, ClusterGroupSummaryDTO dto) { + List groupList = groupService.listClusterGroups(clusterPhyId); + + // 类型转化 + List voList = groupList.stream().map(elem -> GroupConverter.convert2GroupOverviewVO(elem)).collect(Collectors.toList()); + + // 搜索groupName + voList = PaginationUtil.pageByFuzzyFilter(voList, dto.getSearchGroupName(), Arrays.asList("name")); + + //搜索topic + if (!ValidateUtils.isBlank(dto.getSearchTopicName())) { + voList = voList.stream().filter(elem -> { + for (String topicName : elem.getTopicNameList()) { + if (topicName.contains(dto.getSearchTopicName())) { + return true; + } + } + return false; + }).collect(Collectors.toList()); + } + + // 分页 后 返回 + return PaginationUtil.pageBySubData(voList, dto); } @Override @@ -104,7 +141,7 @@ public class GroupManagerImpl implements GroupManager { List latestMetricNames, PaginationSortDTO dto) throws NotExistException, AdminOperateException { // 获取消费组消费的TopicPartition列表 - Map consumedOffsetMap = groupService.getGroupOffset(clusterPhyId, groupName); + Map consumedOffsetMap = groupService.getGroupOffsetFromKafka(clusterPhyId, groupName); List partitionList = consumedOffsetMap.keySet() .stream() .filter(elem -> elem.topic().equals(topicName)) @@ -113,7 +150,7 @@ public class GroupManagerImpl implements GroupManager { Collections.sort(partitionList); // 获取消费组当前运行信息 - ConsumerGroupDescription groupDescription = groupService.getGroupDescription(clusterPhyId, groupName); + ConsumerGroupDescription groupDescription = groupService.getGroupDescriptionFromKafka(clusterPhyId, groupName); // 转换存储格式 Map tpMemberMap = new HashMap<>(); @@ -166,13 +203,13 @@ public class GroupManagerImpl implements GroupManager { return rv; } - ConsumerGroupDescription description = groupService.getGroupDescription(dto.getClusterId(), dto.getGroupName()); + ConsumerGroupDescription description = groupService.getGroupDescriptionFromKafka(dto.getClusterId(), dto.getGroupName()); if (ConsumerGroupState.DEAD.equals(description.state()) && !dto.isCreateIfNotExist()) { return Result.buildFromRSAndMsg(ResultStatus.KAFKA_OPERATE_FAILED, "group不存在, 重置失败"); } if (!ConsumerGroupState.EMPTY.equals(description.state()) && !ConsumerGroupState.DEAD.equals(description.state())) { - return Result.buildFromRSAndMsg(ResultStatus.KAFKA_OPERATE_FAILED, String.format("group处于%s, 重置失败(仅Empty | Dead 情况可重置)", GroupStateEnum.getByRawState(description.state()).getState())); + return Result.buildFromRSAndMsg(ResultStatus.KAFKA_OPERATE_FAILED, String.format("group处于%s, 重置失败(仅Empty情况可重置)", GroupStateEnum.getByRawState(description.state()).getState())); } // 获取offset @@ -185,6 +222,22 @@ public class GroupManagerImpl implements GroupManager { return groupService.resetGroupOffsets(dto.getClusterId(), dto.getGroupName(), offsetMapResult.getData(), operator); } + @Override + public List getGroupTopicOverviewVOList(Long clusterPhyId, List groupMemberPOList) { + // 获取指标 + Result> metricsListResult = groupMetricService.listLatestMetricsAggByGroupTopicFromES( + clusterPhyId, + groupMemberPOList.stream().map(elem -> new GroupTopic(elem.getGroupName(), elem.getTopicName())).collect(Collectors.toList()), + Arrays.asList(GroupMetricVersionItems.GROUP_METRIC_LAG), + AggTypeEnum.MAX + ); + if (metricsListResult.failed()) { + // 如果查询失败,则输出错误信息,但是依旧进行已有数据的返回 + log.error("method=completeMetricData||clusterPhyId={}||result={}||errMsg=search es failed", clusterPhyId, metricsListResult); + } + return this.convert2GroupTopicOverviewVOList(groupMemberPOList, metricsListResult.getData()); + } + /**************************************************** private method ****************************************************/ @@ -293,4 +346,31 @@ public class GroupManagerImpl implements GroupManager { ); } + private List convert2GroupTopicOverviewVOList(String groupName, String state, List groupTopicList, List metricsList) { + if (metricsList == null) { + metricsList = new ArrayList<>(); + } + + // + Map metricsMap = new HashMap<>(); + for (GroupMetrics metrics : metricsList) { + if (!groupName.equals(metrics.getGroup())) continue; + metricsMap.put(metrics.getTopic(), metrics); + } + + List voList = new ArrayList<>(); + for (GroupTopicMember po : groupTopicList) { + GroupTopicOverviewVO vo = ConvertUtil.obj2Obj(po, GroupTopicOverviewVO.class); + vo.setGroupName(groupName); + vo.setState(state); + GroupMetrics metrics = metricsMap.get(po.getTopicName()); + if (metrics != null) { + vo.setMaxLag(ConvertUtil.Float2Long(metrics.getMetrics().get(GroupMetricVersionItems.GROUP_METRIC_LAG))); + } + + voList.add(vo); + } + return voList; + } + } diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java index ec3a3207..f2c05300 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java @@ -1,8 +1,10 @@ package com.xiaojukeji.know.streaming.km.biz.topic; -import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicRecordDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicBrokersPartitionsSummaryVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicRecordVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicStateVO; @@ -23,4 +25,6 @@ public interface TopicStateManager { Result> getTopicPartitions(Long clusterPhyId, String topicName, List metricsNames); Result getTopicBrokersPartitionsSummary(Long clusterPhyId, String topicName); + + PaginationResult pagingTopicGroupsOverview(Long clusterPhyId, String topicName, String searchGroupName, PaginationBaseDTO dto); } diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java index 9c03737a..afc907da 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java @@ -2,17 +2,22 @@ package com.xiaojukeji.know.streaming.km.biz.topic.impl; import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; +import com.xiaojukeji.know.streaming.km.biz.group.GroupManager; import com.xiaojukeji.know.streaming.km.biz.topic.TopicStateManager; +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicRecordDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.broker.Broker; import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.PartitionMetrics; import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.TopicMetrics; import com.xiaojukeji.know.streaming.km.common.bean.entity.partition.Partition; +import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.Topic; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; import com.xiaojukeji.know.streaming.km.common.bean.vo.broker.BrokerReplicaSummaryVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicBrokersPartitionsSummaryVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicRecordVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicStateVO; @@ -32,6 +37,7 @@ import com.xiaojukeji.know.streaming.km.common.utils.PaginationUtil; import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.broker.BrokerService; import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; +import com.xiaojukeji.know.streaming.km.core.service.group.GroupService; import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionMetricService; import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionService; import com.xiaojukeji.know.streaming.km.core.service.topic.TopicConfigService; @@ -77,6 +83,12 @@ public class TopicStateManagerImpl implements TopicStateManager { @Autowired private TopicConfigService topicConfigService; + @Autowired + private GroupService groupService; + + @Autowired + private GroupManager groupManager; + @Override public TopicBrokerAllVO getTopicBrokerAll(Long clusterPhyId, String topicName, String searchBrokerHost) throws NotExistException { Topic topic = topicService.getTopic(clusterPhyId, topicName); @@ -346,6 +358,19 @@ public class TopicStateManagerImpl implements TopicStateManager { return Result.buildSuc(vo); } + @Override + public PaginationResult pagingTopicGroupsOverview(Long clusterPhyId, String topicName, String searchGroupName, PaginationBaseDTO dto) { + PaginationResult paginationResult = groupService.pagingGroupMembers(clusterPhyId, topicName, "", "", searchGroupName, dto); + + if (!paginationResult.hasData()) { + return PaginationResult.buildSuc(new ArrayList<>(), paginationResult); + } + + List groupTopicVOList = groupManager.getGroupTopicOverviewVOList(clusterPhyId, paginationResult.getData().getBizData()); + + return PaginationResult.buildSuc(groupTopicVOList, paginationResult); + } + /**************************************************** private method ****************************************************/ private boolean checkIfIgnore(ConsumerRecord consumerRecord, String filterKey, String filterValue) { diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterGroupSummaryDTO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterGroupSummaryDTO.java new file mode 100644 index 00000000..d199e0d8 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/cluster/ClusterGroupSummaryDTO.java @@ -0,0 +1,18 @@ +package com.xiaojukeji.know.streaming.km.common.bean.dto.cluster; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author wyb + * @date 2022/10/17 + */ +@Data +public class ClusterGroupSummaryDTO extends PaginationBaseDTO { + @ApiModelProperty("查找该Topic") + private String searchTopicName; + + @ApiModelProperty("查找该Group") + private String searchGroupName; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/Group.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/Group.java new file mode 100644 index 00000000..3b2e22e9 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/Group.java @@ -0,0 +1,74 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.group; + +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.kafka.clients.admin.ConsumerGroupDescription; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author wyb + * @date 2022/10/10 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Group { + /** + * 集群id + */ + private Long clusterPhyId; + + /** + * group类型 + * @see GroupTypeEnum + */ + private GroupTypeEnum type; + + /** + * group名称 + */ + private String name; + + /** + * group状态 + * @see GroupStateEnum + */ + private GroupStateEnum state; + + /** + * group成员数量 + */ + private Integer memberCount; + + /** + * group消费的topic列表 + */ + private List topicMembers; + + /** + * group分配策略 + */ + private String partitionAssignor; + + /** + * group协调器brokerId + */ + private int coordinatorId; + + public Group(Long clusterPhyId, String groupName, ConsumerGroupDescription groupDescription) { + this.clusterPhyId = clusterPhyId; + this.type = groupDescription.isSimpleConsumerGroup()? GroupTypeEnum.CONSUMER: GroupTypeEnum.CONNECTOR; + this.name = groupName; + this.state = GroupStateEnum.getByRawState(groupDescription.state()); + this.memberCount = groupDescription.members() == null? 0: groupDescription.members().size(); + this.topicMembers = new ArrayList<>(); + this.partitionAssignor = groupDescription.partitionAssignor(); + this.coordinatorId = groupDescription.coordinator() == null? Constant.INVALID_CODE: groupDescription.coordinator().id(); + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/GroupTopicMember.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/GroupTopicMember.java new file mode 100644 index 00000000..5fe960b1 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/group/GroupTopicMember.java @@ -0,0 +1,27 @@ +package com.xiaojukeji.know.streaming.km.common.bean.entity.group; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author wyb + * @date 2022/10/10 + */ +@Data +@NoArgsConstructor +public class GroupTopicMember { + /** + * Topic名称 + */ + private String topicName; + + /** + * 消费此Topic的成员数量 + */ + private Integer memberCount; + + public GroupTopicMember(String topicName, Integer memberCount) { + this.topicName = topicName; + this.memberCount = memberCount; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupMemberPO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupMemberPO.java index 3d999952..7992ac17 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupMemberPO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupMemberPO.java @@ -3,7 +3,6 @@ package com.xiaojukeji.know.streaming.km.common.bean.po.group; import com.baomidou.mybatisplus.annotation.TableName; import com.xiaojukeji.know.streaming.km.common.bean.po.BasePO; import com.xiaojukeji.know.streaming.km.common.constant.Constant; -import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; import lombok.Data; import lombok.NoArgsConstructor; @@ -23,12 +22,19 @@ public class GroupMemberPO extends BasePO { private Integer memberCount; - public GroupMemberPO(Long clusterPhyId, String topicName, String groupName, Date updateTime) { + public GroupMemberPO(Long clusterPhyId, String topicName, String groupName, String state, Integer memberCount) { this.clusterPhyId = clusterPhyId; this.topicName = topicName; this.groupName = groupName; - this.state = GroupStateEnum.UNKNOWN.getState(); - this.memberCount = 0; + this.state = state; + this.memberCount = memberCount; + } + public GroupMemberPO(Long clusterPhyId, String topicName, String groupName, String state, Integer memberCount, Date updateTime) { + this.clusterPhyId = clusterPhyId; + this.topicName = topicName; + this.groupName = groupName; + this.state = state; + this.memberCount = memberCount; this.updateTime = updateTime; } } \ No newline at end of file diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupPO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupPO.java new file mode 100644 index 00000000..49ac5bf3 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/po/group/GroupPO.java @@ -0,0 +1,61 @@ +package com.xiaojukeji.know.streaming.km.common.bean.po.group; + + +import com.baomidou.mybatisplus.annotation.TableName; +import com.xiaojukeji.know.streaming.km.common.bean.po.BasePO; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupTypeEnum; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@NoArgsConstructor +@TableName(Constant.MYSQL_TABLE_NAME_PREFIX + "group") +public class GroupPO extends BasePO { + /** + * 集群id + */ + private Long clusterPhyId; + + /** + * group类型 + * + * @see GroupTypeEnum + */ + private Integer type; + + /** + * group名称 + */ + private String name; + + /** + * group状态 + * + * @see GroupStateEnum + */ + private String state; + + /** + * group成员数量 + */ + private Integer memberCount; + + /** + * group消费的topic列表 + */ + private String topicMembers; + + /** + * group分配策略 + */ + private String partitionAssignor; + + /** + * group协调器brokerId + */ + private int coordinatorId; + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupOverviewVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupOverviewVO.java new file mode 100644 index 00000000..df976643 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupOverviewVO.java @@ -0,0 +1,27 @@ +package com.xiaojukeji.know.streaming.km.common.bean.vo.group; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * @author wyb + * @date 2022/10/9 + */ +@Data +@ApiModel(value = "Group信息") +public class GroupOverviewVO { + @ApiModelProperty(value = "Group名称", example = "group-know-streaming-test") + private String name; + + @ApiModelProperty(value = "Group状态", example = "Empty") + private String state; + + @ApiModelProperty(value = "group的成员数", example = "12") + private Integer memberCount; + + @ApiModelProperty(value = "Topic列表", example = "[topic1,topic2]") + private List topicNameList; +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupTopicOverviewVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupTopicOverviewVO.java index 205fb923..40d2f652 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupTopicOverviewVO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/group/GroupTopicOverviewVO.java @@ -10,7 +10,7 @@ import lombok.Data; */ @Data @ApiModel(value = "GroupTopic信息") -public class GroupTopicOverviewVO extends GroupTopicBasicVO{ +public class GroupTopicOverviewVO extends GroupTopicBasicVO { @ApiModelProperty(value = "最大Lag", example = "12345678") private Long maxLag; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/PaginationConstant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/PaginationConstant.java index 68dd9358..9b8def80 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/PaginationConstant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/PaginationConstant.java @@ -18,4 +18,14 @@ public class PaginationConstant { * 默认页大小 */ public static final Integer DEFAULT_PAGE_SIZE = 10; + + /** + * group列表的默认排序规则 + */ + public static final String DEFAULT_GROUP_SORTED_FIELD = "name"; + + /** + * groupTopic列表的默认排序规则 + */ + public static final String DEFAULT_GROUP_TOPIC_SORTED_FIELD = "topicName"; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/GroupConverter.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/GroupConverter.java new file mode 100644 index 00000000..131bd243 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/converter/GroupConverter.java @@ -0,0 +1,62 @@ +package com.xiaojukeji.know.streaming.km.common.converter; + +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.GroupTopicMember; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupOverviewVO; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; +import com.xiaojukeji.know.streaming.km.common.enums.group.GroupTypeEnum; +import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; + +import java.util.ArrayList; +import java.util.stream.Collectors; + +/** + * @author wyb + * @date 2022/10/10 + */ +public class GroupConverter { + + private GroupConverter() { + + } + + public static GroupOverviewVO convert2GroupOverviewVO(Group group) { + GroupOverviewVO vo = ConvertUtil.obj2Obj(group, GroupOverviewVO.class); + + vo.setState(group.getState().getState()); + vo.setTopicNameList(group.getTopicMembers().stream().map(elem -> elem.getTopicName()).collect(Collectors.toList())); + + return vo; + } + + public static Group convert2Group(GroupPO po) { + if (po == null) { + return null; + } + + Group group = ConvertUtil.obj2Obj(po, Group.class); + if (!ValidateUtils.isBlank(po.getTopicMembers())) { + group.setTopicMembers(ConvertUtil.str2ObjArrayByJson(po.getTopicMembers(), GroupTopicMember.class)); + } else { + group.setTopicMembers(new ArrayList<>()); + } + + group.setType(GroupTypeEnum.getTypeByCode(po.getType())); + group.setState(GroupStateEnum.getByState(po.getState())); + return group; + } + + public static GroupPO convert2GroupPO(Group group) { + if (group == null) { + return null; + } + + GroupPO po = ConvertUtil.obj2Obj(group, GroupPO.class); + po.setTopicMembers(ConvertUtil.obj2Json(group.getTopicMembers())); + po.setType(group.getType().getCode()); + po.setState(group.getState().getState()); + return po; + } +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/group/GroupTypeEnum.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/group/GroupTypeEnum.java new file mode 100644 index 00000000..ebb91ea1 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/group/GroupTypeEnum.java @@ -0,0 +1,36 @@ +package com.xiaojukeji.know.streaming.km.common.enums.group; + +import lombok.Getter; + +/** + * @author wyb + * @date 2022/10/11 + */ +@Getter +public enum GroupTypeEnum { + + UNKNOWN(-1, "Unknown"), + + CONSUMER(0, "Consumer客户端的消费组"), + + CONNECTOR(1, "Connector的消费组"); + + private final Integer code; + + private final String msg; + + GroupTypeEnum(Integer code, String msg) { + this.code = code; + this.msg = msg; + } + + public static GroupTypeEnum getTypeByCode(Integer code) { + if (code == null) return UNKNOWN; + for (GroupTypeEnum groupTypeEnum : GroupTypeEnum.values()) { + if (groupTypeEnum.code.equals(code)) { + return groupTypeEnum; + } + } + return UNKNOWN; + } +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/GroupService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/GroupService.java index 790a7c47..8dc1c535 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/GroupService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/GroupService.java @@ -1,6 +1,7 @@ package com.xiaojukeji.know.streaming.km.core.service.group; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; @@ -16,27 +17,47 @@ import java.util.Map; public interface GroupService { /** - * 从Kafka中获取消费组 - * @param clusterPhyId 集群ID - * @return - * @throws NotExistException - * @throws AdminOperateException + * 从Kafka中获取消费组名称列表 */ List listGroupsFromKafka(Long clusterPhyId) throws NotExistException, AdminOperateException; - Map getGroupOffset(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; + /** + * 从Kafka中获取消费组详细信息 + */ + Group getGroupFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; - ConsumerGroupDescription getGroupDescription(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; + Map getGroupOffsetFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; - int replaceDBData(GroupMemberPO groupMemberPO); + ConsumerGroupDescription getGroupDescriptionFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException; - void batchReplace(List newGroupMemberList); + Result resetGroupOffsets(Long clusterPhyId, String groupName, Map offsetMap, String operator) throws NotExistException, AdminOperateException; + /** + * 批量更新DB + */ + void batchReplaceGroupsAndMembers(Long clusterPhyId, List newGroupList, long updateTime); + + int deleteByUpdateTimeBeforeInDB(Long clusterPhyId, Date beforeTime); + + /** + * DB-Group相关接口 + */ GroupStateEnum getGroupStateFromDB(Long clusterPhyId, String groupName); - List listGroupByTopic(Long clusterPhyId, String topicName); + Group getGroupFromDB(Long clusterPhyId, String groupName); - List listGroup(Long clusterPhyId); + List listClusterGroups(Long clusterPhyId); + + List getGroupsFromDB(Long clusterPhyId); + + Integer calGroupCount(Long clusterPhyId); + + Integer calGroupStatCount(Long clusterPhyId, GroupStateEnum stateEnum); + + /** + * DB-GroupTopic相关接口 + */ + List listGroupByTopic(Long clusterPhyId, String topicName); PaginationResult pagingGroupMembers(Long clusterPhyId, String topicName, @@ -45,15 +66,5 @@ public interface GroupService { String searchGroupKeyword, PaginationBaseDTO dto); - int deleteByUpdateTimeBeforeInDB(Long clusterPhyId, Date beforeTime); - - List getGroupsFromDB(Long clusterPhyId); - - GroupMemberPO getGroupFromDB(Long clusterPhyId, String groupName, String topicName); - - Integer calGroupCount(Long clusterPhyId); - - Integer calGroupStatCount(Long clusterPhyId, GroupStateEnum stateEnum); - - Result resetGroupOffsets(Long clusterPhyId, String groupName, Map offsetMap, String operator) throws NotExistException, AdminOperateException; -} + GroupMemberPO getGroupTopicFromDB(Long clusterPhyId, String groupName, String topicName); +} \ No newline at end of file diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupMetricServiceImpl.java index 427edc2c..936897a3 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupMetricServiceImpl.java @@ -24,7 +24,6 @@ import com.xiaojukeji.know.streaming.km.core.service.health.score.HealthScoreSer import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionService; import com.xiaojukeji.know.streaming.km.core.service.version.BaseMetricService; import com.xiaojukeji.know.streaming.km.persistence.es.dao.GroupMetricESDAO; -import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaAdminClient; import org.apache.kafka.clients.admin.OffsetSpec; import org.apache.kafka.common.TopicPartition; import org.springframework.beans.factory.annotation.Autowired; @@ -183,7 +182,7 @@ public class GroupMetricServiceImpl extends BaseMetricService implements GroupMe List metricsList = new ArrayList<>(); try { - Map groupOffsetMap = groupService.getGroupOffset(clusterId, groupName); + Map groupOffsetMap = groupService.getGroupOffsetFromKafka(clusterId, groupName); // 组织 GROUP_METRIC_OFFSET_CONSUMED 指标 for (Map.Entry entry: groupOffsetMap.entrySet()) { diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java index 1789671b..1a923f21 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/group/impl/GroupServiceImpl.java @@ -7,11 +7,15 @@ import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; import com.didiglobal.logi.security.common.dto.oplog.OplogDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.GroupTopicMember; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupPO; import com.xiaojukeji.know.streaming.km.common.constant.KafkaConstant; +import com.xiaojukeji.know.streaming.km.common.converter.GroupConverter; import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; import com.xiaojukeji.know.streaming.km.common.enums.operaterecord.ModuleEnum; import com.xiaojukeji.know.streaming.km.common.enums.operaterecord.OperationEnum; @@ -24,6 +28,7 @@ import com.xiaojukeji.know.streaming.km.core.service.group.GroupService; import com.xiaojukeji.know.streaming.km.core.service.oprecord.OpLogWrapService; import com.xiaojukeji.know.streaming.km.core.service.version.BaseVersionControlService; import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaAdminClient; +import com.xiaojukeji.know.streaming.km.persistence.mysql.group.GroupDAO; import com.xiaojukeji.know.streaming.km.persistence.mysql.group.GroupMemberDAO; import org.apache.kafka.clients.admin.*; import org.apache.kafka.clients.consumer.OffsetAndMetadata; @@ -41,6 +46,9 @@ import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionItemT public class GroupServiceImpl extends BaseVersionControlService implements GroupService { private static final ILog log = LogFactory.getLog(GroupServiceImpl.class); + @Autowired + private GroupDAO groupDAO; + @Autowired private GroupMemberDAO groupMemberDAO; @@ -79,7 +87,43 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group } @Override - public Map getGroupOffset(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { + public Group getGroupFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { + // 获取消费组的详细信息 + ConsumerGroupDescription groupDescription = this.getGroupDescriptionFromKafka(clusterPhyId, groupName); + if (groupDescription == null) { + return null; + } + + Group group = new Group(clusterPhyId, groupName, groupDescription); + + // 获取消费组消费过哪些Topic + Map memberMap = new HashMap<>(); + for (TopicPartition tp : this.getGroupOffsetFromKafka(clusterPhyId, groupName).keySet()) { + memberMap.putIfAbsent(tp.topic(), new GroupTopicMember(tp.topic(), 0)); + } + + // 记录成员信息 + for (MemberDescription memberDescription : groupDescription.members()) { + Set partitionList = new HashSet<>(); + if (!ValidateUtils.isNull(memberDescription.assignment().topicPartitions())) { + partitionList = memberDescription.assignment().topicPartitions(); + } + + Set topicNameSet = partitionList.stream().map(elem -> elem.topic()).collect(Collectors.toSet()); + for (String topicName : topicNameSet) { + memberMap.putIfAbsent(topicName, new GroupTopicMember(topicName, 0)); + + GroupTopicMember member = memberMap.get(topicName); + member.setMemberCount(member.getMemberCount() + 1); + } + } + group.setTopicMembers(memberMap.values().stream().collect(Collectors.toList())); + + return group; + } + + @Override + public Map getGroupOffsetFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { AdminClient adminClient = kafkaAdminClient.getClient(clusterPhyId); Map offsetMap = new HashMap<>(); @@ -99,12 +143,12 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group } @Override - public ConsumerGroupDescription getGroupDescription(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { + public ConsumerGroupDescription getGroupDescriptionFromKafka(Long clusterPhyId, String groupName) throws NotExistException, AdminOperateException { AdminClient adminClient = kafkaAdminClient.getClient(clusterPhyId); try { DescribeConsumerGroupsResult describeConsumerGroupsResult = adminClient.describeConsumerGroups( - Collections.singletonList(groupName), + Arrays.asList(groupName), new DescribeConsumerGroupsOptions().timeoutMs(KafkaConstant.ADMIN_CLIENT_REQUEST_TIME_OUT_UNIT_MS).includeAuthorizedOperations(false) ); @@ -117,40 +161,12 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group } @Override - public int replaceDBData(GroupMemberPO groupMemberPO) { - return groupMemberDAO.replace(groupMemberPO); - } - - @Override - public void batchReplace(List newGroupMemberList) { - if (newGroupMemberList == null || newGroupMemberList.isEmpty()) { - return; - } - - Long clusterPhyId = newGroupMemberList.get(0).getClusterPhyId(); - if (clusterPhyId == null) { - return; - } - - List dbGroupMemberList = listGroup(clusterPhyId); - - - Map dbGroupMemberMap = dbGroupMemberList.stream().collect(Collectors.toMap(elem -> elem.getGroupName() + elem.getTopicName(), Function.identity())); - for (GroupMemberPO groupMemberPO : newGroupMemberList) { - GroupMemberPO po = dbGroupMemberMap.remove(groupMemberPO.getGroupName() + groupMemberPO.getTopicName()); - try { - if (po != null) { - groupMemberPO.setId(po.getId()); - groupMemberDAO.updateById(groupMemberPO); - } else { - groupMemberDAO.insert(groupMemberPO); - } - } catch (Exception e) { - log.error("method=batchReplace||clusterPhyId={}||groupName={}||errMsg=exception", clusterPhyId, groupMemberPO.getGroupName(), e); - } - - } + public void batchReplaceGroupsAndMembers(Long clusterPhyId, List newGroupList, long updateTime) { + // 更新Group信息 + this.batchReplaceGroups(clusterPhyId, newGroupList, updateTime); + // 更新Group-Topic信息 + this.batchReplaceGroupMembers(clusterPhyId, newGroupList, updateTime); } @Override @@ -176,14 +192,6 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group return groupMemberDAO.selectList(lambdaQueryWrapper); } - @Override - public List listGroup(Long clusterPhyId) { - LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); - - return groupMemberDAO.selectList(lambdaQueryWrapper); - } - @Override public PaginationResult pagingGroupMembers(Long clusterPhyId, String topicName, @@ -208,8 +216,33 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group return PaginationResult.buildSuc(iPage.getRecords(), iPage); } + @Override + public Group getGroupFromDB(Long clusterPhyId, String groupName) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + lambdaQueryWrapper.eq(GroupPO::getName, groupName); + + GroupPO groupPO = groupDAO.selectOne(lambdaQueryWrapper); + return GroupConverter.convert2Group(groupPO); + } + + @Override + public List listClusterGroups(Long clusterPhyId) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + + return groupDAO.selectList(lambdaQueryWrapper).stream().map(elem -> GroupConverter.convert2Group(elem)).collect(Collectors.toList()); + } + @Override public int deleteByUpdateTimeBeforeInDB(Long clusterPhyId, Date beforeTime) { + // 删除过期Group信息 + LambdaQueryWrapper groupPOLambdaQueryWrapper = new LambdaQueryWrapper<>(); + groupPOLambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + groupPOLambdaQueryWrapper.le(GroupPO::getUpdateTime, beforeTime); + groupDAO.delete(groupPOLambdaQueryWrapper); + + // 删除过期GroupMember信息 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); queryWrapper.le(GroupMemberPO::getUpdateTime, beforeTime); @@ -218,17 +251,19 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group @Override public List getGroupsFromDB(Long clusterPhyId) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); - List poList = groupMemberDAO.selectList(queryWrapper); + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + + List poList = groupDAO.selectList(lambdaQueryWrapper); if (poList == null) { poList = new ArrayList<>(); } - return new ArrayList<>(poList.stream().map(elem -> elem.getGroupName()).collect(Collectors.toSet())); + + return new ArrayList<>(poList.stream().map(elem -> elem.getName()).collect(Collectors.toSet())); } @Override - public GroupMemberPO getGroupFromDB(Long clusterPhyId, String groupName, String topicName) { + public GroupMemberPO getGroupTopicFromDB(Long clusterPhyId, String groupName, String topicName) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); queryWrapper.eq(GroupMemberPO::getTopicName, topicName); @@ -239,28 +274,19 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group @Override public Integer calGroupCount(Long clusterPhyId) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); - List poList = groupMemberDAO.selectList(queryWrapper); - if (poList == null) { - poList = new ArrayList<>(); - } + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); - return poList.stream().map(elem -> elem.getGroupName()).collect(Collectors.toSet()).size(); + return groupDAO.selectCount(lambdaQueryWrapper); } @Override public Integer calGroupStatCount(Long clusterPhyId, GroupStateEnum stateEnum) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); - queryWrapper.eq(GroupMemberPO::getState, stateEnum.getState()); + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + lambdaQueryWrapper.eq(GroupPO::getState, stateEnum.getState()); - List poList = groupMemberDAO.selectList(queryWrapper); - if (poList == null) { - poList = new ArrayList<>(); - } - - return poList.stream().map(elem -> elem.getGroupName()).collect(Collectors.toSet()).size(); + return groupDAO.selectCount(lambdaQueryWrapper); } @Override @@ -303,4 +329,74 @@ public class GroupServiceImpl extends BaseVersionControlService implements Group /**************************************************** private method ****************************************************/ + private void batchReplaceGroupMembers(Long clusterPhyId, List newGroupList, long updateTime) { + if (ValidateUtils.isEmptyList(newGroupList)) { + return; + } + + List dbPOList = this.listClusterGroupsMemberPO(clusterPhyId); + Map dbPOMap = dbPOList.stream().collect(Collectors.toMap(elem -> elem.getGroupName() + elem.getTopicName(), Function.identity())); + + for (Group group: newGroupList) { + for (GroupTopicMember member : group.getTopicMembers()) { + try { + GroupMemberPO newPO = new GroupMemberPO(clusterPhyId, member.getTopicName(), group.getName(), group.getState().getState(), member.getMemberCount(), new Date(updateTime)); + + GroupMemberPO dbPO = dbPOMap.remove(newPO.getGroupName() + newPO.getTopicName()); + if (dbPO != null) { + newPO.setId(dbPO.getId()); + groupMemberDAO.updateById(newPO); + continue; + } + + groupMemberDAO.insert(newPO); + } catch (Exception e) { + log.error( + "method=batchReplaceGroupMembers||clusterPhyId={}||groupName={}||topicName={}||errMsg=exception", + clusterPhyId, group.getName(), member.getTopicName(), e + ); + } + } + } + } + + private void batchReplaceGroups(Long clusterPhyId, List newGroupList, long updateTime) { + if (ValidateUtils.isEmptyList(newGroupList)) { + return; + } + + List dbGroupList = this.listClusterGroupsPO(clusterPhyId); + Map dbGroupMap = dbGroupList.stream().collect(Collectors.toMap(elem -> elem.getName(), Function.identity())); + + for (Group newGroup: newGroupList) { + try { + GroupPO newPO = GroupConverter.convert2GroupPO(newGroup); + newPO.setUpdateTime(new Date(updateTime)); + + GroupPO dbPO = dbGroupMap.remove(newGroup.getName()); + if (dbPO != null) { + newPO.setId(dbPO.getId()); + groupDAO.updateById(newPO); + continue; + } + + groupDAO.insert(newPO); + } catch (Exception e) { + log.error("method=batchGroupReplace||clusterPhyId={}||groupName={}||errMsg=exception", clusterPhyId, newGroup.getName(), e); + } + } + } + + private List listClusterGroupsPO(Long clusterPhyId) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupPO::getClusterPhyId, clusterPhyId); + return groupDAO.selectList(lambdaQueryWrapper); + } + + private List listClusterGroupsMemberPO(Long clusterPhyId) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(GroupMemberPO::getClusterPhyId, clusterPhyId); + + return groupMemberDAO.selectList(lambdaQueryWrapper); + } } diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/group/GroupDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/group/GroupDAO.java new file mode 100644 index 00000000..eb4465c3 --- /dev/null +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/mysql/group/GroupDAO.java @@ -0,0 +1,9 @@ +package com.xiaojukeji.know.streaming.km.persistence.mysql.group; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupPO; +import org.springframework.stereotype.Repository; + +@Repository +public interface GroupDAO extends BaseMapper { +} diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterGroupsController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterGroupsController.java index 4515d695..b035ea02 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterGroupsController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterGroupsController.java @@ -1,12 +1,15 @@ package com.xiaojukeji.know.streaming.km.rest.api.v3.cluster; import com.xiaojukeji.know.streaming.km.biz.group.GroupManager; +import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterGroupSummaryDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.cluster.ClusterGroupsOverviewDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricGroupPartitionDTO; +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.field.PaginationFuzzySearchFieldDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.topic.TopicPartitionKS; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.line.MetricMultiLinesVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.constant.ApiPrefix; @@ -37,7 +40,8 @@ public class ClusterGroupsController { @Autowired private GroupMetricService groupMetricService; - @ApiOperation(value = "集群Groups信息列表") + @Deprecated + @ApiOperation(value = "集群Groups信息列表", notes = "废弃, 下一个版本删除") @PostMapping(value = "clusters/{clusterPhyId}/groups-overview") @ResponseBody public PaginationResult getClusterPhyGroupsOverview(@PathVariable Long clusterPhyId, @@ -53,6 +57,13 @@ public class ClusterGroupsController { ); } + @ApiOperation(value = "集群Groups信息列表") + @GetMapping(value = "clusters/{clusterPhyId}/groups-overview") + @ResponseBody + public PaginationResult getGroupsOverview(@PathVariable Long clusterPhyId, ClusterGroupSummaryDTO dto) { + return groupManager.pagingClusterGroupsOverview(clusterPhyId, dto); + } + @ApiOperation(value = "集群Groups指标信息") @PostMapping(value = "clusters/{clusterPhyId}/group-metrics") @ResponseBody @@ -70,8 +81,17 @@ public class ClusterGroupsController { return groupManager.listClusterPhyGroupPartitions(clusterPhyId, groupName, startTime, endTime); } + @ApiOperation(value = "Group的Topic列表") + @GetMapping(value = "clusters/{clusterPhyId}/groups/{groupName}/topics-overview") + public PaginationResult getGroupTopicsOverview(@PathVariable Long clusterPhyId, + @PathVariable String groupName, + PaginationBaseDTO dto) { + return groupManager.pagingGroupTopicMembers(clusterPhyId, groupName, dto); + } + /**************************************************** private method ****************************************************/ + @Deprecated private Tuple getSearchKeyWords(ClusterGroupsOverviewDTO dto) { if (ValidateUtils.isEmptyList(dto.getFuzzySearchDTOList())) { return new Tuple<>("", ""); diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/group/GroupController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/group/GroupController.java index 17986b16..55e7e778 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/group/GroupController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/group/GroupController.java @@ -55,7 +55,7 @@ public class GroupController { public Result getGroupMetadataCombineExist(@PathVariable Long clusterPhyId, @PathVariable String groupName, @PathVariable String topicName) { - GroupMemberPO po = groupService.getGroupFromDB(clusterPhyId, groupName, topicName); + GroupMemberPO po = groupService.getGroupTopicFromDB(clusterPhyId, groupName, topicName); if (po == null) { return Result.buildSuc(new GroupMetadataCombineExistVO(clusterPhyId, groupName, topicName, false)); } diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java index d1e09e66..b0371537 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java @@ -3,7 +3,6 @@ package com.xiaojukeji.know.streaming.km.rest.api.v3.topic; import com.xiaojukeji.know.streaming.km.biz.topic.TopicStateManager; import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; -import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicRecordDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.BaseMetrics; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; @@ -11,6 +10,7 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.po.KafkaAclPO; import com.xiaojukeji.know.streaming.km.common.bean.vo.acl.AclBindingVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicBasicVO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicBrokersPartitionsSummaryVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicStateVO; @@ -136,8 +136,17 @@ public class TopicStateController { @ApiOperation(value = "TopicGroups基本信息列表") @GetMapping(value = "clusters/{clusterPhyId}/topics/{topicName}/groups-basic") @ResponseBody - public Result> getTopicGroupsBasic(@PathVariable Long clusterPhyId, - @PathVariable String topicName) { + public Result> getTopicGroupsBasic(@PathVariable Long clusterPhyId, @PathVariable String topicName) { return Result.buildSuc(ConvertUtil.list2List(groupService.listGroupByTopic(clusterPhyId, topicName), GroupTopicBasicVO.class)); } + + @ApiOperation("Topic的Group列表") + @GetMapping(value = "clusters/{clusterPhyId}/topics/{topicName}/groups-overview") + public PaginationResult getTopicGroupsOverview(@PathVariable Long clusterPhyId, + @PathVariable String topicName, + @RequestParam(required = false) String searchGroupName, + PaginationBaseDTO dto) { + return topicStateManager.pagingTopicGroupsOverview(clusterPhyId, topicName, searchGroupName, dto); + } + } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncKafkaGroupTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncKafkaGroupTask.java index e2f749fe..cbec5bd2 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncKafkaGroupTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metadata/SyncKafkaGroupTask.java @@ -6,15 +6,10 @@ import com.didiglobal.logi.job.core.consensual.ConsensualEnum; import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import com.xiaojukeji.know.streaming.km.common.bean.po.group.GroupMemberPO; -import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; -import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException; -import com.xiaojukeji.know.streaming.km.common.exception.NotExistException; +import com.xiaojukeji.know.streaming.km.common.bean.entity.group.Group; import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.group.GroupService; import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService; -import org.apache.kafka.clients.admin.*; -import org.apache.kafka.common.TopicPartition; import org.springframework.beans.factory.annotation.Autowired; import java.util.*; @@ -38,98 +33,58 @@ public class SyncKafkaGroupTask extends AbstractAsyncMetadataDispatchTask { @Override public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception { - + // 获取集群的Group列表 List groupNameList = groupService.listGroupsFromKafka(clusterPhy.getId()); - TaskResult tr = updateGroupMembersTask(clusterPhy, groupNameList, triggerTimeUnitMs); - if (!TaskResult.SUCCESS.equals(tr)) { - return tr; + TaskResult allSuccess = TaskResult.SUCCESS; + + // 获取Group详细信息 + List groupList = new ArrayList<>(); + for (String groupName : groupNameList) { + try { + Group group = groupService.getGroupFromKafka(clusterPhy.getId(), groupName); + if (group == null) { + continue; + } + + groupList.add(group); + } catch (Exception e) { + log.error("method=processClusterTask||clusterPhyId={}||groupName={}||errMsg=exception", clusterPhy.getId(), groupName, e); + allSuccess = TaskResult.FAIL; + } + } + + // 过滤掉无效的Topic + this.filterTopicIfTopicNotExist(clusterPhy.getId(), groupList); + + // 更新DB中的Group信息 + groupService.batchReplaceGroupsAndMembers(clusterPhy.getId(), groupList, triggerTimeUnitMs); + + // 如果存在错误,则直接返回 + if (!TaskResult.SUCCESS.equals(allSuccess)) { + return allSuccess; } // 删除历史的Group groupService.deleteByUpdateTimeBeforeInDB(clusterPhy.getId(), new Date(triggerTimeUnitMs - 5 * 60 * 1000)); - return tr; + return allSuccess; } - - private TaskResult updateGroupMembersTask(ClusterPhy clusterPhy, List groupNameList, long triggerTimeUnitMs) { - List groupMemberPOList = new ArrayList<>(); - TaskResult tr = TaskResult.SUCCESS; - - for (String groupName : groupNameList) { - try { - List poList = this.getGroupMembers(clusterPhy.getId(), groupName, new Date(triggerTimeUnitMs)); - groupMemberPOList.addAll(poList); - } catch (Exception e) { - log.error("method=updateGroupMembersTask||clusterPhyId={}||groupName={}||errMsg=exception", clusterPhy.getId(), groupName, e); - tr = TaskResult.FAIL; - } - } - - groupMemberPOList = this.filterGroupIfTopicNotExist(clusterPhy.getId(), groupMemberPOList); - groupService.batchReplace(groupMemberPOList); - - return tr; - } - - private List getGroupMembers(Long clusterPhyId, String groupName, Date updateTime) throws NotExistException, AdminOperateException { - Map groupMap = new HashMap<>(); - - // 获取消费组消费过哪些Topic - Map offsetMap = groupService.getGroupOffset(clusterPhyId, groupName); - for (TopicPartition topicPartition : offsetMap.keySet()) { - GroupMemberPO po = groupMap.get(topicPartition.topic()); - if (po == null) { - po = new GroupMemberPO(clusterPhyId, topicPartition.topic(), groupName, updateTime); - } - groupMap.put(topicPartition.topic(), po); - } - - // 在上面的基础上,补充消费组的详细信息 - ConsumerGroupDescription consumerGroupDescription = groupService.getGroupDescription(clusterPhyId, groupName); - if (consumerGroupDescription == null) { - return new ArrayList<>(groupMap.values()); - } - - groupMap.forEach((key, val) -> val.setState(GroupStateEnum.getByRawState(consumerGroupDescription.state()).getState())); - - for (MemberDescription memberDescription : consumerGroupDescription.members()) { - Set partitionList = new HashSet<>(); - if (!ValidateUtils.isNull(memberDescription.assignment().topicPartitions())) { - partitionList = memberDescription.assignment().topicPartitions(); - } - - Set topicNameSet = partitionList.stream().map(elem -> elem.topic()).collect(Collectors.toSet()); - for (String topicName : topicNameSet) { - groupMap.putIfAbsent(topicName, new GroupMemberPO(clusterPhyId, topicName, groupName, updateTime)); - - GroupMemberPO po = groupMap.get(topicName); - po.setMemberCount(po.getMemberCount() + 1); - po.setState(GroupStateEnum.getByRawState(consumerGroupDescription.state()).getState()); - } - } - - // 如果该消费组没有正在消费任何Topic的特殊情况,但是这个Group存在 - if (groupMap.isEmpty()) { - GroupMemberPO po = new GroupMemberPO(clusterPhyId, "", groupName, updateTime); - po.setState(GroupStateEnum.getByRawState(consumerGroupDescription.state()).getState()); - groupMap.put("", po); - } - - return new ArrayList<>(groupMap.values()); - } - - private List filterGroupIfTopicNotExist(Long clusterPhyId, List poList) { - if (poList.isEmpty()) { - return poList; + private void filterTopicIfTopicNotExist(Long clusterPhyId, List groupList) { + if (ValidateUtils.isEmptyList(groupList)) { + return; } // 集群Topic集合 Set dbTopicSet = topicService.listTopicsFromDB(clusterPhyId).stream().map(elem -> elem.getTopicName()).collect(Collectors.toSet()); dbTopicSet.add(""); //兼容没有消费Topic的group - + // 过滤Topic不存在的消费组 - return poList.stream().filter(elem -> dbTopicSet.contains(elem.getTopicName())).collect(Collectors.toList()); + for (Group group: groupList) { + group.setTopicMembers( + group.getTopicMembers().stream().filter(elem -> dbTopicSet.contains(elem.getTopicName())).collect(Collectors.toList()) + ); + } } } From 88d0a601821445859f3541bc5a23d16038620ec6 Mon Sep 17 00:00:00 2001 From: _haoqi <1148648445@qq.com> Date: Thu, 20 Oct 2022 14:39:44 +0800 Subject: [PATCH 129/145] =?UTF-8?q?[ISSUE=20#677]=20=E9=87=8D=E5=90=AF?= =?UTF-8?q?=E4=BC=9A=E5=AF=BC=E8=87=B4=E9=83=A8=E5=88=86=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E9=87=87=E9=9B=86=E6=8A=9B=E5=87=BA=E7=A9=BA=E6=8C=87=E9=92=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/es/dao/BrokerMetricESDAO.java | 17 +++--- .../es/dao/ClusterMetricESDAO.java | 10 ++-- .../persistence/es/dao/GroupMetricESDAO.java | 10 ++-- .../persistence/es/dao/TopicMetricESDAO.java | 5 +- .../es/ClusterMetricESDAOTest.java | 53 +++++++++++++++++-- .../es/ReplicationMetricESDAOTest.java | 23 +++++++- .../persistence/es/TopicMetricESDAOTest.java | 33 +++++++++--- 7 files changed, 123 insertions(+), 28 deletions(-) diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java index 83145381..7ee76a3e 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/BrokerMetricESDAO.java @@ -207,11 +207,12 @@ public class BrokerMetricESDAO extends BaseMetricESDAO { } for(String metric : metrics){ - String value = esAggrMap.get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esAggrMap.get(metric).getUnusedMap().get(VALUE); + if(null == value){continue;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricMap.put(metric, metricPoint); @@ -243,12 +244,13 @@ public class BrokerMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE); + if(null == value){return;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); metricPoint.setTimeStamp(timestamp); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricPoints.add(metricPoint); @@ -290,13 +292,14 @@ public class BrokerMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long brokerId = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - Double value = Double.valueOf(esBucket.getAggrMap().get(HIST).getBucketList().get(0).getAggrMap() - .get(metric).getUnusedMap().get(VALUE).toString()); + Object value = esBucket.getAggrMap().get(HIST).getBucketList().get(0).getAggrMap() + .get(metric).getUnusedMap().get(VALUE); + if(null == value){return;} List> brokerValue = (null == metricBrokerValueMap.get(metric)) ? new ArrayList<>() : metricBrokerValueMap.get(metric); - brokerValue.add(new Tuple<>(brokerId, value)); + brokerValue.add(new Tuple<>(brokerId, Double.valueOf(value.toString()))); metricBrokerValueMap.put(metric, brokerValue); } }catch (Exception e){ diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ClusterMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ClusterMetricESDAO.java index 82a86253..d53f83bf 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ClusterMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/ClusterMetricESDAO.java @@ -169,11 +169,12 @@ public class ClusterMetricESDAO extends BaseMetricESDAO { } for(String metric : metrics){ - String value = esAggrMap.get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esAggrMap.get(metric).getUnusedMap().get(VALUE); + if(null == value){continue;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricMap.put(metric, metricPoint); @@ -194,12 +195,13 @@ public class ClusterMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE); + if(null == value){return;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); metricPoint.setTimeStamp(timestamp); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricPoints.add(metricPoint); diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/GroupMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/GroupMetricESDAO.java index cf65e6ef..782adc2f 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/GroupMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/GroupMetricESDAO.java @@ -173,8 +173,9 @@ public class GroupMetricESDAO extends BaseMetricESDAO { } for(String metric : metrics){ - String value = esAggrMap.get(metric).getUnusedMap().get(VALUE).toString(); - groupMetricPO.getMetrics().put(metric, Float.valueOf(value)); + Object value = esAggrMap.get(metric).getUnusedMap().get(VALUE); + if(value == null){continue;} + groupMetricPO.getMetrics().put(metric, Float.parseFloat(value.toString())); } return groupMetricPO; @@ -192,12 +193,13 @@ public class GroupMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE); + if(value == null){return;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); metricPoint.setTimeStamp(timestamp); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricPoints.add(metricPoint); diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/TopicMetricESDAO.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/TopicMetricESDAO.java index e9089c17..e70f2656 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/TopicMetricESDAO.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/es/dao/TopicMetricESDAO.java @@ -337,12 +337,13 @@ public class TopicMetricESDAO extends BaseMetricESDAO { try { if (null != esBucket.getUnusedMap().get(KEY)) { Long timestamp = Long.valueOf(esBucket.getUnusedMap().get(KEY).toString()); - String value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE).toString(); + Object value = esBucket.getAggrMap().get(metric).getUnusedMap().get(VALUE); + if(value == null){return;} MetricPointVO metricPoint = new MetricPointVO(); metricPoint.setAggType(aggType); metricPoint.setTimeStamp(timestamp); - metricPoint.setValue(value); + metricPoint.setValue(value.toString()); metricPoint.setName(metric); metricPoints.add(metricPoint); diff --git a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ClusterMetricESDAOTest.java b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ClusterMetricESDAOTest.java index c69f7129..d0f96bff 100644 --- a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ClusterMetricESDAOTest.java +++ b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ClusterMetricESDAOTest.java @@ -5,13 +5,13 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.search.SearchTerm; import com.xiaojukeji.know.streaming.km.common.bean.entity.search.SearchPage; import com.xiaojukeji.know.streaming.km.common.bean.entity.search.SearchRange; import com.xiaojukeji.know.streaming.km.common.bean.entity.search.SearchSort; +import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ClusterMetricPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; import com.xiaojukeji.know.streaming.km.persistence.es.dao.ClusterMetricESDAO; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; public class ClusterMetricESDAOTest extends KnowStreamApplicationTest { @@ -28,6 +28,53 @@ public class ClusterMetricESDAOTest extends KnowStreamApplicationTest { clusterMetricESDAO.listClusterMetricsByClusterIds(metrics, "avg", clusterIds, startTime, endTime); } + /** + * 测试 + * 获取集群 clusterPhyId 中每个 metric 在指定时间[startTime、endTime]区间内聚合计算(avg、max)之后的统计值 + */ + @Test + public void getClusterMetricsPointTest(){ + Long clusterId = 1L; + List metrics = Arrays.asList( + "Connections", "BytesIn_min_15", "PartitionURP", + "HealthScore_Topics", "EventQueueSize", "ActiveControllerCount", + "GroupDeads", "BytesIn_min_5", "HealthCheckTotal_Topics", + "Partitions", "BytesOut", "Groups", + "BytesOut_min_15", "TotalRequestQueueSize", "HealthCheckPassed_Groups", + "TotalProduceRequests", "HealthCheckPassed", "TotalLogSize", + "GroupEmptys", "PartitionNoLeader", "HealthScore_Brokers", + "Messages", "Topics", "PartitionMinISR_E", + "HealthCheckTotal", "Brokers", "Replicas", + "HealthCheckTotal_Groups", "GroupRebalances", "MessageIn", + "HealthScore", "HealthCheckPassed_Topics", "HealthCheckTotal_Brokers", + "PartitionMinISR_S", "BytesIn", "BytesOut_min_5", + "GroupActives", "MessagesIn", "GroupReBalances", + "HealthCheckPassed_Brokers", "HealthScore_Groups", "TotalResponseQueueSize", + "Zookeepers", "LeaderMessages", "HealthScore_Cluster", + "HealthCheckPassed_Cluster", "HealthCheckTotal_Cluster"); + Long endTime = System.currentTimeMillis(); + Long startTime = endTime - 4 * 60 * 60 * 1000; + + Map metricPointVOS = clusterMetricESDAO.getClusterMetricsPoint( + clusterId, metrics, "avg", startTime, endTime); + + assert null != metricPointVOS; + } + + /** + * 测试 + * 获取集群 clusterId 最新的统计指标 + */ + @Test + public void getClusterLatestMetricsTest(){ + Long clusterId = 1L; + List metrics = Collections.emptyList(); + + ClusterMetricPO clusterLatestMetrics = clusterMetricESDAO.getClusterLatestMetrics(clusterId, metrics); + + assert null != clusterLatestMetrics; + } + @Test public void pagingClusterWithLatestMetricsTest(){ List clusterIds = new ArrayList<>(); diff --git a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ReplicationMetricESDAOTest.java b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ReplicationMetricESDAOTest.java index 6fe0ab4e..98224a3d 100644 --- a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ReplicationMetricESDAOTest.java +++ b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/ReplicationMetricESDAOTest.java @@ -2,11 +2,14 @@ package com.xiaojukeji.know.streaming.km.persistence.es; import com.xiaojukeji.know.streaming.km.KnowStreamApplicationTest; import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ReplicationMetricPO; +import com.xiaojukeji.know.streaming.km.common.bean.vo.metrics.point.MetricPointVO; import com.xiaojukeji.know.streaming.km.persistence.es.dao.ReplicationMetricESDAO; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import java.util.ArrayList; +import java.util.Collections; +import java.util.Map; public class ReplicationMetricESDAOTest extends KnowStreamApplicationTest { @@ -15,7 +18,7 @@ public class ReplicationMetricESDAOTest extends KnowStreamApplicationTest { @Test public void getReplicationLatestMetricsTest(){ - Long clusterPhyId = 2l; + Long clusterPhyId = 2L; Integer brokerId = 1; String topic = "know-streaming-test-251"; Integer partitionId = 1; @@ -24,4 +27,22 @@ public class ReplicationMetricESDAOTest extends KnowStreamApplicationTest { assert null != replicationMetricPO; } + + /** + * 测试 + * 获取集群 clusterPhyId 中每个 metric 的指定 partitionId 在指定时间[startTime、endTime]区间内聚合计算(avg、max)之后的统计值 + */ + @Test + public void getReplicationMetricsPointTest(){ + Long clusterPhyId = 2L; + Integer brokerId = 1; + String topic = "know-streaming-test-251"; + Integer partitionId = 1; + Long endTime = System.currentTimeMillis(); + Long startTime = endTime - 4 * 60 * 60 * 1000; + Map metricPointVOMap = replicationMetricESDAO.getReplicationMetricsPoint( + clusterPhyId, topic, brokerId, partitionId, Collections.emptyList(), "avg", startTime, endTime); + + assert null != metricPointVOMap; + } } diff --git a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/TopicMetricESDAOTest.java b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/TopicMetricESDAOTest.java index e3da2f2c..09db0971 100644 --- a/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/TopicMetricESDAOTest.java +++ b/km-rest/src/test/java/com/xiaojukeji/know/streaming/km/persistence/es/TopicMetricESDAOTest.java @@ -15,7 +15,6 @@ import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; public class TopicMetricESDAOTest extends KnowStreamApplicationTest { @@ -38,14 +37,20 @@ public class TopicMetricESDAOTest extends KnowStreamApplicationTest { @Test public void getTopicsAggsMetricsValueTest(){ Long clusterId = 2L; - String topic = "know-streaming-test-251"; - String topic1 = "topic_test01"; - List metrics = Arrays.asList("BytesIn", "BytesIn_min_5"); + List topicList = Arrays.asList("know-streaming-test-251", "topic_test01"); + List metrics = Arrays.asList( + "Messages", "BytesIn_min_15", "BytesRejected", + "PartitionURP", "HealthCheckTotal", "ReplicationCount", + "CollectMetricsCostTimeUnitSec", "FailedFetchRequests", "BytesIn_min_5", + "HealthScore", "LogSize", "BytesOut", + "FailedProduceRequests", "BytesOut_min_15", "BytesIn", + "BytesOut_min_5", "MessagesIn", "TotalProduceRequests", + "HealthCheckPassed"); Long endTime = System.currentTimeMillis(); Long startTime = endTime - 4 * 60 * 60 * 1000; Table ret = topicMetricESDAO.getTopicsAggsMetricsValue( - clusterId, Arrays.asList(topic, topic1), metrics, "max", startTime, endTime); + clusterId, topicList, metrics, "max", startTime, endTime); assert null != ret; } @@ -90,7 +95,14 @@ public class TopicMetricESDAOTest extends KnowStreamApplicationTest { String topic = "know-streaming-test-251"; String topic1 = "know-streaming-123"; String topic2 = "1209test"; - List metrics = Arrays.asList("BytesIn", "BytesIn_min_5"); + List metrics = Arrays.asList( + "Messages", "BytesIn_min_15", "BytesRejected", + "PartitionURP", "HealthCheckTotal", "ReplicationCount", + "CollectMetricsCostTimeUnitSec", "FailedFetchRequests", "BytesIn_min_5", + "HealthScore", "LogSize", "BytesOut", + "FailedProduceRequests", "BytesOut_min_15", "BytesIn", + "BytesOut_min_5", "MessagesIn", "TotalProduceRequests", + "HealthCheckPassed"); List topicMetricPO = topicMetricESDAO.listTopicLatestMetric(clusterId, Arrays.asList(topic,topic1,topic2), metrics); @@ -101,7 +113,14 @@ public class TopicMetricESDAOTest extends KnowStreamApplicationTest { @Test public void listBrokerMetricsByTopicsTest(){ Long clusterId = 2L; - List metrics = Arrays.asList("BytesIn", "BytesIn_min_5"); + List metrics = Arrays.asList( + "Messages", "BytesIn_min_15", "BytesRejected", + "PartitionURP", "HealthCheckTotal", "ReplicationCount", + "CollectMetricsCostTimeUnitSec", "FailedFetchRequests", "BytesIn_min_5", + "HealthScore", "LogSize", "BytesOut", + "FailedProduceRequests", "BytesOut_min_15", "BytesIn", + "BytesOut_min_5", "MessagesIn", "TotalProduceRequests", + "HealthCheckPassed"); List topics = Arrays.asList("QAtest_1_13", "__consumer_offsets"); Long endTime = System.currentTimeMillis(); Long startTime = endTime - 4 * 60 * 60 * 1000; From 714e9a56a36c3d346b2a347890deb353d2bfeb8b Mon Sep 17 00:00:00 2001 From: zengqiao Date: Thu, 20 Oct 2022 19:16:43 +0800 Subject: [PATCH 130/145] =?UTF-8?q?[Optimize]=20=E4=BC=98=E5=8C=96ZK?= =?UTF-8?q?=E6=8C=87=E6=A0=87=E7=9A=84=E8=8E=B7=E5=8F=96=EF=BC=8C=E5=87=8F?= =?UTF-8?q?=E5=B0=91=E9=87=8D=E5=A4=8D=E9=87=87=E9=9B=86=E7=9A=84=E5=87=BA?= =?UTF-8?q?=E7=8E=B0=20(#709)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、避免不同集群,相同的ZK地址时,指标重复获取的情况; 2、避免集群某个ZK地址获取指标失败时,下一个周期还会继续尝试从该地址获取指标; --- .../km/core/cache/ZookeeperLocalCache.java | 46 ++++++++++ .../impl/ZookeeperMetricServiceImpl.java | 84 ++++++++++++------- 2 files changed, 100 insertions(+), 30 deletions(-) create mode 100644 km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/ZookeeperLocalCache.java diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/ZookeeperLocalCache.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/ZookeeperLocalCache.java new file mode 100644 index 00000000..24f6c7f2 --- /dev/null +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/ZookeeperLocalCache.java @@ -0,0 +1,46 @@ +package com.xiaojukeji.know.streaming.km.core.cache; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.BaseFourLetterWordCmdData; + +import java.util.concurrent.TimeUnit; + +public class ZookeeperLocalCache { + private static final Cache fourLetterCmdFailedServerCache = Caffeine.newBuilder() + .expireAfterWrite(10, TimeUnit.MINUTES) + .maximumSize(10000) + .build(); + + private static final Cache fourLetterCmdDataCache = Caffeine.newBuilder() + .expireAfterWrite(60, TimeUnit.SECONDS) + .maximumSize(10000) + .build(); + + public static boolean canUse(String host, int port, String cmd) { + String data = fourLetterCmdFailedServerCache.getIfPresent(gen4lwFailedKey(host, port, cmd)); + + return data == null; + } + + public static void setFailed(String host, int port, String cmd) { + fourLetterCmdFailedServerCache.put(gen4lwFailedKey(host, port, cmd), ""); + } + + public static BaseFourLetterWordCmdData getData(String host, int port, String cmd) { + return fourLetterCmdDataCache.getIfPresent(gen4lwFailedKey(host, port, cmd)); + } + + public static void putData(String host, int port, String cmd, BaseFourLetterWordCmdData cmdData) { + fourLetterCmdDataCache.put(gen4lwFailedKey(host, port, cmd), cmdData); + } + + /**************************************************** private method ****************************************************/ + + private static String gen4lwFailedKey(String host, int port, String cmd) { + return host + "@" + port + "@" + cmd; + } + + + +} diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java index dea1d877..212513aa 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/zookeeper/impl/ZookeeperMetricServiceImpl.java @@ -10,6 +10,7 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.param.metric.Zookeepe import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus; import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionJmxInfo; +import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.BaseFourLetterWordCmdData; import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.ServerCmdData; import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.MonitorCmdDataParser; import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterword.parser.ServerCmdDataParser; @@ -26,8 +27,8 @@ import com.xiaojukeji.know.streaming.km.common.bean.entity.zookeeper.fourletterw import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.ZookeeperMetrics; import com.xiaojukeji.know.streaming.km.common.bean.po.metrice.ZookeeperMetricPO; import com.xiaojukeji.know.streaming.km.common.utils.zookeeper.FourLetterWordUtil; +import com.xiaojukeji.know.streaming.km.core.cache.ZookeeperLocalCache; import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; -import com.xiaojukeji.know.streaming.km.core.service.kafkacontroller.KafkaControllerService; import com.xiaojukeji.know.streaming.km.core.service.version.BaseMetricService; import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperMetricService; import com.xiaojukeji.know.streaming.km.core.service.zookeeper.ZookeeperService; @@ -53,6 +54,7 @@ public class ZookeeperMetricServiceImpl extends BaseMetricService implements Zoo public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_MONITOR_CMD = "getMetricFromMonitorCmd"; public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_SERVER_CMD = "getMetricFromServerCmd"; public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_KAFKA_BY_JMX = "getMetricFromKafkaByJMX"; + public static final String ZOOKEEPER_METHOD_GET_METRIC_FROM_HEALTH_SERVICE = "getMetricFromHealthService"; @Autowired private ClusterPhyService clusterPhyService; @@ -66,9 +68,6 @@ public class ZookeeperMetricServiceImpl extends BaseMetricService implements Zoo @Autowired private KafkaJMXClient kafkaJMXClient; - @Autowired - private KafkaControllerService kafkaControllerService; - @Override protected VersionItemTypeEnum getVersionItemType() { return VersionItemTypeEnum.METRIC_ZOOKEEPER; @@ -171,24 +170,37 @@ public class ZookeeperMetricServiceImpl extends BaseMetricService implements Zoo Result rz = null; for (Tuple hostPort: param.getZkAddressList()) { - Result cmdDataResult = FourLetterWordUtil.executeFourLetterCmd( - param.getClusterPhyId(), - hostPort.getV1(), - hostPort.getV2(), - param.getZkConfig() != null ? param.getZkConfig().getOpenSecure(): false, - param.getZkConfig() != null ? param.getZkConfig().getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, - new ServerCmdDataParser() - ); + ServerCmdData cmdData = null; - if (cmdDataResult.failed()) { - rz = Result.buildFromIgnoreData(cmdDataResult); + BaseFourLetterWordCmdData baseCmdData = ZookeeperLocalCache.getData(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.ServerCmd); + if (baseCmdData != null) { + cmdData = (ServerCmdData) baseCmdData; + } else if (ZookeeperLocalCache.canUse(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.ServerCmd)) { + Result cmdDataResult = FourLetterWordUtil.executeFourLetterCmd( + param.getClusterPhyId(), + hostPort.getV1(), + hostPort.getV2(), + param.getZkConfig() != null ? param.getZkConfig().getOpenSecure(): false, + param.getZkConfig() != null ? param.getZkConfig().getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, + new ServerCmdDataParser() + ); + + if (cmdDataResult.failed()) { + ZookeeperLocalCache.setFailed(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.ServerCmd); + + rz = Result.buildFromIgnoreData(cmdDataResult); + continue; + } + + cmdData = cmdDataResult.getData(); + ZookeeperLocalCache.putData(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.ServerCmd, cmdData); + } else { + // baseCmdData为空 且 当前地址不可使用 continue; } - ServerCmdData cmdData = cmdDataResult.getData(); - ZookeeperMetrics metrics = new ZookeeperMetrics(param.getClusterPhyId()); - metrics.putMetric(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY, cmdData.getZkAvgLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY, cmdData.getZkAvgLatency()); metrics.putMetric(ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY, cmdData.getZkMinLatency().floatValue()); metrics.putMetric(ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY, cmdData.getZkMaxLatency().floatValue()); metrics.putMetric(ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS, cmdData.getZkOutstandingRequests().floatValue()); @@ -208,24 +220,36 @@ public class ZookeeperMetricServiceImpl extends BaseMetricService implements Zoo Result rz = null; for (Tuple hostPort: param.getZkAddressList()) { - Result cmdDataResult = FourLetterWordUtil.executeFourLetterCmd( - param.getClusterPhyId(), - hostPort.getV1(), - hostPort.getV2(), - param.getZkConfig() != null ? param.getZkConfig().getOpenSecure(): false, - param.getZkConfig() != null ? param.getZkConfig().getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, - new MonitorCmdDataParser() - ); + MonitorCmdData cmdData = null; - if (cmdDataResult.failed()) { - rz = Result.buildFromIgnoreData(cmdDataResult); + BaseFourLetterWordCmdData baseCmdData = ZookeeperLocalCache.getData(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.MonitorCmd); + if (baseCmdData != null) { + cmdData = (MonitorCmdData) baseCmdData; + } else if (ZookeeperLocalCache.canUse(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.MonitorCmd)) { + Result cmdDataResult = FourLetterWordUtil.executeFourLetterCmd( + param.getClusterPhyId(), + hostPort.getV1(), + hostPort.getV2(), + param.getZkConfig() != null ? param.getZkConfig().getOpenSecure(): false, + param.getZkConfig() != null ? param.getZkConfig().getRequestTimeoutUnitMs(): Constant.DEFAULT_REQUEST_TIMEOUT_UNIT_MS, + new MonitorCmdDataParser() + ); + + if (cmdDataResult.failed()) { + ZookeeperLocalCache.setFailed(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.MonitorCmd); + + rz = Result.buildFromIgnoreData(cmdDataResult); + continue; + } + + cmdData = cmdDataResult.getData(); + ZookeeperLocalCache.putData(hostPort.getV1(), hostPort.getV2(), FourLetterWordUtil.MonitorCmd, cmdData); + } else { continue; } - MonitorCmdData cmdData = cmdDataResult.getData(); - ZookeeperMetrics metrics = new ZookeeperMetrics(param.getClusterPhyId()); - metrics.putMetric(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY, cmdData.getZkAvgLatency().floatValue()); + metrics.putMetric(ZOOKEEPER_METRIC_AVG_REQUEST_LATENCY, cmdData.getZkAvgLatency()); metrics.putMetric(ZOOKEEPER_METRIC_MIN_REQUEST_LATENCY, cmdData.getZkMinLatency().floatValue()); metrics.putMetric(ZOOKEEPER_METRIC_MAX_REQUEST_LATENCY, cmdData.getZkMaxLatency().floatValue()); metrics.putMetric(ZOOKEEPER_METRIC_OUTSTANDING_REQUESTS, cmdData.getZkOutstandingRequests().floatValue()); From af1bb2ccbdc1c63c9e463fe9acec25933bfcae80 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Fri, 21 Oct 2022 11:47:28 +0800 Subject: [PATCH 131/145] =?UTF-8?q?[Optimize]=20=E5=88=A0=E9=99=A4Replica?= =?UTF-8?q?=E6=8C=87=E6=A0=87=E9=87=87=E9=9B=86=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、当集群存在较多副本时,指标采集的性能会严重降低; 2、Replica的指标基本上都是在实时获取时才需要,因此当前先将Replica指标采集任务关闭,后续依据产品需要再看是否开启; --- .../metric/ReplicaMetricCollector.java | 2 +- .../cache/CollectedMetricsLocalCache.java | 16 ----- .../broker/impl/BrokerMetricServiceImpl.java | 39 +++++++++-- .../service/replica/ReplicaMetricService.java | 4 +- .../impl/ReplicaMetricServiceImpl.java | 55 ++++++++-------- .../v3/replica/ReplicaMetricsController.java | 3 +- .../metrics/ReplicaMetricCollectorTask.java | 64 +++++++++---------- 7 files changed, 100 insertions(+), 83 deletions(-) diff --git a/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ReplicaMetricCollector.java b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ReplicaMetricCollector.java index 5f712f93..3f9e0035 100644 --- a/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ReplicaMetricCollector.java +++ b/km-collector/src/main/java/com/xiaojukeji/know/streaming/km/collector/metric/ReplicaMetricCollector.java @@ -91,7 +91,7 @@ public class ReplicaMetricCollector extends AbstractMetricCollector ret = replicaMetricService.collectReplicaMetricsFromKafkaWithCache( + Result ret = replicaMetricService.collectReplicaMetricsFromKafka( clusterPhyId, metrics.getTopic(), metrics.getBrokerId(), diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/CollectedMetricsLocalCache.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/CollectedMetricsLocalCache.java index bc5b1c34..2fc0a4ff 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/CollectedMetricsLocalCache.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/cache/CollectedMetricsLocalCache.java @@ -24,11 +24,6 @@ public class CollectedMetricsLocalCache { .maximumSize(10000) .build(); - private static final Cache replicaMetricsValueCache = Caffeine.newBuilder() - .expireAfterWrite(90, TimeUnit.SECONDS) - .maximumSize(20000) - .build(); - public static Float getBrokerMetrics(String brokerMetricKey) { return brokerMetricsCache.getIfPresent(brokerMetricKey); } @@ -64,17 +59,6 @@ public class CollectedMetricsLocalCache { partitionMetricsCache.put(partitionMetricsKey, metricsList); } - public static Float getReplicaMetrics(String replicaMetricsKey) { - return replicaMetricsValueCache.getIfPresent(replicaMetricsKey); - } - - public static void putReplicaMetrics(String replicaMetricsKey, Float value) { - if (value == null) { - return; - } - replicaMetricsValueCache.put(replicaMetricsKey, value); - } - public static String genBrokerMetricKey(Long clusterPhyId, Integer brokerId, String metricName) { return clusterPhyId + "@" + brokerId + "@" + metricName; } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerMetricServiceImpl.java index 93c343ff..e82882e1 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerMetricServiceImpl.java @@ -37,6 +37,8 @@ import com.xiaojukeji.know.streaming.km.core.service.version.metrics.BrokerMetri import com.xiaojukeji.know.streaming.km.core.service.version.metrics.ReplicaMetricVersionItems; import com.xiaojukeji.know.streaming.km.persistence.es.dao.BrokerMetricESDAO; import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaJMXClient; +import org.apache.kafka.clients.admin.LogDirDescription; +import org.apache.kafka.clients.admin.ReplicaInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -49,6 +51,7 @@ import java.util.*; import java.util.stream.Collectors; import static com.xiaojukeji.know.streaming.km.common.bean.entity.result.ResultStatus.*; +import static com.xiaojukeji.know.streaming.km.common.enums.version.VersionEnum.*; /** * @author didi @@ -105,7 +108,11 @@ public class BrokerMetricServiceImpl extends BaseMetricService implements Broker registerVCHandler( BROKER_METHOD_GET_HEALTH_SCORE, this::getMetricHealthScore); registerVCHandler( BROKER_METHOD_GET_PARTITIONS_SKEW, this::getPartitionsSkew); registerVCHandler( BROKER_METHOD_GET_LEADERS_SKEW, this::getLeadersSkew); - registerVCHandler( BROKER_METHOD_GET_LOG_SIZE, this::getLogSize); +// registerVCHandler( BROKER_METHOD_GET_LOG_SIZE, this::getLogSize); + + registerVCHandler( BROKER_METHOD_GET_LOG_SIZE, V_0_10_0_0, V_1_0_0, "getLogSizeFromJmx", this::getLogSizeFromJmx); + registerVCHandler( BROKER_METHOD_GET_LOG_SIZE, V_1_0_0, V_MAX, "getLogSizeFromClient", this::getLogSizeFromClient); + registerVCHandler( BROKER_METHOD_IS_BROKER_ALIVE, this::isBrokerAlive); } @@ -351,7 +358,7 @@ public class BrokerMetricServiceImpl extends BaseMetricService implements Broker ); } - private Result getLogSize(VersionItemParam metricParam) { + private Result getLogSizeFromJmx(VersionItemParam metricParam) { BrokerMetricParam param = (BrokerMetricParam)metricParam; String metric = param.getMetric(); @@ -360,19 +367,17 @@ public class BrokerMetricServiceImpl extends BaseMetricService implements Broker List partitions = partitionService.listPartitionByBroker(clusterId, brokerId); - JmxConnectorWrap jmxConnectorWrap = kafkaJMXClient.getClientWithCheck(clusterId, brokerId); - if (ValidateUtils.isNull(jmxConnectorWrap)){return Result.buildFailure(VC_JMX_INIT_ERROR);} - Float logSizeSum = 0f; for(Partition p : partitions) { try { - Result metricsResult = replicaMetricService.collectReplicaMetricsFromKafkaWithCache( + Result metricsResult = replicaMetricService.collectReplicaMetricsFromKafka( clusterId, p.getTopicName(), brokerId, p.getPartitionId(), ReplicaMetricVersionItems.REPLICATION_METRIC_LOG_SIZE ); + if(null == metricsResult || metricsResult.failed() || null == metricsResult.getData()) { continue; } @@ -391,6 +396,28 @@ public class BrokerMetricServiceImpl extends BaseMetricService implements Broker return Result.buildSuc(BrokerMetrics.initWithMetric(clusterId, brokerId, metric, logSizeSum)); } + private Result getLogSizeFromClient(VersionItemParam metricParam) { + BrokerMetricParam param = (BrokerMetricParam)metricParam; + + String metric = param.getMetric(); + Long clusterId = param.getClusterId(); + Integer brokerId = param.getBrokerId(); + + Result> descriptionMapResult = brokerService.getBrokerLogDirDescFromKafka(clusterId, brokerId); + if(null == descriptionMapResult || descriptionMapResult.failed() || null == descriptionMapResult.getData()) { + return Result.buildFromIgnoreData(descriptionMapResult); + } + + Float logSizeSum = 0f; + for (LogDirDescription logDirDescription: descriptionMapResult.getData().values()) { + for (ReplicaInfo replicaInfo: logDirDescription.replicaInfos().values()) { + logSizeSum += replicaInfo.size(); + } + } + + return Result.buildSuc(BrokerMetrics.initWithMetric(clusterId, brokerId, metric, logSizeSum)); + } + private Result getLeadersSkew(VersionItemParam metricParam) { BrokerMetricParam param = (BrokerMetricParam)metricParam; diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/ReplicaMetricService.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/ReplicaMetricService.java index 987303f8..c0a44586 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/ReplicaMetricService.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/ReplicaMetricService.java @@ -13,12 +13,14 @@ public interface ReplicaMetricService { * 从kafka中采集指标 */ Result collectReplicaMetricsFromKafka(Long clusterId, String topic, Integer partitionId, Integer brokerId, String metric); - Result collectReplicaMetricsFromKafkaWithCache(Long clusterPhyId, String topic, Integer brokerId, Integer partitionId, String metric); + Result collectReplicaMetricsFromKafka(Long clusterId, String topicName, Integer partitionId, Integer brokerId, List metricNameList); /** * 从ES中获取指标 */ + @Deprecated Result> getMetricPointsFromES(Long clusterPhyId, Integer brokerId, String topicName, Integer partitionId, MetricDTO dto); + @Deprecated Result getLatestMetricsFromES(Long clusterPhyId, Integer brokerId, String topicName, Integer partitionId, List metricNames); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/impl/ReplicaMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/impl/ReplicaMetricServiceImpl.java index 460e6520..848c8601 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/impl/ReplicaMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/replica/impl/ReplicaMetricServiceImpl.java @@ -17,7 +17,6 @@ import com.xiaojukeji.know.streaming.km.common.jmx.JmxConnectorWrap; import com.xiaojukeji.know.streaming.km.common.utils.BeanUtil; import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; -import com.xiaojukeji.know.streaming.km.core.cache.CollectedMetricsLocalCache; import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionService; import com.xiaojukeji.know.streaming.km.core.service.replica.ReplicaMetricService; import com.xiaojukeji.know.streaming.km.core.service.version.BaseMetricService; @@ -77,32 +76,36 @@ public class ReplicaMetricServiceImpl extends BaseMetricService implements Repli } @Override - public Result collectReplicaMetricsFromKafkaWithCache(Long clusterPhyId, - String topic, - Integer brokerId, - Integer partitionId, - String metric) { - String replicaMetricsKey = CollectedMetricsLocalCache.genReplicaMetricCacheKey(clusterPhyId, brokerId, topic, partitionId, metric); + public Result collectReplicaMetricsFromKafka(Long clusterId, String topicName, Integer partitionId, Integer brokerId, List metricNameList) { + ReplicationMetrics metrics = new ReplicationMetrics(clusterId, topicName, brokerId, partitionId); + for (String metricName: metricNameList) { + try { + if (metrics.getMetrics().containsKey(metricName)) { + continue; + } - Float keyValue = CollectedMetricsLocalCache.getReplicaMetrics(replicaMetricsKey); - if(null != keyValue){ - ReplicationMetrics replicationMetrics = new ReplicationMetrics(clusterPhyId, topic, partitionId, brokerId); - replicationMetrics.putMetric(metric, keyValue); - return Result.buildSuc(replicationMetrics); + Result ret = this.collectReplicaMetricsFromKafka( + clusterId, + metrics.getTopic(), + metrics.getBrokerId(), + metrics.getPartitionId(), + metricName + ); + + if (null == ret || ret.failed() || null == ret.getData()) { + continue; + } + + metrics.putMetric(ret.getData().getMetrics()); + } catch (Exception e) { + LOGGER.error( + "method=collectReplicaMetricsFromKafka||clusterPhyId={}||topicName={}||partition={}||brokerId={}||metricName={}||errMsg=exception!", + clusterId, topicName, partitionId, brokerId, e + ); + } } - Result ret = collectReplicaMetricsFromKafka(clusterPhyId, topic, partitionId, brokerId, metric); - if(null == ret || ret.failed() || null == ret.getData()){return ret;} - - // 更新cache - ret.getData().getMetrics().entrySet().stream().forEach( - metricNameAndValueEntry -> CollectedMetricsLocalCache.putReplicaMetrics( - replicaMetricsKey, - metricNameAndValueEntry.getValue() - ) - ); - - return ret; + return Result.buildSuc(metrics); } @Override @@ -167,8 +170,8 @@ public class ReplicaMetricServiceImpl extends BaseMetricService implements Repli Integer brokerId = metricParam.getBrokerId(); Integer partitionId = metricParam.getPartitionId(); - Result endRet = this.collectReplicaMetricsFromKafkaWithCache(clusterId, topic, brokerId, partitionId, REPLICATION_METRIC_LOG_END_OFFSET); - Result startRet = this.collectReplicaMetricsFromKafkaWithCache(clusterId, topic, brokerId, partitionId, REPLICATION_METRIC_LOG_START_OFFSET); + Result endRet = this.collectReplicaMetricsFromKafka(clusterId, topic, brokerId, partitionId, REPLICATION_METRIC_LOG_END_OFFSET); + Result startRet = this.collectReplicaMetricsFromKafka(clusterId, topic, brokerId, partitionId, REPLICATION_METRIC_LOG_START_OFFSET); ReplicationMetrics replicationMetrics = new ReplicationMetrics(clusterId, topic, brokerId, partitionId); if(null != endRet && endRet.successful() && null != startRet && startRet.successful()){ diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/replica/ReplicaMetricsController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/replica/ReplicaMetricsController.java index 13e2c855..7e276aff 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/replica/ReplicaMetricsController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/replica/ReplicaMetricsController.java @@ -26,6 +26,7 @@ public class ReplicaMetricsController { @Autowired private ReplicaMetricService replicationMetricService; + @Deprecated @ApiOperation(value = "Replica指标-单个Replica") @PostMapping(value = "clusters/{clusterPhyId}/brokers/{brokerId}/topics/{topicName}/partitions/{partitionId}/metric-points") @ResponseBody @@ -45,7 +46,7 @@ public class ReplicaMetricsController { @PathVariable String topicName, @PathVariable Integer partitionId, @RequestBody List metricsNames) { - Result metricsResult = replicationMetricService.getLatestMetricsFromES(clusterPhyId, brokerId, topicName, partitionId, metricsNames); + Result metricsResult = replicationMetricService.collectReplicaMetricsFromKafka(clusterPhyId, topicName, partitionId, brokerId, metricsNames); if (metricsResult.failed()) { return Result.buildFromIgnoreData(metricsResult); } diff --git a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ReplicaMetricCollectorTask.java b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ReplicaMetricCollectorTask.java index 6b93e324..7e52c2f4 100644 --- a/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ReplicaMetricCollectorTask.java +++ b/km-task/src/main/java/com/xiaojukeji/know/streaming/km/task/metrics/ReplicaMetricCollectorTask.java @@ -1,32 +1,32 @@ -package com.xiaojukeji.know.streaming.km.task.metrics; - -import com.didiglobal.logi.job.annotation.Task; -import com.didiglobal.logi.job.common.TaskResult; -import com.didiglobal.logi.job.core.consensual.ConsensualEnum; -import com.xiaojukeji.know.streaming.km.collector.metric.ReplicaMetricCollector; -import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; - -/** - * @author didi - */ -@Slf4j -@Task(name = "ReplicaMetricCollectorTask", - description = "Replica指标采集任务", - cron = "0 0/1 * * * ? *", - autoRegister = true, - consensual = ConsensualEnum.BROADCAST, - timeout = 2 * 60) -public class ReplicaMetricCollectorTask extends AbstractAsyncMetricsDispatchTask { - - @Autowired - private ReplicaMetricCollector replicaMetricCollector; - - @Override - public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception { - replicaMetricCollector.collectMetrics(clusterPhy); - - return TaskResult.SUCCESS; - } -} +//package com.xiaojukeji.know.streaming.km.task.metrics; +// +//import com.didiglobal.logi.job.annotation.Task; +//import com.didiglobal.logi.job.common.TaskResult; +//import com.didiglobal.logi.job.core.consensual.ConsensualEnum; +//import com.xiaojukeji.know.streaming.km.collector.metric.ReplicaMetricCollector; +//import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.beans.factory.annotation.Autowired; +// +///** +// * @author didi +// */ +//@Slf4j +//@Task(name = "ReplicaMetricCollectorTask", +// description = "Replica指标采集任务", +// cron = "0 0/1 * * * ? *", +// autoRegister = true, +// consensual = ConsensualEnum.BROADCAST, +// timeout = 2 * 60) +//public class ReplicaMetricCollectorTask extends AbstractAsyncMetricsDispatchTask { +// +// @Autowired +// private ReplicaMetricCollector replicaMetricCollector; +// +// @Override +// public TaskResult processClusterTask(ClusterPhy clusterPhy, long triggerTimeUnitMs) throws Exception { +// replicaMetricCollector.collectMetrics(clusterPhy); +// +// return TaskResult.SUCCESS; +// } +//} From f9ec890e1db30a5b09d76c555deb0eb1c4b4d677 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Fri, 21 Oct 2022 11:58:57 +0800 Subject: [PATCH 132/145] =?UTF-8?q?[Optimize]=20=E9=9B=86=E7=BE=A4Broker?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E4=B8=AD=EF=BC=8C=E8=A1=A5=E5=85=85Jmx?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E6=88=90=E5=8A=9F=E8=BF=9E=E6=8E=A5=E7=9A=84?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、当前页面无数据时,一部分的原因是JMX连接失败导致; 2、Broker列表中增加是否连接成功的信息,便于问题的排查; --- .../impl/ClusterBrokersManagerImpl.java | 24 ++++++++++++++----- .../cluster/res/ClusterBrokersOverviewVO.java | 3 +++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java index 50c3596d..6b180126 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java @@ -24,6 +24,7 @@ import com.xiaojukeji.know.streaming.km.core.service.broker.BrokerMetricService; import com.xiaojukeji.know.streaming.km.core.service.broker.BrokerService; import com.xiaojukeji.know.streaming.km.core.service.kafkacontroller.KafkaControllerService; import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService; +import com.xiaojukeji.know.streaming.km.persistence.kafka.KafkaJMXClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -51,6 +52,9 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { @Autowired private KafkaControllerService kafkaControllerService; + @Autowired + private KafkaJMXClient kafkaJMXClient; + @Override public PaginationResult getClusterPhyBrokersOverview(Long clusterPhyId, ClusterBrokersOverviewDTO dto) { // 获取集群Broker列表 @@ -75,6 +79,10 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { //获取controller信息 KafkaController kafkaController = kafkaControllerService.getKafkaControllerFromDB(clusterPhyId); + //获取jmx状态信息 + Map jmxConnectedMap = new HashMap<>(); + brokerList.forEach(elem -> jmxConnectedMap.put(elem.getBrokerId(), kafkaJMXClient.getClientWithCheck(clusterPhyId, elem.getBrokerId()) != null)); + // 格式转换 return PaginationResult.buildSuc( this.convert2ClusterBrokersOverviewVOList( @@ -83,7 +91,8 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { metricsResult.getData(), groupTopic, transactionTopic, - kafkaController + kafkaController, + jmxConnectedMap ), paginationResult ); @@ -165,22 +174,24 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { List metricsList, Topic groupTopic, Topic transactionTopic, - KafkaController kafkaController) { - Map metricsMap = metricsList == null? new HashMap<>(): metricsList.stream().collect(Collectors.toMap(BrokerMetrics::getBrokerId, Function.identity())); + KafkaController kafkaController, + Map jmxConnectedMap) { + Map metricsMap = metricsList == null ? new HashMap<>() : metricsList.stream().collect(Collectors.toMap(BrokerMetrics::getBrokerId, Function.identity())); - Map brokerMap = brokerList == null? new HashMap<>(): brokerList.stream().collect(Collectors.toMap(Broker::getBrokerId, Function.identity())); + Map brokerMap = brokerList == null ? new HashMap<>() : brokerList.stream().collect(Collectors.toMap(Broker::getBrokerId, Function.identity())); List voList = new ArrayList<>(pagedBrokerIdList.size()); for (Integer brokerId : pagedBrokerIdList) { Broker broker = brokerMap.get(brokerId); BrokerMetrics brokerMetrics = metricsMap.get(brokerId); + Boolean jmxConnected = jmxConnectedMap.get(brokerId); - voList.add(this.convert2ClusterBrokersOverviewVO(brokerId, broker, brokerMetrics, groupTopic, transactionTopic, kafkaController)); + voList.add(this.convert2ClusterBrokersOverviewVO(brokerId, broker, brokerMetrics, groupTopic, transactionTopic, kafkaController, jmxConnected)); } return voList; } - private ClusterBrokersOverviewVO convert2ClusterBrokersOverviewVO(Integer brokerId, Broker broker, BrokerMetrics brokerMetrics, Topic groupTopic, Topic transactionTopic, KafkaController kafkaController) { + private ClusterBrokersOverviewVO convert2ClusterBrokersOverviewVO(Integer brokerId, Broker broker, BrokerMetrics brokerMetrics, Topic groupTopic, Topic transactionTopic, KafkaController kafkaController, Boolean jmxConnected) { ClusterBrokersOverviewVO clusterBrokersOverviewVO = new ClusterBrokersOverviewVO(); clusterBrokersOverviewVO.setBrokerId(brokerId); if (broker != null) { @@ -203,6 +214,7 @@ public class ClusterBrokersManagerImpl implements ClusterBrokersManager { } clusterBrokersOverviewVO.setLatestMetrics(brokerMetrics); + clusterBrokersOverviewVO.setJmxConnected(jmxConnected); return clusterBrokersOverviewVO; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/cluster/res/ClusterBrokersOverviewVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/cluster/res/ClusterBrokersOverviewVO.java index be1b529d..b172403c 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/cluster/res/ClusterBrokersOverviewVO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/cluster/res/ClusterBrokersOverviewVO.java @@ -31,6 +31,9 @@ public class ClusterBrokersOverviewVO extends BrokerMetadataVO { @ApiModelProperty(value = "jmx端口") private Integer jmxPort; + @ApiModelProperty(value = "jmx连接状态 true:连接成功 false:连接失败") + private Boolean jmxConnected; + @ApiModelProperty(value = "是否存活 true:存活 false:不存活") private Boolean alive; } From 78b02f80ba0d99373831f9cec6cc46bf31d6330e Mon Sep 17 00:00:00 2001 From: zengqiao Date: Fri, 21 Oct 2022 12:06:22 +0800 Subject: [PATCH 133/145] =?UTF-8?q?[Bugfix]=20=E4=BF=AE=E5=A4=8D=E6=8C=87?= =?UTF-8?q?=E6=A0=87=E7=89=88=E6=9C=AC=E4=BF=A1=E6=81=AFlist=E8=BD=ACmap?= =?UTF-8?q?=E6=97=B6=E5=87=BA=E7=8E=B0key=E5=86=B2=E7=AA=81=E4=BB=8E?= =?UTF-8?q?=E8=80=8C=E6=8A=9B=E5=87=BA=E5=BC=82=E5=B8=B8=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../km/biz/version/impl/VersionControlManagerImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java index 0460b601..70f4814b 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java @@ -111,7 +111,11 @@ public class VersionControlManagerImpl implements VersionControlManager { allVersionItemVO.addAll(ConvertUtil.list2List(versionControlService.listVersionControlItem(WEB_OP.getCode()), VersionItemVO.class)); Map map = allVersionItemVO.stream().collect( - Collectors.toMap(u -> u.getType() + "@" + u.getName(), Function.identity() )); + Collectors.toMap( + u -> u.getType() + "@" + u.getName(), + Function.identity(), + (v1, v2) -> v1) + ); return Result.buildSuc(map); } From 538d54cae011ced49563de5e18ea59d0d16b7529 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Fri, 21 Oct 2022 14:32:07 +0800 Subject: [PATCH 134/145] =?UTF-8?q?=E5=AE=89=E8=A3=85=E5=8C=85=E4=B8=AD?= =?UTF-8?q?=EF=BC=8C=E5=8E=BB=E9=99=A4docs=E7=9B=B8=E5=85=B3=E7=9A=84?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-dist/README.md | 3 --- km-dist/ReleaseKnowStreaming.xml | 8 -------- 2 files changed, 11 deletions(-) diff --git a/km-dist/README.md b/km-dist/README.md index 5c6d192a..f5a71758 100644 --- a/km-dist/README.md +++ b/km-dist/README.md @@ -11,9 +11,6 @@ - logback-spring.xml:日志配置 -- docs:产品相关文档 - - - helm:安装KnowStreaming的Helm相关文件 diff --git a/km-dist/ReleaseKnowStreaming.xml b/km-dist/ReleaseKnowStreaming.xml index 80503225..046a5cfd 100755 --- a/km-dist/ReleaseKnowStreaming.xml +++ b/km-dist/ReleaseKnowStreaming.xml @@ -17,14 +17,6 @@ logback-spring.xml - - ../docs - docs - - * - */* - - ../bin bin From 3fb35d1fcc50a2331b98546f1f0f11d3e063addd Mon Sep 17 00:00:00 2001 From: zengqiao Date: Fri, 21 Oct 2022 14:32:57 +0800 Subject: [PATCH 135/145] =?UTF-8?q?=E8=A1=A5=E5=85=85v3.0.1=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=8D=87=E7=BA=A7=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/install_guide/版本升级手册.md | 107 +++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 5 deletions(-) diff --git a/docs/install_guide/版本升级手册.md b/docs/install_guide/版本升级手册.md index dfa4a8e2..2fef58f0 100644 --- a/docs/install_guide/版本升级手册.md +++ b/docs/install_guide/版本升级手册.md @@ -4,9 +4,106 @@ - 如果想升级至具体版本,需要将你当前版本至你期望使用版本的变更统统执行一遍,然后才能正常使用。 - 如果中间某个版本没有升级信息,则表示该版本直接替换安装包即可从前一个版本升级至当前版本。 - ### 6.2.0、升级至 `master` 版本 +暂无 + +### 6.2.1、升级至 `v3.0.1` 版本 + +**ES 索引模版** +```bash +# 新增 ks_kafka_zookeeper_metric 索引模版。 +# 可通过再次执行 bin/init_es_template.sh 脚本,创建该索引模版。 + +# 索引模版内容 +PUT _template/ks_kafka_zookeeper_metric +{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_zookeeper_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "AvgRequestLatency" : { + "type" : "double" + }, + "MinRequestLatency" : { + "type" : "double" + }, + "MaxRequestLatency" : { + "type" : "double" + }, + "OutstandingRequests" : { + "type" : "double" + }, + "NodeCount" : { + "type" : "double" + }, + "WatchCount" : { + "type" : "double" + }, + "NumAliveConnections" : { + "type" : "double" + }, + "PacketsReceived" : { + "type" : "double" + }, + "PacketsSent" : { + "type" : "double" + }, + "EphemeralsCount" : { + "type" : "double" + }, + "ApproximateDataSize" : { + "type" : "double" + }, + "OpenFileDescriptorCount" : { + "type" : "double" + }, + "MaxFileDescriptorCount" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + } +``` + + **SQL 变更** ```sql @@ -48,7 +145,7 @@ CREATE TABLE `ks_km_group` ( --- -### 6.2.1、升级至 `v3.0.0` 版本 +### 6.2.2、升级至 `v3.0.0` 版本 **SQL 变更** @@ -60,7 +157,7 @@ ADD COLUMN `zk_properties` TEXT NULL COMMENT 'ZK配置' AFTER `jmx_properties`; --- -### 6.2.2、升级至 `v3.0.0-beta.2`版本 +### 6.2.3、升级至 `v3.0.0-beta.2`版本 **配置变更** @@ -131,7 +228,7 @@ ALTER TABLE `logi_security_oplog` --- -### 6.2.3、升级至 `v3.0.0-beta.1`版本 +### 6.2.4、升级至 `v3.0.0-beta.1`版本 **SQL 变更** @@ -150,7 +247,7 @@ ALTER COLUMN `operation_methods` set default ''; --- -### 6.2.4、`2.x`版本 升级至 `v3.0.0-beta.0`版本 +### 6.2.5、`2.x`版本 升级至 `v3.0.0-beta.0`版本 **升级步骤:** From 5e7fbcf0788e10baff504e2fe1c65d13e2096ffe Mon Sep 17 00:00:00 2001 From: zengqiao Date: Fri, 21 Oct 2022 14:36:29 +0800 Subject: [PATCH 136/145] =?UTF-8?q?=E5=A2=9E=E5=8A=A0v3.0.1=E5=8F=98?= =?UTF-8?q?=E6=9B=B4=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Releases_Notes.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/Releases_Notes.md b/Releases_Notes.md index f453b582..a3df746f 100644 --- a/Releases_Notes.md +++ b/Releases_Notes.md @@ -1,4 +1,36 @@ +## v3.0.1 + +**Bug修复** +- 修复重置 Group Offset 时,提示信息中缺少 Dead 状态也可进行重置的信息; +- 修复 Ldap 某个属性不存在时,会直接抛出空指针导致登陆失败的问题; +- 修复集群 Topic 列表页,健康分详情信息中,检查时间展示错误的问题; +- 修复更新健康检查结果时,出现死锁的问题; +- 修复 Replica 索引模版错误的问题; +- 修复 FAQ 文档中的错误链接; +- 修复 Broker 的 TopN 指标不存在时,页面数据不展示的问题; +- 修复 Group 详情页,图表时间范围选择不生效的问题; + + +**体验优化** +- 集群 Group 列表按照 Group 维度进行展示; +- 优化避免因 ES 中该指标不存在,导致日志中出现大量空指针的问题; +- 优化全局 Message & Notification 展示效果; +- 优化 Topic 扩分区名称 & 描述展示; + + +**新增** +- Broker 列表页面,新增 JMX 是否成功连接的信息; + + +**ZK 部分(未完全发布)** +- 后端补充 Kafka ZK 指标采集,Kafka ZK 信息获取相关功能; +- 增加本地缓存,避免同一采集周期内 ZK 指标重复采集; +- 增加 ZK 节点采集失败跳过策略,避免不断对存在问题的节点不断尝试; +- 修复 zkAvgLatency 指标转 Long 时抛出异常问题; +- 修复 ks_km_zookeeper 表中,role 字段类型错误问题; + +--- ## v3.0.0 @@ -25,7 +57,7 @@ - 集群信息中,新增 Kafka 集群运行模式字段 - 新增 docker-compose 的部署方式 - +--- ## v3.0.0-beta.3 From 26e60d8a64ba9a1a70c8bfd613f9324b1f43dca8 Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Fri, 21 Oct 2022 11:38:04 +0800 Subject: [PATCH 137/145] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E5=85=A8?= =?UTF-8?q?=E5=B1=80=20Message=20&=20Notification=20=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/Message/index.tsx | 54 +++++++++ .../src/components/Notification/index.tsx | 33 ++++++ .../src/constants/axiosConfig.ts | 8 +- .../src/pages/ConfigManage/index.tsx | 22 +--- .../src/pages/UserManage/RoleTabContent.tsx | 2 +- .../src/pages/UserManage/UserTabContent.tsx | 3 +- .../src/components/Message/index.tsx | 54 +++++++++ .../src/components/Notification/index.tsx | 33 ++++++ .../src/components/TopicJob/ReplicaChange.tsx | 2 +- .../src/components/TopicJob/ReplicaMove.tsx | 2 +- .../src/constants/axiosConfig.ts | 15 +-- .../pages/BrokerDetail/ConfigurationEdit.tsx | 3 +- .../src/pages/Consumers/ResetOffsetDrawer.tsx | 9 +- .../src/pages/Jobs/ViewJobsProgress.tsx | 3 +- .../src/pages/Jobs/index.tsx | 3 +- .../src/pages/LoadRebalance/BalanceDrawer.tsx | 17 +-- .../src/pages/LoadRebalance/ClusterNorms.tsx | 3 +- .../src/pages/Login/login.tsx | 3 +- .../pages/MutliClusterPage/AccessCluster.tsx | 3 +- .../src/pages/SecurityACLs/EditDrawer.tsx | 3 +- .../src/pages/SecurityACLs/index.tsx | 3 +- .../src/pages/SecurityUsers/index.tsx | 2 +- .../src/pages/TestingConsumer/Consume.tsx | 3 +- .../src/pages/TestingProduce/Produce.tsx | 3 +- .../TestingProduce/component/EditTable.tsx | 3 +- .../pages/TopicDetail/ConfigurationEdit.tsx | 3 +- .../src/pages/TopicList/Create.tsx | 3 +- .../src/pages/TopicList/Delete.tsx | 3 +- .../layout-clusters-fe/src/pages/index.tsx | 3 +- .../src/style-addition.less | 107 ++++++++++++++++++ 30 files changed, 339 insertions(+), 69 deletions(-) create mode 100644 km-console/packages/config-manager-fe/src/components/Message/index.tsx create mode 100644 km-console/packages/config-manager-fe/src/components/Notification/index.tsx create mode 100644 km-console/packages/layout-clusters-fe/src/components/Message/index.tsx create mode 100644 km-console/packages/layout-clusters-fe/src/components/Notification/index.tsx diff --git a/km-console/packages/config-manager-fe/src/components/Message/index.tsx b/km-console/packages/config-manager-fe/src/components/Message/index.tsx new file mode 100644 index 00000000..5791939c --- /dev/null +++ b/km-console/packages/config-manager-fe/src/components/Message/index.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { IconFont } from '@knowdesign/icons'; +import { message } from 'knowdesign'; +import { ArgsProps, ConfigOnClose } from 'knowdesign/es/basic/message'; + +type ConfigContent = React.ReactNode; +type ConfigDuration = number | (() => void); +type JointContent = ConfigContent | ArgsProps; + +message.config({ + top: 16, +}); + +function isArgsProps(content: JointContent): content is ArgsProps { + return Object.prototype.toString.call(content) === '[object Object]' && !!(content as ArgsProps).content; +} + +const openMessage = ( + type: 'info' | 'success' | 'warning' | 'error', + content: JointContent, + duration?: ConfigDuration, + onClose?: ConfigOnClose +) => { + if (isArgsProps(content)) { + message[type]({ + icon: , + ...content, + }); + } else { + message[type]({ + icon: , + content, + duration, + onClose, + }); + } +}; + +const customMessage = { + info(content: JointContent, duration?: ConfigDuration, onClose?: ConfigOnClose) { + openMessage('info', content, duration, onClose); + }, + success(content: JointContent, duration?: ConfigDuration, onClose?: ConfigOnClose) { + openMessage('success', content, duration, onClose); + }, + warning(content: JointContent, duration?: ConfigDuration, onClose?: ConfigOnClose) { + openMessage('warning', content, duration, onClose); + }, + error(content: JointContent, duration?: ConfigDuration, onClose?: ConfigOnClose) { + openMessage('error', content, duration, onClose); + }, +}; + +export default customMessage; diff --git a/km-console/packages/config-manager-fe/src/components/Notification/index.tsx b/km-console/packages/config-manager-fe/src/components/Notification/index.tsx new file mode 100644 index 00000000..9673d511 --- /dev/null +++ b/km-console/packages/config-manager-fe/src/components/Notification/index.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { notification } from 'knowdesign'; +import { ArgsProps } from 'knowdesign/es/basic/notification'; +import { IconFont } from '@knowdesign/icons'; + +notification.config({ + top: 16, + duration: 3, +}); + +const open = (type: 'info' | 'success' | 'warning' | 'error', content: ArgsProps) => { + notification[type]({ + icon: , + ...content, + }); +}; + +const customNotification = { + info(content: ArgsProps) { + open('info', content); + }, + success(content: ArgsProps) { + open('success', content); + }, + warning(content: ArgsProps) { + open('warning', content); + }, + error(content: ArgsProps) { + open('error', content); + }, +}; + +export default customNotification; diff --git a/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts b/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts index 3e05e105..b99fd274 100644 --- a/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts +++ b/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts @@ -1,7 +1,8 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ // @ts-nocheck -import { notification, Utils } from 'knowdesign'; +import { Utils } from 'knowdesign'; +import notification from '@src/components/Notification'; export const goLogin = () => { if (!window.location.pathname.toLowerCase().startsWith('/login')) { @@ -37,10 +38,9 @@ serviceInstance.interceptors.response.use( (config: any) => { const res: { code: number; message: string; data: any } = config.data; if (res.code !== 0 && res.code !== 200) { - const desc = res.message; notification.error({ - message: desc, - duration: 3, + message: '错误信息', + description: res.message, }); throw res; } diff --git a/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx b/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx index 1430fbb6..3c85fdf5 100644 --- a/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx +++ b/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx @@ -1,20 +1,6 @@ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react'; -import { - Button, - Form, - Input, - Select, - Switch, - Modal, - message, - ProTable, - Drawer, - Space, - Divider, - Tooltip, - AppContainer, - Utils, -} from 'knowdesign'; +import { Button, Form, Input, Select, Switch, Modal, ProTable, Drawer, Space, Divider, Tooltip, AppContainer, Utils } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import { PlusOutlined } from '@ant-design/icons'; import moment from 'moment'; @@ -81,7 +67,7 @@ const EditConfigDrawer = forwardRef((_, ref) => { // 如果内容可以格式化为 JSON,进行处理 config.value = JSON.stringify(JSON.parse(config.value), null, 2); } catch (_) { - return; + // } } form.setFieldsValue({ ...config, status: config.status === 1 }); @@ -476,7 +462,7 @@ export default () => { rowKey: 'id', dataSource: data, paginationProps: pagination, - columns, + columns: columns as any, lineFillColor: true, attrs: { onChange: onTableChange, diff --git a/km-console/packages/config-manager-fe/src/pages/UserManage/RoleTabContent.tsx b/km-console/packages/config-manager-fe/src/pages/UserManage/RoleTabContent.tsx index 5adeac58..f7db974b 100644 --- a/km-console/packages/config-manager-fe/src/pages/UserManage/RoleTabContent.tsx +++ b/km-console/packages/config-manager-fe/src/pages/UserManage/RoleTabContent.tsx @@ -11,7 +11,6 @@ import { Transfer, Row, Col, - message, Tooltip, Spin, AppContainer, @@ -19,6 +18,7 @@ import { Popover, IconFont, } from 'knowdesign'; +import message from '@src/components/Message'; import moment from 'moment'; import { LoadingOutlined, PlusOutlined } from '@ant-design/icons'; import { defaultPagination } from '@src/constants/common'; diff --git a/km-console/packages/config-manager-fe/src/pages/UserManage/UserTabContent.tsx b/km-console/packages/config-manager-fe/src/pages/UserManage/UserTabContent.tsx index 34bf6180..0ca3ca29 100644 --- a/km-console/packages/config-manager-fe/src/pages/UserManage/UserTabContent.tsx +++ b/km-console/packages/config-manager-fe/src/pages/UserManage/UserTabContent.tsx @@ -1,5 +1,6 @@ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react'; -import { Form, ProTable, Select, Button, Input, Modal, message, Drawer, Space, Divider, AppContainer, Utils } from 'knowdesign'; +import { Form, ProTable, Select, Button, Input, Modal, Drawer, Space, Divider, AppContainer, Utils } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import { PlusOutlined, QuestionCircleOutlined } from '@ant-design/icons'; import moment from 'moment'; diff --git a/km-console/packages/layout-clusters-fe/src/components/Message/index.tsx b/km-console/packages/layout-clusters-fe/src/components/Message/index.tsx new file mode 100644 index 00000000..5791939c --- /dev/null +++ b/km-console/packages/layout-clusters-fe/src/components/Message/index.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { IconFont } from '@knowdesign/icons'; +import { message } from 'knowdesign'; +import { ArgsProps, ConfigOnClose } from 'knowdesign/es/basic/message'; + +type ConfigContent = React.ReactNode; +type ConfigDuration = number | (() => void); +type JointContent = ConfigContent | ArgsProps; + +message.config({ + top: 16, +}); + +function isArgsProps(content: JointContent): content is ArgsProps { + return Object.prototype.toString.call(content) === '[object Object]' && !!(content as ArgsProps).content; +} + +const openMessage = ( + type: 'info' | 'success' | 'warning' | 'error', + content: JointContent, + duration?: ConfigDuration, + onClose?: ConfigOnClose +) => { + if (isArgsProps(content)) { + message[type]({ + icon: , + ...content, + }); + } else { + message[type]({ + icon: , + content, + duration, + onClose, + }); + } +}; + +const customMessage = { + info(content: JointContent, duration?: ConfigDuration, onClose?: ConfigOnClose) { + openMessage('info', content, duration, onClose); + }, + success(content: JointContent, duration?: ConfigDuration, onClose?: ConfigOnClose) { + openMessage('success', content, duration, onClose); + }, + warning(content: JointContent, duration?: ConfigDuration, onClose?: ConfigOnClose) { + openMessage('warning', content, duration, onClose); + }, + error(content: JointContent, duration?: ConfigDuration, onClose?: ConfigOnClose) { + openMessage('error', content, duration, onClose); + }, +}; + +export default customMessage; diff --git a/km-console/packages/layout-clusters-fe/src/components/Notification/index.tsx b/km-console/packages/layout-clusters-fe/src/components/Notification/index.tsx new file mode 100644 index 00000000..9673d511 --- /dev/null +++ b/km-console/packages/layout-clusters-fe/src/components/Notification/index.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { notification } from 'knowdesign'; +import { ArgsProps } from 'knowdesign/es/basic/notification'; +import { IconFont } from '@knowdesign/icons'; + +notification.config({ + top: 16, + duration: 3, +}); + +const open = (type: 'info' | 'success' | 'warning' | 'error', content: ArgsProps) => { + notification[type]({ + icon: , + ...content, + }); +}; + +const customNotification = { + info(content: ArgsProps) { + open('info', content); + }, + success(content: ArgsProps) { + open('success', content); + }, + warning(content: ArgsProps) { + open('warning', content); + }, + error(content: ArgsProps) { + open('error', content); + }, +}; + +export default customNotification; diff --git a/km-console/packages/layout-clusters-fe/src/components/TopicJob/ReplicaChange.tsx b/km-console/packages/layout-clusters-fe/src/components/TopicJob/ReplicaChange.tsx index 16637b9c..cd4f05ba 100644 --- a/km-console/packages/layout-clusters-fe/src/components/TopicJob/ReplicaChange.tsx +++ b/km-console/packages/layout-clusters-fe/src/components/TopicJob/ReplicaChange.tsx @@ -15,10 +15,10 @@ import { Tag, Utils, AppContainer, - message, Divider, Space, } from 'knowdesign'; +import message from '@src/components/Message'; import './index.less'; import Api, { MetricType } from '@src/api/index'; import moment from 'moment'; diff --git a/km-console/packages/layout-clusters-fe/src/components/TopicJob/ReplicaMove.tsx b/km-console/packages/layout-clusters-fe/src/components/TopicJob/ReplicaMove.tsx index a6089e80..a93b26ef 100644 --- a/km-console/packages/layout-clusters-fe/src/components/TopicJob/ReplicaMove.tsx +++ b/km-console/packages/layout-clusters-fe/src/components/TopicJob/ReplicaMove.tsx @@ -14,12 +14,12 @@ import { Table, Utils, AppContainer, - message, Space, Divider, Transfer, Tooltip, } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import './index.less'; import Api, { MetricType } from '@src/api/index'; diff --git a/km-console/packages/layout-clusters-fe/src/constants/axiosConfig.ts b/km-console/packages/layout-clusters-fe/src/constants/axiosConfig.ts index fb0ddf44..5a087ca0 100644 --- a/km-console/packages/layout-clusters-fe/src/constants/axiosConfig.ts +++ b/km-console/packages/layout-clusters-fe/src/constants/axiosConfig.ts @@ -1,4 +1,6 @@ -import { notification, Utils } from 'knowdesign'; +import { Utils } from 'knowdesign'; +import notification from '@src/components/Notification'; + const { EventBus } = Utils; export const licenseEventBus = new EventBus(); @@ -42,8 +44,8 @@ serviceInstance.interceptors.response.use( licenseEventBus.emit('licenseError', desc); } else { notification.error({ - message: desc, - duration: 3, + message: '错误信息', + description: desc, }); } throw res; @@ -83,36 +85,31 @@ const dealResponse = (error: any) => { case 405: notification.error({ message: '错误', - duration: 3, description: `${error.response.data.message || '请求方式错误'}`, }); break; case 500: notification.error({ message: '错误', - duration: 3, description: '服务错误,请重试!', }); break; case 502: notification.error({ message: '错误', - duration: 3, description: '网络错误,请重试!', }); break; default: notification.error({ message: '连接出错', - duration: 3, description: `${error.response.status}`, }); } } else { notification.error({ + message: '连接超时!', description: '请重试或检查服务', - message: '连接超时! ', - duration: 3, }); } return Promise.reject(error); diff --git a/km-console/packages/layout-clusters-fe/src/pages/BrokerDetail/ConfigurationEdit.tsx b/km-console/packages/layout-clusters-fe/src/pages/BrokerDetail/ConfigurationEdit.tsx index a362acc0..f4fda39a 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/BrokerDetail/ConfigurationEdit.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/BrokerDetail/ConfigurationEdit.tsx @@ -1,5 +1,6 @@ import React, { useEffect } from 'react'; -import { Drawer, Form, Input, Space, Button, Checkbox, Utils, Row, Col, Divider, message } from 'knowdesign'; +import { Drawer, Form, Input, Space, Button, Checkbox, Utils, Row, Col, Divider } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import { useParams } from 'react-router-dom'; import Api from '@src/api'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/Consumers/ResetOffsetDrawer.tsx b/km-console/packages/layout-clusters-fe/src/pages/Consumers/ResetOffsetDrawer.tsx index c079393b..bba5059e 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Consumers/ResetOffsetDrawer.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Consumers/ResetOffsetDrawer.tsx @@ -1,11 +1,14 @@ import React, { useState, useEffect } from 'react'; -import { Button, DatePicker, Drawer, Form, notification, Radio, Utils, Space, Divider, message } from 'knowdesign'; +import { Button, DatePicker, Drawer, Form, Radio, Utils, Space, Divider } from 'knowdesign'; +import notification from '@src/components/Notification'; + +import message from '@src/components/Message'; import { useParams } from 'react-router-dom'; import EditTable from '../TestingProduce/component/EditTable'; import Api from '@src/api/index'; import moment from 'moment'; -const CustomSelectResetTime = (props: { value?: string; onChange?: (val: Number | String) => void }) => { +const CustomSelectResetTime = (props: { value?: string; onChange?: (val: number | string) => void }) => { const { value, onChange } = props; const [timeSetMode, setTimeSetMode] = useState('newest'); useEffect(() => { @@ -81,7 +84,7 @@ export default (props: any) => { tableData = customFormRef.current.getTableData(); } const formData = form.getFieldsValue(); - let resetParams: any = { + const resetParams: any = { clusterId: clusterPhyId, createIfNotExist: false, groupName: record.groupName, diff --git a/km-console/packages/layout-clusters-fe/src/pages/Jobs/ViewJobsProgress.tsx b/km-console/packages/layout-clusters-fe/src/pages/Jobs/ViewJobsProgress.tsx index b052cb92..ee8bf0fa 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Jobs/ViewJobsProgress.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Jobs/ViewJobsProgress.tsx @@ -1,7 +1,8 @@ import React, { useState, useEffect } from 'react'; import moment from 'moment'; import { useParams } from 'react-router-dom'; -import { Button, Drawer, Utils, Descriptions, Tabs, Input, message, Spin, InputNumber } from 'knowdesign'; +import { Button, Drawer, Utils, Descriptions, Tabs, Input, Spin, InputNumber } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import TaskDetails from './TeskDetails'; import NodeTraffic from './NodeTraffic'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/Jobs/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/Jobs/index.tsx index 3e08d3a5..a4170af1 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Jobs/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Jobs/index.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect, memo } from 'react'; import { useParams, useHistory, useLocation } from 'react-router-dom'; -import { ProTable, Drawer, Utils, AppContainer, Form, Select, Input, Button, message, Modal, Divider } from 'knowdesign'; +import { ProTable, Drawer, Utils, AppContainer, Form, Select, Input, Button, Modal, Divider } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import API from '../../api'; import { getJobsListColumns, defaultPagination, runningStatus, jobType } from './config'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/LoadRebalance/BalanceDrawer.tsx b/km-console/packages/layout-clusters-fe/src/pages/LoadRebalance/BalanceDrawer.tsx index 8ad1cd3c..2da0fa03 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/LoadRebalance/BalanceDrawer.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/LoadRebalance/BalanceDrawer.tsx @@ -1,19 +1,6 @@ import React, { useState, useEffect, useRef } from 'react'; -import { - Utils, - Drawer, - Button, - Form, - Space, - Divider, - AppContainer, - Radio, - InputNumber, - Transfer, - Select, - message, - Tooltip, -} from 'knowdesign'; +import { Utils, Drawer, Button, Form, Space, Divider, AppContainer, Radio, InputNumber, Transfer, Select, Tooltip } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import CronInput from './CronInput'; import BalanceEditTable from './BalanceEditTable'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/LoadRebalance/ClusterNorms.tsx b/km-console/packages/layout-clusters-fe/src/pages/LoadRebalance/ClusterNorms.tsx index 13cf7ab2..4c0ad07b 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/LoadRebalance/ClusterNorms.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/LoadRebalance/ClusterNorms.tsx @@ -1,5 +1,6 @@ import React, { useState, useEffect, useRef } from 'react'; -import { Utils, Drawer, Button, Form, Space, Divider, AppContainer, Input, Transfer, message, InputNumber } from 'knowdesign'; +import { Utils, Drawer, Button, Form, Space, Divider, AppContainer, Input, Transfer, InputNumber } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import { CloseOutlined } from '@ant-design/icons'; import api from '../../api'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/Login/login.tsx b/km-console/packages/layout-clusters-fe/src/pages/Login/login.tsx index 39c72a76..0400dbf0 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Login/login.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Login/login.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { Form, Button, Input, Row, InputNumber, Utils, message } from 'knowdesign'; +import { Form, Button, Input, Row, InputNumber, Utils } from 'knowdesign'; +import message from '@src/components/Message'; import { FormMap } from './config'; import Api from '../../api'; import { useHistory } from 'react-router-dom'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx index 7435d9a7..e5c1f649 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx @@ -1,4 +1,5 @@ -import { Button, Divider, Drawer, Form, Input, InputNumber, message, Radio, Select, Spin, Space, Utils } from 'knowdesign'; +import { Button, Divider, Drawer, Form, Input, InputNumber, Radio, Select, Spin, Space, Utils } from 'knowdesign'; +import message from '@src/components/Message'; import * as React from 'react'; import { useIntl } from 'react-intl'; import api from '@src/api'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/EditDrawer.tsx b/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/EditDrawer.tsx index 9b2a7203..8afcdccc 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/EditDrawer.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/EditDrawer.tsx @@ -1,5 +1,6 @@ import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react'; -import { Button, Form, Input, Select, message, Drawer, Space, Divider, Utils, Radio, AutoComplete, Alert } from 'knowdesign'; +import { Button, Form, Input, Select, Drawer, Space, Divider, Utils, Radio, AutoComplete, Alert } from 'knowdesign'; +import message from '@src/components/Message'; import api from '@src/api'; import { useParams } from 'react-router-dom'; import { UsersProps } from '../SecurityUsers'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.tsx index a98f6269..d361f3e7 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useRef, useState } from 'react'; -import { Button, Form, Input, Select, Modal, message, ProTable, AppContainer, DKSBreadcrumb, Utils, Divider } from 'knowdesign'; +import { Button, Form, Input, Select, Modal, ProTable, AppContainer, DKSBreadcrumb, Utils, Divider } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import ACLsCardBar from '@src/components/CardBar/ACLsCardBar'; import api from '@src/api'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/SecurityUsers/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/SecurityUsers/index.tsx index 9f493bd7..6291ed42 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SecurityUsers/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/SecurityUsers/index.tsx @@ -4,7 +4,6 @@ import { Form, Input, Modal, - message, ProTable, Drawer, Space, @@ -16,6 +15,7 @@ import { Tooltip, Alert, } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import { CloseOutlined, EyeInvisibleOutlined, EyeOutlined, LoadingOutlined } from '@ant-design/icons'; import './index.less'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/Consume.tsx b/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/Consume.tsx index be43d454..90625de8 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/Consume.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/Consume.tsx @@ -1,6 +1,7 @@ /* eslint-disable no-case-declarations */ import { DownloadOutlined } from '@ant-design/icons'; -import { AppContainer, Divider, message, Tooltip, Utils } from 'knowdesign'; +import { AppContainer, Divider, Tooltip, Utils } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import * as React from 'react'; import moment from 'moment'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/Produce.tsx b/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/Produce.tsx index 8f5e3479..18f0b2c5 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/Produce.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/Produce.tsx @@ -1,4 +1,5 @@ -import { AppContainer, Form, message, Tabs, Utils } from 'knowdesign'; +import { AppContainer, Form, Tabs, Utils } from 'knowdesign'; +import message from '@src/components/Message'; import * as React from 'react'; import ConfigForm from './component/ConfigFrom'; import TestResult from '../TestingConsumer/component/Result'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/component/EditTable.tsx b/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/component/EditTable.tsx index a5300af2..55b06e25 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/component/EditTable.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/component/EditTable.tsx @@ -1,6 +1,7 @@ /* eslint-disable react/display-name */ import React, { useState } from 'react'; -import { Table, Input, InputNumber, Popconfirm, Form, Typography, Button, message, Select } from 'knowdesign'; +import { Table, Input, InputNumber, Popconfirm, Form, Typography, Button, Select } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import './style/edit-table.less'; import { CheckOutlined, CloseOutlined, PlusSquareOutlined } from '@ant-design/icons'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConfigurationEdit.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConfigurationEdit.tsx index 7fc4ab80..ff8c6cd0 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConfigurationEdit.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConfigurationEdit.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { Drawer, Form, Input, Space, Button, Utils, Row, Col, Divider, message } from 'knowdesign'; +import { Drawer, Form, Input, Space, Button, Utils, Row, Col, Divider } from 'knowdesign'; +import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import { useParams } from 'react-router-dom'; import Api from '@src/api'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicList/Create.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicList/Create.tsx index 288b99c7..6f1cb667 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicList/Create.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicList/Create.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from 'react'; import { useParams } from 'react-router-dom'; -import { Alert, Button, Checkbox, Divider, Drawer, Form, Input, InputNumber, Modal, notification, Select, Utils } from 'knowdesign'; +import { Alert, Button, Checkbox, Divider, Drawer, Form, Input, InputNumber, Modal, Select, Utils } from 'knowdesign'; +import notification from '@src/components/Notification'; import { PlusOutlined, DownOutlined, UpOutlined } from '@ant-design/icons'; import Api from '@src/api/index'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicList/Delete.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicList/Delete.tsx index 75af2070..69109225 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicList/Delete.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicList/Delete.tsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import { useParams } from 'react-router-dom'; -import { Button, Form, Input, Modal, notification, Utils } from 'knowdesign'; +import { Button, Form, Input, Modal, Utils } from 'knowdesign'; +import notification from '@src/components/Notification'; import { IconFont } from '@knowdesign/icons'; import Api from '@src/api/index'; diff --git a/km-console/packages/layout-clusters-fe/src/pages/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/index.tsx index 4e1d1808..16d73de9 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/index.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import { Redirect, useHistory, useLocation } from 'react-router-dom'; -import { DProLayout, AppContainer, RouteGuard, notification, Spin } from 'knowdesign'; +import { DProLayout, AppContainer, RouteGuard, Spin } from 'knowdesign'; +import notification from '@src/components/Notification'; import { pageRoutes } from './pageRoutes'; import { leftMenus, systemKey } from '@src/constants/menu'; import { ClustersPermissionMap } from './CommonConfig'; diff --git a/km-console/packages/layout-clusters-fe/src/style-addition.less b/km-console/packages/layout-clusters-fe/src/style-addition.less index 451c31bf..f4b7e04b 100644 --- a/km-console/packages/layout-clusters-fe/src/style-addition.less +++ b/km-console/packages/layout-clusters-fe/src/style-addition.less @@ -11,6 +11,7 @@ @select-item-selected-font-weight: normal; @btn-danger-bg: #F5483B; @btn-danger-border: #F5483B; +@notification-icon-size: 20px; // 自定义变量 // Input @input-bg: rgba(33, 37, 41, 0.06); @@ -656,3 +657,109 @@ .@{ant-prefix}-empty-img-default{ width: 100% !important; } + +// message 样式覆盖 +.@{message-prefix-cls} { + &-notice-content { + padding: 8px 12px; + font-size: 14px; + border-radius: 4px; + background: #fff; + } + &-success, + &-info, + &-warning, + &-error, + &-loading { + margin: unset; + padding: unset; + color: #000; + border-style: unset; + border-width: unset; + border-radius: unset; + } + + &-success { + background-color: unset; + border-color: unset; + } + + &-info, + &-loading { + background-color: unset; + border-color: unset; + } + + &-warning { + background-color: unset; + border-color: unset; + } + + &-error { + background-color: unset; + border-color: unset; + } + + .@{iconfont-css-prefix} { + top: 2px; + color: unset; + } +} + +// Notification 样式覆盖 +.@{notification-prefix-cls} { + &-notice { + width: 348px; + color: #000; + background-color: #fff; + border: unset; + border-radius: 4px; + box-shadow: 0 2px 4px 0 rgba(0,0,0,0.02), 0 4px 6px 6px rgba(0,0,0,0.02), 0 4px 6px 0 rgba(0,0,0,0.06); + &-message { + font-family: @font-family-bold; + font-size: 16px; + color: #000; + } + &-description { + font-size: 14px; + color: rgba(0,0,0,0.60); + } + &-with-icon &-message { + font-size: 16px; + margin-left: 26px; + } + &-with-icon &-description { + font-size: 14px; + margin-left: 26px; + } + &-icon { + top: 18px; + font-size: @notification-icon-size; + line-height: @notification-icon-size; + } + .@{iconfont-css-prefix}&-icon { + color: @notification-content-color !important; + } + &-success { + background-color: #fff; + border: unset; + } + &-warning { + background-color: #fff; + border: unset; + } + &-error { + background-color: #fff; + border: unset; + } + &-close { + color: rgba(0,0,0,0.60); + + &:hover { + & when not (@theme = dark) { + color: shade(@white, 30%); + } + } + } + } +} From 62f7d3f72ffb571864e97867d1c83a7df00888e4 Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Fri, 21 Oct 2022 11:42:34 +0800 Subject: [PATCH 138/145] =?UTF-8?q?fix:=20=E5=9B=BE=E8=A1=A8=E9=80=BB?= =?UTF-8?q?=E8=BE=91=20&=20=E5=B1=95=E7=A4=BA=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layout-clusters-fe/src/api/index.ts | 4 + .../MetricSelect.tsx} | 89 ++++++++------- .../NodeScope.tsx | 89 +++++++-------- .../image/empty.png | Bin .../index.tsx | 103 +++++++++--------- .../style/index.less | 0 .../style/indicator-drawer.less | 13 +-- .../style/node-scope.less | 9 +- .../style/query-module.less | 0 .../Detail.tsx} | 29 ++--- .../config.tsx | 23 ++-- .../index.less | 2 +- .../index.tsx | 74 +++++++------ .../src/constants/chartConfig.ts | 99 ++++++++++++----- .../src/pages/BrokerDashboard/index.tsx | 4 +- .../src/pages/MutliClusterPage/List.tsx | 9 +- .../DetailChart/config.tsx | 6 +- .../SingleClusterDetail/DetailChart/index.tsx | 24 ++-- .../SingleClusterDetail/HealthySetting.tsx | 7 +- .../src/pages/TopicDashboard/index.tsx | 4 +- 20 files changed, 328 insertions(+), 260 deletions(-) rename km-console/packages/layout-clusters-fe/src/components/{SingleChartHeader/IndicatorDrawer.tsx => ChartOperateBar/MetricSelect.tsx} (83%) rename km-console/packages/layout-clusters-fe/src/components/{SingleChartHeader => ChartOperateBar}/NodeScope.tsx (70%) rename km-console/packages/layout-clusters-fe/src/components/{SingleChartHeader => ChartOperateBar}/image/empty.png (100%) rename km-console/packages/layout-clusters-fe/src/components/{SingleChartHeader => ChartOperateBar}/index.tsx (80%) rename km-console/packages/layout-clusters-fe/src/components/{SingleChartHeader => ChartOperateBar}/style/index.less (100%) rename km-console/packages/layout-clusters-fe/src/components/{SingleChartHeader => ChartOperateBar}/style/indicator-drawer.less (94%) rename km-console/packages/layout-clusters-fe/src/components/{SingleChartHeader => ChartOperateBar}/style/node-scope.less (95%) rename km-console/packages/layout-clusters-fe/src/components/{SingleChartHeader => ChartOperateBar}/style/query-module.less (100%) rename km-console/packages/layout-clusters-fe/src/components/{DashboardDragChart/ChartDetail.tsx => DraggableCharts/Detail.tsx} (95%) rename km-console/packages/layout-clusters-fe/src/components/{DashboardDragChart => DraggableCharts}/config.tsx (72%) rename km-console/packages/layout-clusters-fe/src/components/{DashboardDragChart => DraggableCharts}/index.less (98%) rename km-console/packages/layout-clusters-fe/src/components/{DashboardDragChart => DraggableCharts}/index.tsx (84%) diff --git a/km-console/packages/layout-clusters-fe/src/api/index.ts b/km-console/packages/layout-clusters-fe/src/api/index.ts index d3e48939..bbf11d0a 100755 --- a/km-console/packages/layout-clusters-fe/src/api/index.ts +++ b/km-console/packages/layout-clusters-fe/src/api/index.ts @@ -14,6 +14,7 @@ export enum MetricType { Broker = 103, Partition = 104, Replication = 105, + Zookeeper = 110, Controls = 901, } @@ -61,6 +62,8 @@ const api = { phyClusterState: getApi(`/physical-clusters/state`), getOperatingStateList: (clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/groups-overview`), + getGroupTopicList: (clusterPhyId: number, groupName: string) => getApi(`/clusters/${clusterPhyId}/groups/${groupName}/topics-overview`), + // 物理集群接口 phyCluster: getApi(`/physical-clusters`), getPhyClusterBasic: (clusterPhyId: number) => getApi(`/physical-clusters/${clusterPhyId}/basic`), @@ -127,6 +130,7 @@ const api = { getApi(`/clusters/${clusterPhyId}/topics/${topicName}/brokers-partitions-summary`), getTopicPartitionsDetail: (clusterPhyId: string, topicName: string) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/partitions`), getTopicMessagesList: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/records`), // Messages列表 + getTopicGroupList: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/groups-overview`), // Consumers列表 getTopicMessagesMetadata: (topicName: string, clusterPhyId: number) => getApi(`/clusters//${clusterPhyId}/topics/${topicName}/metadata`), // Messages列表 getTopicACLsList: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/acl-Bindings`), // ACLs列表 getTopicConfigs: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/config-topics/${topicName}/configs`), // Configuration列表 diff --git a/km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/IndicatorDrawer.tsx b/km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/MetricSelect.tsx similarity index 83% rename from km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/IndicatorDrawer.tsx rename to km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/MetricSelect.tsx index 9c7a4833..badae226 100644 --- a/km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/IndicatorDrawer.tsx +++ b/km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/MetricSelect.tsx @@ -1,15 +1,12 @@ -import React, { useState, useEffect } from 'react'; -import { Drawer, Button, Space, Divider, AppContainer, ProTable } from 'knowdesign'; +import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'; +import { Drawer, Button, Space, Divider, AppContainer, ProTable, Utils } from 'knowdesign'; import { IconFont } from '@knowdesign/icons'; -import { IindicatorSelectModule } from './index'; +import { MetricSelect } from './index'; import './style/indicator-drawer.less'; import { useLocation } from 'react-router-dom'; interface PropsType extends React.HTMLAttributes { - onClose: () => void; - visible: boolean; - isGroup?: boolean; // 是否分组 - indicatorSelectModule: IindicatorSelectModule; + metricSelect: MetricSelect; } interface MetricInfo { @@ -27,25 +24,25 @@ type CategoryData = { metrics: MetricInfo[]; }; -const ExpandedRow = ({ metrics, category, selectedMetrics, selectedMetricChange }: any) => { - const innerColumns = [ - { - title: '指标名称', - dataIndex: 'name', - key: 'name', - }, - { - title: '单位', - dataIndex: 'unit', - key: 'unit', - }, - { - title: '描述', - dataIndex: 'desc', - key: 'desc', - }, - ]; +const expandedRowColumns = [ + { + title: '指标名称', + dataIndex: 'name', + key: 'name', + }, + { + title: '单位', + dataIndex: 'unit', + key: 'unit', + }, + { + title: '描述', + dataIndex: 'desc', + key: 'desc', + }, +]; +const ExpandedRow = ({ metrics, category, selectedMetrics, selectedMetricChange }: any) => { return (
          { +const MetricSelect = forwardRef(({ metricSelect }: PropsType, ref) => { const [global] = AppContainer.useGlobalValue(); const { pathname } = useLocation(); const [confirmLoading, setConfirmLoading] = useState(false); const [categoryData, setCategoryData] = useState([]); const [selectedCategories, setSelectedCategories] = useState([]); const [childrenSelectedRowKeys, setChildrenSelectedRowKeys] = useState({}); + const [visible, setVisible] = useState(false); const columns = [ { @@ -96,13 +94,13 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType) ]; const formateTableData = () => { - const tableData = indicatorSelectModule.tableData; + const tableData = metricSelect.tableData; const categoryData: { [category: string]: MetricInfo[]; } = {}; tableData.forEach(({ name, desc }) => { - const metricDefine = global.getMetricDefine(indicatorSelectModule?.metricType, name); + const metricDefine = global.getMetricDefine(metricSelect?.metricType, name); const returnData = { name, desc, @@ -125,12 +123,12 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType) }; const formateSelectedKeys = () => { - const newKeys = indicatorSelectModule.selectedRows; + const newKeys = metricSelect.selectedRows; const result: SelectedMetrics = {}; const selectedCategories: string[] = []; newKeys.forEach((name: string) => { - const metricDefine = global.getMetricDefine(indicatorSelectModule?.metricType, name); + const metricDefine = global.getMetricDefine(metricSelect?.metricType, name); if (metricDefine) { if (!result[metricDefine.category]) { result[metricDefine.category] = [name]; @@ -217,10 +215,10 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType) const allRowKeys: string[] = []; Object.entries(childrenSelectedRowKeys).forEach(([, arr]) => allRowKeys.push(...arr)); - indicatorSelectModule.submitCallback(allRowKeys).then( + metricSelect.submitCallback(allRowKeys).then( () => { setConfirmLoading(false); - onClose(); + setVisible(false); }, () => { setConfirmLoading(false); @@ -231,7 +229,7 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType) const rowSelection = { selectedRowKeys: selectedCategories, onChange: rowChange, - // getCheckboxProps: (record: any) => indicatorSelectModule.checkboxProps && indicatorSelectModule.checkboxProps(record), + // getCheckboxProps: (record: any) => metricSelect.checkboxProps && metricSelect.checkboxProps(record), getCheckboxProps: (record: CategoryData) => { const isAllSelected = record.metrics.length === childrenSelectedRowKeys[record.category]?.length; const isNotCheck = !childrenSelectedRowKeys[record.category] || childrenSelectedRowKeys[record.category]?.length === 0; @@ -241,25 +239,33 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType) }, }; - useEffect(formateTableData, [indicatorSelectModule.tableData]); + useEffect(formateTableData, [metricSelect.tableData]); useEffect(() => { visible && formateSelectedKeys(); - }, [visible, indicatorSelectModule.selectedRows]); + }, [visible, metricSelect.selectedRows]); + + useImperativeHandle( + ref, + () => ({ + open: () => setVisible(true), + }), + [] + ); return ( <> setVisible(false)} visible={visible} maskClosable={false} extra={ -
          -
          -
          {scopeLabel}
          -
          -
          - - 全选 - - } - size="small" - placeholder={searchPlaceholder} - onChange={(e) => setScopeSearchValue(e.target.value)} - /> -
          -
          - - - {customList - .filter((item) => item.label.includes(scopeSearchValue)) - .map((item) => ( - - {item.label} - - ))} - - -
          + {hasCustomScope && ( +
          +
          {scopeLabel}
          +
          +
          + + 全选 + + } + size="small" + placeholder={searchPlaceholder} + onChange={(e) => setScopeSearchValue(e.target.value)} + /> +
          +
          + + + {customList + .filter((item) => item.label.includes(scopeSearchValue)) + .map((item) => ( + + {item.label} + + ))} + + +
          -
          - - +
          + + +
          -
          + )}
          ); @@ -185,7 +188,7 @@ const NodeScope = ({ nodeScopeModule, change }: propsType) => { visible={popVisible} content={clickContent} placement="bottomRight" - overlayClassName="d-node-scope-popover" + overlayClassName={`d-node-scope-popover ${hasCustomScope ? 'large-size' : ''}`} onVisibleChange={visibleChange} > diff --git a/km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/image/empty.png b/km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/image/empty.png similarity index 100% rename from km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/image/empty.png rename to km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/image/empty.png diff --git a/km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/index.tsx b/km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/index.tsx similarity index 80% rename from km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/index.tsx rename to km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/index.tsx index 5284093b..42d66366 100644 --- a/km-console/packages/layout-clusters-fe/src/components/SingleChartHeader/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/components/ChartOperateBar/index.tsx @@ -1,9 +1,9 @@ -import React, { useEffect, useState } from 'react'; -import { Tooltip, Select, Utils, Divider, Button } from 'knowdesign'; +import React, { useEffect, useRef, useState } from 'react'; +import { Select, Divider, Button } from 'knowdesign'; import { IconFont } from '@knowdesign/icons'; import moment from 'moment'; import { DRangeTime } from 'knowdesign'; -import IndicatorDrawer from './IndicatorDrawer'; +import MetricSelect from './MetricSelect'; import NodeScope from './NodeScope'; import './style/index.less'; @@ -24,8 +24,8 @@ export interface KsHeaderOptions { data: number | number[]; }; } -export interface IindicatorSelectModule { - metricType?: MetricType; +export interface MetricSelect { + metricType: MetricType; hide?: boolean; drawerTitle?: string; selectedRows: (string | number)[]; @@ -47,20 +47,27 @@ export interface IcustomScope { } export interface InodeScopeModule { + hasCustomScope: boolean; customScopeList: IcustomScope[]; scopeName?: string; scopeLabel?: string; searchPlaceholder?: string; change?: () => void; } + interface PropsType { - indicatorSelectModule?: IindicatorSelectModule; + metricSelect?: MetricSelect; hideNodeScope?: boolean; hideGridSelect?: boolean; nodeScopeModule?: InodeScopeModule; onChange: (options: KsHeaderOptions) => void; } +interface ScopeData { + isTop: boolean; + data: any; +} + // 列布局选项 const GRID_SIZE_OPTIONS = [ { @@ -77,15 +84,17 @@ const GRID_SIZE_OPTIONS = [ }, ]; -const SingleChartHeader = ({ - indicatorSelectModule, +const MetricOperateBar = ({ + metricSelect, nodeScopeModule = { + hasCustomScope: false, customScopeList: [], }, hideNodeScope = false, hideGridSelect = false, onChange: onChangeCallback, }: PropsType): JSX.Element => { + const metricSelectRef = useRef(null); const [gridNum, setGridNum] = useState(GRID_SIZE_OPTIONS[1].value); const [rangeTime, setRangeTime] = useState<[number, number]>(() => { const curTimeStamp = moment().valueOf(); @@ -93,16 +102,35 @@ const SingleChartHeader = ({ }); const [isRelativeRangeTime, setIsRelativeRangeTime] = useState(true); const [isAutoReload, setIsAutoReload] = useState(false); - const [indicatorDrawerVisible, setIndicatorDrawerVisible] = useState(false); - - const [scopeData, setScopeData] = useState<{ - isTop: boolean; - data: any; - }>({ + const [scopeData, setScopeData] = useState({ isTop: true, data: 5, }); + const sizeChange = (value: number) => setGridNum(value); + + const timeChange = (curRangeTime: [number, number], isRelative: boolean) => { + setRangeTime([...curRangeTime]); + setIsRelativeRangeTime(isRelative); + }; + + const reloadRangeTime = () => { + if (isRelativeRangeTime) { + const timeLen = rangeTime[1] - rangeTime[0] || 0; + const curTimeStamp = moment().valueOf(); + setRangeTime([curTimeStamp - timeLen, curTimeStamp]); + } else { + setRangeTime([...rangeTime]); + } + }; + + const nodeScopeChange = (data: any, isTop?: any) => { + setScopeData({ + isTop, + data, + }); + }; + useEffect(() => { onChangeCallback({ rangeTime, @@ -129,68 +157,37 @@ const SingleChartHeader = ({ }; }, [isRelativeRangeTime, rangeTime]); - const sizeChange = (value: number) => { - setGridNum(value); - }; - - const timeChange = (curRangeTime: [number, number], isRelative: boolean) => { - setRangeTime([...curRangeTime]); - setIsRelativeRangeTime(isRelative); - }; - - const reloadRangeTime = () => { - if (isRelativeRangeTime) { - const timeLen = rangeTime[1] - rangeTime[0] || 0; - const curTimeStamp = moment().valueOf(); - setRangeTime([curTimeStamp - timeLen, curTimeStamp]); - } else { - setRangeTime([...rangeTime]); - } - }; - - const openIndicatorDrawer = () => { - setIndicatorDrawerVisible(true); - }; - - const closeIndicatorDrawer = () => { - setIndicatorDrawerVisible(false); - }; - - const nodeScopeChange = (data: any, isTop?: any) => { - setScopeData({ - isTop, - data, - }); - }; - return ( <>
          + {/* 刷新 */}
          + {/* 时间选择 */}
          + {/* 节点范围 */} {!hideNodeScope && } + {/* 分栏 */} {!hideGridSelect && ( { + setCurPartition(id); + }} + > + + {partitionList.map((partition) => ( + + ))} + + )} + {showMode === 'chart' && ( + { + setTimeRange(o); + }} + > + )} + {showMode === 'chart' &&
          } + setShowMode(key)}> + +
          + +
          +
          + +
          + +
          +
          +
          +
          +
          + {showMode === 'table' && ( + + )} + {showMode === 'chart' && ( +
          + { + return data.map((metricData: any) => { + const partitionMetricData = metricData.metricLine?.metricPoints || []; + return { + name: metricData.metricName, + data: partitionMetricData.map((item: any) => [item.timeStamp, item.value, item.unit]), + lineStyle: { + width: 1.5, + }, + smooth: 0.25, + symbol: 'emptyCircle', + symbolSize: 4, + emphasis: { + disabled: true, + }, + }; + }); + }} + /> +
          + )} +
          + + ); +}; diff --git a/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/ResetOffsetDrawer.tsx b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/ResetOffsetDrawer.tsx new file mode 100644 index 00000000..b03f6832 --- /dev/null +++ b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/ResetOffsetDrawer.tsx @@ -0,0 +1,187 @@ +import React, { useState, useEffect } from 'react'; +import { Button, DatePicker, Drawer, Form, notification, Radio, Utils, Space, Divider, message } from 'knowdesign'; +import { useParams } from 'react-router-dom'; +import EditTable from '../TestingProduce/component/EditTable'; +import Api from '@src/api/index'; +import moment from 'moment'; + +const CustomSelectResetTime = (props: { value?: string; onChange?: (val: Number | String) => void }) => { + const { value, onChange } = props; + const [timeSetMode, setTimeSetMode] = useState('newest'); + useEffect(() => { + onChange('newest'); + }, []); + return ( + <> + { + setTimeSetMode(e.target.value); + if (e.target.value === 'newest') { + onChange('newest'); + } + }} + value={timeSetMode} + > + 最新Offset + 自定义 + + {timeSetMode === 'custom' && ( + { + onChange(v.valueOf()); + }} + > + )} + + ); +}; + +export default (props: any) => { + const { record, visible, setVisible } = props; + const routeParams = useParams<{ + clusterId: string; + }>(); + const [form] = Form.useForm(); + const defaultResetType = 'assignedTime'; + const [resetType, setResetType] = useState(defaultResetType); + const customFormRef: any = React.createRef(); + const clusterPhyId = Number(routeParams.clusterId); + const [partitionIdList, setPartitionIdList] = useState([]); + useEffect(() => { + form.setFieldsValue({ + resetType: defaultResetType, + }); + }, []); + + useEffect(() => { + visible && + Utils.request(Api.getTopicsMetaData(record?.topicName, +routeParams.clusterId)) + .then((res: any) => { + const partitionLists = (res?.partitionIdList || []).map((item: any) => { + return { + label: item, + value: item, + }; + }); + setPartitionIdList(partitionLists); + }) + .catch((err) => { + message.error(err); + }); + }, [visible]); + const confirm = () => { + let tableData; + if (customFormRef.current) { + tableData = customFormRef.current.getTableData(); + } + const formData = form.getFieldsValue(); + let resetParams: any = { + clusterId: clusterPhyId, + createIfNotExist: false, + groupName: record.groupName, + topicName: record.topicName, + }; + if (formData.resetType === 'assignedTime') { + resetParams.resetType = formData.timestamp === 'newest' ? 0 : 2; + if (resetParams.resetType === 2) { + resetParams.timestamp = formData.timestamp; + } + } + if (formData.resetType === 'partition') { + resetParams.resetType = 3; + resetParams.offsetList = tableData + ? tableData.map((item: { key: string; value: string }) => ({ partitionId: item.key, offset: item.value })) + : []; + } + Utils.put(Api.resetGroupOffset(), resetParams).then((data) => { + if (data === null) { + notification.success({ + message: '重置offset成功', + }); + setVisible(false); + } else { + notification.error({ + message: '重置offset失败', + }); + setVisible(false); + } + }); + }; + return ( + <> + + + + + + } + className="cluster-detail-consumer-resetoffset" + onClose={(_) => { + setVisible(false); + }} + > +
          + + { + setResetType(e.target.value); + }} + > + 重置到指定时间 + 重置分区 + + + {resetType === 'assignedTime' && ( + + + + )} + {resetType === 'partition' && ( + + + + )} +
          +
          + + ); +}; diff --git a/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/config.tsx b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/config.tsx new file mode 100644 index 00000000..8edd9280 --- /dev/null +++ b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/config.tsx @@ -0,0 +1,117 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import React from 'react'; +import { AppContainer } from 'knowdesign'; +import TagsWithHide from '@src/components/TagsWithHide'; +import { ClustersPermissionMap } from '../CommonConfig'; + +export const runningStatusEnum: any = { + 1: 'Doing', + 2: 'Prepare', + 3: 'Success', + 4: 'Failed', + 5: 'Canceled', +}; + +export const defaultPagination = { + current: 1, + pageSize: 10, + position: 'bottomRight', + showSizeChanger: true, + pageSizeOptions: ['10', '20', '50', '100', '200', '500'], +}; + +export const getGroupColumns = (arg?: any) => { + const columns = [ + { + title: 'ConsumerGroup', + dataIndex: 'name', + key: 'name', + lineClampTwo: true, + render: (v: any, r: any) => { + return ( + { + window.location.hash = `groupName=${v || ''}`; + }} + > + {v} + + ); + }, + width: 200, + }, + { + title: '消费的Topic', + dataIndex: 'topicNameList', + key: 'topicNameList', + width: 200, + render(t: any, r: any) { + return t && t.length > 0 ? `共有${num}个`} /> : '-'; + }, + }, + { + title: 'Status', + dataIndex: 'state', + key: 'state', + width: 200, + }, + { + title: 'Member数', + dataIndex: 'memberCount', + key: 'memberCount', + width: 200, + render: (t: number) => (t ? t.toLocaleString() : '-'), + }, + ]; + return columns; +}; + +export const getGtoupTopicColumns = (arg?: any) => { + const [global] = AppContainer.useGlobalValue(); + const columns: any = [ + { + title: 'Topic名称', + dataIndex: 'topicName', + key: 'topicName', + needTooltip: true, + lineClampOne: true, + width: 150, + }, + { + title: 'Status', + dataIndex: 'state', + key: 'state', + width: 150, + }, + { + title: 'Max Lag', + dataIndex: 'maxLag', + key: 'maxLag', + width: 150, + render: (t: number) => (t ? t.toLocaleString() : '-'), + }, + { + title: 'Member数', + dataIndex: 'memberCount', + key: 'memberCount', + width: 150, + render: (t: number) => (t ? t.toLocaleString() : '-'), + }, + ]; + if (global.hasPermission && global.hasPermission(ClustersPermissionMap.CONSUMERS_RESET_OFFSET)) { + columns.push({ + title: '操作', + dataIndex: 'desc', + key: 'desc', + width: 150, + render: (value: any, record: any) => { + return ( + + ); + }, + }); + } + return columns; +}; diff --git a/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/index.less b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/index.less new file mode 100644 index 00000000..82c5bcf5 --- /dev/null +++ b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/index.less @@ -0,0 +1,186 @@ +.brokerList { + .d-table-box-header { + padding: 0 0 12px 0; + } + .tag-success, + .tag-error { + padding: 2px 8px; + border-radius: 4px; + margin-left: 4px; + } + .tag-success { + background: #f1faf2; + color: #73d380; + } + .tag-error { + background: #fff0ef; + color: #ff7066; + } +} + +.operating-state { + .consumers-search { + display: contents; + .search-input-short { + margin-right: 8px; + } + } + .pro-table-wrap { + // padding: 17px 24px; + background: #fff; + border-radius: 12px; + } +} +.consumer-group-detail-drawer { + &-table { + .dcloud-table-cell { + padding: 7px 16px 8px 2px !important; + } + .dcloud-table-row-expand-icon-cell { + padding: 7px 7px 5px 24px !important; + } + + .dcloud-table-expanded-row-fixed { + padding: 16px 20px !important; + .dcloud-table-cell { + font-size: 12px !important; + } + } + } + + .dcloud-drawer-extra { + button { + width: 90px; + } + .divider { + width: 1px; + height: 17px; + margin: 0 16px; + background: rgba(206, 212, 218, 0.6); + } + } + .dcloud-drawer-body { + padding-top: 2px !important; + } +} + +.consumer-group-detail { + // border: 1px solid #EFF2F7; + // border-radius: 8px; + // padding: 12px 16px; + .title-and-mode { + display: flex; + align-items: center; + justify-content: space-between; + height: 60px; + &-header { + font-family: @font-family-bold; + font-size: 13px; + } + h4 { + font-family: PingFangSC-Semibold; + } + .right { + display: flex; + justify-content: center; + align-items: center; + .d-range-time-input { + height: 27px !important; + padding: 0 11px; + input { + line-height: 100%; + } + } + .divider { + width: 1px; + height: 20px; + background: rgba(206, 212, 218, 0.6); + margin: 0 8px; + } + .switch-mode { + .dcloud-radio-button-wrapper { + font-size: 14px; + width: 34px; + height: 23px; + padding: 0; + line-height: 22px; + text-align: center; + } + } + } + } + .single-chart, + .table { + background: #f8f9fa; + // margin-top: 12px; + border-radius: 8px; + .dcloud-table { + height: 210px; + overflow: auto; + background-color: transparent; + .dcloud-table-content .dcloud-table-cell { + background-color: transparent; + } + } + .dcloud-pagination { + height: 32px; + margin-bottom: 0; + margin-top: 8px; + } + } + .single-chart { + padding: 16px 22px 4px; + .single-chart-header { + display: none; + } + } + .content-with-copy { + display: flex; + align-items: center; + .content { + flex: 1; + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + word-break: break-all; + } + .copy-icon { + width: 20px; + height: 20px; + padding-top: 2px; + border-radius: 50%; + margin-left: 4px; + font-size: 16px; + color: #adb5bc; + opacity: 0; + &:hover { + background: rgba(33, 37, 41, 0.04); + color: #74788d; + } + } + } + .dcloud-table-cell-row-hover { + .copy-icon { + opacity: 1; + } + } +} +.cluster-detail-consumer-resetoffset { + .reset-offset-form { + .dcloud-radio-wrapper { + width: 154px; + } + } + .operate-wrap { + display: flex; + justify-content: center; + align-items: center; + .operate-btns-divider { + width: 1px; + height: 17px; + background: rgba(0, 0, 0, 0.13); + margin: 0 16px; + } + } +} diff --git a/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/index.tsx new file mode 100644 index 00000000..55647ae0 --- /dev/null +++ b/km-console/packages/layout-clusters-fe/src/pages/ConsumerGroup/index.tsx @@ -0,0 +1,134 @@ +import React, { useState, useEffect, memo } from 'react'; +import { useParams } from 'react-router-dom'; +import { ProTable, Utils, AppContainer, SearchInput, Divider, Form, Input, Button } from 'knowdesign'; +import { IconFont } from '@knowdesign/icons'; +import API from '../../api'; +import { getGroupColumns, defaultPagination } from './config'; +import { tableHeaderPrefix } from '@src/constants/common'; +import BrokerDetail from '../BrokerDetail'; +import DBreadcrumb from 'knowdesign/es/extend/d-breadcrumb'; +import ConsumerGroupHealthCheck from '@src/components/CardBar/ConsumerGroupHealthCheck'; +import GroupDetail from './Detail'; +import './index.less'; + +const { request } = Utils; + +const BrokerList: React.FC = (props: any) => { + const [global] = AppContainer.useGlobalValue(); + const [form] = Form.useForm(); + const urlParams = useParams(); // 获取地址栏参数 + const [loading, setLoading] = useState(false); + const [data, setData] = useState([]); + const [searchKeywords, setSearchKeywords] = useState(''); + const [pagination, setPagination] = useState(defaultPagination); + const [searchWords, setSearchWords] = useState<{ groupName: string; topicName: string }>({ groupName: '', topicName: '' }); + // 请求接口获取数据 + const genData = async ({ pageNo, pageSize }: any) => { + if (urlParams?.clusterId === undefined) return; + + setLoading(true); + const params = { + searchGroupName: searchWords.groupName ? searchWords.groupName.slice(0, 128) : undefined, + searchTopicName: searchWords.topicName ? searchWords.topicName.slice(0, 128) : undefined, + pageNo, + pageSize, + }; + + request(API.getOperatingStateList(urlParams?.clusterId), { params }) + .then((res: any) => { + setPagination({ + current: res.pagination?.pageNo, + pageSize: res.pagination?.pageSize, + total: res.pagination?.total, + }); + setData(res?.bizData || []); + setLoading(false); + }) + .catch((err) => { + setLoading(false); + }); + }; + + // 查询 + const onFinish = (formData: any) => { + setSearchWords(formData); + }; + + const onTableChange = (pagination: any, filters: any, sorter: any) => { + genData({ pageNo: pagination.current, pageSize: pagination.pageSize, filters, sorter }); + }; + + useEffect(() => { + genData({ + pageNo: 1, + pageSize: pagination.pageSize, + }); + }, [searchWords]); + + return ( +
          +
          + +
          +
          + +
          +
          +
          +
          +
          genData({ pageNo: pagination.current, pageSize: pagination.pageSize })} + > + +
          + +
          + + + + + + +
          +
          +
          + + + +
          +
          +
          +
          + +
          + {} +
          + ); +}; + +export default BrokerList; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConsumerGroupDetail.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConsumerGroupDetail.tsx new file mode 100644 index 00000000..bd502b1a --- /dev/null +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConsumerGroupDetail.tsx @@ -0,0 +1,502 @@ +import React, { useState, useEffect } from 'react'; +import { useParams, useHistory } from 'react-router-dom'; +import { AppContainer, Divider, Drawer, ProTable, Select, SingleChart, Space, Tooltip, Utils } from 'knowdesign'; +import { IconFont } from '@knowdesign/icons'; +import { DRangeTime } from 'knowdesign'; +import { CHART_COLOR_LIST, getBasicChartConfig } from '@src/constants/chartConfig'; +import Api from '@src/api/index'; +import { hashDataParse } from '@src/constants/common'; +import { ClustersPermissionMap } from '../CommonConfig'; +import ResetOffsetDrawer from './ResetOffsetDrawer'; +import SwitchTab from '@src/components/SwitchTab'; +import ContentWithCopy from '@src/components/CopyContent'; + +const { Option } = Select; + +export interface MetricLine { + createTime?: number; + metricPoints: Array<{ + aggType: string; + createTime: number; + timeStamp: number; + unit: string; + updateTime: number; + value: number; + }>; + name: string; + updateTime?: number; +} +export interface MetricData { + metricLines?: Array; + metricLine?: MetricLine; + metricName: string; +} + +export interface HashData { + groupName: string; + topicName: string; +} + +const metricConsts = ['LogEndOffset', 'OffsetConsumed', 'Lag']; +const metricWithType = [ + { metricName: 'LogEndOffset', metricType: 104 }, + { metricName: 'OffsetConsumed', metricType: 102 }, + { metricName: 'Lag', metricType: 102 }, +]; + +export default (props: any) => { + const { scene, visible, setVisible, hashData } = props; + const params = useParams<{ + clusterId: string; + }>(); + const history = useHistory(); + const [global] = AppContainer.useGlobalValue(); + // const { record } = props; + const now = Date.now(); + const [allGroupMetricsData, setAllGroupMetricsData] = useState>([]); + const [groupMetricsData, setGroupMetricsData] = useState>([]); + const [timeRange, setTimeRange] = useState([now - 24 * 60 * 60 * 1000, now]); + const [consumerList, setConsumerList] = useState([]); + const [partitionList, setPartitionList] = useState([]); + const [curPartition, setCurPartition] = useState(''); + const [showMode, setShowMode] = useState('table'); + const [pageIndex, setPageIndex] = useState(1); + const [pageTotal, setPageTotal] = useState(1); + const [pageSize, setPageSize] = useState(10); + const [consumerListLoading, setConsumerListLoading] = useState(true); + const [consumerChartLoading, setConsumerChartLoading] = useState(false); + // const [hashData, setHashData] = useState({ groupName: '', topicName: '' }); + // const [visible, setVisible] = useState(false); + const [sortObj, setSortObj] = useState<{ + sortField: string; + sortType: 'desc' | 'asc' | ''; + }>({ sortField: '', sortType: '' }); + const [pagination, setPagination] = useState({ + current: 1, + pageSize: 10, + position: 'bottomRight', + showSizeChanger: true, + pageSizeOptions: ['10', '20', '50', '100', '200', '500'], + showTotal: (total: number) => `共 ${total} 条目`, + }); + const clusterId = Number(params.clusterId); + const columns = [ + { + title: 'Topic Partition', + dataIndex: 'partitionId', + key: 'partitionId', + lineClampOne: true, + needTooltip: true, + width: 180, + render: (v: string, record: any) => { + return `${record.topicName}-${v}`; + }, + }, + { + title: 'Member ID', + dataIndex: 'memberId', + key: 'memberId', + width: 200, + render: (v: string) => { + return v ? : '-'; + }, + }, + { + title: 'Current Offset', + dataIndex: 'OffsetConsumed', + key: 'OffsetConsumed', + render: (v: any, record: any) => { + return record?.latestMetrics?.metrics?.OffsetConsumed.toLocaleString(); + }, + sorter: true, + // sorter: { + // compare: (a: any, b: any) => { + // let value1 = a?.metrics?.find((item: any) => item.metricName === 'OffsetConsumed' && item.metricType === 102)?.metricValue + // let value2 = b?.metrics?.find((item: any) => item.metricName === 'OffsetConsumed' && item.metricType === 102)?.metricValue + // return value1 - value2 + // }, + // multiple: 1 + // } + }, + { + title: 'Log End Offset', + dataIndex: 'LogEndOffset', + key: 'LogEndOffset', + render: (v: any, record: any) => { + return record?.latestMetrics?.metrics?.LogEndOffset.toLocaleString(); + }, + sorter: true, + // sorter: { + // compare: (a: any, b: any) => { + // let value1 = a?.metrics?.find((item: any) => item.metricName === 'LogEndOffset' && item.metricType === 104)?.metricValue + // let value2 = b?.metrics?.find((item: any) => item.metricName === 'LogEndOffset' && item.metricType === 104)?.metricValue + // return value1 - value2 + // }, + // multiple: 2 + // } + }, + { + title: 'Lag', + dataIndex: 'Lag', + key: 'Lag', + render: (v: any, record: any) => { + return record?.latestMetrics?.metrics?.Lag.toLocaleString(); + }, + sorter: true, + // sorter: { + // compare: (a: any, b: any) => { + // let value1 = a?.metrics?.find((item: any) => item.metricName === 'Lag' && item.metricType === 102)?.metricValue + // let value2 = b?.metrics?.find((item: any) => item.metricName === 'Lag' && item.metricType === 102)?.metricValue + // return value1 - value2 + // }, + // multiple: 3 + // } + }, + { + title: 'Host', + dataIndex: 'host', + key: 'host', + }, + { + title: 'Client ID', + dataIndex: 'clientId', + key: 'clientId', + needTooltip: true, + lineClampOne: true, + width: 200, + }, + ]; + const getTopicGroupMetric = ({ + hashData, + pagination = { current: 1, pageSize: 10 }, + sorter = {}, + }: { + hashData: HashData; + pagination?: any; + sorter?: any; + }) => { + setConsumerListLoading(true); + const params: any = { + // metricRealTimes: metricWithType, + latestMetricNames: metricConsts, + pageNo: pagination.current, + pageSize: pagination.pageSize, + sortField: sorter.field || undefined, + sortType: sorter.order ? sorter.order.substring(0, sorter.order.indexOf('end')) : undefined, + }; + // if (sorter.sortField && sorter.sortType) { + // params.sortField = sorter.sortField; + // params.sortType = sorter.sortType; + // } + return Utils.post( + Api.getTopicGroupMetric({ + clusterId, + groupName: hashData.groupName, + topicName: hashData.topicName, + }), + params + ) + .then((data: any) => { + if (!data) return; + + setPagination({ + current: data.pagination?.pageNo, + pageSize: data.pagination?.pageSize, + total: data.pagination?.total, + }); + setConsumerList(data?.bizData); + }) + .finally(() => { + setConsumerListLoading(false); + }); + }; + const getTopicGroupPartitionsHistory = (hashData: HashData) => { + return Utils.request(Api.getTopicGroupPartitionsHistory(clusterId, hashData.groupName), { + params: { + startTime: timeRange[0], + endTime: timeRange[1], + }, + }); + }; + const getTopicGroupMetricHistory = (partitions: Array, hashData: HashData) => { + const params = { + aggType: 'sum', + groupTopics: partitions?.map((p) => ({ + partition: p.value, + topic: hashData.topicName, + })), + group: hashData.groupName, + metricsNames: metricWithType.map((item) => item.metricName), + startTime: timeRange[0], + endTime: timeRange[1], + topNu: 0, + }; + Utils.post(Api.getTopicGroupMetricHistory(clusterId), params).then((data: Array) => { + setAllGroupMetricsData(data); + }); + }; + const getConsumersMetadata = (hashData: HashData) => { + return Utils.request(Api.getConsumersMetadata(clusterId, hashData.groupName, hashData.topicName)); + }; + + const getTopicsMetaData = (hashData: HashData) => { + return Utils.request(Api.getTopicsMetaData(hashData.topicName, clusterId)); + }; + + const onClose = () => { + setVisible(false); + setSortObj({ + sortField: '', + sortType: '', + }); + // clean hash' + // scene === 'topicDetail' && history.goBack(); + // scene !== 'topicDetail' && window.history.pushState('', '', location.pathname); + }; + + const onTableChange = (pagination: any, filters: any, sorter: any) => { + getTopicGroupMetric({ hashData, pagination, sorter }); + // setPageIndex(pagination.current); + }; + + useEffect(() => { + if (curPartition === '' || allGroupMetricsData.length === 0) return; + const filteredData = allGroupMetricsData.map((item) => { + const allData = item.metricLines.reduce( + (acc, cur) => { + if (acc.metricLine.metricPoints.length === 0) { + acc.metricLine.metricPoints = cur.metricPoints.map((p) => ({ + timeStamp: p.timeStamp, + value: Number(p.value), + })); + } else { + acc.metricLine.metricPoints.forEach((mp) => { + const curMetricPoint = cur.metricPoints.find((curmp) => curmp.timeStamp === mp.timeStamp); + mp.value += curMetricPoint ? Number(curMetricPoint.value) : 0; + }); + } + return acc; + }, + { + metricName: item.metricName, + metricLine: { + name: 'all', + metricPoints: [], + }, + } + ); + return curPartition === '__all__' + ? allData + : { + metricName: item.metricName, + metricLine: item.metricLines.find((line) => line.name.indexOf(curPartition) >= 0), + }; + }); + setGroupMetricsData(filteredData); + }, [curPartition, allGroupMetricsData]); + + useEffect(() => { + // const hashData = hashDataParse(location.hash); + if (!hashData.groupName || !hashData.topicName) return; + // setHashData(hashData); + // 获取分区列表 为图表模式做准备 + visible && + getConsumersMetadata(hashData).then((res: any) => { + if (!res.exist) { + setVisible(false); + // history.push(`/cluster/${params?.clusterId}/consumers`); + return; + } + getTopicsMetaData(hashData) + // .then((data: any) => { + // if (data.length > 0) { + // setCurPartition(data[0].partition); + // } + // setPartitionList(data); + // return data; + // }) + .then((data: any) => { + const partitionLists = (data?.partitionIdList || []).map((item: any) => { + return { + label: item, + value: item, + }; + }); + setCurPartition(partitionLists?.[0]?.value); + setPartitionList(partitionLists); + getTopicGroupMetricHistory(partitionLists, hashData); + }) + .catch((e) => { + // history.push(`/cluster/${params?.clusterId}/consumers`); + setVisible(false); + }); + // 获取Consumer列表 表格模式 + getTopicGroupMetric({ hashData: hashData as HashData }); + }); + }, [visible]); + + useEffect(() => { + if (partitionList.length === 0) return; + getTopicGroupMetricHistory(partitionList, hashData); + }, [timeRange]); + + return ( + + {global.hasPermission && + global.hasPermission( + scene === 'topicDetail' ? ClustersPermissionMap.TOPIC_RESET_OFFSET : ClustersPermissionMap.CONSUMERS_RESET_OFFSET + ) && } + + + } + > +
          +
          +
          +
          + {showMode === 'chart' && ( + + )} + {showMode === 'chart' && ( + { + setTimeRange(o); + }} + > + )} + {showMode === 'chart' &&
          } + setShowMode(key)}> + +
          + +
          +
          + +
          + +
          +
          +
          +
          +
          + {showMode === 'table' && ( + // { + // setSortObj({ + // sortField: sorter.field || '', + // sortType: sorter.order ? sorter.order.substring(0, sorter.order.indexOf('end')) : '', + // }); + // setPageIndex(pagination.current); + // }} + // >
          + + )} + {showMode === 'chart' && ( +
          + { + return data.map((metricData: any) => { + const partitionMetricData = metricData.metricLine?.metricPoints || []; + return { + name: metricData.metricName, + data: partitionMetricData.map((item: any) => [item.timeStamp, item.value, item.unit]), + lineStyle: { + width: 1.5, + }, + smooth: 0.25, + symbol: 'emptyCircle', + symbolSize: 4, + emphasis: { + disabled: true, + }, + }; + }); + }} + /> +
          + )} +
          +
          + ); +}; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConsumerGroups.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConsumerGroups.tsx index 9fa3be5c..9d1c6a6d 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConsumerGroups.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ConsumerGroups.tsx @@ -1,50 +1,58 @@ import React, { useState, useEffect } from 'react'; import { ProTable, Utils } from 'knowdesign'; import Api from '@src/api'; +import { useParams } from 'react-router-dom'; +import ConsumerGroupDetail from './ConsumerGroupDetail'; const { request } = Utils; -const getColmns = (solveClick: any) => { - const columns = [ + +const getColmns = (arg: any) => { + const baseColumns: any = [ { title: 'ConsumerGroup', - dataIndex: 'ConsumerGroup', - key: 'ConsumerGroup', + dataIndex: 'groupName', + key: 'groupName', + render: (v: any, r: any) => { + return arg.getGroupInfo(v)}>{v}; + }, }, { - title: '关联KafkaUser', - dataIndex: 'kafkaUser', - key: 'kafkaUser', + title: '消费的Topic', + dataIndex: 'topicName', + key: 'topicName', }, + // { + // title: 'Principle', + // dataIndex: 'kafkaUser', + // key: 'kafkaUser', + // }, { title: 'Status', - dataIndex: 'status', - key: 'status', + dataIndex: 'state', + key: 'state', }, { title: 'Max Lag', dataIndex: 'maxLag', key: 'maxLag', + render: (t: number) => (t ? t.toLocaleString() : '-'), }, { title: 'Member数', - dataIndex: 'member', - key: 'member', - }, - { - title: '操作', - dataIndex: 'option', - key: 'option', - // eslint-disable-next-line react/display-name - render: (_t: any, r: any) => { - return solveClick(r)}>解决; - }, + dataIndex: 'memberCount', + key: 'memberCount', + render: (t: number) => (t ? t.toLocaleString() : '-'), }, ]; - return columns; + + return baseColumns; }; const TopicGroup = (props: any) => { + const { hashData } = props; + const urlParams = useParams(); // 获取地址栏参数 const [loading, setLoading] = useState(false); const [data, setData] = useState([]); + const [visible, setVisible] = useState(false); const [pagination, setPagination] = useState({ current: 1, pageSize: 10, @@ -52,32 +60,22 @@ const TopicGroup = (props: any) => { showSizeChanger: true, pageSizeOptions: ['10', '20', '50', '100', '200', '500'], showTotal: (total: number) => `共 ${total} 条目`, - // locale: { - // items_per_page: '条', - // }, - // selectComponentClass: CustomSelect, }); - const solveClick = (record: any) => {}; + const [groupName, setGroupName] = useState(''); // 请求接口获取数据 const genData = async ({ pageNo, pageSize, filters = null, sorter = null }: any) => { - // if (clusterId === undefined) return; - - // filters = filters || filteredInfo; + if (urlParams?.clusterId === undefined || hashData?.topicName === undefined) return; setLoading(true); - // const params = dealTableRequestParams({ searchKeywords, pageNo, pageSize, sorter, filters, isPhyId: true }); const params = { - filterKey: 'string', - filterPartitionId: 1, - filterValue: 'string', - maxRecords: 100, - pullTimeoutUnitMs: 10000, - truncate: true, + searchGroupName: props.searchKeywords ? props.searchKeywords.slice(0, 128) : undefined, + pageNo, + pageSize, }; - request(Api.getTopicMessagesList('你好', 2), { params }) + request(Api.getTopicGroupList(hashData?.topicName, urlParams?.clusterId), { params }) .then((res: any) => { setPagination({ current: res.pagination?.pageNo, @@ -97,38 +95,62 @@ const TopicGroup = (props: any) => { }); }; - const onTableChange = (pagination: any, filters: any, sorter: any) => { - setPagination(pagination); - // const asc = sorter?.order && sorter?.order === 'ascend' ? true : false; - // const sortColumn = sorter.field && toLine(sorter.field); - // genData({ pageNo: pagination.current, pageSize: pagination.pageSize, filters, asc, sortColumn, queryTerm: searchResult, ...allParams }); + const getGroupInfo = (groupName: string) => { + setVisible(true); + setGroupName(groupName); }; - // useEffect(() => { - // genData({ - // pageNo: 1, - // pageSize: pagination.pageSize, - // // sorter: defaultSorter - // }); - // }, [props]); + const onTableChange = (pagination: any, filters: any, sorter: any) => { + // setPagination(pagination); + // const asc = sorter?.order && sorter?.order === 'ascend' ? true : false; + // const sortColumn = sorter.field && toLine(sorter.field); + genData({ pageNo: pagination.current, pageSize: pagination.pageSize }); + }; + + useEffect(() => { + props.positionType === 'ConsumerGroups' && + genData({ + pageNo: 1, + pageSize: pagination.pageSize, + // sorter: defaultSorter + }); + }, [props.searchKeywords]); return ( - +
          + + {} +
          + // ); }; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ResetOffsetDrawer.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ResetOffsetDrawer.tsx new file mode 100644 index 00000000..c079393b --- /dev/null +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/ResetOffsetDrawer.tsx @@ -0,0 +1,197 @@ +import React, { useState, useEffect } from 'react'; +import { Button, DatePicker, Drawer, Form, notification, Radio, Utils, Space, Divider, message } from 'knowdesign'; +import { useParams } from 'react-router-dom'; +import EditTable from '../TestingProduce/component/EditTable'; +import Api from '@src/api/index'; +import moment from 'moment'; + +const CustomSelectResetTime = (props: { value?: string; onChange?: (val: Number | String) => void }) => { + const { value, onChange } = props; + const [timeSetMode, setTimeSetMode] = useState('newest'); + useEffect(() => { + onChange('newest'); + }, []); + return ( + <> + { + setTimeSetMode(e.target.value); + if (e.target.value === 'newest') { + onChange('newest'); + } + }} + value={timeSetMode} + > + 最新Offset + 自定义 + + {timeSetMode === 'custom' && ( + { + onChange(v.valueOf()); + }} + > + )} + + ); +}; + +export default (props: any) => { + const { record } = props; + const routeParams = useParams<{ + clusterId: string; + }>(); + const [form] = Form.useForm(); + const defaultResetType = 'assignedTime'; + const [resetType, setResetType] = useState(defaultResetType); + const [resetOffsetVisible, setResetOffsetVisible] = useState(false); + const customFormRef: any = React.createRef(); + const clusterPhyId = Number(routeParams.clusterId); + const [partitionIdList, setPartitionIdList] = useState([]); + useEffect(() => { + form.setFieldsValue({ + resetType: defaultResetType, + }); + }, []); + + useEffect(() => { + Utils.request(Api.getTopicsMetaData(record?.topicName, +routeParams.clusterId)) + .then((res: any) => { + const partitionLists = (res?.partitionIdList || []).map((item: any) => { + return { + label: item, + value: item, + }; + }); + setPartitionIdList(partitionLists); + }) + .catch((err) => { + message.error(err); + }); + }, []); + const confirm = () => { + let tableData; + if (customFormRef.current) { + tableData = customFormRef.current.getTableData(); + } + const formData = form.getFieldsValue(); + let resetParams: any = { + clusterId: clusterPhyId, + createIfNotExist: false, + groupName: record.groupName, + topicName: record.topicName, + }; + if (formData.resetType === 'assignedTime') { + resetParams.resetType = formData.timestamp === 'newest' ? 0 : 2; + if (resetParams.resetType === 2) { + resetParams.timestamp = formData.timestamp; + } + } + if (formData.resetType === 'partition') { + resetParams.resetType = 3; + resetParams.offsetList = tableData + ? tableData.map((item: { key: string; value: string }) => ({ partitionId: item.key, offset: item.value })) + : []; + } + Utils.put(Api.resetGroupOffset(), resetParams).then((data) => { + if (data === null) { + notification.success({ + message: '重置offset成功', + }); + setResetOffsetVisible(false); + } else { + notification.error({ + message: '重置offset失败', + }); + setResetOffsetVisible(false); + } + }); + }; + return ( + <> + + + + + + + + } + className="cluster-detail-consumer-resetoffset" + onClose={(_) => { + setResetOffsetVisible(false); + }} + > +
          + + { + setResetType(e.target.value); + }} + > + 重置到指定时间 + 重置分区 + + + {resetType === 'assignedTime' && ( + + + + )} + {resetType === 'partition' && ( + + + + )} +
          +
          + + ); +}; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/index.tsx index cd2d6d66..bc3f6ed4 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/index.tsx @@ -1,13 +1,16 @@ import React, { useState, useEffect } from 'react'; import { useHistory, useParams } from 'react-router-dom'; -import { Tabs, Utils, Drawer, Tag, AppContainer, SearchInput, notification } from 'knowdesign'; +import { Tabs, Utils, Drawer, Tag, AppContainer, SearchInput } from 'knowdesign'; +import notification from '@src/components/Notification'; + import Api from '@src/api'; import BrokersDetail from './BrokersDetail'; import Messages from './Messages'; import ConsumerGroups from './ConsumerGroups'; import ACLs from './ACLs'; import Configuration from './Configuration'; -import Consumers from '@src/pages/Consumers'; +import Consumers from './ConsumerGroups'; +// import Consumers from '@src/pages/Consumers'; import './index.less'; import TopicDetailHealthCheck from '@src/components/CardBar/TopicDetailHealthCheck'; import { hashDataParse } from '@src/constants/common'; @@ -115,35 +118,34 @@ const TopicDetail = (props: any) => { useEffect(() => { global?.clusterInfo?.id && hashDataParse(location.hash).topicName ? Utils.request(Api.getTopicMetadata(+global?.clusterInfo?.id, hashDataParse(location.hash)?.topicName), { - init: { - errorNoTips: true, - }, - }) - .then((topicData: any) => { - if (topicData?.exist && !hashDataParse(location.hash).groupName) { - setHashData(topicData); - setVisible(true); - } else { + init: { + errorNoTips: true, + }, + }) + .then((topicData: any) => { + if (topicData?.exist && !hashDataParse(location.hash).groupName) { + setHashData(topicData); + setVisible(true); + } else { + history.replace(`/cluster/${urlParams?.clusterId}/topic/list`); + // history.push(`/`); + setVisible(false); + } + }) + .catch((err) => { history.replace(`/cluster/${urlParams?.clusterId}/topic/list`); - // history.push(`/`); setVisible(false); - } - }) - .catch((err) => { - history.replace(`/cluster/${urlParams?.clusterId}/topic/list`); - setVisible(false); - notification.error({ - message: '错误', - duration: 3, - description: `${'Topic不存在或Topic名称有误'}`, - }); - }) + notification.error({ + message: '错误', + description: 'Topic不存在或Topic名称有误', + }); + }) : setVisible(false); }, [hashDataParse(location.hash).topicName, global?.clusterInfo]); return ( {hashData?.topicName} @@ -192,12 +194,9 @@ const TopicDetail = (props: any) => { {positionType === 'Messages' && } - + {positionType === 'ConsumerGroups' && ( + + )} {positionType === 'ACLs' && } diff --git a/km-console/packages/layout-clusters-fe/src/pages/pageRoutes.ts b/km-console/packages/layout-clusters-fe/src/pages/pageRoutes.ts index 13422a46..50e6ac71 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/pageRoutes.ts +++ b/km-console/packages/layout-clusters-fe/src/pages/pageRoutes.ts @@ -10,7 +10,7 @@ import BrokerControllerChangeLog from './BrokerControllerChangeLog'; import TopicBoard from './TopicDashboard'; import TopicList from './TopicList'; -import Consumers from './Consumers/index'; +import Consumers from './ConsumerGroup'; import Jobs from './Jobs'; From 47b6b3577aaee556c7055bf1e5e2de48ded62a3c Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Fri, 21 Oct 2022 11:44:12 +0800 Subject: [PATCH 140/145] =?UTF-8?q?fix:=20Broker=20=E5=88=97=E8=A1=A8=20jm?= =?UTF-8?q?xPort=20=E5=88=97=E6=94=AF=E6=8C=81=E5=B1=95=E7=A4=BA=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layout-clusters-fe/src/pages/BrokerList/config.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/km-console/packages/layout-clusters-fe/src/pages/BrokerList/config.tsx b/km-console/packages/layout-clusters-fe/src/pages/BrokerList/config.tsx index a0f6cbe5..d2b28cda 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/BrokerList/config.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/BrokerList/config.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { timeFormat, getSizeAndUnit } from '../../constants/common'; import moment from 'moment'; import { Tag, Tooltip } from 'knowdesign'; +import { IconFont } from '@knowdesign/icons'; export const getBrokerListColumns = (arg?: any) => { const columns = [ @@ -82,6 +83,14 @@ export const getBrokerListColumns = (arg?: any) => { dataIndex: 'jmxPort', key: 'jmxPort', width: 100, + render: (t: string, r: any) => { + return ( + + + {t} + + ); + }, }, { title: 'Partitions', From 8f4ff36c09f6298995daa4daf92c42145493b1e6 Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Fri, 21 Oct 2022 11:44:38 +0800 Subject: [PATCH 141/145] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=20Topic=20?= =?UTF-8?q?=E6=89=A9=E5=88=86=E5=8C=BA=E5=90=8D=E7=A7=B0=20&=20=E6=8F=8F?= =?UTF-8?q?=E8=BF=B0=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/TopicList/ExpandPartition.tsx | 19 +++++++++----- .../src/pages/TopicList/index.less | 26 ++++++++++++++----- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicList/ExpandPartition.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicList/ExpandPartition.tsx index b17a41ab..bf87fb59 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicList/ExpandPartition.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicList/ExpandPartition.tsx @@ -1,9 +1,10 @@ import React, { useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; -import { AppContainer, Button, Divider, Drawer, Form, InputNumber, notification, SingleChart, Space, Spin, Utils } from 'knowdesign'; +import { AppContainer, Button, Divider, Drawer, Form, InputNumber, SingleChart, Space, Spin, Tooltip, Utils } from 'knowdesign'; +import notification from '@src/components/Notification'; import Api, { MetricType } from '@src/api/index'; -import { getBasicChartConfig, getUnit } from '@src/constants/chartConfig'; -import { formatChartData, MetricDefaultChartDataType } from '@src/constants/chartConfig'; +import { getBasicChartConfig, getDataUnit } from '@src/constants/chartConfig'; +import { formatChartData, OriginMetricData } from '@src/constants/chartConfig'; const ExpandPartition = (props: { record: any; onConfirm: () => void }) => { const [global] = AppContainer.useGlobalValue(); @@ -60,7 +61,7 @@ const ExpandPartition = (props: { record: any; onConfirm: () => void }) => { ); const empiricalMinValue = 10 * 1024 * record.partitionNum; - const lines = data.map((metric: MetricDefaultChartDataType) => { + const lines = data.map((metric: OriginMetricData) => { const child = metric.metricLines[0]; child.name = metric.metricName; return child; @@ -87,7 +88,7 @@ const ExpandPartition = (props: { record: any; onConfirm: () => void }) => { }); }, [expandPartitionsVisible]); const formattedMinBytesInOut = (v: number) => { - const [unit, size] = getUnit(v); + const [unit, size] = getDataUnit['Memory'](v); return `${(v / size).toFixed(2)}${unit}/s`; }; return ( @@ -130,11 +131,15 @@ const ExpandPartition = (props: { record: any; onConfirm: () => void }) => {
          Topic名称 : - {record.topicName} + + {record.topicName} +
          描述 : - {record.description} + + {record.description || '-'} +
          diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicList/index.less b/km-console/packages/layout-clusters-fe/src/pages/TopicList/index.less index 453363c6..0fa44077 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicList/index.less +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicList/index.less @@ -142,6 +142,7 @@ color: #74788d; } .desc-field { + flex-shrink: 0; width: 34px; } .val, @@ -149,17 +150,28 @@ color: #495057; letter-spacing: 0; font-weight: 400; - } - .val { - width: 105px; margin-left: 12px; } - .desc-val { - width: 809px; - height: 36px; + .val { + max-width: 208px; overflow: hidden; - -webkit-box-orient: vertical; + text-overflow: ellipsis; + white-space: nowrap; + } + .desc-val { + height: 36px; + display: -webkit-box; + overflow: hidden; + text-overflow: ellipsis; -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + word-break: break-all; + } + &:first-child { + margin-right: 40px; + } + &:last-child { + flex: 1; } } } From 163cab78ae601af0f6c2a38d0587b51d3ca5ae51 Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Fri, 21 Oct 2022 11:45:00 +0800 Subject: [PATCH 142/145] =?UTF-8?q?fix:=20=E9=83=A8=E5=88=86=E6=96=87?= =?UTF-8?q?=E6=A1=88=20&=20=E6=A0=B7=E5=BC=8F=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/CopyContent/index.less | 2 +- .../src/pages/Consumers/ConsumerGroupDetail.tsx | 6 +++--- .../layout-clusters-fe/src/pages/Consumers/index.tsx | 2 ++ .../layout-clusters-fe/src/pages/Jobs/ExpandedRow.tsx | 1 + .../packages/layout-clusters-fe/src/pages/Login/index.tsx | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/km-console/packages/layout-clusters-fe/src/components/CopyContent/index.less b/km-console/packages/layout-clusters-fe/src/components/CopyContent/index.less index c21edafd..5e001aa0 100644 --- a/km-console/packages/layout-clusters-fe/src/components/CopyContent/index.less +++ b/km-console/packages/layout-clusters-fe/src/components/CopyContent/index.less @@ -25,7 +25,7 @@ } } -.dcloud-table-cell-row-hover { +.content-with-copy:hover{ .copy-icon { opacity: 1; } diff --git a/km-console/packages/layout-clusters-fe/src/pages/Consumers/ConsumerGroupDetail.tsx b/km-console/packages/layout-clusters-fe/src/pages/Consumers/ConsumerGroupDetail.tsx index 1e057d29..8c220330 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Consumers/ConsumerGroupDetail.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Consumers/ConsumerGroupDetail.tsx @@ -98,7 +98,7 @@ export default (props: any) => { dataIndex: 'OffsetConsumed', key: 'OffsetConsumed', render: (v: any, record: any) => { - return record?.latestMetrics?.metrics?.OffsetConsumed; + return record?.latestMetrics?.metrics?.OffsetConsumed.toLocaleString(); }, sorter: true, // sorter: { @@ -115,7 +115,7 @@ export default (props: any) => { dataIndex: 'LogEndOffset', key: 'LogEndOffset', render: (v: any, record: any) => { - return record?.latestMetrics?.metrics?.LogEndOffset; + return record?.latestMetrics?.metrics?.LogEndOffset.toLocaleString(); }, sorter: true, // sorter: { @@ -132,7 +132,7 @@ export default (props: any) => { dataIndex: 'Lag', key: 'Lag', render: (v: any, record: any) => { - return record?.latestMetrics?.metrics?.Lag; + return record?.latestMetrics?.metrics?.Lag.toLocaleString(); }, sorter: true, // sorter: { diff --git a/km-console/packages/layout-clusters-fe/src/pages/Consumers/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/Consumers/index.tsx index 4e06d92a..53c0f02c 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Consumers/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Consumers/index.tsx @@ -108,11 +108,13 @@ const AutoPage = (props: any) => { title: 'Max Lag', dataIndex: 'maxLag', key: 'maxLag', + render: (t: number) => (t ? t.toLocaleString() : '-'), }, { title: 'Member数', dataIndex: 'memberCount', key: 'memberCount', + render: (t: number) => (t ? t.toLocaleString() : '-'), }, ]; diff --git a/km-console/packages/layout-clusters-fe/src/pages/Jobs/ExpandedRow.tsx b/km-console/packages/layout-clusters-fe/src/pages/Jobs/ExpandedRow.tsx index 399be7a7..4de68b47 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Jobs/ExpandedRow.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Jobs/ExpandedRow.tsx @@ -153,6 +153,7 @@ export const ExpandedRow: any = ({ record, data, loading }: any) => {
          Github: - 5K + 5.4K + Star的项目 Know Streaming
          From afda292796f6c39ec05625f70f60a703a8c7e46f Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Fri, 21 Oct 2022 11:45:12 +0800 Subject: [PATCH 143/145] =?UTF-8?q?fix:=20typescript=20=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-console/packages/config-manager-fe/package-lock.json | 6 +++--- km-console/packages/config-manager-fe/package.json | 2 +- km-console/packages/layout-clusters-fe/package-lock.json | 6 +++--- km-console/packages/layout-clusters-fe/package.json | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/km-console/packages/config-manager-fe/package-lock.json b/km-console/packages/config-manager-fe/package-lock.json index bf0a4f18..08574fb2 100644 --- a/km-console/packages/config-manager-fe/package-lock.json +++ b/km-console/packages/config-manager-fe/package-lock.json @@ -12241,9 +12241,9 @@ "dev": true }, "typescript": { - "version": "3.9.10", - "resolved": "https://registry.npmmirror.com/typescript/-/typescript-3.9.10.tgz", - "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "version": "4.6.4", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", "dev": true }, "unbox-primitive": { diff --git a/km-console/packages/config-manager-fe/package.json b/km-console/packages/config-manager-fe/package.json index 945e8b5c..013ffec0 100644 --- a/km-console/packages/config-manager-fe/package.json +++ b/km-console/packages/config-manager-fe/package.json @@ -95,7 +95,7 @@ "react-router-dom": "5.2.1", "stats-webpack-plugin": "^0.7.0", "ts-loader": "^8.0.11", - "typescript": "^3.5.3", + "typescript": "4.6.4", "webpack": "^4.40.0", "webpack-bundle-analyzer": "^4.5.0", "webpack-cli": "^3.2.3", diff --git a/km-console/packages/layout-clusters-fe/package-lock.json b/km-console/packages/layout-clusters-fe/package-lock.json index 307d3d6e..dfb11c4b 100644 --- a/km-console/packages/layout-clusters-fe/package-lock.json +++ b/km-console/packages/layout-clusters-fe/package-lock.json @@ -13341,9 +13341,9 @@ "dev": true }, "typescript": { - "version": "3.9.10", - "resolved": "https://registry.npmmirror.com/typescript/-/typescript-3.9.10.tgz", - "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "version": "4.6.4", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", "dev": true }, "ua-parser-js": { diff --git a/km-console/packages/layout-clusters-fe/package.json b/km-console/packages/layout-clusters-fe/package.json index 732d9c7f..cee05daa 100644 --- a/km-console/packages/layout-clusters-fe/package.json +++ b/km-console/packages/layout-clusters-fe/package.json @@ -111,7 +111,7 @@ "react-refresh": "^0.10.0", "react-router-dom": "5.2.1", "ts-loader": "^8.0.11", - "typescript": "^3.8.2", + "typescript": "4.6.4", "webpack": "^4.40.0", "webpack-cli": "^3.2.3", "webpack-dev-server": "^3.2.1", From c1502152c034dbbbf6ff99225131ff5aac41e0eb Mon Sep 17 00:00:00 2001 From: zengqiao Date: Fri, 21 Oct 2022 14:59:42 +0800 Subject: [PATCH 144/145] Revert "bump version to 3.1.0" This reverts commit 7b5c2d80 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a168b74c..8a810fa4 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ - 3.1.0 + 3.0.0 8 8 From a96853db90f6aa9842b49ab326c24c8af6462317 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Fri, 21 Oct 2022 15:02:09 +0800 Subject: [PATCH 145/145] bump version to v3.0.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a810fa4..060523b5 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ - 3.0.0 + 3.0.1 8 8