Archive

Archive for the ‘源码分析’ Category

Erlang vheap刨析和注意事项

October 19th, 2013 Comments off

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

本文链接地址: Erlang vheap刨析和注意事项

Erlang从R13B03开始引入了vheap的概念,具体参见这篇文章:R13B03 binary vheap有助减少binary内存压力
官方的release note里面简单的解释了下:

OTP-8202 A new garbage collecting strategy for binaries which is more
aggressive than the previous implementation. Binaries now has
a virtual binary heap tied to each process. When binaries are
created or received to a process it will check if the heap
limit has been reached and if a reclaim should be done. This
imitates the behavior of ordinary Erlang terms. The virtual
heaps are grown and shrunk like ordinary heaps. This will
lessen the memory footprint of binaries in a system.

但除此之外,无法找到更细的文档。最近在做的服务器程序里面用到了大量的binary, 需要对binary的行为做详细的分析,所以就顺便把vheap好好整理下。

我们首先看下如何控制vheap.
首先看下全局的设置, 参见这里

+hmbs Size
Sets the default binary virtual heap size of processes to the size Size.

如果不设定的话,这个值默认是:

./erl_vm.h:62:#define VH_DEFAULT_SIZE 32768 /* default virtual (bin) heap min size (words) */

我们来验证下我们的设置:

Erlang R16B03 (erts-5.10.4) [source-73d1b4a] [64-bit] [smp:16:16] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V5.10.4  (abort with ^G)
1>  erlang:system_info(min_bin_vheap_size).
{min_bin_vheap_size,46422}

oops, 怎么对不起来呢?
看下代码,原来在erl_init里面会对这个值再进行调整:
Read more…

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

决定vheap大小的golden ratio算法(1.61803398875)鉴赏

October 19th, 2013 1 comment

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

本文链接地址: 决定vheap大小的golden ratio算法(1.61803398875)鉴赏

摘抄自Erlang release note:

The vheap size series will now use the golden ratio instead of doubling and fibonacci sequences.

决定binary heap的大小现在是黄金分割率算法,很有意思,给大家参考下:

/* grow
*
* vheap_sz ======================
*
* vheap 75% + grow
* ———————-
*
* vheap 25 – 75% same
* ———————-
*
* vheap ~ – 25% shrink
*
* ———————-
*/

代码如下:

//erl_gc.c:2155
static Uint64
do_next_vheap_size(Uint64 vheap, Uint64 vheap_sz) {
    if ((Uint64) vheap/3 > (Uint64) (vheap_sz/4)) {
        Uint64 new_vheap_sz = vheap_sz;
        while((Uint64) vheap/3 > (Uint64) (vheap_sz/4)) {
            /* the golden ratio = 1.618 */
            new_vheap_sz = (Uint64) vheap_sz * 1.618;
            if (new_vheap_sz < vheap_sz ) {
                return vheap_sz;
            }
            vheap_sz = new_vheap_sz;
        }

        return vheap_sz;
    }

    if (vheap < (Uint64) (vheap_sz/4)) {
        return (vheap_sz >> 1);
    }

    return vheap_sz;

}

祝大家玩得开心!

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

heart低级bug修复过程

October 16th, 2013 3 comments

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

本文链接地址: heart低级bug修复过程

昨天晚上@华侨E 同学在微博上问了个问题:

想跟你探讨下Erlang heart的一个问题?就是打开启heart的时候,调用heart:set_cmd/1了设置自启命令后,如果这个命令字符长度大于128以上的时候,再调用heart:get_cmd/0时就会获取不到上面设置的命令,接着引起系统挂起,并且与beam通讯60秒超时,然后发生重启,看了heart.c的代码也没发现什么问题。不知道你有什么思路?

heart是Erlang系统可靠性最后的防线,如果有问题后果很严重的, 晚节不保。

我们马上来重现下这个问题:

