多级缓存解决微服务高并发

多级缓存的使用场景

大多数网站首页都有轮播图,轮播图数据一般需要通过后台接口获得,当并发量较大时会给服务器带来压力。一般的解决方案是将轮播图数据缓存到Redis中,这样就能减少对数据库的访问。我们访问Redis也需要使用Java,Java项目部署在Tomcat中,Tomcat服务器也会面对并发量大的压力。Nginx服务器的并发性能要远远高于Tomcat,在Nginx中使用Lua脚本就能实现MySQL和Redis的读写,绕过Tomcat,大大提高首页的并发性能。

优化方案

问题1:首页广告轮播图接口多,轮播图接口需要连接后台数据库,访问导致页面响应较慢

 

第一轮优化:

因为轮播图比较少更新,可以使用Redis缓存,通过Tomcat来访问  

 

问题2:

  Tomcat在高并发情况下性能不高,Nginx服务器的并发性能大大优于Tomcat,如何利用Nginx访问Redis,提升响应速度和并发性能

 第二轮优化: 通过OpenResty整合Lua脚本访问Redis,直接将数据返回给前端页面

 Lua

简介 

Lua 是由巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组于1993年开发的一种轻量、小巧的脚本语言,用标准 C 语言编写,其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

Lua的特性

  • 轻量级: 它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。

  • 可扩展: Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。

  • 其它特性:

    • 支持面向过程(procedure-oriented)编程和函数式编程(functional programming);

    • 自动内存管理;只提供了一种通用类型的表(table),用它可以实现数组,哈希表,集合,对象;

    • 语言内置模式匹配;闭包(closure);函数也可以看做一个值;提供多线程(协同进程,并非操作系统所支持的线程)支持;

    • 通过闭包和table可以很方便地支持面向对象编程所需要的一些关键机制,比如数据抽象,虚函数,继承和重载等。

官网:The Programming Language Lua

安装 

 

Windows安装

下载地址:Releases · rjpcomputing/luaforwindows · GitHub

Linux安装

curl -R -O http://www.lua.org/ftp/lua-5.3.0.tar.gz
tar zxf lua-5.3.0.tar.gz
cd lua-5.3.0
make linux test
make install

安装IDE

Elicpse插件:Lua Development Tools, an IDE for the Lua programming language

Idea插件:在plugins菜单中搜索 EmmyLua,安装重启

 语法

2.3.1 Helloworld

print("Hello Lua")

2.3.2 注释

-- 单行注释
-- [[
多行注释
-- ]]

2.3.3 数据类型

Lua的数据类型有:

  • number 只有double类型,占4字节

  • string 单引号和双引号括起来

  • boolean 包含true、false,nil也算false

  • 空 nil

2.3.4 变量

包含全局变量和局部变量

-- 全局变量
num = 10;
print("num="..num)
-- 局部变量
local name = false;
-- 使用type获得数据类型
local myType = type(name)
print("type="..myType)

2.3.5 IF-ELSE

-- if-else
local age = 14;
local gender = "male";
if age >= 18 and gender == "female" then
    print("女大十八变");
elseif age >= 18 and gender == "male" then
    print("男大十八变");
else
    print("小毛孩子");
end

2.3.6 WHILE循环

-- while循环
local i = 0
while i <= 100 do
    print("i = "..i);
    i = i + 1;
end

2.3.7 FOR循环

for 变量初始化,结束值,递增值

-- for循环
for i = 0,100,1 do
    print("i = "..i);
end

2.3.8 函数

基本函数

-- 定义函数
function sum(n1,n2)
    return n1 + n2;
end
local result = sum(22,33);
print(result);

Lua的函数可以返回多个结果

-- 返回多个结果
function getNumbers()
    return 11,22,33;
end
local n1,n2,n3 = getNumbers();
print(n1,n2,n3);
​

闭包机制,函数也可以看做值

function func()
    local num = 0;
    -- 匿名函数
    return function()
        num = num + 2;
        return num;
    end
end
local foo = func();
print(foo())
print(foo())
print(foo())
​

2.3.9 数组

Lua的数组可以包含多种数据类型,甚至函数

下标是从1开始的

-- 数组
arr = {"haha", 100, "hehe",function() print("hoho") return 99 end}
print(arr[1],arr[2],arr[3],arr[4]())
​

使用for-in可以遍历下标和值

for k,v in pairs(arr) do
    print(k,v)
end
​

2.3.10 面向对象

Lua支持面向对象的语法

-- 定义对象属性
local person = {id = 1,name = "张三",age = 20};
print(person.id,person.name,person.age);
-- 定义对象方法
function person.sayHi()
    print("我是"..person.name.."年龄"..person.age);
end
person.sayHi();
​

OpenResty服务器

 简介

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

OpenResty通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。

OpenResty的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。

安装 

Centos为例

预编译安装

yum install yum-utils
yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
yum install openresty

源码编译安装

