1. 高并发的设计思路
简单理解为服务器能抗住多少用户访问量。
普通笔记本支持100个并发量,很明显学校的访问都扛不住。 大量用户访问时,数据库压力过大容易崩溃,考虑中间做一个redis缓存,读完数据库的数据写入redis一份,下次不用读到数据库,降低数据库的压力。
redis也有问题。微服务部署到tomcat并发量也就200,不能支持大量用户同时访问,所以配置到nginx上,好点的并发10w。
nginx也有缺陷,只能部署点静态html,不支持jsp,用OpenResty,动态读取redis的数据。
OpenResty 简单理解成 就相当于封装了nginx,并且集成了LUA脚本,开发人员只需要简单的其提供了模块就可以实现相关的逻辑,而不再像之前,还需要在nginx中自己编写lua的脚本,再进行调用了。
总的来说:
并发量100,直接用数据库。
并发量1w,用redis给数据库做缓存。
并发量10w,可以用nginx给redis做缓存。
并发量100w,可以多买几台nginx服务器,一台10w并发。
2.Lua脚本的简单用法
1.注解
2.定义变量
全局变量,默认的情况下,定义一个变量都是全局变量,
局部变量(方法里面的变量) 需要声明为local.例如:
3.数据类型
4.流程控制
if语句
if(布尔表达式)
then
--[ 在布尔表达式为 true 时执行的语句 --]
end
--[ { } 的作用]
while循环
while(条件)
do
statements
end
3.OpenResty的安装
OpenResty 简单理解成 就相当于封装了nginx,并且集成了LUA脚本,开发人员只需要简单的其提供了模块就可以实现相关的逻辑,而不再像之前,还需要在nginx中自己编写lua的脚本,再进行调用了。
1.安装
1.添加仓库执行命令
yum install yum-utils
yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
2.执行安装
yum install openresty -y
3.安装成功后 会在默认的目录如下:
/usr/local/openresty
进去看
配置Nginx的权限,默认是支持静态语言,要结合Lua.
进入并nginx配置文件。
保存,退出。
再启动nginx,启动openResty,就是启动nginx.
启动成功:
一定要在nginx的/sbin目录下操作。
4.如何把数据库的数据写到redis缓存?
创建/root/lua目录,在该目录下创建update_content.lua: 目的就是连接mysql 查询数据 并存储到redis中。
建立lua脚本
把他下载到本地,放在idea编辑,idea有插件可以用。也可以直接在虚拟机配置。
编辑lua脚本。
数据在数据库,先连数据库读数据。根据自己的参数来,要区分本地和虚拟机上的。
使用连接参数,建立连接。
准备一条sql,id拼接= …categoryid。
执行sql,进行查询,把查询结果赋给连接。
关闭数据库连接。
读到数据后,把数据写到缓存。
写完关闭redis连接,提示写入成功,写完以后上传服务器就行。
建一个redis容器。
在/usr/local/openresty/nginx/conf/nginx.conf中配置如下:
绑定lua脚本,然后重启nginx。
测试:
5.在redis中读数据,显示到网页上面。
再建一个读的lua脚本。
再配置一下nginx配置文件,重启nginx。
测试:
6.配置nginx本地缓存
就是给redis做缓存用的。
逻辑:获取nginx的本地缓存,先从本地缓存读数据,如果没读到就去redis读。redis没数据就连接数据库读,读到的数据写入redis,再写入nginx。
lua脚本:
--- 设置nginx响应头数据类型
ngx.header.content_type="application/json;charset=utf8"
--获取请求中的参数ID
local uri_args = ngx.req.get_uri_args();
local id = uri_args["id"];
--获取nginx本地缓存
local cache_ngx = ngx.shared.dis_cache;
--尝试从ngnx缓存读取广告轮播图数据
local contentCache=cache_ngx:get('content_cache_'..id)
--判断从nginx缓存是否读取到内容
if contentCache ==nil or contentCache == ''
then
-- 从redis读取缓存数据
-- 引入redis类库
local redis=require('resty.redis')
-- 创建redis连接对象
local red=redis:new()
--设置连接超时时间
red:set_timeout(30000)
--建立连接
local ok,error=red:connect('192.168.188.150',6379)
--根据指定key去redis读取数据
local response_context=red:get('content_'..id)
--判断从redis是否读取到广告轮播图的数据
if ngx.null == response_context
then
-- 从数据库读取数据库
local mysql=require('resty.mysql')
-- 创建数据库对象
local db= mysql:new()
-- 设置数据库连接属性
local props={
host="192.168.188.1",
port=3306,
database="dongyimai-db",
user="root",
password="root"
}
-- 设置连接超时时间
db:set_timeout(40000)
-- 和mysql数据库建立连接
local res=db:connect(props);
-- 定义sql语句
local sql="SELECT * FROM tb_content WHERE STATUS='1' AND category_id="..id
--执行sql查询
res=db:query(sql)
-- ngx.say('form mysql----')
--引入json的类库
local cjson=require('cjson')
--把读取到数据转换为json对象,存储到redis
local response_json= cjson.encode(res)
red:set('content_'..id,response_json)
--关闭redis连接
red:close()
--写入到nginx缓存一份 缓存有效期 单位是秒
cache_ngx:set('content_cache_'..id,response_json,60)
--响应给nginx展示用户
ngx.say(response_json)
--关闭数据库连接
db:close()
else
-- 如果redis缓存存在数据写入数据到nginx缓存
cache_ngx:set('content_cache_'..id,response_context,60)
-- 响应nginx给浏览器
ngx.say(response_context)
-- ngx.say('form redis cache----')
end
else
-- 从nginx缓存能够读取到数据
--直接把读取到数据响应给浏览器
ngx.say(contentCache)
-- ngx.say('form nginx cache----')
end
绑定脚本,重启nginx。重复的,不写咯。
本地缓存默认未开启,设置内存:
lua_shared_dict dis_cache 1000m;
结果:
7.nginx限流
7.1 生活中限流对比
-
水坝泄洪,通过闸口限制洪水流量(控制流量速度)。
-
办理银行业务:所有人先领号,各窗口叫号处理。每个窗口处理速度根据客户具体业务而定,所有人排队等待叫号即可。若快下班时,告知客户明日再来(拒绝流量)
-
火车站排队买票安检,通过排队 的方式依次放入。(缓存带处理任务)
7.2 nginx的限流
nginx提供两种限流的方式:
- 一是控制速率
- 二是控制并发连接数
控制速率
(1)漏桶算法实现控制速率限流
漏桶(Leaky Bucket)算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率.示意图如下:
nginx的配置
配置示意图如下:
修改/usr/local/openresty/nginx/conf/nginx.conf:
```lua
user root root;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#cache
lua_shared_dict dis_cache 128m;
#限流设置
limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=2r/s;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
location /update_content {
content_by_lua_file /root/lua/update_content.lua;
}
location /read_content {
#使用限流配置
limit_req zone=contentRateLimit;
content_by_lua_file /root/lua/read_content.lua;
}
}
}
重启:
访问页面:http://192.168.188.128/read_content?id=1
,连续刷新会直接报错。