$ erl -heart
heart_beat_kill_pid = 29045
Erlang R17A (erts-5.11) [source-18d4e3e] [64-bit] [smp:16:16] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V5.11  (abort with ^G)
1> Cmd=string:copies("a",128).
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
2> heart:set_cmd(Cmd).
ok
3> heart:get_cmd().   
heart: Wed Oct 16 10:18:20 2013: heart-beat time-out, no activity for 63 seconds
Killed
$ sh: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: command not found
heart: Wed Oct 16 10:18:21 2013: Executed "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -> 32512. Terminating.

果然调用heart:get_cmd的进程被挂起,63秒后系统vm进程被heart杀掉,试图重新启动一个新进程。上面的实验可以验证2个事情:
1. heart:get_cmd调用在Cmd超过128长度的时候被挂起
2. heart:set_cmd的结果是对的,我们设定的Cmd即使超过128也是正常的。
3. heart重启机制是正常的。

我们接着调查,祭出我们的利器 dbg ,来帮忙看下为什么get_cmd被挂起。
我们用dbg来跟踪下heart模块的函数调用情况:
Read more…

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

Categories: Erlang探索, 源码分析 Tags: ,

调查使用binary最多TOPN进程

October 15th, 2013 Comments off

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

本文链接地址: 调查使用binary最多TOPN进程

Erlang程序是非常健壮的,通常一个典型的虚拟机里面跑很多进程,这些进程即使有bug,按照erlang的哲学是快速死掉,系统留下异常堆栈,很容易发现问题。照理说erlang是很少crash的,但实际情况不是这样的。

在erlang VM crash的案例中,我们会发现大部分的网络服务器的原因都是binary内存不够申请不出来,所以内存短缺是最致命的影响稳定的因素。通常设计良好的erlang程序,按照otp的设计哲学不会占用太多内存的,即使占用了gc也很快就会回收的,除了binary这个内存使用大户。

比如说网络服务器程序,我们用binary来保存用户的封包,我们无法预测用户要发送多大的包,比如上限是50M,如果我们的系统有1000个这样的用户,在极端情况下,我们是要耗用50G内存的。通常在这种情况下,我们拿不出这么多物理内存,然后crash就很大概率会发生。

调查哪些进程用掉了最多的binary内存就很有必要了,我们在极端情况下,可以选择性的杀掉这些内存,保护自己不至于毁灭。

erlang:process_info有个未公开的选项 binary用来获取这个进程拥有的binary情况。

我们看下它的实现:

static Eterm
bld_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh)
{
    struct erl_off_heap_header* ohh;
    Eterm res = NIL;
    Eterm tuple;

    for (ohh = oh->first; ohh; ohh = ohh->next) {
        if (ohh->thing_word == HEADER_PROC_BIN) {
            ProcBin* pb = (ProcBin*) ohh;
            Eterm val = erts_bld_uword(hpp, szp, (UWord) pb->val);
            Eterm orig_size = erts_bld_uint(hpp, szp, pb->val->orig_size);

            if (szp)
                *szp += 4+2;
            if (hpp) {
		Uint refc = (Uint) erts_smp_atomic_read_nob(&pb->val->refc);
                tuple = TUPLE3(*hpp, val, orig_size, make_small(refc));
                res = CONS(*hpp + 4, tuple, res);
                *hpp += 4+2;
            }
        }
    }
    return res;
}


Eterm
process_info_aux(Process *BIF_P,
                 Process *rp,
                 Eterm rpid,
                 Eterm item,
                 int always_wrap)
{
 ...
   case am_binary: {
        Uint sz = 3;
        (void) bld_bin_list(NULL, &sz, &MSO(rp));
        hp = HAlloc(BIF_P, sz);
        res = bld_bin_list(&hp, NULL, &MSO(rp));
        break;
    }
...
}

这个选项会返回一个bin情况tuple的列表,每个tuple的第一个是binary的地址,第二个是大小,第三个是引用次数。

我们来演示下如何使用:
Read more…

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

application配置文件和热升级

August 29th, 2013 Comments off

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

本文链接地址: application配置文件和热升级

前面我们一直说过erlang是以app为单位来组织程序,数据,配置等信息,让这些信息聚合在一起成为一个整体,设计上和unix系统一模一样。 那app的配置信息存在哪里呢?

