之前一直在思考如何實現限流器,最近看redis命令學習到了可以用redis來實現限流器的功能,簡單方便。
用redis來設置限流器,20秒鍾不超過10次,根據key取出value,如果value不存在則設置value自動加一(incr),然后設置超時時間(20);如果value存在並且小於10,則自增1(incr);如果value大於10則返回錯誤。
package main import ( "errors" "fmt" "net/http" "strconv" "strings" "github.com/garyburd/redigo/redis" ) var c redis.Conn func limiter(id string) (int64, error) { var sum int64 var err error val, _ := redis.String(c.Do("GET", id)) if val == "" { sum, err = redis.Int64(c.Do("INCR", id)) if err != nil { fmt.Println("---incr is failed, err: ", err) return 0, err } _, err = c.Do("EXPIRE", id, 20) if err != nil { fmt.Println("---err: ", err) return 0, err } } else { sum, err = strconv.ParseInt(val, 10, 0) if err != nil { fmt.Println("--atoi is failed, err: ", err) return 0, err } if sum > 10 { return 0, errors.New("sum is max.") } else { sum, err = redis.Int64(c.Do("INCR", id)) if err != nil { fmt.Println("---incr2 is failed, err: ", err) } } } return sum, nil } func restrictor(resp http.ResponseWriter, req *http.Request) { urls := strings.Split(req.URL.Path, "/") num, err := limiter(urls[2]) if err != nil { resp.Write([]byte(err.Error())) } resp.Write([]byte("num is " + strconv.Itoa(int(num)))) } func main() { var err error c, err = redis.Dial("tcp", "10.10.30.54:6379") if err != nil { fmt.Println("connect redis server is failed") return } http.HandleFunc("/restrictor/", restrictor) http.ListenAndServe(":9978", nil) }
鏈接上 Redis,在瀏覽器中輸入 http://localhost:9978/restrictor/{id}即可。根據不同用戶不同的id,來進行區分。
例:http://localhost:9978/restrictor/10102
會收到返回 num is 7