基于httpd的Erlang Web Server

Background

  1. 有一堆数据需要用Golang来处理,数据是使用Erlang的term_to_binary保存的。
  2. 数据是热数据,因此不能一次性对数据进行binary_to_term预处理。
  3. Erlang的Ports是不太合适的,因为Ports的设计更侧重于Erlang主动与外部进程(一般是其他语言编写的)进行通信。
  4. 基于通用协议使得Golang与Erlang直接可以通信是唯一的出路,通用协议如http, thrift, protobuf等都可以,因此这条出路还挺宽。BERT-RPC强大而笨重,但是没有Golang的RPC Client. 由于需求非常简单,考虑基于Erlang httpd写一个简单的Web Server完成这个任务。

如果不是Erlang, 这个任务应该是分分钟搞定,但是Erlang的官方文档缺乏example, 相关的文章又太少。难怪有人会吐槽:

When I first started using Erlang it took a fair bit of trial and error to create a server that generated dynamic HTTP content. The main problem is the lack of good tutorials out there for doing these kinds of things. The documentation that comes with Erlang is good for reference, but is not that helpful if you’re just learning the language.

How

下面是将用户输入的内容返回给用户的echo server代码:

  1. httpd实现了一套处理http request的behavior, 通过配置可以设置如何路由这些请求。这里使用esi的方式来处理请求。erl_script_alias依赖mod_esi. 因此{modules,[mod_esi]}不能省去。上例将/esi/echoserver:func交给echo_server:func处理。因此,可以通过 http://localhost:8080/esi/echo_server:echo?abcd你好321 进行测试。
  2. httpd定义了一堆mod_*来处理请求,modules之间的顺序有限制的,启用多个模块需要注意。
  3. mod_esi:deliver()第一段内容必须设置Header:

    Use this callback function to dynamically generate dynamic web content. When a part of the page is generated send the data back to the client through deliver/2. Note that the first chunk of data sent to the client must at least contain all HTTP header fields that the response will generate. If the first chunk does not contain the End of HTTP header, that is “\r\n\r\n”, the server will assume that no HTTP header fields will be generated.

  4. 如果返回的内容有unicode字符,需要使用unicode模块处理,否则浏览器会乱码。

References

[1] Working example for Erlang Server Interface

[2] “Hello World” Webapp in Erlang

「Golang server design pattern」学习笔记

花了近一周时间,把golang基本语法看了两遍。使用了两个资料:

  1. 「学习 Go 语言」,邢星翻译版。GitHub地址PDF版。资料比较精要,非常适合短时间入门。每个章节后的习题设计不错,考察知识点比较充分和全面,但是经常出现「越级」现象,即第x章的内容习题,往往需要你学习了第x+1,x+2章后的内容以后才能完成。
  2. Go语言程序设计」,Mark Summerfield. 虽然是七牛许式伟翻译,但是还是比较粗糙,逻辑错误和排版错误比较多,有人评价说这是许的一本黑书,姑且批判性的看吧。这本书每章的例子分量很重,值得花时间研读以及抄一下代码。

以上是题外话。我接下来的工作会逐步转向golang的服务器维护和开发。因此,除去语言本身,对design pattern是下一阶段要着重学习的。找到一个这方面的资料资料:Golang server design pattern,阅读笔记如下:

  1. golang采用CSP(Communication Sequential Processing)实现并行,类似于Unix管道的概念,但是golang中,CSP是双向的,管道是单向的。由于没有共享资源,因此程序员可以避免显式加锁。
  2. 收/发chan的本质是带锁的FIFO操作。
  3. 从C++观点来开,
    1. golang的一个目录就是一个namespace/class。同一目录中的所有文件中的变量、函数,相互可见。
    2. C++继承 => golang嵌入
    3. 类方法 => 接收者
    4. 构造方法 => init()或者New()接口方法。golang中,一个目录/一个文件中可以有若干个init函数。
    5. void*/object => interface{}
    6. try()/catch() => panic()/recover()
  4. go项目组织原则:
    1. 一个目录下的所有.go文件爱你共同构成一个功能模块,为一个目的服务。
    2. 用层次话的方式组织工程。
    3. 尽可能多的使用goroutine处理并行,goroutine是很廉价的。
    4. 模块+接口 的方式构建项目,二不是OOP的方式。