基于golang的后端一站式服务框架
hydra致力于为后端软件开发者提供简单的、统一的、完善的服务框架,减少在集群管理、配置管理、服务注册与发现、系统监控、日志归集、链路追踪、安全访问、常用组件等的心智消耗。
目前最新版本v1.1.3,已应用于20+生产项目,主要功能有:
-
支持API、WEB、WEBSOCKET、RPC、定时任务、消息消费 等服务器,可在单个应用中组合使用。
-
支持windows, mac, linux以服务方式安装、运行、停止、卸载等。
-
支持分布式集群部署、单机伪集群部署、单机部署。
-
提供对等、分片、主从等集群模式。
-
采用配置中心,中心化管理配置,本地零配置。支持zookeeper, redis, 本地文件,进程内管理配置。
-
配置变更后自动生效,无须手动重启服务
-
支持zookeeper, etcd, redis等作为注册中心,为远程调用提供服务管理。
-
支持将metric信息(如:QPS、处理时长、响应等)定时上报到influxdb,用于系统运行状况监控大屏显示。
-
支持Skywalking,Cat等APM工具进行分布式追踪、性能指标分析、应用和服务依赖分析。
-
支持将本地日志提交到日志归集服务器( rlog),用于日志集中查询分析。
-
支持白名单、黑名单访问控制,Basic Auth、API KEY、Cookie, JWT等安全验证。 支持远程认证服务, 提供加解密、验证签等服务。
-
支持服务器限流、降级、熔断等控制。
-
支持根据业务规则编写灰度脚本,将用户请求转发到不同集群。
-
redis,memcached,数据库,mqtt,activeMQ,rpc,uuid,分布式锁,http client,rpc client等。
package main import ( "github.com/micro-plat/hydra" "github.com/micro-plat/hydra/hydra/servers/http" ) func main() { //创建app app := hydra.NewApp( hydra.WithServerTypes(http.API), ) //注册服务 app.API("/hello", func(ctx hydra.IContext) interface{} { return "hello world" }) //启动app app.Start() }package main import ( "github.com/micro-plat/hydra" "github.com/micro-plat/hydra/hydra/servers/rpc" ) func main() { //创建app app := hydra.NewApp( hydra.WithServerTypes(rpc.RPC), ) //注册服务 app.RPC("/hello", func(ctx hydra.IContext) interface{} { return "hello world" }) //启动app app.Start() }package main import ( "github.com/micro-plat/hydra" "github.com/micro-plat/hydra/hydra/servers/cron" ) func main() { app := hydra.NewApp( hydra.WithServerTypes(cron.CRON), ) //注册服务 app.CRON("/hello",hello,"@every 5s") app.Start() } func hello(ctx hydra.IContext) interface{} { return "success" }package main import ( "github.com/micro-plat/hydra" "github.com/micro-plat/hydra/hydra/servers/mqc" "github.com/micro-plat/hydra/conf/vars/queue/lmq" ) func main() { app := hydra.NewApp( hydra.WithServerTypes(mqc.MQC), ) //注册服务 app.MQC("/hello",hello,"queue-name") //设置消息队列服务器(本地内存MQ,支持redis,mqtt等) hydra.Conf.MQC(lmq.MQ) app.Start() } func hello(ctx hydra.IContext) interface{} { return "success" }package main import ( "github.com/micro-plat/hydra" "github.com/micro-plat/hydra/hydra/servers/http" "github.com/micro-plat/hydra/hydra/servers/cron" ) func main() { app := hydra.NewApp( hydra.WithServerTypes(http.API,cron.CRON), ) app.API("/hello",hello) app.CRON("/hello",hello,"@every 5s") app.Start() } func hello(ctx hydra.IContext) interface{} { return "hello world" }$ ./flowserver run --plat test日志如下:
[2020/07/08 09:36:31.140432][i][29f63e41d]初始化: /test/flowserver/api-cron/1.0.0/conf [2020/07/08 09:36:31.143027][i][29f63e41d]启动[api]服务... [2020/07/08 09:36:31.643524][i][b65655312]启动成功(api,http://192.168.4.121:8080,1) [2020/07/08 09:36:31.643885][i][29f63e41d]启动[cron]服务... [2020/07/08 09:36:31.844844][i][3908a5ccc]启动成功(cron,cron://192.168.4.121,1) [2020/07/08 09:36:32.346047][d][3908a5ccc]the cron server is started as master [2020/07/08 09:36:36.648149][i][01751ece6]cron.request: GET /hello from 192.168.4.121 [2020/07/08 09:36:36.648244][i][01751ece6]cron.response: GET /hello 200 193.356µs [2020/07/08 09:36:41.651858][i][00f45e17b]cron.request: GET /hello from 192.168.4.121 [2020/07/08 09:36:41.651911][i][00f45e17b]cron.response: GET /hello 200 159.694µs服务已启动,cron server开始周期(每隔5秒)执行任务
$ curl http://192.168.4.121:8080/hello返回内容:
hello worldapp := hydra.NewApp( hydra.WithPlatName("test"), hydra.WithSystemName("apiserver"), hydra.WithServerTypes(http.API), hydra.WithClusterName("prod"), ) app.Start()app := hydra.NewApp( hydra.WithServerTypes(http.API), ) app.Start()hydra.Conf.API("8090")hydra.Conf.API("8090", api.WithHeaderReadTimeout(30), api.WithTimeout(30, 30)) hydra.Conf.API("8080"). WhiteList(whitelist.NewIPList("/**", whitelist.WithIP("192.168.4.121"))). BlackList(blacklist.WithIP("192.168.4.120"))-
- 配置*/member*开头人路径不验证,将jwt串串存到header中:
hydra.Conf.API("8080").Jwt(jwt.WithExcludes("/member/**"), jwt.WithHeader())-
- 登录成功设置jwt信息:
type UserInfo struct{ Name string `json:"name"` UID string `json:"id"` } func login(ctx hydra.IContext) interface{} { userInfo := UserInfo{UID:"209867923",Name:"colin"} ctx.User().Auth().Response(&userInfo) return "success" }-
- 从jwt中获取用户信息:
func login(ctx hydra.IContext) interface{} { userInfo :=new(UserInfo) ctx.User().Auth().Bind(&userInfo) return "success" }以 202.222. 开头的IP,转发到名称中包含gray的集群(tengo脚本):
hydra.Conf.API("8090").Proxy(` request := import("request") app := import("app") text := import("text") types :=import("types") fmt := import("fmt") getUpCluster := func(){ ip := request.getClientIP() current:= app.getCurrentClusterName() if text.has_prefix(ip,"202.222."){ return app.getClusterNameBy("gray") } return current } upcluster := getUpCluster() `)-
- 处理输出(tengo脚本):
hydra.Conf.API("8070").Render(` request := import("request") response := import("response") text := import("text") types :=import("types") rc:="<response><code>{@status}</code><msg>{@content}</msg></response>" getContent := func(){ input:={status:response.getStatus(),content:response.getRaw()["id"]} if text.has_prefix(request.getPath(),"/tx/request"){ return [200,types.translate(rc,input)] } if text.has_prefix(request.getPath(),"/tx/query"){ return [200,types.translate(rc,input),"text/plain"] } return [200,response.getContent()] } render := getContent() `)-
- 服务实现
func main() { app := hydra.NewApp( hydra.WithServerTypes(http.API), ) app.API("/tx/request", request) app.API("/tx/query", request) app.API("/request", request) app.Start() } func request(ctx hydra.IContext) interface{} { return map[string]interface{}{ "id": 101010, } }-
- 请求服务
~/work/bin$ curl http://localhost:8070/tx/request <response><code>200</code><msg>101010</msg></response> ~/work/bin$ curl http://localhost:8070/request {"id":101010} hydra.Conf.Vars().DB("db", oracle.New("hydra/hydra"))使用方法:
func GetUserInfo(id int64)(map[string]interface{},error) db:=hydra.C.GetDB() userInfo,err:=db.Query("select t.* from user_info t where t.id=@id",map[string]interface{}{"id",id}) return userInfo,err hydra.Conf.Vars().Cache("cache", redis.New("192.168.0.109"))使用方法:
func GetUserInfo(id int64)(string,error) cache:=hydra.C.GetCache() userInfo,err:=cache.Get(fmt.Sprintf("user:info:%d",id)) return userInfo,err-
- 服务函数
func main() { app := hydra.NewApp( hydra.WithServerTypes(http.API), ) app.API("/request", request) app.Start() } func request(ctx hydra.IContext) interface{} { return "success" }-
- 包含Handle服务的struct构造函数或对象
func main() { app := hydra.NewApp( hydra.WithServerTypes(http.API), ) app.API("/order", NewOrderService) //或 // app.API("/order", &OrderService{}) app.Start() } type OrderService struct { } func NewOrderService()*OrderService{ return &OrderService{} } func (o *OrderService) Handle(ctx hydra.IContext) interface{} { ctx.Log().Info("--------订单处理----------")) return "success" }-
- 多个服务注册
func main() { app := hydra.NewApp( hydra.WithServerTypes(http.API), ) app.API("/order/*", NewOrderService) app.Start() } type OrderService struct { } func NewOrderService()*OrderService{ return &OrderService{} } func (o *OrderService) RequestHandle(ctx hydra.IContext) interface{} { ctx.Log().Info("--------收单处理----------")) return "success" } func (o *OrderService) QueryHandle(ctx hydra.IContext) interface{} { ctx.Log().Info("--------查单处理----------")) return "success" }实际注册了两个服务 /order/request,/order/query
-
- RESTful服务注册
func main() { app := hydra.NewApp( hydra.WithServerTypes(http.API), ) app.API("/product", &ProductService{}) app.Start() } type ProductService struct { } func (o *ProductService) GetHandle(ctx hydra.IContext) interface{} { ctx.Log().Info("--------查询产品----------")) return "success" } func (o *ProductService) PostHandle(ctx hydra.IContext) interface{} { ctx.Log().Info("--------新增产品----------")) return "success" } func (o *OrderService) PutHandle(ctx hydra.IContext) interface{} { ctx.Log().Info("--------修改产品----------")) return "success" } func (o *OrderService) DeleteHandle(ctx hydra.IContext) interface{} { ctx.Log().Info("--------禁用产品----------")) return "success" }实际注册了一个服务 /product
-
- 钩子函数
func main() { app := hydra.NewApp( hydra.WithServerTypes(http.API), ) app.API("/order", NewOrderService) app.Start() } type OrderService struct { } func NewOrderService()*OrderService{ return &OrderService{} } func (o *OrderService) Handling(ctx hydra.IContext) interface{} { ctx.Log().Info("--------预处理----------")) return "success" } func (o *OrderService) Handle(ctx hydra.IContext) interface{} { ctx.Log().Info("--------订单处理----------")) return "success" } func (o *OrderService) Handled(ctx hydra.IContext) interface{} { ctx.Log().Info("--------后处理----------")) return "success" }-
- 普通字符串
func request(ctx hydra.IContext) interface{} { return "success" }响应内容: success
Content-Type: text/plain; charset=utf-8
-
- JSON字符串
func request(ctx hydra.IContext) interface{} { return `{"name":"colin"}` }响应内容: {"name":"colin"}
Content-Type: application/json; charset=utf-8
-
- XML字符串
func request(ctx hydra.IContext) interface{} { return `<name>colin</name>` }响应内容: <name> colin</name> Content-Type: application/xml; charset=utf-8
-
- Map
func request(ctx hydra.IContext) interface{} { return map[string]interface{}{"name":"colin"} }响应内容: {"name":"colin"}
Content-Type: application/json; charset=utf-8
-
- Struct
func request(ctx hydra.IContext) interface{} { return &UserInfo{Name:"colin"} }响应内容: {"name":"colin"}
Content-Type: application/json; charset=utf-8
-
- Map,指定ContentType
func request(ctx hydra.IContext) interface{} { ctx.Response().ContentType(context.UTF8XML) return map[string]interface{}{"name":"colin"} }响应内容: <name/>colin <name/> Content-Type: application/xml; charset=utf-8
-
- Struct,指定ContentType
func request(ctx hydra.IContext) interface{} { ctx.Response().ContentType(context.UTF8XML) return &UserInfo{Name:"colin"} }响应内容: <name/>colin <name/> Content-Type: application/xml; charset=utf-8
-
- 普通错误
func request(ctx hydra.IContext) interface{} { return fmt.Errorf("err") }响应内容: err Content-Type: text/plain; charset=utf-8
-
- 带状态码的错误
func request(ctx hydra.IContext) interface{} { return errs.New(500,"err") }状态码: 500 响应内容: err Content-Type: text/plain; charset=utf-8