Tôi đã triển khai tính năng rate/limit cho bình luận như thế nào?

Tôi đã triển khai tính năng rate/limit cho bình luận như thế nào?

Tin ngắn hàng ngày dành cho bạn
  • Từ lâu rồi suy nghĩ làm thế nào để tăng sự hiện diện thương hiệu, cũng như người dùng cho blog. Nghĩ đi nghĩ lại thì chỉ có cách chia sẻ lên mạng xã hội hoặc trông chờ họ tìm kiếm, cho đến khi...

    In cái áo này được cái tắc đường khỏi phải lăn tăn, càng đông càng vui vì hàng trăm con mắt nhìn thấy cơ mà 🤓

    (Có tác dụng thật nha 🤭)

    » Xem thêm
  • Một vòng của sự phát triển nhiều dự án khá là thú vị. Tóm tắt lại trong 3 bước: Thấy một cái gì đó phức tạp -> Làm cho nó đơn giản đi -> Thêm thắt tính năng cho đến khi nó phức tạp... -> Quay trở lại vòng lặp mới.

    Tại sao lại như vậy? Để mình lấy 2 ví dụ cho các bạn thấy.

    Markdown ra đời với mục tiêu tạo ra một định dạng văn bản thô "dễ viết, dễ đọc, dễ dàng chuyển thành một dạng gì đó như HTML". Vì thời đó chẳng ai đủ kiên nhẫn mà vừa ngồi viết vừa thêm định dạng cho văn bản hiển thị ở trên web như thế nào. Ấy vậy mà giờ đây người ta đang "nhồi nhét" hoặc tạo ra các biến thể dựa trên markdown để bổ sung thêm nhiều định dạng mới đến mức... chẳng nhớ nổi hết cú pháp.

    React cũng là một ví dụ. Từ thời PHP, việc khát khao tạo ra một cái gì đó tách biệt hẳn giao diện người dùng và phần xử lý logic chính của ứng dụng thành 2 phần riêng biệt cho dễ đọc, dễ viết. Kết quả là các thư viện UI/UX phát triển rất mạnh mẽ, mang lại khả năng tương tác với người dùng rất tốt, còn phần logic ứng dụng thì nằm ở một máy chủ riêng biệt. Bộ đôi Front-end, Back-end cũng từ đấy mà thịnh hành, không thể thiếu anh bồi bàn REST API. Ấy vậy mà giờ đây React trông cũng không khác biệt gì so với PHP là mấy, kéo theo là cả Vue, Svelte... lại cùng quy tất cả về một mối.

    Cơ mà không phải vòng lặp là xấu, ngược lại vòng lặp này mang tính tiến hoá nhiều hơn là "cải lùi". Nhiều khi lại tạo ra được cái hay hơi cái cũ thế là người ta lại dựa trên cái hay đó để tiếp tục lặp. Nói cách khác là chắc lọc tinh hoa từng tí một tí một á 😁

    » Xem thêm
  • Song song với các dự án chính thức thì thi thoảng mình vẫn thấy các dự án "bên lề" nhằm tối ưu hoặc cải tiến ngôn ngữ theo khía cạnh nào đó. Ví dụ nature-lang/nature là một dự án hướng tới cải tiến Go, mang lại một số thay đổi nhằm giúp cho việc sử dụng Go trở nên thân thiện hơn.

    Nhìn lại mới thấy hao hao JavaScript 😆

    » Xem thêm

Vấn đề

Captcha là một cách thức được sinh ra nhằm mục đích ngăn chặn hành vi spam trên các ứng dụng, đặc biệt là đối với ứng dụng web. Nếu không có captcha, kẻ tấn công có thể dễ dàng tạo ra những đoạn mã tự động gửi truy vấn với tần suất liên tục đến chức năng nào đó nhằm phá hoại hệ thống.

Tuy vậy, captcha không phải không có nhược điểm. Có lẽ hạn chế lớn nhất của nó là gây "lú" cho người dùng. Nhiều đoạn mã được sinh ra để xác minh bạn là con người, nhưng đôi khi bạn phải tự hỏi liệu mình có là người không khi không thể dịch được những kí tự méo mó hoặc mờ tịt kia.

Chức năng bình luận trên 2coffee không sử dụng captcha để tạo ra khó khăn cho người dùng giống như trên. Thay vào đó tôi đã áp dụng một kỹ thuật gọi là "rate/limit" để hạn chế hành vi spam. Nói nôm na, nó ngăn chặn một hành vi liên tục, giới hạn số lần thực hiện trong một khoảng thời gian nhất định. Ví dụ như chỉ cho phép người dùng bình luận tối đa 3 lần trong 1 phút, hay cần phải chờ ít nhất 10 giây để cho lượt gửi bình luận tiếp theo.

