小团队大开发:iogo微服务集群框架(golang/grpc/http/protobuf/etcd/freetoo/5G物联网/服务发现/负载均衡/一致性哈希/码客/广西南宁卢益贵)
小团队大开发:iogo微服务集群框架
KeyWord: iogo,golang,grpc,protobuf,etcd,zookeeper,microservice,distributed lock,service discovery,cluster,load balancing,k8s,docker,redis,mamcache,5G物联网,微服务框架,分布式集群,分布式锁,分布式文件系统,分布式数据库,高速缓存集群,服务发现,负载均衡,容器编排,一致性哈希
目录
一、iogo 简介
1、开发iogo的初衷
iogo微服务集群框架是grpc、http远程服务方法调用的易用性封装,集成了微服务集群开发中服务发现和负载均衡的核心部分,iogo本着“小团队大开发”的理念,减少开发人员在底层通信方面的开发工作,将精力集中放在应用逻辑的开发上,并且可以轻而易举的进行微服务集群的动态伸缩操作。借助命令行工具iogoc,可以快速创建微服务集群的项目工程模板。
“小团队大开发”是iogo的初衷,对于大型应用场景的超大规模集群来说未免是大话了,但对于中小型的应用场景来说未免不可,尤其更加方便于小型的开发团队,特别特别那个只有一个人做后端的团队。
2、iogo功能简介
-
跨平台
适用于windows和linux平台的集群开发
-
便捷的通讯协议定义
您只需定义一对golang结构体:
type LoginRequest struct {
}
type LoginReply struct {
}
或一对ProtoBuf消息体:
message LoginRequest {
}
message LoginReply {
}
无需定义服务方法,即可实现HTTP或者GRPC的方法调用。iogo自动配对Request和Reply关键字的前缀作为服务方法的函数名称。
-
插件化设计
iogo使用了插件化的设计方法,您可以*选择http或者grpc方式来进行通讯,*选择JSON或者ProtoBuf格式来序列化通讯数据,*选择ETCD或者Zookeeper作为服务发现的平台,当然您还可以根据插件接口标准自定义插件。
-
适用互联网或物联网开发
iogo适用于常规的互联网应用开发,也适用于5G物联网开发。
-
适用消息或流体通讯
iogo全面支持GRPC一元、客户服务流的四种模式,适用于互联网和物联网的消息及流体(文件及视频等)通讯。
-
其他功能(动态权重负载均衡、异步日志)
iogo集成了动态权重负载均衡,您可以根据实时的CPU、内存、网络IO流量、磁盘IO流量、磁盘空间等综合计算权重值,报告给iogo,iogo负载均衡算法会实时更新权重,合适分配服务响应资源。另外iogo集成了异步日志模块。
二、iogo 框架
1、iogo框架
注:Zookeeper尚未实现
2、典型微服务集群框架
你可以根据集群特点,选择适合自己的微服务访问模式,比如:互联网端使用HTTP+JSON或ProtoBuf模式,内部局域网端集群互相访问则使用GRPC+ProtoBuf模式。
三、iogo 使用说明
以下配置均由iogoc命令行工具自动生成,您仅需要修改集群名字、IP地址、通讯秘钥等参数即可。
注:
1、为便于docker容器编排的动态设置要求,iogo提供了config单元,CfgReader首先读取命令行参数,如果没有则读取ini文件,再没有则选择相应函数传入参数的默认值,详细参阅iogo核心源码文件config.go。
2、iogo插件配置详细方法详细参阅工程模板下的 \comm\iogo\grpc\iogo.go 和 \comm\iogo\http\iogo.go 源码文件。
3、iogo插件实现配置化的设置方式,根据NewOption选项来创建插件
1、ETCD插件选项设置
func getNewEtcdOption(endpoints, flag string) etcd.NewOption {
if flag == "mutway" {
caFile := iogo.CfgReader.GetSdCaFileName("")
certFile := iogo.CfgReader.GetSdCertFileName("")
keyFile := iogo.CfgReader.GetSdKeyFileName("")
certSvrName := iogo.CfgReader.GetCertServerName("")
return etcd.WithCertFile(endpoints, certFile, keyFile, caFile, certSvrName)
} else {
return etcd.WithEndpoints(endpoints)
}
}
ETCD插件提供两项设置:TLS(单向或双向)和非TLS
2、创建JSON和ProtoBuf插件
func getCodec(flag string) plugin.Codec {
if flag == "json" {
return json.NewCodec()
} else {
return pb.NewCodec()
}
}
3、创建负载均衡插件
hash.NewLoadBalan(200)
参数:replicas,哈希环复制因子,节点少的时候数值越大平衡性更好。
4、HTTP插件选项设置
// Select IP based on subnet mask
const defSubnetMask = "192.168.1.2/22"
func getNewNetOption(addr, flag string) (svr http.NewOption, cli http.NewOption) {
if flag == "mutway" {
caFile := iogo.CfgReader.GetCaFileName("../keys/mutway/ca.crt")
svrCertFile := iogo.CfgReader.GetServerCertFileName("../keys/mutway/server.crt")
svrKeyFile := iogo.CfgReader.GetServerKeyFileName("../keys/mutway/server.key")
cliCertFile := iogo.CfgReader.GetClientCertFileName("../keys/mutway/client.crt")
cliKeyFile := iogo.CfgReader.GetClientKeyFileName("../keys/mutway/client.key")
certSvrName := iogo.CfgReader.GetCertServerName("")
cli := http.WithCertFilesCli(cliCertFile, cliKeyFile, caFile, certSvrName)
svr := http.WithCertFilesSvr(addr, svrCertFile, svrKeyFile, caFile)
return svr, cli
} else if flag == "oneway" {
caFile := ""
svrCertFile := iogo.CfgReader.GetServerCertFileName("../keys/oneway/server.crt")
svrKeyFile := iogo.CfgReader.GetServerKeyFileName("../keys/oneway/server.key")
cliCertFile := svrCertFile
cliKeyFile := ""
certSvrName := ""
cli := http.WithCertFilesCli(cliCertFile, cliKeyFile, caFile, certSvrName)
svr := http.WithCertFilesSvr(addr, svrCertFile, svrKeyFile, caFile)
return svr, cli
} else {
return http.WithAddr(addr), http.WithDefault()
}
}
addr: iogo可以指定服务地址(IP+Port),也可以仅指定端口和子网掩码,iogo自动获取适合的网卡地址来监听
5、GRPC插件选项设置
// Select IP based on subnet mask
const defSubnetMask = "192.168.1.2/22"
func getNewNetOption(addr, flag string) (svr grpc.NewOption, cli grpc.NewOption) {
if flag == "mutway" {
caFile := iogo.CfgReader.GetCaFileName("../keys/mutway/ca.crt")
svrCertFile := iogo.CfgReader.GetServerCertFileName("../keys/mutway/server.crt")
svrKeyFile := iogo.CfgReader.GetServerKeyFileName("../keys/mutway/server.key")
cliCertFile := iogo.CfgReader.GetClientCertFileName("../keys/mutway/client.crt")
cliKeyFile := iogo.CfgReader.GetClientKeyFileName("../keys/mutway/client.key")
certSvrName := iogo.CfgReader.GetCertServerName("")
cli := grpc.WithCertFilesCli(cliCertFile, cliKeyFile, caFile, certSvrName)
svr := grpc.WithCertFilesSvr(addr, svrCertFile, svrKeyFile, caFile)
return svr, cli
} else if flag == "oneway" {
caFile := ""
svrCertFile := iogo.CfgReader.GetServerCertFileName("../keys/oneway/server.crt")
svrKeyFile := iogo.CfgReader.GetServerKeyFileName("../keys/oneway/server.key")
cliCertFile := svrCertFile
cliKeyFile := ""
certSvrName := ""
cli := grpc.WithCertFilesCli(cliCertFile, cliKeyFile, caFile, certSvrName)
svr := grpc.WithCertFilesSvr(addr, svrCertFile, svrKeyFile, caFile)
return svr, cli
} else {
return grpc.WithAddr(addr), grpc.WithDefault()
}
}
注:GRPC插件设置基本和HTTP一致,无论HTTP或GRPC都支持单向或双向加密认证通讯或者非加密通讯。
6、iogo插件配置
pluginCli := iogo.NewPluginClient()
pluginCli.Cdc = getCodec("pb")
pluginCli.Lb = hash.NewLoadBalan(200)
pluginCli.Sd = etcd.NewClient(newOptEtcd)
pluginCli.Net = grpc.NewClient(newOptNetCli)
pluginSvr := iogo.NewPluginServer()
if servicePort != "" {
pluginSvr.Cdc = pluginCli.Cdc
pluginSvr.Net = grpc.NewServer(newOptNetSvr)
pluginSvr.Sd = etcd.NewServer(newOptEtcd, 20, 25)
}
iogo.SetPlugin(pluginSvr, pluginCli)
注:服务端和客户端可单独设置不同的网络模式(HTTP和GRPC),便于实现可区别的外部服务访问和内部服务访问。
7、iogo启动
func RunIogo(servicePort string) {
sdEndpoints := iogo.CfgReader.GetSdEndpoints(defSdEndpoints)
clusterName := iogo.CfgReader.GetClusterName(defClusterName)
serviceAddr := iogo.CfgReader.GetServiceAddr("", servicePort, defSubnetMask)
newOptEtcd := getNewEtcdOption(sdEndpoints, "") // or mutway stl, or oneway stl, or "" not saft
newOptNetSvr, newOptNetCli := getNewNetOption(serviceAddr, "") // or mutway stl, or oneway stl, or "" not saft
pluginCli := iogo.NewPluginClient()
pluginCli.Cdc = getCodec("pb") // json
pluginCli.Lb = hash.NewLoadBalan(200)
pluginCli.Sd = etcd.NewClient(newOptEtcd)
pluginCli.Net = grpc.NewClient(newOptNetCli)
pluginSvr := iogo.NewPluginServer()
if servicePort != "" {
pluginSvr.Cdc = pluginCli.Cdc
pluginSvr.Net = grpc.NewServer(newOptNetSvr)
pluginSvr.Sd = etcd.NewServer(newOptEtcd, 20, 25)
}
iogo.SetPlugin(pluginSvr, pluginCli)
iogo.Run(clusterName, serviceAddr)
}
四、iogoc 命令行工具说明
1、集群项目目录,默认在GoPath/src目录下
clustername
├── comm
│ └── iogo
│ ├── grpc
│ │ └── iogo.go
│ ├── http
│ │ └── iogo.go
│ └── iogo.go
├── proto
│ ├── src
│ │ ├── servicename1
│ │ │ └── servicename1.proto
│ │ └── servicename2
│ │ └── servicename1.proto
│ ├── servicename1
│ │ ├── servicename1.ig.go
│ │ └── servicename1.pb.go
│ └── servicename2
│ ├── servicename2.ig.go
│ └── servicename2.pb.go
│
├── svcservicename1
│ ├── main.go
│ └── server
│ ├── interceptor.go
│ └── method.go
└── svcservicename2
├── main.go
└── server
├── interceptor.go
└── method.go
\comm: 公共目录
\comm\iogo\grpc\iogo.go: iogo的GRPC设置
\comm\iogo\http\iogo.go: iogo的HTTP设置
\comm\iogo\iogo.go: iogo的模式选择(GRPC或者HTTP):
package iogo
// 修改此处可选择HTTP或者GRPC模式
// 执行通讯协议转换命令时,iogoc命令行工具会自动根据输出的模式来修改
import "testcluster/comm/iogo/grpc"
func RunIogo(servicePort string) {
iogo.RunIogo(servicePort)
}
func StopIogo() {
iogo.StopIogo()
}
\proto\src:ProtoBuf通讯协议源码目录,一个服务进程一个目录
\proto\src\servicename\servicename.proto:ProtoBuf通讯协议源码文件
\proto\servicename\servicename.pb.go:ProtoBuf生成的通讯协议源码go文件
\proto\servicename\servicename.ig.go:iogoc生成的通讯协议源码go文件
\svcservicename1\: 服务进程servicename1目录,iogoc自动加前缀svc
\svcservicename1\server\interceptor.go: 服务方法拦截器go文件
\svcservicename1\server\method.go: 服务方法实现go文件:
package server
import (
"testcluster/proto/servicename1"
)
type demoServer struct {
}
func init() {
proto.RegisterDemoServer(&demoServer{})
}
func (self *demoServer) Hellow(ctx proto.Context, request *proto.HellowRequest) (*proto.HellowReply, error) {
reply := &proto.HellowReply{
Answer: "Welcome to here",
}
return reply, nil
}
\svcservicename1\main.go: 服务进程main.go文件:
package main
import (
"testcluster/comm/iogo"
_ "testcluster/svcservicename1/server"
)
const defServicePort = "28666"
func main() {
iogo.RunIogo(defServicePort)
}
2、选择GoPath(golang源码工作空间)
iogoc需要设置工作空间目录,如果您已经设置GoPath,那么它会自动获取并显示索引号供您输入,或者您也可以直接输入go工作空间的目录全名:
3、创建集群模板或进入集群目录
选择工作空间以后,工作空间目录下的src目录作为集群的根目录,您可以选择集群索引号进入集群目录,或者创建新的集群(创建以后自动进入该集群目录,iogoc自动创建一个svcdemo的服务供参考,目录名均为小写):
mkc NewClusterName
4、创建服务模板
进入集群目录以后,您可以输入mks命令创建服务进程项目目录:
mks NewServiceName
5、编译go源通讯协议(仅适用于HTTP模式)
如果您不打算使用ProtoBuf,那么您可以直接在目录 newclustername\proto\newservicename 下创建通讯协议文件:
newservicename.go(定义Request和Reply对应的一对结构体)
package proto
type LoginRequest struct {
}
type LoginReply struct {
}
然后输入命令:
igc
iogoc会在目录 newclustername\proto\newservicename 下创建通讯协议接口文件:newservicename.ig.go
注:iogoc会把proto目录下所有服务进程目录下的xxx.go文件生成对应的通讯协议文件xxx.ig.go
newclustername
└── proto
└── newservicename
├── newservicename.go
└── newservicename.ig.go
6、编译ProtoBuf源通讯协议
如果您打算使用ProtoBuf来序列化数据,你可以使用命令 pbc 来生成HTTP模式的协议文件:
pbc
也可以使用 pbc -g 命令来生成GRPC模式的协议文件
pbc -g
注:
1、iogoc会调用protoc程序把 proto/src 目录下所有 xxx.proto 文件生成xxx.pb.go文件
2、同时iogoc会生成对应的通讯协议文件xxx.ig.go
newclustername
└── proto
├── src
│ └── newservicename
│ └── newservicename.proto
└── newservicename
├── newservicename.ig.go
└── newservicename.pb.go
7、iogoc其他命令:
返回上一层目录:
up
退出iogoc:
exit
五、iogo Demo 说明
iogo Demo实现了客户端登录会话服务集群并获取Token,然后通过Token访问应用逻辑服务集群的功能。
六、下载安装
1、golang开发包、liteide、etcd(win)、protobuf、grpc源码、iogo源码等下载包(内附安装方法):
https://download.csdn.net/download/GuestCode/12707296
2、iogo源码下载
https://github.com/freetoo/iogo
本文地址:https://blog.csdn.net/guestcode/article/details/107953644