Redis从入门到精通(十七)多级缓存(二)Lua语言入门、OpenResty集群的安装与使用
文章目录
- 前言
- 6.4 Lua语法入门
- 6.4.1 初识Lua
- 6.4.2 Hello World
- 6.4.3 变量
- 6.4.3.1 Lua的数据类型
- 6.4.3.2 声明变量
- 6.4.4 循环
- 6.4.5 函数
- 6.4.6 条件控制
- 6.5 实现多级缓存
- 6.5.1 安装和启动OpenResty
- 6.5.2 实现ajax请求反向代理至OpenResty集群
- 6.5.2.1 反向代理配置
- 6.5.2.2 OpenResty集群监听请求
前言
Redis多级缓存系列文章:
Redis从入门到精通(十六)多级缓存(一)Caffeine、JVM进程缓存
6.4 Lua语法入门
要进行业务Nginx编程,就需要用到Lua语言。Lua语言的官网地址是:https://www.lua.org/

6.4.1 初识Lua
进入Lua官网,可以看到官方对Lua语言的定义:
Lua is a powerful, efficient, lightweight, embeddable scripting language. It supports procedural programming, object-oriented programming, functional programming, data-driven programming, and data description.
Lua是一种强大、高效、轻量级、可嵌入的脚本语言。它支持过程式编程、面向对象编程、函数式编程、数据驱动编程和数据描述。
Lua是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
Lua经常嵌入到C语言开发的程序中,例如游戏开发、游戏插件等。Nginx本身也是C语言开发,因此也允许基于Lua做拓展。
6.4.2 Hello World
CentOS7系统默认已经安装了Lua语言环境,可以直接运行Lua代码。
在虚拟机任意目录下,新建一个hello.lua文件,内容如下:
print("Hello World")
执行lua hello.lua命令:

6.4.3 变量
6.4.3.1 Lua的数据类型
Lua支持的常见数据类型包括:

Lua提供了一个type()函数来判断一个变量的数据类型:

6.4.3.2 声明变量
Lua声明变量时无需指定数据类型,而是用local来声明变量为局部变量:
-- 声明字符串,可以用单引号或双引号
local str = 'hello'
-- 字符串拼接使用 ..
local str2 = 'hello' .. 'hello2'
-- 声明数字
local num = 21
-- 声明布尔类型
local falg = true
Lua的table类型类似于Java中的Map:
-- 声明table,类似Java中的Map
local map = {name = 'Jack', age = 21}
-- 通过key访问table
print(map['name'])
print(map.age)
Lua的table类型也可以作为数组来使用,只是此时的key为数组的角标,且从1开始:
-- 声明数组,key为角标
local arr = {'java', 'python', 'lua'}
-- 访问数组,从角标1开始
print(arr[1])
执行以上程序,结果为:
Jack
21
java
6.4.4 循环
对于table,可以利用for循环来遍历:
- 遍历数组
local arr = {'java', 'python', 'lua'}
-- for循环遍历数组
for index, value in ipairs(arr) doprint(index, value)
end
执行以上程序,结果为:
1 java
2 python
3 lua
- 遍历普通table
local map = {name = 'Jack', age = 21}
-- for循环遍历table
for key, value in pairs(map) doprint(key, value)
end
执行以上程序,结果为:
name Jack
age 21
6.4.5 函数
定义函数的语法:
function 函数名(argument1, argument2..., argumentn)-- 函数体return 返回值
end
例如,定义一个函数用于打印数组:
-- 定义函数:打印数组
function printArr(arr)for index, value in ipairs(arr) doprint(index, value)end
end
6.4.6 条件控制
条件控制的语法:
if(布尔表达式)
then--语句块
else--语句块
end
与Java不同的是,这里的布尔表达式是基于英文单词的,包括:and(逻辑与)、or(逻辑或)、not(逻辑非)。
例如,自定义一个函数,可以打印数组,当参数为nil时,打印错误信息:
function printArr2(arr)if not arrthenprint('数组为空!')elsefor index, value in ipairs(arr) doprint(index, value)endend
end
6.5 实现多级缓存
OpenResty是一个基于Nginx的高性能Web平台,用于方便地搭建能够处理超高并发、扩展性极高的动态Web应用、Web服务和动态网关。
其官网地址为:https://openresty.org/cn/

OpenResty具备下列特点:
- 具备Nginx的完整功能
- 基于Lua语言进行扩展,集成了大量精良的 Lua 库、第三方模块
- 允许使用Lua自定义业务逻辑、自定义库
6.5.1 安装和启动OpenResty
- 1)安装OpenResty依赖开发库
yum install -y pcre-devel openssl-devel gcc --skip-broken

