0
点赞
收藏
分享

微信扫一扫

高并发的设计思路和部署,看完入门直接装逼。

花海书香 2022-04-01 阅读 11

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 ,连续刷新会直接报错。

请添加图片描述

举报

相关推荐

0 条评论