Memcached是一个高性能的K-V键值对缓存,其设计的目的就是为了减少与数据库的交互,保存静态数据信息,与Redis的区别。
前言
在设计商品详情页时,由于信息加载较多,需要考虑加载时间、性能问题。说白了既要保证用户体验,下单流程的完整性,又要尽量减少与数据库的交互。而这部分数据偏静态,这部分数据可以做后台渲染和缓存。我们将详情页按照业务模块和性质拆分成多个子链接访问,这里以商品信息展示(名称、价格、折扣等)为例进行说明。
总结一下我们要做的一件事:后端渲染,减少与数据库的访问,以提高页面打开速度。
文件树
Memcached
这里用的memcached的windows版本,里面也包含了启动教程,不再做过多的解释。
Nginx
首先看Nginx的配置文件
server{
listen 8888;
server_name localhost;
lua_code_cache on;
location /memcached {
root lua;
content_by_lua_file '../openresty-1.13.6.1-win32/lua/memcached.lua';
}
}
将发送到下面的请求映射到memcached.lua文件
http://localhost:8888/memcached
lua
lua一共做了两件事:memcached交互和后端渲染
下面看lua文件的逻辑
local memcached = require "resty.memcached"
--创建memcached实例
local memc, err = memcached:new()
if not memc then
ngx.say("failed to instantiate memc: ", err)
return
end
--设置请求超时时间
memc:set_timeout(1000) -- 1 sec
--创建连接
local ok, err = memc:connect("127.0.0.1", 11211)
if not ok then
ngx.say("failed to connect: ", err)
return
end
--根据传入的productId做为键
local res, flags, err = memc:get("key_demo")
if err then
ngx.say("failed to get key_demo: ", err)
return
end
if not res then
ngx.say("key_demonot found")
return
end
ngx.say("key_demo: ", res)
--memcached尽量设置长连接,减少3次握手的时间
local ok, err = memc:set_keepalive(10000, 100)
if not ok then
ngx.say("cannot set keepalive: ", err)
return
end
以上是创建lua与memcached连接的几个过程,下面根据思路来依次介绍整个流程。
获取url的传参
args=ngx.req.get_uri_args()
local key = args["productId"]
获取数据
给服务端发送http请求获取数据库数据(第一次访问时,memcached中并没有数据)
local http = require "resty.http"
local httpc = http.new()
local cjon=require "cjson"
local url= ""
local res,err = httpc.request_uri(url,{method="GET",path="/api/product?productId="..key})
local result
if not res then
ngx.log(ngx.WARN,'failed to request',err)
return
else
result =cjson.decode(res.body)
数据渲染
将json数据渲染到html中,首先创建html模版productdetail.html。css略,但是貌似css只能用style标签和html写在一起。
<div>
<table>
<tr>
<th>商品名称</th>
<th>{{product.ProductName}}</th>
</tr>
<tr>
<th>商品价格</th>
<th>{{product.ProductPrice}}</th>
</tr>
<tr>
<th>商品折扣率</th>
<th>{{product.ProductRate}}</th>
</tr>
</table>
</div>
模版写完后,如果没配置路径,和lua文件放到同一级下。
渲染方式,接上面的,result是返回的json反序列化串。
local template = require "resty.template"
local context = {prodct=result}
local func = template.compile("productdetail.html")
local content = func(context)
这时候content里存出的是渲染后的html代码,可以把这段代码直接输出给前端。
代码
memcached.lua
local memcached = require "resty.memcached"
local cjon=require "cjson"
args=ngx.req.get_uri_args()
local key = args["productId"]
--创建memcached实例
local memc, err = memcached:new()
if not memc then
ngx.say("failed to instantiate memc: ", err)
return
end
--设置请求超时时间
memc:set_timeout(1000) -- 1 sec
--创建连接
local ok, err = memc:connect("127.0.0.1", 11211)
if not ok then
ngx.say("failed to connect: ", err)
return
end
--设置长连接
local ok ,err = memc:set_keepalive(10000,100)
if not ok then
ngx.say("failed to keepalive", err)
return
end
--根据传入的productId做为键
local res, flags, err = memc:get(key)
if not res then
--从数据库拿数据
local template = require "resty.template"
local http = require "resty.http"
local httpc = http.new()
local cjon=require "cjson"
local url= ""
local res,err = httpc.request_uri(url,{method="GET",path="/api/product?productId="..key})
local result
if not res then
ngx.log(ngx.WARN,'failed to request',err)
return
else
result =cjson.decode(res.body)
end
local context = {prodct=result}
local func = template.compile("productdetail.html")
local content = func(context)
local ok, err = memc:set(key,content)
if not ok then
ngx.say("failed to insert to memcached")
return
end
ngx.say(content)
end
--从缓存读
ngx.say(res)
productdetail.html代码
<div>
<table>
<tr>
<th>商品名称</th>
<th>{{product.ProductName}}</th>
</tr>
<tr>
<th>商品价格</th>
<th>{{product.ProductPrice}}</th>
</tr>
<tr>
<th>商品折扣率</th>
<th>{{product.ProductRate}}</th>
</tr>
</table>
</div>
nginx配置
worker_processes 1;
events{
worker_connections 1024;
}
http {
lua_package_path "../openresty-1.13.6.1-win32/lua/?.lua;../openresty-1.13.6.1-win32/lualib/?.lua"
server{
listen 8888;
server_name localhost;
lua_code_cache on;
location /memcached {
root lua;
content_by_lua_file '../openresty-1.13.6.1-win32/lua/memcached.lua';
}
}
Memcached连接
telnet 127.0.0.1 11211
可以查看内存分块,他这里叫chunk。使用情况。
效果
第一次读库,接口520ms
第二次访问,从memcacahed中读,72ms