Skip to content

2011年阅读的书和看过的电影

照例总结记录一下

2010 年的书、电影和音乐

照例用 doubanlet 统计了一下 2010 的书、电影和音乐。

书籍阅读量比去年数字上有44%的增加,不过貌似大量都是小说和漫画凑数导致的;电影数量略有下降,跟今年网络状况比较烂有关系;比较诡异是都是六月看电影最少,难道两年的六月都是在外面旅行么?音乐比较悲剧,基本没啥进展懒得整理了。:S

今年得在阅读质量上多下工夫,少看闲书啊。

介绍JVM虚拟机实现的培训PPT

前段给公司同事简单介绍了一些JVM虚拟机实现方面的知识,主要是针对某个产品希望自行研发类似引擎的需求,以JVM为例大概分析了一下虚拟机的架构,以及在静态模型和动态执行环境方面的一些设计思路。

J2SE 5.0和CLR 2.0之后,在虚拟机层面Sun和MS就基本没啥大改动,可以说这个领域基本上已经属于非常稳定和成熟。更多的关注被放到企业级应用的各种框架,以及动态语言和DSL领域特定语言的支持上。

但我始终以为,学习和了解一个类似JVM/CLR这样平台,最好的办法就是从底层静态文件结构着手,进而分析和理解其动态执行环境。这种学习方法虽然前期学习曲线较陡,但优点是可以完全无视各种文档里面的忽悠成分,直面语言和环境在设计之初的各种设计理念。毕竟你后期市场宣传忽悠的再天花乱坠,如果技术架构无法提供支持都是白扯。

最典型的案例就是CLR 1.0刚出来时,无论从静态文件结构还是IL指令集,都提供了对泛型的良好支持。因此当时在大家纷纷猜测时我就能非常确信,CLR 2.0或后续版本肯定会提供良好的泛型支持,而且大概知道能支持到什么程度。相反Java对泛型的支持,基本都只是通过annotation等机制模拟,缺乏JVM和byte code一级的有力保障,注定其实现方式倾向于在编译器层面模拟。江山轮流转,JVM对动态语言的支持,则是实实在在通过一系列JSR来完成;对应CLR反而是通过语言层面的DLR来模拟。

这方面比较靠谱的中文书籍并不多《深入Java虚拟机》关注JVM的架构,《虚拟机:系统与进程的通用平台》则是介绍更广泛意义上虚拟机的实现思路。如果只是希望深入了解Java和JVM,阅读《JAVA语言规范》虽然枯燥但确是最权威的。
深入Java虚拟机
JAVA语言规范
JAVA语言规范

Tagged

Gearman 性能调优

Gearman是最早由LiveJournal内部开发并使用的一个通用并行任务调度框架,允许不同语言直接通过非常简单的方式进行互操作。前台提交工作任务(Task)和参数,由后台工作进程(Worker)完成实际工作。

How Does Gearman Work?

例如前台提交用户需要进行渲染的图片,由Gearman调度到后台提供渲染服务的工作进程,在完成工作后返回结果给前台进行展示。提交工作和完成工作的代码只需要通过预先协商好的参数格式进行交互,具体任务的调度、负载均衡、可靠性等,由Gearman服务器来确保。而针对大规模应用,可以很容易进行多路节点的集群部署。

Gearman Cluster

在正式对外发布后,Danga Interactive用C重写了整个服务器代码,支持PHP, Perl, Python等常见脚本客户端,支持用memcached, sqlite, postgresql, tokyocabinet等作为任务持久化队列,基本上来说是便宜量又足。

线程模型

在大规模使用的时候,需要针对应用类型进行参数设置,以使Gearman的性能达到最优,这首先应该了解Gearman的线程模型。

为确保具备对海量任务调度的支持能力,Gearman毫无悬念的选择libevent作为网络操作支撑库。因此Gearman的服务器Gearmand提供了三类线程角色:

    端口监听和管理线程,接受新连接请求并将之交给IO线程,1个
    IO线程,完成实际的任务处理,包括命令解析,队列操作等,n个
    处理线程,完成内部数据结构的管理,无系统调用尽可能简单,1个

