基於HAProxy的高效能HTTP快取伺服器和RESTful NoSQL快取伺服器。

NusterCache發表於2018-07-09

NuSTER

Wiki | English | 中文 | 日本語

基於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倍。

詳見benchmark

入門指南

下載

生產環境的話從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指令。

基本

配置檔案裡有四個基本的sections: global, defaults, frontend and backend

  • global

    • 定義全域性指令
    • 需要定義nuster cache on or nuster nosql on,否則cache和nosql無法使用
  • defaults

    • 定義frontend, backend的預設引數
    • 可以在frontend or backend section重新定義
  • frontend

    • 定義監聽埠等等面向使用者的設定
  • bankend

    • 定義後端伺服器等等設定
    • 需要設定nuster cache on or nuster 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, gG. 預設是1MB,同時也是最小值。

dict-size

決定hash table的大小.

可以使用m, M, gG. 預設是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 configuration7. 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-hostheader來刪除所有屬於這個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 注意事項

  1. 開啟訪問控制
  2. 如果有多個header,按照name, path & host, path, regex & host, regex, host的順序處理

    curl -XPURGE -H "name: rule1" -H "path: /imgs/a.jpg": purge by name

  3. 如果有重複的header,處理第一個

    curl -XPURGE -H "name: rule1" -H "name: rule2": purge by rule1

  4. 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 configurationoption 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

  1. 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.

相關文章