Gogap


  • 首页

  • 归档

Micro的架构与微服务的设计模式

发表于 2016-04-18 | 分类于 微服务

这是一系列介绍Micro框架的文章的第五篇,我将会把作者的博客翻译成中文,推广Micro这个微服务框架。

在过去的几个月,我们已经有了很多有关micro架构的疑问和微服务的设计模式的问题,今天我们讨论一下这两个话题。

关于Micro

Micro是一个微服务工具箱,它有自己固有的设计模式,但插件化的架构可以让底层的实现很轻易的被替换。

micro专注于定位微服务构建过程中的最基本的需求,并通过精密的设计来满足这些需求。

查看过往的文章可以了解微服务的理念和Micro的特性。

关于工具箱

Go Micro 是一个用golang编写的,插件化的RPC框架。它提供了基础的库,比如服务发现、客户端负载均衡、编解码、同步异步通信等。

Micro API是一个API网关,用于将外部的HTTP请求路由到内部的micro服务上。它有单一的接入点,可以通过反向代理或者http转换成RPC来访问。

Micro Web是一个web仪表盘,也是作为micro web应用的反向代理。我们相信web应用也应该是一个微服务,在微服务世界里也应该是第一等公民。它表现的很像Micro API但也有单独的特性比如websocket

Micro Sidecar使用http服务,提供了go-micro的所有特性。虽然我们喜欢golang来构建微服务,但你也许想使用其他语言。所以Sidecar提供了一种其他语言的应用接入Micro世界的方式。

Micro CLI是一个简单直接的命令行接口,用于与你的服务交互。他也可以使用你的Sidecar作为代理来连接服务。

上面是很简单的介绍,下面我们更加深入一些。

RPC,REST,Proto…

第一件你想到的事情是,为什么是RPC,而不是REST? 在内部服务间的通信上,我们相信RPC是更合适的。或者更明确一点,RPC使用protobuf做编码,通过protobuf定义API。这种方式把两个需求结合起来了:一个需求是需要明确定义的API接口,另一个需求是高性能的消息编解码。RPC是非常直接的通信方式。

我们在这个选择上并不孤独。

Google是protobuf的创造者,在内部通过gRPC这个框架,大量的使用RPC调用。Hailo也从RPC/protobuf的组合中收益很多,不仅是系统性能,开发速度也提高很多。Uber选择开发自己的RPC框架,名字叫TChannel

个人而言我认为未来的API将会使用RPC进行构建,因为它们结构化的格式、高效的编解码提供了定义良好的API和高性能的通信。

HTTP to RPC,API…

事实上,我们在web上RPC还有很长的路要走。在内部RPC的表现是完美的,但在面对外部请求比如网站、手机app的接口等等,就是另外一回事了。我们需要面对这个,这就是为什么Micro需要一个API网关,用来接受并转换http请求。

API网关在微服务架构中是一个常见的模式。它作为一个单一的接入点,外部世界的请求,通过它进行路由分发。它让HTTP API可以由背后的很多服务所组成。

micro的API网关使用路径到服务的解决方案,因此不同的请求路径,对应了不同的服务。比如/user => user api,/order => order api。

这里有一个例子。一个请求的路径是/comstomer/orders,这个请求会被转发到go.micro.api.customer这个服务,会使用 Customer.Orders.这个方法进行处理。

你也许会问,API服务到底是怎样的?我们下面来讨论一下不同类型的服务。

服务的类型

微服务的关键理念就是业务的拆解,这是从unix的设计哲学中得到的启示:『doing one thing and doing it well』,因为这个原因,我们认为不同的服务需要有逻辑上和架构上的区别,以实现自己不同的任务。

我们知道这些理念并没有什么太大的新意,但在一些非常大而且成功的公司,它们的实践取得了成功。我们的目标是传播这些开发理念,并通过工具来进行指导。

目前我们定义了下面的几种服务。

API

通过micro api运行,API 服务在你的架构中处于关键位置,大部分作用是接受外部世界的请求并分发到内部的服务上。你可以通过micro api提供的反向代理REST模式进行访问,也可以通过RPC接口进行访问。

WEB

通过micro web运行,web服务专注于服务html请求,构建仪表盘。micro web反向代理http和websocket,目前只有这两种协议支持,未来也许会增加。

SRV

这是后台的RPC服务,他们的目标是为你的系统提供核心的功能,大部分并不是公开的接口。你仍然可以通过micro api和micro web,使用/rpc接入点进行访问。这种接入方式直接使用go-micro的client进行调用。

按照过去的经验,我们发现这样的架构设计非常强大。可以被扩展到数以百计的服务。通过把它整合到Micro架构中,我们发现它为微服务的开发提供了非常好的基础。

Namespacing

你也许会想,怎样区分micro api或者micro web以及服务呢。我们通过命名空间进行拆分。通过命名的前缀,我们可以很清晰的看到,某个服务是哪种类型的。这很简单但很高效。

micro api也会把/customer这样的请求路径定位到go.micro.api.customer服务。

默认的命名空间是:

  • API - go.micro.api
  • WEB - go.micro.web
  • SRV - go.micro.srv