1. 下载源码包 http://openresty.org/cn/download.html
2. 解压后,进入目录执行配置命令
    ./configure
    make && make install
3. 执行编译命令后,出现目录/usr/local/openresty

使用入门

1. 修改/etc/profile,配置nginx环境变量
   PATH=/usr/local/openresty/nginx/sbin:$PATH
   export PATH
2. 使profile生效
   source /etc/profile
3. 启动nginx
   nginx
4. 修改配置文件/usr/local/openresty/nginx/conf/nginx.conf
   server {
           listen 8080;
           location / {
               default_type text/html;
               content_by_lua_block {
                   ngx.say("<p>hello, world</p>")
               }
           }
       }
5. 重启nginx
   nginx -s reload
6. 测试,显示hello, world
   curl http://localhost:8080 

 使用进阶

 

3.4.1 引入lua脚本

在conf目录中新建lua/hello.lua

ngx.say("<h1>Hello Lua!!</h1>")

修改nginx.conf

server {
        listen 8080;
        location /lua {
            default_type text/html;
            content_by_lua_file conf/lua/hello.lua;
        }
    }

3.4.2 获得URI中的单个变量

修改hello.lua

ngx.say(ngx.var.arg_a)

arg_a能获得参数a的值

http://192.168.7.188:8080/lua?a=zhangsan

3.4.3 获得URI中的所有变量

修改hello.lua

local uri_args = ngx.req.get_uri_args()  
for k, v in pairs(uri_args) do  
    if type(v) == "table" then  
        ngx.say(k, " : ", table.concat(v, ", "), "<br/>")  
    else  
        ngx.say(k, ": ", v, "<br/>")  
    end  
end

可以在网页输出所有参数列表

http://192.168.7.188:8080/lua?a=22&b=33&c=88

3.4.4 获得请求头信息

local headers = ngx.req.get_headers()                         
ngx.say("Host : ", headers["Host"], "<br/>")  
ngx.say("user-agent : ", headers["user-agent"], "<br/>")  
ngx.say("user-agent : ", headers.user_agent, "<br/>")
for k,v in pairs(headers) do  
    if type(v) == "table" then  
        ngx.say(k, " : ", table.concat(v, ","), "<br/>")  
    else  
        ngx.say(k, " : ", v, "<br/>")  
    end  
end  

3.4.5 获得POST请求的参数

ngx.req.read_body()  
ngx.say("post args begin", "<br/>")  
local post_args = ngx.req.get_post_args()  
for k, v in pairs(post_args) do  
    if type(v) == "table" then  
        ngx.say(k, " : ", table.concat(v, ", "), "<br/>")  
    else  
        ngx.say(k, ": ", v, "<br/>")  
    end  
end

3.4.6 获得其他内容

http协议版本

ngx.say("ngx.req.http_version : ", ngx.req.http_version(), "<br/>")

请求方法

ngx.say("ngx.req.get_method : ", ngx.req.get_method(), "<br/>")  

原始的请求头内容

ngx.say("ngx.req.raw_header : ",  ngx.req.raw_header(), "<br/>")  

body内容体

ngx.say("ngx.req.get_body_data() : ", ngx.req.get_body_data(), "<br/>")

3.5 MySQL操作

3.5.1 连接MySQL数据库

在OpenResty服务器中使用Lua脚本连接MySQL

-- 引用mysql模块
local mysql = require "resty.mysql"
-- 获得数据库对象
local db = mysql:new()
-- 设置超时
db:set_timeout(1000)
-- 连接数据库 ok是正常结果,err是错误结果
local ok, err = db:connect{
    host = "IP",
    port = 端口,
    database = "数据库名",
    user = "账号",
    password = "密码",
    charset = "utf8"
}
if not ok then
    ngx.say("连接失败", err)
    return
end
ngx.say("连接成功")

3.5.2 执行查询语句

在OpenResty服务器中使用Lua脚本对表进行查询

-- 执行查询 res是查询结果
local res, err = db:query("查询语句")
if not res then
    ngx.say("查询错误 ", err)
    return
end
db:close()
-- 将查询结果转换为json 
local cjson = require "cjson"
ngx.say(cjson.encode(res))

3.6 Redis操作

3.6.1 连接Redis

在OpenResty服务器中使用Lua脚本连接Redis

local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(2000)
local ok,err = red:connect("127.0.0.1",6379)
if not ok then
    ngx.say("connect error: ", err)
    return
end

3.6.2 执行Redis命令

在OpenResty服务器中使用Lua脚本读写Redis数据

red:set("键",值)
local value = red:get("键")
red:close()

 

总结

本次课程我们了解了使用OpenResty和Lua脚本对广告轮播图接口优化的业务流程,然后学习了Lua脚本语言和OpenResty服务器的基本使用,最后使用Lua语言实现了MySQL和Redis数据的查询,完成了接口优化业务的技术储备,后面我们将使用这些技术实现接口优化业务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值