`
wqtn22
  • 浏览: 101060 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

erlang程序优化点的总结(持续更新)

 
阅读更多

转载请注明出处  

注意,这里只是给出一个总结,具体性能需要根据实际环境和需要来确定

霸爷指出,新的erlang虚拟机有很多调优启动参数,今后现在这个方面深挖一下。

1. 进程标志设置:

       消息和binary内存:erlang:process_flag(min_bin_vheap_size, 1024*1024),减少大量消息到达或处理过程中产生大量binary时的gc次数

       堆内存:erlang:process_flag(min_heap_size, 1024*1024),减少处理过程中产生大量term,尤其是list时的gc次数

       进程优先级:erlang:process_flag(priority, high),防止特殊进程被其它常见进程强制执行reductions

       进程调度器绑定:erlang:process_flag(scheduler, 1),当进程使用了port时,还需要port绑定支持,防止进程在不同调度器间迁移引起性能损失,如cache、跨numa node拷贝等,当进程使用了port时,主要是套接字,若进程与port不在一个scheduler上,可能会引发严重的epoll fd锁竞争及跨numa node拷贝,导致性能严重下降

  2. 虚拟机参数:

     +S X:X :启用调度器数量,多个调度器使用多线程,有大量锁争用

     -smp disable :取消smp,仅使用单线程,16个-smp_disabled虚拟机性能高于+S 16:16

     +sbt db :将scheduler绑定到具体的cpu核心上,再配合erlang进程和port绑定,可以显著提升性能,但是如果绑定错误,反而会有反效果

  3. 消息队列:

     消息队列长度对性能的影响主要体现在以下两个方面:进程binary堆的gc和进程内消息匹配,前者可以通过放大堆内存来减少gc影响,后者需要谨慎处理。

     若进程在处理消息时是通过消息匹配方式取得消息,同时又允许其它进程无限制投递消息到本进程,此时会引发灾难,匹配方式取得消息会引发遍历进程消息队列,如果此时仍然有其它进程投递消息,会导致进程消息队列暴涨,遍历过程也将增大代价,引发恶性循环。已知模式有:在gen_server中使用file:write(raw模式)或gen_tcp:send等,这些操作都是erlang虚拟机内部通过port driver实现的,均有内部receive匹配接收,对于这些操作,最好的办法是将其改写为nif,直接走进程堆进行操作,次之为将file:write或gen_tcp:send改写为两阶段,第一阶段为port_command,第二阶段由gen_server接收返回结果,这种异步化可能有些正确性问题,对于gen_tcp:send影响不大,因为网络请求本身要么同步化要么异步化,都需要内部的确认机制;对于file:write影响较大,file:write的错误通常为目录不存在或磁盘空间不足,确保这两个错误不造成影响即可,同时如果进程的其它部分需要使用file的其它操作,必须首先清空之前file:write产生的所有file的port消息,否则有可能产生消息序列紊乱的问题。

     对于套接字的接口调用,可以参考rabbitmq的两阶段套接字发送方法,而对于文件接口调用,可以参考riak的bitcask引擎将文件读写封装为nif的方法

  4. 内存及ets表:

     ets表可以用于进程间交换大数据,或充当缓存,以及复杂匹配代理等,其性能颇高,并发读写可达千万级qps,并有两个并发选项,在建立表时设置,分别是{write_concurrency, true} | {read_concurrency, true},以允许ets的并发读写

     使用ets表可以绕过进程消息机制,从而在一定程度上提高性能,并将编程模式从面向消息模式变为面向共享内存模式

  5. CPU密集型操作:

     erlang执行流程的问题:

       1. 其指令都是由其虚拟机执行的,一条指令可能需要cpu执行3-4条指令,一些大规模的匹配或遍历操作会严重影响性能;

       2. 其bif调用执行过程类似于操作系统的系统调用,需要对传入参数进行转换,在大量小操作时损失性能较为严重

       3. 其port driver流程较为繁冗复杂,需要经历大量的回调等,一般的小功能操作,不要通过port driver实现

     建议:

       字符串匹配不要通过list进行,最好通过binary;单字节匹配,尤其是语法解析,如xmerl、mochijson2、lexx等,尽管使用binary,但是它们是一个字节一个字节匹配的,性能会退化到list的水平,应该尽量将其nif化;

       对于一些小操作,反而应该去bif化、去nif化、去port driver化,因为进入erlang内部函数的执行代价也不小;

       已知的性能瓶颈:re、xmerl、mochijson2、lexx、erlang:now、calendar:local_time_to_universal_time_dst等

  6. 数据结构:

     减少遍历,尽量使用API提供的操作

     由于各种类型的变量实际可以当做c的指针,因此erlang语言级的操作并不会有太大代价

     lists:reverse为c代码实现,性能较高,依赖于该接口实现的lists API性能都不差,避免list遍历,[||]和foreach性能是foldl的2倍,不在非必要的时候遍历list

     dict:find为微秒级操作,内部通过动态hash实现,数据结构先有若干槽位,后根据数据规模变大而逐步增加槽位,fold遍历性能低下

     gb_trees:lookup为微秒级操作,内部通过一个大的元组实现,iterator+next遍历性能低下,比list的foldl还要低2个数量级

     其它常用结构:queue,set,graph等

  7. 计时器:

     erlang的计时器timer是通过一个唯一的timer进程实现的,该进程是一个gen_server,用户通过timer:send_after和timer:apply_after在指定时间间隔后收到指定消息或执行某个函数,每个用户的计时器都是一条记录,保存在timer的ets表timer_tab中,timer的时序驱动通过gen_server的超时机制实现。若同时使用timer的用户过多,则tiemr将响应不过来,成为瓶颈。

     更好的方法是使用erlang的原生计时器erlang:send_after和erlang:start_timer,它们把计时器附着在进程自己身上。

  8. 尾调用和尾递归:

     尾调用和尾递归是erlang函数式语言最强大的优化,尽量保持函数尾部有尾调用或尾递归

  9. 文件预读,批量写,缓存:

     这些方式都是局部性的体现:

     预读:读空间局部性,文件提供了read_ahead选项

     批量写:写空间局部性

       对于文件写或套接字发送,存在若干级别的批量写:

         1. erlang进程级:进程内部通过list缓存数据

         2. erlang虚拟机:不管是efile还是inet的driver,都提供了批量写的选项delayed_write|delay_send,

            它们对大量的异步写性能提升很有效

         3. 操作系统级:操作系统内部有文件写缓冲及套接字写缓冲

         4. 硬件级:cache等

     缓存:读写时间局部性,读写空间局部性,主要通过操作系统系统,erlang虚拟机没有内部的缓存

 10.套接字标志设置:

     延迟发送:{delay_send, true},聚合若干小消息为一个大消息,性能提升显著

     发送高低水位:{high_watermark, 128 * 1024} | {low_watermark, 64 * 1024},辅助delay_send使用,delay_send的聚合缓冲区大小为high_watermark,数据缓存到high_watermark后,将阻塞port_command,使用send发送数据,直到缓冲区大小降低到low_watermark后,解除阻塞,通常这些值越大越好,但erlang虚拟机允许设置的最大值不超过128K

     发送缓冲大小:{sndbuf, 16 * 1024},操作系统对套接字的发送缓冲大小,在延迟发送时有效,越大越好,但有极值

     接收缓冲大小:{recbuf, 16 * 1024},操作系统对套接字的接收缓冲大小

 11. 序列化/反序列化:

     通常情况下,为了简化实现,一般将erlang的term序列化为binary,传递到目的地后,在将binary反序列化为term,这通常涉及到两个操作:

     term_to_binary及binary_to_term,这两个操作性能消耗极为严重,应至多只做一次,减少甚至消除它们是最正确的,例如直接构造binary进行跨虚拟机数据交换;

     但对比与其它的序列化和反序列化方式,如利用protobuf等,term_to_binary和binary_to_term的性能是高于这些方式的,毕竟是erlang原生格式,对于力求简单的应用,其序列化和反序列化方式推荐term_to_binary和binary_to_term

 12. 并发化

     在一些场景下,如web请求、数据库请求、分布式文件系统等,单个接入接口已经不能满足性能需求,需要有多个接入接口,多个数据通道,等等,这要求所有请求处理过程必须是无状态的,或者状态更改同步进入一个公共存储,而公共存储也必须是支持并发处理的,如并发数据库、类hdfs、类dynamo存储等,若一致性要求较高,最好选用并发数据库,如mysql等,若在此基础上还要求高可用,最好选择同步多结点存储,

     mnesia、zk都是这方面的典型;若不需要较高的一致性,类hdfs、类dynamo这类no sql存储即可满足

 13. hipe

     将erlang汇编翻译成机器码,减少一条erlang指令对应的cpu指令数

分享到:
评论
1 楼 johncan 2013-10-21  
但是如果绑定错误,反而会有反效果,请问如何看是否绑定错误?是否如下文http://www.searchtb.com/2012/12/%E7%8E%A9%E8%BD%ACcpu-topology.html提到的,绑定到同一个core的logical processor会导致性能下降?

相关推荐

    Erlang程序设计中文版(完整书签).pdf

    关于给定文件的内容,由于无法提供实际的【部分内容】文本,我将基于文件标题和描述提供的信息,概述Erlang程序设计相关知识点。 Erlang是一种功能强大的编程语言,专门用于创建并发、分布式、容错的系统。它起源于...

    Erlang游戏程序学习完整PDF手册

    2. **热代码升级**:Erlang支持在运行时更新代码,无需停机,这对持续运行的游戏服务来说非常关键,可以保证用户体验的连续性。 3. **容错性**:Erlang的进程隔离和故障隔离机制使得单个组件的故障不会影响整个系统...

    《Erlang程序设计》源码

    《Erlang程序设计》是一本深入探讨Erlang编程语言的书籍,其源码包含在提供的压缩包中。Erlang是一种并发性极强、适用于构建分布式系统和实时软实时系统的函数式编程语言。该书通过源码实例,帮助读者理解和掌握...

    erlang win64_18.1

    4. Hot Code Swap:Erlang程序可以在运行时加载新的代码版本,无需停止服务,这在持续更新和维护系统时非常有用。 5. 朴素的数据类型:Erlang的动态类型系统包含原子(atom)、整数、浮点数、列表、二进制等,简单且...

    RabbitMQ3.9.13和ErLang24.2版本

    2. **容错性**:Erlang的错误恢复机制和热代码升级功能使得Erlang程序能在出现错误时优雅地重启,而不影响整个系统。这对于保持RabbitMQ的稳定性至关重要。 3. **分布式特性**:Erlang的分布式特性使得构建分布式...

    ErlangB和ErlangC计算工具(exe可执行文件+excel两个)

    前者可能是一个图形用户界面的应用程序,用户可以直接输入呼叫参数,如呼叫到达率、系统容量等,然后软件将根据Erlang B公式计算出无阻塞概率。后者是一个Excel电子表格,通常包含预设的计算公式和图表,用户可以...

    erlang官方资源包

    总结起来,"otp_src_21.3.tar.gz"是一个包含Erlang OTP框架源代码的压缩包,对于理解Erlang并发模型、开发基于OTP的系统以及搭建RabbitMQ服务器至关重要。通过学习和使用这些资源,开发者可以构建出高效、健壮的...

    Erlang学习资料

    ### Erlang多核编程入门知识点总结 #### 一、Erlang多核编程背景与重要性 - **多核时代的来临**:随着技术的发展,单个芯片内部的时钟周期可触及部分越来越少,多核处理器成为了不可避免的趋势。这不仅影响着...

    英雄远征源码[erlang]

    Erlang的热代码升级机制允许在不中断服务的情况下更新代码,这对于在线游戏至关重要,因为它保证了游戏的持续运行,同时允许开发者进行快速迭代和修复。 6. **错误处理与容错** Erlang的错误处理机制强调“失败早...

    最新erlang win6421.0.1版本

    用户可以通过运行这个可执行文件来安装Erlang环境,从而能够在本地开发和运行Erlang程序。 总的来说,Erlang和OTP提供了强大的工具和库,用于构建分布式、并发的应用程序,而RabbitMQ则利用这些特性实现高效的消息...

    Erlang-Formula.zip_Erlang B _Erlang-B_erlang_erlang B计算_erlang C

    实现 Erlang B/C 功能的程序可以帮助电信工程师评估和优化通信网络的性能。通过输入不同的参数,如呼叫到达速率、服务器数量等,可以预测在不同负载下的系统表现,从而合理规划资源,减少通话阻塞,提高客户满意度。...

    XP能用的erlang+rabbitMQ版本

    同时,尽管这些版本可以在XP上运行,但随着系统更新和软件迭代,未来可能会遇到兼容性问题,所以持续关注软件更新并适时升级是必要的。 总之,Erlang和RabbitMQ是构建高并发、高可用消息系统的强大工具,它们的组合...

    tsung+erlang包

    OTP 包含了 Erlang 编程语言的标准库,以及一系列预先设计好的应用程序和服务,如 Mnesia 数据库、 supervision trees(监督树)和 gen_server行为模式等。通过这个源代码,你可以深入了解 Erlang 的工作原理和 OTP ...

    Erlang 中的Module级别热部署

    通过学习这些资料,你可以更熟练地掌握Erlang的热部署技术,提升你在Erlang程序设计中的技能。 总的来说,Erlang的模块级别热部署是其强大功能的一个体现,它使得开发者可以在保持系统稳定运行的同时进行代码更新和...

    Erlang克罗尼什系统.zip

    Erlang Cron的设计目标是为Erlang应用程序提供一个灵活且可靠的定时任务管理工具,允许开发者设置周期性的任务,这些任务可以按计划的时间间隔执行,如每日、每周或每小时。它通常用于自动化维护任务、数据备份、...

    Erlang项目内存泄漏分析方法

    Erlang是一种用于构建并发应用的编程语言,其分布式计算模型在处理高...最后,持续监控和定期进行性能分析是预防Erlang内存泄漏的关键。通过这些措施,可以在问题发生前就避免它们的发生,保证系统的稳定性和高可用性。

    远古封神Server(erlang源码)

    此外,Erlang的错误处理机制允许程序在出现错误时能够优雅地恢复,而非崩溃,这对于持续运行的游戏服务器至关重要。在“远古封神Server”中,Erlang的这些特性被充分利用,确保了服务器的稳定运行。 其次,文档的...

    Erlang-21.3 + rabbitmq-3.7.28

    **Erlang-21.3 知识点** Erlang是一种通用的并发编程语言,由瑞典电信设备制造商Ericsson开发,主要用于构建高度可扩展的、容错性强的分布式系统。Erlang-21.3是该语言的一个特定版本,它包含了一些重要的更新和...

    zuuid:适用于Erlang的UUID应用程序

    【标题】"zuuid:适用于Erlang的UUID应用程序"是一个专为Erlang编程语言设计的UUID(通用唯一标识符)生成库。UUID是一种在分布式系统中广泛使用的标准,用于生成全球唯一的标识符,确保在任何网络环境下的数据唯一性...

    cpp-Cowboy用于ErlangOTP的小型快速现代的HTTP服务器

    5. **稳定性**: Erlang/OTP的健壮性保证了Cowboy在面对网络错误、资源耗尽或其他异常情况时能够优雅地处理,确保服务的持续运行。 6. **易用性**: Cowboy提供了清晰的文档和示例代码,帮助开发者快速上手。同时,...

Global site tag (gtag.js) - Google Analytics