NuSTER
基於HAProxy的高效能HTTP快取伺服器和RESTful NoSQL快取伺服器。
中文版更新可能不及時,最新版請參照英文版README.md
目錄
介紹
NuSTER是一個基於HAProxy的高效能HTTP快取伺服器和RESTful NoSQL快取伺服器,完全相容HAProxy,並且利用HAProxy的ACL功能來提供非常細緻的快取規則。
特性
HTTP/TCP負載均衡器
NuSTER可以作為HTTP/TCP負載均衡器使用。
- 繼承了HAProxy的所有特性,完全相容HAProxy
- 負載均衡
- 前端後端HTTPS
- HTTP壓縮
- HTTP重寫重定向
- HTTP資訊增刪改
- HTTP2
- 監控
- 粘性
- 訪問控制
- 內容切換
HTTP快取伺服器
NuSTER也可以用作類似Varnish或者Nginx那樣的HTTP快取伺服器,來快取動態或者靜態的HTTP資源。
- HAProxy的所有特性(HTTPS, HTTP/2, ACL, etc)
- 非常快
-
強大的動態快取功能
- 基於HTTP method, URI, path, query, header, cookies, etc
- 基於HTTP request or response contents, etc
- 基於environment variables, server state, etc
- 基於SSL version, SNI, etc
- 基於connection rate, number, byte, etc
- 快取管理
- 快取清除
- 快取統計資訊
- 快取生存時間
RESTful NoSQL快取伺服器
NuSTER也可以用作RESTful NoSQL快取伺服器, 用HTTP POST/GET/DELETE
來 新增/取得/刪除 Key/Value.
可以像Memcached或者Redis那樣放在應用和資料庫之間作為內部KV快取使用,也可以放在使用者和應用之間作為面向使用者的NoSQL使用。
支援header, cookie等等,所以可以將不同的使用者資料存到相同的路勁。
- HAProxy的所有特性(HTTPS, HTTP/2, ACL, etc)
- 有條件的快取
- 內部KV快取
- 面向使用者快取
- 支援任何型別的資料
- 支援所有程式語言,不需要特定的庫,只需HTTP支援
效能
非常快, 單程式模式下是nginx的3倍,多程式下nginx的2倍,varnish的3倍。
入門指南
下載
生產環境的話從Download下載最新穩定版, 其他情況可以git clone。
編譯
make TARGET=linux2628 USE_LUA=1 LUA_INC=/usr/include/lua5.3 USE_OPENSSL=1 USE_PCRE=1 USE_ZLIB=1
make install PREFIX=/usr/local/nuster
新增
USE_PTHREAD_PSHARED=1
使用pthread如果不需要可以刪除
USE_LUA=1 LUA_INC=/usr/include/lua5.3 USE_OPENSSL=1 USE_PCRE=1 USE_ZLIB=1
具體可以參考HAProxy README。
配置檔案
準備一個配置檔案: nuster.cfg
global
nuster cache on data-size 100m uri /_nuster
nuster nosql on data-size 200m
defaults
mode http
frontend fe
bind *:8080
#bind *:4433 ssl crt example.com.pem alpn h2,http/1.1
use_backend be2 if { path_beg /_kv/ }
default_backend be1
backend be1
nuster cache on
nuster rule img ttl 1d if { path_beg /img/ }
nuster rule api ttl 30s if { path /api/some/api }
server s1 127.0.0.1:8081
server s2 127.0.0.1:8082
backend be2
nuster nosql on
nuster rule r1 ttl 3600
nuster監聽8080埠,接受HTTP請求。/_kv/
開頭的請求分配到backend be2
, 可以傳送HTTP POST/GET/DELETE
到/_kv/any_key
來 新增/取得/刪除 Key/Value.
其他的請求都被分配到backend be1
, 並且會被轉發到伺服器s1
or s2
. 其中/img/*
請求會被快取1天,而/api/some/api
會被快取30秒。
啟動
/usr/local/nuster/sbin/nuster -f nuster.cfg
Docker
docker pull nuster/nuster
docker run -d -v /path/to/nuster.cfg:/etc/nuster/nuster.cfg:ro -p 8080:8080 nuster/nuster
使用方法
NuSTER基於HAProxy, 支援所有的HAProxy指令。
基本
配置檔案裡有四個基本的section
s: global
, defaults
, frontend
and backend
。
-
global
- 定義全域性指令
- 需要定義
nuster cache on
ornuster nosql on
,否則cache和nosql無法使用
-
defaults
- 定義
frontend
,backend
的預設引數 - 可以在
frontend
orbackend
section重新定義
- 定義
-
frontend
- 定義監聽埠等等面向使用者的設定
-
bankend
- 定義後端伺服器等等設定
- 需要設定
nuster cache on
ornuster nosql on
, 否則該backend沒有nosql或者nosql功能 - 需要設定
nuster rule
可以定義多個frontend
or backend
. 如果定義了nuster cache|nosql off
或者沒有nuster cache|nosql on|off
, nuster就是一個HAProxy。
具體參考/doc
下的HAProxy文件, 或者線上HAProxy文件
As TCP loader balancer
frontend mysql-lb
bind *:3306
mode tcp
default_backend mysql-cluster
backend mysql-cluster
balance roundrobin
mode tcp
server s1 10.0.0.101:3306
server s2 10.0.0.102:3306
server s3 10.0.0.103:3306
As HTTP/HTTPS loader balancer
frontend web-lb
bind *:80
#bind *:443 ssl crt XXX.pem
mode http
default_backend apps
backend apps
balance roundrobin
mode http
server s1 10.0.0.101:8080
server s2 10.0.0.102:8080
server s3 10.0.0.103:8080
#server s4 10.0.0.101:8443 ssl verify none
As HTTP cache server
global
nuster cache on data-size 200m
frontend fe
bind *:8080
default_backend be
backend be
nuster cache on
nuster rule all
server s1 127.0.0.1:8081
As RESTful NoSQL cache server
global
nuster nosql on data-size 200m
frontend fe
bind *:8080
default_backend be
backend be
nuster nosql on
nuster rule r1 ttl 3600
指令
global: nuster cache|nosql
syntax:
nuster cache on|off [data-size size] [dict-size size] [purge-method method] [uri uri]
nuster nosql on|off [data-size size] [dict-size size]
default: none
context: global
控制是否開啟cache或者nosql。
會分配一塊data-size + dict-size
的共享記憶體來儲存HTTP頭,資料,key等等,臨時資料從系統記憶體池分配。
如果沒有足夠記憶體,新的請求不會被快取直到有記憶體被釋放。
data-size
和dict-size
一起決定記憶體塊的大小。
可以使用m
, M
, g
和 G
. 預設是1MB,同時也是最小值。
dict-size
決定hash table的大小.
可以使用m
, M
, g
和 G
. 預設是1MB,同時也是最小值。
這個決定hash table buckets的大小,並非key的大小,key存在共享記憶體中。
dict-size(bucket數) 不等於 key數. 就算key的數量超過了dict-size,只要整個共享記憶體有空間,新的key仍然可以被新增。
不過如果key數超過dict-size(bucket數)效能也許會下降. dict-size可以設為大概的最大key數乘以8。
將來版本會刪除dict-size, 像第一版本那樣自動伸縮
purge-method [cache only]
自定義PURGE用的HTTP method,最大14個字元,預設是 PURGE
.
uri [cache only]
定義並開啟cache manager/stats API
nuster cache on uri /_my/_unique/_/_cache/_uri
cache manager/stats預設是關閉的. 如果開啟了,主義開啟訪問控制(see FAQ).
proxy: nuster cache|nosql
syntax:
nuster cache [on|off]
nuster nosql [on|off]
default: on
context: backend, listen
決定是否在這個backend開啟cache/nosql。
如果這個section有filter,記得放在最後。
nuster rule
syntax: nuster rule name [key KEY] [ttl TTL] [code CODE] [if|unless condition]
default: none
context: backend, listen
定義cache/nosql的生效條件,需要定義至少一個rule。
nuster cache on
# cache request `/asdf` for 30 seconds
nuster rule asdf ttl 30 if { path /asdf }
# cache if the request path begins with /img/
nuster rule img if { path_beg /img/ }
# cache if the response header `cache` is `yes`
acl resHdrCache res.hdr(cache) yes
nuster rule r1 if resHdrCache
可以定義多個rule,按定義順序先後匹配。
acl pathA path /a.html
nuster cache on
nuster rule all ttl 3600
nuster rule path01 ttl 60 if pathA
rule path01
永遠不會被匹配。
name
定義rule的name。
在cache manager API中使用, 不必唯一但是建議不同的rule用不同的name,否則相同name的rule視作一樣。
key KEY
定義cache/nosql的key, 由下列關鍵字加.
組成
- method: http method, GET/POST…
- scheme: http or https
- host: the host in the request
- uri: first slash to end of the url
- path: the URL path of the request
- delimiter: `?` if query exists otherwise empty
- query: the whole query string of the request
- header_NAME: the value of header
NAME
- cookie_NAME: the value of cookie
NAME
- param_NAME: the value of query
NAME
- body: the body of the request
CACHE的預設key是 method.scheme.host.uri
, NoSQL的預設key是 GET.scheme.host.uri
.
Example
GET http://www.example.com/q?name=X&type=Y
http header:
GET /q?name=X&type=Y HTTP/1.1
Host: www.example.com
ASDF: Z
Cookie: logged_in=yes; user=nuster;
生成:
- method: GET
- scheme: http
- host: www.example.com
- uri: /q?name=X&type=Y
- path: /q
- delimiter: ?
- query: name=X&type=Y
- header_ASDF: Z
- cookie_user: nuster
- param_type: Y
- body: (empty)
預設key產生GET.http.www.example.com./q?name=X&type=Y.
, 而key method.scheme.host.path.header_ASDF.cookie_user.param_type
則生成 GET.http.www.example.com./q.Z.nuster.Y.
.
相同key的請求則會直接返回cache給客戶端。
ttl TTL
設定快取生存時間,過期後快取會被刪除。 可以使用 d
, h
, m
and s
。預設3600
秒.
如果不希望失效則設為0
code CODE1,CODE2…
預設只快取200的響應,如果需要快取其他的則可以新增,all
會快取任何狀態碼。
cache-rule only200
cache-rule 200and404 code 200,404
cache-rule all code all
if|unless condition
定義ACL條件
詳見HAProxy configuration的7. Using ACLs and fetching samples
Cache
NuSTER也可以用作類似Varnish或者Nginx那樣的HTTP快取伺服器,來快取動態或者靜態的HTTP資源。
出了HAProxy的SSL, HTTP, HTTP2, 重寫重定向,增刪改Header等等,還提供了下面的功能。
快取管理
快取可以通過uri
定義一個endpoint併傳送HTTP請求來進行管理。
定義並且開啟
nuster cache on uri /nuster/cache
基本用法
curl -X POST -H "X: Y" http://127.0.0.1/nuster/cache
記得進行訪問控制
快取開啟關閉
rule可以通過manager uri動態開啟關閉,關閉的rule不會再進行匹配。
headers
header | value | description |
---|---|---|
state | enable | enable rule |
disable | disable rule | |
name | rule NAME | the rule to be enabled/disabled |
proxy NAME | all rules belong to proxy NAME | |
* | all rules |
相同name的rule都會被開啟關閉。
Examples
- 關閉rule r1
curl -X POST -H "name: r1" -H "state: disable" http://127.0.0.1/nuster/cache
- 關閉backend app1b的所有rule
curl -X POST -H "name: app1b" -H "state: disable" http://127.0.0.1/nuster/cache
- 開啟所有的rule
curl -X POST -H "name: *" -H "state: enable" http://127.0.0.1/nuster/cache
快取生存時間
更改快取TTL,只會影響後續的新快取,不會影響已經存在的快取。
headers
header | value | description |
---|---|---|
ttl | new TTL | see ttl in nuster rule
|
name | rule NAME | the rule to be changed |
proxy NAME | all rules belong to proxy NAME | |
* | all rules |
Examples
curl -X POST -H "name: r1" -H "ttl: 0" http://127.0.0.1/nuster/cache
curl -X POST -H "name: r2" -H "ttl: 2h" http://127.0.0.1/nuster/cache
同時設定state和ttl
同時設定state和ttl
curl -X POST -H "name: r1" -H "ttl: 0" -H "state: enabled" http://127.0.0.1/nuster/cache
快取清除
There are several ways to purge cache by making HTTP PURGE
requests to the manager uri defined by uri
.
You can define customized http method using purge-method MYPURGE
other than the default PURGE
in case you need to forward PURGE
to backend servers.
刪除一個特定URL
curl -XPURGE https://127.0.0.1/imgs/test.jpg
生成key GET.scheme.host.uri
, 並刪除那個key。
預設key 包含Host
, 如果快取時用了http://example.com/test
而在localhost刪除是需要Host
header:
curl -XPURGE -H "Host: example.com" http://127.0.0.1/test
通過name刪除
可以通過帶上name
header來 PURGE
headers
header | value | description |
---|---|---|
name | nuster rule NAME | caches belong to rule ${NAME} will be purged |
proxy NAME | caches belong to proxy ${NAME} | |
* | all caches |
Examples
# 刪除所有快取
curl -X PURGE -H "name: *" http://127.0.0.1/nuster/cache
# 刪除backend applb的所有快取
curl -X PURGE -H "name: app1b" http://127.0.0.1/nuster/cache
# 刪除所有rule r1生成的快取
curl -X PURGE -H "name: r1" http://127.0.0.1/nuster/cache
通過host刪除
通過帶上x-host
header來刪除所有屬於這個host的快取。
headers
header | value | description |
---|---|---|
x-host | HOST | the ${HOST} |
Examples
curl -X PURGE -H "x-host: 127.0.0.1:8080" http://127.0.0.1/nuster/cache
通過path刪除
預設情況下,query部分也包含在key中,所以相同的path不同的query會產生不同的快取。
比如nuster rule imgs if { path_beg /imgs/ }
, 然後請求
curl https://127.0.0.1/imgs/test.jpg?w=120&h=120
curl https://127.0.0.1/imgs/test.jpg?w=180&h=180
會生成兩個快取,因為query不一樣。
如果要刪除這些快取,可以
如果知道所有的query,那麼可以一個一個刪除
curl -XPURGE https://127.0.0.1/imgs/test.jpg?w=120&h=120
curl -XPURGE https://127.0.0.1/imgs/test.jpg?w=180&h=180
大多數情況下不知道所有的query
如果query部分不重要,則可以從key裡面刪除query
定義nuster rule imgs key method.scheme.host.path if { path_beg /imgs }
, 這樣的話只會生成一個快取,那麼就可以不用query刪除快取
curl -XPURGE https://127.0.0.1/imgs/test.jpg
大多數情況需要query
通過rule name刪除
curl -X PURGE -H "name: imgs" http://127.0.0.1/nuster/cache
但是如果rule被定義成了 nuster rule static if { path_beg /imgs/ /css/ }
,則無法只刪除imgs
因此,可以通過path刪除
headers
header | value | description |
---|---|---|
path | PATH | caches with ${PATH} will be purged |
x-host | HOST | and host is ${HOST} |
Examples
# 刪除所有path是/imgs/test.jpg的快取
curl -X PURGE -H "path: /imgs/test.jpg" http://127.0.0.1/nuster/cache
# 刪除所有path是/imgs/test.jpg 並且host是127.0.0.1:8080的快取
curl -X PURGE -H "path: /imgs/test.jpg" -H "x-host: 127.0.0.1:8080" http://127.0.0.1/nuster/cache
通過正則刪除
也可以通過正則刪除,所有匹配正則的快取將被刪除。
headers
header | value | description |
---|---|---|
regex | REGEX | caches which path match with ${REGEX} will be purged |
x-host | HOST | and host is ${HOST} |
Examples
# 刪除所有 /imgs 開頭 .jpg結尾的快取
curl -X PURGE -H "regex: ^/imgs/.*.jpg$" http://127.0.0.1/nuster/cache
#delete all caches which path starts with /imgs and ends with .jpg and belongs to 127.0.0.1:8080
curl -X PURGE -H "regex: ^/imgs/.*.jpg$" -H "127.0.0.1:8080" http://127.0.0.1/nuster/cache
PURGE 注意事項
- 開啟訪問控制
- 如果有多個header,按照
name
,path & host
,path
,regex & host
,regex
,host
的順序處理curl -XPURGE -H "name: rule1" -H "path: /imgs/a.jpg"
: purge by name - 如果有重複的header,處理第一個
curl -XPURGE -H "name: rule1" -H "name: rule2"
: purge byrule1
-
regex
不是 glob比如 /imgs下的.jpg檔案是
^/imgs/.*.jpg$
而不是/imgs/*.jpg
快取統計
可以通過GET uri
定義的endpoint來獲取快取統計資訊。
Eanble and define the endpoint
nuster cache on uri /nuster/cache
Usage
curl http://127.0.0.1/nuster/cache
Output
- used_mem: http快取使用的記憶體,不包括overhead
- req_total: 開啟了cache的所有的backend的總請求數,不包含那些沒有cache的backend的請求數
- req_hit: cache擊中數
- req_fetch: 從後端取得數量
- req_abort: 中斷的請求
NoSQL
NuSTER也可以用作RESTful NoSQL快取伺服器, 用HTTP POST/GET/DELETE
來 新增/取得/刪除 Key/Value.
基本操作
Set
curl -v -X POST -d value1 http://127.0.0.1:8080/key1
curl -v -X POST --data-binary @icon.jpg http://127.0.0.1:8080/imgs/icon.jpg
Get
curl -v http://127.0.0.1:8080/key1
Delete
curl -v -X DELETE http://127.0.0.1:8080/key1
Response
Check status code.
-
200 OK
- POST/GET: 成功
- DELETE: 總是
-
400 Bad request
- 空值
- 不正確的acl, rules, etc
-
404 Not Found
- POST: rule tests失敗
- GET: not found
-
405 Method Not Allowed
- 其他的methods
-
500 Internal Server Error
- 發生未知錯誤
-
507 Insufficient Storage
- 超過data-size
分使用者的data
通過在key里加入header, cookie等等,可以將不同的使用者資料存到相同的路勁。
nuster rule r1 key method.scheme.host.uri.header_userId if { path /mypoint }
nuster rule r2 key method.scheme.host.uri.cookie_sessionId if { path /mydata }
Set
curl -v -X POST -d "333" -H "userId: 1000" http://127.0.0.1:8080/mypoint
curl -v -X POST -d "555" -H "userId: 1001" http://127.0.0.1:8080/mypoint
curl -v -X POST -d "userA data" --cookie "sessionId: ijsf023xe" http://127.0.0.1:8080/mydata
curl -v -X POST -d "userB data" --cookie "sessionId: rosre329x" http://127.0.0.1:8080/mydata
Get
curl -v http://127.0.0.1:8080/mypoint
< 404 Not Found
curl -v -H "userId: 1000" http://127.0.0.1:8080/mypoint
< 200 OK
333
curl -v --cookie "sessionId: ijsf023xe" http://127.0.0.1:8080/mydata
< 200 OK
userA data
客戶端
支援任何支援HTTP的客戶端,庫: curl
, postman
, python requests
, go net/http
, etc.
FAQ
如何除錯?
在global
新增debug
, 或者帶-d
啟動haproxy
快取相關的除錯資訊以[CACHE]
開頭
如何快取POST請求?
新增option http-buffer-request
如果自定義了key的話需要使用body
關鍵字
請求body可能不完整,詳見HAProxy configuration 的 option http-buffer-request小節
另外可以為post請求單獨設定一個後端
如何做訪問控制?
類似
acl network_allowed src 127.0.0.1
acl purge_method method PURGE
http-request deny if purge_method !network_allowed
如何開啟HTTP2?
bind :443 ssl crt pub.pem alpn h2,http/1.1
Example
global
nuster cache on data-size 100m
nuster nosql on data-size 100m
#daemon
## to debug cache
#debug
defaults
retries 3
option redispatch
timeout client 30s
timeout connect 30s
timeout server 30s
frontend web1
bind *:8080
mode http
acl pathPost path /search
use_backend app1a if pathPost
default_backend app1b
backend app1a
balance roundrobin
# mode must be http
mode http
# http-buffer-request must be enabled to cache post request
option http-buffer-request
acl pathPost path /search
# enable cache for this proxy
nuster cache
# cache /search for 120 seconds. Only works when POST/PUT
nuster rule rpost key method.scheme.host.uri.body ttl 120 if pathPost
server s1 10.0.0.10:8080
backend app1b
balance roundrobin
mode http
nuster cache on
# cache /a.jpg, not expire
acl pathA path /a.jpg
nuster rule r1 ttl 0 if pathA
# cache /mypage, key contains cookie[userId], so it will be cached per user
acl pathB path /mypage
nuster rule r2 key method.scheme.host.path.delimiter.query.cookie_userId ttl 60 if pathB
# cache /a.html if response`s header[cache] is yes
http-request set-var(txn.pathC) path
acl pathC var(txn.pathC) -m str /a.html
acl resHdrCache1 res.hdr(cache) yes
nuster rule r3 if pathC resHdrCache1
# cache /heavy for 100 seconds if be_conn greater than 10
acl heavypage path /heavy
acl tooFast be_conn ge 100
nuster rule heavy ttl 100 if heavypage tooFast
# cache all if response`s header[asdf] is fdsa
acl resHdrCache2 res.hdr(asdf) fdsa
nuster rule resCache ttl 0 if resHdrCache1
server s1 10.0.0.10:8080
frontend web2
bind *:8081
mode http
default_backend app2
backend app2
balance roundrobin
mode http
# disable cache on this proxy
nuster cache off
nuster rule all
server s2 10.0.0.11:8080
listen web3
bind *:8082
mode http
nuster cache
nuster rule everything
server s3 10.0.0.12:8080
frontend nosql_fe
bind *:9090
default_backend nosql_be
backend nosql_be
nuster nosql on
nuster rule r1 ttl 3600
Conventions
- Files with same name: those with
.md
extension belong to NuSTER, otherwise HAProxy
Contributing
- Join the development
- Give feedback
- Report issues
- Send pull requests
- Spread nuster
License
Copyright (C) 2017-2018, Jiang Wenyuan, < koubunen AT gmail DOT com >
All rights reserved.
Licensed under GPL, the same as HAProxy
HAProxy and other sources license notices: see relevant individual files.