erlang 监听高并发socket

原文 2014-05-29 22:58:26 发表于 CSDN,这里对以前写的文章做下收录。

看了erlang的一些开源网络框架RabbitMQ、Ranch,他们都使用多个进程同时accept一个socket。这种方式在使得socket端口监听的工作分担了更多的调度机会,但是,在erlang中,socket接受一个新连接后,如果想让另一个进程处理消息,就要显式的调用gen_tcp:controlling_process(Socket, Pid)。

所以问题来了,erlang多个进程同时监听一个socket安全吗?
这种方式在早期的erlang是不安全的,但R11B03 版本之后,erlang做了改进,允许多个进程同时监听同一个socket。

erlang R11B03 更新日志
OTP-6416 gen_tcp now allows for several processes to issue accept calls to the same listen-socket simultaniously. The different accepting processes will get connected sockets on a first-come-first-served basis.

当多个进程同时accept一个socket,erlang 内部将使用队列保存acceptor信息,以先来先服务的原则将新的连接关联到acceptor,再给acceptor投递消息 {inet_async, L, Ref, Result}。
具体看\erts\emulator\drivers\common\inet_drv.c 的 tcp_inet_ctl 函数,erlang对socket的处理都集中在inet_drv.c

erlang配合{backlog, N},监听新连接效果更佳
backlog是erlang用来设置socket等待连接队列。N为队列的长度,默认值5,显然太小了

erlang binary 数据转换问题

原文 2015-01-12 00:11:27 发表于 CSDN,这里对以前写的文章做下收录。

erlang 提供 binary_to_term,把一个二进制数据转为原始的 erlang 数据。但是,这个函数也有副作用。如果直接将对端传来的数据做一次 binary_to_term,就有可能导致VM crash掉。

binary_to_term 副作用
这是因为二进制数据带有原子时,binary_to_term 会生成这些原子。但VM原子总数是有限制,而且原子不参与GC。假如数据带有原子数量超过erlang VM限制,就会导致VM crash
所以,针对这个问题,erlang提供了另外一个函数 binary_to_term(Binary, [safe]),这个函数不会生成新的的原子,在这点上,这两个函数关系也像 list_to_atom 和 list_to_existing_atom

1> term_to_binary(atom).
<<131,100,0,4,97,116,111,109>>
2> binary_to_term(v(1), [safe]).
atom
3> binary_to_term(v(1)).
atom
4> binary_to_term(<<131,100,0,4,116,101,115,116>>, [safe]).
%%这里会抛出异常
** exception error: bad argument
     in function  binary_to_term/2
        called as binary_to_term(<<131,100,0,4,116,101,115,116>>,[safe])
5> binary_to_term(<<131,100,0,4,116,101,115,116>>).
test
6> binary_to_term(<<131,100,0,4,116,101,115,116>>, [safe]).
%%这里就不会抛出异常
test

继续阅读erlang binary 数据转换问题

erlang二进制数据垃圾回收

原文 2014-06-10 01:01:57 发表于 CSDN,这里对以前写的文章做下收录。

erlang 二进制数据在内存中有两种存在形式,当数据大小不到 64 bytes,就直接存在进程堆内,如果超过了 64 bytes,就被保存到进程外的共享堆里,可以给节点内所有进程共享。

erlang 有两种二进制容器:heap binaries 和 refc binaries。
heap binaries

Heap binaries are small binaries, up to 64 bytes, that are stored directly on the process heap. They will be copied when the process is garbage collected and when they are sent as a message. They don't require any special handling by the garbage collector.

这个就是进程堆二进制,是一些比较小的二进制数据,每个数据大小不超过 64bytes,这些数据保存在进程堆内。对于这里的二进制数据,垃圾回收走的是进程堆数据的回收机制,参考这里。如果发给其他进程的消息含有这些数据,erlang 将直接复制一份到别的进程堆内。
继续阅读erlang二进制数据垃圾回收

erlang 开发防坑指南

原文 2015-02-12 23:25:02 发表于 CSDN,这里对以前写的文章做下收录。

任何语言在使用中都会遇到这样那样的问题,erlang也是。这里整理下我遇到的一些问题,避免继续踩坑。说实话,“防坑指南”这个标题有点过于招摇,不过还是希望引起重视,避免在实际开发中重复犯这些问题。

'--' 运算与 '++'运算

1> [1,2,3,4] -- [1] -- [2]. 
[2,3,4]

算是erlang经典的问题了。这是从后面算起的,先算 [1] -- [2] ,得到 [1] 后被 [1,2,3,4] --,最后得到 [2,3,4]
 '++'运算也是一样的,也是从后面开始算起。

2> [1,2,3,4] -- [1] ++ [2,3,4].
[]

另外,以下这种情况也要注意,只会减去遇到的第一个元素。

3> [1,2,3,2] -- [2].
[1,3,2]

继续阅读erlang 开发防坑指南

erlang 判断导出函数问题

原文 2014-11-01 01:27:49 发表于 CSDN,这里对以前写的文章做下收录。

erlang 本身提供一个接口 erlang:function_exported/3,可以用来检查模块是否有导出函数,但是有时候这个接口无法正常使用。
下面重现一下这个问题:

1> erlang:function_exported(crypto,start,0).
false
2> crypto:start().
ok
3> erlang:function_exported(crypto,start,0).
true

注意:例子中并不是说一定要 crypto:start() 才能使用这个函数,只是说这个函数确实存在。
继续阅读erlang 判断导出函数问题

erlang 热更新实现分析

原文 2015-02-10 01:08:22 发表于 CSDN,这里对以前写的文章做下收录。

Joe Armstrong 在描述 Erlang 的设计要求时,就提到了软件维护应该能在不停止系统的情况下进行。在实践中,我们也因为这种不停止服务的热更新获益良多。那么 Erlang 是如何做到热更新的呢?这就是本文要讨论的问题。

erlang VM 为每个模块最多保存 2 份代码,当前版本'current'和旧版本'old',当模块第一次被加载时,代码就是'current'版本。如果有新的代码被加载,'current'版本代码就变成了'old'版本,新的代码就成了'current'版本。erlang 用两个版本共存的方法来保证任何时候总有一个版本可用,对外服务就不会停止。

前言

为什么代码热更新时不影响进程运行?
为什么进程要使用外部调用(M:F/A)才能切换到新代码?
为什么可以同时使用2个版本的代码?
为什么只能一个模块一个模块热更?
....

我们总会有很多疑问,但一切的答案都在源码上。现在深入剖析下 erlang 热更新实现机制,相信你的疑惑可以找到答案。
继续阅读erlang 热更新实现分析