友情链接
· 歪酷博客
· 管理我的Blog
· 我拍的照片
· <! --- Dude Start Here ---!>
· 多儿
· 洪七公的直接
· 科大吴老师
· 维C周星星
· 民工土人男
· 小猪土人女
· 闺中贝贝赵
· 女经纪范^_^
· 甜甜的老鼠
· 嗔!一群土人
· 佳佳的水云间
· micheal@uestc
· 摇滚女青年
· lyker@uestc
· JalenWoo@uestc
· plan@uestc
· 帅哥包同学
· 阿楠@uestc
· cicy小朋友
· 翠花的酸菜
· 终于承认是小资
· rice@uestc
· J@WING@uestc
· 咨询业的付毒人
· 丁珊珊同学
· 我的徒弟
· 五弟面爷
· 科大人文办周总
· <! --- Dude End Here ---!>
· <! --- Bookmark Start Here ---!>
· LWN
· Wikipedia
· ScienceWorld
· Public Library of Science
· <! --- Bookmark End Here---!>

Perpetuum Vestigium

一花一世界,一叶一乾坤。


kaby @ 2008-06-02 22:59

1. request per second
a jerky server model
这次做的是一个http log服务器,需要在有限的资源下支持尽可能高的PV。
提高PV,无非是改进两个指标:1. Connect Time;2. Process Time。
其实这两个问题都是一个思路,后面我们可以看到。

对于传统的长连接TCP服务,鉴于Erlang的低成本线程调度,一般采取的方案是每个TCP连接在gen_tcp:accept时spawn一个独立的线程处理后续的C/S交互。
但是对于眼下的http log服务,首先并不是一个keep-alive的连接:我们的设计目标是尽可能快的返回http响应并关闭TCP Socket,传统模型不是非常适用。
于是便有了一种callback模型:用一个daemon线程专司接收消息并创建监听线程,由监听线程阻塞在gen_tcp:accept上,例子如下:
start_server() ->
    DT = spawn(test, daemon, [Listen_Sock]),
    DT ! {new}.

daemon(Listen_Sock) ->
    receive
       {new} ->
          spawn(test, proc, [Listen_Sock, self()])
    end.

proc(Listen_Sock, DT) ->
    Client = gen_tcp:accept(Listen_Sock),
    DT ! {new},
    gen_tcp:send(Client, "HTTP 200\n\r"),
    % do further process
这种方案的好处在于,把spawn的开销从http处理中剥离了开来:
所有的处理线程都是预生成后阻塞在哪里,gen_tcp:accept后无需spawn直接执行后续的代码。
再配合+K true参数使用kqueue模型,可以预先生成多个proc的线程阻塞在accept上,可极大提高性能。

至于Process Time,同样是依赖预处理的思路:
因为http log服务涉及到Set-Cookie等操作,取localtime并格式化的过程中涉及到大量系统调用和字符串操作,在Erlang中开销不小。
解决办法是在daemon中预先生成好不同情况下需要返回的各色字符串,作为参数传给spawn出来的proc线程,剩下的操作无非是 条件判断->发送。

还有非常重要的一点是根据县城内处理数据的规模,使用spawn_opt设置合适的process heap大小
因为避免后期的heap扩充是开销非常大的一种操作,在轻量级线程内尤其要避免。


2. normal optimization[待续]

为了保证daemon进程的栈空间不增长,必须把函数写成tail-recursive。
这个积累还是很惊人的,而且属于不可回收空间;
如果你的服务运行那个多日因为内存问题挂掉,可以检查下所有的守护线程。

3. memory (crash dump)[待续]

4. 垃圾回收
期间遇到了比较到的严重的内存问题,造成服务器几个小时候因为alloc()失败而崩溃;
查看erlang:memory()的信息,发现processes占用绝大部分内存,开始误认为是产生了大量无用线程;
最后确诊还是因为deque大量申请释放,造成heap的回收效率问题以至于内存不够用。
使用spawn_opt设置fullsweep_after为0没有用,非常奇怪;必须显式调用erlang:garbage_collect()。

