C
Linux
nginx
haproxy
Cache

キャッシュサーバーnusterを紹介

https://github.com/jiangwenyuan/nuster

Nusterは高速なキャッシュサーバー。

仕様は変更されるかもしれないので、最新のものはhttps://github.com/jiangwenyuan/nuster/blob/master/README.mdを参照してください。

紹介

NusterはHAProxyを元に開発したキャッシュサーバーで、HAProxyと互換性がある。
そしてHAProxyのACLを利用して細かいキャッシュルールを定義できる。

  • HAProxyのすべての機能や特徴がサポート、100%互換性
  • 動的キャッシング機能
    • HTTP method, URI, path, query, header, cookiesなどでキャッシング
    • HTTP request or response contentsなどでキャッシング
    • environment variables, server stateなどでキャッシング
    • SSL version, SNI などでキャッシング
    • connection rate, number, byte などでキャッシング
  • スーパー速い
  • キャッシュ purging
  • フロントエンドとバックエンド両方HTTPS
  • HTTP圧縮
  • HTTPリライトやリダイレクト
  • などなど

性能

スーパー早い

シングルコアでnginxより3倍、マルチコアでnginxより2倍varnishより3倍のテスト結果
があった。

詳細はこちら

インストール

make TARGET=linux2628
make install

HAProxy README参照

使い方

globalセクションにnuster cache onを定義して、backendlistenセクションに
nuster-ruleも定義する

ディレクティブ

cache

syntax: nuster cache on|off [share on|off] [data-size size] [dict-size size] [purge-method method]

default: none

context: global

キャッシュを使うかどうかを決める。

単位m, M, g and Gdata-sizeで最大キャッシュサイズが設定できる。

ディフォルトは1MBで、最小値も1MBである。 リスポンス内容だけが計算される。

nuster cache

syntax: nuster cache [on|off]

default: on

context: backend, listen

cache filterを定義する。 cache-rule も定義する必要がある。

on,offで単独でコントロールできる。

複数のfilterがある場合、cache filterは最後におくこと。

nuster-rule

syntax: nuster-rule name [key KEY] [ttl TTL] [code CODE] [if|unless condition]

default: none

context: backend, listen

cache ruleを定義する。複数のルールがある場合は順序を注意して定義すること。
マッチングできたら止まるので。

acl pathA path /a.html
nuster cache
nuster-rule all ttl 3600
nuster-rule path01 ttl 60 if pathA

allが全てのリクエストをキャッシュしたので、path01は実行されない

name

名前を定義する

key KEY

下記のキーワードで.で繋いでkeyを定義する。

  • method: http method, GET/POST...
  • scheme: http or https
  • host: the host in the request
  • path: the URL path of the request
  • 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

ディフォルトkeyはmethod.scheme.host.path.query.body

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
  • path: /q
  • query: name=X&type=Y
  • header_ASDF: Z
  • cookie_user: nuster
  • param_type: Y
  • body: (empty)

ので、ディフォルトkeyはGEThttpwww.example.com/qname=X&type=Yで、
key method.scheme.host.path.header_ASDF.cookie_user.param_type
GEThttpwww.example.com/qZnusterYになる。

キャッシュにリクエストと同じなkeyがあったら、キャッシュを返す。

ttl TTL

生存期限を定義する。単位は d, h, msで、 ディフォルトは3600秒。
0の場合は失効しない。

code CODE1,CODE2...

ディフォルトは200のリスポンスしかキャッシュしない、ほかのものをキャッシュしたい場合は
定義する。 allの場合は全てキャッシュする。

nuster-rule only200
nuster-rule 200and404 code 200,404
nuster-rule all code all

if|unless condition

HAProxy ACLを使う。
See 7. Using ACLs and fetching samples section in HAProxy configuration

FAQ

debug方法?

globaldebugを設定か, haproxy-dで起動する。

キャッシュに関するメッセージは[CACHE]を含む。

どうやってPOSTリクエストをキャッシュする?

option http-buffer-requestを設定

カスタマイズしたkeyはbodyを入れること。

POST bodyは不完全な可能性があるので、option http-buffer-request
section in HAProxy configuration を参照

単独でPOST用のbackendを設置した方がいいかもしれない

Example

global
    nuster cache 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 on

    # cache /search for 120 seconds. Only works when POST/PUT
    nuster-rule rpost 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.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