From 0f92b0ae549ee9ecc8c29d609815625f3b52f6ba Mon Sep 17 00:00:00 2001 From: Xargin Date: Sat, 16 Jun 2018 18:45:38 +0800 Subject: [PATCH 1/7] update rl --- ch5-web/ch5-06-ratelimit.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ch5-web/ch5-06-ratelimit.md b/ch5-web/ch5-06-ratelimit.md index c9b8100..98bbff8 100644 --- a/ch5-web/ch5-06-ratelimit.md +++ b/ch5-web/ch5-06-ratelimit.md @@ -246,6 +246,10 @@ func TakeAvailable(block bool) bool{ TODO -## 题外话: 分布式流量限制 +## 服务瓶颈和 QoS -TODO,在线系统应该保证 CPU 资源的余量,以确保 QoS,不应完全把资源用暴。 +前面我们说了很多 CPU-bound、IO-bound 之类的概念,这种性能瓶颈从大多数公司都有的监控系统中可以比较快速地定位出来,如果一个系统遇到了性能问题,那监控图的反应一般都是最快的。 + +虽然性能指标很重要,但对用户提供服务时还应考虑服务整体的 QoS。QoS 全称是 Quality of Service,顾名思义是服务质量。QoS 包含有可用性、吞吐量、时延、时延变化和丢失等指标。一般来讲我们可以通过优化系统,来提高 web 服务的 CPU 利用率,从而提高整个系统的吞吐量。但吞吐量提高的同时,用户体验是有可能变差的。用户角度比较敏感的除了可用性之外,还有时延。虽然你的系统吞吐量高,但半天刷不开页面,想必会造成大量的用户流失。所以在大公司的 web 服务性能指标中,除了平均响应时延之外,还会把响应时间的 95 分位,99 分位也拿出来作为性能标准。平均响应在提高 CPU 利用率没受到太大影响时,可能 95 分位、 99 分位的响应时间大幅度攀升了,那么这时候就要考虑提高这些 CPU 利用率所付出的代价是否值得了。 + +在线系统的机器一般都会保持 CPU 有一定的余裕。 From 0b603e1887176d0d95ca705b420a4e91f76eed26 Mon Sep 17 00:00:00 2001 From: Xargin Date: Sat, 16 Jun 2018 22:08:53 +0800 Subject: [PATCH 2/7] add ratelimit to catalog --- SUMMARY.md | 1 + ch5-web/ch5-06-ratelimit.md | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/SUMMARY.md b/SUMMARY.md index e2e1ac5..d0c6567 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -45,6 +45,7 @@ * [5.3. Middleware中间件](ch5-web/ch5-03-middleware.md) * [5.4. Validator请求校验](ch5-web/ch5-04-validator.md) * [5.5. Database和数据库打交道](ch5-web/ch5-05-database.md) + * [# 5.6. Ratelimit 服务流量限制](ch5-web/ch5-06-ratelimit.md) * [5.7. Layout大型web项目分层](ch5-web/ch5-07-layout-of-web-project.md) * [5.9. 灰度发布和 A/B test](ch5-web/ch5-09-gated-launch.md) * [5.11. Load-balance负载均衡](ch5-web/ch5-11-load-balance.md) diff --git a/ch5-web/ch5-06-ratelimit.md b/ch5-web/ch5-06-ratelimit.md index 98bbff8..d950a2f 100644 --- a/ch5-web/ch5-06-ratelimit.md +++ b/ch5-web/ch5-06-ratelimit.md @@ -244,7 +244,14 @@ func TakeAvailable(block bool) bool{ 一些公司自己造的限流的轮子就是用上面这种方式来实现的,不过如果开源版 ratelimit 也如此的话,那我们也没什么可说的了。现实并不是这样的。 -TODO +我们来思考一下,令牌桶每隔一段固定的时间向桶中放令牌,如果我们记下上一次放令牌的时间为 t1,和当时的令牌数 k1,放令牌的时间间隔为 ti,每次向令牌桶中放 x 个令牌,令牌桶容量为 cap。现在如果有人来调用 `TakeAvailable` 来取 n 个令牌,我们将这个时刻记为 t2。在 t2 时刻,令牌桶中理论上应该有多少令牌呢? + +> cur = k1 + ((t2 - t1)/ti) * x +> cur = cur > cap ? cap : cur + +我们用两个时间点的时间差,再结合其它的参数,理论上在取令牌之前就完全可以知道桶里有多少令牌了。那劳心费力地像本小节前面向 channel 里填充 token 的操作,理论上是没有必要的。只要在每次 `Take` 的时候,再对令牌桶中的 token 数进行简单计算,就可以得到正确的令牌数。是不是很像 `惰性求值` 的感觉? + +在得到正确的令牌数之后,再进行实际的 Take 操作就好,这个 Take 操作只需要对令牌数进行简单的减法即可,记得加锁以保证并发安全。`github.com/juju/ratelimit` 这个库就是这样做的。 ## 服务瓶颈和 QoS From 67c96a8b1f22881d5afb0ad99845fade2799751f Mon Sep 17 00:00:00 2001 From: Xargin Date: Sat, 16 Jun 2018 22:10:04 +0800 Subject: [PATCH 3/7] fix typo --- SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.md b/SUMMARY.md index d0c6567..b8ccb5b 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -45,7 +45,7 @@ * [5.3. Middleware中间件](ch5-web/ch5-03-middleware.md) * [5.4. Validator请求校验](ch5-web/ch5-04-validator.md) * [5.5. Database和数据库打交道](ch5-web/ch5-05-database.md) - * [# 5.6. Ratelimit 服务流量限制](ch5-web/ch5-06-ratelimit.md) + * [5.6. Ratelimit 服务流量限制](ch5-web/ch5-06-ratelimit.md) * [5.7. Layout大型web项目分层](ch5-web/ch5-07-layout-of-web-project.md) * [5.9. 灰度发布和 A/B test](ch5-web/ch5-09-gated-launch.md) * [5.11. Load-balance负载均衡](ch5-web/ch5-11-load-balance.md) From f6af94243a8e6c85ae8725736106bf25cff139b7 Mon Sep 17 00:00:00 2001 From: Xargin Date: Sat, 16 Jun 2018 22:16:06 +0800 Subject: [PATCH 4/7] add image --- ch5-web/ch5-06-ratelimit.md | 1 + images/ch6-06-leaky-bucket.jpg | Bin 0 -> 17691 bytes 2 files changed, 1 insertion(+) create mode 100644 images/ch6-06-leaky-bucket.jpg diff --git a/ch5-web/ch5-06-ratelimit.md b/ch5-web/ch5-06-ratelimit.md index d950a2f..e73693b 100644 --- a/ch5-web/ch5-06-ratelimit.md +++ b/ch5-web/ch5-06-ratelimit.md @@ -109,6 +109,7 @@ Transfer/sec: 5.51MB 这两种方法看起来很像,不过还是有区别的。漏桶流出的速率固定,而令牌桶只要在桶中有令牌,那就可以拿。也就是说令牌桶是允许一定程度的并发的,比如同一个时刻,有 100 个用户请求,只要令牌桶中有 100 个令牌,那么这 100 个请求全都会放过去。令牌桶在桶中没有令牌的情况下也会退化为漏桶模型。 TODO,这里需要画漏桶和令牌桶的图 +![leaky bucket](../images/ch6-06-leaky-bucket.jpg) 实际应用中令牌桶应用较为广泛,开源界流行的限流器大多数都是基于令牌桶思想的。并且在此基础上进行了一定程度的扩充,比如 `github.com/juju/ratelimit` 提供了几种不同特色的令牌桶填充方式: diff --git a/images/ch6-06-leaky-bucket.jpg b/images/ch6-06-leaky-bucket.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6722e6277c0b1f5d597a44816b2e519a5d173a4a GIT binary patch literal 17691 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 NGx6q Date: Sat, 16 Jun 2018 22:16:37 +0800 Subject: [PATCH 5/7] =?UTF-8?q?remove=20todo=EF=BC=8C=E6=9C=AA=E6=9D=A5?= =?UTF-8?q?=E8=BF=99=E9=87=8C=E7=9A=84=E5=9B=BE=E8=BF=98=E8=A6=81=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E7=94=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch5-web/ch5-06-ratelimit.md | 1 - 1 file changed, 1 deletion(-) diff --git a/ch5-web/ch5-06-ratelimit.md b/ch5-web/ch5-06-ratelimit.md index e73693b..366e8f9 100644 --- a/ch5-web/ch5-06-ratelimit.md +++ b/ch5-web/ch5-06-ratelimit.md @@ -108,7 +108,6 @@ Transfer/sec: 5.51MB 这两种方法看起来很像,不过还是有区别的。漏桶流出的速率固定,而令牌桶只要在桶中有令牌,那就可以拿。也就是说令牌桶是允许一定程度的并发的,比如同一个时刻,有 100 个用户请求,只要令牌桶中有 100 个令牌,那么这 100 个请求全都会放过去。令牌桶在桶中没有令牌的情况下也会退化为漏桶模型。 -TODO,这里需要画漏桶和令牌桶的图 ![leaky bucket](../images/ch6-06-leaky-bucket.jpg) 实际应用中令牌桶应用较为广泛,开源界流行的限流器大多数都是基于令牌桶思想的。并且在此基础上进行了一定程度的扩充,比如 `github.com/juju/ratelimit` 提供了几种不同特色的令牌桶填充方式: From adfa34fd1be2f91f670c633deaa8292e04fd17b0 Mon Sep 17 00:00:00 2001 From: Xargin Date: Sat, 16 Jun 2018 22:18:05 +0800 Subject: [PATCH 6/7] fix fomula --- ch5-web/ch5-06-ratelimit.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ch5-web/ch5-06-ratelimit.md b/ch5-web/ch5-06-ratelimit.md index 366e8f9..2eb1cf1 100644 --- a/ch5-web/ch5-06-ratelimit.md +++ b/ch5-web/ch5-06-ratelimit.md @@ -244,10 +244,12 @@ func TakeAvailable(block bool) bool{ 一些公司自己造的限流的轮子就是用上面这种方式来实现的,不过如果开源版 ratelimit 也如此的话,那我们也没什么可说的了。现实并不是这样的。 -我们来思考一下,令牌桶每隔一段固定的时间向桶中放令牌,如果我们记下上一次放令牌的时间为 t1,和当时的令牌数 k1,放令牌的时间间隔为 ti,每次向令牌桶中放 x 个令牌,令牌桶容量为 cap。现在如果有人来调用 `TakeAvailable` 来取 n 个令牌,我们将这个时刻记为 t2。在 t2 时刻,令牌桶中理论上应该有多少令牌呢? +我们来思考一下,令牌桶每隔一段固定的时间向桶中放令牌,如果我们记下上一次放令牌的时间为 t1,和当时的令牌数 k1,放令牌的时间间隔为 ti,每次向令牌桶中放 x 个令牌,令牌桶容量为 cap。现在如果有人来调用 `TakeAvailable` 来取 n 个令牌,我们将这个时刻记为 t2。在 t2 时刻,令牌桶中理论上应该有多少令牌呢?伪代码如下: -> cur = k1 + ((t2 - t1)/ti) * x -> cur = cur > cap ? cap : cur +```go +cur = k1 + ((t2 - t1)/ti) * x +cur = cur > cap ? cap : cur +``` 我们用两个时间点的时间差,再结合其它的参数,理论上在取令牌之前就完全可以知道桶里有多少令牌了。那劳心费力地像本小节前面向 channel 里填充 token 的操作,理论上是没有必要的。只要在每次 `Take` 的时候,再对令牌桶中的 token 数进行简单计算,就可以得到正确的令牌数。是不是很像 `惰性求值` 的感觉? From 2e57dac359f34996190fbf5cb08d51551d7043d0 Mon Sep 17 00:00:00 2001 From: chai2010 Date: Sat, 16 Jun 2018 23:54:41 +0800 Subject: [PATCH 7/7] =?UTF-8?q?ch3:=20=E5=A2=9E=E5=8A=A0=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E6=A0=88=E5=B8=A7=E5=B8=83=E5=B1=80=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch3-asm/ch3-04-func.md | 2 + images/ch3-func-call-frame-01.ditaa.png | Bin 0 -> 36895 bytes images/ch3-func-call-frame-01.ditaa.txt | 51 ++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 images/ch3-func-call-frame-01.ditaa.png create mode 100644 images/ch3-func-call-frame-01.ditaa.txt diff --git a/ch3-asm/ch3-04-func.md b/ch3-asm/ch3-04-func.md index 389af30..9c52767 100644 --- a/ch3-asm/ch3-04-func.md +++ b/ch3-asm/ch3-04-func.md @@ -191,6 +191,8 @@ func Foo() { 在前文中我们已经学习过一些汇编实现的函数参数和返回值处理的规则。那么一个显然的问题是,汇编函数的参数是从哪里来的?答案同样明显,被调用函数的参数是有调用方准备的:调用方在栈上设置好空间和数据后调用函数,被调用方在返回前将返回值放如对应的位置,函数通过RET指令返回调用放函数之后,调用方从返回值对应的栈内存位置取出结果。Go语言函数的调用参数和返回值均是通过栈传输的,这样做的有点是函数调用栈比较清晰,缺点是函数调用有一定的性能损耗(Go编译器是通过函数内联来缓解这个问题的影响)。 +![](../images/ch3-func-call-frame-01.ditaa.png) + 为了便于演示,我们先用Go语言构造foo和bar两个函数,其中foo函数内部调用bar函数: ```go diff --git a/images/ch3-func-call-frame-01.ditaa.png b/images/ch3-func-call-frame-01.ditaa.png new file mode 100644 index 0000000000000000000000000000000000000000..14aa74ca6665b486f4b9fdd4a5f05d3ac920a1e9 GIT binary patch literal 36895 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 H)#v{Jr&PMj literal 0 HcmV?d00001 diff --git a/images/ch3-func-call-frame-01.ditaa.txt b/images/ch3-func-call-frame-01.ditaa.txt new file mode 100644 index 0000000..e5e77f6 --- /dev/null +++ b/images/ch3-func-call-frame-01.ditaa.txt @@ -0,0 +1,51 @@ + function call frame + ++----------+<-=-g.stack.hi +| stack | +| cRED | func main() +| | main frame ++----------+<-=-----+----------+ +| main | | cGRE | +| cGRE | | local | func printsum(a, b int) +| | | | printsum frame +| | +----------+ +----------+ +| | | | : | +| | | +8(SP) |----=--->| b+8(FP) | +| call | +8(SP)| cPNK | arg b | cGRE |b+8(FP) +| printsum | +----------+ +----------+ +| | | | : | +| | | +0(SP) |----=--->| a+0(FP) | +| | +0(SP)| cPNK | arg a | cGRE |a+0(FP) ++----------+<-=-----+----------+<-=------+----------+ +| printsum | | | +| cYEL | |var c int | func sum(a, b int) int +| | | cYEL |c-8(SP) sum frame +| | +----------+ +----------+ +| call sum | | | : | +| | | sum.ret |<----=---|ret+24(FP)| +| | +16(SP)| cPNK | return | |ret+16(FP) +| | +----------+ +----------+ +| | | | : | +| | | sum.b |-----=-->| b+8(FP) | +| | +8(SP)| cPNK | arg b | |b+8(FP) +| | +----------+ +----------+ +| | | | : | +| | | sum.a |-----=-->| a+0(FP) | +| | +0(SP)| cPNK | arg a | |a+0(FP) ++----------+<-=--------------------------+----------+<-=------+----------+ +| func sum | | cBLU |t-8(SP) +| cBLU | | local | +| ret a+b | | | ++----------+<-=-----------------------------------------------+----------++0(SP) +| cAAA |+0(SP) +| unused | +| | +| | +| | +| | ++----------+<-=-g.stack.lo +| cRED | +|StackLimit| +|StackGuard| ++----------+ +