1 điểm bởi GN⁺ 2024-09-26 | 1 bình luận | Chia sẻ qua WhatsApp
  • Wafris thay kho lưu trữ Redis do người dùng sở hữu trong client middleware Rails v1 bằng kho lưu trữ dựa trên SQLite ở v2, nhằm đồng thời giảm độ khó khi triển khai và độ trễ đánh giá yêu cầu
  • Việc chọn Redis trước đây chịu ảnh hưởng từ quán tính của hệ sinh thái Rails như Heroku và Sidekiq, nhưng trong vận hành thực tế, vấn đề người dùng phải gánh cả vai trò quản trị Redis ngày càng lớn
  • Đường đọc so sánh mọi yêu cầu HTTP đến với các quy tắc là nút thắt chính; các lượt ghi để báo cáo có thể được xử lý chậm hơn hoặc tách ra theo batch/bất đồng bộ
  • Kết quả kiểm thử tra cứu dải IP trong trường hợp xấu nhất với tập dữ liệu 1,2 triệu dải trên MacBook Air M2 cục bộ cho thấy SQLite nhanh hơn Redis cục bộ khoảng 3 lần, chưa tính độ trễ mạng
  • v2 dùng cấu trúc đồng bộ hóa trong đó client kiểm tra quy tắc mới theo một khoảng thời gian hoặc số lượng yêu cầu nhất định, rồi tải xuống toàn bộ DB SQLite mới; số lượt cài đặt thành công tăng khoảng 3 lần

Ma sát triển khai bộc lộ ở v1 dựa trên Redis

  • Wafris là một công ty tường lửa ứng dụng web mã nguồn mở, cung cấp client middleware gắn vào các ứng dụng Rails
  • Client v1 yêu cầu kho lưu trữ Redis do người dùng sở hữu được triển khai cùng ứng dụng
  • Việc chọn Redis ban đầu chịu ảnh hưởng từ môi trường có thể dễ dàng gắn Redis trên Heroku, sự tiện lợi của truy cập từ xa và các câu chuyện thành công như Sidekiq
  • Môi trường thực tế của người dùng đa dạng hơn, và nhiều người gặp khó khăn khi debug các vấn đề triển khai và cấu hình Redis
  • Tại RailsWorld 2023, cũng có bầu không khí không mấy tích cực với giả định rằng nhất thiết phải có một máy chủ Redis bên cạnh ứng dụng Rails

Cốt lõi của vấn đề tốc độ là độ trễ mạng

  • Redis nhanh hơn so với RDBMS truyền thống, nhưng vì là một cơ sở dữ liệu riêng biệt, nó đòi hỏi quản lý kết nối, bộ nhớ và tiến trình
  • Trong môi trường đám mây, độ trễ mạng trực tiếp làm dao động hiệu năng xử lý yêu cầu
    • Wafris phải so sánh mọi yêu cầu HTTP đi vào ứng dụng với các quy tắc đã lưu
    • Dù tối ưu client v1 nhanh nhất có thể, nếu mạng nơi ứng dụng được triển khai chậm thì toàn bộ phản hồi vẫn có thể chậm lại
  • Ứng dụng Rails cũng không phải lúc nào cũng được triển khai dưới dạng một “majestic monolith” duy nhất
    • Ứng dụng được triển khai ở nhiều zone
    • Ứng dụng được chia thành nhiều máy chủ có trách nhiệm chồng lấn
    • Ứng dụng chỉ một phần là Rails và được triển khai cùng ngôn ngữ hoặc framework khác
  • Trong các môi trường vận hành như vậy, ma sát khi dùng Redis càng lớn hơn

Tách đọc và ghi trong xử lý yêu cầu của Wafris

  • Wafris được cài đặt dưới dạng middleware Rails; sau khi đặt quy tắc như “chặn IP 1.2.3.4”, nó so sánh các yêu cầu đến với quy tắc đó
  • Luồng xử lý đơn giản hóa gồm hai bước
    1. So sánh yêu cầu HTTP với các quy tắc; nếu khớp thì xử lý 403, nếu không thì 200
    2. Báo cáo kết quả xử lý như chặn, cho phép hoặc cho qua
  • Đọc quy tắc, bước đầu tiên, quan trọng hơn nhiều so với ghi báo cáo
    • Yêu cầu phải được xử lý tuần tự
    • Nếu lọc không hoạt động, yêu cầu xấu có thể lọt qua
    • Việc đánh giá yêu cầu ảnh hưởng đến hiệu năng website mà người dùng cảm nhận
    • Ghi báo cáo có thể xử lý chậm hơn, theo batch, bất đồng bộ

