【图解秒杀系列】秒杀技术点——静态化

【图解秒杀系列】秒杀技术点------静态化

什么是静态化、静态化的作用

静态化就是指通过某种静态化技术,将原本需要动态渲染生成的HTML页面固定下来变成一个静态页面文件,后续请求该页面都直接返回该静态页面。

首先要有模板和数据,然后根据给定的模板和数据,通过模板引擎,就能生成对应的静态HTML文件。

生成的静态HTML页面,可以推到Nginx上缓存到Nginx本地。当用户请求访问对应的页面时,Nginx直接返回缓存在本地的静态页面,这样响应速度就大大提升。

在秒杀场景中,商品详情页就可以进行静态化处理,提升商品详情页的访问速度。

如何实现静态化

FreeMarker、Thymleaf

一种方式是通过FreeMarker、Thymleaf这种Java语言的模板引擎实现。

处理流程

FreeMarker、Thymleaf需要跑在一个Tomcat进程里面,当接收到请求时,通过Freemarker、Thymleaf等模板引擎技术,根据指定的模板和数据,生成静态HTML页面,返回客户端。

另外,我们可以监听MQ上的修改操作消息,当监听到有修改操作发生时,就在异步工程里面使用模板引擎生成静态HTML页面,然后推到Nginx上缓存到Nginx本地。

问题

但是这种方案会有几个问题。

首先第一个问题是,如果我们修改了模板,那么使用该模板生成的静态HTML页面全部都要删除或刷新。

第二个问题是如果我们有多个Nginx,则要同时推送给多个Nginx。

如果是多Nginx场景下,碰上批量刷新,那这个操作就很复杂了。

OpenResty + Lua

为了解决上面的问题,就有了一个更好的解决方案,那就是OpenResty加Lua脚本。

OpenResty是基于Nginx进行二次开发的Web平台,支持执行Lua脚本,并且内部集成了许多Lua库和第三方模块。

lua_shared_dict & lua-resty-template

在这个方案下,我们用到OpenResty的两个重要的东西,一个是"lua_shared_dict"指令、lua-resty-template模块。

lua_shared_dict用于声明一个共享内存区域,可以将其作为缓存空间使用,比如"lua_shared_dict my_cache 128m;"表示声明一个128m大小名为"my_cache"的内存共享区域。

而lua-resty-template模块的作用就是一个模板引擎,它的作用与FreeMarker或者Thymleaf类似,只是它是跑在OpenResty内部而不是后端服务。

处理流程

那么此时处理流程如下:

  1. 客户端的请求被OpenResty接收
  2. OpenResty在location块中通过content_by_lua_file命令指定执行的lua脚本
  3. lua脚本被执行,首先判断lua_shared_dict命令声明的缓存空间中是否缓存了对应的数据
  4. 如果缓存命中,则直接通过lua-resty-template模块进行模板渲染生成静态html文件并返回
  5. 如果缓存不命中,则请求后端服务获取对应数据,再缓存到lua_shared_dict命令声明的缓存空间中,然后再进行模板渲染生成静态html文件并返回

这么做的好处就是:

  • 即使模板变了,我们只需要更新OpenResty上的模板即可,由于最终的html文件是由OpenResty动态渲染生成的,所以只要更新了模板,生成的html就会更新。
  • 由于是OpenResty自己通过模板渲染生成的html,而不是后端服务生成的,因此不再需要推送ng的这一步操作。

具体操作

在nginx.conf文http模块中加入:

bash 复制代码
lua_package_path '../lualib/?.lua;;';
lua_package_cpath '../lualib/?.so;;';
include lua.conf;

lua.conf:

bash 复制代码
lua_shared_dict my_cache 128m;
server {
	listen 222;
	set $template_location "/templates";
	set $template_root "D:/ProgramData/nginx/";
	
	location /product {
		default_type 'text/html;charset=UTF‐8';
		lua_code_cache on;
		content_by_lua_file D:/ProgramData/nginx/product.lua;
	}
}

product.lua:

lua 复制代码
	local uri_args = ngx.req.get_uri_args()
	local productId = uri_args["productId"]
	local cache_ngx = ngx.shared.my_cache
	local productCacheKey = "product_info_"..productId
	local productCache = cache_ngx:get(productCacheKey)
	if productCache == "" or productCache == nil then
		local http = require("resty.http")
		local httpc = http.new()
		local resp, err = httpc:request_uri("http://127.0.0.1:8866",{
			method = "GET",
			path = "/pms/productInfo/"..productId
		})
		productCache = resp.body
		local expireTime = math.random(600,1200)
		cache_ngx:set(productCacheKey, productCache, expireTime)
	end
	local cjson = require("cjson")
	local productCacheJSON =cjson.decode(productCache)
	ngx.say(productCache);
	local context = {
		id = productCacheJSON.data.id,
		name = productCacheJSON.data.name,
		price = productCacheJSON.data.price,
		pic = productCacheJSON.data.pic,
		detailHtml = productCacheJSON.data.detailHtml
	}
	local template = require("resty.template")
	template.render("product.html", context)

html模板:

html 复制代码
<html>
	<head>
		<meta http‐equiv="Content‐Type" content="text/html; charset=utf‐8" />
	</head>
	<body>
		<h1>
			商品id: {* id *}<br/>
			商品名称: {* name *}<br/>
			商品价格: {* price *}<br/>
			商品库存: <img src={* pic *}/><br/>
			商品描述: {* detailHtml *}<br/>
		</h1>
	</body>
</html>
相关推荐
AIMath~4 分钟前
雪花算法+ZooKeeper解决方案+RPC是什么
分布式·zookeeper·云原生
C澒9 分钟前
IntelliPro 产研协作平台:基于 AI Agent 的低代码智能化配置方案设计与实现
前端·低代码·ai编程
KmSH8umpK10 分钟前
Redis分布式锁从原生手写到Redisson高阶落地,附线上死锁复盘优化方案进阶第六篇
数据库·redis·分布式
一袋米扛几楼9819 分钟前
【Git】规范化协作:详解 GitHub 工作流中的 Issue、Branch 与 Pull Request 最佳实践
前端·git·github·issue
直奔標竿25 分钟前
Java开发者AI转型第二十五课!Spring AI 个人知识库实战(四)——RAG来源追溯落地,拒绝AI幻觉
java·开发语言·人工智能·spring boot·后端·spring
嘟嘟MD26 分钟前
程序员副业 | 2026年4月复盘
后端·创业
网络点点滴32 分钟前
前端与后端的区别与联系
前端
时空系33 分钟前
认识Rust——我的第一个程序 Rust中文编程
开发语言·后端·rust
EnCi Zheng1 小时前
M5-markconv自定义CSS样式指南 [特殊字符]
前端·css·python
DevilSeagull1 小时前
Windows 批处理 (Batch) 编程: 从入门到入土. (一) 基础概念与环境配置
开发语言·windows·后端·batch·语言