Heim Datenbank MySQL-Tutorial 通过Nginx/Lua给Redis的PIPELINING减肥

通过Nginx/Lua给Redis的PIPELINING减肥

Jun 07, 2016 pm 04:29 PM
lua nginx pipelining redis passieren

某手机应用市场项目,其中请求量最大的功能是查询升级接口,具体点来说:客户端会不定期的把手机中应用名称及其应用版本发送到服务端,服务端通过比较版本来判断客户端的应用是否需要升级,如果需要就返回若干项相关信息。通常,一台手机里会装几十个到上百

某手机应用市场项目,其中请求量最大的功能是查询升级接口,具体点来说:客户端会不定期的把手机中应用名称及其应用版本发送到服务端,服务端通过比较版本来判断客户端的应用是否需要升级,如果需要就返回若干项相关信息。通常,一台手机里会装几十个到上百个应用不等,当海量客户端一起请求时,服务端的压力可想而知。

客户端请求的数据格式如下所示,可以采用GET或POST方法:

packages=foo|1&packages=bar|2&packages=<name>|<version>&...</version></name>
Nach dem Login kopieren

服务端选择Lua作为编程语言,同时利用了Redis的PIPELINING机制批量查询数据:

local redis = require "resty.redis"
local cjson = require "cjson"
local config = require "config"
ngx.header["Content-Type"] = "application/json; charset=utf-8"
local args = ngx.req.get_uri_args(1000)
if ngx.var.request_method == "POST" then
    ngx.req.read_body()
    for key, val in pairs(ngx.req.get_post_args(1000)) do
        args[key] = val
    end
end
if type(args["packages"]) == "string" then
    args["packages"] = {args["packages"]}
end
if type(args["packages"]) ~= "table" then
    ngx.exit(ngx.HTTP_BAD_REQUEST)
end
local cache = redis.new()
local res, err = cache:connect(config.host, config.port)
if not res then
    ngx.log(ngx.ERR, "error: ", err)
    ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
end
cache:init_pipeline()
local packages = {}
for _, val in ipairs(args["packages"]) do
    if type(val) == "string" then
        local name, version = string.match(val, "([^|]+)|([0-9]+)")
        if name and version then
            packages[name] = tonumber(version)
            cache:hget(name, "all")
        end
    end
end
local res, err = cache:commit_pipeline()
if not res then
    ngx.log(ngx.ERR, "error: ", err)
    ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
end
local data = {}
for _, val in ipairs(res) do
    if type(val) == "string" then
        val = cjson.decode(val)
        if packages[val["name"]] 
<p>补充:应用的数据作为HASH保存在Redis里,不过由于HGETALL非常耗费CPU,所以做了些处理:冗余保存了一个名为「all」的字段,用来保存原始数据的JSON编码,如此一来,就把复杂度为O(N)的HGETALL操作转化成了复杂度为O(1)的HGET操作,从而提升了效率。详细介绍请参考:《记Redis那坑人的HGETALL》。</p>
<p>如上代码平稳运行了一段时间,但随着访问量的增加,开始暴露问题:Redis时不时出现卡住的现象,究其原因就是单线程的Redis无法承载过大的PIPELINING请求。通常我们都是采用多实例的方法来规避Redis单线程的性能瓶颈问题,但在本例中,由于PIPELING很大,不是随便冗余几个实例就能解决问题,同时系统也没有太多的内存可用。</p>
<p>最后我们想到的办法是利用Nginx/Lua给Redis的PIPELINING减肥,具体一点来说:当客户端查询升级接口时,虽然会把多至上百个应用的信息同时发送到服务端,但其中真正升级的应用却很少,如果我们能把那些不升级的应用过滤掉,只查询升级的应用,无疑将大大提升系统的性能,形象一点说:当一个胖子请求经过过滤后,就变成了一个瘦子请求。实际操作时,我们可以把应用的版本缓存到Nginx/Lua共享内存里,客户端请求先在Nginx/Lua共享内存过滤一次,然后再判断是否需要查询Redis。</p>
<p>为了使用共享内存,需要在Nginx配置文件中声明:</p>
<pre class="brush:php;toolbar:false">lua_shared_dict versions 100m;
Nach dem Login kopieren