Lý do chọn SQLite

  • Nút thắt chính của Wafris là I/O mạng, và câu trong tài liệu SQLite rằng “SQLite không cạnh tranh với cơ sở dữ liệu client/server. SQLite cạnh tranh với fopen()” đã ảnh hưởng đến lựa chọn này
  • Với giả định rằng chỉ cần loại bỏ lượt đi-về qua mạng cũng có thể nhanh hơn kiến trúc dựa trên Redis, họ benchmark SQLite và Redis
  • Tài liệu tham khảo gồm

Phạm vi benchmark và các giới hạn có chủ ý

  • Benchmark này không phải là so sánh hiệu năng cơ sở dữ liệu phổ quát, mà là một bài kiểm thử thiên lệch nhắm vào hot path và truy vấn tệ nhất của Wafris
  • Truy vấn tệ nhất là tra cứu trên cấu trúc dữ liệu “lexical decimal” ánh xạ dải IP với danh mục
    • Một ví dụ đơn giản là ánh xạ IP → quốc gia, trong đó kiểm tra địa chỉ IP có nằm giữa hai địa chỉ hay không để trả về quốc gia
    • Cấu trúc này có quy mô hàng triệu dòng, và với IPv6 thì mỗi mục rất lớn
  • Tra cứu dải được tính trước rồi ghi vào hai kho lưu trữ
  • Trong trường hợp bệnh lý, mỗi yêu cầu HTTP đến phải so sánh IP của yêu cầu với các dải sau
    1. Dải cho phép do người dùng định nghĩa
    2. Dải chặn do người dùng định nghĩa
    3. Dải GeoIP
    4. Dải uy tín IP
  • Vì loại truy vấn này đủ quan trọng, họ chỉ kiểm thử một loại này mà không port các truy vấn hay tính năng khác

Cách kiểm thử và kết quả

  • Kiểm thử dùng Redis cài bằng Homebrew và DB SQLite cục bộ trên MacBook Air M2 cục bộ
  • Giao thức như sau
    1. Dùng tập dữ liệu dải hiện có gồm 1,2 triệu mục
    2. Chạy nhiều tập IP trên SQLite và Redis theo cùng thứ tự
    3. Chạy kiểm thử 5 lần cho mỗi bội số và dùng giá trị trung bình
  • Trong use case cụ thể của Wafris, SQLite nhanh hơn Redis cục bộ khoảng 3 lần
  • Kết quả này là con số trước khi tính đến độ trễ mạng
  • Kiểm thử cố ý phản ánh cấu hình đơn giản và các khiếm khuyết của sử dụng thực tế, nên khó khái quát hóa thành so sánh cơ sở dữ liệu phổ quát

Khác biệt vận hành không hiện trên biểu đồ

  • Ngay cả nếu hiệu năng SQLite trong benchmark tệ hơn Redis đáng kể, họ vẫn cho rằng trong môi trường thực tế nó có thể nhanh hơn vì độ trễ mạng đến Redis trong cùng data center hoặc region
  • Dù máy chủ Redis được cấu hình chắc chắn bằng cluster hoặc sharding, các giới hạn như băng thông mạng, số lượng kết nối và độ trễ giữa các region vẫn còn
  • Vì SQLite nằm cục bộ trên từng compute instance, trong use case này của Wafris, chi phí mở rộng ngang gần như biến mất
  • Onboarding cũng đơn giản hơn với SQLite
    • Người dùng có thể thêm gem vào ứng dụng web và chạy mà không cần biết SQLite đang được dùng
  • Redis cũng còn nhiều cơ hội tối ưu bổ sung, nhưng Wafris khó thuyết phục người dùng một cách nhất quán ngay cả với các thay đổi cấu hình cơ bản như chính sách loại bỏ cache

