Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes
File renamed without changes
File renamed without changes
Binary file added images/20200109-golang-gc-deep-01.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-02.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-03.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-04.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-05.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-06.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-07.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-08.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-09.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-10.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-11.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-12.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-13.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-14.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-15.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-16.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-17.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-18.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200109-golang-gc-deep-19.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200119-nginx_api.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/20200318mysql_redo.png
Binary file added images/20201028-influx.jpg
Binary file added images/20201210-callstack.png
Binary file added images/2021/20210716-01connect.png
Binary file added images/2021/20211228-01-env.png
Binary file added images/2021/20211228-02-arch.png
Binary file added images/2021/20211228-03-iptables-exec.png
Binary file added images/2021/20211228-04-iptables-docker.png
Binary file added images/2021/20211228-05-iptables-host.png
Binary file added images/20210219-01wlxy.jpg
Binary file added images/20210219-02tcp_3.jpg
Binary file added images/20210219-03tcp_4.jpg
Binary file added images/20210219-04dns.jpg
Binary file added images/20210618-tcp-congestion.jpg
Binary file added images/20210618-tcp-sliding-window.webp
Binary file added images/20210620-congestion.png
Binary file added images/20210620-osi.png
Binary file added images/20210620-tcp.png
2 changes: 1 addition & 1 deletion markdown/2019/20190909go的协程调度整理.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ go的协程调度整理
三个线程模型图例:

<center>
<img src="https://github.com/alwaysthanks/learning-docs/blob/master/images/1568024209257.png">
<img src="https://github.com/alwaysthanks/learning-docs/blob/master/images/20190909-threads.png">
</center>

