go 语言高并发实战

45
Go 语语语语语语语 语语语语语语语语语语语语语语语语 2012.12.23

Upload: skule

Post on 09-Jan-2016

102 views

Category:

Documents


1 download

DESCRIPTION

Go 语言高并发实战. 构建千万级在线的实时消息推送服务 2012.12.23. 关于我. 张景埕,网名 diogin( /’daɪədrɪn/ ) programmer@360 Go 语言追随者与实践者 新浪微博: http://weibo.com/ diogin [email protected]. 摘要. 一、为什么选用 Go 二、探究 Go 语言的实现细节 三、实时消息推送服务的特点 四、系统架构及组件细节 五、数据、经验和教训. 一、为什么选用 Go. 1. 高并发. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Go 语言高并发实战

Go 语言高并发实战

构建千万级在线的实时消息推送服务2012.12.23

Page 2: Go 语言高并发实战

关于我• 张景埕,网名 diogin ( /’daɪədrɪn/ )• programmer@360

• Go 语言追随者与实践者• 新浪微博: http://weibo.com/diogin

[email protected]

Page 3: Go 语言高并发实战

摘要• 一、为什么选用 Go

• 二、探究 Go 语言的实现细节• 三、实时消息推送服务的特点• 四、系统架构及组件细节• 五、数据、经验和教训

Page 4: Go 语言高并发实战

一、为什么选用 Go

Page 5: Go 语言高并发实战

1. 高并发• 一个 Go 进程可以轻易支撑几十万上百万并

发运行的 Go 例程(只要你内存足够大)• O(1) 的调度• 5KiB/goroutine 的内存开销• net 包: pollServer (epoll/kqueue/iocp) 支

持大量并发连接 fd 的事件通知,同时还支持多核并行 ( 目前为 8 核 )

• select/channel 提供卓越的例程间通信能力

Page 6: Go 语言高并发实战

2. 高性能• 编译为本地机器码• 静态链接 (CGO_ENABLED=0)

• 轻量级的 runtime 实现• 热点代码可以直接编写 C 或 ASM ,同样

静态链接进目标文件

Page 7: Go 语言高并发实战

3. 垃圾收集• 不想为内存泄露问题焦头烂额• 朴素的实现:停顿式、标记 & 清除• 还有很大的提升空间• 资源泄露还得自己解决

Page 8: Go 语言高并发实战

4. 低成本• 学习成本低:源自 C 系,大量的 C 系程

序员可以很快上手(这很重要)• 运维成本低:不需要安装各种让人头疼的

依赖,不需要搭建各种运行环境,部署非常方便

Page 9: Go 语言高并发实战

5. 够用的标准库• net• encoding/gob• strings, bytes, errors, strconv• regexp• os, time• syscall• sync• ......

Page 10: Go 语言高并发实战

6. 高移植性• 多种操作系统: Linux, FreeBSD, Darwin,

NetBSD, OpenBSD, Windows

• 多种体系结构: 386, amd64, arm(v5,v6,v7)

• 多种目标文件格式: elf/pe/macho

Page 11: Go 语言高并发实战

7. 优秀的背景• Google, BSD License

• Ken Thompson, Rob Pike, Robert Griesemer, Russ Cox, Brad Fitzpatrick...

• 拥有强烈的 Plan 9 血统• C, Python 的风格

Page 12: Go 语言高并发实战

Alternatives?

• Erlang

• Node.js

• D

• Rust

Page 13: Go 语言高并发实战

二、探究 Go 语言的实现细节

Page 14: Go 语言高并发实战

WHY?

• 产品级的应用,不是玩具• 在国内(甚至国外),仍处于吃螃蟹阶段• 我们需要能 hold 住可能出现的各种问题• 提升团队成员技术水平• 回击各种针对 Go 的恶意 FUD 和各种 P

K

• 回馈 Go 本身,积极为其做贡献

Page 15: Go 语言高并发实战

摘要• 代码结构• 逻辑结构• 实现结构• 程序启动• 运行视角• 深入 runtime

Page 16: Go 语言高并发实战

1. 代码结构• 工具 + 标准库• include/ : Go 基本工具依赖的库的头文件• src/ : Go 基本工具、标准库的实现• src/cmd/ : Go 基本工具及其实现• src/lib*/ : Go 基本工具依赖的库的实现• src/pkg/ : Go 标准库的实现

