Chìa khóa để mở rộng lớp cân bằng tải HTTP là trước tiên thêm một lớp cân bằng tải cấp thấp hơn (IP hoặc TCP). Lớp này có thể được xây dựng hoàn toàn bằng phần mềm nguồn mở, mặc dù bạn sẽ có kết quả tốt hơn nếu bạn có bộ định tuyến hiện đại.
Các luồng (phiên TCP) phải được băm bằng cách sử dụng các tiêu đề như cổng nguồn / IP đích và cổng TCP để quyết định giao diện nào chúng đi đến. Bạn cũng cần một cơ chế để đảm bảo rằng khi một frontend chết, nó sẽ ngừng sử dụng.
Có nhiều chiến lược khác nhau, tôi sẽ phác thảo một cặp đôi mà tôi đã sử dụng trong sản xuất trên các trang web phục vụ hàng triệu người dùng, để bạn có thể có ý tưởng. Sẽ là quá dài để giải thích mọi thứ chi tiết nhưng tôi hy vọng câu trả lời này sẽ cung cấp cho bạn đủ thông tin / gợi ý để bắt đầu. Để thực hiện các giải pháp này, bạn sẽ cần một người thực sự am hiểu về mạng.
Phải thừa nhận rằng những gì tôi mô tả ở đây khó thực hiện hơn nhiều so với những gì được mô tả trong các câu trả lời khác, nhưng đây thực sự là công nghệ tiên tiến nếu bạn có một trang web bị buôn bán cao với các vấn đề về khả năng mở rộng lớn và yêu cầu về tính khả dụng trên 99,9% . Với điều kiện bạn đã có một anh chàng kỹ sư mạng trên tàu, chi phí thiết lập và chạy (cả trong capex và opex) ít hơn so với các thiết bị cân bằng tải, và nó có thể được thu nhỏ hơn mà không phải trả thêm chi phí (so với mua mới, thậm chí nhiều hơn thiết bị đắt tiền khi bạn vượt xa mô hình hiện tại của bạn).
Chiến lược đầu tiên: với tường lửa
Có lẽ bạn có một vài bộ định tuyến mà trên đó các đường lên ISP của bạn được kết nối. ISP của bạn cung cấp 2 liên kết (chủ động / thụ động, sử dụng VRRP). Trên các bộ định tuyến của bạn, bạn cũng sử dụng VRRP và bạn định tuyến lưu lượng truy cập đến mạng công cộng của mình đến tường lửa. Tường lửa ( FW 1
và FW 2
bên dưới) cũng hoạt động / thụ động và sẽ lọc lưu lượng và gửi từng luồng đến một máy chủ lối vào lành mạnh (bộ cân bằng tải HTTP của bạn FE 1
và FE 2
bên dưới).
+ -------------- + + -------------- +
| Bộ định tuyến ISP A | | Bộ định tuyến ISP B |
+ -------------- + + -------------- +
| |
== # ====================== # == (mạng công cộng)
| |
+ --------------- + + --------------- +
| Bộ định tuyến của bạn A | | Bộ định tuyến của bạn B |
+ --------------- + + --------------- +
| |
== # ===== # ========== # ===== # == (Mạng riêng RFC 1918)
| | | |
+ ------ + + ------ + + ------ + + ------ +
| FW 1 | | FE 1 | | FE 2 | | FW 2 |
+ ------ + + ------ + + ------ + + ------ +
Mục tiêu là để có một dòng chảy như thế này:
- ISP định tuyến lưu lượng truy cập đến IP của bạn đến bộ định tuyến hoạt động của bạn.
- Bộ định tuyến của bạn định tuyến lưu lượng đến VIP sử dụng địa chỉ RFC 1918 . VIP này được sở hữu bởi tường lửa hoạt động, giống như VRRP. Nếu bạn sử dụng OpenBSD cho nhu cầu tường lửa của mình, thì bạn có thể sử dụng CARP , một giải pháp thay thế không có bằng sáng chế cho VRRP / HSRP.
- Tường lửa của bạn áp dụng bộ lọc (ví dụ: "chỉ cho phép 80 / tcp và 443 / tcp đi đến địa chỉ IP cụ thể này").
- Tường lửa của bạn cũng hoạt động như một bộ định tuyến và chuyển tiếp các gói đến một lối vào lành mạnh.
- Giao diện của bạn chấm dứt kết nối TCP.
Bây giờ phép màu xảy ra ở bước 4 và 5, vì vậy hãy xem chi tiết hơn những gì họ làm.
Tường lửa của bạn biết danh sách các frontend ( FE 1
và FE 2
) và nó sẽ chọn một trong số chúng dựa trên một khía cạnh cụ thể của luồng (ví dụ: bằng cách băm IP và cổng nguồn, trong số các tiêu đề khác). Nhưng nó cũng cần đảm bảo rằng nó chuyển tiếp lưu lượng truy cập đến một lối vào lành mạnh, nếu không bạn sẽ bị tắc nghẽn giao thông. Nếu bạn sử dụng OpenBSD, ví dụ, bạn có thể sử dụng relayd
. Gìrelayd
thật đơn giản: nó kiểm tra sức khỏe tất cả các frontend của bạn (ví dụ bằng cách gửi cho chúng một yêu cầu HTTP thăm dò) và bất cứ khi nào frontend khỏe mạnh, nó sẽ thêm nó vào một bảng mà tường lửa sử dụng để chọn bước nhảy tiếp theo của các gói của một luồng nhất định . Nếu một frontend không kiểm tra sức khỏe, nó sẽ bị xóa khỏi bảng và không có gói nào được gửi đến nó nữa. Khi chuyển tiếp một gói đến một giao diện, tất cả các tường lửa thực hiện là hoán đổi địa chỉ MAC đích của gói thành địa chỉ của giao diện được chọn.
Trong bước 5, các gói từ người dùng được nhận bởi bộ cân bằng tải của bạn (có thể là Varnish, nginx hoặc bất cứ thứ gì). Tại thời điểm này, gói tin vẫn được chuyển đến địa chỉ IP công cộng của bạn, do đó bạn cần đặt bí danh cho VIP của mình trên giao diện loopback. Đây được gọi là DSR (Direct Server Return), bởi vì các giao diện của bạn chấm dứt kết nối TCP và tường lửa ở giữa chỉ nhìn thấy lưu lượng đơn giản (chỉ các gói đến). Bộ định tuyến của bạn sẽ định tuyến các gói đi trực tiếp trở lại bộ định tuyến của ISP. Điều này đặc biệt tốt cho lưu lượng HTTP vì các yêu cầu có xu hướng nhỏ hơn phản hồi, đôi khi đáng kể là như vậy. Nói rõ hơn: đây không phải là một điều cụ thể của OpenBSD và được sử dụng rộng rãi trong các trang web buôn bán cao.
Gotchas:
- Người dùng cuối sẽ kết nối trực tiếp với máy chủ lối vào của bạn vì bạn sử dụng DSR. Có thể đó là trường hợp đã xảy ra, nhưng nếu không, bạn cần đảm bảo rằng chúng được bảo mật đầy đủ.
- Nếu bạn sử dụng OpenBSD, hãy cẩn thận rằng hạt nhân là một luồng để hiệu suất của lõi CPU đơn sẽ hạn chế thông lượng của tường lửa. Nó có thể là một vấn đề tùy thuộc vào loại NIC của bạn và tốc độ gói bạn đang thấy. Có nhiều cách để giải quyết vấn đề này (nhiều hơn về điều này dưới đây).
Chiến lược thứ hai: không có tường lửa
Chiến lược này hiệu quả hơn nhưng khó thiết lập hơn vì nó phụ thuộc nhiều hơn vào chi tiết cụ thể của các bộ định tuyến bạn có. Ý tưởng là vượt qua tường lửa ở trên và để các bộ định tuyến thực hiện tất cả công việc mà tường lửa đang làm.
Bạn sẽ cần các bộ định tuyến hỗ trợ các LL / L4 ACL trên mỗi cổng, BGP và ECMP và Định tuyến dựa trên chính sách (PBR). Chỉ các bộ định tuyến cao cấp mới hỗ trợ các tính năng này và chúng thường có thêm phí cấp phép để sử dụng BGP. Điều này thường vẫn rẻ hơn so với cân bằng tải phần cứng, và cũng dễ dàng hơn để mở rộng quy mô. Điểm hay của các bộ định tuyến cao cấp này là chúng có xu hướng tốc độ đường truyền (ví dụ: chúng luôn có thể tối đa hóa liên kết, ngay cả trên các giao diện 10GbE, bởi vì tất cả các quyết định mà chúng đưa ra đều được thực hiện trong phần cứng bởi ASIC).
Trên các cổng mà bạn có đường dẫn ISP của mình, hãy áp dụng ACL đã từng có trên tường lửa (ví dụ: "chỉ cho phép 80 / tcp và 443 / tcp đi đến địa chỉ IP cụ thể này"). Sau đó, mỗi một trong các frontend của bạn duy trì một phiên BGP với bộ định tuyến của bạn. Bạn có thể sử dụng OpenBGPD tuyệt vời (nếu tiền tuyến của bạn là trên OpenBSD) hoặc Quagga . Bộ định tuyến của bạn sẽ ECMP lưu lượng truy cập đến các tiền tuyến khỏe mạnh (vì họ đang duy trì các phiên BGP của họ). Bộ định tuyến cũng sẽ định tuyến lưu lượng ra một cách thích hợp bằng PBR.
Sàng lọc
- Với giải pháp cặp tường lửa, thật tuyệt nếu bạn có thể đồng bộ hóa các trạng thái TCP trên tường lửa, để khi một tường lửa bị lỗi, mọi thứ sẽ không hoạt động trơn tru với trạng thái khác. Bạn có thể đạt được điều này với
pfsync
.
- Hãy nhớ rằng
pfsync
thông thường sẽ tăng gấp đôi tốc độ gói trên tường lửa của bạn.
- HTTP là một giao thức không trạng thái, vì vậy nó không phải là kết thúc của thế giới nếu bạn đặt lại tất cả các kết nối trong khi chuyển đổi tường lửa vì bạn không sử dụng
pfsync
.
- Nếu bạn vượt qua một tường lửa, bạn có thể sử dụng ECMP trên bộ định tuyến của mình để định tuyến lưu lượng truy cập của bạn đến nhiều hơn một cặp tường lửa.
- Nếu bạn sử dụng nhiều hơn một cặp tường lửa, bạn cũng có thể làm cho tất cả chúng hoạt động / hoạt động. Bạn có thể đạt được điều này bằng cách yêu cầu tường lửa duy trì phiên BGP với các bộ định tuyến, giống như các mặt trận cần duy trì một trong thiết kế thứ 2 mà không cần tường lửa.
relayd
Cấu hình mẫu
Xem thêm HOWTO tại https://calomel.org/relayd.html
vip = "1.2.3.4" # Địa chỉ IP công cộng của bạn
# (bạn có thể có nhiều hơn một, nhưng không cần)
phong1 = "10.1.2.101"
phong2 = "10.1.2.102"
phong3 = "10.1.2.103"
fe4 = "10.1.2.104" # Bạn có thể có bất kỳ số lượng giao diện nào.
int_if = "em0"
bảng <fe> {$ fe1 thử lại 2, $ fe2 thử lại 2, $ fe3 thử lại 2, $ fe4 thử lại 2}
bảng <dự phòng> {127.0.0.1}
chuyển hướng webtraffic {
nghe trên cổng $ vip 80
thời gian chờ phiên 60
tuyến đường đến <fe> kiểm tra http "/healthcheck.html" digest "(sha1sum của Healthcheck.html)" giao diện $ int_if
}