你应该把它设置成你的域名,比如com.example.api。这些都可以进行配置。

同步和异步

你经常听说微服务是很灵活的模式。大多数来说,微服务是关于创造事件驱动的架构,以及设计通过异步通信的方式响应的服务。

Micro把异步通信作为微服务构建中的第一等公民。事件通过异步消息,可以被任何人消费并作出反应,搭建一个新服务不需要对系统的其他部分作出任何更改。这是一种强大的设计模式,因为这个原因,我们在go-micro中定义了Broker接口。

异步和同步通信在Micro中是分离开的。 Transport 接口用于构建服务之间的点对点的通信。go-micro中的client和server基于transport来进行请求和返回RPC调用,提供了双向的通信流。

在构建系统时,两种通信方式都应该使用,但关键是理解在什么场景下应该用什么类型的通信方式。在大部分情况下并没有好坏之分,我们需要权衡处理。

一个broker和异步通信的典型使用方式是这样:监听系统通过broker对服务的事件历史进行记录。

在这个例子中,每个服务的每个API在被调用时,都会把事件上报到监听topic,监听系统会订阅这个topic,并把他们存储到时间序列的数据库中。在admin管理平台可以看到任何用户的操作历史。

如果我们通过同步通信做,监听系统直接面对巨大的请求数。如果监听系统宕机了,我们就丢失了这些数据。通过把这些事件发布到broker,我们可以异步的持久化这些数据。这是一种微服务中常见的事件驱动设计模型。

我们怎样定义微服务?

我们已经讨论了很多Micro能为微服务提供的工具箱,也定义了服务的类型。但还没有真正讨论,到底什么是微服务。

微服务与其他应用的区别到底在哪里,微服务为什么叫微服务。

现在有很多不同的定义,但有两条适合大部分微服务系统。

1
Loosely coupled service oriented architecture with a bounded context
1
An approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms

微服务的哲学与unix也类似

1
Do one thing and do it well

我们认为微服务是这样一种应用程序:专注于单一的业务,并通过明确定义的API对外提供服务。

看看我们在社交网络中怎样使用微服务:

其中一种是流行的MVC架构,在MVC世界中,每个实体代表了一个模型,模型又是作为数据库的抽象。模型之间也许有一对多或者多对多的关系。controller模块负责处理请求,接受model模块返回的数据,并把数据传输到view层,进行渲染,最后输出给用户。

在微服务架构中,面对同样的例子。每个模型实际上是一个服务,通过API进行服务间通信。用户请求,数据的集合以及渲染是通过一系列不同的web服务进行处理的。每个服务有自身的专注点,当我们需要增加一个新特性时,我们只需要把关联的服务进行修改,或者直接写一个新的服务。分离的理念提供了大规模开发的模式。

版本

开发真实世界的软件时,版本是非常重要的。在微服务世界里,严格的把API和业务逻辑分离到许多不同的服务上,因为这个原因,服务的版本控制是核心的工具的很重要的一部分。可以让我们在流量很大时也能进行升级。

在go-micro中,服务定义了名字和版本,Registry模块返回服务的列表,根据版本把节点进行了区分。这里是service的接口定义。

1
2
3
4
5
6
7
type Service struct {
Name string
Version string
Metadata map[string]string
Endpoints []*Endpoint
Nodes []*Node
}

板块控制需要与Selector结合起来,selector是客户端的负载均衡机制,通过selector的策略实现请求根据版本进行分发。

selector是非常强大的接口,我们根据不同的路由算法,比如随机、轮询、根据标签、响应时间等等。

通过使用默认的随机负载算法,再加上版本控制算法,我们就可以进行灰度发布。

在未来,我们会尝试实现一个全局的负载策略,根据历史的趋势进行选择,可以根据版本,设置不同的百分比,并动态的为服务增加标签。

大规模扩展

上面的介绍的版本系统,是大规模扩展服务时的基本模式。register存储了服务的注册信息,我们通过selector实现了路由和负载均衡。

按照doing one thing well的理念,扩展架构也应该是简单、明确定义的API、分层次的架构。通过创造这些工具,我们可以构建更加可靠的系统,专注于更高级别的业务需求。

这是Micro编写的基础理念,也是我们希望微服务开发者遵循的理念。

当我们在生产环境部署应用时,我们就需要构建可扩展、高容错、高性能的应用。云计算让我们可以进行不受限制的扩展,但是没有任何东西会一直正常运行。事实上,在构建分布式系统中,怎样对待运行失败的服务是非常重要的一方面,你在构建你的系统时,需要好好考虑。

在云计算的世界,我们想要在数据中运行错误,甚至多个数据中心运行错误的情况下,也能正常提供服务。在过去我们讨论的是冷热备份,或者是灾难恢复计划。在今天,最先进的技术公司,在全世界不停歇的运作,每个程序都会有多个备份,运行在世界上不同的数据中心。

我们需要向google,facebook,netflix和Twitter学习,即使在数据中心运行失败时,也要对用户提供服务,在多个数据中心运行失败时,也需要尽快恢复。

Micro可以让你构建这样的应用,通过插件化的架构,我们可以为不同的分布式系统,实现不同的工具箱。

