手动实现代理服务器(仿nginx)

前言

经常使用nginx来做web服务器,你对它了解有多少,这篇文章将带领你简单的触碰它。


代理服务器

代理服务器都是存在Client(客户端)与Server(服务端)之间,但是性质不同,所以为了两种。

  1. 正向代理服务器(客户端)
  2. 反向代理服务器(服务端)

正向代理服务器

写前端的小伙伴就会触碰到,后端xxx不会弄跨域只能用代理解决,哈哈哈。

直接偷图,正向代理就是直接在客户端进行代理,服务器不知道实际发送请求的客户端

反向代理服务器

也是偷图,反向代理就是直接在服务器进行代理,客户端不知道实际提供服务的服务器

好了,也介绍完了,我们实现的代理服务器就是反向代理。


轮询

轮询是一种CPU决策如何提供周边设备服务的方式,又称《程控输入输出》

普通轮询

将请求依次发给服务器,周而复始

加权轮询

主要解决:效率偏低,无法满足服务器配置不同的情况

例子: 现在有三台服务器,A=5、B=3、C=1,数字代表权重。将三台服务器权重值相加值为9,也就是说每9个请求会分给 5个给A、3个给B、1个给C,依次循环 AAAAABBBC .....

代码实现

/***
 *  加权轮询
 */
let server = []
function init() {
    let A = {
        ip: '211.xxx.xxx.xxx',
        weight: 5
    }
    let B = {
        ip: '192.xxx.xxx.xxx',
        weight: 3
    }
    let C = {
        ip: '166.xxx.xxx.xxx',
        weight: 1
    }
    server.push(A)
    server.push(B)
    server.push(C)
    // console.log(server)
}
function getServer(requestId) {
    // 计算总权重
    total = 0
    for(let i = 0; i < server.length; i++) {
        let itemI = server[i]
        total += itemI.weight
    }
    // console.log(`总权重是 ${total}`)
    
    // 第几次请求 % 权重总数 + 1  =  (2 % 9) + 1 = 2 + 1 = 3
    // +1是因为怕余数等于0
    let s = requestId % total + 1
    // console.log(s)

    // 计算返回结果
    for(let n = 0; n < server.length; n++) {
        let itemN = server[n]
        if (s <= itemN.weight) {
            return itemN
        }
        s = s - itemN.weight
    }
    return null
}
function run() {
    // 模拟请求
    for(let i=1; i <= 9; i++) {
        let item = getServer(i)
        console.log(`当前访问的服务器ip是 ${item.ip}`)
    }
}
init()
run()

/**
当前访问的服务器ip是 211.xxx.xxx.xxx
当前访问的服务器ip是 211.xxx.xxx.xxx
当前访问的服务器ip是 211.xxx.xxx.xxx
当前访问的服务器ip是 211.xxx.xxx.xxx
当前访问的服务器ip是 192.xxx.xxx.xxx
当前访问的服务器ip是 192.xxx.xxx.xxx
当前访问的服务器ip是 192.xxx.xxx.xxx
当前访问的服务器ip是 166.xxx.xxx.xxx
当前访问的服务器ip是 211.xxx.xxx.xxx
 * 
 */

那这样是不是也会有问题呢,这样是不是会导致权重高的服务器会一直被请求呢,一系列问题,所以就出现了 平滑加权轮询

平滑加权轮询

主要解决加权轮询的问题(短时间内权重大的服务器得到过多的请求数,不是一种均匀的分配方式)

例子:现在有三台服务器,A=5、B=3、C=1,数字代表权重。将三台服务器权重值相加值为9,也就是说每9个请求会分给 5个给A、3个给B、1个给C,依次循环 ABCABABAA....

代码实现

/**
 * 平滑加权轮询
 */
let server = []
function init() {
    let A = {
        ip: '211.xxx.xxx.xxx',
        weight: 5,
        dynamicWeight: 0
    }
    let B = {
        ip: '192.xxx.xxx.xxx',
        weight: 3,
        dynamicWeight: 0
    }
    let C = {
        ip: '166.xxx.xxx.xxx',
        weight: 1,
        dynamicWeight: 0
    }
    server.push(A)
    server.push(B)
    server.push(C)
    // console.log(server)
}
function getServer() {
    // 计算总权重
    total = 0
    for(let i = 0; i < server.length; i++) {
        let itemI = server[i]
        total += itemI.weight
    }
    // console.log(`总权重是 ${total}`)
    
    // 给每台服务器加上动态权重 = 动态权重 + 权重
    for(let a = 0; a < server.length; a++) {
        let itemA = server[a]
        itemA.dynamicWeight = itemA.dynamicWeight + itemA.weight
    }

    // 选出动态权重最大的服务器
    let maxServerItem = server[0]
    for(let b = 0; b < server.length; b++) {
        let itemB = server[b]
        if (maxServerItem.dynamicWeight < itemB.dynamicWeight) {
            maxServerItem = itemB
        }
    }

    // 选中的动态权重最大的服务器的动态权重 - 总权重
    maxServerItem.dynamicWeight = maxServerItem.dynamicWeight - total

    // console.log(server)

    return maxServerItem
}
function run() {
    // 模拟请求
    for(let i=1; i <= 9; i++) {
        let item = getServer()
        console.log(`当前访问的服务器ip是 ${item.ip}`)
    }
}
init()
run()

/**
当前访问的服务器ip是 211.xxx.xxx.xxx
当前访问的服务器ip是 192.xxx.xxx.xxx
当前访问的服务器ip是 211.xxx.xxx.xxx
当前访问的服务器ip是 166.xxx.xxx.xxx
当前访问的服务器ip是 211.xxx.xxx.xxx
当前访问的服务器ip是 192.xxx.xxx.xxx
当前访问的服务器ip是 211.xxx.xxx.xxx
当前访问的服务器ip是 192.xxx.xxx.xxx
当前访问的服务器ip是 211.xxx.xxx.xxx
 * 
 */

那我们轮询算法就完毕了,开始手动实现一个,不过实现的话 啥语言都可以实现但是性能差距肯定是不一样的,所以我们使用了go语言实现


实现功能

效果如下

文件结构

    
└─src
    │  go.mod
    │  go.sum
    │  main.go  代理服务器
    │  
    ├─config
    │      env  配置目录
    │      init.go  解析配置目录
    │      
    ├─util
    │      httpChecker.go  检查当前服务器状态
    │      loadBalance.go  实现轮询的几种方式
    │      
    └─web
            web1.go
            web2.go
            web3.go

 

项目地址


总结

我们介绍了代理服务器,也介绍了轮询并实现了几种轮询的方式,然后使用了go语言写了一个小案例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

An_s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值