package main
import (
"fmt"
"net"
"net/http"
"sync"
"time"
)
type Counter struct {
mu sync.Mutex
count int
timestamp time.Time
}
func NewCounter() *Counter {
return &Counter{
count: 0,
timestamp: time.Now(),
}
}
func (c *Counter) Inc() {
c.mu.Lock()
defer c.mu.Unlock()
now := time.Now()
if now.Sub(c.timestamp) > time.Second {
c.count = 1
c.timestamp = now
} else {
c.count++
}
}
func (c *Counter) Count() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.count
}
func main() {
counter := NewCounter()
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/index" && r.Method == "GET" {
if counter.Count() >= 10 {
http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
return
}
counter.Inc()
}
fmt.Fprintf(w, "Hello, world!")
})
listener, err := net.Listen("tcp", "localhost:8080")
if err != nil {
fmt.Println("Error listening:", err)
return
}
defer listener.Close()
fmt.Println("Listening on localhost:8080...")
http.Serve(listener, nil)
}
当然实际生产场景中考虑因素远远比这个复杂的多,只是用作简单原理展示
在本文示例代码中,我们使用Go语言实现了一个简单的限流算法——令牌桶算法,并将其应用于HTTP请求服务器的/index GET接口上。具体地,我们定义了一个Counter结构体来记录当前请求计数和时间戳,使用NewCounter函数初始化一个Counter对象,并实现了Inc方法来增加计数器的值,并根据时间戳判断是否需要重置计数器的值。同时,我们还定义了一个处理函数,使用http.HandleFunc函数来为HTTP请求注册处理函数。在处理函数中,我们对请求路径和请求方法进行判断,仅对/index GET请求进行限流,限流阈值为10。最后,我们使用net.Listen函数创建一个listener对象,并使用http.Serve函数启动HTTP服务器,监听在localhost:8080地址上。
需要注意的是,本示例代码中的计数器算法仅是一种简单的实现,并未考虑实际应用中可能遇到的更多因素,如计数器的重置策略、限流阈值的动态调整、高并发等问题。在实际应用中,我们需要结合具体的业务场景和需求,采用更加严谨和完善的限流算法来保证服务的可靠性和稳定性。同时,我们还需要关注算法的性能和并发安全等问题,以确保其正确性和可维护性。