服务发现和注册器是Micro的关键模块,它们可以用于发现在数据中心中的一系列服务,Micro API可以用于路由和负载一系列的服务。

总结

希望这篇文章清晰的讲解了Micro的架构,以及怎样实现可扩展的微服务设计模式。微服务首先是一种软件设计模式,我们可以通过工具实现基础、核心的功能,同时也能灵活组合其他设计模式。

因为Micro是一个插件化的架构,它强大的能力,可以实现不同的设计模式,在不同的场景中都能使用。比如你构建一个视频流的服务,你也许需要基于http的点对点服务。如果你对性能不敏感,你也许需要使用消息队列比如NATS或RabbitMQ。

使用Micro这样的工具进行开发是非常让人兴奋的。

如果你想了解更多,请看这个blog,或者这个repo,Twitter可以关注@MicroHQ,Slack社区在这里

基于消息队列NATS构建微服务

发表于 2016-04-11 | 分类于 微服务

这是一系列介绍Micro框架的文章的第四篇,我将会把作者的博客翻译成中文,推广Micro这个微服务框架。

这篇文章我们会讨论基于NATS使用Micro。讨论包括了服务发现,同步通信和异步通信。如果需要了解Micro,请翻看以前的文章。

NATS是什么?

NATS是一个开源的消息系统,或者说消息队列。NATS的作者是Derek Collison, Apcera的作者。它起源于VMWare,最开始是一个ruby的系统。后来使用golang进行重写,逐步的成为了一个高扩展性的高性能消息系统。

为什么是NATS?

为什么不是呢?过去我使用过很多消息队列,很明显NATS是鹤立鸡群的,在过去消息系统似乎成了企业的灵丹妙药了,结果是每个人参与的每个系统都离不开消息系统。导致了很多无效的承诺、高昂的研发投入,制造出比它解决的更多的麻烦。

NATS,相比之下,就十分专注,在难以置信的简洁之下,解决了性能问题,解决了高可用行问题。它的口号是『always on and available』,使用了一种『fire and forget』的消息模式。它简单、专注、轻量的特性使它在微服务的候选中脱颖而出。我们相信,在服务间的消息传递领域,它很快会变成主要的候选者。

NATS能提供什么?

  • 高性能、高扩展

  • 高可用

  • 极致的轻量级

  • 一次部署

    ​

NATS不支持什么?

  • 持久化
  • 事务
  • Enhanced delivery modes
  • Enterprise queueing

NATS是否适合Micro呢?我们接着讨论

Micro on NATS

Micro 采用插件化的架构设计,用户可以替换底层的实现,而不更改任何底层的代码。每个Go-Micro框架的底层模块定义了相应的接口, registry 是作为服务发现,transport作为同步通信, broker作为异步通信。

为每个组件创建一个插件很简单,只需要实现这些组件的接口即可。我们会在未来的文章里详细讨论,怎样写插件,如果你想详细了解NATS的插件或者其他的类似etcd作为服务发现,kafka作异步通信,rabbitmq作同步通信,在这里可以看到: github.com/micro/go-plugins

Micro on NATS本质上是实现一系列的插件,将NATS消息系统整合到Micro的框架中来。通过为Go Micro提供不同的插件,我们可以创造出很多灵活的组合。

在实践过程中,不能一套系统打天下,Micro on NATS的可以灵活的定义各种模型。

下面我们会讨论一下NATS插件怎样在transport,broker和registry下工作。

Transport

transport 是 go-micro定义的同步通信接口,它使用了泛型的语法描述,类似其他golang代码,比如Liesten,Dial,Accept。这些理念和模式在类似TCP和HTTP这样的同步通信中很容易理解,但是在消息系统中要怎样兼容呢?通信过程中,连接是与消息队列建立的,而不是服务本身。为了达到目的,我们使用消息系统中的topics和channels来创造虚连接。

它是怎样工作起来的?

一个服务使用transport.Listen来监听消息,这会与NATS之间建立连接。当transport.Accept被调用时,一个唯一的topic会被创建并订阅。这个唯一的topic地址会作为服务的地址,注册到go-micro的注册器中。每个收到的消息会被虚连接处理,如果一个连接已经存在,而且回复的地址是一样的,我们会简单的把消息积压在连接上。

客户端通过transport.Dial来连接服务端,其实它是建立了与NATS的连接,然后创建了唯一的topic并且订阅这个topic。这个topic用于接收服务端的返回。任何时候客户端发送消息到服务端时,它都会把回复地址设置成这个topic。(译注:服务端的地址是固定的,而客户端的每个请求,都会生成一个客户端地址,唯一的请求与唯一的地址实现一一关联)

当任何一边想要关闭连接时,简单的调用transport.Close就会断开与NATS的连接。

使用transport插件

引用插件

1
import _ "github.com/micro/go-plugins/transport/nats"

启动时传入参数

1
go run main.go --transport=nats --transport_address=127.0.0.1:4222

或者直接在代码中创建

1
transport := nats.NewTransport()

go-micro的transport接口:

1
2
3
4
5
type Transport interface {
Dial(addr string, opts ...DialOption) (Client, error)
Listen(addr string, opts ...ListenOption) (Listener, error)
String() string
}