配置信息有三种方式体现(其实是4种):
1. .app文件里面的env字段, 通常是MyApplication.app, 具体参见这里
2. .config文件,通常是sys.config,具体参见这里
3. 命令行 erl -ApplName Par1 Val1 … ParN ValN 具体参见这里

我们摘抄重要的信息如下:
方式1:

7.8 Configuring an Application

An application can be configured using configuration parameters. These are a list of {Par, Val} tuples specified by a key env in the .app file.

{application, ch_app,
[{description, “Channel allocator”},
{vsn, “1”},
{modules, [ch_app, ch_sup, ch3]},
{registered, [ch3]},
{applications, [kernel, stdlib, sasl]},
{mod, {ch_app,[]}},
{env, [{file, “/usr/local/log”}]}
]}.
Par should be an atom, Val is any term. The application can retrieve the value of a configuration parameter by calling application:get_env(App, Par) or a number of similar functions, see application(3)

方式2:

A configuration file contains values for configuration parameters for the applications in the system. The erl command line argument -config Name tells the system to use data in the system configuration file Name.config.

Configuration parameter values in the configuration file will override the values in the application resource files (see app(4)). The values in the configuration file can be overridden by command line flags (see erl(1)).

The value of a configuration parameter is retrieved by calling application:get_env/1,2.

方式3:

The values in the .app file, as well as the values in a system configuration file, can be overridden directly from the command line:

% erl -ApplName Par1 Val1 … ParN ValN

这三种方式都可以很方便的来设置应用的配置信息,由于一个应用会依赖于其他很多应用,所以会有很多的配置信息,这里我比较推荐sys.config方式,这也是rebar组织配置文件的标准形式。
Read more…

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

erlang关键的环境变量

August 23rd, 2013 Comments off

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

本文链接地址: erlang关键的环境变量

Erlang新增全面的系统信息收集器-system_information模块 这个模块列出来以下的环境变量,对系统运行非常关键,你都了解吗?

+%% get known useful erts environment
+
+os_getenv_erts_specific() ->
+ os_getenv_erts_specific([
+ “BINDIR”,
+ “DIALYZER_EMULATOR”,
+ “CERL_DETACHED_PROG”,
+ “EMU”,
+ “ERL_CONSOLE_MODE”,
+ “ERL_CRASH_DUMP”,
+ “ERL_CRASH_DUMP_NICE”,
+ “ERL_CRASH_DUMP_SECONDS”,
+ “ERL_EPMD_PORT”,
+ “ERL_EMULATOR_DLL”,
+ “ERL_FULLSWEEP_AFTER”,
+ “ERL_LIBS”,
+ “ERL_MALLOC_LIB”,
+ “ERL_MAX_PORTS”,
+ “ERL_MAX_ETS_TABLES”,
+ “ERL_NO_VFORK”,
+ “ERL_NO_KERNEL_POLL”,
+ “ERL_THREAD_POOL_SIZE”,
+ “ERLC_EMULATOR”,
+ “ESCRIPT_EMULATOR”,
+ “HOME”,
+ “HOMEDRIVE”,
+ “HOMEPATH”,
+ “LANG”,
+ “LC_ALL”,
+ “LC_CTYPE”,
+ “PATH”,
+ “PROGNAME”,
+ “RELDIR”,
+ “ROOTDIR”,
+ “TERM”,
+ %”VALGRIND_LOG_XML”,
+
+ %% heart
+ “COMSPEC”,
+ “HEART_COMMAND”,
+
+ %% run_erl
+ “RUN_ERL_LOG_ALIVE_MINUTES”,
+ “RUN_ERL_LOG_ACTIVITY_MINUTES”,
+ “RUN_ERL_LOG_ALIVE_FORMAT”,
+ “RUN_ERL_LOG_ALIVE_IN_UTC”,
+ “RUN_ERL_LOG_GENERATIONS”,
+ “RUN_ERL_LOG_MAXSIZE”,
+ “RUN_ERL_DISABLE_FLOWCNTRL”,
+
+ %% driver getenv
+ “CALLER_DRV_USE_OUTPUTV”,
+ “ERL_INET_GETHOST_DEBUG”,
+ “ERL_EFILE_THREAD_SHORT_CIRCUIT”,
+ “ERL_WINDOW_TITLE”,
+ “ERL_ABORT_ON_FAILURE”,
+ “TTYSL_DEBUG_LOG”
+ ]).