(2). 内核调度
Expand Down
12 changes: 4 additions & 8 deletions markdown/2019/20191217golang_pprof使用.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,9 @@ pprof是golang对于runtime运行时进行系统状态监控的工具。golang
(1).封装pprof类库,参见[go-libs/pprof](https://github.com/alwaysthanks/learning-docs/blob/master/go-libs/pprof/pprof.go)

```
//cpu采样函数
StartCpuProf()
StopCpuProf()
//内存采样
SaveMemProf()
//goroutine数量采样
SaveGoroutineProfile()
<center>
<img src="https://github.com/alwaysthanks/learning-docs/blob/master/images/20191222-01http-pool.png">
</center>
```

(2).嵌入代码用例等进行采样
Expand Down Expand Up @@ -131,7 +127,7 @@ X轴代表采样总量。从左到右并不代表时间变化,从左到右也
- `alloc_space`用于查看堆内存的累计分配,通过`web`查看内存堆积处

<center>
<img src="https://github.com/alwaysthanks/learning-docs/blob/master/images/20191218105106.png">
<img src="https://github.com/alwaysthanks/learning-docs/blob/master/images/20191217-01pprof.png">
</center>


Expand Down
3 changes: 1 addition & 2 deletions markdown/2019/20191222golang之http连接池.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
在http早期,每个http请求都要求打开一个tpc socket连接,并且使用一次之后就断开这个tcp连接。
使用keep-alive可以改善这种状态,即在一次TCP连接中可以持续发送多份数据而不会断开连接。通过使用keep-alive机制,可以减少tcp连接建立次数,也意味着可以减少TIME_WAIT状态连接,以此提高性能和提高httpd服务器的吞吐率(更少的tcp连接意味着更少的系统内核调用,socket的accept()和close()调用)。
<center>
<img src="https://github.com/alwaysthanks/learning-docs/blob/master/images/20191222180715.png">
<img src="https://github.com/alwaysthanks/learning-docs/blob/master/images/20191222-01http-pool.png">
</center>

在HTTP/1.0,为了实现client到web-server能支持长连接,必须在HTTP请求头里显示指定:
`Connection:keep-alive`
在HTTP/1.1,就默认是开启了keep-alive,要关闭keep-alive需要在HTTP请求头里显示指定:
Expand Down
6 changes: 4 additions & 2 deletions markdown/2019/20191222golang之栈.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@
##### (1)分段栈

<center>
<img src="https://github.com/alwaysthanks/learning-docs/blob/master/images/image-20191222135530268.png">
<img src="https://github.com/alwaysthanks/learning-docs/blob/master/images/20191222-01segment-stack.png">
</center>


对于分段栈(Segmented stacks), 如上图,当G调用H的时候,没有足够的栈空间来让H运行,这时候Go运行环境就会从堆里分配一个新的栈内存块去让H运行。在H返回到G之前,新分配的内存块被释放回堆。这种管理栈的方法一般都工作得很好。但对有些代码,特别是递归调用,它会造成程序不停地分配和释放新的内存空间。举个例子,在一个程序里,函数G会在一个循环里调用很多次H函数。每次调用都会分配一块新的内存空间。这就是热分裂问题(hot split problem)。

- 优点:动态扩展,初始成本小,可以将协程当作廉价资源使用。
Expand All @@ -34,9 +35,10 @@
##### (2)连续栈

<center>
<img src="https://github.com/alwaysthanks/learning-docs/blob/master/images/image-20191222135826148.png">
<img src="https://github.com/alwaysthanks/learning-docs/blob/master/images/20191222-02continuous-stack.png">
</center>


- 优点:动态扩展,初始成本小,可以将协程当作廉价资源使用,且不存在hot split problem问题
- 缺点:由于通常以2倍扩展,当请求量密集,内存敏感的情况下,内存会消耗比较多,容易oom,当然,通常的业务量是ok的,不会有任何问题。同时100w连接才要考虑优化。

Expand Down
54 changes: 27 additions & 27 deletions markdown/2020/20200108-golang之gc入门篇.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Golang GC系列共分为三篇. 分别为:

### 1.GC相关概念

#### GC简介
#### 1.1 GC简介

垃圾回收(英语:Garbage Collection,缩写为GC)是一种自动内存管理机制. 垃圾回收器(Garbage Collector)尝试回收不再被程序所需要的对象所占用的内存. GC最早起源于LISP语言, 1959年左右由John McCarthy创造用以简化LISP中的内存管理. 所以GC可以说是一项"古老"的技术, 但是直到20世纪90年代Java的出现并流行, 广大的普通程序员们才得以接触GC. 当前许多语言如Go, Java, C#, JS和Python等都支持GC.

Expand Down Expand Up @@ -125,7 +125,7 @@ func ReturnValue() *Person {

GC大大减少了开发者编码时的心智负担, 把精力集中在更本质的编程工作上, 同时也大大减少了程序的错误.

#### GC与资源回收
#### 1.2 GC与资源回收

**GC是一种内存管理机制. 在有GC的语言中也要注意释放文件, 连接, 数据库等资源!**

Expand All @@ -135,7 +135,7 @@ GC大大减少了开发者编码时的心智负担, 把精力集中在更本质

Java和Go均有类似的机制, 目前Java 1.9中已经明确把finalizer标记为废弃.

#### 术语简单说明
#### 1.3 术语简单说明

这里简单的说明一些术语,帮助快速了解, 并不追求完全准确.

Expand Down Expand Up @@ -167,7 +167,7 @@ stop the world, GC的一些阶段需要停止所有的mutator(应用代码)以

如果某一个对象在程序的后续执行中可能会被mutator访问, 则称该对象是存活的, 不存活的对象就是我们所说的garbage. 一般通过可达性来表示存活性.

#### Mark Sweep
#### 1.4 Mark Sweep

三大GC基础算法中的一种. 分为mark(标记)和sweep(清扫)两个阶段. 朴素的Mark Sweep流程如下:

Expand All @@ -192,7 +192,7 @@ freelist改成多条, 同一个大小范围的对象, 放在一个freelist上,

并发Sweep和并发Mark, 大大降低stw时间.

#### 并发收集:
#### 1.5 并发收集

朴素的Mark Sweep算法会造成巨大的STW时间, 导致应用长时间不可用, 且与堆大小成正比, 可扩展性不好. Go的GC算法就是基于Mark Sweep, 不过是并发Mark和并发Sweep.

Expand All @@ -204,7 +204,7 @@ freelist改成多条, 同一个大小范围的对象, 放在一个freelist上,

首先backgroup sweep是比较容易实现的, 因为mark后, 哪些对象是存活, 哪些是要被sweep是已知的, sweep的是不再引用的对象, sweep结束前, 这些对象不会再被分配到. 所以sweep容和mutator内存共存, 后面我们可以看到golang是先在1.3实现的sweep并发. 1.5才实现的mark并发.

#### 写屏障
#### 1.6 写屏障

接上面, mark和mutator同时运行就比较麻烦, 因为mutator会改变已被scan的对象的引用关系.

Expand Down Expand Up @@ -240,7 +240,7 @@ mutaotr a.obj1=c

这一步, 将c的指针写入到a.obj1之前, 会先执行一段判断代码, 如果c已经被扫描过, 就不再扫描, 如果c没有被扫描过, 就把c加入到待扫描的队列中. 这样就不会出现丢失存活对象的问题存在.

#### 三色标记法
#### 1.7 三色标记法

三色标记法是传统Mark-Sweep的一个改进, 由Dijkstra(就是提出最短路径算法的)在1978年发表的论文On-the-Fly Garbage Collection: An Exercise in Cooperation中提出.

Expand Down Expand Up @@ -271,7 +271,7 @@ mutaotr a.obj1=c

### 2.Golang GC发展历史

#### Golang GC简介
#### 2.1 Golang GC简介

Golang对于GC的目标是低延迟, 软实时GC, 很多围绕着这两点来设计.

Expand All @@ -295,7 +295,7 @@ Golang刚发布时(13,14年)GC饱受诟病, 相对于当时Java成熟的CMS(2002

[https://www.zhihu.com/question/42353634](https://links.jianshu.com/go?to=https%3A%2F%2Fwww.zhihu.com%2Fquestion%2F42353634) R大的回答

#### Golang各版本GC改进简介
#### 2.2 Golang各版本GC改进简介

以下是简单介绍Golang GC的版本更新以及STW时间(以下STW时间仅供参考, 因为STW时间与机器性能, 堆大小, 对象数量, 应用分配偏好, 都有很大的关系)

Expand All @@ -315,7 +315,7 @@ GC's STW pauses in Go1.12 beta are much shorter than Go1.11

[https://www.reddit.com/r/golang/comments/aetba6/gcs_stw_pauses_in_go112_beta_are_much_shorter/](https://links.jianshu.com/go?to=https%3A%2F%2Fwww.reddit.com%2Fr%2Fgolang%2Fcomments%2Faetba6%2Fgcs_stw_pauses_in_go112_beta_are_much_shorter%2F)

#### Golang GC官方数据
#### 2.3 Golang GC官方数据

以下GC的STW时间从网络上文章及官方分享中获取, 数据供参考, 但不会出现数量级的问题:

Expand All @@ -335,7 +335,7 @@ Go 1.3-1.5

以下数据来自前google和前twitter工程师Brain Hatfield, 每隔半年在twitter上发表的一个服务升级Golang版本带来的GC提升. 这些数据在Golang GC掌门人Richard L. Hudson的分享上也列举过. 大概10GB级别堆从1.4-1.8的STW数据对比: [https://twitter.com/brianhatfield/status/804355831080751104](https://links.jianshu.com/go?to=https%3A%2F%2Ftwitter.com%2Fbrianhatfield%2Fstatus%2F804355831080751104)

#### Go 1.4-Go 1.5
#### 2.4 Go 1.4-Go 1.5

2015/8月重新编译发布

Expand All @@ -347,7 +347,7 @@ Go 1.3-1.5
<img src="https://github.com/alwaysthanks/learning-docs/blob/master/images/20200108golang-gc-05.webp">
</center>

#### Go1.5-Go 1.6
#### 2.5 Go1.5-Go 1.6

2016年1月编译发布

Expand All @@ -359,7 +359,7 @@ Go 1.3-1.5



#### Go 1.6-Go 1.7
#### 2.6 Go 1.6-Go 1.7

2016年8月编译发布, Go1.6升级1.7后, 服务stw时间由3ms降为1-2ms

Expand All @@ -369,7 +369,7 @@ Go 1.3-1.5
<img src="https://github.com/alwaysthanks/learning-docs/blob/master/images/20200108golang-gc-07.webp">
</center>

#### Go 1.7-Go 1.8
#### 2.7 Go 1.7-Go 1.8

2016年12月编译发布, 升级后, 服务STW时间由2-3ms->1ms以下

Expand All @@ -381,15 +381,15 @@ Go 1.3-1.5



#### Go 1.9
#### 2.8 Go 1.9

2017年8月

go 1.9在18GB堆下, stw时间, 都在1.0ms以下. go1.8版本之后, stw时间的提升均不大, 已经到sub ms了.



#### 总结图
#### 2.9 总结图

Golang 1.4-1.9 STW时间与版本关系.

Expand All @@ -405,11 +405,11 @@ Golang 1.4-1.9 STW时间与版本关系.

Golang 1.8后GC的STW时间基本上做到了和堆大小无关. 而并发Mark时间则与存活对象数目(当然这个描述并不是非常准确)基本成正比, 与CPU的核数基本成反比.

#### 存活对象较少的堆
#### 3.1 存活对象较少的堆

对于我们的业务系统来说, 一般都是有大量的临时对象. 反而总的存活对象不会很多. 我们先来看看堆里面存活对象不多的服务的GC情况.

##### 测试方式:
##### 测试方式

以下来自某服务.

Expand All @@ -425,7 +425,7 @@ client调用(合并rpc和kv) 43W/min,7000qps/s

(服务的qps倒不是很高, 主要是这个服务每次都会发6个rpc请求, 且没有优化过, 火焰图里可以看出来日志里序列化pb, 耗费了30%的性能)

##### 结果与分析:
##### 结果与分析



Expand All @@ -437,13 +437,13 @@ client调用(合并rpc和kv) 43W/min,7000qps/s

可以看出STW时间基本都在1ms以下, 有小部分超过2ms, 也比较正常.

#### 存活对象较大的堆
#### 3.2 存活对象较大的堆

前面分析的是存活对象不多的情况.

Mark Sweep是根据root来找到所有存活对象, 虽然堆很大, 但存活的对象不多, 所以mark时间也不会很大. 如果存活对象很多, 比如像缓存服务, golang的gc是怎样的情况呢?

##### 测试方式:
##### 测试方式

这里我写了一个代码来模拟.

Expand All @@ -461,7 +461,7 @@ Mark Sweep是根据root来找到所有存活对象, 虽然堆很大, 但存活
<img src="https://github.com/alwaysthanks/learning-docs/blob/master/images/20200108golang-gc-11.webp">
</center>

##### 分析:
##### 分析

由上可以看出, Golang GC Mark消耗的CPU时间与存活的对象数基本成正比(更准确的说是和需扫描的字节数, 每个对象第一个字节到对象的最后一个指针字段). 对于G级别以上的存活对象, 扫描一次需要花秒以上的CPU时间.

Expand All @@ -473,11 +473,11 @@ Golang GC在存活对象非常多的情况下, 对CPU吞吐量的降低还是比

### 4.Golang GC的一些演进规划

标题有点标题党, 我们就不谈未来了, 我们谈谈Golang GC的一些规划和尝试. 这个部分主要参考Go的GC掌门人Richard L. Hudson在去年做的一个演讲.
谈谈Golang GC的一些规划和尝试. 这个部分主要参考Go的GC掌门人Richard L. Hudson在去年做的一个演讲.

Getting to Go: The Journey of Go's Garbage Collector [Getting to Go: The Journey of Go's Garbage Collector](https://links.jianshu.com/go?to=https%3A%2F%2Fblog.golang.org%2Fismmkeynote)

#### Request Oriented Collector(面向请求的回收器)
#### 4.1 Request Oriented Collector(面向请求的回收器)

在2016年有一个propose是, Request Oriented Collector(面向请求的GC), 简单的说就是私有对象随着请求的结束而消亡.

Expand All @@ -489,13 +489,13 @@ Go目前很大一个应用场景(Cloud Native?)是接受一个请求, 开一个

[https://blog.golang.org/ismmkeynote](https://links.jianshu.com/go?to=https%3A%2F%2Fblog.golang.org%2Fismmkeynote)

#### Generational GC(分代GC)
#### 4.2 Generational GC(分代GC)

对ROC尝试上的失败, Go团队转向分代GC.(从描述来看, 个人感觉ROC像是对分代GC的一种激进的做法. 主要思路也是为了减少对象的publish, 能回收掉的对象尽快回收掉.)

分代GC理论是80年代提出来的, 基于大部分对象都会在短时间内成为垃圾这个软件工程上的事实, 将内存分为多个区, 不同的区采取不同的GC算法. 分代GC并不是一种GC算法, 而是一种策略.

#### Java的分代GC
#### 4.3 Java的分代GC

Java GC是分代GC的忠实拥簇者, 从98年发布的Java 1.2开始, 就已经是分代GC了. 图中是Java多种分代算法的默认分配情况.

Expand All @@ -513,7 +513,7 @@ Java GC是分代GC的忠实拥簇者, 从98年发布的Java 1.2开始, 就已经

大部分时候只需要对新生代进行Minor GC,因为新生代空间小,Minor GC的暂停很短(生产服务中, 4核机器中500M-1G的新生代, GC大概为3ms-10ms的级别). 且绝大部分对象分配后就很快被Minor GC回收, 不会提升到老年代中, 对老年代Major GC的次数就会很少, 大大减少了频繁进行Major GC而Scan和Mark消耗的CPU时间, 减少回收大堆而导致的大的STW时间频次. 像API/RPC后台服务, 比较稳定的话, 可能几小时或一天才进行一次Major GC.

#### Golang的分代GC
#### 4.4 Golang的分代GC

##### 为何Golang对分代GC需求相对不大?

Expand Down
Loading