From 463bef34f9836706500fe47033793ac727c861f7 Mon Sep 17 00:00:00 2001 From: Zhang Peng Date: Mon, 13 Jul 2020 17:03:42 +0800 Subject: [PATCH] update docs --- README.md | 11 +- assets/redis/redis.xmind | Bin 693931 -> 584814 bytes docs/.vuepress/config.js | 95 ++------ docs/README.md | 18 +- docs/nosql/redis/README.md | 20 ++ docs/nosql/redis/redis-action.md | 4 +- docs/nosql/redis/redis-cluster.md | 16 +- docs/nosql/redis/redis-interview.md | 319 ++++++++++++++++----------- docs/nosql/redis/redis-ops.md | 13 ++ docs/nosql/redis/redis-pub-sub.md | 23 -- docs/nosql/redis/redis-quickstart.md | 238 ++------------------ 11 files changed, 288 insertions(+), 469 deletions(-) delete mode 100644 docs/nosql/redis/redis-pub-sub.md diff --git a/README.md b/README.md index 18b8725..f736089 100644 --- a/README.md +++ b/README.md @@ -56,16 +56,17 @@ > [Redis](docs/nosql/redis) 📚 +![img](http://dunwu.test.upcdn.net/snap/20200713105627.png) + - [Redis 面试总结](docs/nosql/redis/redis-interview.md) 💯 -- [Redis 入门指南](docs/nosql/redis/redis-quickstart.md) ⚡ +- [Redis 入门指南](docs/nosql/redis/redis-quickstart.md) ⚡ - 关键词:`内存淘汰`、`事件`、`事务`、`管道`、`发布与订阅` - [Redis 数据类型和应用](docs/nosql/redis/redis-datatype.md) - 关键词:`STRING`、`HASH`、`LIST`、`SET`、`ZSET`、`BitMap`、`HyperLogLog`、`Geo` - [Redis 持久化](docs/nosql/redis/redis-persistence.md) - 关键词:`RDB`、`AOF`、`SAVE`、`BGSAVE`、`appendfsync` -- [Redis 复制](docs/nosql/redis/redis-replication.md) - 关键词:`SYNC`、`PSYNC`、`REPLCONF ACK` +- [Redis 复制](docs/nosql/redis/redis-replication.md) - 关键词:`SLAVEOF`、`SYNC`、`PSYNC`、`REPLCONF ACK` - [Redis 哨兵](docs/nosql/redis/redis-sentinel.md) - 关键词:`Sentinel`、`PING`、`INFO`、`Raft` -- [Redis 集群](docs/nosql/redis/redis-cluster.md) - 关键词:`分片`、`虚拟 Hash 槽` -- [Redis 发布与订阅](docs/nosql/redis/redis-pub-sub.md) +- [Redis 集群](docs/nosql/redis/redis-cluster.md) - 关键词:`CLUSTER MEET`、`Hash slot`、`MOVED`、`ASK`、`SLAVEOF no one`、`redis-trib` - [Redis 实战](docs/nosql/redis/redis-action.md) - 关键词:`缓存`、`分布式锁`、`布隆过滤器` -- [Redis 运维](docs/nosql/redis/redis-ops.md) 🔨 +- [Redis 运维](docs/nosql/redis/redis-ops.md) 🔨 - 关键词:`安装`、`命令`、`集群`、`客户端` #### Elasticsearch diff --git a/assets/redis/redis.xmind b/assets/redis/redis.xmind index 5fb92f726adddd35a0626c479dbc7c7331292635..cd8a6823d36a15edfc274037141db3525ecdf771 100644 GIT binary patch delta 10393 zcmZ`f36vDowLLvE)m;saC=ARDJAwj1seJ)vfW#ODR4~RQu2gsJ`_{$2xhp7;LY`ku zgp>Rv--rRXPK-f}NlXk;aLG5(7%(J3{T+8D}!K0H~SkUoV{=vAbg=v`y<{iy<@&CD1dabu5 zm*e1Sqy!IMYxuf^EaBZ@fBQw)aT;J~r` znep!1hk!q?EzTGO$9J{ffif6}V=Te)_nqJN=vT%`Txg}YS zzhXknd~Z?h?Z=9X^4+B9$hz(coN8dY?^h`5ihxUKmZPw9z)Io6TV*@IZBd!5yLc<@D!TR z1qTaNDa0eN=UA};{fN2!#p zb7XSneiPww%j5H6?8Fh>6l?O;D(3~1N(-V*5|O}5W#6&mC7q{0=Vv1D_~zY{6YgCi z6_#yL3^>ojBr?Pt-x3&2V8P*~=*0NY`nCZH;Mn8E3GsS@>B2%=)p1XEtBy|vhUpMI zO|W4le)pqEO%#t_gQQCJ5T3}eQpB^e>~ao9(vjdRR+Tk`8?(V^cuyQ&0YGB@uR0T7z&&qpbO(+ROcwtt9W!ID^-fpCDjfj-&eRY8*lyg zDJ7Ui{e}fQ1yqg~p8`XJ5i#G<%8Vf}m|oTmEHDCzFMnPmu(*t7z9Vei(rC-2RW+hR z8U~=@GqmTEVB(QtLwtAy&|% z*wb5>2cD{+MrK=HQC-_&1l%-u9j7=<m+L9%P;$xafT6W;#A`#M#&Z@Ljp~dDfOcM{r zZD$w8sT!xal?rDmDn+Q0SH>OAl$yN}KmYSH(=aC}NeU{ur8<(Osk(rBuEx?7ZZ;*} zPZe}VmUy^IN^mz|7@o2)#vvq2VycD}Ph2vo!F%yv9_l9`11l&K7>TPD3Z@fbN}e6D zWh};rHAF{z{x25AXUrSXjZ-*9(W-A&D28KfnpH&8b3z4%$61rm!SKjx(~}QtV9S@= zdb%me!dzZ)P2a8f9>*FyQLgYDEFVxxQ$6U3pM3b1t}qg82G=>(jVg|>NTj3*Sk?5Q zkw(Ouf7z2{-!~b8pg9JgG$C|ct#Z01_D=e@+DVgU_RR^ZmL zDa&$!5h+`6ZQH9v1jV_&jftKHdtVZG1L?NplEPP$Fzq5_+7~dg;##=qR{1jTgqBN` zad2oU+FUDJLgdW&ov}SV6s^dxOhS7^jA=)fB$=VhVHy)ODYSJLvM@=UQEKR7EQ32R zAV@*M@UlX&V#ST;?{5~cK|>a0sbd9#Mfqiqsq%PLv~68As#L|QCb>`#)%fsZ=O_Le zIFo_lOl`>9G>A!rO9W* zesf;tVcHZKhvi69w@4?14bgK1LB#aqThN}zk+YLScLluakOD(iJ=PFqhc{G_V2!8@ zmIR;cS|?puSee+h8@C)rjWmIdsuCwlR+S4lOfUocI59~t1;e((VW6r*UukUQ_+hmw z!>LCK6hU>4qX18Z=-Fw}R|F$aBAjw9QiupnqD&Siov7Me_F~w!(s;!gI8brE#t2qK zX%$D1MN1UYCu_HZ_zkI`xQ9R@YRaPSM0!4C^25Y z>ePY!A8d*}l)`hO5B(rxs$)^I9%?G51~lV;Uc_)Pdj&c(t@qs$rSfp{9h{16%J2f7D)$>9L1(~Dq_qchpN7~lA4l|1K2z0f!`Fms$p$8*@!6If0zB2)HU^wI4cU;SSy#n_sDUENhC#@tC^E8L z5w(bmH>{dcU~vYc847ev&ko%s+0`W^#>5{hfG%2HFhdvP_}CuU2)<O{r#C07Y}gK~Ug zusqg@;*J-lq=ly!FdeJxUwCkd4Xi^ z183m+_ze*?L%3 zs}WmISeDUn3SKX&90N0Aa9qfuY5t*ZFoHzj%mC*wctgN+ z3Qw|*5j>;95lX-)6xDx??w4^liMVMzRTN1!If11x%wb7~q+HwOc#{Sb&qlM6WI)D( z?CwU1idM#>s%h#l;cUfStu4)5AZWMekPg_O$UxRv;z zkkmyeAq&CXG;&3H2$oVbT_+=%Nrwz7;CCT;)R8e=P}%{HT6MOb*U-;H5tmv(O*{ zS~qFR2}9W06*&qW)e9+%#hOW=!xwPKRoQ^0>tW=SH31KJi{X4|yvS2mK{vSs{&aqOR~kvYUqQB?-#TCZsx>z=PT!?31vFAW9kZ~lQ3}^nZsdO z5F<`VeVAUcG6Hb%EM$I4A)6Lg(Md)!e1)k%A-GGb7B2U{{q*yH^i?aJG)N0)Mc;)Z zSw*ebWv>bomXr;%UX@vl0=LaZ&dEX~AYsIYyeb6n%|#U4F!0sTFtaK<;E5S?khz&B z$co9az8b*WVO0a!gQ5fyGh;n<80(f=~GArvZm@Y@W$r%JC!UqRW@vz8qIe7a> znni<=rCZuj* zG0c)2!ofwB^{X0I(J?1bEioBU8YHDeznP1CJAP+X30(es@#a#RMI6IXlfbUq(NRA- z;m^eu*bZ16jvN>V_TQWgL6;>{?V$lU%yF_|PXC=ULz8RekQ7dL<| z*#ciX;B6%S@zO@jx3-{4T4Q5XfN-2ANjPXQ;Cox4C|F5jq&%lCE_tE=@BFp+qh?Ti zdgY0_sPBlY>mR^Lhl*mn_`LS`s5m>NN-o#&d}(X)0jFr104;1=4_JS=cuh0cL=XzF zmx~WJuzUOE;`S!A(eW7d#X3UVqBZaL#6Q=bu2YPEwfIRUnZ=2CgWMDEHoi!1ywv<| zooefA#rx`?pcO{n_kuMEx(4SNisB%r*FQ)v81W@ecFNQ{5OFNnH>uDTKjOTfA(I46 zf_b;1UrTc=?(&+^Q|qGfTJNUMi95q@>lX)Ko0xcZu)WalZZP3Cv^PocczRf87F*#h zgBbYj=sFl=L%{fVi{%1?)38qv@u$^wS?`2z*Bk>*`rl&qt_Lpq-{P!n2Zw2n#U0De zNr#a5(q&EX9m^J^sUN@H1P712mzCOh&GOj|e873{7w0G43T%77S-_$d>BTy}V?`r= ze0ar=;50{YBuB-YS7uX6{OrnJgvArZ;!&&4O+pmB|9{0kh?pt6Yt`9Fn1gHoRh*N& z+Y3T0ARd3Vr~={Yrs<9xW2-sm2|vgZ8HL;w|r?gBk+11$_Y8 zmBe`Xsy;io81&}Rx=-G{_SDoTyYgsiKUiTn0=%0?)2|FV!JO6xR_j|)7>DrT3jC(E zA3gm>25p0nyl^xE=d}%D!#AuO`jP*;0SZR9qni?S2$IIYJ?;I3@3q$n0gIr0Y4ogs z|MZ6h4)!AO83LLb3@J3=LX}2>n+_M}fUN~|z}4Wn0-C<>fN8}BT&tM!?F73Uq3;(_ zICv$8`U={Bd>xARW$t>S5!_KiFUzpqQUmt=C3Jp*JraCULgx(X+&2W>lsut=Cxi)N1tbvxD?bCttWPUCveAwR8_2wtP zyokHIB{vPOMqyyy0A*TIGl+t;=d6uJGQcC71}@^2s51HW0k8?NJt zE+2)Ct%0ZWx3%PDC*d=ucK);ZZNvIMjRn(JmB!Y_ztVsJ#%x5#)joK&4*F{APjVNg zQu8bF`73Lmy^-&z z!>uEQabWebQmMA&t^94pLB($0RvHU-tSptJj=M+-zFiO#ttGt0gn&u|1=wX@45W&+KzLP{U`Txo>RMPDe`HG0Oia9$F406 zul>tH+ENiI=!(BWnni1n)&x|8AbpS+%)1_<54{sPXZQd=@RJ1e!+VjtMh<{#H~$_v zYt+Ce@a7@NZ^~h0e)k~AwIEIHW8~}}2&%Po7S5WO?75al41`f~<|0pO8f8f802Q%;yc+|^6DDR08#b;Yn4hiVcJCOLT zuHx5HtswW=K;8Q5f zS@%Fb<5$6Q1nXXX@5O{{*zP2UiWv~P6Fb4a8=!u7K9@fk z%(*u6`GRZVPVdxg2Nu=gGnz?Z#QtE!&tLDz`b^Y+qr2IG90`HcP1p>xrS2RnZt9r>2Ni(-y~=Fuv(|=h3g@cQ&(m{ zSg%vy{scI2YX*cBdpMYOLqF%K_G{0d)(y=MS2O4T{Bee#)b!)dyX%)jo<0L+?licX z$=F{dWDAp{o^T@+d*H>4O>bvmIM8p*j=CJ~w00duK+DF`m%uE$bnY{0CP8H9M9bdWxY;jJKHywCL{{{ECK%Un;9_a9>+$%CsBvIPm7n>Il#Evro8nuZ!ez23*bbFJF`4!`_oQ z<|fGG;Y}G3cApgZhXgomTLxUczi_;vd%pI-hc6U!xj(_xEa1Q$8QDIsH2m|SeCN%O zZ|4s)grtjsPj1fagl>jA6ZU|un_-Y+!50{Q(fyxYxd+DC-N(h+3HK*tscTL)3reCo3bZD=s$Jxv|l#wN!5uCU+V>oszWQhDT z+kp*oe3}uz`{2~^qhV@~JTAR=zmuUJfT)T0-c9J~&oW@rM8Ub=$v9u~9k}z>5O8n{ zR5j_PY4u3i|KZ%P-m?=L;10N&&Hl$R89r>ZDf^i*Wb!HpZo)laj2ReB(3A zRai_ba5abUduJAN;Ld0A$JL;}Y=c$ux69xzY!=7u{`3}@Hp_MtlXlSuhHmdKb;nvR z`t{e)T<*(obv2c`XipIgy94b8XBUvH+%~q|&L-T}UlhT*?WJ)YvvRX?_l(Tt?s^W! HT<-q?wwtT; delta 61574 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 z zF@*0rL282cb6P3#|=H|FhNzO(80h;4Ce)XprAPL~Tkz*T)*pB3S?nhF&$@Cblgu2B--lcPp ze6Y?BMdgoL{IXZC3(*JvE zc<*e#XO_HTLBA^a$npxQg7chVkybyO>5kH4g2_bfnH6dvIg{GU9sTN}=QlrPBh zIBqbC)Ieg^m=A+9RnWR0Ox3w9hCYCX+Ik?h(*w`$eD&97vV z4X-^jI|$K;cOM^tL64jZJ&ZeD2@77C0|lSInLL^137yVp>{&n@h||fQ4S(^+eaVw1 z$NzhgDXJ+bxyvv})OD)^uI07j(CT`E)rmZRn^*kvl!o5O692t5oyYtU)x_M_ zc0*|fzE-)KCe*$JUU)j(jM^BA_4A?VD1rNot^N5nbyu|Wt{0Nu{$x=vzZU6q;P-9F zV=bI`#KGskBryG4nNFOa`$W@$c>3DQR7#wOUBMxXB3wzCdT!^pVt%!q2a|fyZPW>l z)f%cWKsLO^Wze=RkNVF`H9|4L* zLF7OR@EWz)#Zcd0vRJTiipG3GAH8dvU(9V>6Z4uq8*)uOIjoG%q8{|vn?bez8awIV zYNDv2{FzCkb74XDC6ZL+m%JNBepq=Y5E_|N5O>-@;X7*6c7V!4bKxTQh!He)H zO&REMXs^@JT+yin>A1?E+45lf^g{brqq?{I^FezbmAl?32_RC?ZQSK(94}X3Wz}{rtiblaOdfBn(SnUIi1HJpy1Ev6YOLJuE74fz;*q-8QnA{Vw$QA5WVo|F zLvR`dF~34i6}SDNF->#Z6=6|xW=)f*i$UDWPH~*oHx}JgjU{JsDo`fNPn0_Q$m+Q`$@uWu6bV7# zZQQSjM`*S?H-_FMd+z15Z%PZdN34pKK7q<_lU#r$uCH;tmF|p%mphJapKHA*Fmh4w zkxC#73zkv1@>f38O9EzwADkF+g}XSR2qQ(?Pzm~1F8($$iXPoN(Mmj%mtkppx5I84 z8&InKwS+~dfHhhgvpDsWR$Rnm%4ReRJ&5IRs&O%Eiac}gh}=E%Ix4q>h^=&%CnSCjR~i3k`L|CMz`s)#`WAx8drvkyu+GlPek?W>F-(g;mR)=i~n$1plAO^CSYWV*Ys z89e4?Jr+1OH*)PKJ-oth55*Ie?{IqiB^8c!4ueXG7pb54WFE|1ew$dp4oUi>^22q6 zvNX~s9vBil-gY+^Tp6TPtb~|0{o?;=2yL@c@xTPuzSJ<-D1NlHm7trGX76Ft5rS}& zRT)BkEW7|j#_c*{b|oS$r=9g{DnM9c-QEb0no}Px@J+pUPh-|Uu}WeWt@JPgL5r-~ z(p`H{jVuiB%5YUpQYBw&!gX0Xsx@)nS z|AwnI_JBk?#hoDtVl=4Eo2GR>o&4~k$Jh8UI?m7Os4sG+-Fh_{gS~R+pJPrOXEw+n zG=p<(=^G z#LtPGP){7IdEl{S)wt9U;-hoEUd_@DMV1J(J*u-3-o3~MoJCjpSd@ay({{#q_>4qL zZ6g7~V+}Qd7ZLI7Q-F-|nJUxT>nY-uB&WSQ98t(icj1b{d}t+6)T>G)Ea^yv?<#DF z)|u#8KxYI@I`gTD7vb;e2Z9u@|3>Q75)dX>Jm^c`j>#Su+O`VVKxu!QDmxG3nLv{& zK|ZfdD%>%0_3gy(q;os!DjeGb4qtohx+D^%bHm;izI^O1~=6}7N#r$aauC@M)r)sD|XUe0#))9=q6 z;`(IyW~AiY%r?oxTU`((kJD!;K*yFLH`U~>XBIm8$m8IeebJtrylQr@rEFO{r>>)Z zR36Ss@c=%CI*y{JF;55>bD3FlN)TO%zdI*re`4_`t(w_oPUe&i(Gbk@fUh?ugZiV2 z?Nq+(23F8v=L_-BpLgpL@@(p#1p6sKmH0(n$m6$7fT7zItPYh?Z$h81>kR_*?fI4P zh8&XN9Kum+Yu)0+x;GGa#E2DcGKPa4l<5ysXu_w`ohBBxL%Yc9B&esPhO*Y4pdlk1 zr&_J1yUW?&47H4Srgm=WYA{8dLt0dxa$U#s75VQQ<~KV&6ngFXUSJEcB~|ZA+D($- zK!4J)CEbUP_bD;*%K@mDuMEb#so4>?@Xzy<`2e9DB=RJX4C`@5YoKx&_PZkX3T#Yl z2P6LYhv=+K7dGQWwm_5DSg^Bl$w7$Pfts^ho|sy_&$PcTeNVpDZDC8t&|+)dzlko+ zvqLMff4uP^Ra3x3u+!Z`7!|B9pNz_L{}6SG2en;zUjs!XWvl*vziS(W`uW}{O!8hM zA0lX^a9b}m$VYUE<;%c5x^tJ8_{yrLe632L5i9B^*A(?5cC2iTc7?oNoe_=sG0ll~ zosY6Pn|dK0SRNKe^Qdfe_Q-xNzFS;U=Y}%t{+f2mRoHzo?I5p5&UU~&gdQ)B(04%4 zcHCgJqfOO(no#Z?Z|X7pKVQ4d(kQb&-Ke1o`3->F+(MI-QZva2-svBhPcPgYnnO(k zWc79U9~HPVMi(crrxJb05oq0?T^befd@J3-Dsesn{OA6|?;LSGzhIASH7ObT`flOg zIDiEnjEyB6=JxM4=)U4Qcy00aA^`_LTHix3eF{a-njZXBS z=AoDT8YbAS&RdrK!M5rRt$w{<;?+@ZgtnFyH=D-pjE#~+_W!a-&;|LP@2_E_stT?- zVttpevJLbJS5np0lc#^z!k5PGhmfD#Hd`XWz4-uUz@xxGJwMJmyxN6N5Pud4@Abcy zjLFf#P+pm2{}B?-n_~5j55X%!as_r8cH0yGm4D6IOPgw$n}37ApnKlbL4tpSkcjZ` z%Z!ZgF~NlqHW$EOL%dXR8J9G-!4MG7rP<|8N8<+=c~DopErIkYkV1z4nQ4t`o!N{R zb9Y)E;N#=#gigm678VR(=b!#7U?M;W_e7r-a;Q(EMB@Rui zl+T}(B6Nv072gA~`ogtZm-UfXd$#>6^fjK)WL({s7wx*%RaI~pK^5WJGT;UAZ$-r^u zi~oe^%wa$co!3U2=pm1-S!`fnU_F8e>`~bs#N)@9&U#|VC8sMx8q#AaPEj4Jknx~bSq_tE&`V$>a4qn-V7=XOyO`D?fVk>_XpN-@1IWBI`Sd<(t@rZ4?t6YPoBIi!) zKS5%jbe^2IAVE}#LXwh_h7OyUn);8BgSCEd!$-s>r045doZ-AmpqCY5g2e^jZ{t*{ zcAV-@Q84|ODu*OxEwLhGuP4`7R;*slLF%QBQVN%8jWrLjop2#9&VK{?`{Wc9Fa&OY ze=5{wtj2S|`hs7&Cq7kK7&J^3B0eNi7uFYgSh6g9dc(n-XQdTR2VVbC{w5;%;~)8! zemHw|o^oh=O_{AzKCnj0D3oJ2rkcP8 z-nannU3;&Y%jZeOx2mJ@)%m=>Jp7`z!K+KyQGxsfgnqD^=^R88m~^*YZtcx+)JesA zcF}HmQ}fq~4VT~P1_B5ip9by`eeg^?fRUzn%_Yr+^61@GL2*Pz0*mpe(xX}uNqXU* zY?1UW0@41;TF7R!&FDLC-!UdQhH<_-;71{~==WO`yuWz-)`X78bb7=+%TIlVmr{B9 zosXT4{2L*E@lU1kj%Z)+T`F8a)Qu}}WD5M@_;2sIi+Eu#X>bE)tViNy$Mhy6it?s* z9if*J%Do&%sCm4m_B*2}I!fW^b_^6cp!G>%Q$SQW|9}w4tC?Sx>jE4(_(}{>CD+f- zW-?+Go)J}n%JwCJw8oS-43@Kd4K*>rNHK^*chqS&gF|9Lus4HtQ1xukvv)=|j)yOb zrW0U<4G6SFX-Xa3qmQ8982W>eqZZKe;H^@pGShEeFLFp9fnhXwPlZy&8nK_x3pC`omlOgP1*+v4 z`tN`Di$AM14mOE+{=!=GkFoB+g+?}5;OTFId+FB^K?-pqJ1+fob#=g4+zi)UBoRd0 zitqY7i8fNjeMG&|x9!$tg?YK<9}bo06)ZUqi}wIWu-Gsa1?Ayz(E5iXks@SCgB`rPfZeNfC##n?h{L!ZfgO3?> zWjCftF~OZ}P+Jf+j+2Xvuu}LZZ!__72qo?#Jmgy~D?XGFL1}jRm-rX)KN?Xn1jaj# zhYhpG94qvT&=FjnhbCK9y#vHX@YXW+lBKO3Yj~kDs`nj4SXIAWlN|<8c{Ipxb;-?9 ziVyaG^UB%S9-75r=Cd#T1W>8FFfnkQwIQ}oLZKZB;nSI$icJx|z&*>xL}@U`TP|cq`k-Y;W>I>O-@M+F8MO-X_O`(wIEuF=k5bZj%R~GvuuM*E2eIW^pnBO z(plZqCwi$=MU_<7=&tMNgsb8EM+E07XUhhs_m?8tn8q&RO%s6x_tQy;bUW*ZB_{dX z5W@7G_{fw>4HA z#--sCN~WD^@m?)1{%>`eJi z+FL+LDT!fmmcE{Z_a^Av2LoLh?;M2o!t$))Hv#*_Xff|;mGmd`OV{n$zm$(RRvg}- zT4NUIl5u$tg4&lr$e3AJM#fDL2*d#Pf}hl3GLsC_$m6ohpCZhPYlGplc99Q*D`X8n z(%_ijk+R=Zn`y_vhv__JaBwm?tCG)N41dI~6B?%6VKTjsE*G(!d5!mu8_eJ4D>m4C zdL+@Hor+TW$k6|)+;>||e%6P&`}ypJZ;s(U(zM%N!N;C)HaG7>0@DgCXw3dSG#`6Z z>t)!x!#5Z9UUc!+=?y%xABDZ{y0bGWbw+7xoZxu_!C4|RRn0yk`_zK={iu0AIo+NvIMTny-PgX_qk3zq41Xnm2 z>{L>6%{@##xofQ#IWQ&}spGd^?=fQ74pSyV9BaI-dzR6E&(2*X8;!s8AfM0-m%n-) z!K)4qECYQ(yM^@2uUpSFY)QFP=iiFXw3GLas*%3M~bHEHKb_8xBdgKK! zr~E%xN)Ay_fIBrbH2n7o(@I;vRO%7WhrT+O#Y7swE>3xmU*&W3Um>IkS6I2QLO5!u z@cJPQZa(T0Uw-QDgHT=DlzV6lyw_hkiyg`p#>1{X0rD!{^Mgi`1wS!hXCAYvFCXZHcImJ!%OP0Nu93w2Q7$l}lBs z)}vK}_=r-g!H2+lKb5(T*aX9`=K*8;fs)TP^W@m4-~38#`vrfo-o1`+=;c~`&?uAg zPM~1~DnGilV}_A`s)CQ;ePZVv7nQX#Tn2`4M&7tGjA!?LoEfxr-|64N-TMY@-$RNq z^=!-#ou)r}RS(cBNt04}Ii2zZ92IN_303BXUQ|(qCc6sse_-X6?Xtb2)$ZWH3=9m; z4@}?|ZW??<><5C8nqdUgL7 zH4Kr{YjGZ_Z37SU?;`Q=3OSwoUCoEf?bCG}_+c>E@+{udj{iLkynC(Zdn~mpU%m=k zN$?+`!JEH}kq108yz28WCcV{K&D-h{g2Cpl!bF{xDV^-`5&^N$6;#l-A#lBTpN-GA zrURlpv@JtD4(}2_oIQsvV%C2o=rIGjnZcVnkpg(Zcbu&wj{5Y=0|hXE$33=y9V0$TpeipN6vE?~2~Fi#wY)S#V+d954I@U%{tXIJAc~)j*4NP|2PnNzBl@ zPuLD_>9`SI)f`Xs`TysUKhWsk;GtX=$SJA2BNcay^$T$L&tuO%T!wvNM|cn}PIKSS z3`l!V6|?^`W*S=N_7I)0h!?hIncAOqSgZBWYH?#)TVq3 zE*{NlH2)ske@<;F6pMoKw-HLckICNers8{KewL&9L*fQvQVoYr@-13CKCbG1*IA$f^?zTydg;1J(~lT+n-6X)G^Zi&5N@x%c42xbKkxdt5*kmx%q!G1u8B;%Z<8Pg23>xn!-T$C)wL>-bRB%vR!?89WwNMmfiP=K3+_ za^h(<`e#y8CHZAghWHL#m4~jj)M4p&r75m|vVmH?6T1iHRzG#$Sx>pG-EW;QgjOOC z^Pz?>DCBJ6T%fgAd-K3AmRSJ!j4o){x;;bsJZttsrqq(C=-geYKn@TG;%zbj1@t^W zaYCnLgE<~$-@x_2ho|}Bz4J2GbsUI`QdJA9Y=%FlII~EWe|u?PujV{1Nklsk(BmQCbsZ zuudu4QUS%sGqfY`uThEi3(n~?qnknhqm+LO%O%yRH0rw7s+FK71^ex;U3cjRkc)80;0Df~`7{f^{* zdp(x7&WLjE(!kzjHdn$ihAeL||2G*-C}~nM|0+bNkW+gH8Pn%^XaCqEl!Bm)oLVtI zmm5x^g3>lFFED+vRp&6!0=U}<2bDYO{ct1`5n?E2?by|5I4UeRuj_Jn>4hdea6XlnDU*%G4#+hYcoTAggxxn? zPH>J$C|+L&b+9xvDOw^+FZAU2Q*X!oFO}Qs@-#S?{s?JX0)=s_Fi#|dP0HIEzYRU3{Ug*-o?y@Hl{=l^^5aFuit(v~ z-(^wXqdiv+l&|j<7}|9qHOg;<=HABzQR1ns(o|wwrb=7!`jKor=Y{P?w0Q$QqDS`D z$ev=g>i3TbE+M#kMuENF)IteXqo%Kls$eM3f4q?w8V_}Q=w5#7LZ}q7Tts|u|1_UT zpL+1zH2@p8BL1#Pp=PZr{&-vBXIKqSNHH-9^2x|fYDvX7^P$GW!*MC?Ugz8iol)f7 z`*2sbepk@9eDmk8C`QUO5F(sbal*h`J*&XTzqadgy-3UYE$A;;R0r>h$nJ@S#cp2je>1|t z0r}?Id8QH~rnBh;(R>|hzW@iS1%W2HqGA>K|j;clUtKpA;K45$$~%2aq^CMoAFT z{Bv)OeWdiz`uwtcf%?V_9p>4`v=5Eo1HuHc0|_>ZeLT55mM(cxJ`V;PyqLXh*N zj=;bbcEal%85U1PN9oE+oEW5Rt8&AY3Js-I$FOMJ?b`vGLgfAeap^nT-)%!@UM%Rr z3df}%!x!;h{qKDgMBYO;XR_8W{U)XqysXx>`_krJ#Pq62egdfBOkenq8@a13{ZG8(jVh1?BEtChCqO!&h0FiMBszHa*t}7X|50N8(({VYhjTO1{gq26 zc05g&o4Aq-?=wic|MgS<=LKm1>C|x%uG`ijE&8qiG~oW{mcU1A-+lRfuGw0en&VpI zc$!htmNC2c9@6*e$e-=jBFg|PNI#yP*6VB4wf32)_VZl5dcOJbX-LFVVmZPQQ zRfocFq`HoHPqa-0mDHFNeN4A8!pT`{=aV;R8U#MV9O~s^H*D&OOqVHHAJoOpLM%sA zJUH=X_3r>1cu4|eB7aX_=_cZ8u6nlhSk1{s6a84BvFy57jfFZhcs~LC+7k1VG(Cdn3j8IO z;o&_wV*z;P^6umuv3O>f+;e0BiI?l-~`C#aeWHXb<@cK3GIKioFuuEC_=D5dWz>gjB zI}66^4}aTFne81kTe=dvvub`zFxGJT=2kPKYH+7xjmvo- zP=s%s?E?OMX<4{QmQ+S2Q6gj1;WwKaZBWJlroB_%`ycV$ropwXo%Si#^t!Haz)PW# z+)?@1ffep4PG+p*|JU1hKt;7IYY#{ml86LRR3u20q`&}@l`KJWMnRD{M9HubL`kEl z;3!FvB$8ENNP{R@L2?{&&JrYtzXv?`T<a@f6hSMTcX>guYms!OEB zbNe~v(=OANS8J3l?C|i@0(d8 zt)_yZ$cT|ar!zI{xF;JA3&u9fG+V|~b3RojtEt?$)Td!<5WUwtg+gYbw{~!-I-;M0vhK>%rXnBQN0zAj8saLze`Y@WlzR%vuAoZZRkdDoIJ~o zGNx(HRJv+L9DE7&Vhm2&9Z}Po{`1blJAR9I;rhr<&q3%+()~)W&cG% zpTX3|VKG^2O%}pn$*N80w(1BixYS8>_al?7{G^;N5h5SxMIGHAZgyu+Q3o+m9;;M8 zmRq8~C)rSa>BxH~oDIpb)AF>6dsHOLtS-)0lWeN`o z1r3LQ9ecGQa~*7x&3Gm%nF<*lGWPb9!PVBJa>5lToYw$WPK4;!y<%g1pI5pEC7v!2 zw(7IXgep2~yRRj%d#4~XJ%_JfVtL`@ddFTtiC@MZy2waM3;FFO!clUTppkYUD0+~J zFO&6(_}cy=luXEY>NSf=O1?GqqJ zp`t-X(=#l>@%WecJrHg!&}g%FR&n<3(7l>A`&pTiWN}Zy&iu!W2V(&BKs=`9wq$~U zF`?7U`1g-dnhlX8h@|#54znLqKF_|ojoy~Wt}BbVHPGLGZ)51(_BhA_CZ!B9;HG#j z$F@$HsXQvpkt(NcW>mEnP9C<|R>^48`jRje?;2MKl1SQ))}VaX7eI8d*G?nsOOjtN zQ@B$!`B8xj@Z6GW8Pe;>h1T=fwx^2+a)pmAEAx7eN2hF z$I=KDIQwkhxHKSVZ`Zv%#y=N+0LNG&|nkY*)6P!h!K_J&HWKBk&VZVV12w zxIGl_I|sP*kq4Q$&pf-mZ}jnAfT{Kq^(+tv_}!IW<5f^x$nuY8=mGP_XQjzqS5Sh0 zBhB3)Q7_w(bsfX4x)sg##VdPb7X$Ru&frdOI1FQ_4JvkK1^{9K!migp9LcIAL14cK z>f)|Os0*j7tT=1z*4?{TNtHnrB?Znrx?;gDu9*MTF>xnVpy)}1^O#(O2wRtOTfuHh zyY<^)4SAsJO$&C2N=fyPb_No_mC3(VqE0X{`sj0;0B;bS_eBuXe34Q^$bAp3(Y2jb z5Q_rs#q=uqiugkzO=pois{?rjM{>p49=otP<~;Oddxtd0SQF}eRjSmco~3U;XL@3v zTLGX!)^KJ(=DIiuHsO~=aSG%bUm^gr7I$Uem#oOUWU?ViPL90x3cWQwO^j%?UU@tS zZG&&Mkd%RDYFaa2@!`F1-GbgXGPXiK$i5j;Y=b%`$!HM_)YmZ?!{#;Z=rA&oY3RQQKpV=ME|N}#*f1Dg&#kDygS>8cd{)G zlt*etMyi4H1HS}W4qfaYw{V&H#QM8a#tB<5f8NOG2B*P%YZCKa}pBFxksp9oBm#CGMT7Svdkw`{2Huuj(v_ zi((YPgbCHCKZHJw{6IO3gcW(?1!IGebK6>X{W^1kzrcV*!$bEUxv{n-@;z_Mkz>xB zsoytaeCF4JOPzA`cM4JgYC>#r!#SAgi;7;SApN)C}n(g`2`TC5XYDmxF-J)Ljj2)G~=l1PeBwNugMe z`V13kYwH!~wp}fKeFK?{yCz-K8gnLBPj7O>Z^MHbtr*tcdfzNrYV)1d%(1P=GMB$z z>qkY2ywE__>aL)<)E}x!iR{%!$L31u0@bc_cz^2XtlSVp_DVb2rjDDmG?4s5tcpjFg>|1KQY~ z9!Q*qZv1#kr7@Qx_?c0d;7g;sg=@;ls_*i5@p^%=#kss>BUJzu5_GY@CI5U@Lx9|OKFdaOJt6ykm0Q0{1Uc~)Y2bvV zRQf!mXzdfIJD4I&=;981@xY?$x3g4>a2mkvdEeM34qT-Y!O)ay(csR(f#HG+%B@tF zEC=G3CWKqEnUlVENKr=Bw5$q9i0XM#&+ToMf_~^@nbXoW`%l5N+t`KW^zPN^|l`l=oO{fKa3#&H{L|HCoiSAKqJFgtc~{hiV#b zS6!%~!vTzY^A5XH5EC4Zgz(z^DFShoBALepp-jT}scr8}Jx!jy=-@@DH&->3ME%HN zd+h$x-ZJ0$P()Y z+_yCKCTclbwW$Y;qa;TUm8%qNeN!V=P}*d2VxUP#m7qVQgf=;{%3gy6B$SC!^arpe zb+)Qhjo7I5Y4_EM!yZ0eIq*kUOoXI6$zZmD3^X-0 zbD0DS9~VogD7(>UW<41{Bt(S3@|~NuYzu?Z`NnVM@0)(My*u z;e8I;yKga1Mrre9bmPZDaeX7)<$@l-O?GZ20VJ9awglNIE6m$fS zei3pQ#Dd%sYm0+2hg46+Gb+=A@o9q#juU$BW55lYA`OaTTwCa$B|-olmC55^zswX# zbkIkQ-C*A=cpQ$j>;}sCDD4qOZ@?#DB=~d3atv1m&^YI)!Q2GT{bNrFDWAiH-2`ch z@!R#Yl~js^fNJO;`&iI2VD10n&${u;3~+-T&w)R-3IKF>1Z=S-fddFs^V{Z)WZh*5 z;9*Ywm+i#3B-7%eRiV^hri;JS@a`*Gpma9{eDdYFiPx`yw;`mp%yz*qBQMQRG;4Ay zi|>N%uFa4muUAERt5d(9@C-SDnqqIfbHKOzmrgwCx@vzuzp`^7tI%+Ne$@Mn!e1G3 zRpjzzXqE)=@aUOS9&XJBc0@yQws&Yt+>@k|O;?{%+`eK-HXVCH+j4zzta+k{47bvIp6{OrEP z{k%7fum@O*q<>*Op7VB)t7|J2(%RY@nDSD1EPPFd-k^_}~`*nuUg3k@8lhI^GJo4wcuUVE#(Z5Ps`%XiEW^Sab!-SDyl- zZDS+w$1Cf3i9alg*H&o7K3gCW-FsaP4mR)CKx{ryb8n?Yj$9S=pW>m{-vEo^Xd;&r z)AG`qdFn`eucVv7&$(NAAKihaxVIBkoL3Nh3Eh;@a>klDDDGv2gTwZ^4-Ve!c`!Pm zU-qD5xT|_RF*p!z`w|*lIS;^{v(~hg)!fytp4ew>@TB{UNOun3Fva*GjsY{jIU(d5 zvc>S*bK(ryAq$dM&)<%D-m%OX>h8U__}tf8 z_{ee!$i%}hlDL;pQ?aY*+Y5&T0e1Xgmc$^PN6k(*Fn8{rsX6wE5p+(9erECG=w7@L zEH3zCH8nC^p7br!@P@kZBU)O0mr;|XZIjqa_2}?8u7uPo`p@=wCxxN2^QdkLBgw;- zv*D%Xo5)yNzo&LF6Y@s>jTM&V3=Kcc_Oo@6Zq~!^wvDlR84%bBJ8eJhxM_E{zHIun zr&_4}PQ5x z0yZYBUwk>2i~4*qR-id@`$yx{LX)Z4f(*mWkyA@*U$yE_IY!oAyX42D%8(aQaot6r zOFe>V(QpS^RQ>eo;l|NAdvQo~#Gr8ubyD7$wjPIzH$i@Y_V<9%#}=T+m6@g2WSrJ2 zY_K#D<$XUuyww)9P^onavlWi`8l!#K&^OOE>J8@M^$h+Mx zqoAAwfjY6Ue)P^(J}}{QqQn8d4`i(d`~AjlRbYkp<4bAuipTy;d&_wa^F-j{};H(Pi|R$>DFtY8@E{cfR8vJ)5fvclN@qS z=mpUk@zy844(x^myv)0kN4`>E!MrV+%}3W(zG53G8CV5JvWmM;9b==NG>Q~LN>q!C z4~@{cT*G2#K?Muxnl_09YKJA`rt(m7 zxPb6d@NjHPpQV@ZYbs{p+SbGin)LQ)Dtg3C>QK0S_=Dk*9-NJB$#$vrEy7JgHJ#IR zuH$b_`ZtgmBh%;PZO0{-sPf zQ>-8GTgx?!jFSz>*ngJU=!GtuwD2OUP!#(b=`^^jkd|(Wz%iebbe!d2L-E2rvRAVq zv3A+E=cgDRJrx``VNWd*u=ypgK>cOJFuB(B4Mpc*A%ML+5HbLAI9IQ!xmt*_p+C_O z5>c3DR0196nnui8i`=`-z0esy9m~TosP_^>zZk@JF5{wwRR|HH*M1U;=jij0Sl<c z^5shFpEa{FOF7qLJ|ty0KI!It;FoQq9QO@{e1!@^ywmJ~@@MR0Ja3=u99MP-6%3n*Q>|&%Z%DIH1i8Nl%B0zUhUWy0d?G7!)V9Jc^ce01 zVXO^tEY^uAC6}jlTD&9vGTt1+iE*mHBq)qJoYmwI?7w}e%u;=_%@&1Iy8R>H ztz9UE#1k4`!uD8s7hiN~**pWL#95NZg_mwPLO!{O=$~ZAX{E9k^^9((75eX09K4%5if*>ZR9H%@wi@Q;K zy&U?<{%$+OL#`ID-)x*ED*WOYskg*-`XlyEw3ECs7^_W9efDQU{J!1vz37jcPMBLL z`dXRHZuJ9>{2X=!cY%L7DN$f)Zz;NzVp}F0mnt#n5gLN1e6{dEi)A-Q+og~e@^Ec$ ztW!wGw#=1W3Oad;A-Y6)#gFEZ^Va6n^q+d&xkq&%#FkgqMet_hy8(K&I%S>#;wX@9 zsw*1Xe9<73i@0sA)810sJ}ixCab?2Ys^71B+jJp6OG>pG zwQU`X&5JyX3uQW5!4Iuzyt`cTh@KgoXmsa2w`@2K&QNDQD`(F93#p#^O)dcV7W_mN zSjO@X74zI9b6(`wjAQYQDlzRFY6%nBylXVB=`Sj_S0>3VHGL-K61L9%=$#L1iR@yM z0Z6e)LRX1n$t|tR{bMR7yL@NmOUA#Fe@!ZPz9B(l$hC;UAHn8HY-PZ5C5Oe6fG1+R!=ancDl2J>P{e5Y$yQm#HD+{4 z_1j7mZAU#>RK*u2HahAvmFjR33_%p)ADSyu)v-?E0lv&1tsm> zU78fNM6fThq|T&$I~gkK2+zPQH9l9nG&ZCtMxAs=z$5u`2iN)Hv07)Md>&-kmDY}g zDr)48Nxm=Slrc}y@GQE@4rM)TXoY)mgk#+Fh7I`cXw~z0>HvHAYa_w5dhT;*SlVfJ z?`o8oeq^_|D&{K#$?cZMD}CA?4wOhjODYk#mi?uap_=}O0*2G4!*drk;}tzA949(3 zERq;9V93Zs?_4pp3yyo8awQ=b^+;k9dJer#(6A6*N|@KsPNca_Z9*&Vwshu!QwlpJ z0Hs6$6gzO5aTXl7A^{NI_MgV&8|4mB%ch}$=u+-`8Iw`RONr1W@M4s3dv?V>N`@dx z&3(048BDwa^s}5j#kLI9I_7Wb{MN~rYk5*ww~SBalC{=BmweV}s|#8}Fz*(2u5R@G zNH{06yLmUQX`6X#Ot^u+NP9m^-h@^0o+{H5u%D8fn3%x1#_eveQUf{*`r4LW=ezyG5`{sQ~| z(>DU_7XX6Qf#oZq-5R(j@DAjZ`~MI$M__dqgP4-X$8Q(mtidJ@j~x4J@c~@m<%<`1 z;MX}I7XRo^e4`*7;~AL%92N4>naiSc6Ww@F*K!^c!D`NKx+zy9btygG_4rG!{UTRi zuL3?YE^hYA*=XOcO>LG9^TP77XMKihb}#fj7#@4YIS9m0@D=pg-L`C&me&j^i7xJl zb-P`lIB-Sl90N|*{_>Vy_UKVR6UA4Mvt93GrIf~WymES{6er21l%CNQ=in!@2RZ}5 zt^t_i^t3khQdJ^b(5Is)`gIcpH3)SD0yXNrN4sT z)@(6S;)B|XysY&e)3pyI=|*N5%=<2*&0S36PQuon3g((p1OFSMC|`XD+?Tf5{0fG8(z^MNGSiCyDEHZN-*Eum_`TD>m_%TT{We|S z_34xIho3k58R|vLg@fFcGD4;uEQ;O=G}5H=4lbwb!iITMn>+OHcbag~gy}KRi4*;} z%~P_)DAXP5`ZSg9vr(~IQGbuhr?~M_`t^m+RvbioS{&>cGKn%nvU@@{lylOZi{Ol| zhK{XAgE_!kNuS`856q$_1*+Y>C6Zci->PmEUIl@ez9y`;0nq#0rO&%z`ozHKfL}Tf zhZvg>#>hB)`L4ey0oZBy4ssP0$``Ra-eJwBRx>iKH&<#n^?6%Z;hC%R=$do*!1r$! zl(c!q?I4Cx)|oHN$qkr|gm{oa3+toA2!O@%b(TBRMIuq7zS|*FNbcyDC9Sh4b+XW- zp;8@+43BFcc&?1!W(i#5G^WQ}m%tX|a6U)AXTV|33(9#`ELkxW5GsZ7jSbsA1+c3P zHkeb1#DdcOW3n=0`8Thg>OTp$E_!E3H;9qXz`bOY6n=D*?%4~ndw$zzi!*gUDL3UG z4_dHD6%x}S<2f${e0H~`Si z-zG$4pS2s2RBxN)Q8mc;IKW`EGLz-`Mq{B+I}Y#trDha8XfP`6;Rm&{)o7W=4b`D& zEi6UI!orBOke*xd>mJ8ug^>1WcSQ4}Ix=vajId(yXN%erGNk-?Ug=F?*ZET|Z`=3Xjv9N6w=GIJHXDXaaPJ5lnk%YG&8!fb0y+|SJ`sEV@e@>@4NMjuy> zP)Xeqdmb80o4#LYXctpMvF^(`^XW)??~Pk{dlbl=GPWvz+#9zU==cJJZGAxt_}%eH z+uiC3p+jz!t2G3E7cTla6aN}HC8Qc1L+n0ivLWCr!W=)L193NrkV@wF(FlMoU&w6m+qI-Urd| zwzs%1NDlH3GT?|rO>DeB74ZYF>6-QYNUW=~)iuvK5F52t|3o#7l?36+^jV^oIL5RbfF3UyMavUne7>`6c{_I{gQgy`i=`>X!Pfn90`{3N~Nxt>(o%STbO=< zKoxl!lrau9jW0T^4h~&)3mESN*%JmXi7efz@X6iX3TDgg-<|k+sVkR5f+(Xt)`!8Z z@aA4`eYtc@u6LE1nPW9-vrkmr&F{pG2fdIx;?aB2Nykq2-A2@p zSG45;3k(K}4_F!EhbEenuK0JCNz1sXiKGl5R%*UCCW2*rEp_Q7&3NXMjY{=y=@jpo zbZeDuf@%Lyr3#Oy(mQvVe{7Kt1+sEj$={fIKx>;qx1x?+<*3zwr}V!0F~l(vZw|FX zOZ{7MgZkQW#@U@-!+R5)+n+l{ne8;4)Z&L~`V5zgi0jC}2yagQuqd^(M5@v`=f^Nr zI?E_C?U!)d%AY-_-QKfeb9ulmy_&kTUhPC@`O?V9jA~FY{5T6{dS~cN-eOeQDAmS$ zHU7#4Q&St}p%ydTx@Z!FZF8}USFJ13LyEpy%&LmKvLPRb{p zOSHMdlIc9uA|w5!q9Dw>Hm8CG%`dM_g-kJWp$+0v5{OBt>oRN@tSl>bgZwX`q?qiK zM7=ZAZx?TFeQE4E8=hxZwZg6uv0Mn0G#?+6z%smXl`khJOR5Y4QFb``Y6>xkOz}p2 zu5ZHe?Lz;y`t=I`ku#9@^kZ;VWbZd!+!c6IMO2$%F+wR~Abh+w$5K0DM_sIUj`zE>k2AI!(|P z)LA*0;J4}7uw8w`#k}-;!qHxzkFCdl!b{AWFZW09nB?(4pWBn|v=UPTW@qeo<9ssg zP|g14yVDPVsq4qfM{P%4Lb#mXVqDgFb(R=g-^r6iF%uzJ7#JAhhpe~P=DCsj8@2rg z4s3ju*Vd|`5w@MSvqG39hNC=^p=;MIA&I;fAP(@gwr0lbMU|3Qqp^!3z@cWD!2a_{ zud{h81?xp6zu?_2<%tT7d4ucTQYx^gY#6x-?(3*&3SNY{R)gqeO++a4a4*K6Lyg-SQUaOJet!q=3l6`@g)MijE?R9*8|c zGko8c74>>RtzVW~5VJJj-c=1<*1kMOe=YsGT}C_MPfq}SlLmyJqtQhUJtK7ex;!nV zW+3_(fLEg&OCDw2GfS%8I_)C2JA`3bkTD)`U-n zY$SF}q5or2^La5$3xczO5iw1Im}p}qMcjLmm`e=OY24+B*k6Z1=hlJwFGH87DY>#9 zpK=9kXKuwxC(~?8$0R?#%v>>-*7{aPVtW8&K3WGX4gl$N7A04AK!EshN&2r{TW_s! zQaBqWQn7HjHzQ!_j3W@f;+DOrEljMt$)8w^L zc#9#M^J2K^Y&rO-u@Y4*$f19EjEsdIF~E2)7Ovv?8TJ~)#Nq=X_jb2Iz%RzC_K~#Y z9T45!4g7nR*U9CBFfKvOEwxdxUOrhEnm*{3U)}wWG;S|w>CpG}a8rFrk_a};NX=fQ z;|Q$d`qq4a2Eky& z=Ja8(D1g!jcY$gKeoOsdenbDxL;s7yd){Vx*!MHl*iv*>@d5g`BSztvCwMI#t7 zt}czS^0oopjUYDuAT8Ychd^Bu1qffVwy?Wd3K6$2Pq&at)trRE*zxHQU`5pc?dd#yc?BK?vEwP+>gH>jPmaVH)@sGJB?16BYziM>c32v{sa>gR)S%#2 zkBY1Nn4<;G>oR zkqv7G@vJb|IS6DIYEIs=oNf4$O|kA_9ucDd;rK_ts&J;;^gO@4UB0n%V|K2$^CzbX z?|75_U5?Lo`d+lL7(p>1*o{wkO0sJpqAq{UqN(_9c8&J84tZ51j=g3UF+OoAK?P6? z#NwmTU_D@eUzH>2(9v6E`4AG-p8#-ZF8??2giJSC!M^LC>snzlj+vf{=&O%B_RXEg zX)ftOmraSr%U~uKT6}%&e|)x_W%Vh`$E2_*fdgjxV%8Ncca~tVWsq482D?SQKA;>aa~39x zJ#6Uk08`jfE!g6oIP6ZGFB>GZ=LLgp;?uo>KJsR$)GJMq@BRG}{w8jF zU$Zwa$97?v{LRjs_s-WepENLYPM#11USR-Se=|j~W_t-&D0OlePf( z>za4m+HaU_PnvB~!DNFEJFb%I_^cEr|H{*+T3l_3=R$`7(CT_O8w^WY8%Yzm*j3P0iHESs1$t?J+L7H`PTelG8v{jhD)7=Du&+89x! zu#6w!zwn4Ti$c3o^jZYio4SVbt2D{x{pun1#{xM>UBcp0?7fS;+gzR5Qnb^C6wQ@EP*Lldn-^GMfk4dRhdAJr{r-~Q zo-1B9bSPz0TBbUb^R!LSj|pB4HH$y#`uR1xC|ID!EsHE-KGGH&JkN9E%xsD2ts+Cl z#;idsi0^|YrAwBn?|tw-@sfbim6;Q~*=-hf{(Eok8Y86!K_fD;HUl5Gbh-VPP}-WK z3J9Qz#?r(Q+?e~54R`jg+Yft=?Cdgv0I>^fBxK8@pMrUj@lE>XXkLM6twL4@T;JQB zop&2%sX6{dE}MOOiQ1^|P`dFX;;OWGcpyOtP$*9HzwptoH^I;Dlm8gOqU+Qq1{G)S z5W6`idz%&aEz&i7KEBVG@ zwAuv{zBaQ*fM2%`#Y7D_0HFKl&=!b8fs8{haW)kq)D`T5yel)*<=lLG-M2Ib8N^g0 zUU6gclWFe=-vr^?0qhJ`DZqHJP{-d-YH-puP6IxoDP$>iw5&j)O`<5rdy@%el3QTW zI4fhb-&?Y&+ure$^w|XrjgL_Vr%vx_D~2P1%)h=UZs_DA5X5pT7J#fFQH477-ph8m zNYgr`Qq@MS-GlCHg1(wa(gzu)n0DkzToauC`1MTqZ~5WVapY@Ksf zs(QT<50zwGy~g_d?(?Padw_<>rX7wLqk;aCjZb+@Es*BTq?)u0eOY8{m|NA5Vv}RM zJfk?JtLr%z?NgN~HPt6&N7{)s_nxPOgZ}$N&d0`d_7r%Zo!}70^w56{l)+q|aWw9q zt4UxGG}Wk6mY^ZUEXC|&P|;lrDGKFPqK!4GD-CRon*v4BW^J(m7Sdy2@>9V{w2}(g z{|}cMj_l~{C&-#04sn-vW}VxmqG38^St-x@UMR-5D99}Am1ss@979}Z=1SGYVL%@1 z<)^X8ig)HUJYb}`d3NPGWa()bQDe-@bt|xK;hVUdo@8K2{Vd8_fn zOANuoc;~k#RS~??(@D@Ua){OO{M!>T1`M|rzNfNZ8nKj;zWL5&=`mgg-3H?sOc3`y zUHp1@SldO1>99_)#G7opo*Cq-R4dA>*~*n*N68HK2&WoJi8<30vQP%%iiQ-kj?66O z4>fKTbmHdq5++6rvMQc|7!%kzr-RkCQ16Zj^s0YQ!auI#%*5w%wjag`Vcz%C!cPtc zereD~=0~=xb7S^u%GBq5_VV2*NB0#_n!UcWIVawR?)S!Gg-bs0So+gpmeakk+7%od$wy}#oanwN8Q>PlUZlgyFm&) zxlY2laN!gihK!N6)`(*UhUm|Kj&O8M6yv9#%YuGXl6EQeY2?i~xY?Sl>_`Ecz&d${ zAx9$D?Zk6{z*mD>OIDRSH}}UDbwFO*I$FHA54;JdMpjWOP63c@(xrL|Z%g+Wath=d z>T6}@W(G%NK9(w91^wc-mK{C+fzITnJ5mbXqJAU@^Xp;@gU&Z zY&56yHp$7(Igu@$$|J9ga)e#mIMRhW*HVio{CIi-8yf8g9Zk1%?gqxim1ga^1LWo} zr2|HJC3;Aa>s3oMcH?0o!1lE95ig%&TmA8#GxouvN;l;F&dAox@3r?ZcB>IRlle** zS#B-mGq*#M`|uRLs}4pd>;VgahwEk8v^~D-YQVj}anYEd5@m4IDm-B9Ld~?pIMX?! z4=KV{<<{(@UeYq%#uq*|;cS0KmF%Sm<8x^q&Kua5W0x>3?B}rN%6qjw+cg<9yhuob zARNoAQxyDszj9z!#H_geIfYuol?$GuN$lk*tN_;dOZWODc$G08qw~>{>fDEb1W1dK zleec`-D8#h0>KeVdpozC$4nMo^Qq%%j`6oWin*h@Tr=ow?Cj7!DgGe*O(iJK)kQsj zZVxEtVihGaL}4GBr}B>0YD0J*7dJ>m@~hh@kP>oXT4$3x)Yd%N z)+8q8?!41=dSO>D#S~jQ!CO_P1#I?qn<7Is$tMaL6G27p0tv zQabIkH6d;Dx#KTlLgT`P$@9Fmtc0k^8Gm*UGM-mf6=igBfWk^tVP&l4L;6P1r z4r223(DE3aY5MJBl6GUqg@VA!7wCZJI*d{M2o(}{J5oVj-m29LscY%BFE`sN zqiJPHpx^ni3sW3q{{wEU63PXUH&}LMud0bZuH10&#E{s1%yg)T*t}G zn{E}?v*XRmyhaZa0Dvg_j)siRX#pb&(@n+M)~?G+EZCqKmoXSmo{Qxy84}3fIJ_`| zMX}vkaOjx8b3B_#X0GaV*DFfXT4vk}<_q-N&)c#G$U2Z?1+}p&6-JryC57&4l*s2! zdNV~FCT>M0d=*=vG5s6COp}a1@7F2t6}6nbatA=KVYk5HG@x?VDk`L96yd2PxWbDC z{o$!j^#Q$^54oMWi_ofPj2+Ia@b1#RTYb8$C(b{bzAsv`0FK#)MXBSp1z6pafgq;K zoz0Sl4LI9(=|gFH36A`@R7wrg+6HihN_Z zMxS0sZE|rHn&HFPmTv004fETFjx_Z2&d85WtmxZ8&p?9KYA;2J8VxkJzw@XJ6D%<4 zKw`>10*#hPQsgWR%bgrbyWP=m_&qAN;)@T+#Aa?k`lG8sj3D}0zx#)`fjQa(T4L?} zuulM14_bUq$&v)P-Gbuu?n@snyFfQ||J)qN<_7$wpium2N+uoHIvuD5fu|w7s&%-# zg1O?K_$4apX#Nyo=RgqjAB#`m>Hq8t(81OWH2J?G!EOW+*XOvCmjZLNwxg!O0bK5-j@?PM~|O=>aJhFK(2|b$^)?i zjA>t6j)O52d9Y;!Gohe1%YbrX2Cc8GJfbKao9bs0!@;;_I}j(v350tOwwXLsACikz0sP#T3COPHX5WbqTIgA^f0 z^Hi&YRs{1T`K-9`a;L%N@C*|n{vH*Fs#C1~*Q0E!m|?QQhr<%x@e;2Ee5Jno&Z##y zPLnuyIOd^EiR4N7;}&8x(YPsaKEuWrxrD;#Xs%lhmLi151J;Y$qfdlf$Y^@5^kWIt zdd2k!3<9y`_#xv7R4Np+Pi12(ZD+J#|JAFf-ioPCrs{XU7HxSG8O@9QSc&34-RdOh zpyK8{>N`i@p9(ujN&^;K-d@>Hdz0RAGk3F8u#~rCt#CF0%(~83G>*VB@S_C=lf1Wk z&;2XWH8)mDi0J89hW5f(A_!|ETfB5 z{Ad4mU;PhB{Vk<~@&6whOaGnr0s8-)Vf!C@3HsleR{wVUp#Sj<{ zJ#SVXD;uWa$EJ#c#?>788$nuXq;SV{e%Y5bFxX>oX{j9{qJzQVa9E}mnz|IuMTBB< z9YYT{5Ze}|l*04qj`Ll-D8eTsA}%Z{C?bCG65^sTnxFzMims0(HN!m# zsQJVWo)QtgD25Ocy@+;cha=GOEpVnHqE>hz!Li@VFI_sUMY9dggyw!vNOe#ZnyefA z`Q{t(Mf|U`=qhvToiZ){NrCSnxYea>Ky)|X`b6GS(yZ|1aRR~C;#~`njP)Z zM9g^bRQ-qkN^elRJGd_X`3U&s)r|JU-EPanD7N{BwD0Ov;EXn~WX`ZmO=cZxf6uwC$r#D&TcrvK?`okJXCiB z)RBK_LC6%^to!iYSKXj4!x?n>ufO-f-$!`oKwUG$+-T~8e&yP9KNt57`{H+(R zoFGACyTOOd^})~K8GaN8KJO(f3I5Ba(e}7QBHrLG(M?%E1hh-?!oSx4G(Ge4`{OWJ zHn@JTUr`-R&<|I|*R0+Tcx-tC|Mvy7_h&dQ`d$BF?HGJXyyIa>g$N1lUkD@^e1*_zf&2m zI(#jA?2t;+7^q9++u==AJs3|svWDSoE&pl^Hy6l^Bolq`7ZckSbDP(CdTmIbcgS$=Wu*9#RBhb$ci)evgH z&{{K~Q_ocZmP$_^w)5H~C~>AcEP3<|)c+Qg95DNfopt~pU;)=(*bvQl`27ClAsfz3 zfl7Fp4{xeZ0%rS79abNXFX`YqEGcRHo1y=#+J;IKOes}x{myJ-k;B){Hi1@YO&?Zh zJ`F0Qy?R)pQAS9MF8Nhbhc8*yJuI03@BC#3H(qzv{exk@liIbxzovS?){!f&uk&BR zVCmqJ{%xK!`oq!KSVC_0zb>i#UXBj`GPdJqK-YA+Kb|Ut$ki=b2ZgfkqZWs1K01pkJBYXCw2jOnwLvR{}(xY zvVZCRE+q`M0j}Sffbu6pn*%xgFXS&>`aAN=-&B&Kj{zM7T)&fF4JX4de}~NcXH|vq sH)gKHk)d~H;pY!{{?Ez*{cn%8T9Tu+z7wB4Dh0?aoB-Vt02l}RKQYg~LjV8( diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 148ef41..859664c 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -7,90 +7,43 @@ module.exports = { base: "/db-tutorial/", title: "DB-TUTORIAL", description: "数据库教程", - head: [["link", { rel: "icon", href: `/favicon.ico` }]], + head: [["link", {rel: "icon", href: `/favicon.ico`}]], markdown: { externalLinks: { - target: "_blank", - rel: "noopener noreferrer" + target: "_blank", rel: "noopener noreferrer" } }, themeConfig: { logo: "images/dunwu-logo-100.png", repo: "dunwu/db-tutorial", repoLabel: "Github", - docsDir: 'docs', - docsBranch: 'master', + docsDir: "docs", + docsBranch: "master", editLinks: true, smoothScroll: true, locales: { "/": { - label: "简体中文", - selectText: "Languages", - editLinkText: "帮助我们改善此页面!", - lastUpdated: "上次更新", - nav: [ - { - text: "sql", - link: "/sql/", - items: [ - { - text: "Mysql", - link: "/sql/mysql/" - } - ] - }, - { - text: "nosql", - link: "/nosql/", - items: [ - { - text: "Redis", - link: "/nosql/redis/" - } - ] - }, - { - text: "🎯 博客", - link: "https://github.com/dunwu/blog", - target: "_blank", - rel: "" - } - ], - sidebar: "auto", - sidebarDepth: 2 + label: "简体中文", selectText: "Languages", editLinkText: "帮助我们改善此页面!", lastUpdated: "上次更新", nav: [{ + text: "SQL", link: "/sql/" + }, { + text: "NOSQL", link: "/nosql/" + }, { + text: "Mysql", link: "/sql/mysql/" + }, { + text: "Redis", link: "/nosql/redis/" + }, { + text: "🎯 博客", link: "https://github.com/dunwu/blog", target: "_blank", rel: "" + }], sidebar: "auto", sidebarDepth: 2 } } }, - plugins: [ - ['@vuepress/active-header-links', { - sidebarLinkSelector: '.sidebar-link', - headerAnchorSelector: '.header-anchor' - }], - ["@vuepress/back-to-top", true], - [ - "@vuepress/pwa", - { - serviceWorker: true, - updatePopup: true - } - ], - ["@vuepress/medium-zoom", true], - [ - "container", - { - type: "vue", - before: '
',
-        after: "
" - } - ], - [ - "container", - { - type: "upgrade", - before: info => ``, - after: "" - } - ], - ["flowchart"] - ] + plugins: [["@vuepress/active-header-links", { + sidebarLinkSelector: ".sidebar-link", headerAnchorSelector: ".header-anchor" + }], ["@vuepress/back-to-top", true], ["@vuepress/pwa", { + serviceWorker: true, updatePopup: true + }], ["@vuepress/medium-zoom", true], ["container", { + type: "vue", before: '
', after: "
" + }], ["container", { + type: "upgrade", before: info => ``, after: "" + }], ["flowchart"]] }; diff --git a/docs/README.md b/docs/README.md index 85dae0a..a4e71c5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -47,15 +47,17 @@ footer: CC-BY-SA-4.0 Licensed | Copyright © 2018-Now Dunwu > [Redis](nosql/redis) 📚 +![img](http://dunwu.test.upcdn.net/snap/20200713105627.png) + - [Redis 面试总结](nosql/redis/redis-interview.md) 💯 -- [Redis 入门指南](nosql/redis/redis-quickstart.md) ⚡ -- [Redis 数据类型和应用](nosql/redis/redis-datatype.md) -- [Redis 持久化](nosql/redis/redis-persistence.md) -- [Redis 复制](nosql/redis/redis-replication.md) -- [Redis 哨兵](nosql/redis/redis-sentinel.md) -- [Redis 集群](nosql/redis/redis-cluster.md) -- [Redis 发布与订阅](nosql/redis/redis-pub-sub.md) -- [Redis 运维](nosql/redis/redis-ops.md) 🔨 +- [Redis 入门指南](nosql/redis/redis-quickstart.md) ⚡ - 关键词:`内存淘汰`、`事件`、`事务`、`管道`、`发布与订阅` +- [Redis 数据类型和应用](nosql/redis/redis-datatype.md) - 关键词:`STRING`、`HASH`、`LIST`、`SET`、`ZSET`、`BitMap`、`HyperLogLog`、`Geo` +- [Redis 持久化](nosql/redis/redis-persistence.md) - 关键词:`RDB`、`AOF`、`SAVE`、`BGSAVE`、`appendfsync` +- [Redis 复制](nosql/redis/redis-replication.md) - 关键词:`SLAVEOF`、`SYNC`、`PSYNC`、`REPLCONF ACK` +- [Redis 哨兵](nosql/redis/redis-sentinel.md) - 关键词:`Sentinel`、`PING`、`INFO`、`Raft` +- [Redis 集群](nosql/redis/redis-cluster.md) - 关键词:`CLUSTER MEET`、`Hash slot`、`MOVED`、`ASK`、`SLAVEOF no one`、`redis-trib` +- [Redis 实战](nosql/redis/redis-action.md) - 关键词:`缓存`、`分布式锁`、`布隆过滤器` +- [Redis 运维](nosql/redis/redis-ops.md) 🔨 - 关键词:`安装`、`命令`、`集群`、`客户端` #### Elasticsearch diff --git a/docs/nosql/redis/README.md b/docs/nosql/redis/README.md index ee782c9..53ec1d5 100644 --- a/docs/nosql/redis/README.md +++ b/docs/nosql/redis/README.md @@ -12,16 +12,26 @@ ### [Redis 入门指南 ⚡](redis-quickstart.md) +> 关键词:`内存淘汰`、`事件`、`事务`、`管道`、`发布与订阅` + +![img](http://dunwu.test.upcdn.net/snap/20200713105627.png) + ### [Redis 数据类型和应用](redis-datatype.md) +> 关键词:`STRING`、`HASH`、`LIST`、`SET`、`ZSET`、`BitMap`、`HyperLogLog`、`Geo` + ![Redis 数据类型](http://dunwu.test.upcdn.net/snap/20200226113813.png) ### [Redis 持久化](redis-persistence.md) +> 关键词:`RDB`、`AOF`、`SAVE`、`BGSAVE`、`appendfsync` + ![img](http://dunwu.test.upcdn.net/snap/20200224214047.png) ### [Redis 复制](redis-replication.md) +> 关键词:`SLAVEOF`、`SYNC`、`PSYNC`、`REPLCONF ACK` + ![img](http://dunwu.test.upcdn.net/snap/20200712182603.png) ### [Redis 哨兵](redis-sentinel.md) @@ -29,15 +39,25 @@ > Redis 哨兵(Sentinel)是 Redis 的高可用性(Hight Availability)解决方案。 > > Redis 哨兵是 Raft 算法 的具体实现。 +> +> 关键词:`Sentinel`、`PING`、`INFO`、`Raft` ![img](http://dunwu.test.upcdn.net/snap/20200713072747.png) ### [Redis 集群](redis-cluster.md) +> 关键词:`CLUSTER MEET`、`Hash slot`、`MOVED`、`ASK`、`SLAVEOF no one`、`redis-trib` + ![img](http://dunwu.test.upcdn.net/snap/20200713100613.png) +### [Redis 实战](redis-action.md) + +> 关键词:`缓存`、`分布式锁`、`布隆过滤器` + ### [Redis 运维 🔨](redis-ops.md) +> 关键词:`安装`、`命令`、`集群`、`客户端` + ## 📚 资料 - **官网** diff --git a/docs/nosql/redis/redis-action.md b/docs/nosql/redis/redis-action.md index 0dd2386..91d7757 100644 --- a/docs/nosql/redis/redis-action.md +++ b/docs/nosql/redis/redis-action.md @@ -4,8 +4,10 @@ - [一、应用场景](#一应用场景) - [缓存](#缓存) - - [布隆过滤器](#布隆过滤器) + - [BitMap 和 BloomFilter](#bitmap-和-bloomfilter) - [分布式锁](#分布式锁) +- [二、技巧](#二技巧) + - [keys 和 scan](#keys-和-scan) - [参考资料](#参考资料) diff --git a/docs/nosql/redis/redis-cluster.md b/docs/nosql/redis/redis-cluster.md index 518e475..5ad105e 100644 --- a/docs/nosql/redis/redis-cluster.md +++ b/docs/nosql/redis/redis-cluster.md @@ -12,18 +12,18 @@ -- [一、分区](#一分区) +- [一、Redis Cluster 分区](#一redis-cluster-分区) - [集群节点](#集群节点) - [分配 Hash 槽](#分配-hash-槽) - [寻址](#寻址) - [重新分片](#重新分片) - [ASK 错误](#ask-错误) -- [二、故障转移](#二故障转移) +- [二、Redis Cluster 故障转移](#二redis-cluster-故障转移) - [复制](#复制) - [故障检测](#故障检测) - [故障转移](#故障转移) -- [三、通信](#三通信) -- [四、应用](#四应用) +- [三、Redis Cluster 通信](#三redis-cluster-通信) +- [四、Redis Cluster 应用](#四redis-cluster-应用) - [集群限制](#集群限制) - [集群配置](#集群配置) - [五、其他方案](#五其他方案) @@ -34,7 +34,7 @@ -## 一、分区 +## 一、Redis Cluster 分区 ### 集群节点 @@ -118,7 +118,7 @@ Redis 集群的重新分片操作由 Redis 集群管理软件 **redis-trib** 负 ![img](http://dunwu.test.upcdn.net/cs/database/redis/redis-ask.png) -## 二、故障转移 +## 二、Redis Cluster 故障转移 ### 复制 @@ -147,7 +147,7 @@ Redis 复制机制可以参考:[Redis 复制](redis-replication.md) Redis 集群选举新的主节点流程基于[共识算法:Raft](https://www.jianshu.com/p/8e4bbe7e276c) -## 三、通信 +## 三、Redis Cluster 通信 集群中的节点通过发送和接收消息来进行通信。 @@ -159,7 +159,7 @@ Redis 集群节点发送的消息主要有以下五种: - `FAIL` - 当一个主节点 A 判断另一个主节点 B 已经进入 FAIL 状态时,节点 A 会向集群广播一条关于节点 B 的 FAIL 消息,所有收到这条消息的节点都会立即将节点 B 标记为已下线。 - `PUBLISH` - 当节点收到一个 PUBLISH 命令时,节点会执行这个命令,并向集群广播一条 PUBLISH 消息,所有接受到这条消息的节点都会执行相同的 PUBLISH 命令。 -## 四、应用 +## 四、Redis Cluster 应用 ### 集群限制 diff --git a/docs/nosql/redis/redis-interview.md b/docs/nosql/redis/redis-interview.md index fc11f5b..4de4717 100644 --- a/docs/nosql/redis/redis-interview.md +++ b/docs/nosql/redis/redis-interview.md @@ -1,33 +1,50 @@ # Redis 面试总结 + + +- [Redis 数据类型](#redis-数据类型) +- [Redis 内存淘汰](#redis-内存淘汰) +- [Redis 持久化](#redis-持久化) +- [Redis 事务](#redis-事务) +- [Redis 管道](#redis-管道) +- [Redis 高并发](#redis-高并发) +- [Redis 复制](#redis-复制) +- [Redis 哨兵](#redis-哨兵) +- [Redis vs. Memcached](#redis-vs-memcached) +- [参考资料](#参考资料) + + + ## Redis 数据类型 -问题: +【问题】 -- Redis 数据类型有哪些? -- Redis 各种数据类型适用于什么样的场景? +- Redis 有哪些数据类型? +- Redis 的数据类型分别适用于什么样的场景? --- -解答: +【解答】 -Redis 基本数据类型: +> **_Redis 数据类型和应用_** +> +> 数据类型的特性和应用细节点较多,详情可以参考:[Redis 数据类型](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-datatype.md) -| 数据类型 | 可以存储的值 | 操作 | -| -------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------- | -| STRING | 字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作
对整数和浮点数执行自增或者自减操作 | -| LIST | 列表 | 从两端压入或者弹出元素
读取单个或者多个元素
进行修剪,只保留一个范围内的元素 | -| SET | 无序集合 | 添加、获取、移除单个元素
检查一个元素是否存在于集合中
计算交集、并集、差集
从集合里面随机获取元素 | -| HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对
获取所有键值对
检查某个键是否存在 | -| ZSET | 有序集合 | 添加、获取、删除元素
根据分值范围或者成员来获取元素
计算一个键的排名 | +(1)Redis 支持五种基本数据类型: -Redis 各种数据类型的应用比较繁杂,详情可以参考:[Redis 数据类型](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-datatype.md) +- String:常用于 KV 缓存 +- Hash:存储结构化数据,如:产品信息、用户信息等。 +- List:存储列表,如:粉丝列表、文章评论列表等。可以通过 lrange 命令进行分页查询。 +- Set:存储去重列表,如:粉丝列表等。可以基于 set 玩儿交集、并集、差集的操作。例如:求两个人的共同好友列表。 +- Sorted Set:存储含评分的去重列表,如:各种排行榜。 + +(2)除此以外,还有 Bitmaps、HyperLogLogs、GEO、Streams 等高级数据类型。 ## Redis 内存淘汰 -问题: +【问题】 -- Redis 有哪些淘汰策略? +- Redis 有哪些内存淘汰策略? - 这些淘汰策略分别适用于什么场景? - Redis 有哪些删除失效 key 的方法? - 如何设置 Redis 中键的过期时间? @@ -35,9 +52,14 @@ Redis 各种数据类型的应用比较繁杂,详情可以参考:[Redis 数 --- -解答: +【解答】 -Redis 内存淘汰策略: +(1)Redis 过期策略是:**定期删除+惰性删除**。 + +- 消极方法(passive way),在主键被访问时如果发现它已经失效,那么就删除它。 +- 主动方法(active way),定期从设置了失效时间的主键中选择一部分失效的主键删除。 + +(2)Redis 内存淘汰策略: - **`noeviction`** - 当内存使用达到阈值的时候,所有引起申请内存的命令会报错。这是 Redis 默认的策略。 - **`allkeys-lru`** - 在主键空间中,优先移除最近未使用的 key。 @@ -46,27 +68,20 @@ Redis 内存淘汰策略: - **`volatile-random`** - 在设置了过期时间的键空间中,随机移除某个 key。 - **`volatile-ttl`** - 在设置了过期时间的键空间中,具有更早过期时间的 key 优先移除。 -如何选择内存淘汰策略: +(3)如何选择内存淘汰策略: - 如果数据呈现幂等分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用 `allkeys-lru`。 - 如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用 `allkeys-random`。 - `volatile-lru` 策略和 `volatile-random` 策略适合我们将一个 Redis 实例既应用于缓存和又应用于持久化存储的时候,然而我们也可以通过使用两个 Redis 实例来达到相同的效果。 - 将 key 设置过期时间实际上会消耗更多的内存,因此我们建议使用 `allkeys-lru` 策略从而更有效率的使用内存。 -Redis 删除失效主键的方法主要有两种: - -- 消极方法(passive way),在主键被访问时如果发现它已经失效,那么就删除它。 -- 主动方法(active way),周期性地从设置了失效时间的主键中选择一部分失效的主键删除。 - -LRU 算法实现思路: - -`HashMap` + `LinkedList` +(4)LRU 算法实现思路:可以继承 LinkedHashMap,并覆写 removeEldestEntry 方法来实现一个最简单的 LRUCache ## Redis 持久化 -问题: +【问题】 -- Redis 有哪些持久化方式? +- Redis 有几种持久化方式? - Redis 的不同持久化方式的特性和原理是什么? - RDB 和 AOF 各有什么优缺点?分别适用于什么样的场景? - Redis 执行持久化时,可以处理请求吗? @@ -74,122 +89,47 @@ LRU 算法实现思路: --- -解答: +【解答】 -Redis 支持两种持久化方式:RDB 和 AOF。 +> **_Redis 持久化_** +> +> 详情可以参考:[Redis 持久化](redis-persistence.md) -RDB 即快照方式,它将某个时间点的所有 Redis 数据保存到一个经过压缩的二进制文件(RDB 文件)中。 +(1)Redis 支持两种持久化方式:RDB 和 AOF。 -AOF(Append Only File) 是以文本日志形式将所有写命令追加到 AOF 文件的末尾,以此来记录数据的变化。 +(2)RDB 即某一时刻的二进制数据快照。 -更详细的特性及原理说明请参考:[Redis 持久化](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-persistence.md) +Redis 会周期性生成 RDB 文件。 -## Redis 高并发 +生成 RDB 流程:Redis fork 一个子进程,负责生成 RDB;生成 RDB 采用 Copy On Write 模式,此时,如果收到写请求,会在原副本上操作,不影响工作。 -问题: +RDB 只能恢复生成快照时刻的数据,之后的数据无法恢复。生成 RDB 的资源开销高昂。RDB 适合做冷备。 -- Redis 是单线程模型,为何吞吐量还很高? -- Redis 集群如何分片和寻址? -- Redis 集群如何扩展? -- Redis 集群如何保证数据一致? -- Redis 集群如何规划?你们公司的生产环境上如何部署 Redis 集群? -- Redis 的并发竞争问题如何解决? +(3)AOF 会将写命令不断追加到 AOF 文本日志末尾。 ---- +AOF 丢数据比 RDB 少,但文件会比 RDB 文件大很多。 -解答: +一般,AOF 设置 `appendfsync` 同步频率为 **`everysec`** 即可。 -Redis 为单进程单线程模式,采用队列模式将并发访问变为串行访问。 +(4)RDB or AOF -Redis 单机吞吐量也很高,能达到几万 QPS,但需要格外注意的是:**Redis 是单线程模型**。很多人可能会奇怪,Redis 是单线程模型,如何能处理高并发请求呢? - -原因在于: - -- Redis 读写都是内存操作。 -- Redis 基于**非阻塞的 IO 多路复用机制**,同时监听多个 socket,将产生事件的 socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处理。 -- 单线程,避免了线程创建、销毁、上下文切换的开销,并且避免了资源竞争。 - -Redis 的高并发通过主从架构来实现。Redis 集群采用主从模型,提供复制和故障转移功能,来保证 Redis 集群的高可用。通常情况,一主多从模式已经可以满足大部分项目的需要。根据实际的并发量,可以通过增加节点来扩展并发吞吐。 - -一主多从模式下,主节点负责写操作(单机几万 QPS),从节点负责查询操作(单机十万 QPS)。 - -进一步,如果需要缓存大量数据,就需要分区(sharding),Redis 集群通过划分虚拟 hash 槽来分片,进行数据分享。 - -根据 CAP 理论,Consistency、Availability、Partition tolerance 三者不可兼得,而 Redis 集群的选择是 AP。Redis 集群节点间采用异步通信方式,不保证强一致性,尽力达到最终一致性。 - -`Redis` 集群一般由 **多个节点** 组成,节点数量至少为 `6` 个,才能保证组成 **完整高可用** 的集群。 - -![img](https://user-gold-cdn.xitu.io/2019/10/10/16db5250b0d1c392?w=1467&h=803&f=png&s=43428) - -更详细的特性及原理说明请参考:[Redis 集群](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-cluster.md) - -## Redis 高可用 - -问题: - -- Redis 如何实现高可用? -- Redis 哨兵的功能? -- Redis 哨兵的原理? -- Redis 哨兵如何选举 Leader? -- Redis 如何实现故障转移? - ---- - -解答: - -Redis 的高可用是通过哨兵来实现(Raft 协议的 Redis 实现)。Sentinel(哨兵)可以监听主服务器,并在主服务器进入下线状态时,自动从从服务器中选举出新的主服务器。 - -由一个或多个 Sentinel 实例组成的 Sentinel 系统可以监视任意多个主服务器,以及这些主服务器的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。 - -![img](http://dunwu.test.upcdn.net/snap/20200131135847.png) - -更详细的特性及原理说明请参考:[Redis 哨兵](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-sentinel.md) - -## Redis 复制 - -问题: - -- Redis 复制的工作原理?Redis 旧版复制和新版复制有何不同? -- Redis 主从节点间如何复制数据? -- Redis 的数据一致性是强一致性吗? - ---- - -解答: - -旧版复制基于 `SYNC` 命令实现。分为同步(sync)和命令传播(command propagate)两个操作。这种方式存在缺陷:不能高效处理断线重连后的复制情况。 - -新版复制基于 `PSYNC` 命令实现。同步操作分为了两块: - -- **`完整重同步(full resychronization)`** 用于初次复制; -- **`部分重同步(partial resychronization)`** 用于断线后重复制。 - - 主从服务器的**复制偏移量(replication offset)** - - 主服务器的**复制积压缓冲区(replication backlog)** - - **服务器的运行 ID** - -Redis 集群主从节点复制的工作流程: - -- 步骤 1. 设置主从服务器 -- 步骤 2. 主从服务器建立 TCP 连接。 -- 步骤 3. 发送 PING 检查通信状态。 -- 步骤 4. 身份验证。 -- 步骤 5. 发送端口信息。 -- 步骤 6. 同步。 -- 步骤 7. 命令传播。 - -更详细的特性及原理说明请参考:[Redis 复制](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-replication.md) +建议同时使用 RDB 和 AOF。用 AOF 来保证数据不丢失,作为数据恢复的第一选择; 用 RDB 来做不同程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可以使用 RDB 来进行快速的数据恢复。 ## Redis 事务 -问题: +【问题】 +- Redis 的并发竞争问题是什么?如何解决这个问题? - Redis 支持事务吗? - Redis 事务是严格意义的事务吗?Redis 为什么不支持回滚。 - Redis 事务如何工作? - 了解 Redis 事务中的 CAS 行为吗? -- 除了事务,还有其他批量执行 Redis 命令的方式吗? -解答: +【解答】 + +> **_Redis 的事务特性、原理_** +> +> 详情参考:[Redis 入门指南之 事务](redis-quickstart.md#六redis-事务) **Redis 提供的不是严格的事务,Redis 只保证串行执行命令,并且能保证全部执行,但是执行命令失败时并不会回滚,而是会继续执行下去**。 @@ -200,15 +140,135 @@ Redis 不支持回滚的理由: `MULTI` 、 `EXEC` 、 `DISCARD` 和 `WATCH` 是 Redis 事务相关的命令。 -- **[`MULTI`](https://redis.io/commands/multi) 命令用于开启一个事务,它总是返回 OK 。** -- **[`EXEC`](https://redis.io/commands/exec) 命令负责触发并执行事务中的所有命令。** -- **当执行 [`DISCARD`](https://redis.io/commands/discard) 命令时, 事务会被放弃, 事务队列会被清空, 并且客户端会从事务状态中退出。** -- **[`WATCH`](https://redis.io/commands/watch) 命令可以为 Redis 事务提供 check-and-set (CAS)行为。**被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回 nil-reply 来表示事务已经失败。 +Redis 有天然解决这个并发竞争问题的类 CAS 乐观锁方案:每次要**写之前,先判断**一下当前这个 value 的时间戳是否比缓存里的 value 的时间戳要新。如果是的话,那么可以写,否则,就不能用旧的数据覆盖新的数据。 + +## Redis 管道 + +【问题】 + +- 除了事务,还有其他批量执行 Redis 命令的方式吗? + +【解答】 Redis 是一种基于 C/S 模型以及请求/响应协议的 TCP 服务。Redis 支持管道技术。管道技术允许请求以异步方式发送,即旧请求的应答还未返回的情况下,允许发送新请求。这种方式可以大大提高传输效率。使用管道发送命令时,Redis Server 会将部分请求放到缓存队列中(占用内存),执行完毕后一次性发送结果。如果需要发送大量的命令,会占用大量的内存,因此应该按照合理数量分批次的处理。 +## Redis 高并发 + +【问题】 + +- Redis 是单线程模型,为何吞吐量还很高? +- Redis 的 IO 多路复用原理是什么? +- Redis 集群如何分片和寻址? +- Redis 集群如何扩展? +- Redis 集群如何保证数据一致? +- Redis 集群如何规划?你们公司的生产环境上如何部署 Redis 集群? + +--- + +【解答】 + +> **_Redis 集群_** +> +> 详情可以参考:[Redis 集群](redis-cluster.md) + +(1)单线程 + +Redis 为单进程单线程模式,采用队列模式将并发访问变为串行访问。Redis 单机吞吐量也很高,能达到几万 QPS。 + +Redis 单线程模型,依然有很高的并发吞吐,原因在于: + +- Redis 读写都是内存操作。 +- Redis 基于**非阻塞的 IO 多路复用机制**,同时监听多个 socket,将产生事件的 socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处理。 +- 单线程,避免了线程创建、销毁、上下文切换的开销,并且避免了资源竞争。 + +(2)扩展并发吞吐量、存储容量 + +Redis 的高性能(扩展并发吞吐量、存储容量)通过主从架构来实现。 + +Redis 集群采用主从模型,提供复制和故障转移功能,来保证 Redis 集群的高可用。通常情况,一主多从模式已经可以满足大部分项目的需要。根据实际的并发量,可以通过增加节点来扩展并发吞吐。 + +一主多从模式下,主节点负责写操作(单机几万 QPS),从节点负责查询操作(单机十万 QPS)。 + +进一步,如果需要缓存大量数据,就需要分区(sharding)。Redis 集群通过划分虚拟 hash 槽来分片,每个主节点负责一定范围的 hash 槽。当需要扩展集群节点时,重新分配 hash 槽即可,redis-trib 会自动迁移变更 hash 槽中所属的 key。 + +(3)Redis 集群数据一致性 + +Redis 集群基于复制特性实现节点间的数据一致性。 + +## Redis 复制 + +【问题】 + +- Redis 复制的工作原理?Redis 旧版复制和新版复制有何不同? +- Redis 主从节点间如何复制数据? +- Redis 的数据一致性是强一致性吗? + +--- + +【解答】 + +> **_Redis 复制_** +> +> 详情可以参考:[Redis 复制](redis-replication.md) + +(1)旧版复制基于 `SYNC` 命令实现。分为同步(sync)和命令传播(command propagate)两个操作。这种方式存在缺陷:不能高效处理断线重连后的复制情况。 + +(2)新版复制基于 `PSYNC` 命令实现。同步操作分为了两块: + +- **`完整重同步(full resychronization)`** 用于初次复制; +- **`部分重同步(partial resychronization)`** 用于断线后重复制。 + - 主从服务器的**复制偏移量(replication offset)** + - 主服务器的**复制积压缓冲区(replication backlog)** + - **服务器的运行 ID** + +(3)Redis 集群主从节点复制的工作流程: + +- 步骤 1. 设置主从服务器 +- 步骤 2. 主从服务器建立 TCP 连接。 +- 步骤 3. 发送 PING 检查通信状态。 +- 步骤 4. 身份验证。 +- 步骤 5. 发送端口信息。 +- 步骤 6. 同步。 +- 步骤 7. 命令传播。 + +## Redis 哨兵 + +【问题】 + +- Redis 如何实现高可用? +- Redis 哨兵的功能? +- Redis 哨兵的原理? +- Redis 哨兵如何选举 Leader? +- Redis 如何实现故障转移? + +--- + +【解答】 + +> **_Redis 哨兵_** +> +> 详情可以参考:[Redis 哨兵](redis-sentinel.md) + +(1)Redis 的高可用是通过哨兵来实现(Raft 协议的 Redis 实现)。Sentinel(哨兵)可以监听主服务器,并在主服务器进入下线状态时,自动从从服务器中选举出新的主服务器。 + +由一个或多个 Sentinel 实例组成的 Sentinel 系统可以监视任意多个主服务器,以及这些主服务器的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。 + +![img](http://dunwu.test.upcdn.net/snap/20200131135847.png) + ## Redis vs. Memcached +【问题】 + +Redis 和 Memcached 有什么区别? + +分布式缓存技术选型,选 Redis 还是 Memcached,为什么? + +Redis 和 Memcached 各自的线程模型是怎样的? + +为什么单线程的 Redis 性能却不输于多线程的 Memcached? + +【解答】 + Redis 不仅仅支持简单的 k/v 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。memcache 支持简单的数据类型,String。 Redis 支持数据的备份,即 master-slave 模式的数据备份。 @@ -223,10 +283,9 @@ Memcached 是多线程,非阻塞 IO 复用的网络模型;Redis 使用单线 如果想要更详细了解的话,可以查看慕课网上的这篇手记(非常推荐) **:《脚踏两只船的困惑 - Memcached 与 Redis》**:[www.imooc.com/article/23549](https://www.imooc.com/article/23549) -### Redis 与 Memcached 的选择 - **终极策略:** 使用 Redis 的 String 类型做的事,都可以用 Memcached 替换,以此换取更好的性能提升; 除此以外,优先考虑 Redis; ## 参考资料 - [面试中关于 Redis 的问题看这篇就够了](https://juejin.im/post/5ad6e4066fb9a028d82c4b66) +- [advanced-java](https://github.com/doocs/advanced-java#缓存) diff --git a/docs/nosql/redis/redis-ops.md b/docs/nosql/redis/redis-ops.md index 65797a4..2e9e0f9 100644 --- a/docs/nosql/redis/redis-ops.md +++ b/docs/nosql/redis/redis-ops.md @@ -276,6 +276,19 @@ Redis 3.0 后支持集群模式。 理想情况当然是所有节点各自在不同的机器上,首先于资源,本人在部署 Redis 集群时,只得到 3 台服务器。所以,我计划每台服务器部署 2 个 Redis 节点。 +【示例】最简高可用 Redis 集群规划 + +机器配置:16G 内存 + 8 核 CPU + 1T 磁盘 + +Redis 进程分配 10 G 内存。一般线上生产环境,Redis 的内存尽量不要超过 10g,超过 10g 可能会有问题。 + +集群拓扑:三主三从;三哨兵,每个哨兵监听所有主节点。 + +估算性能: + +- 容量:三主,占用 30 G 内存,所以最大存储容量为 30 G。假设每条数据记录平均 大小为 10 K,则最大能存储 300 万条数据。 +- 吞吐量:单机一般 TPS/QPS 为 五万到八万左右。假设为五万,那么三主三从架构理论上能达到 TPS 15 万,QPS 30 万。 + ### 部署集群 > Redis 集群节点的安装与单节点服务相同,差异仅在于部署方式。 diff --git a/docs/nosql/redis/redis-pub-sub.md b/docs/nosql/redis/redis-pub-sub.md deleted file mode 100644 index f9fc6be..0000000 --- a/docs/nosql/redis/redis-pub-sub.md +++ /dev/null @@ -1,23 +0,0 @@ -# Redis 发布与订阅 - -Redis 提供了 5 个发布与订阅命令: - -| 命令 | 描述 | -| -------------- | ------------------------------------------------------------------- | -| `SUBSCRIBE` | `SUBSCRIBE channel [channel ...]`—订阅指定频道。 | -| `UNSUBSCRIBE` | `UNSUBSCRIBE [channel [channel ...]]`—取消订阅指定频道。 | -| `PUBLISH` | `PUBLISH channel message`—发送信息到指定的频道。 | -| `PSUBSCRIBE` | `PSUBSCRIBE pattern [pattern ...]`—订阅符合指定模式的频道。 | -| `PUNSUBSCRIBE` | `PUNSUBSCRIBE [pattern [pattern ...]]`—取消订阅符合指定模式的频道。 | - -## 参考资料 - -- **官网** - - [Redis 官网](https://redis.io/) - - [Redis github](https://github.com/antirez/redis) - - [Redis 官方文档中文版](http://redis.cn/) -- **书籍** - - [《Redis 实战》](https://item.jd.com/11791607.html) - - [《Redis 设计与实现》](https://item.jd.com/11486101.html) -- **教程** - - [Redis 命令参考](http://redisdoc.com/) diff --git a/docs/nosql/redis/redis-quickstart.md b/docs/nosql/redis/redis-quickstart.md index cb942a8..4e6aa5a 100644 --- a/docs/nosql/redis/redis-quickstart.md +++ b/docs/nosql/redis/redis-quickstart.md @@ -113,228 +113,11 @@ Redis 是单线程模型(Redis 6.0 已经支持多线程模型),为什么 ## 二、Redis 数据类型 -| 数据类型 | 可以存储的值 | 操作 | -| -------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------- | -| STRING | 字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作
对整数和浮点数执行自增或者自减操作 | -| LIST | 列表 | 从两端压入或者弹出元素
读取单个或者多个元素
进行修剪,只保留一个范围内的元素 | -| SET | 无序集合 | 添加、获取、移除单个元素
检查一个元素是否存在于集合中
计算交集、并集、差集
从集合里面随机获取元素 | -| HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对
获取所有键值对
检查某个键是否存在 | -| ZSET | 有序集合 | 添加、获取、删除元素
根据分值范围或者成员来获取元素
计算一个键的排名 | +Redis 基本数据类型:STRING、HASH、LIST、SET、ZSET -> [What Redis data structures look like](https://redislabs.com/ebook/part-1-getting-started/chapter-1-getting-to-know-redis/1-2-what-redis-data-structures-look-like/) +Redis 高级数据类型:BitMap、HyperLogLog、GEO -### STRING - -
- -
- -应用场景:缓存、计数器、共享 Session - -命令: - -| 命令 | 行为 | -| ----- | ---------------------------------------------------- | -| `GET` | 获取存储在给定键中的值。 | -| `SET` | 设置存储在给定键中的值。 | -| `DEL` | 删除存储在给定键中的值(这个命令可以用于所有类型)。 | - -> 更多命令请参考:[Redis String 类型命令](https://redis.io/commands#string) - -示例: - -```shell -127.0.0.1:6379> set hello world -OK -127.0.0.1:6379> get hello -"jack" -127.0.0.1:6379> del hello -(integer) 1 -127.0.0.1:6379> get hello -(nil) -``` - -### HASH - -
- -
- -场景:适合存储结构化数据,如一个对象:用户信息、产品信息等。 - -命令: - -| 命令 | 行为 | -| --------- | ------------------------------------------ | -| `HSET` | 在散列里面关联起给定的键值对。 | -| `HGET` | 获取指定散列键的值。 | -| `HGETALL` | 获取散列包含的所有键值对。 | -| `HDEL` | 如果给定键存在于散列里面,那么移除这个键。 | - -> 更多命令请参考:[Redis Hash 类型命令](https://redis.io/commands#hash) - -示例: - -```shell -127.0.0.1:6379> hset hash-key sub-key1 value1 -(integer) 1 -127.0.0.1:6379> hset hash-key sub-key2 value2 -(integer) 1 -127.0.0.1:6379> hset hash-key sub-key1 value1 -(integer) 0 -127.0.0.1:6379> hset hash-key sub-key3 value2 -(integer) 0 -127.0.0.1:6379> hgetall hash-key -1) "sub-key1" -2) "value1" -3) "sub-key2" -4) "value2" -127.0.0.1:6379> hdel hash-key sub-key2 -(integer) 1 -127.0.0.1:6379> hdel hash-key sub-key2 -(integer) 0 -127.0.0.1:6379> hget hash-key sub-key1 -"value1" -127.0.0.1:6379> hgetall hash-key -1) "sub-key1" -2) "value1" -``` - -### LIST - -
- -
- -适用场景:用于存储列表型数据。如:粉丝列表、商品列表等。 - -命令: - -| 命令 | 行为 | -| -------- | ------------------------------------------ | -| `RPUSH` | 将给定值推入列表的右端。 | -| `LRANGE` | 获取列表在给定范围上的所有值。 | -| `LINDEX` | 获取列表在给定位置上的单个元素。 | -| `LPOP` | 从列表的左端弹出一个值,并返回被弹出的值。 | - -> 更多命令请参考:[Redis List 类型命令](https://redis.io/commands#list) - -示例: - -```shell -127.0.0.1:6379> rpush list-key item -(integer) 1 -127.0.0.1:6379> rpush list-key item2 -(integer) 2 -127.0.0.1:6379> rpush list-key item -(integer) 3 -127.0.0.1:6379> lrange list-key 0 -1 -1) "item" -2) "item2" -3) "item" -127.0.0.1:6379> lindex list-key 1 -"item2" -127.0.0.1:6379> lpop list-key -"item" -127.0.0.1:6379> lrange list-key 0 -1 -1) "item2" -2) "item" -``` - -### SET - -
- -
- -适用场景:适用于存储不出现重复的列表数据。 - -命令: - -| 命令 | 行为 | -| ----------- | ---------------------------------------------- | -| `SADD` | 将给定元素添加到集合。 | -| `SMEMBERS` | 返回集合包含的所有元素。 | -| `SISMEMBER` | 检查给定元素是否存在于集合中。 | -| `SREM` | 如果给定的元素存在于集合中,那么移除这个元素。 | - -> 更多命令请参考:[Redis Set 类型命令](https://redis.io/commands#set) - -示例: - -```shell -127.0.0.1:6379> sadd set-key item -(integer) 1 -127.0.0.1:6379> sadd set-key item2 -(integer) 1 -127.0.0.1:6379> sadd set-key item3 -(integer) 1 -127.0.0.1:6379> sadd set-key item -(integer) 0 -127.0.0.1:6379> smembers set-key -1) "item" -2) "item2" -3) "item3" -127.0.0.1:6379> sismember set-key item4 -(integer) 0 -127.0.0.1:6379> sismember set-key item -(integer) 1 -127.0.0.1:6379> srem set-key item2 -(integer) 1 -127.0.0.1:6379> srem set-key item2 -(integer) 0 -127.0.0.1:6379> smembers set-key -1) "item" -2) "item3" -``` - -### ZSET - -
- -
- -场景:由于可以设置 score,且不重复。适合存储各种排行数据,如:按评分排序的有序商品集合、按时间排序的有序文章集合。 - -命令: - -| 命令 | 行为 | -| --------------- | ------------------------------------------------------------ | -| `ZADD` | 将一个带有给定分值的成员添加到有序集合里面。 | -| `ZRANGE` | 根据元素在有序排列中所处的位置,从有序集合里面获取多个元素。 | -| `ZRANGEBYSCORE` | 获取有序集合在给定分值范围内的所有元素。 | -| `ZREM` | 如果给定成员存在于有序集合,那么移除这个成员。 | - -> 更多命令请参考:[Redis ZSet 类型命令](https://redis.io/commands#sorted_set) - -示例: - -```shell -127.0.0.1:6379> zadd zset-key 728 member1 -(integer) 1 -127.0.0.1:6379> zadd zset-key 982 member0 -(integer) 1 -127.0.0.1:6379> zadd zset-key 982 member0 -(integer) 0 - -127.0.0.1:6379> zrange zset-key 0 -1 withscores -1) "member1" -2) "728" -3) "member0" -4) "982" - -127.0.0.1:6379> zrangebyscore zset-key 0 800 withscores -1) "member1" -2) "728" - -127.0.0.1:6379> zrem zset-key member1 -(integer) 1 -127.0.0.1:6379> zrem zset-key member1 -(integer) 0 -127.0.0.1:6379> zrange zset-key 0 -1 withscores -1) "member0" -2) "982" -``` +> :bulb: 更详细的特性及原理说明请参考:[Redis 数据类型和应用](redis-datatype.md) ## 三、Redis 内存淘汰 @@ -360,7 +143,7 @@ Redis 可以为每个键设置过期时间,当键过期时,会自动删除 示例: -```py +```shell redis> SET mykey "Hello" "OK" redis> EXPIRE mykey 10 @@ -410,7 +193,6 @@ Redis 是内存型数据库,为了保证数据在宕机后不会丢失,需 Redis 支持两种持久化方式:RDB 和 AOF。 - RDB - **RDB 即快照方式,它将某个时间点的所有 Redis 数据保存到一个经过压缩的二进制文件(RDB 文件)中**。 - - 创建 RDB 后,用户可以对 RDB 进行**备份**,可以将 RDB **复制**到其他服务器从而创建具有相同数据的服务器副本,还可以在**重启**服务器时使用。一句话来说:RDB 适合作为 **冷备**。 - AOF - `AOF(Append Only File)` 是以文本日志形式将所有写命令追加到 AOF 文件的末尾,以此来记录数据的变化。当服务器重启的时候会重新载入和执行这些命令来恢复原始的数据。AOF 适合作为 **热备**。 > :bulb: 更详细的特性及原理说明请参考:[Redis 持久化](redis-persistence.md) @@ -639,6 +421,16 @@ pipe.exec(); ## 八、Redis 发布与订阅 +Redis 提供了 5 个发布与订阅命令: + +| 命令 | 描述 | +| -------------- | ------------------------------------------------------------ | +| `SUBSCRIBE` | `SUBSCRIBE channel [channel ...]`—订阅指定频道。 | +| `UNSUBSCRIBE` | `UNSUBSCRIBE [channel [channel ...]]`—取消订阅指定频道。 | +| `PUBLISH` | `PUBLISH channel message`—发送信息到指定的频道。 | +| `PSUBSCRIBE` | `PSUBSCRIBE pattern [pattern ...]`—订阅符合指定模式的频道。 | +| `PUNSUBSCRIBE` | `PUNSUBSCRIBE [pattern [pattern ...]]`—取消订阅符合指定模式的频道。 | + 订阅者订阅了频道之后,发布者向频道发送字符串消息会被所有订阅者接收到。 某个客户端使用 SUBSCRIBE 订阅一个频道,其它客户端可以使用 PUBLISH 向这个频道发送消息。 @@ -715,7 +507,7 @@ Sentinel(哨兵)可以监听主服务器,并在主服务器进入下线状 - 代理分片:将客户端请求发送到代理上,由代理转发请求到正确的节点上。 - 服务器分片:Redis Cluster(官方的 Redis 集群解决方案)。 -## Redis Client +## 十二、Redis Client Redis 社区中有多种编程语言的客户端,可以在这里查找合适的客户端:[Redis 官方罗列的客户端清单](https://redis.io/clients)