mirror of
https://github.com/chai2010/advanced-go-programming-book.git
synced 2025-05-24 04:22:22 +00:00
fix 5-6
This commit is contained in:
parent
2a57def713
commit
c718dec526
@ -1,12 +1,12 @@
|
||||
# 5.6 Ratelimit 服务流量限制
|
||||
|
||||
计算机程序可依据其瓶颈分为 Disk IO-bound,CPU-bound,Network-bound,分布式场景下有时候也会外部系统而导致自身瓶颈。
|
||||
计算机程序可依据其瓶颈分为磁盘IO瓶颈型,CPU计算瓶颈型,网络带宽瓶颈型,分布式场景下有时候也会外部系统而导致自身瓶颈。
|
||||
|
||||
Web 系统打交道最多的是网络,无论是接收,解析用户请求,访问存储,还是把响应数据返回给用户,都是要走网络的。在没有 epoll/kqueue 之类的系统提供的 IO 多路复用接口之前,多个核心的现代计算机最头痛的是 C10k 问题,C10k 问题会导致计算机没有办法充分利用 CPU 来处理更多的用户连接,进而没有办法通过优化程序提升 CPU 利用率来处理更多的请求。
|
||||
Web系统打交道最多的是网络,无论是接收,解析用户请求,访问存储,还是把响应数据返回给用户,都是要走网络的。在没有`epoll/kqueue`之类的系统提供的IO多路复用接口之前,多个核心的现代计算机最头痛的是C10k问题,C10k问题会导致计算机没有办法充分利用CPU来处理更多的用户连接,进而没有办法通过优化程序提升CPU利用率来处理更多的请求。
|
||||
|
||||
自从 Linux 实现了 epoll,FreeBSD 实现了 kqueue,这个问题基本解决了,我们可以借助内核提供的 API 轻松解决当年的 C10k 问题,也就是说如今如果你的程序主要是和网络打交道,那么瓶颈一定在用户程序而不在操作系统内核。
|
||||
自从Linux实现了`epoll`,FreeBSD实现了`kqueue`,这个问题基本解决了,我们可以借助内核提供的API轻松解决当年的C10k问题,也就是说如今如果你的程序主要是和网络打交道,那么瓶颈一定在用户程序而不在操作系统内核。
|
||||
|
||||
随着时代的发展,编程语言对这些系统调用又进一步进行了封装,如今做应用层开发,几乎不会在程序中看到 epoll 之类的字眼,大多数时候我们就只要聚焦在业务逻辑上就好。Go 的 net 库针对不同平台封装了不同的 syscall API,http 库又是构建在 net 库之上,所以在 Go 我们可以借助标准库,很轻松地写出高性能的 http 服务,下面是一个简单的 `hello world` 服务的代码:
|
||||
随着时代的发展,编程语言对这些系统调用又进一步进行了封装,如今做应用层开发,几乎不会在程序中看到`epoll`之类的字眼,大多数时候我们就只要聚焦在业务逻辑上就好。Go 的 net 库针对不同平台封装了不同的syscall API,`http`库又是构建在`net`库之上,所以在Go语言中我们可以借助标准库,很轻松地写出高性能的`http`服务,下面是一个简单的`hello world`服务的代码:
|
||||
|
||||
```go
|
||||
package main
|
||||
@ -87,13 +87,13 @@ Requests/sec: 45118.57
|
||||
Transfer/sec: 5.51MB
|
||||
```
|
||||
|
||||
多次测试的结果在 4w 左右的 QPS 浮动,响应时间最多也就是 40ms 左右,对于一个Web程序来说,这已经是很不错的成绩了,我们只是照抄了别人的示例代码,就完成了一个高性能的 `hello world` 服务器,是不是很有成就感?
|
||||
多次测试的结果在4万左右的QPS浮动,响应时间最多也就是40ms左右,对于一个Web程序来说,这已经是很不错的成绩了,我们只是照抄了别人的示例代码,就完成了一个高性能的`hello world`服务器,是不是很有成就感?
|
||||
|
||||
这还只是家用PC,线上服务器大多都是24核心起,32G内存+,CPU基本都是Intel i7。所以同样的程序在服务器上运行会得到更好的结果。
|
||||
|
||||
这里的 `hello world` 服务没有任何业务逻辑。真实环境的程序要复杂得多,有些程序偏 Network-bound,例如一些 cdn 服务、proxy 服务;有些程序偏 CPU/GPU bound,例如登陆校验服务、图像处理服务;有些程序偏 Disk IO-bound,例如专门的存储系统,数据库。不同的程序瓶颈会体现在不同的地方,这里提到的这些功能单一的服务相对来说还算容易分析。如果碰到业务逻辑复杂代码量巨大的模块,其瓶颈并不是三下五除二可以推测出来的,还是需要从压力测试中得到更为精确的结论。
|
||||
这里的`hello world`服务没有任何业务逻辑。真实环境的程序要复杂得多,有些程序偏Network-bound,例如一些cdn服务、proxy服务;有些程序偏CPU/GPU bound,例如登陆校验服务、图像处理服务;有些程序瓶颈偏磁盘,例如专门的存储系统,数据库。不同的程序瓶颈会体现在不同的地方,这里提到的这些功能单一的服务相对来说还算容易分析。如果碰到业务逻辑复杂代码量巨大的模块,其瓶颈并不是三下五除二可以推测出来的,还是需要从压力测试中得到更为精确的结论。
|
||||
|
||||
对于 IO/Network bound 类的程序,其表现是网卡/磁盘 IO 会先于 CPU 打满,这种情况即使优化 CPU 的使用也不能提高整个系统的吞吐量,只能提高磁盘的读写速度,增加内存大小,提升网卡的带宽来提升整体性能。而 CPU bound 类的程序,则是在存储和网卡未打满之前 CPU 占用率提前到达 100%,CPU 忙于各种计算任务,IO 设备相对则较闲。
|
||||
对于IO/Network瓶颈类的程序,其表现是网卡/磁盘IO会先于CPU打满,这种情况即使优化CPU的使用也不能提高整个系统的吞吐量,只能提高磁盘的读写速度,增加内存大小,提升网卡的带宽来提升整体性能。而CPU bound类的程序,则是在存储和网卡未打满之前CPU占用率提前到达100%,CPU忙于各种计算任务,IO设备相对则较闲。
|
||||
|
||||
无论哪种类型的服务,在资源使用到极限的时候都会导致请求堆积,超时,系统hang死,最终伤害到终端用户。对于分布式的Web服务来说,瓶颈还不一定总在系统内部,也有可能在外部。非计算密集型的系统往往会在关系型数据库环节失守,而这时候Web模块本身还远远未达到瓶颈。
|
||||
|
||||
@ -110,6 +110,8 @@ Transfer/sec: 5.51MB
|
||||
|
||||

