服务搭建


安装apisix

安装依赖

# install epel, `luarocks` need it.
wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
sudo rpm -ivh epel-release-latest-7.noarch.rpm

# install etcd
wget https://github.com/etcd-io/etcd/releases/download/v3.4.13/etcd-v3.4.13-linux-amd64.tar.gz
tar -xvf etcd-v3.4.13-linux-amd64.tar.gz && \
    cd etcd-v3.4.13-linux-amd64 && \
    sudo cp -a etcd etcdctl /usr/bin/

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

# install OpenResty and some compilation tools
sudo yum install -y openresty curl git gcc luarocks lua-devel

# start etcd server
nohup etcd &

安装apisix

sudo yum install -y https://github.com/apache/apisix/releases/download/2.2/apisix-2.2-0.x86_64.rpm

安装好户输入 apisix 即可得到版本号

修改配置文件

安装好的apisix在user/local/apisix目录下

安装好后测试一下是否有效

curl "http://127.0.0.1:9080/apisix/admin/services/" -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1'

我们修改一下配置文件,让apisix可以公网访问

修改文件格式如下

apisix:
  allow_admin:                  # http://nginx.org/en/docs/http/ngx_http_access_module.html#allow
    - 0.0.0.0/0
  admin_key:
    -
      name: "admin"
      key: edd1c9f034335f136f87ad84b625c8f2 # using fixed API token has security risk, please
      # update it when you deploy to production environment
      role: admin

plugins:
  - echo
  - xiaoyou

然后重新apisix apisix restart

我们使用apifox来访问测试,可以看到,外网可以访问了

配置插件

自己新建一个插件文件,可以建在plugins文件夹下面 我这里取名为 xiaoyou.lua

插件内容如下

local core = require("apisix.core")
local roundrobin  = require("resty.roundrobin")
local limit_conn = require("resty.limit.conn")
local sleep = core.sleep -- 延迟的
local ngx = ngx
-- 全局状态
local status = {}
-- 设置权重的函数

-- 用于统计等待队列里面的请求数量
local lim, err = limit_conn.new("my_limit_conn",5, 1000, 2)
if not lim then
    core.log.error(core.json.encode(err))
end

local setWeight

--设置定时任务,定时设置权重,这里设置的是定时10s
setWeight = function()
    ngx.timer.at(10, setWeight)
    -- 先计算每个节点的权重
    CalculationWeight()
end
-- 我们创建一个回调函数
local ok, err1 = ngx.timer.at(10, setWeight)

-- 下面是计算需要提前定义的变量-------------------------------------------------------------
-- γi 是静态的所有服务器都一样
local g1 = 0.3
local g2 = 0.13
local g3 = 0.15
local g4 = 0.22
local g5 = 0.2
-- 设置节点的数量
local n_num = 4
-- r1 = 0.7 -- 使用的是单位时间内完成成功的请求平均数
-- r2 = 0.015865084322299 -- cpu使用率
-- r3 = 0.51381299570136 -- 内存使用率
-- r4 = 0.000123 -- 网络带宽使用率
-- r5 = 0.99 -- 该节点请求成功的除以所有请求
-- r6 = 10 -- 代表节点接收的所有请求
local Qmax = 100000 -- 提前定义的最大排队数量
-- 排队等待队列长度
local Q = 0
-- 是β
local B = 0
-- α是指集群节点设备每秒处理的客户请求数量,每个节点的,是静态的需要提前定义
local a = {100, 121, 141, 161}
-- Rall 每个服务器节点的资源可用性
local Rall = 0
-- ωi为每个集群节点上客户请求的到达概率
local w = {}
-- ω_t是上面的wi全部相加的总和
local w_t = 0
-- Qdi 存储计算出来的权重
local Qdi = {}
-- Qall 所有r6相加,是集群接收的请求数量
local Qall = 0

--------------------------------------------上面定义一些变量---------------------------------------------------------------------

-- 插件源数据配置
local schema = {
    -- 类型
    type = "object",
    -- 插件接收的配置参数
    properties = {},
    minProperties = 1,
    -- 附加属性
    additionalProperties = false,
}

-- 插件名
local plugin_name = "xiaoyou"

-- 插件的配置信息
local _M = {
    -- 版本
    version = 0.1,
    -- 优先级
    priority = 999999,
    -- 插件的类型
    --type = 'auth',
    -- 插件名字
    name = plugin_name,
    -- 插件的参数
    schema = schema,
}

-------------------------------------上面配置插件信息----------------------------------------------------------------------

