写点什么

Go 云原生应用实战系列(二)

用户头像
田晓亮
关注
发布于: 2020 年 09 月 09 日
Go 云原生应用实战系列(二)

本章节我将专注于开发第一个微服务系统,我们将学会如何用 go chassis 开发微服务并完成微服务之间的调用


系列 1https://xie.infoq.cn/article/f658d19b6f22f9d9bac1dfe75


开发你的第一个微服务

启动注册中心

docker run -d -p 30100:30100 servicecomb/service-center
复制代码

强烈推荐直接使用 all in one 的 docker compose 模板启动,因为可以使用可视化的 UI 界面。


https://github.com/go-chassis/go-chassis/blob/master/examples/docker-compose.yaml


  • UI 的地址为 http://127.0.0.1:30103

  • 注册中心地址为 http://127.0.0.1:30100


初始化 Go 工程

go mod init github.com/go-chassis/go-chassis-examples/hellogo get github.com/go-chassis/go-chassis/v2
复制代码


工程目录规划

可以创建一个 server(名称任意)文件夹,这个就是一个微服务的目录

mkdir server
复制代码

目录结构

server
+-- main.go
+-- conf
+-- chassis.yaml
+-- microservice.yaml
复制代码

最小化配置

在 chassis.yaml 中涵盖了几乎所有的配置,不过想要启动只需要 2 个简单的配置

servicecomb:  registry:     address: http://127.0.0.1:30100  protocols:     rest:       listenAddress: 127.0.0.1:9000
复制代码

也就是服务监听地址和注册中心地址


在 microservice.yaml 里定义微服务信息,只需要一个简单的微服务名即可,它还有大量的其他高级特性,我们将后续在高级特性中介绍

servicecomb:  service:    name: HelloServer
复制代码

编写业务逻辑

是时候编写自己的 API 了

//通常持有一批API,并定义API Patternstype HelloResource struct {}
//业务APIfunc (r *HelloResource) SayHi(b *rf.Context) { b.Write([]byte("hello, go chassis")) return}
//定义所有的API Patterns,用于API路由func (r *HelloResource) URLPatterns() []rf.Route { return []rf.Route{ {Method: http.MethodGet, Path: "/hello", ResourceFunc: r.SayHi}, }}
复制代码

之后仅需要注册即可

chassis.RegisterSchema("rest", &HelloResource{})
复制代码

启动服务

启动很简单,只需要编写如下内容

if err := chassis.Init(); err != nil {	openlog.Fatal("Init failed." + err.Error())	return}chassis.Run()
复制代码

编译执行

go build main.go./main
复制代码

验证:访问 UIhttp://127.0.0.1:30103


额外可以看到自动生成的 open API 文档


直接访问服务

curl http://127.0.0.1:9000/hello
复制代码

调用服务

接着我们需要调用这个服务

创建一个新的微服务

mkdir client
复制代码

定义微服务

在 chassis.yaml 中定义另一个监听地址

servicecomb:  registry:      address: http://127.0.0.1:30100  protocols:    rest:      listenAddress: 127.0.0.1:8000
复制代码

在 microservice.yaml 中定义微服务名

servicecomb:  service:    name: HelloClient
复制代码

#编写客户端

为了简单这里只需要简单的转发即可,这里给出完整逻辑

type SimpleResource struct {}//在这个方法中,调用上面编写的服务func (r *SimpleResource) SayHi(b *rf.Context) {	req, _ := rest.NewRequest(http.MethodGet, "http://HelloServer/hello", nil)//这里要填写需要调用哪个服务,填写服务名即可,然后就是他的api路径	restInvoker := core.NewRestInvoker()//并发安全,可全局使用	resp, err := restInvoker.ContextDo(context.TODO(), req)//执行调用,这时go chassis介入,执行一些列用户不可见的计算和操作	if err != nil {		log.Println(err)		return	}	b.Write(httputil.ReadBody(resp))//读出服务端body体并直接透传返回	return}
func (r *SimpleResource) URLPatterns() []rf.Route { return []rf.Route{ {Method: http.MethodGet, Path: "/hi", ResourceFunc: r.SayHi}, }}
func main() { chassis.RegisterSchema("rest", &SimpleResource{}) if err := chassis.Init(); err != nil { openlog.Fatal("Init failed." + err.Error()) return } chassis.Run()}
复制代码

验证:

go build main.go./main## 打开另一个终端,执行curl http://127.0.0.1:8000/hi
复制代码

将返回 HelloServer 的返回结果


此时 2 个微服务实例应该同时在线


完整例子

https://github.com/go-chassis/go-chassis-examples/tree/master/hello


小知识

为了提高系统的可用性,我们通常可以通过简单的扩容实例来达成。从概率来说这切实有效。假设一个实例的可用度为 0.995. 那么 2 个实例并联后,他们的可用性为

1-(1-0.995)的平方=0.999975
复制代码

在访问量大的情况下,我们也期望通过扩容来获得线性的吞吐增长。然而吞吐能力并非随着实例的数量呈线性增长。

通常在给定一个实例的规格后,需要进行 benchmark 测试找到该规格下,到底多大的实例数量能达到最佳性价比。后续就要通过优化代码来去提升吞吐了。这也是降成本的一种手法。


总结

本次,我们学会了开发简单的微服务,并且完成了 2 者的一次调用。


在实际使用中,可以启动数个服务端实例,提升服务可用性。


go chassis 通过客户端负载均衡与注册中新帮助屏蔽了网络拓扑的复杂性,只需要理解服务名即可。


扩展阅读

注册中心设计:https://www.jianshu.com/p/c676a69771bd


用户头像

田晓亮

关注

工程师,云计算老司机 2017.11.30 加入

还未添加个人简介

评论 (1 条评论)

发布
用户头像
学习的好材料
2020 年 09 月 09 日 22:58
回复
没有更多了
Go 云原生应用实战系列(二)