Broker

broke是go-micro的异步通信接口,它定义了泛型的、高等级的通用接口。NATS本身作为消息系统,是可以作为消息broker的。这里只有一个警告:nats并不持久化消息。虽然在某些场景有风险,但我们相信NATS可以也应该用于go-micro的broker。持久化并不是必须的,它提供了高扩展的发布和订阅架构。

NATS通过Topics和Channels的理念,非常直接的实现了发布和订阅机制。这里并没有其他工作需要做。消息可以被发布到任何异步的fire and forget manner。通过NATS的Queue Group,订阅方可以通过channel的名字就行订阅。实现消息自动的分发的多个订阅者。

使用broker插件

引入包

1
import _ "github.com/micro/go-plugins/broker/nats"

(译注:注意此时引用的是broker中的nats包,上面引用的是transport中的nats包)

通过参数启动

1
go run main.go --broker=nats --broker_address=127.0.0.1:4222

也可以直接启动

1
broker := nats.NewBroker()

go-micro的broker需要实现的接口:

1
2
3
4
5
6
7
8
9
10
type Broker interface {
Options() Options
Address() string
Connect() error
Disconnect() error
Init(...Option) error
Publish(string, *Message, ...PublishOption) error
Subscribe(string, Handler, ...SubscribeOption) (Subscriber, error)
String() string
}

Register

注册器是go-micro定义的服务发现接口,你也许想过。用消息系统做服务发现?这能工作吗?事实上它不仅能工作,还工作的很好。许多人在服务发现中使用消息系统,避免了不一致的发现机制。这是因为消息队列通过topics和channels实现了路由,Topics定义为服务的名字可以作为路由的key,订阅topics的服务自动实现了负载均衡。

Go-micro把服务发现和传输机制看做两个不同的领域,任何时候,客户端向服务发起请求,都会首先在注册器中根据服务的名字查询到正在运行的服务节点,然后客户端通过transport与节点进行通信。

一般来说,最常见的存储服务发现信息的方式是通过分布式key-value store,比如zookeeper、etcd等等。正如你了解到的,NATS闭市一个分布式的KV store,我们将做一下改动。。。

广播查询!

广播查询正如你想象的那样,服务都会监听一个特点的topic,任何需要服务发现信息的都需要订阅这个topic,然后对这个topic做一个反馈。

因为我们并不知道有多少服务正在运行,我们对响应时间设置一个上限。这是一个粗糙的服务发现机制,但因为NATS本身的高扩展性和高性能,它运行的反而非常好。它也间接的提高了过滤服务节点的响应时间。未来我们会试着提高底层的实现。

我们总结一下它是怎么工作的:

  1. 创建一个reply topic并订阅
  2. 向广播topic发起查询,附带上reply topic
  3. 监听回复,超过限制时间就注销订阅
  4. 聚合响应并返回结果

使用register插件

引入包

1
import _ "github.com/micro/go-plugins/registry/nats"

通过参数启动

1
go run main.go --registry=nats --registry_address=127.0.0.1:4222

或者直接在代码中设置

1
registry := nats.NewRegistry()

go-micro中的register接口

1
2
3
4
5
6
7
8
type Registry interface {
Register(*Service, ...RegisterOption) error
Deregister(*Service) error
GetService(string) ([]*Service, error)
ListServices() ([]*Service, error)
Watch() (Watcher, error)
String() string
}

大规模在Micro中使用NATS

在上面的例子中,我们只是用了单个的NATS服务,但是在实际情况下,我们一般都是使用NATS集群来实现高可用和容错。你可以在这里看看更多NATS集群的知识。

Micro 在启动时可以接收一系列的参数,如环境变量等。如果直接使用client的库,也可以在创建时指定参数。

在目前云计算的架构下,我们过去的经验是,每个AZ都应该有集群。大部分的云计算公司,不同的AZ之间的延迟大概是3到5毫秒,集群的通信是没有任何问题的。当我们运行一个高可用的配置,你的系统必须要能在AZ宕机、甚至整个region崩溃时还能提供服务。我们不建议跨region部署集群。理想的高等级工具应该是用于管理多集群和多region系统。

Micro是一个极其灵活的微服务系统,它本身就被设计成运行在任何配置的任何地方。整个Micro世界是通过服务发现进行指导,服务的集群可以运行在机器集群中,AZ或者regions。再考虑到NATS集群,它可以让你构建高可用的服务。

总结

NATS是一个高可用和高性能的消息系统,在我们的微服务生态系统中运行的很好。它与Micro配合的非常的好,我们可以把它用在register,transport,broker中,我们也已经全部实现了这些插件。

NATS在Micro中的使用只是一个示例,它展示了Micro高度的插件化架构,每个go-micro的包都可以被替换,底层不需要改动代码,上层也只需要改动非常少的代码。在未来我们还会看到更多的Micro on X,下一个可能是Micro on kubernetes。

希望这可以鼓励你来使用Micro on NATS,或者编写自己的插件并回馈给社区。

在这里看更多的NATS插件github.com/micro/go-plugins

