在javashop电商系统中像买家端首页、商品详情页、店铺首页等这类页面有两个共同的特点,即访问量大,数据不常变动。对于这类页面,为了减轻前端服务器的压力,javashop将这些页面缓存到了Redis中,当用户访问这些页面时,服务器会通过OpenResty代理执行lua脚本访问Redis中缓存的静态页面信息。接下来,我们来详细的讲解下整个流程中所涉及到的技术点。
1、缓存静态页
缓存静态页的过程在javashop中是通过httpClient抓取前端服务器中的静态页内容放到redis中。
1)抓取静态页信息
private String getHTML(String url, String type, int times) throws IOException { String html; // socket超时 connect超时 RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(50000) .setConnectTimeout(50000) .build(); CloseableHttpClient httpClient =HttpClients.custom().setDefaultRequestConfig(requestConfig).build(); HttpGet httpGet = new HttpGet(url); httpGet.setHeader("Client-Type", type); CloseableHttpResponse response = httpClient.execute(httpGet); int status = response.getStatusLine().getStatusCode(); if (status != 200) { html = EntityUtils.toString(response.getEntity(), "utf-8"); debugger.log("生成静态页出错:静态页渲染服务返回" + status, "uri:" + url); debugger.log(html); if (times >= 4) { return ("create error ,return code is :" + status + ",url is :" + url); } else { times++; debugger.log(times + "次重试..."); //重试时等待时间,在一段时间后重试 防止出现429(Too much connections in one mintue)问题 try { Thread.sleep(times * 1000); } catch (InterruptedException e) { logger.debug(e.getMessage()); } html = getHTML(url, type, times); return html; } } else { if (times > 0) { debugger.log("重试成功"); } html = EntityUtils.toString(response.getEntity(), "utf-8"); } return html; }
2)存入redis
//生成消息 String url = getUrl(path, type); //通过http 来获取html存储redis String html = this.getHTML(url, type); stringRedisTemplate.opsForValue().set(name, html);
2、访问静态页
OpenResty? 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
OpenResty官网地址:http://openresty.org/cn/
下面我们着重介绍一下OpenResty是如何通过lua脚本访问redis的,以PC端静态页为例。
1)首先我们准备好访问redis的lua脚本,代码如下
单机版:single_connector.lua
local request_uri = ngx.var.uri local redis = require "resty.redis" local red = redis:new() --red:set_timeout(10000) -- 1 sec local ok, err = red:connect("ip", port) if not ok then ngx.say("failed to connect: ", err) return end --如果设置了密码请打开注释,并填写密码 --local res, err = red:auth("password") -- if not res then -- ngx.say("failed to authenticate: ", err) -- return --end local res, err = red:get(request_uri) -- 请修改https://www.test.com 为实际配置域名或IP端口 if res == ngx.null then ngx.redirect("https://www.test.com/404.html") return end if not res then ngx.say("failed to get: " .. request_uri , err) return end red:set_keepalive(6000,1000) ngx.say(res)
集群版:cluster_connector.lua
local request_uri = ngx.var.uri local config = { name = "testCluster", --rediscluster name -- enableSlaveRead = true, serv_list = { --redis cluster node list(host and port), { ip = "ip", port = port }, { ip = "ip", port = port } }, keepalive_timeout = 60000, --redis connection pool idle timeout keepalive_cons = 300, --redis connection pool size connection_timout = 15000, --timeout while connecting max_redirection = 5 --maximum retry attempts for redirection } local redis_cluster = require "resty.rediscluster" local red_c = redis_cluster:new(config) -- 请修改https://www.test.com 为实际配置域名或IP端口 local v, err = red_c:get(request_uri) if v == ngx.null then ngx.redirect("https://www.test.com/404.html") return end if err then ngx.log(ngx.ERR, "err: ", err) else ngx.say(v) end
注意:
redis配置注释掉bind 127.0.0.1、设置protected-mode 为no;否则通过lua连接redis出错
2)在OpenResty中配置server路径
#新建静态页输出节点,content_by_lua_file为lua脚本实际路径。 server { listen 80; server_name localhost; #pc端静态响应 location /PC { default_type text/html; content_by_lua_file "/usr/local/openresty/nginx/conf/lua/single_connector.lua"; #redis集群请使用此配置 #content_by_lua_file "/usr/local/openresty/nginx/conf/lua/cluster_connector.lua"; } }
原文:https://www.cnblogs.com/javashop-docs/p/13737920.html