翻文档吧,都是很有意思的控制参数。

祝玩得开心!

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

Categories: Erlang探索, 源码分析 Tags:

再谈crashdump产生注意事项

August 23rd, 2013 Comments off

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

本文链接地址: 再谈crashdump产生注意事项

在前面的博文里面,我们提到了crashdump的作用, 以及看门狗heart的工作原理,我们可以在程序crash后,让heart看门狗重新帮我们拉起来。

这里有几个问题需要注意:
1. 看门狗检查失效的时间,默认是65秒。
2. erlang系统在crash的时候会记录crashdump, 操作系统会产生coredump, 这个时间到底是多长。

代码证明如下:

/* heart.c */
...
/*  Maybe interesting to change */
/* Times in seconds */
#define  HEART_BEAT_BOOT_DELAY       60  /* 1 minute */
#define  SELECT_TIMEOUT               5  /* Every 5 seconds we reset the                                                  
                                            watchdog timer */

/* heart_beat_timeout is the maximum gap in seconds between two                                                           
   consecutive heart beat messages from Erlang, and HEART_BEAT_BOOT_DELAY                                                 
   is the the extra delay that wd_keeper allows for, to give heart a                                                      
   chance to reboot in the "normal" way before the hardware watchdog                                                      
   enters the scene. heart_beat_report_delay is the time allowed for reporting                                            
   before rebooting under VxWorks. */

int heart_beat_timeout = 60;
int heart_beat_report_delay = 30;
int heart_beat_boot_delay = HEART_BEAT_BOOT_DELAY;
...

这二个时间都会影响系统重新启动的间隔时间。
而crashdump的dump文件名、dump时间和优先级由下面几个变量来控制:

ERL_CRASH_DUMP
If the emulator needs to write a crash dump, the value of this variable will be the file name of the crash dump file. If the variable is not set, the name of the crash dump file will be erl_crash.dump in the current directory.

ERL_CRASH_DUMP_NICE
Unix systems: If the emulator needs to write a crash dump, it will use the value of this variable to set the nice value for the process, thus lowering its priority. The allowable range is 1 through 39 (higher values will be replaced with 39). The highest value, 39, will give the process the lowest priority.

ERL_CRASH_DUMP_SECONDS
Unix systems: This variable gives the number of seconds that the emulator will be allowed to spend writing a crash dump. When the given number of seconds have elapsed, the emulator will be terminated by a SIGALRM signal.

If the environment variable is not set or it is set to zero seconds, ERL_CRASH_DUMP_SECONDS=0, the runtime system will not even attempt to write the crash dump file. It will just terminate.

If the environment variable is set to negative valie, e.g. ERL_CRASH_DUMP_SECONDS=-1, the runtime system will wait indefinitely for the crash dump file to be written.

This environment variable is used in conjuction with heart if heart is running:

ERL_CRASH_DUMP_SECONDS=0
Suppresses the writing a crash dump file entirely, thus rebooting the runtime system immediately. This is the same as not setting the environment variable.

ERL_CRASH_DUMP_SECONDS=-1
Setting the environment variable to a negative value will cause the termination of the runtime system to wait until the crash dump file has been completly written.

ERL_CRASH_DUMP_SECONDS=S
Will wait for S seconds to complete the crash dump file and then terminate the runtime system.

如果我们不想产生coredump 可以透过 -env ERL_CRASH_DUMP_SECONDS 0 来关掉,避免产生dump时间过长的悲剧。同时每次crashdump产生的文件名相同,可以在启动通过 -env ERL_CRASH_DUMP erl_crash_date_time.dump 来修改,避免覆盖掉。

祝玩得开心!

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

Categories: Erlang探索, 源码分析 Tags: