Silence & Solitude makes...

Pu's mind space

桌上足球防守位心得两则

最近公司新来了第二张桌上足球台,球性和第一张完全不同,所以我想某些技巧和心得可能是因球桌而异的。这里记录的是在双打中本人打防守位的一些总结,只针对我司目前破旧生涩的第一张球桌生效。

成功率要比快速出球重要

防守人很怕对方反弹,但是如果反应够快,可以在对方进攻的第一时间 – 对方前锋出脚之后刚刚回收的期间 – 通过类似前锋反弹的击球方式防守,这样可以轻易突破对方锋线把球输送到前场。 – 这就是我之前总结的快速出球打法
对方进攻失败后把球控制住,选择合适的时机合适的角度,用大力射门的方式把球击出。 – 这是成功率打法。

这里说的结论其实是马后炮,因为我见到了成功率打法的拿了我司桌上足球比赛的冠军,而我–快速出球打法的信奉者–表现并不是很好。其实思考原因也很简单, 因为人的力量和反应时间是几乎固定的两个指标,训练到极致也无法突破某个比例,而桌上足球尺寸的大小已经决定了只可能存在完美的进攻,没有完美的防守。所以除非你的前锋比对方前锋把握能力强10倍,否则不要使用快速出球的打法,虽然突破了对方前锋的第一道防线,很大程度上你的前锋也不会能利用好这个机会,所以相比于把球控下来,这样做(快速出球)无异于把控球状态变为开球状态。

防守的选位

防守的两根杆是要跟着当前球所在的位置结合出球点来调整的。当球不在正中路的时候,对方可能的选择路线有:球当前所在边路的三角,直线,撞另一个边路库的大三角。其中最后一种是可能性最小也是留给了我们最长防守时间的,所以正确的站位应该是(下图中o表示球,【】表示球门,|表示你的防守队员)

1
2
3
4
5
6
7
8
9
[ ]
o
。。。。。。
| |
| | |
[ ]

而不是我之前选的

1
2
3
4
5
6
7
8
9
[ ]
o
。。。。。。
| |
| | |
[ ]

因为显然第一种选位对于斜向来球的防守角度更大,且左边后卫离球门更远,减小了撞左后卫脚折射进球门的概率。

A Programmer's Daily Time Distribution And Beyond

As a programmer, I’ve witnessed peers moaning about working-overtime or being pushed by schedule, such as these. Utopia is coding at home with beer aside, pets/kids occasionally interrupt you with their cuteness, but where are your boss and peers in this territory – if you want be a cathedral guy instead of making a living in the bazaar as a vendor, you can’t go through without them. Certainly, working like that won’t maximize your employer’s profits and can’t cooperate with teammates effectively. So that situation is unreachable, we still have to go to office, but at least there’s a way to make yourself really comfortable in office and your employer get the maximum output from you. But how? I happen to have some shower thoughts the other day regarding this.

Consensuses

We need to make some consensus before making a bargain.

First, programmer’s effective input is not measurable, not by working time, not by code-lines. Unlike manufacturing industry, in which qualified parts built by a worker in a unit time is measurable, building software is always a non-linear work, fixing one critical bug may need as much time as writing ten ‘qualified’ features which passed all unit tests and integrational tests, but would fail the stress test, and of course can require as less time as typing several characters if it’s obvious, to someone – I’m not emphasizing this because this example is focus on the diversity of bugs themselves, so programmers’ diversity is not the point.

Second the output is not measurable either, a software is nothing if there’s no user, or user find it hard to use. Even if we don’t consider the money a software can make, or the productivity a software can improve, as metric, just use the software metrics, like story points in the agile context, it is not measurable too. We all experienced two similar stories bidding the same points, but actually the first implemented one values much than the first one, as you know copy&paste constitute most of the most programmer’s activity.

Bearing these in mind, then, from the manager/employer’s perspective, how does he knows his management job is well done, or how is he get the best of his employers? I don’t think there’s any way, person varies with person, if you can not measure their productivity, just believe they are professional(how to ensure this is another topic and is HR’s duty which is answered when he get the offer), and ensure them are productive. If I were a boss, what I would like to is to just make programmers being in a vigorous state, both mental & physical.

Mentally vigorous

It dictates communication in a proper extent. Communicating with others would help you to recognize your issue-to-handle more clearly, but too much of this would blur your focus, make you not-so-targeted – not to mention occupying your time.

Reading an internet post, raising an issue or service request, talking to peers or join a meeting are all kinds of communicating.

It also demand you to distribute your mental activity reasonably. By distribute reasonably, I mean you might need some music or non work chat when you have worked for long time(say longer than 4 four), as long as there’s meal break and coffee break, this would be a problem, the only constraint it brings is not to work over-time heavily and constantly. But it has another meaning which is often ignored, that is even you have 6 hour code time, if it’s broken down into many piecies, I mean divided by meetings, peer-communications, coffee break or internet surfing, it won’t make ‘mental vigorous’ too, with experience, you at least need a block of 1.5 - 2 hours’ time to solve real-challenging problems.

Physical health

I mean cervical/lumbar spondylosis. The 10 tips to prevent lumbar spondylosis or such things always mention don’t keep sitting in 1 hour, walk every 1 hour or so. I’m suggesting this too, actually this didn’t conflict with the 2 hour block you need to solve real-challenge, you can keep thinking of the same issue with this break. And for other breaks outside the 2 hour, talk with peers or go for coffee is surely OK.

Programmer’s daily time distribution

In common sense, to make you productive, yourself or your manager would give you a list of things-to-do, daily or weekly. Books tell you do so too, but as a mental job, things-to-do didn’t always get done even if you assign enough time to it. As I mentioned, inevitable breaks (for mental and physical healthy) and communications didn’t list in your things-to-do, but they actually effect if you can get things done with fixed time. For not-so-competent tasks, you might need more communication. For boring-tasks, you might breaking more, consciously or not. And also for improvement, you need spend time learning, as an employee, you need spend time to meet executive’s requirement, daily task can easily fail if you count in all these. If you log your time by actual items like communication, break, coding, learning&documenting, instead of business items, problems get more clear.

But unfortunately managers often focus the latter, i.e. today you spend 4 hour on issue1, and 4 hour on issue2, why they are not improving? Not until you and your employers start to care about your first log, i.e. daily time distribution(DTD), would the programmer’s life more easier.

What profile does most of the programmer’s DTD look like actually concretize the so called corporational culture. I feel satisfied with my productivity recently, and I think my DTD is reasonable, I’ll give it here:

item time(h)
communication 3
break 1.5
coding 2
learning&documenting 2

If goes into detail, communication includes peer-communication(work and non-work, email or non-email) or searching for internet for solving a problem(like SF), and also for meetings(mostly not-related with your task-to-do today), so actually it not always help you finish your task; break includes coffee break, toilet, table-football, and surfing internet; coding include write code, and miscellaneous tasks like download ide plugin, checking api(in internet or not) but not include things searching SF; learning and documenting include reading-book/posts not directly related with your task in hand, write summary, or log time in JIRA, or write post in Confluence.

It can vary among programmer and production phase, say if not so competent with your current task, you need to learn more, and non-lead programmer can have more time learning. But in general, I say it could profile the corporational culture. Some “performance-targeted” company use story points or features-finished to measure a programmer, this would elongate the code time, and squeezing others, especially learning and break. Some “performance-targeted” company judge programmer with there sounding, thus making unnecessary communication time long. Even not to extent of squeezing physiologic break time, at least it could break the mental vigor. I’m not senior programmer, just 5 years experience with several companies, I never meet any company whose HR/manager would like to survey/query programmer’s DTD, so that they can introspect how they can help programmer to improve productivity. I’m not try to be sensational and union the programmer’s party to do something, but employer does have to discard the one-sided view of software engineering, either just accept it’s a chaos and hence only measure programmer with final result or regard it an analog of manufacturing and hence don’t respect programmer’s job as mental work. It would bring WIN-WIN if employer and programmer start to know DTD and its means.

每个人的五一

有个词叫“伤春悲秋”。所谓悲秋,就是秋凉天里,天朗气清,看见树叶飘零,感到气温下降而唤起一些对大千世界的悲悯,当然也很容易由外而内思及自己。这种体会我是有过的,或者说每年的秋天都有机会体会。然而“伤春”的说法我一直不敢苟同,甚至无法理解,我一直把它当作是被文人硬加进去的无聊的对偶。然而今年,在这个五一,我却有了不一样的体会。

五一她去山西参加闺蜜的婚礼,我会有一个完整的3天!之前一直憧憬的一口气看一整本书,或者在自己的项目上敲一天的代码似乎终于可以实现了。然而把她送到机场回来我就陷到了与孤独苦战的阶段了–原来我面对整块的孤独时间竟然是手足无措的!跟她在手机上诉苦也无济于事,于是我就在看电视,看书,看电脑,看手机之间频繁地切换着。一面给自己压力说不要这样把整块的时间用散了,一面又无法集中精力做一件事情,承认无聊对于我这样自认内在丰富的人来说简直是打脸。

妈妈打电话来了,知道我一个人在家,让我喊陈苏进出去喝酒,不要闷着。我能理解她的心情。这和我看到碗碗懒懒地趴在阳光下就想带它出去散步,或者看到小雪躺在沙发上玩手机就想带她去吃东西看电影一样。然而我告诉她我还要打游戏,告诉她我并不闷。挂完她的电话,我躺在沙发上睡着了。

睡醒之后继续翻书,贪心算法。对于合适的问题,最短视的策略,亦即使每一个当下利益最大化的行动将会得到全局最优结果。好可笑,这让我想起了和郑扬下棋,他从来没有什么固定阵型或者进攻布局,就是想尽一切办法占得局部的便宜–然而我总是输给他–输给了他中轴线上两个马两个炮这样别扭的阵型。我知道有哪里不对,这样走肯定是会有破绽的,但是还没等我找出破绽,我的局地损失已经让我无法翻盘了。这个世界也是这样,你看到人们涌向雄安买房,你不想当中线上两个炮中间的那个马–像个小丑,你觉得哪里不对,这不是兵法上优雅的阵型,然而你却输了。也许活在当下的世界就是那个适合贪心算法的“合适的问题”吧。不学也罢。

我下楼吃了晚饭,带上来可乐和烟,今天的天气真的不错呢。

晚上的球赛并不好看,曼联和阿森纳都踢得很丑,我从来都觉得她影响了我熬夜看球,没想到她不在里屋睡觉会让球赛变得无聊。半夜一点的时候,三儿发了一个朋友圈说五一快乐–配了张出公司的照片–我想表示一下关心,却不想暴露我自己的无聊,只好等明天再说了。是的,不应该这样,明天还是看个电影吧,《记忆大师》好像可以,订个12点的场吧,正好还可以出去吃饭,免得宅到让关心的人感到落寞。

半醒的时候王体虎打来电话,瞎聊了几句,他正在内蒙打算弄个海外食品店,然而内蒙人喝酒的热情却让我的酒桌苦主碰到的麻烦。起床的时候已经11点半了,电影是看不成了,跟三寒暄了几句,让他别太拼了。窗外,风和阳光共同把杨树打造如水晶塔般粼粼可爱,市声远嚣,愈衬安静。朋友们,我祝你们都好,就如同这春光。

Compare Latin Charactors to Basic ASCII Charactor

In some circumstances we meet words that contains Latin charactors, like the word naïve , especially in names like simão. For some reason, we want to translate them to naive, and simao, or at least we can know that they are equal to naive or simao respectively.

I’ve met such a problem recently, and I try to find a solution to this, but honestly, it’s hard to describe such a question. When I browse all the posible related pages which google shows, I find a function in ES6 called normalize which finally helped me out. If you look at the description of the argument of this function, and finally trace to the concept of the so called Canonical Decomposition, you probably would WOW out like me do. Yes, it’s exactly what we want, we want È É Ê Ë being equal to E, want ìíîï all equal to i. Now with this function, we can easily solve the problem with the help of this function, and I’m really glad I found the solution even before I know how to describe the problem.

So here is the utility function

1
2
3
function convertLatin(str) {
return str.normalize("NFD").match(/\w/g).join("");
}

And you’ll find that convertLatin(“naïve”) === “naive”, and convertLatin(“simão”) === “simao”. Enjoy this small utility!

##Update(26 Mar 2017)

After some close investigation, I found the solution above is neither robust nor necessary, as ES6 have provided official support for this user case, please check the new API of
String.prototype.localeCompare
Intl.Collator

十年

—无韵集句 和小智

青山遮不住
毕竟东流去
十年扬州梦
天凉好个秋

总角宴晏晏
岁月忽已晚
幽并游侠儿
萧萧斑马鸣

<转/译>如何将应用配置打包进Docker

粗译

新手开始部署他们的第一个Docker Container的时候经常会问的一个问题就是:”我该怎么把应用的配置打包进Docker容器里面?”.问题中提到的配置包括worker的数量,JVM的内存大小,或者数据库的连接串.现实中实现这些有一套标准方法,而它们各有利弊.

将配置发送到Docker打包了的应用里的三个半方法

1. 将配置烧进容器里

这可能是最简单的配置了,也就是在Dockerfile里面利用COPY指令把配置文件扔到容器里,或者通过RUN指令执行sed以及echo等命令来修改默认的配置文件.

优点:

缺点:

  • 因为配置已经烧到镜像里,未来可能的配置改动都需要修改Dockerfile并重新build来实现

2a. 利用环境变量动态地配置应用

这是一个在Docker Hub上的镜像比较常用的方法,譬如PostgreSQL的’POSTGRES_USER’和’POSTGRES_PASSWORD’这两个环境变量.

简单地说,当你启动容器docker run的时候,需要指定环境变量,而容器的进入点(Entry point)也就是启动脚本会寻找这些变量,并把他们用在相应的配置文件里.

需要提的是,启动脚本应该提供有意义的缺省值,以防用户没有提供这些环境变量.

优点:

  • 从配置角度看,这样的容器更灵活

缺点:

  • 打破了生产/开发环境的一致性要求,也就是说其他人可以通过不同的配置使得容器的行为在生产/开发环境下不一致
  • 一些复杂的配置无法映射为简单的键值对

2b. 利用环境变量动态地配置应用

和上面的一样,但是启动脚本是从网络,像是Consul或者etcd来获取配置参数.

这就使得通过环境变量来实现复杂配置成为可能.因为键值对存储器可以有多层结构.值得一提的是有很多工具可以用来抓取键值对并替换到你的配置文件中.而像confd这类工具甚至可以在配置改变时自动重新加载应用.这就使得应用的配置更加动态化.

优点:

  • 配置更动态
  • 键值存储使得复杂配置成为可能

缺点:

  • 同样违反了生产/开发环境一致性(译注:和所谓的immutable container是同一个概念)
  • KV store必须高可用,因为所有的容器配置都依赖于这个存储器

3. 将配置文件目录挂载到Docker Volumes

Docker Volume介绍略

如果配置文件正好在运行容器的文件系统上,可以通过挂载的方式提供到容器内部使用.例如

docker run -v /home/dan/my_statsd_config.conf:/etc/statsd.conf hopsoft/graphite-statsd

优点:

  • 无需修改容器就可以随意配置

缺点:

  • 违反生产/开发环境一致性要求
  • 如果要用在生产环境中,必须要保证配置文件在基础操作系统中可用.

结论

如上所述,想要配置一个容器包里的应用,方法其实很多,各有利弊.哪个最好?其实取决于你需要多大的动态配置的自由度以及你是否愿意承担额外的譬如维护一个KV store这样的负担.

译后评

个人目前倾向1和2a,但是还没有在生产环境中体验过实际会有哪些坑,所以只能是倾向.

原文地址

一次搭建高性能Nodejs httpServer的尝试(2)

继续上次的.
上次搞的node http server,一个简单的服务器,接收HTTP POST,解析数据入mongo库(nodejs driver用的native driver而非mongoose),主要做了下面的一些优化:

  • 系统层面放开同时打开的文件数(也就是socket数)的限制
  • 复用链接(主要是ab http1.0 keepalive的坑)
  • 增加并发
  • “优化”业务逻辑

其实都是一些”预”优化,在没有需要针对处理的问题出现的情况下先放开一些东西. 后来测试结果满意,一个小项目开始,两周完成了一个小业务之后,需要部署让测试介入.环境一换,问题就来了.

原先在本地的Linux台式机上近16000的TPS到了openstack(4core, 4GB memory)的VM上TPS瞬间掉到了小几千.赶紧登陆上去vmstat查看,发现Procs的r值(等待执行的进程数)接近20,远大于CPU核心数,也就是说CPU成了应用的瓶颈.–原来台式机是8X3.4GHz,到了虚拟机上只有4X2.3GHz,早该想到!

提高虚拟核心数!当然同时也把node.js的slave process提高到8个.同时,把libuv的线程池的限制也放开(设置UV_THREADPOOL_SIZE=8的环境变量),至于这个有没有用,其实我也是不太清楚的,顺便贴一个关于这个问题的争论—好吧,其实是撕逼,吃瓜群众表示看神仙打架也很有意思嘛—也不知道libuv团队最后有没有采纳这个不礼貌的家伙的建议.但是不管libuv的线程池是否应该跟核心数相等,个人觉得不管怎么说,mongodb的native driver开的线程池的大小是5,如果libuv的线程池大小只有4的话肯定不能发挥出其期待的性能吧.再次顺便提一句,mongodb nodejs官方的driver其默认线程池大小也是可以改的–详见参考文档,但是我这里并没有尝试.

好吧,再次测试,TPS又恢复到了16000+. Done!

之后又简单看了一下GC/内存有没有潜在的问题,这也是上一篇文末希望做的.简单来讲做法就是使用node-inspector+Chrome DevTools来比对heap snapshot(和参考文章的工具小有差异)以及使用–trace_gc来查看请求量大量/持久的压力下GC的时间是否能够接受.
但是由于压力较小,没能发现什么—于是就草草地交给测试了.

希望这个DEMO项目能做下去,这样之后说不定在使用中真的就能碰到大数据量的情况,来真正被需求倒逼去进一步探索其他的性能瓶颈—作为一个敏捷开发者(傲娇),我们不提倡提前优化,哈哈.

开发环境的虚拟化

随着Docker越来越火,产品的持续集成,测试,甚至交付(部署)都越来越倾向于使用容器来进行’标准化’.痛苦往往发生在不明白为什么要这么做就被迫跟着走.
但是用着用着确实能感觉到一些方便的地方.我想作为产品开发者,应该是这个Docker化的方案里受益最少的了吧.

最近在关于开发环境如何和Docker集成颇感头疼.最好的结果是开发者能在开发机器上直接使用于测试团队一致的环境进行初步测试/单元测试.对于脚本语言还好–因为开发者需要的其实仅仅是一个文本编辑器而已.但编译语言就不同了,需要编译.如果需要把测试人员的那一套弄到开发者本地,编译这一步到底应该在Docker里面做还是在Docker外面做?拿java来说,IDE一般都支持热部署,其效果就是修改某个java文件后不需要整个替换war包,IDE应该是增量替换了explored的artifact里面的部分class,重新build是很稀少的情况,因此代码-ide-测试是联系在一起的.而如果要测试基于Docker的产品,那么必然需要对每一个改动进行build,对于大的项目,这显然是个灾难.

2017-08-20 更新

去年这个时候的理解还是比较肤浅的,更新一下:

首先澄清初始问题,依据12-factors的要求:Make the tools gap small: keep development and production as similar as possible.
现在看来这里要求的开发和生产环境的一致性其实是在要求CI/CD环境的一致性,或者具体点,是Jenkins Build Node和Production Node的一致性。由于容器技术的引入,其实小环境一致性的要求是自然满足的,而Node系统以及Docker-Engine本身(版本的)一致性,可以很容易地通过复用诸如Chef recipes或者Openstack Heat Template来达到,至于容器编排器的不一致性 – 譬如在Jenkins Slave上用的是docker-compose而在生产环境中使用Kubernetes – 可能造成的问题,我想是Operation需要解决的,毕竟DevOps的存在只是为了让Ops日子好过点,而不是让Ops失去存在的必要。

然后回到开发者视角,具体的问题是:开发者本机上跑的那个开发中的应用/服务应该以容器的形式调试吗?
这是本文最初关注的问题,因为我当时把开发环境理解成了开发者环境,现在看来这个问题已经没有多少意义了,答案是随便。如果是java开发的话,可能你本机的jdk版本跟容器里的jre版本一致比较好,但是其实也无所谓,如果有一些这种环境差异带来的问题,也会以CI的单元测试失败的形式暴露出来。甚至你的开发机器也可以不需要装Docker,因为有Contract Test的保证,你的应用/服务与其他组件集成时可能出现的问题也会在CI过程中以inter-service测试失败的形式暴露出来。当然如果你希望少一点这种类型的返工,还是需要尽量保持开发机器中的单元测试和CI环境下的环境经可能一致 – 在CI里尽可能调用Gradle Task可以很好地帮助我们实现这一点 – 但是这不是必要的,我想说的是12条军规中的关于开发和生产的环境一致性要求是在要求CI和CD的一致性,而非开发者环境和CI环境的一致性,所以作为开发者来说,这个问题可以忽略。

重听旧日的足迹

我已经不知道初听这个曲子的时候是什么情景了,只知道是在15,6岁的时候,我还在家乡的小镇子上上初中。当时不清楚那将是我在故乡生活的最后两年,之后一路走远,高中到城市里,大学出了省,如今又在另一个城市生活。家乡是回不去了。

刚从生理和心理上开始往一个独立的人发展,这首歌是那个阶段的背景音。我不知道是因为它本身自带的怀旧情愫还是因为我自己初听此歌时的情境在我的脑海里给这段音乐打上了时空烙印,再听到这个曲子的时候颇有感触,画面感很强烈。我想把它画出来,可惜没有绘画的本领,只好试图用语言来刻画–虽然语言也不怎么样。

先是一段钢琴solo,很轻很静,像是怕打断已经如此脆弱的记忆,怕破坏已如此模糊的印象–就像我已经不记得初中不再联系的那些同学的相貌,2000年的冬天上学路上会听到什么–架子鼓和贝司都不敢介入,任由琴音缓缓流淌,试看能否触到往日的情景。

琴键点点滴滴,记忆寻寻觅觅,我的25岁在干什么,我的20岁在干什么,我15岁的时候又在干什么?15岁,啊,我曾经无邪的15岁呀,我想起来了。

–Band就都进来了,吉他和架子鼓,那么热烈。就像我的15岁也曾经那么热烈,就像我的家乡也曾经车水马龙,也曾经有如吵架般拉家常的老人,有忙碌向上的中年人,有花花绿绿的孩子们。有金融,轻工业,手工业和农业,我15岁的时候就在他们中间,没有意识到这些马上就要消失,现在再想回去找却也找不见了–家乡变得太快,而我也失了凝视的眼。

–像是怕赶不上自己的回忆,家驹的吐词节奏很轻快,追着记忆跑,忘记了抒情。

他梦萦家乡,只记得那一片绿油油,只记得她,想到就要回乡了,他并没有克制自己的关于她的回忆。

而回到实际中的家乡时,他才发现旧人多已不在,虽然还有着一样的安谧,一样友好的乡音,但却都是陌生的了。然而家乡的夜晚还是那样熟悉,就像那时候的夜晚,作为独生子女,在家乡,大抵住着比如今安身的租住房宽敞得多的房间,一个个独处的夜晚,从来没有物质上的幻想,宇宙,爱情甚至是一些异怪故事都是睡前餐。而和她在一起共度未来的憧憬,大概是幻想得最多的事情吧--虽然对于未来其实没有一点概念。

第二天早起的时候,妈妈已经做好了早饭,还是像从前那样清淡。吃饭的时候,妈妈看似不经意地提起了她,说起她在县城的工作很不错,嫁的人家也挺富裕……他不知道妈妈为什么要给他讲这个故事,也不打算告诉妈妈她曾可能跟这个人成为一家人。

还好有一个老友还住在家乡,他买了水果去带给他的孩子。去往他家的路十多年没有修了,车虽然也能开进去,他还是喜欢走路,虽然远了点,但是慢点也好。

老友托他介绍城里的工作,他应了下来,心里却不希望老友离开妻儿出门打工。

回头的时候,太阳已经快下去了,晚霞如幻。

路过了她的老家,隔河忘去屋子里不像是有人住了,曾经每次路过这里,他都会扭头望向屋边小桥,希望她也恰好去上学。

迎着晚霞又走了几步,路过了两个打闹的孩子,衣着鲜亮,笑声悦耳。

每一张可爱在远处的笑面
每一分亲切在这个温暖家乡故地
已过去的不可再今天只可忆起
一双只懂哭的眼落泪又再落泪
呜……

一次搭建高性能Nodejs httpServer的尝试

老板让尝试用node搭建一个高TPS的http服务器,业务不重要,仅仅测试一下传说中的适合I/O的技术能比java web container好多少.英文版测试结果:

Tried several approach to increase the TPS of a node.js http server to check if it’s competitive to be a easy tool for some specific tasks.
I create a simple http server, based on nodejs native http server. It receives http requests, records its information into a (remote) mongo DB, then response with ‘Okey’.

Test tool is Apache Bench, installed in the same host machine with http server: a desktop of “Dell OptiPlex 7010” with 8 core CPU as well as 8G memory running Oracle Linux Server 6.8.