改良后的代码如下所示,注意其中共享内存的查询和设置部分的代码:

local redis = require "resty.redis"
local cjson = require "cjson"
local config = require "config"
local versions = ngx.shared.versions;
ngx.header["Content-Type"] = "application/json; charset=utf-8"
local args = ngx.req.get_uri_args(1000)
if ngx.var.request_method == "POST" then
    ngx.req.read_body()
    for key, val in pairs(ngx.req.get_post_args(1000)) do
        args[key] = val
    end
end
if type(args["packages"]) == "string" then
    args["packages"] = {args["packages"]}
end
if type(args["packages"]) ~= "table" then
    ngx.exit(ngx.HTTP_BAD_REQUEST)
end
local cache = redis.new()
local res, err = cache:connect(config.host, config.port)
if not res then
    ngx.log(ngx.ERR, "error: ", err)
    ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
end
cache:init_pipeline()
local packages = {}
for _, val in ipairs(args["packages"]) do
    if type(val) == "string" then
        local name, version = string.match(val, "([^|]+)|([0-9]+)")
        if name and version then
            version = tonumber(version)
            if not versions[name] or versions[name] > version then
                packages[name] = version
                cache:hget(name, "all")
            end
        end
    end
end
local res, err = cache:commit_pipeline()
if not res then
    ngx.log(ngx.ERR, "error: ", err)
    ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
end
local data = {}
for _, val in ipairs(res) do
    if type(val) == "string" then
        val = cjson.decode(val)
        if packages[val["name"]] 
<p>或许会有人会质疑:本质上请求量并没有减少啊,只是从Redis转嫁到了Nginx而已,这样就能提升性能么?问题的关键在于Redis是单线程的,而Nginx通过worker_processes指令,可以充分发挥多核CPU的能力,所以性能总体是提升的。</p>
<p>补充:代码里在设置共享内存过期时间的时候,没有采用固定值,而是采用了一个随机数的方式,之所以这样设计,是为了避免大量数据同时过期,系统性能出现抖动。</p>
<p>…</p>
<p>当然,随着访问量的增加,本文的方案可能还会出现问题,到时候怎么办呢?其实类似查询升级之类的功能,就不应该设计成同步的形式,如果能改成异步的方式,那么多数问题就都不存在了,不过这个就不多言了,现在的方案刚刚好够用。</p>
    <p class="copyright">
        原文地址:通过Nginx/Lua给Redis的PIPELINING减肥, 感谢原作者分享。
    </p>
    
    


Nach dem Login kopieren
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

Video Face Swap

Video Face Swap

Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen

Java-Tutorial
1662
14
PHP-Tutorial
1262
29
C#-Tutorial
1235
24
So starten Sie einen Container von Docker So starten Sie einen Container von Docker Apr 15, 2025 pm 12:27 PM

Startschritte des Docker -Containers: Ziehen Sie das Containerbild: Führen Sie "Docker Pull [Mirror Name]" aus. Erstellen eines Containers: Verwenden Sie "Docker erstellen [Optionen] [Spiegelname] [Befehle und Parameter]". Starten Sie den Container: Führen Sie "Docker Start [Container Name oder ID]" aus. Containerstatus überprüfen: Stellen Sie sicher, dass der Container mit "Docker PS" ausgeführt wird.

So überprüfen Sie den Namen des Docker -Containers So überprüfen Sie den Namen des Docker -Containers Apr 15, 2025 pm 12:21 PM

Sie können den Namen des Docker -Containers abfragen, indem Sie den Schritten folgen: Alle Container auflisten (Docker PS). Filtern Sie die Containerliste (unter Verwendung des GREP -Befehls). Ruft den Containernamen ab (befindet sich in der Spalte "Namen").

So erstellen Sie Container für Docker So erstellen Sie Container für Docker Apr 15, 2025 pm 12:18 PM

