From f435e89a90bcc5415c3958bbce2886f606087548 Mon Sep 17 00:00:00 2001 From: Xargin Date: Sun, 23 Dec 2018 18:27:39 +0800 Subject: [PATCH] fix img for ch5-9 --- ch5-web/ch5-09-gated-launch.md | 48 +++++++++------------------------ images/ch5-set-time-line.png | Bin 0 -> 9710 bytes images/ch5-set-time-line_2.png | Bin 0 -> 11117 bytes 3 files changed, 13 insertions(+), 35 deletions(-) create mode 100644 images/ch5-set-time-line.png create mode 100644 images/ch5-set-time-line_2.png diff --git a/ch5-web/ch5-09-gated-launch.md b/ch5-web/ch5-09-gated-launch.md index 3c240e9..3233ccc 100644 --- a/ch5-web/ch5-09-gated-launch.md +++ b/ch5-web/ch5-09-gated-launch.md @@ -81,35 +81,13 @@ func isTrue(phone string) bool { 这种情况可以按照指定的百分比,返回对应的 true 和 false,和上面的单纯按照概率的区别是这里我们需要调用方提供给我们一个输入参数,我们以该输入参数作为源来计算哈希,并以哈希后的结果来求模,并返回结果。这样可以保证同一个用户的返回结果多次调用是一致的,在下面这种场景下,必须使用这种结果可预期的灰度算法: -```shell - .---------. - ( user_2 ) - `---------' - +--------+ - .---------. | set.V2 |---------------------+ - ( user_1 ) +--------+ | - `---------' | | - +--------+ | | - +--------------| set.V2 | | | - | +--------+ | | - | | | | - v | | v -+-------------+ | | +-------------+ -| storage_v1 | | | | storage_v2 | -+-------------+ | | +-------------+ - | | | | - | | | | - | | | | - | v | | - | +--------+ | | - +------------->| get.V2 | | | - +--------+ | | - | | - v | - +--------+ | - | get.V2 |<--------------------+ - +--------+ -``` +![set 和 get 流程不应该因为灰度走到不同版本的 API](../images/ch5-set-time-line.png) + +如果采用随机策略,可能会出现像下图这样的问题: + +![set 和 get 流程不应该因为灰度走到不同版本的 API](../images/ch5-set-time-line_2.png) + +举个具体的例子,网站的注册环节,可能有两套API,按照用户ID进行灰度,分别是不同的存取逻辑。如果存储时使用了V1版本的API而获取时使用V2版本的API,那么就可能出现用户注册成功后反而返回注册失败消息的诡异问题。 ## 5.9.3 如何实现一套灰度发布系统 @@ -136,7 +114,7 @@ func isPassed(cityID int) bool { } ``` -如果公司给 cityID 赋的值比较大,那么我们可以考虑用 map 来存储映射关系,map 的查询比数组稍慢,但扩展会灵活一些: +如果公司给cityID赋的值比较大,那么我们可以考虑用map来存储映射关系,map的查询比数组稍慢,但扩展会灵活一些: ```go var cityID2Open = map[int]struct{}{} @@ -157,7 +135,7 @@ func isPassed(cityID int) bool { } ``` -按白名单、按业务线、按 UA、按分发渠道发布,本质上和按城市发布是一样的,这里就不再赘述了。 +按白名单、按业务线、按UA、按分发渠道发布,本质上和按城市发布是一样的,这里就不再赘述了。 按概率发布稍微特殊一些,不过不考虑输入实现起来也很简单: @@ -185,7 +163,7 @@ func isPassed(rate int) bool { ### 5.9.3.2 哈希算法 -求哈希可用的算法非常多,比如 md5,crc32,sha1 等等,但我们这里的目的只是为了给这些数据做个映射,并不想要因为计算哈希消耗过多的 cpu,所以现在业界使用较多的算法是 murmurhash,下面是我们对这些常见的 hash 算法的简单 benchmark: +求哈希可用的算法非常多,比如md5,crc32,sha1等等,但我们这里的目的只是为了给这些数据做个映射,并不想要因为计算哈希消耗过多的cpu,所以现在业界使用较多的算法是murmurhash,下面是我们对这些常见的hash算法的简单benchmark: hash.go: @@ -263,13 +241,13 @@ PASS ok _/Users/caochunhui/test/go/hash_bench 7.050s ``` -可见 murmurhash 相比其它的算法有三倍以上的性能提升。 +可见murmurhash相比其它的算法有三倍以上的性能提升。 ### 5.9.3.3 分布是否均匀 对于哈希算法来说,性能是一方面的问题,另一方面还要考虑哈希后的值是否分布均匀。 -我们先以 15810000000 开头,造一千万个和手机号类似的数字,然后将计算后的哈希值分十个桶,并观察计数是否均匀: +我们先以15810000000开头,造一千万个和手机号类似的数字,然后将计算后的哈希值分十个桶,并观察计数是否均匀: ```go package main @@ -301,4 +279,4 @@ map[7:999475 5:1000359 1:999945 6:1000200 3:1000193 9:1000765 2:1000044 \ 4:1000343 8:1000823 0:997853] ``` -偏差基本都在 1/100 以内,是可以接受的。 +偏差都在1/100以内,可以接受。 diff --git a/images/ch5-set-time-line.png b/images/ch5-set-time-line.png new file mode 100644 index 0000000000000000000000000000000000000000..28064b427539b09f8b7b69c485282f9ed05826ca GIT binary patch literal 9710 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 Il8^oV4+OWYDF6Tf literal 0 HcmV?d00001 diff --git a/images/ch5-set-time-line_2.png b/images/ch5-set-time-line_2.png new file mode 100644 index 0000000000000000000000000000000000000000..41d39eebc34b2ce4f1a41e6e7170b8c1ed6697f6 GIT binary patch literal 11117 zcmdsdg;!PE7p~w@5CP92qy-KQ3ew$&Qc_AlK)O4nOE`cajldy9=|%zRZUG4i5s(t; z?s|*gy>j1pf5Kzz!GOK@T6?a!=9=-%FH~7k1_z52>&A^6IC8RxXE$!3^Mk)jFmHq3 zlurjpZ``1|A%_rGbJtr>z57K?{kTI^3@RU2`wC;|$v3F7N{q6+ni@JsMqLnQ7(JHW z&NK8dQ@zJ3@`D7}3f*GzjNF8>S%^hT_oYk-RyHK_MbNIVPw&C;07<`z=|Eai#bMp* ztNvDl{^`{n9V^r6^CGt*^@75}!mnSgC(2ED+%{hLM9@+=w82L6)eB^Ip3%dp(Eq)n z9{Fn{Q4aGR6T1VV>Ff2}dNV~jytP{`cdhCaiI9Gn|6XDv5X(n;bziL8kT8`cowON3 z%@+o#0xmr|7d_7*2(f=JW*X(yK^e+NDMGItr~mA&jtv~C;Gw~w|6KkOcu`$Uv^Mc{ ze?PDM7#)xQmSj=D^$b{Y8PB5eT|F%NlDT=Det*Tl!KsuK8Lj_&xycO( z&~O;F!thrlXqX?E@BjB#UcvYu=~R9WyeBgLqteEzNV}r^{v++9e(`<$zuP5C>@O?T zU)K4+>ilFsHdk((O2z5lZK8^V!14LVblp>H)cQ*3n>g*)}B;k4eWK=0|*U>LVHq+gOZ?C<`yrHBRI#<8BPv~gX|O8oI%Q=j6=8UpSZz}WxZ zjrG&(0$wQzmlg}pi5quPWuG(S|7&?jGXFB8&L8obdKQyac2(LHmJ?gEt)K1-Mu(vc zhDFQEoJ6{l<~R1OCJUQStyY-LVtW2s^xV@7i{b2pZU+73FpvEelSi&_LVmS?ynK~` z;tImc-C5)C0}LC|AG!0%iweJ9c&=CQSdQdc7i6tU{hdOHO1a8bciwEiBZ7OB{#i7q zP4{iV?0weJTptRZQjgf}%UcD!lQnFW)t8rU!v|P|mQ`lnR%(rv_*@|y>N6e{6W^z5 z&xVUOPV{VAQX(v^t68D`mY9Xw6+HrO8`grGb)RrZINDyz#m7kbU7T;V-Yat3obLab zON$QwMTu4d=kNSk)gomNW$66;qrK)rY0EeOM}^aKV#)T_{WWXxwuIt*XgC9bG&l%^jo3>t`tl|}E zlnwiBUWoM5hwN0=FuM$-SSP=T@9L(1`%60%^?1Zt={b6VW=ZA6`Drb(?___q_mlX- zTIHl|rTwf#3ZH}F_?k;P1|;F3mLWr$dnUCrkIl(Sa~Q>hzWeO0Nw8*uzU_>+YPVpr zbWv5_j<<2i|4g4H(MQ@*$t@T^ksmuoyae9Qb<(D4BH@va_3CH|Pcb$g-0aV{_Z@Xx zz8AZcRzn{{mDDwLIcS^W)CSUoSumg5n#8gr9-Z1p5%hIKb6N5I-$9XW?m{jrYN4oi z&R_DYY5W_!PivOLJ0i#g-%E1kD5eT*xFPzxqG@cJ{Lp|K6C{Z;;`966pK1mCZ8=z0 z?Kw}w+0N4f-P+32#8*Cgr-zM~MdpgwryA<_{gW|e7e)}WzHChBLW7?kI_xZTSK3b1 zI7V|i{g!92Hx`RrvM1)XMeWXU*-ih96ge@snyRS~zC7Di{PR%1;b(oZxuVdiM#X*q z6)=;z7qaOR^P@=LK)UD*unr?4UFYa2kJX|LEctv6s!q=@LWe({TqjHtwZ1iSntru! ztg;xE9z?mj6>y^l=`x9?|=Il3bvDO*OO-GdH z_*&to{&HLjf$>s<))$h=+*YQl+45z;gV$WLB;#*hsIN;=rHW<2WeN(ol%GV1(WhZo z-cLm1Z=jif4hX={nc6>=qvhM<&9%ckh0p{`<)&B&e+`$Awu0;=i+{txdUm>sYDdOdy7=ZRjCfpStp zwy`@4{IkP-Bv9lW)A={adoE;<9zPV?7F;)`X!iLa3hojYM(8gDL#i!6Tu>EzPAPnL zsoR@jE`&-h#rYKL2ZeSw1=eiqe{g+Hh*4>#ye0Izd-unOx-{r;=p+BSaFlsL!A}I0+tup<+FgDqPu~TWkkViy zDW{$9G(DQv+h7R0gE&`Xz3B)O{1lw>@LMzQ~8J2Bak9=#h*6&+i6p=M=C1vMdH zV0?1h_%c|x_-c}~Rn_mZkQQJdcO(@K+hW8T(mG7U4(#|427DS^osB-~5eO&la>F>Z%Z-5H2K7zH?GS_rc4ydcf<}Gyn=s6$VsM6s{8L1C(O-wn-H^P! zFozrJMH)%i$7DN`@BIHfhkzBZPM3D&Tc40H9%bR zlZ`dL=2(+N-4#W@Yr>~!r^Vi>HOo|hfFUWt3rG7&mMAoTLn((`(%a*veaY3nDO?sY z;x;aFtPm`VtH~16hU($U?qJQY&5H4M<(oostl)R$b#N#}ga(S#4_@<-vm}3DXF%Vk zri#W-Z+ND_Nvr&oQBhe6yKBVg;_R4YR6FrC-LF85o)C7Tg!B!3e_H≧+}|gqM?E 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 literal 0 HcmV?d00001