Trang chủ Linux Webserver Varnish – Tìm hiểu VCL

Varnish – Tìm hiểu VCL

bởi Thạch Phạm
1 bình luận 4,K views

Tham gia nhóm hỗ trợ WordPress

Tham gia nhóm Hỗ trợ Server - Hosting & WordPress để cùng nhau hỏi đáp và hỗ trợ các vấn đề về WordPress, tối ưu máy chủ/server.

Tham gia ngay
Bài này thuộc phần 6 của 6 phần trong serie Varnish cho WordPress

Khi sử dụng Varnish, chắc chắn bạn sẽ nghe nhiều đến VCL và nhất là tập tin /etc/varnish/default.vcl. Vậy VCL là gì? ý nghĩa của những đoạn code trong đó ra sao? Trong bài này mình sẽ giải thích khái quát cho các bạn hiểu về VCL để có thể tự tìm hiểu hơn ở trang Varnish Documentation. Cũng xin nói trước rằng các đoạn code trong VCL đa phần là dò tìm và so sánh giá trị nên sẽ sử dụng regex (biểu thức chính quy) rất nhiều nên đây là dịp tốt bạn nên tìm hiểu luôn về biểu thức chính quy.

VCL trong Varnish là gì?

VCL trong Varnish là chữ viết tắt của Varnish Configuration Language (ngôn ngữ cấu hình Varnish), đọc qua tên chắc bạn cũng biết nó là cái gì rồi. VCL được phân cấu trúc bởi các chương trình con (subroutines) và mỗi chương trình con sẽ đều có một chức năng khi các đoạn code bên trong mỗi chương trình con khớp với chỉ thị của các truy cập gửi vào server. Nghe có vẻ trừu tượng quá, bạn hãy tưởng tượng VCL có một số chương trình con trong VCL như chương trình trả dữ liệu về client, chương trình nhận dữ liệu về client,…và trong mỗi chương trình đó ta sẽ viết code để điều khiển nó làm việc như ý muốn. Ví dụ bạn có thể chỉ định Varnish không gửi cache đến các truy vấn truy cập vào website đang mang một cookie nào đó (ví dụ như cookie wordpress_logged_in của các truy vấn của người dùng đang đăng nhập vào WordPres).

Mặc dù VCL rất đơn giản nhưng lại cực kỳ mạnh mẽ bởi vì bạn có thể tự xây dựng một subroutine ngoài việc sử dụng các subroutine có sẵn của Varnish. Dưới đây là ví dụ của một đoạn code sử dụng subroutine vcl_recv để tùy biến việc nhận dữ liệu từ backend server vào Varnish.

[c]
sub vcl_recv {

Khuyến mãi Black Friday

# Không load cache cho những người dùng Wordpress đang đăng nhập (dùng cookie wordpress_logged_in)
if ( req.http.cookie ~ "wordpress_logged_in" ) {
return( pass );
}
}
[/c]

Điều này cũng có nghĩa là tất cả các code trong file default.vcl đều phải đặt trong một subroutine và một subroutine không thể tái sử dụng hai lần trong cùng một tập tin.

Website sẽ ra sao khi không có bất kỳ đoạn mã VCL nào?

Nếu file default.vcl của bạn không có nội dung VCL nào ngoài dòng backend server để khai báo cổng kết nối của backend, thì tất cả các trang của bạn đều được gắn cache và tự động hủy (purge) sau 2 phút.

Cấu trúc một đoạn VCL

Cấu trúc code của VCL rất đơn giản và dễ hiểu, thoạt nhìn bạn có thể thấy nó có chút hơi na ná với ngôn ngữ C hoặc Perl. Một đoạn VCL được bao gồm thế này:

[c]sub tên-chương-trình-con {
// Các quy tắt thực thi
}[/c]

Trong đó, sub là từ khóa khai báo một subroutine, các subroutine có sẵn luôn bắt đầu là vcl_ nhưng nếu bạn tự tạo subroutine thì bạn sẽ không có quyền đặt tên là vcl_.

Cú pháp VCL

Như mình đã nói ở trên, VCL có cấu trúc giống như C hoặc Perl nên việc một đoạn code VCL nhìn giống C là điều hiển nhiên, kể cả trong cú pháp.

String (giá trị kiểu chuỗi)

Khi thiết lập giá trị kiểu chuỗi trong VCL, bạn chắc chắn rằng nó luôn được bọc trong dấu nháy đôi “…” và không được xuống hàng. Kể cả khi bạn dùng regex (biểu thức chính quy) thì việc khai báo các ký tự đặc biệt cũng phải được đặt trong cặp dấu nháy đôi.

[c]req.url ~ "(?i)\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm)(\?[a-z0-9]+)?$" )[/c]

Toán tử

Tuy là một ngôn ngữ đơn giản nhưng VCL cũng hỗ trợ một số toán tử như:

=
Gán giá trị.

==
So sánh bằng giá trị tuyệt đối.

~
So sánh bằng giá trị tương đối/tương đương, hoặc sử dụng với regex.

!
Phủ định.

&&
Logical and

||
Logical or

Các subroutines có sẵn

