暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

OpenResty+Lua+Redis+MQ实现高QPS下热点数据的存取方案

龙虾编程 2024-05-06
227

    京东、淘宝首页每天的访问量是非常的大,如果不对首页上的一些热点数据做技术上的处理就会出现首页的访问速度慢,甚至在高并发下无法打开首页,这些都会严重的影响用户的体验。首页常见的热点数据是轮播图,下图是京东和淘宝首页的轮播图:

    每个用户打开京东、淘宝网站的首页都会出现这个轮播图,由于平台是国内知名的购物平台,所以其QPS是非常高的;另外这个轮播图也是可以做更改和替换来达到展示不同的图片的效果。如果不做好应对措施那么在高并发下就会出现读取速度慢,甚至击垮后端的服务器。

    针对这个场景,我们使用OpenResty+Lua+Redis+MQ实现一套支持高QPS的热点数据缓存和读取的方案。

1、技术点—— OpenResty

    OpenResty是一个基于Nginx与Lua的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。OpenResty足以胜任 10K-1000K以上单机并发连接。

    这里就不介绍OpenResty的具体搭建过程,给大家展示一张搭建OpenResty成功之后访问首页的效果图:

    OpenResty利用Nginx的负载均衡功能,将请求分发到不同的Lua进程中,从而提高系统的并发处理能力。Lua和Redis这里就不再做介绍了。

2、热点数据的存取方案设计

2.1 热点数据的发布

    运营人员发布热点数据(如网站首页的轮播图的配置),首先将热点数据同步到Mysql中,然后热点数据发送一条添加或者修改消息到MQ中(如Kafka、RocketMQ等),通过MQ来同步Redis中数据一致性。通过MQ同步热点数据到Redis中会存在一定的延迟,但是针对首页轮播图业务场景来讲是可以忽略的(因为只是做展示而已,不会影响实际的业务),但是如果想要低延迟我们可以采用Canal来监听Mysql的binlog方案来实现,这里就不具体的展开了。

2.2 热点数据的读取过程

    用户通过客户端访问数据的时候,请求先到达OpenResty上(单机支持10K-1000K并发连接),由于OpenResty是基于Nginx实现的,所以OpenResty可以通过内部的location配置来执行预先配置的Lua脚本,执行Lua脚本的时候我们的逻辑如下:

(1)先读Redis集群,判断是否有需要的数据,如果Redis中存在需要的数据就直接返回数据给客户端。

(2)如果在Redis中没有获取到数据,Lua会连接Mysql获取需要的数据,数据读取到之后同步一份数据到Redis集群中,最后返回数据到客户端。

2.3  整体热点数据发布和存取的流程

Lua脚本的代码

    ngx.header.content_type="application/json;charset=utf8"
    local uri_args = ngx.req.get_uri_args();
    local id = uri_args["id"];
    local cache_ngx = ngx.shared.dis_cache;
    local hotCache = cache_ngx:get('hot_cache_'..id);
    ngx.say(hotCache)
    if hotCache == "" or hotCache == nil then
    local redis = require("resty.redis");
    local red = redis:new()
    red:set_timeout(2000)
    red:connect("192.168.223.134", 6379)
    local rescontent=red:get("content_"..id);


    if ngx.null == rescontent then
    local cjson = require("cjson");
    local mysql = require("resty.mysql");
    local db = mysql:new();
    db:set_timeout(2000)
            local props = {
    host = "192.168.223.132",
    port = 3306,
                database = "test",
    user = "root",
    password = "123456"
    }
    local res = db:connect(props);
    local select_sql = "select * from tb_hot where id="..id.." order by created";
    res = db:query(select_sql);
    local responsejson = cjson.encode(res);
    red:set("content_"..id,responsejson);
    ngx.say(responsejson);
    db:close()
    else
            cache_ngx:set('hot_cache_'..id, rescontent, 10*60);
    ngx.say(rescontent)
    end
    red:close()
    else
    ngx.say(contentCache)
    end

    总结:

        高并发下热点的数据的存取本文采用OpenResty+Lua+Redis的方案,方案的实现难度小,可用性高,支持几十万甚至百万的QPS。

    文章转载自龙虾编程,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论