Golang在京东的使用

2020-02-27 603浏览

  • 1.ECUG Con 2013 GOLANG 在京东的应用 刘奇 @goroutine Copyright of JD.com
  • 2.概况 1.Golang 开发的项目 2.实现技术与经验 3.正在进行的工作
  • 3.Golang 开发的项目 • 京东云消息推送系统 ( 团队人数 :4)      单机并发 tcp 连接数峰值 118w 内存占用 23G(Res) Load 0.7 左右 心跳包 4k/s gc 时间 2-3.x s
  • 4.Golang 开发的项目 • 云存储 ( 团队人数 12) 小文件存储 储存储 通用存储( 大部分兼容 s3) 除存储储 引擎用 储 储 c/c++ , sdk 用 java ,其它均用 go 实现 兄弟储储储 开储储 的储储 目:自 储 储 储储 部署系 储 储 储 ……    
  • 5.快乐与痛苦同在 • happy   简洁,开发速度快 并发实现方便,基础库完善 • pains   GC 还是 GC
  • 6.消息推送整体架构
  • 7.储于 消息 储储列 • Redis + lua 实现 ( 高可用: vip + replication) • 那么多现成的,为什么重复造轮子? • 简单,轻量,高性能,持久化,有问题也 hold 得住 •Rabbitmq:不懂 erlang ,整个东西搞得 太复杂 • Kafka & activemq :不会 java ,另外过 于复杂
  • 8.关于消息队列 • Crash safe • Worker 取到消息后 crash ,消息会超时重 发,不会丢失 • Worker 从队列中 pull 消息,若队列不空, 则持续取消息,否则 sleep 1/20 秒 ( 可以 结合 redis 的 pub/sub 机制实现实时消息 通知,暂未实现 ) • 多个 worker • 消息队列的逻辑由 lua 维护
  • 9.数据库选型 • 个人觉得基本什么数据库 ( 拆分 ) 都能搞 定,无明显喜好 • Mongodb :正在使用,异步写 入, sharding + replication 公司有高 手,无需自己操心,省心 • Mysql :个人偏好 • Couchbase :兴趣较大,迁移做得不错, 目前国内商用不多,暂不冒险储 • 中途硬盘坏过两次,有 raid ,直接热插拔 更换,对服务没任何影响
  • 10.Session 信息存储 • 分布式 cache, redis • 自己在 sdk 中做 sharding? 麻烦 •Twemproxy:一致性 hash, redis 主从 + vip • 部署方式:和储储 用部署在一起, 储 储 储 储 储 储 储储 用储储 接 localhost 的 twemproxy
  • 11.消息路由算法 • 由于移动网络不稳定,客户端可能短时间出 现在多个 server 上,仅仅通过客户端 id 无 法区分 • 引入 session id ,自增,由各个 server 分 配 • Session 存 储 格Clientid:
  • 12.优化的基本原则 • 储化 方案不会 储储著提高 储 储 储储储成本 储 • 有良好的兼容性,严格遵守 golang 的规 范,以便更好的利用新版本的改进 • 先优化明显的热点 • 优化方案在其它语言也有效 ( 内存池,储 接 储 池)
  • 13.一些经验 1.Object pool (gc & performance) 2.Group commit 3.JSON encoding/decoding (gc & performance) 4.标准库优化 (network, gc & performance) 5.Defer 是性能和 gc 储手 6.Dump 信息储储 取
  • 14.Object pool (gc & performance) 一个数组实现的栈 代储储 示例: 储储
  • 15.
  • 16.关于 json • 标准库的实现性能比较挫,由于使用了反 射,还有 defer , profiling 时轻松上榜 • 代码片段和热点图
  • 17.Json unmarshal 热点图
  • 18.关于 json • 解决方案: magajson • github.com/benbjohnson/megajson • Code generation, No reflection, no defer
  • 19.标准库优化 • 网络库中读写数据都需要 lock , unlock 是在 defer 中完成的,在长连接的程序中, 大部分时间是 idle 的,造成 defer 分配的 内存长时间驻留内存,使得内存压力较大, 也增加了 gc 的压力 • 看个热点图 ( 有图有真相储 )
  • 20.网络库热点图
  • 21.标准库优化 (network) • 解决方案: • 去 defer unlock ,改为手动在合适的地方 unlock
  • 22.Group commit • IO 通常较慢,压力测试下消息队列的速度 是瓶颈,通过 golang 的 buffered channel ,合并作为一个大消息提交 • 通过 buffered channel 合并消息给客户 端,减少网卡中断次数
  • 23.其它 • errors.New 优化 • time 存储 • socket close, runtime.SetFinalizer
  • 24.Group commit • 代码示例:
  • 25.
  • 26.Dump 信息获取 • Bug 不可避免, Crash 不可避免 • Golang 程序 crash 时会打出调用栈,硬编 码了写入的 fd(2) ,需要重定向到自定义的 文件存储 • syscall.Dup2(int(crashFile.Fd()), 2)
  • 27.小结 • 每个储储 接2 个 goroutine ,一读一写 • 关键代码没有 defer ,整个 server 不使用 defer • 16 个 gc 储程 和8 个 gc 线程差别不大,肉 眼储储 察提升不到 储 储 储 储 1/5 • 整体优化效果:内存占用减少一半, gc 时 间减少一半左右
  • 28.小结 • 还有优化的余地,细节改进 • Golang 的 gc 能力不能根据 cpu 核数储 性 储 扩充,多进程拆分效果显著, gc 时间至少 可以再缩短 1/3 ,但管理更多的进程也麻烦 • 今年的目储储 :储储 机储储 接数达到 储 储180w 储 左右, gc 时 间缩短到 1.3 秒左右
  • 29.云存储 • 商品订单  每年 500TB • 库房流水记录  每年超过 1PB • 商品图片  近百 TB ,持续增长
  • 30.元数据存储储 引擎 储 • key-value, memcache 类似的 cas 指 令,支持 ListBucket 操作 ( 参考 amazon s3 ) • 持久化字典树 (Adaptive Radix Tree) 实 现, key 和 value 分离,尽量让字典树常 驻内存,快速索引, value 的缓存交给应用 决定 • 原型由 golang 实现
  • 31.元数据存储引擎 • 再说说缓存 • 私有云:用户存储数据量非常大,每天几百 万到千万,数据特点明显,新的数据较热 ( 一周内 ) ,因此缓存策略在业务层可以较 好处理 (LRU, FIFO ...) • 内存是存储引擎宝贵的资源,能省则省,好 钢花在刀刃上
  • 32.元数据存储引擎 • 如果字典储好 在内存放不下呢? 像只能剪枝 了 • 剪枝策略:这是个麻烦的事情…
  • 33.云存储分布式模块简介 • Replication, split, migration 均由 golang 实现 • Split 按 key 做切分,迁移算法类似 couchbase ,但更复杂些,因为迁移后, ListBucket 要 merge • ListBucket 时从多个机器取得数据后做合 并操作
  • 34.• Thank You! •储