其中第1, 3种线程对全局处理性能没有直接影响,虽然处理线程有可能成为瓶颈,但他的工作足够简单消耗可忽略不计,因此我们的性能调优主要目标是在IO线程的数量。
对每个IO线程来说,它都会有一个libevent的实例;所有Gearman的操作会以异步任务方式提交到处理线程,并由IO线程获取完成实际操作,因此IO线程的数量是与可并行处理任务数成正比。Gearmand 提供 -t 参数调整总IO线程数,需要使用 libevent 1.4 以上版本提供多线程支持。

进程句柄数

另外一个影响大规模部署的是进程句柄数,Gearman会为每一个注册的Worker分配一个fd(文件描述符),而这个fd的总数是受用户限制的,可以使用 ulimit -n 命令查看当前限制

flier@debian:~$ ulimit -n
1024
flier@debian:~$ ulimit -HSn 4096 // 设置进程句柄数的最大软硬限制
4096

也就是说gearman缺省配置下,最多允许同时有小于1024个worker注册上来,fd用完之后的Worker和Client会出现连接超时或无响应等异常情况。因此,发生类似情况时,我们应首先检查 /proc/[PID]/fd/ 目录下的数量,是否已经超过 ulimit -n 的限制,并根据需要进行调整。而全系统的打开文件设置,可以参考 /proc/sys/fs/file-max 文件,并通过 sysctl -w fs.file-max=[NUM] 进行修改。

flier@debian:~$ cat /proc/sys/fs/file-max
24372
flier@debian:~# sysctl -w fs.file-max=100000
100000

更详细的设置请参考 Linux increase the maximum number of open files or file descriptors

Gearmand 本身也提供了调整句柄数量限制的功能,启动时则可以通过 –file-descriptors 参数指定,但非特权进程不能设置超过soft limit的数额。

-f, –file-descriptors=FDS Number of file descriptors to allow for the process
(total connections will be slightly less). Default
is max allowed for user.

The soft limit is the value that the kernel enforces for the corresponding resource. The hard limit acts as a
ceiling for the soft limit: an unprivileged process may only set its soft limit to a value in the range from 0
up to the hard limit, and (irreversibly) lower its hard limit. A privileged process (under Linux: one with the
CAP_SYS_RESOURCE capability) may make arbitrary changes to either limit value.

轮询调度

此外,Gearmand 还提供了一些增强任务调度公平性的参数,例如 0.13 里面新增的 round-robin 模式,允许将任务公平的调度到多个 Worker,而不是用缺省按 Worker 注册函数的顺序进行调度,避免工作过于集中在少数设备上。

-R, –round-robin Assign work in round-robin order per
workerconnection. The default is to assign work in
the order of functions added by the worker.

Gearmand 内部通过一个 Worker 队列,在 RR 模式下动态调整 Worker 的调度次序。

  if (server_con->thread->server->flags.round_robin)
  {
    GEARMAN_LIST_DEL(server_con->worker, server_worker, con_)
    _server_con_worker_list_append(server_con->worker_list, server_worker);
    ++server_con->worker_count;
    if (server_con->worker_list == NULL) {
      server_con->worker_list= server_worker;
    }
  }

受限唤醒

而通过 –worker-wakeup 参数,则可以指定收到任务时,需要唤醒多少个 Worker 进行处理,避免在 Worker 数量非常大时,发送大量不必要的 NOOP 报文,试图唤醒所有的 Worker。

-w, –worker-wakeup=WORKERS Number of workers to wakeup for each job received.
The default is to wakeup all available workers.

根据 Gearman 协议设计, Worker 如果发现队列中没有任务需要处理,是可以通过发送 PRE_SLEEP 命令给服务器,告知说自己将进入睡眠状态。在这个状态下,Worker 不会再去主动抓取任务,只有服务器发送 NOOP 命令唤醒后,才会恢复正常的任务抓取和处理流程。因此 Gearmand 在收到任务时,会去尝试唤醒足够的 Worker 来抓取任务;此时如果 Worker 的总数超过可能的任务数,则有可能产生惊群效应。

  /* Queue NOOP for possible sleeping workers. */
  if (job->function->worker_list != NULL)
  {
    worker= job->function->worker_list;
    noop_sent= 0;
    do
    {
      if (worker->con->options & GEARMAN_SERVER_CON_SLEEPING &&
          !(worker->con->options & GEARMAN_SERVER_CON_NOOP_SENT))
      {
        ret= gearman_server_io_packet_add(worker->con, false,
                                          GEARMAN_MAGIC_RESPONSE,
                                          GEARMAN_COMMAND_NOOP, NULL);
        if (ret != GEARMAN_SUCCESS)
          return ret;

        worker->con->options|= GEARMAN_SERVER_CON_NOOP_SENT;
        noop_sent++;
      }

      worker= worker->function_next;
    }
    while (worker != job->function->worker_list &&
           (job->server->worker_wakeup == 0 ||
           noop_sent < job->server->worker_wakeup));

    job->function->worker_list= worker;
  }