Các thay đổi kiến trúc cần thiết sau khi chuyển sang SQLite

  • Luồng cập nhật của v1 dựa trên Redis khá đơn giản
    1. Người dùng cập nhật quy tắc trong Wafris Hub
    2. Wafris Hub cập nhật quy tắc trong kho Redis của người dùng
  • Với SQLite, Wafris Hub không thể trực tiếp “push” cơ sở dữ liệu SQLite đến máy chủ web
  • Một số nhà cung cấp SQLite as a service cho phép cách làm tương tự, nhưng không phù hợp với Wafris vì cân nhắc chi phí, hiệu năng và bảo mật
    • Từng người dùng phải triển khai nó
    • Phải mở port
    • Phải cho phép kết nối inbound
  • Luồng cập nhật của v2 dựa trên SQLite như sau
    1. Người dùng cập nhật quy tắc trong Wafris Hub
    2. Client kiểm tra quy tắc đã cập nhật theo một khoảng thời gian nhất định hoặc theo số lượng yêu cầu
    3. Nếu quy tắc đã thay đổi, client tải xuống một cơ sở dữ liệu SQLite hoàn toàn mới
  • Cấu trúc này giảm đáng kể trách nhiệm cài đặt và cấu hình của người dùng, và số lượt cài đặt thành công của client v2 tăng khoảng 3 lần

Kiến trúc SQLite trong triển khai phân tán

  • Khi ứng dụng Rails autoscale trong các môi trường đám mây như AWS, Heroku, Fly, compute instance tăng lên nhưng cơ sở dữ liệu thường không tăng theo
  • Khi lưu lượng tăng từ 100 req/s lên 10.000 req/s, dyno, machine, EC2 instance sẽ được bật thêm, nhưng nút thắt cơ sở dữ liệu có thể vẫn giữ nguyên
  • Nguyên nhân chính gây sự cố ứng dụng Rails mà Wafris quan sát được thường là credential stuffing hoặc lưu lượng bot xấu hơn là DDoS thực sự
    • Loại lưu lượng này kích hoạt autoscaling
    • Sau đó kết nối cơ sở dữ liệu cạn kiệt và ứng dụng có thể sập
  • Khi đồng bộ DB SQLite tới từng compute instance, mọi lời gọi của instance mới có thể được giữ ở cục bộ

Loại bỏ đường ghi khỏi client

  • Các kiểm thử ở trên không xét đến thao tác ghi, và cũng không cho rằng SQLite phù hợp với mọi vai trò
  • Wafris dùng SQLite theo hướng vai trò thiên về đọc, còn đường ghi được thiết kế lại riêng
  • Đường báo cáo của v2 thay đổi như sau
    • Báo cáo qua kết nối bất đồng bộ đến Wafris Hub
    • Gửi dữ liệu báo cáo theo batch
    • Loại bỏ hoàn toàn ghi cơ sở dữ liệu khỏi client
  • Cấu trúc này có thể không phù hợp với hầu hết dịch vụ khác, nhưng phù hợp với mục tiêu của người dùng Wafris là triển khai dễ dàng và client nhanh
  • Kiến trúc v2 dựa trên SQLite đã giúp nhiều website chống chịu tấn công và duy trì trạng thái online, đồng thời giảm công việc hỗ trợ của Wafris và sự bất tiện cho người dùng

