work.log

元エンジニアの備忘録的ブログ

HAProxyとNginxで作るコンテンツキャッシュシステム (前編)

投稿:2014-05-08 20:34  更新:

オープンソースの HAProxy とNginx を組み合わせてコンテンツキャッシュシステムを構築するメモです。

リバースプロキシ型で動作するキャッシュシステムを構成して、既に動いている WordPress を何もしなくてもキャッシュで高速化できるようなものを作ってみたいと思います。

キャッシュだけなら Nginx の単体構成が低コストで手っ取り早いですが、今回つくるシステムはリバースプロキシ型で動作するので終端のサーバの事をあまり気にする必要がなく、既存の環境へも適用しやすいのがメリットです。(じゃないかと思っています。)

構成的には下記のような感じを予定しています。

http --> [haproxy *1] -- req --> [nginx *2] -- req --> [apache]

 * [server] <= 物理サーバの凡例
 * ip は下記を割り当て
   haproxy vip       = 192.168.0.1, 192.168.0.2
   proxy1 (nginx) ip = 192.168.0.51
   proxy2 (nginx) ip = 192.168.0.52
   www1 (apache) ip  = 192.168.0.101
   www2 (apache) ip  = 192.168.0.102

今回、コンテンツキャッシュシステムとして構築するのは *1 と *2 の部分です。Apache は既に動いているものをそのまま使います。

概要としては、HAProxy で HTTP アクセスを制御 + 配下のキャッシュサーバ (Nginx) の死活をコントロール、Nginx でリバースプロキシ型の構成でキャッシュ。という感じです。

これを使う場合は、WordPress で使う独自ドメインを HAProxy の vip へ向けてやるという感じです。

コンテンツキャッシュシステム構築は前編と後編に分けて書こうと思いますが。今回は HAProxy 側から先に書きます。

HAProxy の構成例

HAProxy は version 1.4.22 を使って、コンテンツ、サーバの振り分けとキャッシュサーバの死活監視ができるように設定してあげます。

Nginx の設定でも一応は絞りますが、キャッシュサーバに流すトラフィックとそうでないものを最初から HAProxy で分けてしまいます。

キャッシュサーバに流すトラフィック内容はこんな感じです。

  • リクエストヘッダに text/html を含むもの
  • リクエストヘッダに application/xhtml+xml を含むもの
  • css および js ファイル

これ以外は全て Apache が動いているリアルサーバに直接流してやります。

ただし、下記の場合は除外します。

  • wp-login.php へのアクセス
  • wp-admin 配下へのアクセス

上記はキャッシュするとよろしくないので完全にキャッシュ対象外としてしまいます。

多分、こんな感じで足りるはず!

上記を元にした HAProxy コンフィグはこんな感じに。

global
	log 127.0.0.1 local6 notice
	maxconn 150000
	daemon
	nbproc 1

defaults
	log 127.0.0.1 local6 info
	retries 0
	mode    http
	balance leastconn
	timeout connect 30s
	timeout server  30s
	timeout client  30s
	timeout check   5s
	option  httplog
	option  forwardfor
	option  httpchk GET /check.html HTTP/1.0

frontend multiple_frontend
	bind    :80
	maxconn 130000
 
	## ホストの判定
	acl is_www1 dst 192.168.0.1
	acl is_www2 dst 192.168.0.2
	acl is_lb hdr_dom(host) -i lb.example.com

	## http header の判定
	acl is_cache hdr(Accept) -i text/html
	acl is_cache hdr(Accept) -i application/xhtml+xml
	acl is_cache path_end -i .css .css.gz .js .js.gz

	## url path の判定
	acl is_admin url -i /wp-login.php
	acl is_admin url_dir -i /wp-admin/

	## ここから宛先を振り分け

	## is_lb が真の場合は haproxy のステータスを表示
	use_backend lb_monitor if is_lb

	## is_admin が偽、かつ、is_cache が真の場合はキャッシュサーバへ
	use_backend dst_nginx_1 if ! is_admin is_cache

    ## is_www? が真の場合は対応するリアルサーバへ
	use_backend dst_www1 if is_www1
	use_backend dst_www2 if is_www2

	## どれにもマッチしなければデフォルトサーバへ
	default_backend dst_default

backend dst_nginx_1
	server  proxy1 192.168.0.51:80 check inter 5000 fall 2
	server  proxy2 192.168.0.52:80 check inter 5000 fall 2

backend dst_www1
	server  www 192.168.0.101:80

backend dst_www2
	server  www2 192.168.0.102:80

backend dst_default
	server  default 192.168.0.254:80

backend lb_monitor
	log     global
	stats   enable
	stats   show-legends
	stats   uri /hastats
	stats   auth haadmin:haadminpasss

ほぼそのままコピってるので長くなりました。

見通しの良さを重視して、1 つの frontend で処理できるように vip と 宛先 ip を結びつけるように書いているのがポイント。各種オプションも defaults ディレクティブに押し込んでいます。

後は、コンフィグチェックをして問題がなければ daemon を起動して HAProxy 側の構築は完了です。

今回は割愛していますが、HAProxy 自体も冗長化しておくのがベターかと思います。

※ ヘルスチェック は配下の DocumentRoot に置いた check.html を見るようにしているので注意。

今回初めて知りましたが、HAProxy の if で AND を使いたい場合は、「if is_hoge is_huga」のようにそのまま続けて書くらしい。

OR だと「if is_hoge or is_huga」か「if is_hoge || is_huga」なので、AND も「if is_hoge and is_huga」かと思ってたのにコンフィグチェックで怒られまくった。

※ ACL については公式ドキュメント 「7. Using ACLs and pattern extraction」を参照。

参考にしたページ
HAProxy Document

次は、Nginx 側について書きます。(つづく)