Page 17: Go 语言高并发实战

2. 逻辑结构• gc (Go 编译器 ) 、 cc (Plan 9 C 编译器 ) 、 as

(Plan 9 汇编器 ) 、 ld (Plan 9 链接器 ) 、 pack (Plan 9 目标文件归档工具 ) 工具链一条龙

• 支持多种操作系统、体系结构和可执行文件格式

• 程序 = N 个包的合并、组合• 包 = const 、 var 、 type 、 func

• dist :引导程序,负责构建 Go 基本工具• go :管理 Go 的各项功能

Page 18: Go 语言高并发实战

3. 实现结构• 每个包里可以有 .go 、 .c 、 .s 文件,分别由

gc 、 cc 、 as 编译,最后统一用 ld/pack 链接并打包成静态链接库 (遵循一致的 ABI)

• 每个 Go 程序都包含最底层的 runtime 包, runtime 实现并封装了程序的运行时环境

• syscall 包封装了操作系统调用,同时与 runtime 协作进行 goroutine 调度

• sync 提供了基本的并发同步原语(工具包)• reflect 为应用层代码提供运行时自省能力

Page 19: Go 语言高并发实战

4. 程序启动• 基本概念: M— 内核线程, G—goroutine• Go 使用符号“ ·”分隔包与包内的成员名字• 第一个 M 叫 m0 ,每个 M 的调度例程叫 g

0• 准备 runtime·m0/runtime·g0 -> 准备 argc,

argv -> 调度器初始化 ( 内存初始化 -> m 初始化 -> 注册 args, envs -> 设置并行参数 ) -> 创建并运行 runtime·main 例程 (启动垃圾收集器 -> main·init() -> main·main())

Page 20: Go 语言高并发实战

5. 运行视角• 程序由多个包构成,入口为 main 包,每

个包在程序启动时按依赖顺序逐一初始化• 程序内有多个 goroutine 并发运

行, goroutine 通过 channel 进行同步 /异步通信

• 自动化内存管理,不区分堆和栈

Page 21: Go 语言高并发实战

6. 深入 runtime

• mgc0.c :垃圾收集器• proc.c : goroutine 管理及调度

• hashmap.c : Go map• chan.c : channel 实

现• malloc.goc :内存分配

器• asm_GOARCH.s :体

系结构相关功能

• iface.c : Go interface• symtab.c :符号表• cpuprof.c/mprof.goc

: Profiling• sys_GOOS.s :操作

系统相关功能• thread_GOOS :内核

线程统一抽象• panic : panic管理

Page 22: Go 语言高并发实战

三、实时消息推送服务的特点

Page 23: Go 语言高并发实战

摘要• 长连接(多种接入协议: HTTP 、 TCP )• 高并发( >= 10,000,000 )• 多种发送方式(支持单播、多播、广播)• 持久 / 非持久• 准实时( 200ms ~ 2s )• 客户端多样性(手机端、 PC 端)• 同一账号多客户端同时接入• 接入网络频繁变化(电信、联通……)

Page 24: Go 语言高并发实战

1. 长连接• Server PUSH 的基础• HTTP Long Polling ( Keep-Alive )• 基于 TCP 的自定义通信协议• 采用心跳来侦测对方是否还在线

Page 25: Go 语言高并发实战

2. 高并发• C10K? out 了,现在的标准是 C1000K

• 用户众多:各接入产品实时在线人数都在 10,000,000 以上

• Linux Kernel >= 2.6.32, x86-64

• sysctl -w fs.file-max=12000000

• sysctl -w fs.nr_open=11000000

• limit.conf: nofile=10000000

• TCP/IP 协议栈参数调优

Page 26: Go 语言高并发实战

3. 多种发送方式• 点对点聊天(单播)• 定点推送(多播)• 全网推送(广播)

Page 27: Go 语言高并发实战

4. 持久 / 非持久• 持久消息必须保证不丢失 ( 需要离线存储 )

• 非持久消息仅发给当前在线用户

Page 28: Go 语言高并发实战

5. 准实时• 发一条消息,另一个人必须能很快收到• 200ms ~ 2s

• GC 卡顿会造成巨大麻烦

Page 29: Go 语言高并发实战

