Archive

Archive for the ‘源码分析’ Category

gen_tcp如何限制封包大小

May 14th, 2013 4 comments

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: gen_tcp如何限制封包大小

我们在做tcp服务器的时候,通常会从安全考虑,限制封包的大小,预防被无端攻击或者避免极端的请求对业务造成损害。
我们的tcp服务器通常是erlang做的,那么就涉及到gen_tcp如何限制封包的大小.

gen_tcp对封包的获取有2种方式:
1. {active, false} 封包透过gen_tcp:recv(Socket, Length) -> {ok, Packet} | {error, Reason} 来接收。
2. {active, true} 封包以消息方式投递。

对于第一种方式:gen_tcp:recv(Socket, Length) 我们开看下代码实现:
Read more…

Post Footer automatically generated by wp-posturl plugin for wordpress.

gen_tcp接收缓冲区易混淆概念纠正

May 14th, 2013 1 comment

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: gen_tcp接收缓冲区易混淆概念纠正

Erlang的每个TCP网络链接是由相应的gen_tcp对象来表示的,说白了就是个port, 实现Erlang网络相关的逻辑,其实现代码位于erts/emulator/drivers/common/inet_drv.c

参照inet:setopts文档,它有三个buffer相关的选项,非常让人费解:

{buffer, Size}
Determines the size of the user-level software buffer used by the driver. Not to be confused with sndbuf and recbuf options which correspond to the kernel socket buffers. It is recommended to have val(buffer) >= max(val(sndbuf),val(recbuf)). In fact, the val(buffer) is automatically set to the above maximum when sndbuf or recbuf values are set.

{recbuf, Size}
Gives the size of the receive buffer to use for the socket.

{sndbuf, Size}
Gives the size of the send buffer to use for the socket.

其中sndbuf, recbuf选项比较好理解, 就是设置gen_tcp所拥有的socket句柄的内核的发送和接收缓冲区,从代码可以验证:

/* inet_drv.c */
#define INET_OPT_SNDBUF     6   /* set send buffer size */
#define INET_OPT_RCVBUF     7   /* set receive buffer size */
static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
{
...
        case INET_OPT_SNDBUF:    type = SO_SNDBUF;
            DEBUGF(("inet_set_opts(%ld): s=%d, SO_SNDBUF=%d\r\n",
                    (long)desc->port, desc->s, ival));
            break;
        case INET_OPT_RCVBUF:    type = SO_RCVBUF;
            DEBUGF(("inet_set_opts(%ld): s=%d, SO_RCVBUF=%d\r\n",
                    (long)desc->port, desc->s, ival));
            break;
...
        res = sock_setopt           (desc->s, proto, type, arg_ptr, arg_sz);
...
}

那buffer是什么呢,他们三者之间的关系? 从文档的描述来看:
It is recommended to have val(buffer) >= max(val(sndbuf),val(recbuf)). In fact, the val(buffer) is automatically set to the above maximum when sndbuf or recbuf values are set.
Read more…

Post Footer automatically generated by wp-posturl plugin for wordpress.

log2的快速计算法

May 9th, 2013 8 comments

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: log2的快速计算法

从erl_mseg.c中摘抄的:

static const int debruijn[32] = {

0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};

#define LOG2(X) (debruijn[((Uint32)(((X) & -(X)) * 0x077CB531U)) >> 27])

供大家参考!

Post Footer automatically generated by wp-posturl plugin for wordpress.

Categories: 源码分析 Tags: ,

Erlang集群全联通问题及解决方案

May 2nd, 2013 10 comments

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: Erlang集群全联通问题及解决方案

Erlang的集群默认情况下是全联通的,也就是当一个节点加入集群的时候,介绍人会推荐集群里面所有的节点主动来和新加入的节点建立联系,
效果如下图:

erlang_connect

具体点讲那就是net_kernel模块负责节点间的通道的建立、检查、断开并提供monitor_node语义。
摘抄 http://www.erlang.org/doc/man/erlang.html 如下:

monitor_node(Node, Flag) -> true
Types:
Node = node()
Flag = boolean()
Monitors the status of the node Node. If Flag is true, monitoring is turned on; if Flag is false, monitoring is turned off.

Making several calls to monitor_node(Node, true) for the same Node is not an error; it results in as many, completely independent, monitorings.

If Node fails or does not exist, the message {nodedown, Node} is delivered to the process. If a process has made two calls to monitor_node(Node, true) and Node terminates, two nodedown messages are delivered to the process. If there is no connection to Node, there will be an attempt to create one. If this fails, a nodedown message is delivered.

Nodes connected through hidden connections can be monitored as any other node.

Failure: badargif the local node is not alive.

其他模块如global, pg2, mnesia都利用这个monitor_node提供的语义来实现更上层的逻辑。那么上面提到的引荐机制正是global模块实现的,它的目的是提供集群层面的名称和进程的映射关系,所以它需要全联通。

学过中学数学的同学都知道系统总的通道的数目是N*(N-1)/2, 随着N的增长,这个数目会急速上升,见下图。

hidden_visible

这个对集群的规模有致命的破坏作用。 这么多链接需要耗用很多资源,更坏的是,erlang为了检测节点的存活,需要定期发心跳包来检查,一分钟一个tick, 这会造成大量的网络风暴。

那么我们如何来避免这个事情呢?
Read more…

Post Footer automatically generated by wp-posturl plugin for wordpress.

Erlang集群RPC通道拥塞问题及解决方案

May 2nd, 2013 1 comment

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: Erlang集群RPC通道拥塞问题及解决方案