除此之外,针对应用特点合理使用持久化队列,在大并发任务量的情况下对性能也会有直接影响。

归根结底,需要根据自己的应用场景,合理设计一些测试用例和自动化脚本,通过实际的运行状态进行参数调整。

Tagged ,

GCC和VS2010中对C++ 0x的支持

根据GCCVS2010的文档,大致整理了一下几个主流编译器对C++ 0x标准的支持程度。

Tagged , , ,

函数式编程入门培训PPT

上周给公司同事做了一个函数式编程 (Functional Programming) 的介绍,原以为可以随便到网上找一个ppt讲讲,结果发现居然没有合适的可以直接用,只好根据 wiki 结合 python 示例自己整理了一个培训PPT。大概涵盖了FP的发展历史、基本概念和一些简单例子,回头有空再把它细化一下,看看是否有必要继续深入讲。

说起来函数式编程 (Functional programming) 这个话题基本是个无底洞,属于在常青藤高校也能开几年课挂掉无数人的领域。如何在短短一个多小时的时间内,让听众有一些直观印象,进而有兴趣继续深入学习下去,这是让我最为头疼的事情。因此我基本放弃了对那些较为复杂概念的介绍,甚至连 Closure 都只敢简单提及,跟别提什么 Monad 这种我自己都挠头的概念。

开讲前在几十个听众中做了个简单调查,果然是听说过和使用过 FP 的人基本都是个位数。这基本上可以说是天朝 CS/EE 教育失败的体现,要知道欧美大学第一年就会讲 Structure and Interpretation of Computer Programs 这种被 Joel 视为是否适合就读 CS 专业过滤器的 BT 课程 (在线课程)。

因此在一开始的时间里,基本上都是集中在对 FP 的鼓吹上,基本集中在 (1) 应对复杂性,(2) 降低维护成本和 (3) 增强自信心三个角度。前面两个基本上是洗脑用套话,个人最赞同也最想灌输的是第三点。

如果实际参与开发过代码量上百万行,代码维护历史在5-7年以上,先后参与人数几十上百的产品,最直观的感受是应该就是对其自身复杂性的本能恐惧。因为对绝大多数技术人员来说,我们更倾向于参与具有确定性的工作,也就是说我们潜意识里认为,我们做的事情应该是有可预测结果的。但一旦代码复杂到了一定程度,解耦没有到位过过于到位,我们就会发现所有的修改,都有可能引发不确定的影响。为了缓解这种影响,我们搞出了各种各样的最佳实践,TDD、CI、peer review,blabla;但归根结底我们只是试图用这些尝试来确保,我们有胆量继续修改那些我们自己也逐渐无法控制的代码,就好象在黑夜中无助的抓住一个火把,却又大声喊叫说自己不怕黑暗。

FP 在这方面可以说具有天然的优势,在去除 side effect 和复杂控制逻辑后,我们通过 Pure functions 和 Recursion 表达的是我们真正的计算目的,而非达成目标的方法。这也是声明式语言 (Declarative programming) 与命令式语言 (Imperative programming) 最大的差别所在。这也是为啥我在开发 rabbitmq-memcached 时,真正能把大部分时间用在编写代码上的原因,实际上线调试反而只是简单而且直接的结果而非过程。

Tagged , ,

2009 年的书、电影和音乐

doubanlet 统计了一下 2009 的书、电影和音乐。果然是上半年比较闲,每个月读书在10-15本;不过电影倒是一直很勤奋的在看,除了中间五六月时忙于换工作交接旅行啥的,只能偷空听听音乐。

Tagged , , ,
Get Adobe Flash player