Giới thiệu
Giới hạn tốc độ (Rate Limiting) là một kỹ thuật quan trọng trong phát triển API, cho phép chúng ta kiểm soát số lượng yêu cầu mà một người dùng hoặc máy khách có thể gửi đến API trong một khoảng thời gian nhất định. Kỹ thuật này rất cần thiết để bảo đảm công bằng khi sử dụng API, tăng cường bảo mật, và bảo vệ tài nguyên của máy chủ khỏi việc quá tải.
Bài viết này sẽ hướng dẫn chi tiết cách xây dựng một máy chủ HTTP đơn giản với Golang và framework Gin, đồng thời áp dụng chức năng giới hạn tốc độ cho một endpoint thông qua Redis.
Tại sao cần giới hạn tốc độ API?
Khi làm việc với các API công cộng, chúng ta có thể gặp phải thông báo như "vượt quá giới hạn tốc độ" khi liên tục gửi yêu cầu. Việc giới hạn tốc độ API giúp:
- Đảm bảo sự công bằng trong việc sử dụng tài nguyên API.
- Bảo vệ API khỏi các cuộc tấn công như DDoS.
- Tăng cường khả năng bảo mật và ổn định cho hệ thống.
Điều kiện tiên quyết
Trước khi bắt đầu, bạn cần:
- Có kiến thức cơ bản về Golang, Gin, và Redis.
- Có sẵn một instance Redis (có thể sử dụng Docker hoặc máy từ xa).
Bắt đầu xây dựng máy chủ HTTP
Để khởi tạo dự án Golang, bạn cần chạy lệnh sau:
bash
go mod init <đường dẫn github>
Tiếp theo, chúng ta sẽ tạo một máy chủ HTTP đơn giản sử dụng framework Gin. Dưới đây là đoạn mã nguồn mẫu:
go
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/message", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Bạn có thể gửi thêm yêu cầu.",
})
})
r.Run(":8081") // lắng nghe và phục vụ trên localhost:8081
}
Chạy máy chủ bằng lệnh go run main.go
. Bạn sẽ thấy thông báo trên terminal và có thể truy cập endpoint trên trình duyệt thông qua địa chỉ localhost:8081/message
.
Thiết lập giới hạn tốc độ cho endpoint
Để thiết lập chức năng giới hạn tốc độ, chúng ta sẽ sử dụng gói go-redis/redis_rate
. Gói này giúp chúng ta không cần phải lập trình lại logic kiểm tra giới hạn từ đầu.
Dưới đây là đoạn mã hoàn chỉnh đã tích hợp chức năng giới hạn tốc độ:
go
package main
import (
"context"
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/go-redis/redis_rate/v10"
"github.com/redis/go-redis/v9"
)
func main() {
r := gin.Default()
r.GET("/message", func(c *gin.Context) {
err := rateLimiter(c.ClientIP())
if err != nil {
c.JSON(http.StatusTooManyRequests, gin.H{
"message": "Bạn đã vượt quá giới hạn, vui lòng thử lại sau.",
})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "Bạn có thể gửi thêm yêu cầu.",
})
})
r.Run(":8081")
}
func rateLimiter(clientIP string) error {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
limiter := redis_rate.NewLimiter(rdb)
res, err := limiter.Allow(ctx, clientIP, redis_rate.PerMinute(10))
if err != nil {
panic(err)
}
if res.Remaining == 0 {
return errors.New("Rate")
}
return nil
}
Trong mã này:
- Hàm
rateLimiter
chấp nhận địa chỉ IP của client và trả về lỗi nếu đạt giới hạn. Nếu không, nó sẽ trả về giá trị nil. - Chúng ta sử dụng địa chỉ IP như một khóa duy nhất để lưu trữ số lượng yêu cầu trong Redis.
- Mức giới hạn được thiết lập là 10 yêu cầu mỗi phút, nhưng có thể điều chỉnh theo nhu cầu của bạn.
Hoạt động của máy chủ
Khi máy chủ đang chạy, bạn có thể làm mới trang localhost:8081/message
và thử gửi nhiều yêu cầu. Nếu số lượng yêu cầu vượt quá 10 trong một phút, bạn sẽ nhận được thông báo lỗi với mã 429.
Kết luận
Bài viết này đã hướng dẫn bạn cách xây dựng một API với giới hạn tốc độ sử dụng Golang và Redis. Hy vọng rằng những thông tin này hữu ích và giúp ích cho quá trình phát triển API của bạn! Hãy thực hành và áp dụng những kiến thức vừa học vào các dự án thực tế nhé!
source: viblo