如果你想了解更多,请看这个blog,或者这个repo,Twitter可以关注@MicroHQ,Slack社区在这里

使用Go Micro编写微服务

发表于 2016-03-28 | 分类于 微服务

这是一系列介绍Micro框架的文章的第三篇,我将会把作者的博客翻译成中文,推广Micro这个微服务框架。

这是一个高等级的说明:怎样使用go-micro来编写微服务,如果你想学习更多微服务的知识以及Micro的整体架构,参考以前的文章。

什么是Go Micro?

Go Micro是一个插件化的基础框架,基于此可以构建微服务。Micro的设计哲学是『可插拔』的插件化架构。在架构之外,它默认实现了consul作为服务发现,通过http进行通信,通过protobuf和json进行编解码。我们一步步深入下去。

Go Micro是:

  1. 一个用Golang编写的包
  2. 一系列插件化的接口定义
  3. 基于RPC

Go Micro为下面的模块定义了接口:

  1. 服务发现
  2. 编解码
  3. 服务端、客户端
  4. 订阅、发布消息

更详细的说明可以在这里看到。

为什么是Go Micro?

Go Micro从一年多以前开始开发,最初只是个人需求,很快我发现这对那些编写微服务的程序员会有很大的价值。它基于我在不同的技术公司如google和hailo的开发经验编写而成。

就像前面提到的,Go Micro是一个golang编写的插件化架构,专注于提供底层的接口定义和基础工具。这些接口可以接纳各种实现。比如 Registry接口定义了服务发现的接口,默认采用了consul作为服务发现的实现,但也可以采用其他实现比如etcd和zookeeper等,只要能满足接口,就可以使用。

插件化的架构意味着如果你想替换底层的实现,你不需要修改任何底层的代码。

编写一个服务

如果你想直接看代码,看这里:examples/service

顶层的Service接口是构建服务的主要组件。它把底层的各个包需要实现的接口,做了一次封装。

1
2
3
4
5
6
7
8
type Service interface {
Init(...Option)
Options() Options
Client() client.Client
Server() server.Server
Run() error
String() string
}

初始化

一个服务可以这样创建micro.NewService

1
2
3
import "github.com/micro/go-micro"

service := micro.NewService()

参数可以在创建时传入

1
2
3
4
service := micro.NewService(
micro.Name("greeter"),
micro.Version("latest"),
)

所有可选的参数设置可以在这里看到

Go Micro也提供了读取命令行的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
import (
"github.com/micro/cli"
"github.com/micro/go-micro"
)

service := micro.NewService(
micro.Flags(
cli.StringFlag{
Name: "environment",
Usage: "The environment",
},
)
)

通过 service.Init来解析参数,附加的处理可以通过micro.Action解决

1
2
3
4
5
6
7
8
service.Init(
micro.Action(func(c *cli.Context) {
env := c.StringFlag("environment")
if len(env) > 0 {
fmt.Println("Environment set to", env)
}
}),
)

Go Micro提供了提供了预定义的参数,也会被service.Init解析,这里可以看到所有的flag

定义API

我们使用protobuf文件来定义服务的API,这是一种方便且严格的定义方式,协议将会提供给服务端和客户端。下面是一个协议的例子:greeter.proto

1
2
3
4
5
6
7
8
9
10
11
12
13
syntax = "proto3";

service Greeter {
rpc Hello(HelloRequest) returns (HelloResponse) {}
}

message HelloRequest {
string name = 1;
}

message HelloResponse {
string greeting = 2;
}

这里定义了一个服务叫做Greeter,它提供一个接口叫Hello,它接受HelloRequest的请求,返回HelloResponse。

生成API接口

我们使用protoc和proto-gen-go这两个工具来生成代码,Go Micro也会生成客户端代码,减少工作量,这里需要使用我们fork并修改过的github.com/micro/protobuf,与原始版本的区别是,fork版本能生成客户端代码

1
2
go get github.com/micro/protobuf/{proto,protoc-gen-go}
protoc --go_out=plugins=micro:. greeter.proto

生成的代码可以在handler中引用相应的包进行使用,下面是生成的一部分代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
type HelloRequest struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
}

type HelloResponse struct {
Greeting string `protobuf:"bytes,2,opt,name=greeting" json:"greeting,omitempty"`
}

// Client API for Greeter service

type GreeterClient interface {
Hello(ctx context.Context, in *HelloRequest, opts ...client.CallOption) (*HelloResponse, error)
}


type greeterClient struct {
c client.Client
serviceName string
}

func NewGreeterClient(serviceName string, c client.Client) GreeterClient {
if c == nil {
c = client.NewClient()
}
if len(serviceName) == 0 {
serviceName = "greeter"
}
return &greeterClient{
c: c,
serviceName: serviceName,
}
}

