Erlang应用优化指南 余 锋 2009/11/07
优化案例
Erlang应用优化案例 Ehttpd测试 Hotwheel 40000广播 简单Key/Value查询系统 输出“Hello world” 可超过20000并发短链接 Hotwheel 40000广播 Google hotwheel 简单Key/Value查询系统
HTTP echo每秒20000短连接单个CPU Taskset -c 1 erl +K true +h 99999 +P 99999 -s ehttpd 优化前后对比 11203 20090 硬件普通桌面双核CPU,2G内存 微调Linux VM和协议栈,32位操作系统 优化和patch了Erlang VM,采用beam.plain 优化了ehttpd程序,采用系统高级网络选项
Hotwheel广播服务 Joel悬赏$2000,挑战20K 成功挑战通过每CPU 40K/s 这个应用代表了大部分网络服务程序的模型,对于整个业界水平的提高很有借鉴意义
简单Key/Value查询系统(身份证查询系统?) 测试硬件 8核心 16G内存 测试结果 并发长链接数1000000 并发查询100000/s
预备知识
优化的层次 选型 操作系统 Erlang VM 语言 集群 业务
Erlang适合做什么 IO 密集型 高性能网络服务器 CPU利用 高度优化完备的IO, 顶尖的C高手20年的耕耘 多年的开发 非常完善 类似于一个操作系统 很好的处理掉了[高性能服务器Seven Sins] 轻松达到C10K CPU利用 先进的SMP调度器更好的利用多核心CPU
Erlang和操作系统的类比 *nix操作系统,用C++做例子 函数 (void fun() {}) 类 (class mod{};) 模块(mod.cpp) 可执行文件(编译器,机器指令) 应用程序包括数据文件 OS启动,系统进程(抢占式调度 ) IPC通讯 监控工具(Top)
Erlang和操作系统的类比 (cont’d) 函数 fun () -> ok end 模块 module mod. mod.erl Beam文件 编译器opcode Application beam+数据文件
Erlang和操作系统的类比 (cont’d) VM bootstrap Erlang进程 (抢占调度 ) 消息 Port IPC 工具集 etop
ERTS内部结构
Erlang进程调度原理 调度原则 上下文切换 消息传递的开销 尽量让一个CPU忙 Logic CPU从低到高 context_switch开销 消息传递的开销 拷贝 malloc/free 垃圾收集
Port调度原理 Port独立调度 和宿主进程同一个调度器 调度的单位是该Port触发的一串IO事件 调度延迟 busy_port 水位线buffer 锁
如何优化
工具方法 理解了Erlang和*nix的相同点 借鉴*nix 的工具和方法 创造工具和方法
操作系统层面的优化 操作系统的选择 32位系统 vs. 64位系统 RHEL上游厂商致力于高性能操作系统 重新用ICC编译内核和glibc 没有内存空间限制 64位比较慢 RHEL上游厂商致力于高性能操作系统 Vdso RhelRt 重新用ICC编译内核和glibc VM和TCP协议栈的优化
操作系统层面的优化 降低系统的swapness, 避免内存颠簸 资源倾斜,全力服务应用 给我尽可能多的物理内存,越多越好
Erlang运行期层面优化 新版本的OTP致力于SMP方面的改进 Hipe(erlang的jit) Crack系统 参数微调 未公开的特性 更细粒度的锁 更好的内存分配器 Hipe(erlang的jit) 全面启用preloaded otp库 Crack系统 减少无必须的系统调用 参数微调 Effective guide 未公开的特性 调度器绑定
语言层面优化 减少VM GC开销 进程字典 加大min_heap_size Hibernate Cache Lazy eval Record或者tuple变化部分和惰性部分分开
语言层面优化 (cont’d) 模式匹配 避免创建无用的中间变量 数据结构设计尽可能的每个调度器一个 erl +”’S’” mod.erl 相同的标签尽可能的放在一起 排序 二分查找 避免创建无用的中间变量 数据结构设计尽可能的每个调度器一个 erl +”’S’” mod.erl bin_opt_info 直接函数调用 vs. 异步消息
集群层面优化 节点间通讯 节点管理成本 Ei库用C来赢得速度 Pg2简化管理 inet_tcp 唯一通道,潜在的瓶颈 net tick 开销不可忽视 节点up、down开销 Ei库用C来赢得速度 Pg2简化管理
业务层面的优化 尽可能的简单 能够并行计算 Small message, big computation 为业务估算要消耗的资源提早分配 内存 CPU
内存和CPU的平衡 部署 Plain vs. SMP Hibernate 计算密集型和IO密集性在同一台物理机器资源互补 plain适合做简单的IO操作 smp适合做密集计算 Hibernate 根据业务的特点 定时来做 快速打扫战场 释放资源
数据组织 进程和物理世界的对象1:1 多用ets tuple, list, array dict, process dict 无锁结构 有限的调度器 每个调度器一个slot 适用的规模
如何测量
测量什么 热点 Erlang代码的热点 Erts的热点 OS的热点 延迟 调度排队 抖动 不是绝对的公平
测量工具 OS层面 systemtap oprofile dstat top iptraf wireshark proc fs
Erlang工具集 etop pman instrument lockcounter dbg erlang:statistics module:info (inet, ets,…) erts_debug 配上图片
Erlang工具集 monitor os_monitor profile *prof系列 snmp appmon
可视化消息跟踪系统 Et_viewer Trace机制
优化最佳实践
硬件和操作系统 物理内存 越多越好 大部分时候是瓶颈 >64G过分? 操作系统 推荐RHEL 5.X 资源倾斜给应用系统
编码 尽量多用list comprehension,让编译器来优化 多利用iolist和gather write Binary注意>256才是引用计数的 Hipe_bif 也是个选择 避免昂贵的BIF now() io_lib:format
CPU亲缘性 Taskset 大量减少锁的竞争 Futex Spinlock Scheduler erl -sct db
操作系统native特性 Futex VDSO TCP/IP协议栈 Socket快速回收 大文件句柄数微调 send_file tcp_defer_accept
可诊断的系统 提供内部状态的信息 关键参数可动态调整 过程工具化、自动化 高压力测试 完善的日志系统 Erlang的一贯传统 调优的依据 便于观测效果 过程工具化、自动化 test server, common test, eunit 高压力测试 tsung
尽可能的利用ERTS的优势 port整合不同的语言和系统 性能苛刻 可以考虑用driver改写关键部分 尽可能的利用高级特性如{packet, 2}, http* 设计的协议什么的尽可能的方便Erlang处理 推荐工业标准的协议 asn.1 leex和yecc
资源竞争 锁还是存在的 锁减少再减少 只是下移到了ETRS 不同的调度器间操作都需要锁 设计方面考虑业务并行 每CPU调度器并行 数据结构并行
广告时间 提供服务器架构、诊断、优化咨询服务 联系我 主页: http://yufeng.info 邮件: erlang.help@gmail.com
谢谢 提问时间