34
Erlang 开开开开开 [email protected]

Erlang开发及应用

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Erlang开发及应用

Erlang 开发及应用[email protected]

Page 2: Erlang开发及应用

What is Erlang?•  ERicsson LANGuage?• 函数式编程语言 (FP)• 面向并发 (OC), 基于消息• Ericsson 创建 , 最初用于电信系统开发• 成熟 , 稳定 , 具有 20 多年历史• 适于电信系统 , 分布式系统 , 高并发服务器 • Open Source, 跨平台 , GC 不适于底层系统开发

Page 3: Erlang开发及应用

History• 1980s Ericsson 实验室思考如何轻松开发电信系统应用• 1987 年左右 , Erlang 浮出水面• 1989 年 JAM 虚拟机 C 语言实现 • 1996 年 OTP 项目启动 , 融合开发经验 , 提供易用 , 强大的 Erlang 开发库 • 1998 年开源• 2007 年《 Programming Erlang 》出版• 目前版本 Erlang R13B1 (5.7.2)

Page 4: Erlang开发及应用

Erlang 优势• 多核 SMP 支持• 内建分布式支持• 基于轻量进程及消息的高并发模型• 代码热替换• 开发速度快 , 高性能 , 高稳定性• FP 编程 , 代码灵活高效 , 副作用小• 丰富的分析及监控程序• 经过商业产品 , 长久大规模验证• OpenSource, 代码面前无秘密

Page 5: Erlang开发及应用

Erlang Hello World代码 hello.erl: 1 -module(hello).2 -compile([export_all]).34 main() ->5    io:format("hello world!~n").编译 : $ erlc hello.erl运行 : $ erlEshell V5.7.1  (abort with ^G)1> hello:main().hello world!ok  

Page 6: Erlang开发及应用

Erlang Hello World CON'T1 -module(hello).声明模块名称 , 其必须和文件名一致 . 模块是 Erlang 项目中代码组织的基本方式 .2 -compile([export_all]).指明编译选项 ,export_all 用来导出所有本模块中的函数 ,exported function 是模块的接口 , 其他模块只能调用 exported function4 main() ->为函数头 (head), 包含函数名称和参数 , 后紧随一个 '->' 分割符5    io:format("hello world!~n").为函数体 (body), 包含 Erlang 表达式 , 这里调用 io 模块的 format函数在默认输出中打印 "hello world!"

在上面的运行结果中 , 最后有一个 "ok", 这是 io:format/1 的返回值 , 表示打印成功 ,Erlang 中任何函数都有返回值 .

Page 7: Erlang开发及应用

Erlang 语法• Data Types

     8 种基本类型 integer - 4,  -4, 2#100, 16#4, 920828990801238101010.. float - 3.0, 3.5e2, 6.5e-2, (IEEE754 64bit) atom - hello, your_name, root@host, 'IsAtom' binary - <<"some text">> reference - make_ref(), 一个随机值 fun - fun() -> some_expr end port - 与外部应用进行交互的接口 pid - process identifier, 用来操作 process

     2 种复合类型 tuple - {foo, male, 28, china, <<"i love erlang">>}  list - [{ip, any}, {port, 1234}, binary]

Page 8: Erlang开发及应用

Erlang 语法 CON'T• Pattern Match 语言层级的模式匹配 , 代码更加简洁 . 适用于函数调用 , case, receive, try 表达式及 "=" 操作

    case Value of       N when is_integer(N) -> N;       _ when is_list(Value) -> list_to_integer(Value)    end• 变量 大写字母或 "_" 开头 , 只能包含数字 , 字母 ,"_", "@". 如 X, Name1, _Phone, _, Host@ 变量分为 Unbound 和 Bound, Unbound 变量只能用在模式匹配中 . 变量 Bound 后 ,Value 就不可修改 变量只能单次赋值 ( 并发及调试考虑 ) N = 3 (ok) N = 4 ( oops! not match)     

   

Page 9: Erlang开发及应用

Erlang 语法 CON'T• Binary 匹配 使用 binary 可以轻松的实现二进制协议 . (1) 解析 IP 包 : -define(IP_VERSION, 4). -define(IP_MIN_HDR_LEN, 5)....