func (c *greeterClient) Hello(ctx context.Context, in *HelloRequest, opts ...client.CallOption) (*HelloResponse, error) {
req := c.c.NewRequest(c.serviceName, "Greeter.Hello", in)
out := new(HelloResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}

// Server API for Greeter service

type GreeterHandler interface {
Hello(context.Context, *HelloRequest, *HelloResponse) error
}

func RegisterGreeterHandler(s server.Server, hdlr GreeterHandler) {
s.Handle(s.NewHandler(&Greeter{hdlr}))
}

实现handler

服务端需要注册handler来处理请求,一个handler是一个这样的方法:

1
func(ctx context.Context, req interface{}, rsp interface{}) error

正如上面看到的,一个handler实现了API协议中定义的接口

1
2
3
type GreeterHandler interface {
Hello(context.Context, *HelloRequest, *HelloResponse) error
}

这里是一个Greeter的handler实现

1
2
3
4
5
6
7
8
import proto "github.com/micro/micro/examples/service/proto"

type Greeter struct{}

func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {
rsp.Greeting = "Hello " + req.Name
return nil
}

handler需要注册到某个服务

1
2
3
4
5
service := micro.NewService(
micro.Name("greeter"),
)

proto.RegisterGreeterHandler(service.Server(), new(Greeter))

运行服务

服务可以直接调用server.Run()来运行,这会让服务监听一个随机端口,这个调用也会让服务将自身注册到注册器,当服务停止运行时,会在注册器注销自己。

完整的服务端

greeter.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
"log"

"github.com/micro/go-micro"
proto "github.com/micro/go-micro/examples/service/proto"

"golang.org/x/net/context"
)

type Greeter struct{}

func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {
rsp.Greeting = "Hello " + req.Name
return nil
}

func main() {
service := micro.NewService(
micro.Name("greeter"),
micro.Version("latest"),
)

service.Init()

proto.RegisterGreeterHandler(service.Server(), new(Greeter))

if err := service.Run(); err != nil {
log.Fatal(err)
}
}

注意,服务发现机制需要首先运行起来,这样服务才能注册到注册器中,才能被客户端发现,这里有一个简单的介绍。

编写客户端

client 包用于向服务端发起请求,当你创建一个服务,客户端可以调用的接口已经自动生成了

调用上面的服务可以用下面的客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
/ create the greeter client using the service name and client
greeter := proto.NewGreeterClient("greeter", service.Client())

// request the Hello method on the Greeter handler
rsp, err := greeter.Hello(context.TODO(), &proto.HelloRequest{
Name: "John",
})
if err != nil {
fmt.Println(err)
return
}

fmt.Println(rsp.Greeter)

proto.NewGreeterClient就是我们刚才生成的代码,根据服务名称发送请求。

完整的示例可以在这里看到:go-micro/examples/service

总结

这篇文章是一个高等级的使用说明,介绍了怎样编写客户端和服务端代码,你可以在这里看到更多示例代码:github.com/micro

如果你想了解更多,请看这个blog,或者这个repo,Twitter可以关注@MicroHQ,Slack社区在这里

Micro - 微服务工具箱

发表于 2016-03-20 | 分类于 微服务

这是一系列介绍Micro框架的文章的第二篇,我将会把作者的博客翻译成中文,推广Micro这个微服务框架。

现在你也许听到了这个新现象:微服务。如果你对此不熟悉也有兴趣学习,欢迎参考上一篇文章。

这篇文章我们将讨论Micro - 一个开源的微服务工具箱,Micro提供了核心的必须工具来构建和管理微服务。它包含了一系列由golang开发的库和工具,同时也通过Sidecar特性与其他语言兼容。

在我们开始了解Micro之前,我们讨论一下为什么我们要把时间花费在它上面。

开发与部署

从我们过去在软件工程领域的经验可以很清晰的看到,我们有这样一种需求:专注于开发而不是部署。PasS的解决方案是可行的,类似AWS,Google和微软的公司,提供了功能丰富的平台,并快速的推进着容器技术(container)。所有的这些让我们点几下鼠标就能使用大规模计算服务。

新世界看着不错,你也许说这解决了你所有的问题,真的是这样吗?当我们能接触到大规模计算的能力时,仍然缺少工具来让我们发挥出大规模计算的优势。不仅如此,在这个新世界中,容器的生命周期变得更加短暂,在运行时调度中不断创建和销毁。

规模的挑战

另一个问题是,正如我们一次又一次看到的,我们一直是巨型架构的受害者。随着功能需求的增加,现在的趋势是在巨型系统上不断增加功能,直到不断增加的技术债务让我们回天乏术。除此以外,随着组织不断扩张工程师团队,开发者想要单独的进行代码开发,或者开发功能时不被其他人block,变得极其困难。

这是一种难以避免的需求:重新进行架构设计,使用SOA或者微服务架构。公司需要在研发上投入努力,在尝试和错误中学习。现在正需要这样一种工具来帮助我们构建可扩展系统,减少研发部门的阻碍,由在此领域有经验的人士为大家提供建议。

了解Micro

在Micro中我们构建了一个微服务生态系统,包括用于开发的基本的工具、服务和解决方案。我们已经构建好了基础的工具,这个工具与整个项目同名,也叫Micro,这一工具让我们更容易构建可扩展的架构,提供效率。

让我们更深入的挖掘Micro的特性。

Go Micro

Go Micro 是一个golang编写的用于构建微服务的插件化的RPC框架。它实现了服务创建、服务发现、服务间通信需要的功能需求。任何优秀的微服务架构都需要解决这三个基础问题:服务发现、同步通信和异步通信。