- 2)安装OpenResty仓库
安装OpenResty仓库,便于未来安装或更新软件包(通过yum check-update命令):
yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo

如果提示命令不存在,则先运行yum install -y yum-utils先安装工具,在重复运行上面的命令。
- 3)安装OpenResty
yum install -y openresty

- 4)安装opm工具
opm是OpenResty的一个管理工具,用于安装第三方的Lua模块:
yum install -y openresty-opm

- 5)OpenResty目录结构
以上命令执行完毕后,OpenResty安装完成,其默认的目录是:/usr/local/openresty。

可以看到,OpenResty安装目录中有一个nginx文件夹,因此可以说OpenResty就是在Nginx的基础上继承了一些Lua模块。
- 6)配置Nginx环境变量
修改配置文件/etc/profile,在最下面添加以下内容:
export NGINX_HOME=/usr/local/openresty/nginx
export PATH=${NGINX_HOME}/sbin:$PATH
然后执行source /etc/profile命令让配置生效。
- 7)启动和运行OpenResty
修改Nginx配置文件(由于Nginx默认配置文件注释太多,影响编辑,所以可以将注释部分删掉,只保留需要的部分):
# /usr/local/openresty/nginx/conf/nginx.conf# user nobody;
worker_processes 1;
error_log logs/error.log;events {worker_connections 1024;
}http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;server {listen 8082;server_name localhost;location / {root html;index index.html index.htm;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}
}
OpenResty底层是基于Nginx的,它内部nginx目录和普通的Nginx的目录是一致的,所以启动方式也基本一致:
# 启动nginx(已配置环境变量)
nginx
# 重新加载配置
nginx -s reload
# 停止nginx
nginx -s stop
启动后,在浏览器访问:http://192.168.146.128:8082/,出现以下页面,说明OpenResty安装成功。

- 8)OpenResty集群模拟
可以在Nginx配置文件的http块下增加一个server,配置不同的端口,以模拟OpenResty集群:
# /usr/local/openresty/nginx/conf/nginx.confhttp {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;server {listen 8082;server_name localhost;location / {root html;index index.html index.htm;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}server {listen 8083;server_name localhost;location / {root html;index index.html index.htm;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}
}
执行nginx -s reload命令重启服务,此时8082端口和8083端口均可访问OpenResty的主页。
6.5.2 实现ajax请求反向代理至OpenResty集群
下面来梳理一下多级缓存的架构,如图:

如上图所示,在Windows上部署的Nginx用来做反向代理服务,将前端的查询商品信息的ajax请求代理到部署在虚拟机上的OpenResty集群;而OpenResty集群用来编写业务,按照Nginx本地缓存、Redis、Tomcat的顺序依次查询。
6.5.2.1 反向代理配置
修改Windows的反向代理Nginx服务的配置文件,将前端的ajax请求反向代理到OpenResty集群,如图:

6.5.2.2 OpenResty集群监听请求
OpenResty的很多功能都依赖于其目录下的Lua库,因此需要在nginx.conf中指定依赖库的目录,并导入依赖:
- 1)添加对OpenResty的Lua模块的加载
修改/usr/local/openresty/nginx/conf/nginx.conf文件,在其中的http块中,添加下面代码:
#lua 模块
lua_package_path "/usr/local/openresty/lualib/?.lua;;";
#c模块
lua_package_cpath "/usr/local/openresty/lualib/?.so;;";
- 2)监听
/api/item路径
修改/usr/local/openresty/nginx/conf/nginx.conf文件,在其中的server块中,添加对/api/item路径的监听:
location /api/item {# 默认的响应类型default_type application/json;# 响应结果由lua/item.lua文件来决定content_by_lua_file lua/item.lua;
}
- 3)编写item.lua文件
在/usr/local/openresty/nginx目录下创建文件夹lua,并在lua文件夹内创建新文件:item.lua

