uWSGI Go支持 (只有1.4)¶
警告
自1.9.20起,Go插件已经被 GCCGO插件 插件取代了。
从uWSGI 1.4-dev起,你可以在你的uWSGI栈中托管Go web应用了。你可以从http://golang.org/下载Go。目前,支持Linux i386/x86_64, FreeBSD i386/x86_64和OSX。对于OSX支持,你需要Go 1.0.3+,或者你将需要应用http://code.google.com/p/go/source/detail?r=62b7ebe62958上的可用补丁。goroutine目前只在Linux i386/x86_64上支持。
构建带Go支持的uWSGI¶
可以作为嵌入部件或者插件构建Go支持。与其他语言的设置主要的不同是,这次,我们会构建一个uwsgi库,而不是一个uwsgi二进制文件。这个库将会被名为uwsgi.go的一个Go包使用,你可以链接你的应用。不要怕,因为在uWSGI发行版中,已经有一个构建配置文件,你可以用它来构建一个内置Go支持的完整的(单片)发行版。在构建过程的最后,你会得到一个libuwsgi.so共享库和一个uwsgi.a Go包。
要构建uWSGI+go,仅需运行 (在uWSGI源代码目录)
UWSGI_PROFILE=go make
或者如果Python并不在你的系统目录中,或者你需要使用一个指定python版本:
/usr/local/bin/python uwsgiconfig.py --build go
(或者你自定义的Python的位置)
在构建过程的最后,你会得到一个libuwsgi.so文件 (拷贝或者链接它到一个库目录,例如/usr/local/lib或者/usr/lib,最后需要的话,运行ldconfig),和一个plugins/go/pkg子目录(基于你的架构/操作系统)中的uwsgi.a文件。
重要
构建过程的最后的消息报告了你在构建uWSGI Go应用的时候应该使用的 GOPATH
(在某个地方拷贝/记住/注释该值)。
如果你已经知道Go导入系统是如何工作的,那么随意拷贝你的系统范围的GOPATH中的uwsgi.a。
编写第一个Go应用¶
默认情况下,uWSGI Go插件支持 http.DefaultServeMux
处理器,所以,如果你的应用已经基于此了,那么在uWSGI中运行它应该非常简单。
package main
import (
"uwsgi"
"net/http"
"fmt"
)
func oneHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<h1>One</h1>")
}
func twoHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<h2>Two</h2>")
}
func main() {
http.HandleFunc("/one/", oneHandler)
http.HandleFunc("/two/", twoHandler)
uwsgi.Run()
}
可以看到,唯一与标准的基于 net/http
的应用不同的地方在于,需要 import "uwsgi"
,以及调用 uwsgi.Run()
函数,这将会运行整个uWSGI服务器。如果你想用你自己的请求处理器来取代 http.DefaultServeMux
,那么使用``uwsgi.Handler(http.Handler)`` 或者 uwsgi.RequestHandler(func(http.ResponseWriter, *http.Request))
来设置它。
func myHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<h2>Two</h2>")
}
func main() {
uwsgi.RequestHandler(myHandler)
uwsgi.Run()
}
构建你的第一个应用¶
假设你的应用是helloworld.go,仅需运行以下。
GOPATH=/home/foobar/uwsgi/plugins/go go build helloworld.go
将GOPATH改为你从构建过程获得的值,或者你安装/拷贝uwsgi.a的目录。如果一切顺利,你会得到一个’helloworld’可执行文件。那个可执行文件是一个完整的uWSGI服务器 (是的,真的是)。
./helloworld --http :8080 --http-modifier1 11
仅需将你的浏览器指向端口8080,然后检查/one/和/two/。你可以开始添加进程和一个master:
./helloworld --http :8080 --http-modifier1 11 --master --processes 8
注意:官方分配了modifier1 11给Go。
上生产¶
在一个生产环境中,你可能会把一个web服务器/代理放在你的应用前面。因此,你的nginx配置看起来会是这样::
- location / {
- include uwsgi_params; uwsgi_pass 127.0.0.1:3031; uwsgi_modifier1 11;
}
而你的uWSGI配置将会差不多是这样……
[uwsgi]
socket = 127.0.0.1:3031
master = true
processes = 4
最后,简单运行你的应用:
./helloworld config.ini
goroutine (目前仅Linux/FreeBSD)¶
goroutine非常可能是Go平台最有趣的特性。当你构建带go插件的uWSGI时,一个用于goroutine的uWSGI循环引擎自动嵌入到uWSGI库中。要在每个uWSGI进程中生成goroutine,只需添加 goroutines = N
选项,其中,N是要生成的goroutine数目。
[uwsgi]
socket = 127.0.0.1:3031
master = true
processes = 4
goroutines = 100
使用这个配置,你将为每个uWSGI进程生成100个goroutine,总共生成400个goroutine (!) 就uWSGI看来,goroutine对应pthread,但你将也能够从你的应用生成基于coroutine的任务。
uWSGI api¶
从你的Go应用访问uWSGI API是相当简单的。要这样做,请引用uwsgi包导出的函数:
package main
import (
"fmt"
"uwsgi"
)
func hello2(signum int) {
fmt.Println("I am an rb_timer running on mule", uwsgi.MuleId())
}
func hello(signum int) {
fmt.Println("Ciao, 3 seconds elapsed")
}
func postinit() {
uwsgi.RegisterSignal(17, "", hello)
uwsgi.AddTimer(17, 3)
uwsgi.RegisterSignal(30, "mule1", hello2)
uwsgi.AddRbTimer(30, 5)
}
func foofork() {
fmt.Println("fork() has been called")
}
func main() {
uwsgi.PostInit(postinit)
uwsgi.PostFork(foofork)
uwsgi.Run()
}
PostInit()函数设置在完成Go初始化之后,调用的“钩子”。PostFork()设置在每次fork()之后调用的“钩子”。在postinit钩子中,我们注册了两个uwsgi信号,第二个运行在一个mule (mule1) 中。要运行这个代码,只需像上面那样构建你新的应用,然后执行它
[uwsgi]
socket = 127.0.0.1:3031
master = true
processes = 2
goroutines = 20
mules = 2
memory-report = true
这次,我们添加了memory-report,试一试,看看Go应用可以多省内存。
从Emperor运行¶
如果你运行在Emperor模式下,那么你可以通过 privileged-binary-patch
选项运行uWSGI-Go应用。你的vassal配置应该差不多像这样。
[uwsgi]
socket = 127.0.0.1:3031
master = true
processes = 2
goroutines = 20
mules = 2
memory-report = true
uid = foobar
gid = foobar
privileged-binary-patch = /tmp/bin/helloworld
(显然,修改``/tmp/bin/helloworld`` 为任何你应用所在的地方……)
注意事项¶
- 你可以在uWSGI源代码发行版的
t/go
目录中找到一系列有趣的go样例。 - 目前不可能在不修改go核心的情况下修改进程名
- 你不能和Go一起使用uWSGI原生线程 (只使用–goroutines)
- 目前只公开了一小部分uWSGI API。如果你想要hack下,或者需要更多,那么只需编辑plugins/go/src/uwsgi目录中的uwsgi.go文件
- goroutine需要异步模式 (如果你正自定义你的uWSGI二进制文件,那么记得总是包含它)
- 似乎可能甚至在goroutines模式下无问题加载Python, Lua和PSGI插件 (需要更多的测试)