我正在玩不同的異步HTTP服務器,看他們如何處理多個同時連接。要強制執行耗時的I/O操作,我使用PostgreSQL函數來模擬耗時的數據庫查詢。這裏是比如我做什麼用的Node.js:執行異步數據庫查詢的HTTP服務器的最小示例?
var http = require('http');
var pg = require('pg');
var conString = "postgres://al:[email protected]/al";
/* SQL query that takes a long time to complete */
var slowQuery = 'SELECT 42 as number, pg_sleep(0.300);';
var server = http.createServer(function(req, res) {
pg.connect(conString, function(err, client, done) {
client.query(slowQuery, [], function(err, result) {
done();
res.writeHead(200, {'content-type': 'text/plain'});
res.end("Result: " + result.rows[0].number);
});
});
})
console.log("Serve http://127.0.0.1:3001/")
server.listen(3001)
所以這個,做一個SQL查詢到300毫秒,並返回一個響應一個非常簡單的請求處理程序。當我嘗試對它進行基準測試時,我得到以下結果:
$ ab -n 20 -c 10 http://127.0.0.1:3001/
Time taken for tests: 0.678 seconds
Complete requests: 20
Requests per second: 29.49 [#/sec] (mean)
Time per request: 339.116 [ms] (mean)
這清楚地表明請求是並行執行的。每個請求需要300ms才能完成,因爲我們有兩批10個請求並行執行,所以總共需要600ms。
現在我正試圖用Elixir做同樣的事情,因爲我聽說它的透明異步I/O。這裏是我的幼稚的做法:
defmodule Toto do
import Plug.Conn
def init(options) do
{:ok, pid} = Postgrex.Connection.start_link(
username: "al", password: "al", database: "al")
options ++ [pid: pid]
end
def call(conn, opts) do
sql = "SELECT 42, pg_sleep(0.300);"
result = Postgrex.Connection.query!(opts[:pid], sql, [])
[{value, _}] = result.rows
conn
|> put_resp_content_type("text/plain")
|> send_resp(200, "Result: #{value}")
end
end
在情況下,可能相關的,這裏是我的上司:
defmodule Toto.Supervisor do
use Application
def start(type, args) do
import Supervisor.Spec, warn: false
children = [
worker(Plug.Adapters.Cowboy, [Toto, []], function: :http),
]
opts = [strategy: :one_for_one, name: Toto.Supervisor]
Supervisor.start_link(children, opts)
end
end
正如您所料,這不會給我預期的結果:
$ ab -n 20 -c 10 http://127.0.0.1:4000/
Time taken for tests: 6.056 seconds
Requests per second: 3.30 [#/sec] (mean)
Time per request: 3028.038 [ms] (mean)
看起來沒有並行性,請求被一個接一個地處理。我究竟做錯了什麼?
酷!請記住,建立連接池是最好的方式,因爲建立與數據庫的連接並不便宜。你也會有更好的結果! – 2015-04-06 08:49:49
其實這段代碼創建連接,但從來沒有關閉它,所以它停止工作後一段時間:) – 2015-04-06 18:54:52
@AlexMarandon - 是的,你應該真正使用Ecto池,因爲何塞說,所以我會upvote你的答案。這僅僅是爲了演示的目的,但很好的電話指出,以防有人過來後,沒有意識到這一點。 – chrismcg 2015-04-07 09:45:00