Optimization approaches include:

  • Increasing the host server’s ‘open files limit’ with “ulimit -n 99999” while the default is 1024, also increasing the default stack size for V8 in node with '--max-old-space-size 2048'

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    [root@pu ~]# ulimit -a
    core file size (blocks, -c) 0
    data seg size (kbytes, -d) unlimited
    scheduling priority (-e) 0
    file size (blocks, -f) unlimited
    pending signals (-i) 31197
    max locked memory (kbytes, -l) 64
    max memory size (kbytes, -m) unlimited
    open files (-n) 99999
    pipe size (512 bytes, -p) 8
    POSIX message queues (bytes, -q) 819200
    real-time priority (-r) 0
    stack size (kbytes, -s) 10240
    cpu time (seconds, -t) unlimited
    max user processes (-u) 31197
    virtual memory (kbytes, -v) unlimited
    file locks (-x) unlimited
  • Re-use TCP connections for successive requests, i.e. make use of the Keep-Alive feature of http(1.0)

  • Make the http server a cluster, make use of more cores of CPU.
  • Change the business logic, return immediately when receiving request instead of waiting for database finish recording.

OS level tuning

Increasing the max open files(and hence the sockets) as well as stack size didn’t improve the performance. Which means we haven’t reached the limit of parallel socket numbers, nor memory limit.

Reuse connection

The http header ‘Connection: keep-alive’ is needed for Http/1.0 to reuse connection for further request— while for Http/1.1, the connection is keep-alive by default. Apache Bench is using 1.0, and with a parameter “-k”, it will add the “keep-alive” header.
As Http/1.0 can’t make use of ‘Transfer-encoding: chunked’, there’s only one possible way for the client to determine the boundary of successive requests in a single connection, i.e. ‘Content-Length’, it’s easy to know the content-length when requesting static file, but for the case of dynamic page, we need to manually calculate the ‘Content-Length’ and then mark it in the response header. And this is what we do by adding code in the node.js http server.
By doing this, the throughput increased:

1
2
3
4
5
6
[root@pu ~]# ab -n 10000 -c 10 http://localhost:1337/
Concurrency Level: 10
Time taken for tests: 1.512 seconds
[root@pu ~]# ab -n 10000 -c 10 -k http://localhost:1337/
Concurrency Level: 10
Time taken for tests: 1.144 seconds

Introduce concurrency

It contains two aspects when we introduce concurrency:
Adding the concurrency level of the test client
Adding the concurrency level of the http server
Since we are doing test in the exact server where http server deploys, the bottleneck can shift between client and server. So adding the concurrency level blindly won’t always increase the performance.
Adding the concurrency of Apache Bench is easy, just increase the parameter value of “-c”, adding this value will increase the TPS, but only valid in a certain range, approximately 1-50, in this range increase concurrency level will increase TPS, but out of this range, the TPS didn’t increase, –and also won’t decrease. For example if you increase the concurrency level to a non-sense high value, it won’t increase the TPS as 50.
To add the concurrency of Nodejs Http Server, we use node’s build-in feature of ‘cluster’, creating several slaves to strive for a single port. After several tuning, I find the concurrent level of 4 slaves increases the performance better, unlike the Apache Bench, adding the concurrency level of Http Server bigger than 4 will cause the total TPS decreased– this is because it will occupy the CPU resources that used for Apache Bench.

1
2
3
[root@pu ~]# ab -n 10000 -c 100 -k http://localhost:1337/
Concurrency Level: 100
Time taken for tests: 0.794 seconds

It is argued that several slaves striving for the same port is not so efficient than four slaves listening to different port respectively, and in the front, adding a inverse-proxy like Nginx to balance the load. This approach is not tried yet.

Change business logic

I tried to remove the code snippet of writing to mongo db, and then test it. In this situation, node.js server has the same TPS as Apache Httpd server.

1
2
3
[root@pu ~]# ab -n 10000 -c 100 -k http://localhost:1337/
Concurrency Level: 100
Time taken for tests: 0.251 seconds

So for static page, nodejs is not so powerful, it’s value lies in when the business logic added, the TPS won’t drop down rapidly.

Future test

Stability: as last time I tried this http server, it shows periodically TPS down, probably related with V8’s GC, so need to investigate into more detail about it.

Update