Các subroutine mình khai báo trong đây là các subroutine ở Varnish 3. Trên phiên bản Varnish 4, một số subroutine đã được đổi tên, xem tại đây.

Xin nhắc lại rằng, subroutine nghĩa là một chương trình con để gom nhóm các đoạn code bên trong để nó sẽ thực thi dựa vào ý nghĩa của từng subroutine. Mặc định Varnish cung cấp sẵn một số subroutines như:

vcl_recv

Các code trong nhóm này sẽ được gọi ra khi bắt đầu khách gửi một truy vấn đến server, hoặc sau khi hoàn thành một truy vấn đã được nhận và phân tích. Mục đích của subroutine này là để điều hướng kiểm tra dữ liệu của người gửi truy vấn nhằm có thể điều hướng cho Varnish gửi truy vấn thẳng đến backend server mà không cần trả lại cache cho khách.

Tiến trình xử lý của subroutine này sẽ được kết thúc bằng return(), nó có thể chứa các từ khóa như:

  • hash – Khi return bằng từ khóa này, trang của người dùng sẽ được Varnish hiểu như là có thể lưu cache bằng cách gán cho nó một mã băm riêng biệt, lúc này Varnish sẽ chuyển đến subroutine vcl_hash để nó làm việc.
  • pass – Khi return bằng từ khóa này, Varnish sẽ gửi truy vấn đến trực tiếp backend server, bạn có thể hiểu nếu pass thì khách sẽ truy cập thẳng vào backend server mà không có cache.
  • pipe – Chuyển request đến Pipe Mode dựa trên subroutine vcl_pipe.
  • purge – Chuyển đối tượng request thành một biến thể để loại bỏ, nó sẽ được xử lý thông qua subroutine vcl_hash và vcl_purge.

vcl_pipe

Ngay sau khi subroutine nếu có chuyển quá trình xử lý đến Pipe Mode thông qua việc return(pipe) thì các code trong subroutine này sẽ được thực thi. Hãy hiểu rằng, Pipe Mode là Varnish sẽ mở một kết nối hai chiều TCP Proxy để request có thể gửi thẳng đến backend server và ngược lại. Hãy nhớ rằng, nếu bạn có sử dụng subroutine này thì không có bất cứ subroutine nào khác được xử lý sau khi Pipe Mode kết thúc. Pipe Mode sẽ được kết thúc bằng return() với một số từ khóa như:

  • pipe – chuyển request vào Pipe mode.

vcl_pass

Subroutine này sẽ được áp dụng khi request được gửi vào pass mode. Pass mode nghĩa là các request sẽ được gửi đến thẳng backend server và backend server sẽ trả lại dữ liệu mà không truy cập vào bất cứ đối tượng cache nào.

Subroutine này sẽ được kết thúc bằng return() với một số từ khóa như:

  • fetch – Báo hiệu request này đã đi vào pass mode và backend server bắt đầu xử lý.
  • restart – Bắt đầu lại quá trình chuyển giao request.

vcl_hit

Subroutine vcl_hit sẽ được gọi ra khi request đã tìm thấy một bản cache phù hợp thành công trong Varnish. vcl_hit sẽ được kết thúc quá trình bằng return() với các từ khóa:

  • deliver – Chuyển giao đối tượng cache cho người gửi request.
  • fetch – Đồng bộ lại dữ liệu của đối tượng đã được lưu cache với nội dung trả về từ backend server. Lúc này, subroutine vcl_miss sẽ bắt đầu làm việc.
  • pass – Gửi request vào pass mode với vcl_pass.
  • restart – Bắt đầu lại quá trình chuyển giao request.

vcl_miss

Subroutine này sẽ được kích hoạt nếu request không tìm thấy đối tượng cache phù hợp, hoặc request được return(fetch) ở subroutine vcl_hit.

Nó cũng sẽ được kết thúc bằng return() với các từ khóa như sau:

  • fetch – lấy lại đối tượng đã được request đến backend. Nó sẽ được control qua subroutine vcl_backend_fetch.
  • pass – Đưa request vào pass mode và xử lý bằng vcl_pass.
  • restart – Bắt đầu lại quá trình chuyển giao request.

vcl_hash

Ngay sau khi các request được xử lý bằng vcl_recv mà được return(hash) thì subroutine này sẽ làm việc. Nó được sử dụng như để tìm ra một đối tượng đã được cache trong Varnish bằng một mã băm riêng biệt.

Riêng với subroutine này nó chỉ có một cách kết thúc quá trình là return(lookup) để tìm một đối tượng cache.

vcl_purge

Được gọi ra khi quá trình purge cache bắt đầu. Nó sẽ được kết thúc quá trình bằng return() với các từ khóa:

  • restart – Bắt đầu lại quá trình chuyển giao request.

vcl_deliver

Subroutine này sẽ được gọi ra trước khi bất cứ đối tượng nào được gửi cho người gửi request, ngoại trừ kết quả của subroutine vcl_synth. Nó kết thúc bằng return() với các từ khóa:

  • deliver – Chuyển giao đối tượng cache cho người gửi request.
  • restart – Bắt đầu lại quá trình chuyển giao request.