Go Micro包括以下这些包和功能

  • Registry:客户端的服务发现

  • Transport:同步通信

  • Broker:异步通信

  • Selector:节点过滤、负载均衡

  • Codec:消息编解码

  • Server:基于此库构建RPC服务端

  • Client:基于此库构建RPC客户端

    ​

Go Micro跟其他工具最大的不同是它是插件化的架构,这让上面每个包的具体实现都可以切换出去。举个例子,默认的服务发现的机制是通过Consul,但是如果想切换成etcd或者zookeeper 或者任何你实现的方案,都是非常便利的。官方实现的插件可以在这个地址看到:[github.com/micro/go-plugins]

插件化架构的最大好处是你可以选择你喜欢的平台来支撑微服务架构,但无需更改任何底层代码。Go Micro无需任何更改,只需要import你的插件,直接使用即可。

Go Micro是编写微服务的切入点,readme提供了说明包括怎样编写、运行和查询一个服务。这个greeter示例可以参考:micro/examples/greeter ,更多的服务示例可以在这个工程看到: github.com/micro

Sidecar

Go Micro提供了用Golang编写服务的方式,那么其他编程语言呢?我们怎样构建一个有兼容性的系统,让任何人都能受益于MIcro?虽然Micro是用golang编写的,我们提供了一个快速且方便的方式,让其他语言能够接入。

Sidecar是一个轻量级的组装服务,概念上来说就是将Micro的库提供的功能,依附于其他语言的主程序中。sidecar本质上是一个单独运行的服务,通过http提供接口,其他语言通过接口使用Go Micro提供的功能。

sidecar的特性:

  • 在服务发现系统进行注册
  • 发现其他服务
  • 与主程序进行健康检查
  • 作为代理与RPC系统通信
  • 通过websocket订阅

用ruby和python借助sidecar进行使用的例子可以在这里看到micro/examples/greeter,我们会提供更多示例,帮助理解sidecar的使用。

API

服务之间的请求是非常简单直接的,但从外部接入就要复杂一些。具体的服务实例可能会崩溃,重新调度,并监听随机的端口。API这个组件提供了一个接入点,外部的服务可以通过这个API网关向内部的服务发起请求。

API提供了几种不同的请求方式

/rpc

每个单独的服务可以通过/rpc这个接入点进行访问,示例如下:

1
2
3
4
5
6
7
curl \
-d "service=go.micro.srv.greeter" \
-d "method=Say.Hello" \
-d "request={\"name\": \"John\"}" \
http://localhost:8080/rpc

{"msg":"Hello John"}

api.Request

API也可以通过约定好的URL格式,请求到内部的服务,这是API服务的一个强大功能。经过URL解析能将路径转换成实际的请求,示例如下

请求

1
GET /greeter/say/hello?name=John

将会处理成

1
2
3
4
5
6
7
8
9
service: go.micro.api.greeter (default namespace go.micro.api is applied)
method: Say.Hello
request {
"method": "GET",
"path": "/greeter/say/hello",
"get": {
"name": "John"
}
}

这里看看通过protobuf定义的这个接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
syntax = "proto3";

message Pair {
optional string key = 1;
repeated string values = 2;
}

message Request {
optional string method = 1; // GET, POST, etc
optional string path = 2; // e.g /greeter/say/hello
map<string, Pair> header = 3;
map<string, Pair> get = 4; // The URI query params
map<string, Pair> post = 5; // The post body params
optional string body = 6; // raw request body; if not application/x-www-form-urlencoded
}

message Response {
optional int32 statusCode = 1;
map<string, Pair> header = 2;
optional string body = 3;
}

使用示例可以在这里看到:Greeter API

反向代理

最后一个API服务提供的功能是反向代理。正如上面例子中提到的,API服务可以通过路径解析到具体的服务,通过添加参数--api_handler=proxy 我们就可以支持REST风格的请求。反向代理只需要简单的在运行时天机--api_handler=proxy 参数即可。

使用API构建RESTful 风格的API可以在这个例子中看到:micro/examples/greeter/api

Web UI

web UI 提供了一个简单的界面观察运行中的系统,也可以进行一些交互。它提供了类似API这样的反向代理功能,我们的『web代理』也可以把开发好的其他web应用接入到web UI中,web UI与API一样仍然通过路径解析实现与内部服务的通信,通过websocket我们可以实时了解运行中系统的情况

CLI

CLI是一个命令行工具,让我们可以观察、交互和管理运行中的服务,当前的特性允许你查询服务注册,检查服务的健康情况,也可以对服务进行请求

其他有意思的特性包括,CLI可以使用Sidecar作为代理,只需要简单的设置参数:--proxy_address=example.proxy.com

组装在一起