-- 服务器上报数据
local upload =function(ctx)
    -- 获取系统状态
    -- local ip = ngx.ctx.api_ctx.var.host .. ":" .. tostring(ngx.ctx.api_ctx.var.server_port)
    -- r1 服务率,节点单位时间内处理成功的数量
    -- r2 cpu使用率
    -- r3 内存使用率
    -- r4 网络使用率,网络带宽占用率
    -- r5 节点响应率,响应成功的请求
    -- r6 改节点接收的所有请求
    local info ={}
    local n = tonumber(ngx.var.arg_n) -- 获取服务器的标志位,标志这个服务器的类别
    core.log.error("标志位 ", n)
    -- 全部都转数字
    info["r1"] = tonumber(ngx.var.arg_r1)
    info["r2"] = tonumber(ngx.var.arg_r2)
    info["r3"] = tonumber(ngx.var.arg_r3)
    info["r4"] = tonumber(ngx.var.arg_r4)
    info["r5"] = tonumber(ngx.var.arg_r5)
    info["r6"] = tonumber(ngx.var.arg_r6)
    -- 记录当前时间戳
    info["flag"] = 6
    status[n] = info

    ngx.say(core.json.encode(status))
end

-- 计算所有节点的权重,并且存储起来
function CalculationWeight()
    -- 求每个w
    for i = 1, n_num, 1 do
        core.log.error("status状态--- ", i, ": " , core.json.encode(status))
        Rall = math.pow(status[i]["r1"], g1) * math.pow(status[i]["r2"], g2) * math.pow(status[i]["r3"], g3) * math.pow(status[i]["r4"], g4) * math.pow(status[i]["r5"], g5)
        core.log.error("Rall: ", i, "--", Rall, "--")
        B = a[i] * Rall
        core.log.error("B: ", i, "--", B, "--")
        w[i] = ((Qmax - Q)/(Qmax - Q + 1)) * a[i] * Rall
        core.log.error("WI: ", i, "--", w[i], "--")
        -- 求w的总和
        w_t = w_t + w[i]
        Qall = Qall + status[i]["r6"]
    end
    core.log.error("w_t: ", "--", w_t, "--")
    core.log.error("Qall: ", "--", Qall, "--")

    -- 求每个Qdi
    for i = 1, n_num, 1 do
        -- 判断flag是否大于0
        if status[i]["flag"] > 0 then
            Qdi[i] = Qall * (w[i]/w_t)
        else
            Qdi[i] = 0
        end
        core.log.error("weight ", i, ": " , Qdi[i])
    end
    -- 重新设置权重
    reloadWeight()
end

-- 返回全局变量中的数据
local get = function()
    ngx.say(core.json.encode(status))
    ngx.say(Q)
end

-- 重新设置权重
function reloadWeight()
    -- 每个节点的flag减一
    subFlag()
    -- 引入resty的http请求模块
    local http = require("resty.http")
    -- 新建一个http请求
    local httpc = http.new()
    -- 负载均衡的节点列表
    local hosts = {}
    hosts[1] = Qdi[1]
    hosts[2] = Qdi[2]
    hosts[3] = Qdi[3]
    hosts[4] = Qdi[4]
    -- 发送一个http请求
    local resp, err = httpc:request_uri("http://192.168.123.119:82/send", {
        method = "POST",
        headers = {
            -- 设置发送的数据类型
            ["Content-Type"] = "application/json"
        },
        body = core.json.encode(hosts)
    })
    --如果请求为空,那么就返回错误信息
    if not resp then
        ngx.say("request error :", err)
        return
    end
    --返回请求结果
    ngx.say(resp.body)
    --关闭http请求
    httpc:close()
end

-- 每个节点的flag减一
function subFlag()
    for i = 1, n_num, 1 do
        status[i]["flag"] = status[i]["flag"] - 1
    end
end

---- 自己注册路由一个上报数据,一个获取数据
function _M.api()
    return {
        {
            methods = {"GET"},
            uri = "/apisix/xiaoyou/upload",
            handler = upload
        },
        {
            methods = {"GET"},
            uri = "/apisix/xiaoyou/get",
            handler = get
        }
    }
end


-- 在balancer阶段来处理请求
-- 常见的阶段:init, rewrite,access,balancer,header filer,body filter 和 log 阶段
function _M.access(conf, ctx)
    ----当一个请求到达时会触发一个传入事件,并会根据指定的key计算当前请求应该延迟处理或者应该立即拒绝。语法如下:
    local delay, err = lim:incoming("remote_addr", true)
    -- 获取当前请求队列数
    core.log.error("now queue: ", err, "---")
    --sleep(1)
    local conn= lim:leaving("remote_addr")
    -- 新的并发请求数(或活跃的连接数)。与incoming不同是,该方法总是会提交到共享字典空间。
    -- 记录当前需要处理的请求数量
    Q = conn
    core.log.error("leave queue: ", conn)