编写item.lua文件,暂时先返回假数据:
-- /usr/local/openresty/nginx/lua/item.luangx.say('{"id":1,"name":"SALSA AIR","title":"(集群中的)RIMOWA 21寸托运箱拉杆箱 SALSA AIR系列果绿色 820.70.36.4","price":17900,"image":"https://m.360buyimg.com/mobilecms/s720x720_jfs/t6934/364/1195375010/84676/e9f2c55f/597ece38N0ddcbc77.jpg!q70.jpg.webp","category":"拉杆箱","brand":"RIMOWA","spec":"","status":1,"createTime":"2019-04-30T16:00:00.000+00:00","updateTime":"2019-04-30T16:00:00.000+00:00","stock":2999,"sold":31290}')
- 4)重新加载配置,刷新页面
完整的nginx.conf配置文件内容如下:
# /usr/local/openresty/nginx/conf/nginx.conf
# user nobody;
worker_processes 1;
error_log logs/error.log;events {worker_connections 1024;
}http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;server {listen 8082;server_name localhost;location / {root html;index index.html index.htm;}location /api/item {# 默认的响应类型default_type application/json;# 响应结果由lua/item.lua文件来决定content_by_lua_file lua/item.lua;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}server {listen 8083;server_name localhost;location / {root html;index index.html index.htm;}location /api/item {# 默认的响应类型default_type application/json;# 响应结果由lua/item.lua文件来决定content_by_lua_file lua/item.lua;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}# lua模块lua_package_path "/usr/local/openresty/lualib/?.lua;;";# c模块 lua_package_cpath "/usr/local/openresty/lualib/?.so;;";
}
执行以下命令重新加载配置文件:
nginx -s reload
浏览器刷新页面:

可见,页面确实从OpenResty集群拿到了数据。
…
本节完,下一节继续进行多级缓存的实现。
本节所涉及的代码和资源可从git仓库下载:https://gitee.com/weidag/redis_learning.git
更多内容请查阅分类专栏:Redis从入门到精通
感兴趣的读者还可以查阅我的另外几个专栏:
- SpringBoot源码解读与原理分析(已完结)
- MyBatis3源码深度解析(已完结)
- 再探Java为面试赋能(持续更新中…)
相关文章:
Redis从入门到精通(十七)多级缓存(二)Lua语言入门、OpenResty集群的安装与使用
文章目录 前言6.4 Lua语法入门6.4.1 初识Lua6.4.2 Hello World6.4.3 变量6.4.3.1 Lua的数据类型6.4.3.2 声明变量 6.4.4 循环6.4.5 函数6.4.6 条件控制 6.5 实现多级缓存6.5.1 安装和启动OpenResty6.5.2 实现ajax请求反向代理至OpenResty集群6.5.2.1 反向代理配置6.5.2.2 OpenR…...
pytest常用钩子函数
1、什么叫钩子函数 在Pytest框架中,钩子函数是一种允许用户扩展或者自定义测试执行过程的机制。钩子函数允许用户在测试的不同阶段插入自定义的代码,以实现特定的行为,操作或处理。这种插入式的机制使得Pytest具有高度的灵活性和扩展性。 如…...
.Net <% %>
<% %> 语法 : <% import namespace"system.data"%> 用来导入后台命名空间 指令用于指定当页和用户控件编译器处理 ASP.NET Web 窗体页 (.aspx) 和用户控件 (.ascx) 文件时所使用的设置。<% %> 语法 : <% name %> <% getstr() %&g…...
【C语言__编译和链接__复习篇2】
目录 前言 一、翻译环境和运行环境 二、翻译环境 2.1 预处理 2.1 编译 2.1.1 词法分析 2.1.2 语法分析 2.1.3 语义分析 2.2 汇编 2.3 链接 三、运行环境 四、简答主线问题 前言 本篇主要讨论以下问题: 主线问题: 1. 源文件(.c)如何转换成(.exe)文件…...
Jmeter —— 自动录制脚本
1、Jmeter配置 1.1新增一个线程组 1.2Jmeter中添加HTTP代理 1.3配置HTTP代理服务器 修改端口 修改Target Cintroller(目标控制器) 修改Grouping(分组) 编辑录制中的包含和排除 在“URL Patterns to include包含模式”中填入.*(123456).*用以过滤请求地址中不包含123456的请求…...
使用python互相转换AVI、MP4、GIF格式视频文件
一、AVI文件转MP4文件 要将AVI格式的视频转换为 MP4,你可以使用 Python的 moviepy 库。以下是一个示例代码,用于将 AVI 文件转换为 MP4 文件: from moviepy.editor import VideoFileClip# 读取 AVI 文件 clip VideoFileClip("input.a…...
11 Php学习:函数
PHP 内建函数Array 函数 PHP Array 函数是 PHP 核心的组成部分。无需安装即可使用这些函数。 创建 PHP 函数 当您需要在 PHP 中封装一段可重复使用的代码块时,可以使用函数。下面详细解释如何创建 PHP 函数并举例说明。 创建 PHP 函数的语法 PHP 函数的基…...
查询电脑用户名和组信息
在命令行里查看电脑名: c:\>hostname 在命令行里,查看组信息: # 显示本地所有的用户组 c:\>net localgroup #显示administrators组包含的用户信息 c:\>net localgroup administrators # 比如我的显示信息: C:\>ne…...
【Godot4.2】CanvasItem绘图函数全解析 - 9.绘制表格
概述 之前介绍TextLine和TextParagraph的时候,提到了用制表符和设定列宽形式来绘制简易表格,但是很明显,单纯使用此种方式很难获得对表格的精确控制。 所以对于表格绘制问题,我决定单独开坑,单独深入研究。 目前比较…...
部署HDFS集群(完全分布式模式、hadoop用户控制集群、hadoop-3.3.4+安装包)
目录 前置 一、上传&解压 (一 )上传 (二)解压 二、修改配置文件 (一)配置workers文件 (二)配置hadoop-env.sh文件 (三)配置core-site.xml文件 &…...
TCP协议简单总结
TCP:传输控制协议 特点:面向连接、可靠通信 TCP的最终目的:要保证在不可靠的信道上实现可靠的传输 TCP主要有三个步骤实现可靠传输:三次握手建立连接,传输数据进行确认,四次挥手断开连接 三次握手建立可靠…...
【Qt 实现录音】
Qt 实现录音源代码: #include <QAudioInput> #include <QAudioDeviceInfo> #include <QAudioRecorder> #include <QFile> #include...
python:算法竞赛入门之一
计算 斐波那契数列(Fibonacci sequence),不受长整型位数限制。 编写 fibonacci.py 如下 # -*- coding: utf-8 -*- """ 计算 斐波那契数列(Fibonacci sequence)""" import sys from …...
【大数据与云计算】虚拟机安装Linux
前言:使用Linux系统对大数据学习必不可少,本文主要介绍虚拟机安装linux的流程 文章目录 一、 下载VMware二、下载Linux三、安装Linux 一、 下载VMware 官网链接 下载VMware-player,一直下一步安装即可。 二、下载Linux 点击链接直接下载&…...
从零开始编写一个cmake构建脚本
简介 本文档介绍cmake构建脚本编写,包含的一些主要元素和命名规范。 cmake构建脚本编写步骤 cmake构建工具版本要明确 # 命令名字要小写,这条语句要求构建工具至少需要版本为3.12或以上 cmake_minimum_required (VERSION 3.12)工程名及库的版本号明确…...
pringboot2集成swagger2出现guava的FluentIterable方法不存在
错误信息 Description: An attempt was made to call a method that does not exist. The attempt was made from the following location: springfox.documentation.spring.web.scanners.ApiListingScanner.scan(ApiListingScanner.java:117) The following method did not ex…...
进程线程的关系
举个例子 滑稽老师吃100只鸡 如何加快滑稽老师吃鸡的效率?? 有一个方案,搞两个房间,两个滑稽老师 一个滑稽吃50只鸡,速度一定会大幅度增加 多进程的方案 创建新的进程 就需要申请更多的资源(房间和…...
一些 VLP 下游任务的相关探索
目录 一、Image-Text Retrieval (ITR , 图像文本检索) 任务目的: 数据集格式 训练流程 evaluation流程 实际使用推测猜想 二、Visual Question Answering (VQA , 视觉问答) 任务目的 数据集格式 训练流程 demo以及评估流…...
【opencv】示例-pca.cpp PCA图像重建演示
// 加载必要的头文件 #include <iostream> // 用于标准输入输出流 #include <fstream> // 用于文件的输入输出 #include <sstream> // 用于字符串的输入输出流操作#include <opencv2/core.hpp> // OpenCV核心功能的头文件 #include "o…...
C语言中的编译和链接
系列文章目录 文章目录 编辑 系列文章目录 文章目录 前言 一、 翻译环境和运行环境 二、 翻译环境 2.1 编译 2.1.1 预处理 2.1.2 编译 2.1.2.1 词法分析 : 2.1.2.2 语法分析 2.1.2.3 语义分析 2.1.3 汇编 2.2 链接 三、运行环境 前言 在我们平常的写代码时,我们很…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...
数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)
名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 原创笔记:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 上一篇:《数据结构第4章 数组和广义表》…...
Vue 3 + WebSocket 实战:公司通知实时推送功能详解
📢 Vue 3 WebSocket 实战:公司通知实时推送功能详解 📌 收藏 点赞 关注,项目中要用到推送功能时就不怕找不到了! 实时通知是企业系统中常见的功能,比如:管理员发布通知后,所有用户…...
