Quần Cam

Monitor Varnish Cache như thế nào?

Giới thiệu Varnish

Varnish Cache là một reverse HTTP proxy, đôi khi còn được xem là một web accelerator (tăng tốc web). Varnish đóng vai trò đứng giữa client và server trong một web service, cache lại HTTP response files trong memory, giúp giảm thời gian response và hao tốn network bandwidth của những request tương tự.

varnish-graph

Như hình bên trên bạn thấy Quần Cam đang xem phim XXX, .. à nhầm, đang xem phim từ dịch vụ của XXX. Ở lần request đầu tiên, Varnish không tìm thấy response tương ứng trong memory cache store, nó sẽ forward request đến server XXX và lưu response object vào cache store. Ở các request tương tự tiếp theo, thay vì phải request XXX, nó sẽ tự serve client bằng response object trong cache store.

Như app bên mình có đến 80% request là read, nên việc có một Varnish đứng đầu ngọn sóng đã giúp giảm một lượng lớn tải cho các backend server.

Trong bài viết này, mình sẽ giới thiệu một chút về cách bọn mình thu thập metrics và monitor Varnish cluster.

Thu thập metrics

Về mặt tổng quan thì bên mình dùng influxdb để lưu trữ, Telegraf để thu thập, Kapacitor để cảnh báo, và Grafana cho việc hiển thị metrics. Bạn có thể đọc bài viết này để biết thêm chi tiết.

Telegraf có hỗ trợ sẵn Varnish input plugin giúp thu thập Varnish metrics. Tuy nhiên có lẽ vì Varnish bên mình dùng khá cổ (2.x), không có metrics nào được report khi bật thử plugin.

Cái khó ló cái khôn

Sau khi đọc code một hồi thì lý do Telegraf không nhận thông số là do output của varnishstat đã thay đổi từ version 3. Xem tham số output của hai version bên dưới ta thấy Varnish 4 gán category prefix cho tên của các thông số như MAIN.*, Telegraf dựa vào format này để đọc và group các tham số.

Các tham số output của varnishstat version 2.

uptime               14234778          .   Child uptime
client_conn        2703079202       189.89 Client connections accepted
client_req         2839064624       199.45 Client requests received
cache_hit          2267678359       159.31 Cache hits
cache_hitpass               0         0.00 Cache hits for pass
cache_miss          478890598        33.64 Cache misses

Còn của version 4.

NAME                  CURRENT       CHANGE      AVERAGE       AVG_10      AVG_100     AVG_1000
MAIN.uptime           171488         1.00         1.00         1.00         1.00         1.00
MAIN.sess_conn          1055         7.98          .           8.35         4.49         2.11
MAIN.client_req         1055         7.98          .           8.35         4.49         2.11
MAIN.cache_hit          1052         7.98          .           8.35         4.49         2.10
MAIN.cache_miss            3         0.00          .           0.00         0.00         0.00
MAIN.backend_conn          4         0.00          .           0.00         0.00         0.01

May mắn là Telegraf cho phép tùy chỉnh file thực thi của varnishstat, nên tụi mình đã tự viết lại một cái varnishstat riêng. Nói thì ghê gớm chứ thực chất chỉ gắn thêm MAIN.* vào tên của các tham số rồi output lại, chỉ với một bash script nhỏ dưới đây.

# /usr/bin/varnishstat2to4

#!/bin/bash

/usr/bin/varnishstat -1 | sed -e '/^[a-z]/ s/^/MAIN./'

Công việc còn lại chỉ là cài đặt file này vào Telegraf config.

# A plugin to collect stats from Varnish HTTP Cache
[[inputs.varnish]]
  ## The default location of the varnishstat binary can be overridden with:
  binary = "/usr/bin/varnish2to4"

  ## By default, telegraf gathers stats for 3 metric points.
  ## Setting stats will override the defaults shown below.
  ## stats may also be set to ["all"], which will collect all stats
  stats = ["all"]

Các thông số quan trọng

1. hit rate

Đây là thông số quan trọng nhất để đánh giá performance của một Varnish cluster. Nôm na nếu hit rate đạt 80% có nghĩa phần lớn lượng request đến web service đã được served bởi cache mà không cần request đến backend. Nó cũng đồng nghĩa thời gian response nhanh hơn và giảm tải rất nhiều cho backend server (điều này có thể không đúng, xem thêm giải thích cache_hitpass ở bên dưới).

Ba thông số đáng chú ý nhất là:

  • cache_hit: Lũy tích số lần mà Varnish serve request từ cache store.
  • cache_miss: Lũy tích số lần mà Varnish không thể serve request từ cache store, mà phải request từ backend.
  • cache_hitpass: Có một số request không thể cache được mà phải luôn request đến backend, như POST /users/create chẳng hạn. Những request này sẽ được tính là cache_hitpass chứ không là cache_miss.

Công thức tính hit rate khá đơn giản.

hit_rate = cache_hit / (cache_hit + cache_pass)

Hit rate càng cao thì càng tốt, cụ thể như bên mình luôn giữ hit rate ở mức tối thiểu 60% cho thời điểm bình thường và 80% cho peak. Quan trọng nhất là ở peak hours, khi web service của bạn đang chịu tải lớn, việc giữ cho hit rate của Varnish càng cao sẽ giảm càng nhiều tải cho backend servers.

varnish hit rate

Varnish hit rate graph của Wikimedia

2. Memory