end

-- 返回插件对象
return _M

配置路由

我们需要让我们的apisix进行负载均衡,我们这里为了方便起见直接用的内网地址

配置Python服务器转发

我们需要使用Python来进行转发,同样给服务器安装Pythonyum install python3,脚本内容如下

# coding=UTF-8
import json
import requests
from flask import Flask,request
import math

app = Flask(__name__)

@app.route('/log',methods=["POST"])
def log():
    print(request.get_json())
    return '45'


def get_num(num):
    return math.ceil(num*1000000)

@app.route('/send',methods=["POST"])
def server1():
    # 设置头部信息
    heard = {
        "X-API-KEY": "edd1c9f034335f136f87ad84b625c8f2",
        "Content-Type": "application/json"
    }
    print('获取数据')
    weight = request.get_json()
    total = weight[0] + weight[1] + weight[2]
    node1 = int(weight[0] / total * 100)
    node2 = int(weight[1] / total * 100)
    node3 = int(weight[2] / total * 100)
    # node1 = 1
    # node2 = 1
    # node3 = 1
    print(weight,node1,node2,node3)
    # 获取request的参数
    # 设置body数据
    body = {
        "plugins": {
            "xiaoyou": {}
        },
        "upstream": {
            "nodes": {
                '172.25.12.14:8085': node1,
                '172.25.12.16:8085':  node2,
                '172.25.12.18:8085':  node3,
            },
            "type": "roundrobin"
        },
        "uri": "/*"
    }
    response = requests.put('http://127.0.0.1:9080/apisix/admin/routes/1', headers=heard, data=json.dumps(body))
    return response.text


if __name__ == "__main__":
    # 先启动4个线程
    app.run(port=82, host='0.0.0.0')

使用pip安装依赖

pip3 install flask
pip3 install requests

运行项目 python3 nginx.py

这里会显示各个项目的权重

注意修改一下插件的Python项目的路径

配置虚拟内存

首先我们修改这个配置文件

这里我们给自己的插件分配内容

这里我们的limit设置

节点设置

每个节点都安装一个宝塔,使用宝塔我们导入我们的数据库

然后安装java,centos安装命令

yum install java-1.8.0-openjdk-devel.x86_64

ubuntu安装命令

apt install openjdk-8-jdk

windows安装命令: 直接到官网下载 Python Releases for Windows | Python.org

同时我们还需要安装Python环境

centos安装命令 yum install python3

ubuntu默认安装了,我们不管

然后就是打包项目,这个实验idea打包即可(linux系统需要修改一下路径)

同时还需要把net.py文件放入root目录

net.py文件内容如下

#!/usr/bin/env python
# -*- coding: utf-8 -*-
try:
    import psutil
except ImportError:
    print('Error: psutil module not found!')
    exit()


def get_key():
    key_info = psutil.net_io_counters(pernic=True).keys()

    recv = {}
    sent = {}

    for key in key_info:
        recv.setdefault(key, psutil.net_io_counters(pernic=True).get(key).bytes_recv)
        sent.setdefault(key, psutil.net_io_counters(pernic=True).get(key).bytes_sent)

    return key_info, recv, sent


def get_rate(func):
    import time

    key_info, old_recv, old_sent = func()

    time.sleep(1)

    key_info, now_recv, now_sent = func()

    net_in = {}
    net_out = {}

    for key in key_info:
        # float('%.2f' % a)
        net_in.setdefault(key, float('%.2f' % ((now_recv.get(key) - old_recv.get(key)) / 1024)))
        net_out.setdefault(key, float('%.2f' % ((now_sent.get(key) - old_sent.get(key)) / 1024)))

    return key_info, net_in, net_out


if __name__ == "__main__":
    try:
        key_info, net_in, net_out = get_rate(get_key)
        for key in key_info:
            if key == 'eth0':

                # 获取网络带宽使用率
                print('%f,%f' % (net_out.get(key), net_out.get(key) / (100 / 8 * 1024)))

    except KeyboardInterrupt:
        exit()

运行Python文件需要下面这几个依赖

centos:
sudo yum install python3-devel
pip3 install psutil

ubuntu:
apt install python3-pip
sudo apt-get install python3-dev
pip3 install psutil

如果运行成功,会有下面的提示

最后我们运行一下java项目 java -jar jenkins-test.jar

注意里面的内容需要正常显示

访问网址,如果出现下面的内容说明安装成功

我们也可以测试一下数据库操作

windows 解除端口占用:

netstat -aon|findstr "8081"
taskkill /T /F /PID 9088  PID号

压力测试

这里说一下这个函数如何生成


文章作者: 小游
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小游 !
  目录