vcl_error

Subroutine này sẽ được thực thi khi backend server bị lỗi không truy cập được để lấy dữ liệu. Trường hợp dùng nhiều nhất là khai báo hàm synthetic() trong subroutine này để tạo một trang báo lỗi trong Varnish. Subroutine này mình sẽ có một số ví dụ ở phần sau.

Lệnh include trong VCL

Ngoài tập tin default.vcl mặc định, bạn có thể tạo ra nhiều file.vcl khác và sau đó bạn có thể sử dụng từ khóa include trong file default.vcl để load nó.

[c]include "wordpress.vcl";

include "main.vcl";[/c]

Các biến toàn cục

Nếu bạn có đọc qua nội dung VCL mà mình đã kêu bạn copy thì sẽ thấy có một số biến như req.url, req.request,…Vậy nó là gì, Varnish có những biến gì? Ở phần này bạn sẽ hiểu. Danh sách các biến toàn cục của VCL có rất nhiều nên mình chỉ liệt kê một số biến hay sử dụng mà thôi, bạn có thể xem chi tiết tại đây.

Ngoài ra, các biến toàn cục này có thể được gán giá trị bằng từ khóa set hoặc unset để bỏ gán.

now
Hiển thị thời gian hiện tại.

Các biến dưới đây sẽ lấy thông tin ở backend server:

.host
Hostname hoặc địa chỉ IP của Varnish Server.
.port
Lấy số cổng kết nối đang được Varnish sử dụng.

Các biến dưới đây sẽ dùng được trong một quá trình xử lý các request:

client.ip
Địa chỉ IP của máy khách đang gửi truy vấn.
client.identity
Mã chứng minh của khách truy cập.
server.hostname
Tên hostname của máy chủ.
server.ip
Địa chỉ IP của máy chủ mà khách truy cập đang truy cập vào.
server.port
Port của máy chủ mà khách truy cập đang truy cập vào.
req.request
Loại request: POST, GET, TRACE, HEAD,….
req.url
Địa chỉ URL được gửi request.
req.proto
Giao thức HTTP được gửi request.
req.backend
Tên của backend server được xử lý request.
req.backend.healthy
Whether the backend is healthy or not. Requires an active probe to be set on the backend.
req.http.header
Thông tin header của địa chỉ gửi request.
req.hash_always_miss
Nếu biến này được thiết lập giá trị là true, thì Varnish sẽ không quan tâm đến bất kỳ đối tượng nào được trả về từ backend server.
req.restarts
Hiển thị số lần request đã được restart.

Một số ví dụ về VCL

Ở trên bạn đã đọc qua một số khái niệm quan trọng trong VCL rồi, bây giờ mình sẽ cho bạn một số ví dụ về VCL để bạn hiểu hơn về cách làm việc của nó.

Cho request pass vào backend server trong đường dẫn http://domain/wp-admin hoặc wp-admin:

[c]sub vcl_recv {

# Pass các request trang admin vào backend
if ( ! ( req.url ~ "wp-(login|admin)" ) ) {
return (pass);
}

}[/c]

Hiển thị trang báo lỗi nếu backend server bị ngưng hoạt động.

[c]
sub vcl_backend_error { set obj.http.Content-Type = "text/html; charset=utf-8"; synthetic {"
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>We’ll Be Right Back!</title>
<meta http-equiv="refresh" content="3">
</head>
<body bgcolor=#FFFFFF text=#222222>
<center>
<table border=0 cellpadding=3 cellspacing=3 width=790>
<tr><td>
<div style="font-size:150%; font-family:Arial;">
<h1>WEBSITE ĐANG BỊ NGHẼN – HÃY ĐỢI MỘT CHÚT</h1>
<p>Website sẽ tự động làm mới sau mỗi 3 giây</p>
</div>
</td></tr>
</table>
</center>
</body>
</html>
"};
return(deliver);
}
[/c]

Chặn liên kết ở các website khác. Ví dụ như chặn hiển thị hình ảnh từ link của bạn trên website khác.

[c]
sub vcl_recv {
if (req.http.host == "www.example.com" &&
req.url ~ "^/fun/" &&
(req.http.referer && req.http.referer !~ "^http://www.example.com/")) {
error 403 "No hotlinking please";
}
}
[/c]

Một số nguồn cấu hình VCL khác như:

Lời kết

Trong bài này có lẻ mình đã viết hơi dài rồi và có thể kết thúc serie Varnish 3 tại đây. Hãy nhớ rằng bài viết của mình chỉ nói khái quát chứ không thể nói chi tiết được VCL của Varnish nên hãy lên Google gõ “Varnish Documentation” để biết thêm chi tiết để có hiểu nó toàn diện hơn.

Hy vọng với serie Varnish này, các bạn có thể dễ dàng áp dụng phần mềm này vào máy chủ của mình để có thể tối ưu hơn về tốc độ của website.

Đánh giá nội dung này
1 bình luận

Có thể bạn quan tâm

Hiện tại blog tạm đóng bình luận vì mình cần tập trung thời gian vào cập nhật bài viết. Bình luận sẽ mở ra cho đến khi mình sẵn sàng.