Bài viết ngày hôm nay tôi xin phép được tường thuật lại quá trình triển khai tính năng rate/limit của mình. Tôi nghĩ rằng điều đó sẽ giúp ích cho bạn đọc, hoặc hy vọng được nhận lại ý kiến của bạn đọc để có thêm cách triển khai tốt hơn.

Thuật toán

Ý tưởng ban đầu rất đơn giản, vì không quá khắt khe nên tôi quyết định cho phép người dùng được gửi bình luận sau mỗi 10 giây kể từ lần gửi thành công trước đó. Sau khi gửi bình luận thành công ở một bài viết thì cần chờ tối thiểu 10 giây để gửi bình luận ở bất kỳ bài nào.

Lúc này cần triển khai được thuật toán có đầu vào là id người dùng, đầu ra là true/false. True nếu chưa vượt quá limit và false nếu đã bình luận quá nhiều. Dựa vào đó để cho phép họ gửi được hay không.

Có nhiều cách để giải quyết vấn đề này, đơn giản nhất là cứ mỗi lần bình luận sẽ lấy ra bình luận cuối cùng của họ rồi kiểm tra thời gian xem có hợp lệ. Cách này thì triển khai nhanh, đơn giản nhưng nếu sau này bình luận nhiều lên thì truy vấn có phần chậm chạp. Hơn nữa việc mở rộng sau này có phần phức tạp hơn. Ví dụ như thay đổi thuật toán để cho phép họ gửi tối đa 3 bình luận trong thời gian một phút chẳng hạn. Lúc đó truy vấn sẽ phức tạp và nhiều khả năng sẽ chậm hơn.

Vì đang sử dụng Redis, tôi có thêm một cách là tận dụng chức năng khóa hết hạn (ttl) của một key trong Redis. Tôi sẽ tạo ra một key có dạng "comment_limit:" chứa một giá trị boolean có thời gian hết hạn là khoảng thời gian giữa các lần bình luận liên tiếp. Mỗi khi bình luận, chỉ cần kiểm tra key "comment_limit:" có tồn tại hay không, nếu có thì chắc chắn là họ không được phép bình luận và ngược lại.

Ưu điểm của cách này là thời gian kiểm tra điều kiện tương đối nhanh, chỉ mất một truy vấn lấy ra key "comment_limit:". Tuy vậy, cần phải viết nhiều mã hơn để xử lý logic.

Triển khai

Triển khai rất đơn giản, bạn cần có máy chủ Redis để tạo ra các key có ttl. Mỗi khi gọi hàm tạo bình luận thì kiểm tra xem đã có key "comment_limit:" chưa.

Ví dụ trong trường hợp user_id của tôi bằng 1:

GET comment_limit:1

Nếu comment_limit:1 trả về true hãy bắn ra một lỗi không được phép bình luận. Ngược lại nếu là null thì cho phép thêm bình luận rồi sau đó thêm một key comment_limit:1 với thời gian hết hạn là thời gian bạn thiết lập. Giả sử là 10 giây:

SET comment_limit:1 true EX 10

Khi đó, cứ sau 10 giây thì comment_limit:1 sẽ tự động bị xóa và trả lại logic được phép bình luận cho người dùng.

Tổng kết

Có nhiều cách để triển khai thuật toán rate/limit cho phần bình luận. Tôi đang áp dụng cách sử dụng tính năng key tự động xóa kết hợp với việc quy ước tên của key để tạo ra logic kiểm tra tính khả dụng của hoạt động bình luận. Còn bạn có cách nào khác hãy để lại bình luận cho mọi người biết nhé!

Cao cấp
Hello

Bí mật ngăn xếp của Blog

Là một lập trình viên, bạn có tò mò về bí mật công nghệ hay những khoản nợ kỹ thuật về trang blog này? Tất cả bí mật sẽ được bật mí ngay bài viết dưới đây. Còn chờ đợi gì nữa, hãy bấm vào ngay!

Là một lập trình viên, bạn có tò mò về bí mật công nghệ hay những khoản nợ kỹ thuật về trang blog này? Tất cả bí mật sẽ được bật mí ngay bài viết dưới đây. Còn chờ đợi gì nữa, hãy bấm vào ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.

Bình luận (0)

Nội dung bình luận...