我们已经写了一个全功能的示例,整体的执行过程是这样的:

  1. HTTP GET请求到API服务,请求地址是:/greeter/say/hello with the query name=John
  2. API服务将请求解析并转换成默认的服务形式,服务是go.micro.api.greeter,方法是 Say.Hello
  3. API使用Go Micro,查询注册器中服务go.micro.api.greeter注册的所有节点,根据负载均衡算法,选择其中一个节点,发出请求
  4. go.micro.api.greeter服务收到请求,解析到结构体,去注册器查询到go.micro.srv.greeter这个服务,发送请求
  5. greet server处理完成后,返回相应的内容到greet api
  6. greet api转换greet服务的响应内容到 api.Response,返回到API服务
  7. API服务解析请求,返回HTTP请求

整体流程如下:

有更复杂的例子,比如API服务请求多个服务,组装多个服务的返回内容。示例如下:greeter service

Demo

如果你想看看正在运行中的系统,在这个页面查看:web.micro.pm

我们运行了一个Micro在Kubernetes上,demo是开源的,你可以运行一下:github.com/micro/kubernetes

总结

Micro提供了基础的工具用于编写和管理微服务,Go Micro包括了核心的必须功能:服务发现、客户端、服务端和订阅、发布。CLI可以让你与运行中的服务进行交互。Sidecar可以让你接入其他非Micro应用。API是一个单独的接入点来调用内部的服务。借助于插件化的接口,你可以灵活选择各种组件来提升你的微服务。

在Micro我们的目标是让开发人员在一开始就能应对大规模开发,提高工作效率。我们感觉Micro是最好的选择。随着时间推移,整个微服务生态系统功能会更加完善。

如果你想了解更多,请看这个blog,或者这个repo,Twitter可以关注@MicroHQ,Slack社区在这里

Micro - 微服务生态系统

发表于 2016-03-17 | 分类于 微服务

这是一系列介绍Micro框架的文章的第一篇,我将会把作者的博客翻译成中文,推广Micro这个微服务框架。

让我们讨论一下软件开发的特性。

变化总是在进行中,我们越来越接近一个被技术和商业驱动的社会,维持竞争能力变得越来越困难,如果采用低效的平台、结构和代码,组织将会越来越低效。创立十年以上的技术公司正在经历扩张带来的技术痛苦,但大部分仍然采用旧有的技术解决新问题。

是时候把世界上最成功的公司的竞争优势分享给其他人了,现在我们讨论微服务,一种构建你的核心技术优势的手段。

什么是微服务?

微服务是一种软件架构模式,用于将大型架构拆解成小型模块,服务之间使用灵活的协议进行通信,使各个服务专注于自身的业务。

用学院派的定义来说明微服务:

  • Loosely coupled service oriented architecture with a bounded context

  • An approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms

微服务并不是一个新的概念,这是一种新的服务架构模式,但早在unix中类似的理念就出现在进程和管道中。

微服务架构的哲学是这样的

  • 服务是很小的,单一的服务只做单一的业务,类似unix中的 『Do one thing and do it well』
  • 应该适合进行自动化部署和测试,可以轻易的减轻运维和管理的负担
  • 系统必须有很好的容错性,健壮性

为什么是微服务?

随着组织的技术和人员扩张,庞大的代码已经越来越难以维护。我们都认为twitter会失败,因为他们尝试在现有的巨大的系统上不断进行产品需求的开发。微服务的理念让Twitter分解整个应用为很小服务,每个服务都被单个小型团队负责。每个团队都为整个系统负责,而每个服务又可以单独的进行部署。

alt

我们从第一手的经验知道了微服务让开发周期进行的更快,提高了生产力,构造了优秀的可扩展系统

我们看一下其中的一些好处:

  • 更容易进行开发:不同的团队根据不同的需求,管理好自己的服务即可
  • 更容易理解:微服务很小,经常是1000行或者更少
  • 更容易频繁的部署新版本:服务很容易独立的进行部署、扩展和管理
  • 提高了错误的容忍度和错误隔离:单个服务的错误不会对其他服务造成影响
  • 提高了执行的速度:团队独立的开发、部署和管理微服务将使需求实现的更快
  • 服务可以重用:unix的设计理念影响了微服务,这让你可以复用很多服务

    ​

什么是Micro?

Micro是一个微服务的生态系统,专注于为当代科技驱动的企业提供产品、服务和解决方案。我们计划为企业提供微服务资源以提高企业的技术水平。从早期的产品原型到大规模产品的部署都有解决方案。

我们看到了行业的基本的转折点正在到来,摩尔定律在起作用,我们拥有了越来越多的能力,而我们并不能完全了解这些全新的能力,当前的工具和开发实践不能在新的领域再起作用。开发者没有获得工具来从庞大的代码系统转向更加高效的设计架构。大部分公司会经历到一个节点即大量的研发投入到庞大的系统中,但没有产生相应的产出。Netfix,Twitter等公司都经历了这些,结局都是构建自己的微服务平台。

我们的愿景是提供基础的工具让任何人都能受益于微服务,我们已经开始行动,基于开源的微服务工具包Micro ,接下来将会有一系列的文件介绍各个工具。

如果你想了解更多,请看这个blog,或者这个repo,Twitter可以关注@MicroHQ,Slack社区在这里

12

Gogap

15 日志
3 分类
3 标签
RSS
GitHub
© 2018 Gogap
由 Hexo 强力驱动 v3.7.0
|
主题 — NexT.Gemini v6.1.0