1 bình luận

 
GN⁺ 2024-09-26
Các ý kiến trên Hacker News
  • Mô hình trong đó mỗi máy chủ ứng dụng có một bản sao của tệp cơ sở dữ liệu SQLite và định kỳ thay thế toàn bộ thật sự rất thú vị
    Ở đây họ dùng cho các quy tắc tường lửa ứng dụng web, nhưng có vẻ cũng rất hợp với cấu hình feature flag. Feature flag có thể được kiểm tra hàng chục lần cho mỗi request, và thường cần các truy vấn kiểu “người dùng thuộc nhóm A và IP ở quốc gia B”, điều mà SQLite cục bộ có thể xử lý tốt. Với feature flag, việc cập nhật được lan truyền trễ vài giây, hoặc lâu hơn, nhìn chung vẫn chấp nhận được

    • Đây cũng là mô hình được dùng trong CDN. Họ cập nhật một tệp cấu hình toàn cục chứa chứng chỉ của mọi khách hàng, quy tắc định tuyến HTTP, v.v. dưới dạng cấu trúc B-tree một tệp, rồi thường xuyên phân phối “bundle” đó tới mọi vị trí edge
      Tuy nhiên tôi chưa thấy trường hợp nào dùng SQLite cho mục đích này; thường họ dùng các cơ sở dữ liệu kiểu DBM như LMDB hoặc Kyoto Cabinet
    • Airbnb cũng đã dùng mô hình này để phân phối bản dịch, feature flag, cấu hình, chỉ mục tìm kiếm và nhiều thứ khác. Thay vì SQLite, họ dùng Sparkey, một định dạng tệp key-value do Spotify tạo ra
      Ban đầu, cron job trên từng máy chủ sẽ lấy dữ liệu của dịch vụ tương ứng; sau khi chuyển sang Kubernetes, họ dùng DaemonSet cùng một cơ chế tương tự host tagging/taints để tải nhiều loại dữ liệu xuống từng host, rồi bảo đảm các dịch vụ sử dụng dữ liệu đó chỉ chạy trên những host ấy. Trong Ruby, họ gọi thứ này là “hammerspace”: https://github.com/airbnb/hammerspace
    • Vấn đề tra cứu giá trị feature flag nhiều lần trong mỗi request được giải quyết bằng cách chỉ lấy giá trị flag một lần rồi lưu vào đối tượng request
      Làm vậy giúp không phải trả chi phí tra cứu đắt đỏ hơn một lần trong cùng một request, đồng thời tránh rủi ro giá trị trở nên không nhất quán nếu flag được cập nhật trong lúc xử lý request
    • Sau khi xử lý feature flag trong thời gian dài trong một đợt migration kéo dài, tôi tin rằng thành phần nền tảng thật sự hữu ích là “giống SQLite nhưng mỗi thay đổi đều làm tăng bộ đếm phiên bản toàn cục, và có thể lấy hoặc áp dụng chỉ phần thay đổi giữa các số phiên bản”
      Trên nền đó có thể đặt nhiều cơ chế phân phối khác nhau, như mạng gossip hoặc mạng cache/phân phối dạng cây rõ ràng. Bất kỳ ai có phiên bản mới hơn đều có thể cung cấp bản cập nhật
      Có thể đưa phiên bản DB hiện tại vào artifact của ứng dụng, nhưng sau khi ứng dụng chạy thì vẫn cập nhật hiệu quả được. Với feature flag hoặc cấu hình live, có thể fallback về trạng thái gần đây thay vì giá trị mặc định ở mức mã nguồn
      Bất kỳ client nào cũng có thể gửi bộ đếm toàn cục giống như ETAG và chỉ nhận phần thay đổi; việc kết nối lại sau khi mạng đứt tạm thời cũng trở nên đơn giản và rẻ
      Nếu có thể giữ lịch sử trong vài phút, có thể gắn bộ đếm vào các lời gọi microservice theo kiểu header W3C Baggage để nhiều dịch vụ đánh giá flag/cấu hình/dữ liệu dựa trên cùng một số phiên bản. Ngay cả khi không có khả năng đánh giá theo thời điểm, việc ghi generation number vào log cũng giúp ích rất nhiều cho debug hậu kỳ
    • SQLite dùng để phân phối dữ liệu rất hay. Ý tưởng này có vẻ được truyền cảm hứng phần nào từ dự án Datasette, và về sau có lẽ vẫn còn làm được điều gì đó ở mảng báo cáo và khám phá dữ liệu
  • Ngoài độ trễ mạng, với Redis tôi còn thấy độ trễ đọc/ghi có xu hướng gần như tỷ lệ tuyến tính với số lượng key được truy vấn, và biểu đồ trong bài cũng có vẻ tương tự
    Khi dùng Postgres và Redis cùng nhau theo từng mục đích trong một ứng dụng monolithic, nó hoạt động khá tốt, nhưng việc nhét một tính năng mới vào cụm Redis dùng chung lại quá dễ. Redis là đơn luồng, nên chỉ một tính năng thiếu cân nhắc thực hiện truy vấn hàng loạt hơn 100 nghìn key cũng có thể làm chậm cả các tính năng khác
    Vì vậy tôi đã đề xuất guideline rằng Redis đặc biệt phù hợp khi đọc/ghi một key hoặc một số lượng key nhỏ và cố định mỗi lần, chẳng hạn như lock hoặc rate limiting cho endpoint phổ biến, khi nhiều tính năng ngẫu nhiên cùng dùng Redis
    Trong trường hợp này, Redis sẽ tỏa sáng với truy vấn đơn giản trên một key duy nhất (địa chỉ IP), nhưng có vẻ không hợp với các thao tác đọc phức tạp hơn như biểu diễn truy vấn phạm vi. Tôi không hiểu sâu vì sao SQLite lại hoạt động tốt đến vậy so với Redis cục bộ, nên điều đó khá bất ngờ và thú vị

    • Redis thường trở thành cái bẫy vì mọi người dễ hiểu sai điểm mạnh và điểm yếu của nó
      Tốt nhất nên xem Redis như một cache có các phép toán cơ bản phong phú hơn. Dùng đúng thì nó nhanh và ổn định
      Nhưng nếu bắt đầu đưa vào Redis những thứ không hợp với RDBMS cơ bản, chẳng mấy chốc sẽ xuất hiện hàng đợi công việc, nhiều loại lock, v.v.; khi đó chỉ còn là vấn đề thời gian trước khi hiệu năng rơi xuống vực hoặc sụp vì lý do khác. Quá trình khôi phục thường lộn xộn, và dễ đi đến kết cục phải chấp nhận mất một phần dữ liệu
      Dòng chảy này diễn ra từng chút một rất dễ dàng, nên cần kỷ luật để tránh. Hiệu năng của SQLite không chỉ đến từ việc tránh overhead mạng; một yếu tố lớn nữa là nhiều người đánh giá thấp chi phí tuần tự hóa/giải tuần tự hóa. Dù giao thức Redis khá tối giản, chi phí vẫn tích lũy; còn trong SQLite, nhiều thao tác rốt cuộc chỉ là sao chép bộ nhớ trong cùng tiến trình
  • Vài tuần trước, trong hackathon nội bộ của Neon, tôi đã tạo một máy chủ Node.js nhỏ chuyển giao thức wire của Redis, RESP, thành truy vấn Postgres
    Đó là một dự án hack rất vui: https://github.com/btholt/redis-to-postgres

  • Nghe như một use case đặc thù khá phù hợp với SQLite phía server, nơi cơ sở dữ liệu chỉ đọc nên không cần replication
    Một phương án khác có thể là nạp tệp tĩnh vào bộ nhớ, nhưng trong trường hợp này có vẻ dữ liệu quá nhiều để giữ liên tục trong bộ nhớ, nên SQLite là một lựa chọn tốt

    • Hy vọng bài viết đã truyền tải được rằng đây là một giải pháp tuyệt vời phù hợp với use case cụ thể, chứ không phải bản thay thế 1:1 cho Redis hay Postgres
    • Nếu bắt đầu từ cách nạp tệp tĩnh vào bộ nhớ rồi thêm vừa đủ các tính năng cần thiết để nó hoạt động cho các use case phổ biến, cuối cùng bạn sẽ có một cơ sở dữ liệu quan hệ giống SQLite
      Khác biệt là SQLite rất vững chắc, hiệu năng tốt và được kiểm thử đặc biệt kỹ lưỡng
  • Tôi tò mò về đoạn nói rằng ở RailsWorld 2023 có bầu không khí “ngửi thấy mùi máu” đối với Redis
    Trong sự nghiệp, tôi chỉ từng làm một ứng dụng Rails production, và ứng dụng đó dùng Redis, nên không rõ xu hướng hiện nay. Tôi tò mò liệu hệ sinh thái đang quay lưng với Redis từ góc nhìn kinh doanh, do thay đổi giấy phép, hay chỉ là tình huống gần với YAGNI
    Khi đó, chúng tôi chủ yếu dùng nó cùng với Resque để lên lịch các tác vụ bất đồng bộ như tạo chỉ mục, transcoding, và lúc ấy nó trông như một công cụ khá ổn

    • Hơi gần với YAGNI. Lý do lớn nhất khiến Redis được dùng nhiều trong cộng đồng Rails là các tác vụ bất đồng bộ, và công cụ mà đa số chọn là Sidekiq
      Trong khảo sát cộng đồng Rails 2024, Redis vẫn là kho lưu trữ dữ liệu được dùng nhiều nhất trong ứng dụng
      Tuy nhiên, dù nhiều ứng dụng có dùng Redis, thực tế thường chỉ dùng cho các mục đích như Sidekiq, chứ không tận dụng cho leaderboard thời gian thực hay tính năng vector DB, nên bức tranh sử dụng thực tế hơi mờ
    • Tôi nghĩ đây thuần túy là vấn đề đơn giản hóa
      Hiện nay, một cấu hình Rails có lượng traffic nhất định thường có server frontend, SQL DB, kho khóa-giá trị (Redis hoặc Memcached), và cache store trỏ tới kho khóa-giá trị đó. Nhưng cách dùng khóa-giá trị thông thường để duy trì quota API hay rate limit khá khác với mô hình dùng cache, nên khá phiền
      Hiệu năng đĩa đã đủ nhanh và hiệu năng SQL cũng tốt hơn, nên có xu hướng loại bỏ kho khóa-giá trị: các nhu cầu khóa-giá trị truyền thống chuyển sang SQL DB, còn backend cache chuyển xuống đĩa. Đĩa NVMe mới nhanh gần bằng RAM nhưng rẻ hơn nhiều, nên có thể cache nhiều hơn
    • Redis từng hữu ích như một dạng bộ nhớ chia sẻ rất thông minh, có sẵn các tính năng như hết hạn. Khi clustering thì cũng có thể chia sẻ giữa nhiều máy
      Nhưng trong thời Kubernetes và Redis-as-a-service, “bộ nhớ chia sẻ” đó lại nằm trên một VM khác ở một rack khác. Đến mức đó thì coi như đã từ bỏ hiệu quả tài nguyên rồi, nên tôi nghĩ cứ đọc/ghi file từ S3 còn hơn
    • SSD ngày nay nhanh, nên nhiều người hơn nên dùng RocksDB. Có thể chạy một kho khóa-giá trị lớn hơn nhiều trên SSD
  • Về đoạn “Redis nhanh hơn RDBMS truyền thống, nhưng vẫn là một cơ sở dữ liệu phải quản lý kết nối, bộ nhớ, tiến trình, v.v., nên làm stack dễ mong manh hơn”, tôi nghĩ khi bắt đầu xử lý các transaction vượt mức đồ chơi, thì mọi cơ sở dữ liệu, dù quan hệ hay phi quan hệ, đều cần mức quản lý và bảo trì tương tự nhau
    Phần “nhanh” cũng hơi thú vị. Nếu không phải bận tâm đến join, thì chèn và truy vấn hàng cũng khá nhanh

    • Lý do SQLite nhanh đặc biệt trong môi trường server là vì không cần lời gọi mạng khi query hoặc lấy dữ liệu
      Khi hiểu rằng nó đọc trực tiếp từ đĩa cục bộ, thì chuyện join hay transaction không còn nhiều ý nghĩa. Bản thân đường đi đó đã nhanh hơn vài bậc độ lớn
    • SQLite có thao tác VACUUM trông giống một dạng garbage collection
      Mỗi lần đọc tài liệu về việc nên chạy VACUUM khi nào tôi đều thấy rối. Lần gần nhất triển khai một ứng dụng dựa trên SQLite, tôi chỉ đặt một bộ đếm và chạy VACUUM sau nhiều thao tác ghi
    • Tôi không đồng ý với câu “mọi cơ sở dữ liệu đều yêu cầu mức quản lý và bảo trì tương tự nhau”
      Nếu là cơ sở dữ liệu phải vận hành một tiến trình server độc lập, thì chắc chắn nỗ lực quản lý và bảo trì sẽ khác nhau. Nhìn cực đoan thì thật khó tin rằng dùng SQLite và Oracle lại không có khác biệt gì
  • Có thể bạn sẽ quan tâm đến Redka, một bản tái triển khai Redis bằng Go trên SQLite: https://github.com/nalgeon/redka

    • Nó thú vị đến mức đáng cân nhắc chuyển sang, nhưng tôi chần chừ khi thấy phần “theo benchmark, Redka chậm hơn Redis vài lần”
      Đúng là một dự án hay, nhưng ở mức này thì gần như không có động lực để chuyển đổi
  • Tôi muốn kiểm tra xem cách dùng Redis được hiểu như sau có đúng không
    Ở v1, WAF và Redis nằm trên cùng một server; khi client thiết lập rule mới trong panel quản trị, rule đó được đưa vào Redis trên cùng server với panel quản trị, rồi nhờ cơ chế đồng bộ nội bộ của Redis, các Redis cục bộ bên cạnh WAF trên toàn thế giới được cập nhật rule — tôi muốn biết có phải cấu trúc là như vậy không. Sau đó, khi một request mới tới một WAF nào đó, WAF sẽ kiểm tra request/IP bằng các rule Redis đã được cập nhật — tôi muốn xác nhận luồng này
    Ở v2, có phải là loại bỏ cụm Redis, mỗi server WAF có một SQLite DB, tạo một cơ chế đồng bộ riêng để phát tán rule mới từ panel quản trị tới từng server WAF+SQLite, và khi request mới đến, WAF kiểm tra nhanh bằng các rule SQLite đã cập nhật không

  • Câu hay nhất là “SQLite không cạnh tranh với cơ sở dữ liệu client/server. SQLite cạnh tranh với fopen()