DgramSize = size(Dgram),case Dgram of<<?IP_VERSION:4, HLen:4, SrvcType:8, TotLen:16,ID:16, Flgs:3, FragOff:13,TTL:8, Proto:8, HdrChkSum:16,SrcIP:32,DestIP:32, RestDgram/binary>> when HLen >= 5, 4*HLen =< DgramSize ->OptsLen = 4*(HLen - ?IP_MIN_HDR_LEN),<<Opts:OptsLen/binary,Data/binary>> = RestDgram,

   

Page 10: Erlang开发及应用

Erlang 语法 CON'T  (2) 自定义协议 假如我们定义了一个协议 , 前 2 bytes(16 位 ) 标记消息体的长度 , 后面为消息体 , 最后为占用 1 个 byte 的结尾符 0xef, 示意图如下 : [--- length ---][--------- payload ------][ef] |------ 2 -------|---------- Length -------|-1-| ( 单位 byte)

则对应的 binary 匹配表达式如下 : ... Packet = ... case Packet of     <<Len:16,  PayLoad:Len/binary, 16#ef>> ->         {body, PayLoad};     _ ->         {error, invalid_packet} end.

   

Page 11: Erlang开发及应用

Erlang 语法 CON'T• 序列化与反序列化 Erlang 中序列化非常简单 term_to_binary/1 - 将任意数据转化为二进制序列 binary_to_term/1 - 将编码的二进制数据转化为 Erlang 数据 比如 : Obj = {apple, {price, 2.0}, {origin, shandong}}, Bin = term_to_binary(Obj), Obj = binary_to_term(Bin)

CouchDB 中大量使用 erlang 的序列化相关函数,完成数据的存储与加载 .

   

Page 12: Erlang开发及应用

Erlang 语法 CON'T• 函数 一切皆函数 , 每个调用都有 return, 函数可以作为基本数 据类型 . 作为返回值 : op_fun('+') ->     fun(N1, N2) -> N1 + N2 end; op_fun('-') ->      fun(N1, N2) -> N1 - N2 end. 作为参数 : > FIsEven = fun(E) -> E band 2#1 =:= 0 end. > lists:filter(FIsEven, [1, 2, 3, 4, 5, 6]). > [2, 4, 6]

   

Page 13: Erlang开发及应用

Erlang 语法 CON'T• Tail Recursion 尾递归 Erlang 中没有 for, while关键字 可以利用递归实现循环 在 server 开发中 ,确保使用尾递归 : server_loop(Args) ->     ...some action...     server_loop(Args). 使用尾递归 , 可以消耗很少的内存 ,仅仅是一个地址跳转 . server_loop(Args) ->     ...some action...     server_loop(Args),     other_fun().

Page 14: Erlang开发及应用

Erlang 语法 CON'T• 发送Message "!" 基于消息通信 ,No Lock! No Shared Memroy!

     Pid ! {msg, "hello, I love erlang"} 向 Pid( 本地或远程主机 ) 代表的进程发送消息• receive

1, 阻塞等待任意消息 :receive     Msg -> okend3,等待消息 ,超时为 5 sec:receive      Msg -> okafter 5000 ->     timeoutend

2, 实现 sleep:receiveafter Time ->    okend4,检测是否存在消息 :receive     SomeMsg -> existafter 0 ->      no_existend

Page 15: Erlang开发及应用

Erlang 并发关于 Process• 每个 Process拥有一个 mailbox,保存消息 • Processes之间通过发送异步Message 进行交互 , 无共享状态• 轻量 ,兼有 OS Process 的隔离及 OS Thread 的高效• Process 具有自己 Stack, Heap, GC• Process 可以位于 Local,也可以位于 Remote Machine• Process 能够进行多种形式的管理及控制 (link, monitor,

exit signal)• Process 为 erlang 高并发 , 高容错 , 分布式的基础• 并发 Process 数 : default 32768, max 268435456

Page 16: Erlang开发及应用

Erlang 并发 CON'T

• 创建 Process spawn(Fun), 比如 > spawn(fun() -> io:format("i'm ~p~n", [self()]) end). i'm <0.33.0>