经过这几天压力测试,Erlang的garbage collection机制还是相当强健的:
在每秒近万次的不规则数据申请、释放的压力下,十几个小时后运行依然稳健,整体回收效率很高并且没有拖累到业务逻辑的性能。
可怜的Java…………

5. profiling[待续]
cprof

先列个题头,回头再写。。。

迅猛把活干完,然后去旅行。
What a wonderful world.


Ver. 3.14
周末肉过来了,去八达岭过了儿童节,很累。
所以洗洗睡了先,改日再写。

Ver. 3.141
在家了,一个劲的下雨。我华丽的假期



 
kaby @ 2008-05-22 08:21

Everything is settled down.And I am entirely refreshed.

The most urgent is a vocation.


 
kaby @ 2008-05-14 09:20

兄弟们都安好,只是担心汶川的人民。
那一年的十月,在古尔沟看到救援队露营留下的余灰,我确信他们都是好人。

有人说这是上帝对人类的惩罚,但是为什么让那些淳朴的人民来遭难;
而我们这些生活在肮脏的城市里的人却安然无恙,甚至继续玩世不恭,
像对待超级女声一样带着笑意说出阵亡的数字,继续娱乐一切。


Anyway, God bless our fellow.


BTW:
部队虽然抵达了汶川县,但是映秀离汶川县城还很远,现在的道路损毁情况,只能看十五军了,上帝保佑。


 
kaby @ 2008-05-13 00:11

花了两天时间把C FAQ又过了一遍,发现了从前忽略的一些点。

1. 虽然K&R上说结构体必须memcpy或者一个元素一个元素的赋值,其实struct可以直接用=操作符做整体拷贝的;
2. offsetof(),用来计算结构体内成员偏移的宏;
3. 如果函数的返回值为struct,C也会类似C++的在函数形参里加上一个struct *指针的;
4. 可能大家都习惯malloc后做强转了,其实这是含糊的C/CPP编译器混用的恶果。作为C程序,其一void *可以自动转换,其二因为C默认函数返回int,如果malloc没有正确申明,int也会被错误的强转为指针且不报错;
5. sequence point间evaluation的顺序是不保证的;
6. void **是一个很无厘头的东西,void *作为万用指针,void **是什么?指向万用指针的特型指针?
7. 关于申明指针char *p还是char* p的问题,char* p, c这样误导性的代码就是答案。永远写成前者,这不是风格问题;
8. 3["abcde"] 等于 3 + "abcde" 等于"abcde" +3 等于"abcde"[3],华丽的C语言。



 
kaby @ 2008-05-11 13:27

"Fight and you may die, run and you'll live. At least a while. And dying in your beds many years from now, would you be willing to trade all the days from this day to that for one chance, just one chance to come back here and tell our enemies that they may take our lives, but they'll never take our freedom."

 - William Wallace


Background:
成都警方处罚利用四川石化项目散布谣言者》;
上周的南方周末有半版的PX报道,我也觉得四川政府在满足民众知情权之前,如此强势的打压不是非常合理。

PS:
还好不是喉舌大报的新闻,不然英勇的南瓜泡沫死定了。


 
网志分类
· 所有网志 · 壹家杂谈 · Tech. et Sci. · 未分类 ·
最新的评论
· 07/24 生活很幸福啊,还能游泳~~~[:O...
· 07/24 保持队形[:Orz:]
· 07/24 顶上[:Orz:]
· 07/23 最后一句话不知道说了多少次了[:O...
· 07/21 可惜我没有见到你。只有等你下次出差...
· 07/20 难道赶上沙发了?...
· 06/28 mama ,i'm coming ...
· 06/11 都去阿里找妈妈去了...
· 06/08 反腐开始了~
· 06/07 给你说你被帝都腐化了,你不信。[:...
站内搜索

订阅 RSS

0039263

歪酷博客