Đây là cơ sở để bạn tiến hành nâng hit rate, dựa vào các dữ kiện như LRU objects đã được evicted (dọn) như thế nào, dung lượng bộ nhớ ra sao.

Các thông số nên chú ý ở đây là:

  • n_expired: Số lượng object expired vì TTL từ Cache-Control header.
  • n_lru_nuked: Số lượng object đã bị evicted vì thiếu memory.
  • sma_nbytes: Tổng số allocated memory.
  • sma_nobj: Tổng số allocated objects.

Có ba cách để một object bị xóa/dọn khỏi Varnish:

1) Expired: object bị xóa vì TTL được set trong Cache-Control đã hết hạn. Cách xóa này được xem là lành mạnh, vì vòng đời của object diễn ra theo đúng ý nguyện của backend server.

2) Purged: object bị xóa vì admin muốn thế, như đôi khi bạn muốn content được refresh ngay lập tức (chẳng hạn sau khi cập nhật CSS, JS). Cách xóa này cũng có thể xem là lành mạnh.

3) Evicted: object bị xóa khỏi Varnish bị thiếu memory. Varnish là một LRU (Least Recently Used) cache, nên các object ít được dùng nhất sẽ bị lấy chỗ cho object mới.

Khi monitor Varnish, nếu n_lru_nuked tăng một cách chóng mặt (thường tỉ lệ nghịch với hit rate), bạn nên xem xét tăng memory cho Varnish để các cache object cần thiết không bị xóa đi.

3. Client

Các thông số về client cũng khá thú vị.

  • client_req: Số lượng request Varnish nhận được.
  • client_conn: Số lượng connection Varnish nhận được.

Bạn có thể dùng client_req để biết số request/s và setup một số alerts khi thông số này tăng/giảm đột ngột.

varnish request

HTTP request graph của Wikimedia

Bài viết này có giúp tôi tăng lương không?

Xin khẳng định là bài viết không giúp bạn tăng lương. Nhưng mình có một số tips để giúp bạn nâng hit rate.

1) Để ý thông số n_lru_nuked

Như mình đã viết, việc các object bị evicted theo cách không tự nhiên đồng nghĩa với việc miss rate cao hơn -> hit rate giảm đi. Trong trường hợp này bạn có thể xem xét tăng memory cho Varnish.

2) Sử dụng default HTTP caching mechanism

Rất khó để mình liệt kê hết tất cả HTTP caching mechanism trong này, mình sẽ nêu một số ví dụ.

Giả sử bạn đang dùng Varnish để host một cái S3 bucket (Cloudfront đắt lắm), hãy đảm bảo bạn có set Cache-Control hay Expires cho các S3 objects. TTL có thể được cài đặt mặc định khi Varnish được chạy nhưng đặt các cache headers sẽ giúp bạn điều khiển được vòng đời của Varnish object theo ý muốn.

Mặc định Varnish sẽ pass các request sử dụng cookies vì lý do security, nên hãy bỏ Cookies header cho các request không cần cookies, để Varnish cache và tự serve client mà không cần backend request.

3) Normalize các header

Varnish dựa vào Vary header để cache các version khác nhau của cùng một request.

Như Varnish sẽ xem hai request dưới đây là khác nhau, từ đó lưu thành hai version khác nhau.

Vary: Accept-Encoding
Accept-Encoding: gzip,deflate

Vary: Accept-Encoding
Accept-Encoding: deflate,gzip

Vì vậy bạn nên normalize lại để tránh lãng phí memory, để có thêm không gian cho Varnish lưu những object khác.

Nếu không normalize, trường hợp xấu nhất là một số server trả về Vary: User-Agent trong response headers tùy theo browser/client, mà User-Agent thì chỉ riêng Google Chrome đã có chừng chục cái, tỉ lệ hit rate của bạn rơi xuống vực thẳm là rất cao.

4) Viết lại hàm hash của bạn nếu cần thiết

Chỉ nên làm việc này nếu bạn hiểu rõ bạn đang làm gì.

Varnish lưu object với key là một hash, sau đó nó sẽ dùng hash này khi cần tìm lại object. Mặc định hash sẽ được tính toán dựa trên request url và Host header.

Tuy vậy bạn có thể viết lại hàm hash theo ý của mình để nâng hiệu suất cache của Varnish.

sub vcl_hash {
  set req.hash += req.url;
  set req.hash += req.http.host;
  set req.hash += req.http.Accept;
  return (hash);
}

Tham khảo

  1. The Varnish Book.
  2. Top Varnish Performance Metrics.

NGUY HIỂM! KHU VỰC NHIỀU GIÓ!
Khuyến cáo giữ chặt bàn phím và lướt thật nhanh khi đi qua khu vực này.
Chức năng này hỗ trợ markdown và các thứ liên quan.

Bài viết cùng chủ đề

Cache stampede—Hiện tượng chất đống cache

Caching là một kĩ thuật tăng tốc mà hầu như mọi kĩ sư phần mềm đều cần biết. Tuy vậy, đôi khi caching vẫn có thể mang lại cho bạn những vấn đề phiền toái khác như cache stampede.

Chết server, làm gì đây?

Giả sử server tự dưng lăn đùng ra chết không còn gửi được request nữa, bạn sẽ làm gì?

Chạy database migration khi deploy, nên hay không?

Có một thủ pháp thường hay được sử dụng khi deploy app là chạy database migration ngay khi deploy, nhưng liệu đó có phải là một good practice (tam dịch: cách làm tốt)?