<0.39.0> spawn(Mod, Fun, Args),比如 > spawn(io, format, ["i'm ~p~n", [self()]]).

 i'm <0.33.0><0.41.0>

spawn_link,  spawn_opt, spawn_monitor ...• 销毁 Process 进程内部调用 exit(Reason), 比如 exit(normal), 正常退出 进程内部发生异常导致程序退出 其他进程调用 exit(PidBeTerminate, Reason)

 

Page 17: Erlang开发及应用

Erlang 并发 CON'T基于 Process 的 http server 框架(one loop process, per conection per process): setup up listen socket,spawn(listen_process).in listen_process:   while can accept new  client connect        accept ,        spawn(client_process)   loop

in client_process:    process protocol,    close socket.     

Page 18: Erlang开发及应用

Erlang 并发 CON'T使用 Erlang 我们可以 :以清晰的风格开发高并发的应用 我们将不在受困于 :线程池的复杂死锁 ,竞赛的窘迫内存泄露局部问题 , 导致的全局崩溃 与跨平台多核 SMP 的格格不入

  

Page 19: Erlang开发及应用

Erlang 分布式• Erlang Node 是分布式通讯的基本单元 , 可以位于同一机器 or 多台机器 , 实现了原语级的节点通讯• Erlang Node 通过 erl -sname Name  or erlang -name Name启动 , 同一台机器可以启动多个 Node• 每台机器上启动 Erlang Node时 , 都会启动一个

epmd(Erlang Port Mapper Daemon, port 4396), 用来进行Node 和 Machine之间的映射

• 不同机器的 Node之间通过 Tcp连接进行 Message传输( 可以自定义分布式通讯实现 , 如通过 ssh)

• global维护一个全局的 Nodes网络• spawn[_link|_opt] 都具有分布式版本 , 可以再其他节点创建 Process

Page 20: Erlang开发及应用

Erlang 分布式 CON'T

• rpc 模块可以在其他 Node 上执行操作• slave, remsh, remote shell等方式启动 ,连接 Erlang

Node• Erlang 中进程具有位置透明性• 通过 message 及 receive 表达式 , 轻松实现同步 or异步 , timeout等网络通信中多种机制• Erlang 本身提供 tcp,udp等常规的网络编程方式• 使用 Erlang 内建分布式机制 , 可以快速开发多种应用 ,也可以基于 socket 开发各种专有应用

Page 21: Erlang开发及应用

Erlang 分布式 CON'T

Page 22: Erlang开发及应用

Erlang 分布式 CON'T

节点 A2连接节点 B2步骤1. Node A2, B2 启动 ,绑定一个本机端口 , 并注册到本机的

epmd(default port 4396)– A2连接 HostB epmd,请求获取 B2节点的绑定端口– HostB epmd将 B2 的 bind port 及 dist 协议版本等信息返回给 A2–  A2 与 B2 协商 , 建立 tcp连接 , 如果连接成功 ,维护一个

tick, 来定期检测 B2节点 – A2 与 B2节点之间的消息 ,通过此连接进行发送

 

Page 23: Erlang开发及应用

Erlang OTP

• OTP(Open Telecom Platform),其定义了一系列项目开发中需要的模式及部署升级策略,为提高开发效率,构建高效,稳定系统提供了巨大的帮助。• 同最初时的专有电信平台应用已没有太多关系• 当前系统都是采用 OTP 进行开发• Erlang 中各种 lib 都是基于 OTP 开发• 可以理解成某种轻量的框架,或者具体化的设计模式• behaviours 包含 :application, supervisor, gen_server,

gen_fsm, gen_event• application, release, release handling• 提供应用的部署,升级,回退等实现

Page 24: Erlang开发及应用

Erlang OTP CON'TBehaviours通过定义一些简单的 callback 模块实现特定功能 .

• application - 定义 application,实现某种功能,由其他behaviours 组成

• supervisor - 定义一个 supervisor tree,实现各种策略的任务重启机制• gen_server - 定义一个通用的 server 模型,一个 process

loop,提供同步异步接口• gen_fsm - 实现一个状态机• gen_event - 实现一个 event manager 及 event handler 模型