Erstellen Sie einen Container in Docker: 1. Ziehen Sie das Bild: Docker Pull [Spiegelname] 2. Erstellen Sie einen Container: Docker Ausführen [Optionen] [Spiegelname] [Befehl] 3. Starten Sie den Container: Docker Start [Containername]

Wie verwendet ich die Redis -Cache -Lösung, um die Anforderungen der Produktranking -Liste effizient zu erkennen? Wie verwendet ich die Redis -Cache -Lösung, um die Anforderungen der Produktranking -Liste effizient zu erkennen? Apr 19, 2025 pm 11:36 PM

Wie erkennt die Redis -Caching -Lösung die Anforderungen der Produktranking -Liste? Während des Entwicklungsprozesses müssen wir uns häufig mit den Anforderungen der Ranglisten befassen, z. B. das Anzeigen eines ...

So installieren Sie Redis in CentOS7 So installieren Sie Redis in CentOS7 Apr 14, 2025 pm 08:21 PM

Laden Sie das Quellcodepaket von der offiziellen Redis -Quelle herunter, um es zu kompilieren und zu installieren, um die neueste und stabile Version zu gewährleisten, und kann auf personalisierte Weise angepasst werden. Die spezifischen Schritte sind wie folgt: Aktualisieren Sie die Liste der Softwarepakets und erstellen

So konfigurieren Sie langsame Abfragebogin in CentOS Redis So konfigurieren Sie langsame Abfragebogin in CentOS Redis Apr 14, 2025 pm 04:54 PM

Aktivieren Sie Redis langsame Abfrageprotokolle im CentOS -System, um die Leistungsdiagnoseeffizienz zu verbessern. In den folgenden Schritten führen Sie die Konfiguration durch: Schritt 1: Suchen und bearbeiten Sie die Redis -Konfigurationsdatei zuerst und suchen Sie die Redis -Konfigurationsdatei, die sich normalerweise in /etc/redis/redis.conf befindet. Öffnen Sie die Konfigurationsdatei mit dem folgenden Befehl: Sudovi/etc/redis/redis.conf Schritt 2: Passen Sie die Langsame-Abfrage-Protokollparameter in der Konfigurationsdatei an, suchen Sie die folgenden Parameter: #Slow Query-Schwellenwert (MS) Slow-Log-Slow-Than10000 #Maximum der Einträge für langsame Query-Log-Logog-Logog-Len-Len-Len

Wählen Sie zwischen Nginx und Apache: Die richtige Passform für Ihre Anforderungen Wählen Sie zwischen Nginx und Apache: Die richtige Passform für Ihre Anforderungen Apr 15, 2025 am 12:04 AM

Nginx und Apache haben ihre eigenen Vor- und Nachteile und eignen sich für verschiedene Szenarien. 1.Nginx ist für hohe Parallelitäts- und geringe Ressourcenverbrauchsszenarien geeignet. 2. Apache eignet sich für Szenarien, in denen komplexe Konfigurationen und reichhaltige Module erforderlich sind. Durch den Vergleich ihrer Kernfunktionen, Leistungsunterschiede und Best Practices können Sie die Serversoftware auswählen, die Ihren Anforderungen am besten entspricht.

Redis 'Rolle: Erforschung der Datenspeicher- und Verwaltungsfunktionen Redis 'Rolle: Erforschung der Datenspeicher- und Verwaltungsfunktionen Apr 22, 2025 am 12:10 AM

Redis spielt eine Schlüsselrolle bei der Datenspeicherung und -verwaltung und ist durch seine mehreren Datenstrukturen und Persistenzmechanismen zum Kern moderner Anwendungen geworden. 1) Redis unterstützt Datenstrukturen wie Zeichenfolgen, Listen, Sammlungen, geordnete Sammlungen und Hash -Tabellen und eignet sich für Cache und komplexe Geschäftslogik. 2) RDB und AOF sorgt durch zwei Persistenzmethoden für eine zuverlässige Speicherung und eine schnelle Wiederherstellung von Daten.

See all articles