From 0e008d012b70153dd761ed694e9c50feb12b3e67 Mon Sep 17 00:00:00 2001 From: Lucas Rodriguez Date: Fri, 20 Sep 2024 17:02:46 +0000 Subject: [PATCH 1/2] HLD for Redis Client Manager --- doc/mgmt/images/rcm_client.png | Bin 0 -> 18118 bytes doc/mgmt/images/rcm_init.png | Bin 0 -> 16021 bytes doc/mgmt/images/rcm_transactional_client.png | Bin 0 -> 17898 bytes doc/mgmt/redis_client_manager.md | 176 +++++++++++++++++++ 4 files changed, 176 insertions(+) create mode 100644 doc/mgmt/images/rcm_client.png create mode 100644 doc/mgmt/images/rcm_init.png create mode 100644 doc/mgmt/images/rcm_transactional_client.png create mode 100644 doc/mgmt/redis_client_manager.md diff --git a/doc/mgmt/images/rcm_client.png b/doc/mgmt/images/rcm_client.png new file mode 100644 index 0000000000000000000000000000000000000000..850c902609ef17f36d0a6df51c24ecc05f0d3b74 GIT binary patch literal 18118 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 z zfx73-^0yzHpH&Bv$2o20-ohZDq3l2Y21<;kx2NmUi42Jx$i#b$brO};cxaRW4)a4S zpI@)uri;+NHD{zpvy9;0i^l8WS|e)U+~O{RHJ#$8)2-ET5;J+lE(+CKMF>!?`NKnJ z&$pH>8i+KMYa!VECtr^IA;4TAo8;qQ9CeIL9Duhnw8*489MqENTmJS0j&qShn7Wx} z-yXWyV9ywj?hcRN;Q_#tD(#+b%OmYKD;{&LZZ%Go{^>%$p^#5l*`QQ~rOwAK2N=Fi zbsDBEZ4beKbS&4K6N7=zZ0_(WM6m%lX2D@L`Ep52DVaN;!(lgGAth-Tofa2nvrXZ4*5j%}X>VjQC6VZDY83XVngGueO?OLCn)v(9k!C92c+cv>Uldr>4MZ z;FpRB4U2eoMDw0xAD;Pjvv?@x?OFhOL^1qvT&M6WZfJ>8t*rxCo^)Z#-xE1viOp<$v0gjg9qbjP5UD7T@QX0p8nOd$Il=>Zb<+Xr!OkmgJ0%~PKR~m)7r~ko9Slk*xa>5HBDkY1jY|WcvIye~!hFGcz%SB7OSPZzPq==vi;;cVC zKm1cLsICSS+2=3!&<~3o(ZG>X?hB_^^c9tuF&KFOVuDYLEESWo!=O=|4WNGo7OXro zgZc8Ksa$F_GI-Kt*npZS?*)>V5h*i3=mZ2aT{lA65JL4cwV@~I?+478Crsp*BkWA4^G2Xvesi=5*konEb=GSRft7d(X0 zSgOSNg^1Gz=Tl!ZpeqMa)4TyrNh_4mAN;?qdd)V#8?>WJwo6(*%?f z0I%s07=HqAb9(Q`6>dQFYeRpV{R$sxA8OZOgl$4o`wKI4m7@9PJddp3S4K&>4*_4g zlN8vK4_zSNSgYGb0&=9;(y%N-=#UqwYQYD$^Y1AWtMkMAGfsYLfNM?k8kUKpsuFL~ zesc(5Ub?e9vV#Cp8fLfLOz+`fzBDSkUN>tf2H@XJb=?1UM$?Agc0E5m;Cuptff`JX zq+Sz1!`^)fv2Zl|LutR#I%HEg(+#-5pG1bnecY|kLl!MR*?9m>`6}GaI8n{k?hIJ; zvO_}i*qTew@4BTPQqF2DiLtZy){L3L=Bk_Nd|xC#x*kl^Z*$P-vnagu7CXhV;>i-4X3 z?Q?YQDK6{3bZxeGT^QGVUv^ObVo%KjIOPO|Vtigckii544nX^-xF3#~A^mn~C%IS< zY|;cp)l2}+RyJZ&;g2rjSD~HOEV+>j;E9VL5t!`;j+77Sc)6fY0_y|W^=SK&qi_ZMgyKrUMP`J z+Pw7_(CqP1SWSr)*2%&FNKa3fzpau3Hpo2%HH}zjfwH3e+?~~Ih{bMb(%#5)Fm$1!Lycs`!>)9hGzYkt`oQK1p-cDAq5 z;UeL(N~m^L@t$z4^w*ib8V!aNv5xbW4aTYf+NN%Zy8L#F&b_Ha`()R_Ddx(*+Sedy zaG)pY(i8tk3{X-33U44WLLuf?ZyIS;&Jm^A!h2>i^OQ$(svC|q%)!KZ8S=m0&GbMc z7H~nCA(~1P2PUyu@-4{zjTw~Kaq?@>>+TLjPE@mP2U-9c)bUHSD*6BjFA?xy9(nqB zy~eh{wG4Qo8IYi55w(q0E|JH5MDR>YIpG; z(z&dY>X5CB_oso?=hfnA6keO90$#-$lp4+1A4RP8w^Kq=GS_jl4}Qy-G@gT=%z~)- zPF9wWUawDVd(X>FFe&dAzf=S`q%W!2J7sq-j<+Y*WCDgjI&pMc7v28odAz{2?eEf* zp-9tv={FQTNNSLsM{)Ye8FX*ou|U z_{r~nK-@&T2V5zsSPF@RV`UU{Ox~}1ZvnJAS6^iClni{go)G?X3!At}za0n$#LXxG z7l>AAo-zCC^9?{KD~JOTjVO;ms*xVj`ZlJXGFbY<#mM`iZB>+=x7nbe0Ub21#42I8 zjCE!c$KMg5pw}Xt_&FfUd+=^XG!k5D585=^le3p zCKVJRwNT#uU*KWa0Z zZFOS&Z+5fg#9Kw|K@+bsGo!O;)hN@&ae84ETZ7#)_O)-ng9nT=>IZf;x^HDbaU2n7 zj?e_wi6I03`VIvW5>V@`p@+g}hiZpJa#zSX0TashSL~opL;zURaD$13+u@MYZ*e*9 zjARQG1)@9)F}(MmP=JE;PBG=mlQ@f#l%gnfRzP(s0D13BG9M3gw`^Rs1QLrGiBqCcf^ z+a|=zo1LbJkV2f4OPQz{44P|&;0^2~KKScrOeW?kjN!|Czx3!W) zgduwx%i)rQ{pj4jSI{cnZQIKJHKG2I&8pHp}=q9P(t zC(tUgw`XZyubnhBaAt$z2$Z`v;sTYG6K~6RsWZ38+vX97tCk9O-9E@%v z5+}D!T^9jvBP+A$rzsAg22@&S!WPvD1i6XvU$>A{;5Xkq0$Cgo1K@L*Dbr-S8vO1k zrS~N{Ry6e3?)rLYzSAcdw8A`$(sEe~B(Y{Lf6Ip}fCNq(fE~85Dd#79Is+%rYyIvn zc1@>?RAL6Bfsm@w>jxC-PQ&4Gcek6B7DHI0-RO|xRN0*uEmYjP{!5*GMrE-4WIFS7KX*-%kuy`q+vG9;eHeq0-)F4A^wcQJ7`$C%~Ero(%9kz#X zw#|0?Nj&87DL=9$`#$cOjb{>bFzT0TvwwO2&C%|l3&|-ZnW%KFZ_OQ?V2%f8o*2sPP_@c=c{Ni*AKGmc#w{sO24bhILo0uW6Gzq2Ud(Gt~)mYtLXOW>3hXJWR& zg-ThPESz!M5R@Iv7<0C2YZ01EGmrGvRQ4ZA#tXHdhx}iF$d>%u$r2uqT{BCgmVyhtKx8=kYp{O!Xq(`VjK()LS@e#6PE!GT>sr(Biup=PN;%R3HwIzgurePe0?-K`n@ zf5wfVp}Daz9L7rL2Th_6uAqI6pJH92a1O?+;I>1|$~Kq>bc%18{VG$8k=%!;!e9{R_LPS^|=Vg@bN;`lkbGFb*{OLC3qu~?+ZK@ZGW!u z*`wu|$$J+R$k&OJ43E?8Tl|3=ZSQRj!8zj)&=7`{1#6aQ1y2iOg*HkT#_ipMQKe0n zZ0q#JzxRj%sMXVE_p?){Ljr=a6~-&Zqm4q#nZnl_7twi>J9pf4y0w-QAIz@0PWL_* zX;yGpak=ta3fL*RK3v;I;BgY@{4wu+KMwm%E)xKk;FF*0VV{KDkY(a&99yDA%U>F% zcGr5I)ht)*y_D-&3|m7)0uXW+2{V)%wR5s<*d{w*>upz}&Wz-H^t@Kk+~cTdxZ$G( zV__ooK8V$lW5&#Gps(WjF3cQe1HK5XH)Q}?eONR2>du7;haBv4%4tmSPT|z>-*b^h znWAzFRe=u|aSEwIbRY9w<^HxIerBW7J%6h3><8m`z)W|aa}7_}Po#kh%_09_>tEVo z)TEU91?)Qr*(eO)lxYO7N#+Ad?7yNmlF7g2@#A9rYjWqWvA58q2mSH$=4R6O8Bgdl zT^zO2J7rzTs5GFpU2C$$z#iq+GQ0WCcdI2(Qbdw)!tEaQ<+z6QR%V!^Q2uOxJ%Ior?cr7LTH`1pSK)yV`^Z4e1Fj*xdJc zw?=h9+e3*LE$_|)E(Z$(-U7!utWvN!LxuNsWS4b^|?%&*$ujVnPqShW2E7Nc_|F5Y<;_*M_N zKK-*kb23_)TIb;urpy%ZAbDEF`~Ljz=H`9x>f~1}sLs^%?lBMBv$dT$(g2LNWG06l z0Y|}z|4`x+ZjDNwRIbP{Kiwl0t?*;d(KpT%6rIy!im&@eFAn49+ry5}J36(Y8y|mq z2cVIes9%)haqLa`CSmW>_&WKVe5Yr3y~tYuW2dM*QJ>EIOp#6@Lj@kZ?bu_AM-%zc z*b?SIa~{15KZ?J+8Q`y-kKfIay2*T|1_6NyrhbbL{&)kj=XuXRd3_?s2>~&T`2rZ# zpVI3*a0YOv%jowXFKgGmEyhBgvEE36%sbn3S}f>%pG~g?3f`!L)EvYkE2sR1&>q(@-g zanj}_fEMFeOr#1(OtPp2d<}AzvLX(^h92Jf3qq~$M43_HCQ`j8^VPAT25bkPz6(N^ zl@C7sX9I`$xd0tnY+zV`sqf#5;Bx9*&_URHGgIu&7>oluUtnykF3>19!QZ}ymtE)C z#SXQ;7n@ZD_T7tL&3^sAUa}iUuoFY<*<;Lje3tYBh4-@kVU^3w{fle=`%G?8{m)cU zsfy<;dO4g!>P$~cs$3Zj9MV*_`huz9Gr(&o;o6aD{)bH-C82hk{$8QC!hr`^C0C#) z+lQ46xB6q~6Zu(S+ip$v{p8~AnP7a^eP5Lz)KNFBFLv+jz9U$vT(1s%-sD+;Q@lr> zM;b!w6ON~lfpwTz!aMjrQe0gaYcZ|?whZ-7{ycfS)~@A8aaAM9I~b!Z5?*L%!F%i7;v*89lI^5vKHTzv>SFXc4^)sf8@5j$2Nd~aOq zqm^~cS0SczbN5)AmdwGCtiy0mdXHUL{JD(IcY&02J7?liIdshu-wNOLLF5b@suWbr zeAR_PsEeUtEBnD#H_tn!l+JhMdvAPQ11YTivEE@tBc7G*aEC|x->a-K--U-Mp{#@V zj4!hf2r@R!ilF>Iy1@tZzPjueo-rD`LnQ(Aw3u4StIUw1d$A{#5INB1Cbkwq6+L<` zLvtp2x+iUSp_le%4NkGr5e2X#w0$^tET~aibtA0uVSnRyO>vz?8MXt2!5K&qM3eZJ z%fFd&ch3r_6~Wz=YCr^~m66{Jg5Fc$6u;r2a-LxWm5;zBsICoKw|iu}C;9+&MT)gh zQhGAO4X3<#E7&j68Y$-{iJm8r%D$4-R%{-8`M5<0EHII! zwRYQ={-Nb1b5r}^_b(xB3KtV4VhdH_WO(!Gwek#i-!oL=$0?5x3$i6WR&th?JNIL* zbA&-VNYOFay&c1?oyOxCV&S*2}N0e1$$Oo($kb^ zrTt>Zczj-Frb!pfdEh(@5O4}POr&ksBDY`dy~_Lfd^_k6=&~X9v@}3U)$%5Lw?|*U z&E)vYmK{(c^0sW9!RoP0pOboSXHH>4wr)wXX_3ddjEX6}dZ)bqS>s1&9;xSC zd^OR}LRb^XQUNr1h1WV+)RM5ByZlyxaGVr;`S&oyzOnnF>jsgx^Nl7p)Ok5e7solH z;93f5Tk?D_w$aOjeAF~TU7l&?DL4X}?8jfOf)wGB2`pBnf)-NpNz5BkK?f?dEsNQp zh2?;=1mGnz^RDWv*`x<7ox9Lv8SuIiFmWb;i9?n&h*Sn_)n{hY{}{Pf3tNd`Dd@AO zOYv%S#keKGDEK)i@N+QJ#J`+T05Y4%^oVd1y3fYw6YkFwbpR~`#~_;s2p)&%GHNA4 zk$~zU9?;y;j|*7eVO*=vbiRKt!&&kHyXmjOLwN)~2vX${d)6`NP=xX~7+`GFG(SAO@82`HeqjH|QDEIEz@CTwmp!jS_+KxXv=8>? ztP~DXc$`lCYGcR%_!Xi7lK(gtw_i`zdk;GT!1I~F)z=)5I1HN}@T`oKUBKJ)e^)ue24`hmF1iJ8ZUj^tg?!by9!ikhDJIGU>^#3n+ z`B-I(yQ7#EeX{I+n+)o#HXnA_zjmuVnE3OLGh$EJk7fL(M~c)t0*I>aGNgIH2}BRA zSMWg*#J&l?RPPNyl9$oY%Qbd7&1_!T1UjI00#Ykb6giWXP_B}7>zHE8^#Qu(>j^qu z>WOW2JNAI@Uwa?^F6&KfMzZ|Z7W6w@h}#6(fd;;y+vGK$s;@Ym7?iKhZ!ntg!%egJ^UczoOhM)GftwAi!d^$G40(JJ!vc1eH=r8N{* z2>%>W*V!(LHq1erg3LjPLWzhAZeP_*Jd%J5!ck(4etLg(xOcN6;Oes{Fp#tv>x!d!$h4NuV5A0bwC9;i}N{vwzNy>QTbln`d_`^zOTQ6*OBTheaQi*zK| zO32!_EVx!Hzn0M%YU;D`v_hKmfO-8*!g zSw3g@470y{t?C}LCXg5?lc@+6eDIts#>0W*!t0wZ!zs(MIi8FE98Ey7ZK*|Tgvy_? z`bApvkbjz^x;!|;e0?~=Ns!{D-{Qz+csz>?WP!*FQHxlHyx+iCSENzZ7~3$ZkvCf| zM|12b(Ii1d$qVGUHZl#SsK1`$`#nSDEXs4e7OzF-*~LNmRP0sk(y0vWhDVnW)j}C! z_4TFny<}3K-t_&8xAXNdNZ535Il^9_#vJ!?g&aLoAiYCeHXMMfPVqBX{6^`rg`E&d z7Yrc5f%^B$Ex-rou$Xr+Y%YvybNaBKtb$Xy+*sB`u5Wp5=PJRgqiF#f z=HWTAqeBB3{~URYQGZ1tT$A)v8)+I3HtK%d47&1iV8gFOu z1ZF>2M9jTUtD!+-S%T3sjDI)!=Y{h`o5C!oD^;XtIMqS$=7mjV5=QGk7*75?Cf9yY%F+*Jr;Ax030KK#5 zH~IqQhJ{J=pd>!$gXw`JX2LjHB|A$Y-OUYToiqTt;obt?9MyW3WljQMw@R(0iutH{ z^Vglol$BODtn&yUMejWbk!Lm9=n2I!8hD>;!KMMaV&b(0UUkMmivZvw2h+?QcsaHR zRJ|AeIx_(;$Nu}{|K`d6dxZ#51C^-%@&_#6V!g?$8UfFSDI5Sq^zwKS7bq!7`U5U@ n^(N7G6?k?SmFOgn~p literal 0 HcmV?d00001 diff --git a/doc/mgmt/images/rcm_init.png b/doc/mgmt/images/rcm_init.png new file mode 100644 index 0000000000000000000000000000000000000000..f70aef32c6075a7912794df1b4aca6600a83f6af GIT binary patch literal 16021 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 K5*1>`AN~(&w8`TD literal 0 HcmV?d00001 diff --git a/doc/mgmt/redis_client_manager.md b/doc/mgmt/redis_client_manager.md new file mode 100644 index 0000000000..b8592bbdf8 --- /dev/null +++ b/doc/mgmt/redis_client_manager.md @@ -0,0 +1,176 @@ +# Redis Client Manager \(RCM\) HLD # + +## Table of Contents +- [Table of Contents](#table-of-contents) +- [Revision](#revision) +- [Scope](#scope) +- [Definition/Abbreviation](#definitionsabbreviations) +- [Overview](#overview) +- [Requirements](#requirements) +- [Architecture Design](#architecture-design) +- [High Level Design](#high-level-design) +- [SAI API](#sai-api) +- [Configuration and Management](#configuration-and-management) +- [Warmboot and Fastboot Design Impact](#warmboot-and-fastboot-design-impact) +- [Memory Consumption](#memory-consumption) +- [Restrictions/Limitations](#restrictionslimitations) +- [Testing Requirements/Design](#testing-requirementsdesign) +- [Open/Action items - if any](#openaction-items---if-any) + +### Revision +| Rev | Rev Date | Author(s) | Change Description | +|------|------------|--------------------|--------------------| +| v0.1 | 09/13/2024 | Lucas Rodriguez (Google) | Initial version | + +### Scope + +This document describes the high-level design using Redis connection pools to connect to Redis from within sonic-mgmt-common. It describes the singleton object that manages these connections and the integration of these connection pools into the existing framework. + +### Definitions/Abbreviations + +- Redis: An open-source, in-memory data store that's used as a cache, database, and message broker. +- RCM: Redis Client Manager. +- Redis Client: A type defined in go-redis that is used to interact with the Redis databases. +- Redis Transaction: The execution of a group of Redis commands in a single step. +- go-redis: The [Redis API](https://pkg.go.dev/github.com/go-redis/redis/v8) used in sonic-mgmt-common. +- RPC: Remote Procedure Call, used to interface with sonic-mgmt-common. +- CVL: [Config Validation Library](https://github.com/sonic-net/SONiC/blob/master/doc/mgmt/Management%20Framework.md#3228-config-validation-library-cvl) + +### Overview + +The translib framework that lives in sonic-mgmt-common is responsible for carrying out various config and telemetry related tasks, such as serving gNMI GETs, SETs, and SUBSCRIBEs. In order to do this, translib creates and uses many Redis Clients to read/write the Redis databases. Redis Clients support connection pooling, which consists of keeping a pool of active connections that can be used instead of creating a new one each time one is needed. Connection pools significantly reduce the number of connections made to Redis and reduce stress on the Redis TCP/Unix sockets. Since the connection pools are held and managed by a Redis Client object, these Redis Client objects must be reused instead of being closed after each use. + +### Requirements + +- Redis Clients with a connection pool must be reused wherever possible instead of creating a new Redis Client each time one is needed, within sonic-mgmt-common. +- Transactional Redis operations must be handled correctly. Connection pools do not support transactions. +- The number of Redis Clients and connections to Redis must be tracked for the life of the server. + +### Architecture Design + +This design does not change the existing SONiC Architecture. This design adds a new API that is meant to be a replacement for redis.NewClient and redis.Close. + +### High-Level Design + +This design introduces a new API that manages all Redis connections within sonic-mgmt-common called Redis Client Manager (RCM). With a central manager, Redis Clients can be kept open after an RPC completes, reused, and usage statistics can be tracked. This will also abstract most of the Redis logic away from the user and avoid misuse of the go-redis library. Since the RCM will be the only place in sonic-mgmt-common where new Redis Clients are created, any client/connection creation failure can be exposed here. By pinging a newly created client, UMF can identify and log any connection failures. + +The new API will expose four new functions that will replace [redis.NewClient](https://pkg.go.dev/github.com/go-redis/redis/v8#NewClient) and [redis.Close](https://pkg.go.dev/github.com/go-redis/redis/v8#Client.Close). + +#### RedisClient(db DBNum) + +This RedisClient function takes in a database number, defined in [db.go](https://github.com/sonic-net/sonic-mgmt-common/blob/master/translib/db/db.go#L136), and returns an existing Redis Client to the caller. This Redis Client can be shared across multiple goroutines and has a connection pool. It cannot be used for [Transactional Redis Operations](https://redis.io/docs/latest/develop/interact/transactions/) (such as MULTI, EXEC, PSUBSCRIBE, etc...). + +This function is implemented using a cache of Redis Clients that are initialized during the Go init process. One client is created for each DBNum and stored in a map. Initially, each Redis Client will only have 1 active connection in the connection pool but the number of connections in the pool can grow up to a specified max number of connections as needed. The max pool size is set to 20, and the rest of the Redis options are taken from the [existing API](https://github.com/sonic-net/sonic-mgmt-common/blob/master/translib/db/db_redis_opts.go) for these options. This init process looks like this: + +![RCM Init](images/rcm_init.png) + +When a Redis Client is requested through this new function, the Redis Client is taken from the cache and returned to the caller. Multiple callers can use a given Redis Client at a time and the number of connections in the pool will increase to satisfy simulatenous Redis operations through the same client. All of the connection pool management is handled by go-redis, with more details [here](https://pkg.go.dev/github.com/go-redis/redis/v8#Options). This process looks like this: + +![RCM Clients](images/rcm_client.png) + +#### TransactionalRedisClient(db DBNum) + +The TransactionalRedisClient function takes in a database number, defined in [db.go](https://github.com/sonic-net/sonic-mgmt-common/blob/master/translib/db/db.go#L136), creates a new Redis Client for that database with a PoolSize of 1, and returns it to the caller. This Redis Client is not shared with any other client and it can be used for [Transactional Redis Operations](https://redis.io/docs/latest/develop/interact/transactions/) (such as MULTI, EXEC, PSUBSCRIBE, etc...). This client must be closed after it is done being used, by calling CloseRedisClient. + +No initialization is required to support this function. A new client is created using redis.NewClient when this function is called. This process looks like this: + +![RCM Transactional Client](images/rcm_transactional_client.png) + +#### TransactionalRedisClientWithOpts(opts *redis.Options) + +The TransactionalRedisClientWithOpts function takes in [redis.Options](https://pkg.go.dev/github.com/go-redis/redis/v8#Options) struct, creates a new Redis Client with those options and a PoolSize of 1, and returns it to the caller. This Redis Client is not shared with any other client and it can be used for [Transactional Redis Operations](https://redis.io/docs/latest/develop/interact/transactions/) (such as MULTI, EXEC, PSUBSCRIBE, etc...). This client must be closed after it is done being used, by calling CloseRedisClient. The purpose of this function is to provide a more custom client to the caller if necessary. + +The implementation of this function is very similar to TransactionalRedisClient. + +#### CloseRedisClient(client *redis.Client) + +The CloseRedisClient function takes in a [redis.Client](https://pkg.go.dev/github.com/go-redis/redis/v8#Client) object and closes the client if necessary. For shared Redis Clients that use a connection pool, this function is a no-op because those clients must stay open. For unique Redis Clients fetched with TransactionalRedisClient or TransactionalRedisClientWithOpts, this function will close the client. This is necessary to prevent a leak of these clients. + +The function is implemented by calling [redis.Close](https://pkg.go.dev/github.com/go-redis/redis/v8#Client.Close) on the client if the pool size of that Client is equal to 1. + +#### Counters + +RCM keeps counters for the number of requests for Redis Clients. The counters are updated on calls to the functions described above. This is why it is important to refactor all call sites to use these new functions. The counters include: +- curTransactionalClients: The number of active transactional clients that were provided by RCM. +- totalPoolClientsRequested: The number of pool clients that were requested through RCM. +- totalTransactionalClientsRequested: The number of transactional clients that were requested through RCM. + +Additionally go-redis has internal counters for Connection Pools that can be accessed for each Redis Client in the cache. More details are provided [here](https://pkg.go.dev/github.com/go-redis/redis/v8@v8.11.5/internal/pool#Stats). + +The counters can be fetched through another function provided by RCM, called RedisClientManagerCounters(). + +#### Command Line Flag + +The connection pools feature can be disabled through a new boolean command line flag: "use_connection_pools" + +This flag is set to true by default, enabling connection pools. + +When "use_connection_pools" is false, all calls to RedisClient() will just call TransactionalRedisClient(). This will return a unique Redis Client to each caller and bypass the pool feature completely. + +#### Refactoring Callsites + +In all places where a Redis Client is not used to perform a transactional operation, the call will be refactored to use RedisClient(). This will result in the caller now using a shared Redis Client with a connection pool. This will significantly reduce the number of new Redis Clients and connections to Redis. + +In all places where a transactional operation is performed, the call will be refactored to use TransactionalRedisClient(). This will give the caller a new Redis Client that is unique. If more options need to be specified, the call will be refactored to use TransactionalRedisClientWithOpts(). + +All calls to redis.Close() will be replaced with calls to CloseRedisClient(). This will ensure that Redis Clients that use connection pools are not closed. + +### SAI API + +This HLD does not include any changes to the SAI API. + +### Configuration and Management +Although this change interacts with configuration and management, it should be a transparent change. There is no change in functionality. The purpose of this HLD is to reduce the stress of configuration and management on Redis. + +#### CLI/YANG model Enhancements + +This HLD does not include any changes to CLI or YANG models. + +#### Config DB Enhancements + +This HLD does not include any changes to the Config DB. + +### Warmboot and Fastboot Design Impact + +This HLD does not have any implications on Warmboot/Fastboot. + +### Memory Consumption + +Increased memory usage from this HLD should be minimal. Increased memory comes from the 10 (DBNum) Redis pool clients that are created during initialization and stay open for the life of the server. There are also new counters that are being introduced that live in memory. + +### Restrictions/Limitations + +RCM lives in the translib/db package. This package imports CVL, so refactoring calls in CVL to use RCM would create a circular dependency. + +### Testing Requirements/Design + +Unit tests are implemented to test RCM's functionality. Since callsites are updated to use RCM, many existing tests provide additional coverage for this feature. + +#### Unit Test cases + +- TestCreateRedisClient + - Tests the internal RCM function that creates new Redis Clients. +- TestRedisClient + - Tests the exposed RCM function that returns a Redis Client with a connection pool, given a DBNum. +- TestTransactionalRedisClient + - Tests the exposed RCM function that returns a new Redis Client, given a DBNum. +- TestTransactionalRedisClientWithOpts + - Tests the exposed RCM function that returns a new Redis Client, given a redis.Options object. +- TestCloseRedisClient + - Tests the exposed RCM function that closes the given Redis Client, if necessary. +- TestIsTransactionalClient + - Tests the function that returns whether or not a given Redis Client is a transactional one or not. +- TestConnectionPoolDisable + - Tests the command line flag that can be used to enable/disable Redis connection pools. +- TestNilRCM + - Tests the scenario where RCM is nil or never intialized. +- TestRedisCounters + - Tests that the RCM counters are updated correctly given different scenarios. +- TestRedisClientManagerCounters + - Tests the exposed RCM function that returns the counters held by RCM. +- TestRedisClientPoolExhaustion + - Tests the scenario where more requests than connections in a given Redis Client's connection pool are received. + +### Open/Action items - if any + +RCM can be used across other Go repositories, such as sonic-gnmi and sonic-mgmt-framework. This will further reduce the stress on Redis from those repositories. From 9135500ad1ec26d18686a1de31e1bbab3830af83 Mon Sep 17 00:00:00 2001 From: Lucas Rodriguez Date: Fri, 20 Sep 2024 17:02:46 +0000 Subject: [PATCH 2/2] HLD for Redis Client Manager --- doc/mgmt/redis_client_manager.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/doc/mgmt/redis_client_manager.md b/doc/mgmt/redis_client_manager.md index b8592bbdf8..329057c75b 100644 --- a/doc/mgmt/redis_client_manager.md +++ b/doc/mgmt/redis_client_manager.md @@ -70,7 +70,7 @@ When a Redis Client is requested through this new function, the Redis Client is #### TransactionalRedisClient(db DBNum) -The TransactionalRedisClient function takes in a database number, defined in [db.go](https://github.com/sonic-net/sonic-mgmt-common/blob/master/translib/db/db.go#L136), creates a new Redis Client for that database with a PoolSize of 1, and returns it to the caller. This Redis Client is not shared with any other client and it can be used for [Transactional Redis Operations](https://redis.io/docs/latest/develop/interact/transactions/) (such as MULTI, EXEC, PSUBSCRIBE, etc...). This client must be closed after it is done being used, by calling CloseRedisClient. +The TransactionalRedisClient function takes in a database number, defined in [db.go](https://github.com/sonic-net/sonic-mgmt-common/blob/master/translib/db/db.go#L136), creates a new Redis Client for that database with a PoolSize of 1, and returns it to the caller. This Redis Client is not shared with any other client and it can be used for [Transactional Redis Operations](https://redis.io/docs/latest/develop/interact/transactions/) (such as MULTI, EXEC, PSUBSCRIBE, etc...). This client must be closed after it is done being used, by calling CloseRedisClient. The Redis Options that are used to create the client will be fetched using the existing [adjustRedisOpts()](https://github.com/sonic-net/sonic-mgmt-common/blob/master/translib/db/db_redis_opts.go#L80) API. No initialization is required to support this function. A new client is created using redis.NewClient when this function is called. This process looks like this: @@ -97,7 +97,7 @@ RCM keeps counters for the number of requests for Redis Clients. The counters ar Additionally go-redis has internal counters for Connection Pools that can be accessed for each Redis Client in the cache. More details are provided [here](https://pkg.go.dev/github.com/go-redis/redis/v8@v8.11.5/internal/pool#Stats). -The counters can be fetched through another function provided by RCM, called RedisClientManagerCounters(). +The counters will be managed by RCM and exported through the existing [DBStats](https://github.com/sonic-net/sonic-mgmt-common/blob/master/translib/db/db_stats.go) API. This will require modifications to the existing API to integrate these new counters. #### Command Line Flag @@ -113,6 +113,29 @@ In all places where a Redis Client is not used to perform a transactional operat In all places where a transactional operation is performed, the call will be refactored to use TransactionalRedisClient(). This will give the caller a new Redis Client that is unique. If more options need to be specified, the call will be refactored to use TransactionalRedisClientWithOpts(). +The calls to redis.NewClient() that will be refactored are: +- [db.go:401](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/db/db.go#L401): RedisClient or TransactionalRedisClient depending on the value of the `TransactionsRequired` option. +- [db_lock.go:268](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/db/db_lock.go#L268): TransactionalRedisClient +- [db_stats.go:538](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/db/db_stats.go#L538): TransactionalRedisClient +- [] + +Since calls to [NewDB()](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/db/db.go#L388) will need to result in using a pool or transactional Redis Client, the caller will need to specify which one is needed. A new DB [Option](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/db/db.go#L164) is being introduced, called `TrasactionsRequired`. If a transactional Redis Client is needed, the caller of NewDB() needs to pass this option in, otherwise a pool client will be used. + +All the calls to NewDB() and their corresponding `TransactionsRequired` value are: +- [cs.go:183](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/cs/cs.go#L183): TrasactionsRequired=`true` +- [cs_getdb.go:49](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/cs/cs_getdb.go#L49): TrasactionsRequired=`true` +- [db/subscribe.go:145](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/db/subscribe.go#L145): TransactionsRequired=`true` +- [subscribe.go:176](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/subscribe.go#L176): TransactionsRequired=`true` +- [subscribe.go:223](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/subscribe.go#L223): TransactionsRequired=`false` +- [subscribe.go:275](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/subscribe.go#L275): TransactionsRequired=`false` +- [subscribe.go:467](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/subscribe.go#L467): TransactionsRequired=`true` +- [translib:go:179](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/translib.go#L179): TransactionsRequired=`true` +- [translib.go:252](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/translib.go#L252): TransactionsRequired=`true` +- [translib.go:326](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/translib.go#L326): TransactionsRequired=`true` +- [translib.go:399](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/translib.go#L399): TransactionsRequired=`true` +- [translib.go:569](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/translib.go#L569): TransactionsRequired=`true` +- [translib.go:468](https://github.com/sonic-net/sonic-mgmt-common/blob/b91a4df3bd0e4be97e67ab3f27b1826b1713afc5/translib/translib.go#L468): TransactionsRequired=`false` + All calls to redis.Close() will be replaced with calls to CloseRedisClient(). This will ensure that Redis Clients that use connection pools are not closed. ### SAI API