说明,本文档基于 SOFAMosn 0.4.0 版本编写html
SOFAMosn 是一款采用 GoLang 开发的 Service Mesh 数据平面代理,由蚂蚁金服系统部网络团队、蚂蚁金服中间件团队、UC 大文娱团队共同开发,功能和定位相似 Envoy,旨在提供分布式,模块化,可观察,智能化的代理能力;她经过模块化,分层解耦的设计,提供了可编程,事件机制,扩展性,高吞吐量的能力。git
——摘自《 SOFAMosn 的诞生和特性》github
整体上看,链接迁移的流程以下图:编程
此后:后端
——摘自《SOFAMosn Introduction》网络
在 MOSN 启动的时候,会加载包数据结构
github.com/alipay/sofa-mosn/pkg/server
在这个包加载的时候,该里面的 serverkeeper.go 这个文件中的 init() 函数被执行。这个函数会起一个协程在捕获 HUP 信号。dom
当 Mosn 接收到来自系统的 HUP 信号时,MOSN 首先会调用 stopStoppable 函数先让 Admin Server 中的全部 Listener 都关闭 。而后调用 reconfigure 函数来进行配置从新加载。socket
触发了 reconfigure 函数后,首先 MOSN 会设置两个环境变量分布式
_MOSN_GRACEFUL_RESTART=true _MOSN_INHERITFD_FD=<number>
准备好环境变量后,就调用 syscall 包的 ForkExec 按照当前 MOSN 的启动参数进行启动,并将环境变量和标准输入输出错误和 ListenerFD 都和 New MOSN 共享。而后,MOSN 会等 3 秒,让 New MOSN 启动起来。认为 New MOSN 启动完成后,它就会调用 StopAccept() 让全部的 Listener 中止 Accept 新的请求(已经 Accept 的请求不会结束,socket 的监听也不会断),而后调用 WaitConnectionsDone 函数根据 GracefulTimeout(默认是 30秒) 设置的优雅重启的超时时间让全部的链接都完毕。接着 MOSN 就进行 Metrics 的迁移,完成后就会退出进程。
在 WaitConnectionsDone 中,MOSN 设置了一个时间长度为 2 个 GracefulTimeout + 10秒 的时间的定时器。而后首先会 sleep 一个 GracefulTimeout 的时间,等待全部的链接主动关闭。而后关闭全部 server 中 connHandler 的 listeners 成员的 stopChan. 而后再 sleep 一个 GracefulTimeout + 10秒的时间,等待全部链接的迁移。时间过了以后,函数就会返回。此后,上层会调用 TransferMetrics 进行 Metrics 的调用 Exit 进行进程退出。
在 New MOSN 启动的过程当中,首先会调用 getInheritListeners。这个函数会从读取 Old MOSN 设置的环境变量 _MOSN_GRACEFUL_RESTART,若是为 true, 说明这是一个优雅重启,就会读取环境变量 _MOSN_INHERITFD_FD。因为 Listener 是最早使用 fd 的,因此 fd 老是从3 开始,那么全部 Listener fd 就是: 3, 4, ... , 3 + _MOSN_INHERITFD_FD。而后利用这些 fd 将 Old MOSN 的 Listener 恢复出来。从而获取到继承过来的 Listener。获取完以后,会对获取的 Listener 和配置文件进行比对,判断其合法性。若是不合法的,或者不能新的配置里面没有以至继承过来的 Listener 不须要复用,就会将其关闭。
完成了全部的初始化以后,就会启动两个 Unix Sock 的Server, 分别用与进行链接的迁移和 metrics 的迁移。用于链接迁移的 Unix Sock Server 会在 2 个 GracefulTimeout + 10 秒后自动关闭。
迁移过程当中,New MOSN 对每个 Unix Sock 请求都会分配一个协程去处理。
当一个请求进来的时候,若是请求使用的协议不是 HTTP1 且不使用系统提供的事件循环的时候,MOSN 会启动本身的 ConnIo, 调用 startReadLoop 和 startWriteLoop 来开启针对这个请求的的读写循环。
在发送请求的过程当中,首先会发送一个字节的数据, 这个字节表明了传输的是读数据迁移仍是写数据迁移。0 表明是使用读数据迁移协议。1 表明是使用写数据协议。若是是 0, 还会将该链接的 fd 以 out-of-band 的方式也发送出去。
读数据迁移协议
首先是头部分:包括 8 个字节,前 4 个字节是 data 部分的长度,后 4 个字节是 TLS 部分的长度。body 部分:接下来 data length 个字节存储的是 readBuffer 数据。最后 TLS length 个字节存储的是 TLS 的数据。
写数据迁移协议
头部分也是 8 个字节, 前 4 个字节存储了 data 部分长度,后 4 个字节存储的是 connection ID。body 部分:接下来的 data length 本身存储的是 writeBuffer 数据。
Old MOSN 发送
在 startReadLoop 中,MOSN 会捕获以前提到的 stopChan 被关闭的事件。捕获到这个事件以后,MOSN 会让这个连接等待一个随机的时间,而后开启链接迁移的过程。
首先 MOSN 会往链接中的 transferChan 发一个 transferNotify(值为1) 消息,告诉这个链接对应的写循环:要开始迁移链接了。而后调用 transferRead 开始迁移读链接,并返回一个connection ID,最后将这个 ID 再次发送给 transferChan。
在函数 transferRead 中:
New MOSN 的接收
当 New MOSN 接受到来自 Old MOSN 的数据时:
Old MOSN 的发送
当写循环收到读循环从 transferChan 发过来的 transferNotify 消息时,会再读一次 transferChan, 获取到这一次链接传输的 ID,若是 ID 合法,则会开始监听两个 channel:
在 transferWrite 中:
New MOSN 的接收
当 New MOSN 接受到来自 Old MOSN 的数据时:
至此,链接迁移的过成就完成了。
Old MOSN 退出前的最后一件事,就是把 Metrics 数据托付给 New MOSN。
Metrics 的传输协议很简单,包括两部分 header 和 body
当 New MOSN 接受到来自 Old MOSN 的数据时,会调 serveConn 函数去处理每个迁移请求:
至此,全部关于平滑重启的操做就完成了。