Erlang的集群默认情况下是全联通的,也就是当一个节点加入集群的时候,介绍人会推荐集群里面所有的节点主动来和新加入的节点建立联系,
效果如下图:

erlang_connect

我们这次不讲如何避免全联通而是来讲这个节点间通道的问题。

我们知道erlang的消息发送是透明的,只要调用Pid!Msg, 虚拟机和集群的基础设施会保证消息到达指定的进程的消息队列,这个是语义方面的保证。那么如果该Pid是在别的节点,这个消息就会通过节点间的rpc通道来传递。rpc模块就是基于erlang的这个语义在上面实现了远程函数调用。

目前社区推比较推荐erlang服务分层,所以层和层之间的交互基本上透过rpc来进行的。类似下图的分层结构越来越多,当大量的消息在节点间流动的话,势必会造成通道拥塞。

layer

阻塞会导致发送进程被挂起,而rpc是单进程(gen_server)的,被挂起,rpc调用就废了。当然除了RPC, Pid!Msg 这种方式还是可以并行的走的。
这种阻塞极大的影响力系统的rt, 对性能和体验有很大的影响。

那这个问题如何定位、解决呢?Erlang很贴心的提供了一揽子解决方案:

首先是发现问题:

erlang:system_monitor(MonitorPid, Options) -> MonSettings

busy_dist_port
If a process in the system gets suspended because it sends to a process on a remote node whose inter-node communication was handled by a busy port, a message {monitor, SusPid, busy_dist_port, Port} is sent to MonitorPid. SusPid is the pid that got suspended when sending through the inter-node communication port Port.

比如说 riak_sysmon 就用了以下代码:

 BusyDistPortP = get_busy_dist_port(),
    Opts = lists:flatten(
             [[{long_gc, GcMsLimit} || lists:member(gc, MonitorProps)
                                           andalso GcMsLimit > 0],
              [{large_heap, HeapWordLimit} || lists:member(heap, MonitorProps)
                                                  andalso HeapWordLimit > 0],
              [busy_port || lists:member(port, MonitorProps)
                                andalso BusyPortP],
              [busy_dist_port || lists:member(dist_port, MonitorProps)
                                     andalso BusyDistPortP]]),
    _ = erlang:system_monitor(self(), Opts),

当我们收到{monitor, SusPid, busy_dist_port, Port}消息的时候,就可以确认系统经常有阻塞问题。

那么如何解决呢?

社区早就认识到这个问题, 所以设计dist_buf_busy_limit是个可配置的值。
Read more…

Post Footer automatically generated by wp-posturl plugin for wordpress.

lz4: Extremely Fast Compression algorithm

March 15th, 2013 9 comments

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: lz4: Extremely Fast Compression algorithm

最近在不少项目特别是存储相关的项目用到了lz4压缩算法,它有什么特点呢?

LZ4 is a very fast lossless compression algorithm, providing compression speed at 300 MB/s per core, scalable with multi-cores CPU. It also features an extremely fast decoder, with speeds up and beyond 1GB/s per core, typically reaching RAM speed limits on multi-core systems.

这个特性对于需要大吞吐量的压缩场合还是非常有用的,以很小的CPU代价换来更大的存储密度。

官方网站:https://code.google.com/p/lz4/, 摘抄下它的性能指标:

Name Ratio C.speed D.speed
LZ4 (r59) 2.084 330 915
LZO 2.05 1x_1 2.038 311 480
QuickLZ 1.5 -1 2.233 257 277
Snappy 1.0.5 2.024 227 729
LZF 2.076 197 465
FastLZ 2.030 190 420
zlib 1.2.5 -1 2.728 39 195
LZ4 HC (r66) 2.712 18 1020
zlib 1.2.5 -6 3.095 14 210

更多的测试可以看 这里 这里

它还有个高压缩率的版本:

LZ4 HC – High Compression Mode of LZ4

从源码lz4.c可以看到快的原因之一:
lz4

这个技术叫做 “The Blocking Technique”, 见图:
bt

考虑在项目中用起来。

祝玩得开心!

Post Footer automatically generated by wp-posturl plugin for wordpress.

Categories: Linux, 杂七杂八, 源码分析 Tags:

ulimit限制之nproc问题

March 2nd, 2013 4 comments

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: ulimit限制之nproc问题

前两天微博上的@王关胜同学问了个问题:

#ulimit问题# 关于nproc设置:centos6,内核版本是2.6.32. 默认情况下,ulimit -u的值为1024,是/etc/security/limits.d/90-nproc.conf的值限制;注释掉这个限制后,值为95044;手工设置90-nproc.conf文件,值为新设置的值。想请 问这个95044是怎么来的?

这个问题挺有意思的,这里面有二个信息点:

1. 为什么limit配置文件是 /etc/security/limits.d/90-nproc.conf 而不是其他?
2. 为什么是nproc的值95044,而不是其他。

之前我也写了些ulimit的问题的解决,参见 这里

我们来简单的做下实验:

$ cat /etc/security/limits.d/90-nproc.conf          
*      soft    nproc   8933
$ ulimit -u
8933

$ cat /etc/security/limits.d/90-nproc.conf      #注释掉
#*      soft    nproc   8933
$ ulimit -u
385962

我们可以看出就是说当注释掉限制的话,不同的机器值是不同的。

我们先来回答第一个问题:为什么limit配置文件是 /etc/security/limits.d/90-nproc.conf 而不是其他
这个问题早些时候 杨德华 同学碰到了,也写了篇 博文 来解释redhat6下面如何破解nproc的限制,但是文章没提到这个问题。
Read more…

Post Footer automatically generated by wp-posturl plugin for wordpress.

Categories: Linux, 源码分析 Tags: , ,