go语言实现一个简单的简单网关

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言实现一个简单的简单网关相关的知识,希望对你有一定的参考价值。

参考技术A 网关=反向代理+负载均衡+各种策略,技术实现也有多种多样,有基于 nginx 使用 lua 的实现,比如 openresty、kong;也有基于 zuul 的通用网关;还有就是 golang 的网关,比如 tyk。

这篇文章主要是讲如何基于 golang 实现一个简单的网关。

转自: troy.wang/docs/golang/posts/golang-gateway/

整理:go语言钟文文档:www.topgoer.cn

启动两个后端 web 服务(代码)

这里使用命令行工具进行测试

具体代码

直接使用基础库 httputil 提供的NewSingleHostReverseProxy即可,返回的reverseProxy对象实现了serveHttp方法,因此可以直接作为 handler。

具体代码

director中定义回调函数,入参为*http.Request,决定如何构造向后端的请求,比如 host 是否向后传递,是否进行 url 重写,对于 header 的处理,后端 target 的选择等,都可以在这里完成。

director在这里具体做了:

modifyResponse中定义回调函数,入参为*http.Response,用于修改响应的信息,比如响应的 Body,响应的 Header 等信息。

最终依旧是返回一个ReverseProxy,然后将这个对象作为 handler 传入即可。

参考 2.2 中的NewSingleHostReverseProxy,只需要实现一个类似的、支持多 targets 的方法即可,具体实现见后面。

作为一个网关服务,在上面 2.3 的基础上,需要支持必要的负载均衡策略,比如:

随便 random 一个整数作为索引,然后取对应的地址即可,实现比较简单。

具体代码

使用curIndex进行累加计数,一旦超过 rss 数组的长度,则重置。

具体代码

轮询带权重,如果使用计数递减的方式,如果权重是5,1,1那么后端 rs 依次为a,a,a,a,a,b,c,a,a,a,a…,其中 a 后端会瞬间压力过大;参考 nginx 内部的加权轮询,或者应该称之为平滑加权轮询,思路是:

后端真实节点包含三个权重:

操作步骤:

具体代码

一致性 hash 算法,主要是用于分布式 cache 热点/命中问题;这里用于基于某 key 的 hash 值,路由到固定后端,但是只能是基本满足流量绑定,一旦后端目标节点故障,会自动平移到环上最近的那么个节点。

实现:

具体代码

每一种不同的负载均衡算法,只需要实现添加以及获取的接口即可。

然后使用工厂方法,根据传入的参数,决定使用哪种负载均衡策略。

具体代码

作为网关,中间件必不可少,这类包括请求响应的模式,一般称作洋葱模式,每一层都是中间件,一层层进去,然后一层层出来。

中间件的实现一般有两种,一种是使用数组,然后配合 index 计数;一种是链式调用。

具体代码

用Go语言实现一个简单的聊天机器人

一、介绍

目的:使用Go语言写一个简单的聊天机器人,复习整合Go语言的语法和基础知识。

软件环境:Go1.9,Goland 2018.1.5。

 

二、回顾

Go语言基本构成要素:标识符、关键字、字面量、分隔符、操作符。它们可以组成各种表达式和语句,而后者都无需以分号结尾。

  • 标识符:程序实体,前者即为后者的名称。
  • 关键字:被编程语言保留的字符序列,不能把它用作标识符。
  • 字面量:值的一种标记法。
  • 操作符==运算符:用于执行特定算术或逻辑操作的符号,操作的对象称为操作数。

 

数组:由若干相同类型的元素组成的序列。

切片(slice):可以看作是一种对数组的包装形式,它包装的数组称为该切片的底层数组。

函数和方法:一个函数的声明通常包括关键字func、函数名、分别由圆括号包裹的参数列表和结果列表,以及由花括号包裹的函数体。

func divide(dividend int,divisor ,int)(int,error){
    
}
//函数可以没有参数列表,也可以没有结果列表,但空参数列表必须保留括号,而空结果列表则不用
func printTab(){
    //
}

 

 

三、程序(初版本)

代码仓库链接:https://github.com/OctopusLian/ChatRobot

package main

import (
    "bufio"
    "os"
    "fmt"
    "strings"
)

func main() {
    inputReader := bufio.NewReader(os.Stdin)  //准备从标准输入读取数据
    fmt.Println("Please input your name:")
    input,err := inputReader.ReadString(\'\\n\')  //读取数据直到碰到 \\n为止
    if err != nil{
        fmt.Printf("An error occurred:%s")
        os.Exit(1)  //异常退出
    }else {
        //用切片操作删除最后的 \\n
        name := input[:len(input)-1]
        fmt.Printf("Hello,%s! What can I do for you?\\n",name)
    }
    for{
        input,err = inputReader.ReadString(\'\\n\')
        if err != nil{
            fmt.Printf("An error occurred:%s\\n",err)
            continue
        }
        input = input[:len(input)-1]
        //全部转换为小写
        input = strings.ToLower(input)
        switch input {
        case "":
            continue
        case "nothing","bye":
            fmt.Println("Bye!")
        //正常退出
        os.Exit(0)
        default:
            fmt.Println("Sorry,I didn\'t catch you.")
        }
    }
}

 

参考资料

bufio

os

strings

fmt

 

以上是关于go语言实现一个简单的简单网关的主要内容,如果未能解决你的问题,请参考以下文章

Go语言实战 (10) go-micro微服务 实现简单备忘录 (上) | 用户模块

Go语言-一个简单的MockServer实现

Go语言实战 (11) go-micro微服务 实现简单备忘录 (下) | 备忘录模块

用Go语言实现一个简单的聊天机器人

Go语言之从0到1实现一个简单的Redis连接池

Go语言实现队列 最简单简介的实现队列