|
||||
|
||||
*图 5-12 令牌桶*
|
||||
|
||||
实际应用中令牌桶应用较为广泛,开源界流行的限流器大多数都是基于令牌桶思想的。并且在此基础上进行了一定程度的扩充,比如`github.com/juju/ratelimit`提供了几种不同特色的令牌桶填充方式:
|
||||
|
||||
```go
|
||||
@ -122,13 +124,13 @@ func NewBucket(fillInterval time.Duration, capacity int64) *Bucket
|
||||
func NewBucketWithQuantum(fillInterval time.Duration, capacity, quantum int64) *Bucket
|
||||
```
|
||||
|
||||
和普通的 NewBucket 的区别是,每次向桶中放令牌时,是放 quantum 个令牌,而不是一个令牌。
|
||||
和普通的`NewBucket()`的区别是,每次向桶中放令牌时,是放`quantum`个令牌,而不是一个令牌。
|
||||
|
||||
```go
|
||||
func NewBucketWithRate(rate float64, capacity int64) *Bucket
|
||||
```
|
||||
|
||||
这个就有点特殊了,会按照提供的比例,每秒钟填充令牌数。例如 capacity 是 100,而 rate 是 0.1,那么每秒会填充 10 个令牌。
|
||||
这个就有点特殊了,会按照提供的比例,每秒钟填充令牌数。例如`capacity`是100,而`rate`是0.1,那么每秒会填充10个令牌。
|
||||
|
||||
从桶中获取令牌也提供了几个API:
|
||||
|
||||
@ -259,7 +261,7 @@ cur = cur > cap ? cap : cur
|
||||
|
||||
## 5.6.3 服务瓶颈和 QoS
|
||||
|
||||
前面我们说了很多 CPU-bound、IO-bound 之类的概念,这种性能瓶颈从大多数公司都有的监控系统中可以比较快速地定位出来,如果一个系统遇到了性能问题,那监控图的反应一般都是最快的。
|
||||
前面我们说了很多CPU瓶颈、IO瓶颈之类的概念,这种性能瓶颈从大多数公司都有的监控系统中可以比较快速地定位出来,如果一个系统遇到了性能问题,那监控图的反应一般都是最快的。
|
||||
|
||||
虽然性能指标很重要,但对用户提供服务时还应考虑服务整体的QoS。QoS全称是Quality of Service,顾名思义是服务质量。QoS包含有可用性、吞吐量、时延、时延变化和丢失等指标。一般来讲我们可以通过优化系统,来提高Web服务的CPU利用率,从而提高整个系统的吞吐量。但吞吐量提高的同时,用户体验是有可能变差的。用户角度比较敏感的除了可用性之外,还有时延。虽然你的系统吞吐量高,但半天刷不开页面,想必会造成大量的用户流失。所以在大公司的Web服务性能指标中,除了平均响应时延之外,还会把响应时间的95分位,99分位也拿出来作为性能标准。平均响应在提高CPU利用率没受到太大影响时,可能95分位、99分位的响应时间大幅度攀升了,那么这时候就要考虑提高这些CPU利用率所付出的代价是否值得了。
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user