天天看點

nginx 程式實作分布式限流

作者:埋頭苦幹的小碼農

#大有學問#

Nginx 是一個高性能的 Web 伺服器和反向代理伺服器,可以用于實作分布式限流。分布式限流是指在多台伺服器上進行流量限制,以保證整個系統的穩定性和可用性。下面将介紹如何在 Nginx 中實作分布式限流。

使用 ngx_http_limit_req_module 子產品

Nginx 内置了 ngx_http_limit_req_module 子產品,可以用于實作基于請求速率的限流。但是,這個子產品僅限于單台 Nginx 伺服器上的限流。為了實作分布式限流,我們需要将限流狀态在多台伺服器之間共享。

使用 Redis 實作狀态共享

為了在多台 Nginx 伺服器之間共享限流狀态,可以使用 Redis 作為分布式存儲。我們需要借助第三方子產品 ngx_http_redis 和 Nginx 的 Lua 子產品(如 OpenResty)來實作與 Redis 的互動。

以下是一個簡單的示例配置,用于實作基于 IP 的分布式限流:

http {
    # 加載 Lua 子產品和 Redis 子產品
    include /path/to/ngx_http_lua_module.so;
    include /path/to/ngx_http_redis_module.so;

    # 設定 Redis 連接配接參數
    upstream redis_backend {
        server redis-server-ip:redis-server-port;
        keepalive 1024;
    }

    server {
        listen 80;

        location / {
            # 使用 access_by_lua_block 運作 Lua 代碼
            access_by_lua_block {
                local redis = require "resty.redis"
                local red = redis:new()

                -- 連接配接 Redis
                local ok, err = red:connect("redis_backend")
                if not ok then
                    ngx.log(ngx.ERR, "Failed to connect to Redis: ", err)
                    return ngx.exit(500)
                end

                -- 擷取用戶端 IP
                local client_ip = ngx.var.remote_addr

                -- 設定限流參數
                local limit_key = "limit:" .. client_ip
                local limit_rate = 10   -- 每秒請求限制
                local limit_burst = 20  -- 最大突發請求限制

                -- 使用 Redis INCRBY 和 EXPIRE 實作限流
                local current, err = red:incrby(limit_key, 1)
                if tonumber(current) == 1 then
                    red:expire(limit_key, math.ceil(1 / limit_rate))
                end

                -- 判斷是否超過限流門檻值
                if tonumber(current) > limit_burst then
                    return ngx.exit(429)
                end
            }

            # 其他正常配置
            proxy_pass http://backend;
        }
    }
}
           

這個示例配置使用 Redis 記錄每個 IP 的請求計數,并在請求計數超過限流門檻值時傳回 429(Too Many Requests)狀态碼。通過這種方式,可以在多台 Nginx 伺服器之間實作分布式限流。

需要注意的是,這僅是一個基本示例,實際應用中需要根據具體需求進行調整和優化。例如,可以使用更複雜的限流政策,如基于使用者身份、API 路徑等實作不同級别的限流。此外,還需要考慮 Redis 伺服器的性能、高可用性和安全性等因素。

以下是一些建議和注意事項,以幫助您更好地實施分布式限流:

  1. 限流粒度:根據實際需求選擇合适的限流粒度。例如,可以根據用戶端 IP、使用者身份(如使用者 ID 或 API 密鑰)或 API 路徑進行限流。
  2. 限流算法:可以根據業務需求選擇合适的限流算法。例如,可以使用令牌桶(Token Bucket)或漏桶(Leaky Bucket)算法實作平滑限流,避免流量突發對系統造成沖擊。
  3. Redis 高可用性:為確定分布式限流的穩定性,需要關注 Redis 伺服器的高可用性。可以使用 Redis Sentinel 或 Redis Cluster 等技術實作 Redis 高可用叢集。
  4. 性能優化:在實作分布式限流時,需要關注性能和延遲。可以使用連接配接池、Lua 協程等技術減小連接配接 Redis 時的開銷。另外,可以考慮使用緩存或者局部限流降低對 Redis 的依賴。
  5. 安全性:為保證 Redis 伺服器的安全,應設定通路控制、認證機制以及資料加密等安全措施。此外,需要定期對 Redis 伺服器進行安全掃描和漏洞修複。
  6. 監控和告警:建立一套完善的監控和告警系統,實時關注分布式限流的運作狀态。例如,可以監控 Nginx 伺服器的限流日志,以及 Redis 伺服器的性能名額和錯誤日志。

以上方法和建議,您可以在 Nginx 中實作分布式限流,進而保證整個系統的穩定性和可用性。在實際應用中,需要根據具體場景和需求進行調整和優化,以實作更高效和靈活的分布式限流方案。

繼續閱讀