6. 客户端多样性• 手机、 PC 、平板电脑• 不同的产品有不同的需求• 提供机制,而非策略

Page 30: Go 语言高并发实战

7. 同一账号多客户端接入• iMessage : iPhone, iPad, MacOSX

• QQ : PC 、手机、平板、微信• 互斥(早期 QQ ) & 共存• 策略:如何控制?

Page 31: Go 语言高并发实战

8. 接入网络频繁变化• 白天在电信,晚上在联通• 一会儿在公司 wifi ,一会儿 3G ,一会儿

2G

• 断线,重连,断线,重连……

Page 32: Go 语言高并发实战

四、系统架构及实现细节

Page 33: Go 语言高并发实战

摘要• 逻辑架构:简单至上• 组件: room

• 组件: register

• 组件: saver

• 组件: idgenerator

• 组件: center

• 存储: redis

Page 34: Go 语言高并发实战

1. 逻辑架构:简单至上

Page 35: Go 语言高并发实战

2. 组件: room

• 客户端所连接的进程,类似于一个聊天室• 每个客户端一个 server goroutine 进行下推• 每个 server 有一个 channel 存消息队列• room 内有 book 记录 user 与 server 映射• 一个 http server 负责收消息并将消息路由到接

收人所在的 room 和 server

• manager 负责掌控 room 的服务:内部单播、多播、广播

• admin 负责 room 进程的管理

Page 36: Go 语言高并发实战

3. 组件: register

• 由于 room 的分布式与全对称设计,需要有一个地方记录用户当前连到了哪个 room , register 实现该角色

• 同时需要记录在线时长等信息 (业务需求 )• 本质上就是一个 key -> value 的 map• value 是个 struct• hash 算法定位 register 进程• 可以直接用 redis ,但自己实现可以方便地添加业务逻辑

Page 37: Go 语言高并发实战

4. 组件: saver

• 分布式全对称设计• 提供存储接口,封装后端的分布式存储• 接口采用 encoding/gob 编码格式的 rpc

Page 38: Go 语言高并发实战

5. 组件: idgenerator

• 全局消息 id 生成器, int64

• 分布式,每个进程负责一块 id 区域• 保证不重叠• 后台 goroutine 每隔一秒写一次磁盘,记录当前 id

• 启动时跳过一段 id ,防止一秒内未写入磁盘的 id 重复生成

Page 39: Go 语言高并发实战

6. 组件: center

• 提供消息操纵接口给应用服务器调用• 运营人员后台发消息 -> 应用服务器 ->

center -> room -> 客户端• RESTful API

• 有些任务(比如广播)需要一段时间,运营人员需要追踪发送进度,可能要临时停止,因此需要有“任务”概念,并可管理

• 提供统计接口

Page 40: Go 语言高并发实战

7. 存储: redis

• 核心数据• db_users : ZSET ,存各产品的用户集合• db_slots : LIST ,存用户离线消息队列• db_buckets : DICT ,存消息 id -> 消息

Page 41: Go 语言高并发实战

五、数据、经验和教训

Page 42: Go 语言高并发实战

数据• 16台机器,标配 24 个硬件线程, 64GB 内存• Linux Kernel 2.6.32 x86_64

• 单机 80 万并发连接, load 0.2~0.4 , CPU 总使用率 7%~10% ,内存占用 20GB (res)

• 目前接入的产品约 1280 万在线用户• 2分钟一次GC ,停顿 2秒 (1.0.3 的 GC 不给

力,直接升级到 tip ,再次吃螃蟹 )

• 15亿个心跳包 /天,占大多数• 持续运行一个月无异常,稳定

Page 43: Go 语言高并发实战

经验• 敢于尝试新东西,勇于面对新挑战• 拿代码说话,拿数据说话• 不要凭感觉,要实际去测• 对一项新技术要切实了解其优势和劣势• 对于感觉模糊的地方,追查其实现,做到

有备无患

Page 44: Go 语言高并发实战

教训• 实时系统对 GC 非常敏感,幸好 tip 上提

供了并行 GC ,否则这就是一次惨痛教训,需要做架构方面的大调整 (将大进程拆分成小进程 )

Page 45: Go 语言高并发实战

ThanksQ & A

张景埕 [email protected]

http://weibo.com/diogin