Page 25: Erlang开发及应用

与其它语言的交互• External App 外部应用崩溃不会影响 Erlang 虚拟机

o Ports - 通过 port 与外部应用交互 (stdin/stdout)o Erl_Iterface - 提供 c 的封装,方便开发 port 应用

• Link in Driver shared library (SO in Unix, DLL in Windows),影响 Erlang虚拟机稳定性(不推荐)• Port dirvers - 提供 c封装,运行在 erlang 虚拟机内部• C Nodes 遵照 erlang 的交互协议, 使用 c 实现的一个 erlang node• Jinterface 提供一系列与 Erlang 进行交互的 Java 包

Page 26: Erlang开发及应用

Erlang 代码片段• 求某个数的阶乘

                  factorial(0) -> 1;         factorial(N) -> N * factorial(N-1).

• 获取远程机器的 issue 信息( linux)       -module(issue).       -compile([export_all]).       %% start server       server() ->            register(issue_server, spawn(fun server_loop/0)).

       server_loop() ->            receive                   {From, {get, issue}} ->                  From ! {issue, get_issue()};            _ ->                ok             end,           server_loop().

    

Page 27: Erlang开发及应用

Erlang 代码片段 CON'tget_issue() ->    {ok, Bin} = file:read_file("/etc/issue"),    Bin.

%% start clientclient(ServerNode) ->    true = net_kernel:connect_node(ServerNode),    {issue_server, ServerNode} ! {self(), {get, issue}},    receive        {issue, Issue} ->            io:format("server issue:~s~n", [Issue])    after 1000 ->            io:format("receive issue time out~n")    end.

调用:$ erl -sname server(server@litao)1> issue:server().true$ erl -sname client(client@litao)1> issue:client('server@litao').server issue:Ubuntu 9.04 \n \l

    

Page 28: Erlang开发及应用

产品开发流程1.架构设计2.单台 or 分布式? Master-Slave or Grid?  Monitor,     Failover,

Net Comunication, Database, Replica ...3. OTP Behaviour

how many application?use supervisor, gen_server, gen_fsm, gen_event

4. Coding, 及单元测试用例 . 每个 module 都经过测试 (eunit)5.编写系统测试框架,覆盖测试,确保系统正确 (common test)6.压力测试,分析性能瓶颈,进行优化 (fprof)7.系统上线,监控功能 (ganglia, nagios, monit)8.新的功能或需求,重复 2-7

Page 29: Erlang开发及应用

一些工具appmon - OTP application 监控工具cover -  erlang 代码覆盖测试ntop - 显示 Node 中进程信息 (unix top)make - erlang 中的 make工具pman - erlang 中进程管理器tv - ets 和 mnesia 查看器fprof -  erlang 系统性能分析common_test - erlang测试框架dialyzer - 代码静态分析debugger - 单步调试工具,基于 (tcl/tk)

Page 30: Erlang开发及应用

学习资源Erlang官方网站http://www.erlang.org/doc Erlang China http://www.erlang-china.org/Erlang Mailisthttp://www.nabble.com/Erlang-Questions-f14096.htmlErlang Planethttp://www.planeterlang.org/Erlang 非业余研究http://mryufeng.javaeye.com/Erlang Display http://erlangdisplay.javaeye.com/

Page 31: Erlang开发及应用

开源项目ejabberd - the Erlang Jabber/XMPP daemon RabbitMQ - AMQP serverCouchDB - schema-free document databaseTsung - multi-protocol distributed load testing Scalaris - distributed key-value storeDisco - MapReduce Framework Mochiweb - Powerful Http Server Tookit

自己动手发起 erlang 开源项目 !

Page 32: Erlang开发及应用

案例• AXD301 • 高并发的电信交换机• 99.9999999% 可靠性 (~3ms 故障 / 年 )• 超过 100万行 Erlang 代码• 软实时系统 • 高容错

Page 33: Erlang开发及应用

案例

• WEB IM 后台 (mochiweb)•  7+ 百万活跃用户• ~ 100 server• ajax + comet(long-polling)

Page 34: Erlang开发及应用

更多应用