原文链接:https://blog.gopheracademy.com/birthday-bash-2014/kite-microservice-library/ 此为中文翻译

用GO语言来编写web服务是一件很轻松的事。简单而又强大的net/http包允许你以一种快速的方式编写高性能的web服务。然而,有时候你仅仅想要编写一个RPC后端应用。本质上,你想有很多独立运行的应用程序,他们各自负责自己的那块工作。他们应当接收请求并恰当的回复。

很显然,一旦脱离了基本的需求,事情就变得复杂了。在真实场景中,你可能拥有数百个正在运行的web服务,并希望能和他们安全的(并经过身份验证)通信交流。为了达成这一目的,首先必须与某一个应用建立连接。除非你只有很少的几个应用节点,你很难记住某个特定应用的IP地址或hostname(有太多应用)。仅仅把所有host的IP地址持久化储存也是不够的,因为host IP可能改变。你需要的是一个能让你访问、询问并取得某应用IP地址的服务,就像DNS服务器。

所以说搭建一个有许多应用的分布式系统比较难。KodingKite库旨在以一种简单快捷轻便的方式搭建分布式微服务应用。Kite框架本身有很多细节部分,在这篇文章中只会大概阐述Kite能干什么。

Kite介绍

Kite是一个用GO语言编写的微服务RPC框架,它使得用户能编写清晰易懂的分布式系统。它在便捷使用和性能之间找到了一个平衡。Kite既是一个RPC服务器又是客户端。它能与其它的Kite同伴进行双向通信。一个Kite节点由以下参数确定(顺序很重要):

  1. Username: Kite的拥有者,比如 Brian, Fatih, Damian etc..
  2. Environment: 当前环境,比如 “production”, “testing”, “staging”, etc…
  3. Name: 标识Kite类型的简称,比如 mykite,fs,terminal, etc…
  4. Version: 三位数的语义版本(semantic version)
  5. Region: 当前地区,比如 “Europe”, “Asia” 或其他地方
  6. Hostname: Kite的hostname
  7. ID: 唯一ID,用来确定一个Kite。由Kite框架生成,也可以自行更改

这些标识符很重要因为Kite就是通过他们来让他人鉴别和搜索自己。

Kite使用SockJS在很多不同传输方法(websocket, xhr, etc..)提供WebSocket模拟(emulation ),这意味着你也可以通过浏览器来链接Kite(见Kite.js)。Kite使用修改过的dnode protocal来进行RPC消息传递。Kite协议增加了一个额外的session和authentication层,这样就能轻松地识别Kite。在后台,它使用JWT进行身份验证和会话信息管理。

通过“Kontrol”这个服务发现机制,一个Kite可以发现其他Kites与他们安全地进行身份验证通信。Kontrol使用etcd作为后台储存。但是你也用其他的替代(当前支持PostgreSQL),只要它实现了 kontrol.Storage接口。Kontrol同时也有许多认证用户的方式。这是可定制的所以人们能用自己方式使用Kontrol。

如何使用Kite

我们现在来学习一下。编写Kite并让他们之间通信很有趣。首先,介绍一个最简单的形式(原谅我忽略了错误处理,你不应该像我这样:))

package main

import "github.com/koding/kite"

func main() {
k := kite.New("first", "1.0.0")
k.Run()
}

这里我们创建了一个kite,它的名字是first,版本是1.0.0。Run()方法用来启动一个阻塞服务器(就像http.Serve)。它现在能够接受请求。由于没分配端口号,操作系统会自动为我们分配一个。

现在我们分配一个端口号,这样我们就能使另一个kite和他连接(否则,你需要从日志中选择分配的URL)。为了更改Kite配置,例如端口号,一些属性(Environemt, Region, etc...),你需要更改Config域:

package main

import "github.com/koding/kite"

func main() {
k := kite.New("first", "1.0.0")
k.Config.Port = 6000
k.Run()
}

如有需要,配置值也可以被环境变量覆盖。

让我们创建第二个kite来和第一个kite通信:

package main

import (
"fmt" "github.com/koding/kite"
) func main() {
k := kite.New("second", "1.0.0") client := k.NewClient("http://localhost:6000/kite")
client.Dial() response, _ := client.Tell("kite.ping")
fmt.Println(response.MustString())
}

这回我们直接连接新的kite,因为我们已经知道了URL。对于一个RPC系统,你得有URL路径的概念。Kite使用方法名来让别人调用。每个方法对应一个Handle(就像http.Handler)。Kite框架有一些默认的方法,其中一个就是kite.ping,它返回一个pong字符串作为响应(他不需要任何身份验证信息)。响应可以是任何东西,从能被序列化的GO类型到JSON,这取决于发送方。Kite也有一些预先定义好的辅助方法来把响应转换成给定类型。在这个例子里,second kite 和 first kite 连接并调用了first kite 的 kite.ping方法。我们没有传递任何参数(下面将解释),所以如果你运行,可以看到:

$ go run second.go
pong

为Kite添加方法

现在我们添加第一个自定义方法。这个方法用来接收一个值并返回它的平方值。方法名字是square。要将函数分配给方法,只需确保其满足 kite.Handler接口kite.Handler :

package main

import "github.com/koding/kite"

func main() {
k := kite.New("first", "1.0.0")
k.Config.Port = 6000
k.Config.DisableAuthentication = true k.HandleFunc("square", func(r *kite.Request) (interface{}, error) {
a := r.Args.One().MustFloat64()
return a * a, nil
}) k.Run()
}

通过 second kite 调用:

package main

import (
"fmt" "github.com/koding/kite"
) func main() {
k := kite.New("second", "1.0.0") client := k.NewClient("http://localhost:6000/kite")
client.Dial() response, _ := client.Tell("square", 4)
fmt.Println(response.MustFloat64())
}

可以看到,唯一改变的是方法调用。调用 "square" 方法也传递了参数4。运行例子得到:

$ go run second.go
16

就这么简单。

服务发现,如何找到对方

服务发现被集成到了Kite框架中。就像前面所说,这是一个非常基本的概念,并且在Kite API也得到了充分体现。这意味着Kite框架强制用户使用服务发现机制。为了能发现自己,对方要知道你的真实身份。也就是说你需要进行身份验证。身份验证可以通过多种方法完成,这取决于Kontrol怎么执行。它可以被完全禁用,可以询问用户密码(通过kite cli),可以获取令牌并验证用户提供的内容等等。

kitectl是一个方便的CLI程序,可用于通过命令行轻松管理kites。我们可以用它(通过 kitectl register 命令)来向Kontrol认证我们的host,所以I每个运行在我们host的kite实例将默认被验证。这个命令在home目录下创建kite.key文件,它由kontrol自己签名认证。其中内容没有加密,但是因为已签名,所以可以用它和Kontrol安全交流。我们的用户名会被储存到Kontrol中,所以其他人可以信任我们(当然他们得使用同一个Kontrol服务器)。相信Kontrol意味着可以相信任何人。这很重要因为可能会有其他的Kontrol服务器,他们也在你的内网中或者是公开的。

我们将使用先前的例子,不过这次会把 first kite 注册到Kontrol并从 second kite 取得它的IP地址:

package main

import (
"net/url" "github.com/koding/kite"
) func main() {
k := kite.New("first", "1.0.0")
k.Config.Port = 6000
k.HandleFunc("square", func(r *kite.Request) (interface{}, error) {
a := r.Args.One().MustFloat64()
return a * a, nil
}) k.Register(&url.URL{Scheme: "http", Host: "localhost:6000/kite"})
k.Run()
}

如你所见, 我们用Register()方法把自己注册到Kontrol中。唯一传递的参数时我们自己的URL,其他人可以通过它和我们连接。这个值保存在Kontrol中,其他kite实例可以从那里获取到它。Register()方法很特殊,如果你断开连接并重连,它会自动重新注册。为了保护Kontrol,我们使用了exponential backoff算法进行重连尝试。因为Koding在实际生产也大量是用它,所以有许多类似这样的小细节小改进。另一点是注册时你不需要传递Kontrol的URL,因为你已经通过验证,Kontrol的URL被存放在kite.key中了。你要做的仅仅是调用Register()方法。

现在我们寻找first kite并调用其square方法:

package main

import (
"fmt" "github.com/koding/kite"
"github.com/koding/kite/protocol"
) func main() {
k := kite.New("second", "1.0.0") // search a kite that has the same username and environment as us, but the
// kite name should be "first"
kites, _ := k.GetKites(&protocol.KontrolQuery{
Username: k.Config.Username,
Environment: k.Config.Environment,
Name: "first",
}) // there might be several kites that matches our query
client := kites[0]
client.Dial() response, _ := client.Tell("square", 4)
fmt.Println(response.MustFloat64())
}

首先GetKites()方法获取了一个list,其中包含匹配我们查询的所有kites。GetKites()连接到Kontrol并获取所有URL匹配给定查询的kites节点。该查询必须采用树路径形式(与etcd中使用的格式相同),所以Username和Environment需要在你搜索first kite之前给定。在这个例子中,我们假定只有一个匹配上了,接着取出它,拨号并调用方法,这样就能得到和之前一样的结果。

因此,动态注册和获取kites是一件大事。你可以设计一个分布式系统,它能容忍你定义的某些条件。一个例子是开启10个first kites,每个都以你的名字命名。如果另一个kite节点从Kontrol中获取,它会得到一个包含10个kite节点及其URL的list,之后该怎么做完全取决于这个kite实例。可以随机挑选一个,也可以轮询调用,抑或是ping所有list里的kite节点并选取最快的一个等等。

这一切都交给了调用方。Kontrol并不知道某个kite实例会有什么行为,它只知道该节点是否连接(注册)上了。这样的简化让使用者可以基于该框架构建更复杂的系统。

结论

Kite框架还有许多其它这里没涉及的小改进与特性。比如Kite.js可以在浏览器上作为客户端使用。它还包含一个等效node.js的服务器。它包含开箱即用的通道代理和反向代理,可用于在单个端口/应用后面多路复用kite。Koding正在实际生产中使用它,因此默认情况下它具有许多基于性能的修复和改进。

编写Kite并使用它是最重要的部分。一旦开始使用它,你就可以感受到API的简单性。Kite库易于使用,因为它与Go具有相同的理念。它使用一些用Go编写的最好的开源项目(例如etcd)。Go使编写稳定平台作为Kite库的基础变得简单。由于Go的性质,扩展和改进Kite库也很容易。

希望你对这个框架的想法和意图及其功能和局限性有所了解。我们正在广泛使用和维护它。但是,我们也有很多事情想改进(例如提供其他消息协议和传输协议)。尽情fork项目(https://github.com/koding/kite)并随意使用。欢迎贡献!让我知道你的想法。

Kite: 一个分布式微服务框架(翻译)的更多相关文章

  1. Surging 分布式微服务框架使用入门

    原文:Surging 分布式微服务框架使用入门 前言 本文非 Surging 官方教程,只是自己学习的总结.如有哪里不对,还望指正. 我对 surging 的看法 我目前所在的公司采用架构就是类似与S ...

  2. [转载]Surging 分布式微服务框架使用入门

    前言 本文非 Surging 官方教程,只是自己学习的总结.如有哪里不对,还望指正. 我对 surging 的看法 我目前所在的公司采用架构就是类似与Surging的RPC框架,在.NET 4.0框架 ...

  3. 推荐一款分布式微服务框架 Surging

    surging   surging 是一个分布式微服务框架,提供高性能RPC远程服务调用,采用Zookeeper.Consul作为surging服务的注册中心,集成了哈希,随机,轮询,压力最小优先作为 ...

  4. Dapeng框架-开源高性能分布式微服务框架

    我们公司性质是新零售,公司也有专门的框架组.这群大牛自己开发了一整套分布式微服务框架.我们也在使用这套框架,有很多心得体会. 该框架既Dapeng也!开源github地址:https://github ...

  5. .Net Core 分布式微服务框架 - Jimu 添加 Swagger 支持

    系列文章 .Net Core 分布式微服务框架介绍 - Jimu .Net Core 分布式微服务框架 - Jimu 添加 Swagger 支持 一.前言 最近有空就优化 Jimu (一个基于.Net ...

  6. .Net Core 分布式微服务框架介绍 - Jimu

    系列文章 .Net Core 分布式微服务框架介绍 - Jimu .Net Core 分布式微服务框架 - Jimu 添加 Swagger 支持 一.前言 近些年一直浸淫在 .Net 平台做企业应用开 ...

  7. Net Core 分布式微服务框架

    Jimu : .Net Core 分布式微服务框架介绍 https://www.cnblogs.com/grissom007/p/9291345.html 一.前言 近些年一直浸淫在 .Net 平台做 ...

  8. 我的分布式微服务框架:YC-Framework

    YC-Framework官方文档:http://framework.youcongtech.com/ YC-Framework源代码:https://github.com/developers-you ...

  9. 反应式微服务框架Flower

    Flower是一个构建在Akka上的反应式微服务框架,开发者只需要针对每一个细粒度的业务功能开发一个Service服务,并将这些Service按照业务流程进行可视化编排,即可得到一个反应式系统. 即时 ...

随机推荐

  1. ado.net Web前端:关于JavaScript知识点的简单梳理

    学习js:1.htmml2.cssjs+html+css == html5 js的组成:1).ecamscript ES是js的标准,js 是es 的实现2)文档对象模型(Document Objec ...

  2. 玩Python小游戏猜数字,在游戏中掌握基础,你还能学不会?

    学python怎么离得开案例呢? 今天再继续给大家分享一个Python教程里的猜数字游戏     我最近也是在学python,从事编程工作几年了,但是python还是今年才开始玩的,不得不说,这真是一 ...

  3. uni-app之实现分页

    一.下载库 官方文档地址为:https://ext.dcloud.net.cn/plugin?id=32 点击下载zip压缩包即可,下载完毕后解压到放置前端相关组件目录,即components目录. ...

  4. django xadmin 配置过程

    1.拷贝xadmin的一个下的一个xadmin文件夹放到项目里

  5. Javascript数组迭代精髓,拿去花

    数组迭代 数组迭代是处理各数组的利器,编写代码时常常会用到,为我们提供了大大的便利.如果还不知道,真的别告诉别人你知道js哈哈. 以下迭代方法均不会改变原数组,带*为必选对象. 1.arr.forEa ...

  6. 都在讲DevOps,但你知道它的发展趋势吗?

    根据最近的一项集体研究,DevOps的市场在2017年创造了约29亿美元的产值,预计到2022年,这个数字将达到约66亿美元.人工智能的融入和安全性的融入,加上向自动化的巨大转变,可合理预测,在202 ...

  7. SpringBoot项目部署到tomcat

    SpringBoot部署到tomcat 一.修改maven.xml 1.添加<.packaging>war</.packaging>,打包为war包 <packaging ...

  8. 个人对于flask中蓝图的理解

    什么是蓝图? 蓝图可以理解为,是一种对项目中的代码进行模块化管理的工具,相当于python中的包为什么要使用蓝图? 在一个py文件中具有多个功能代码,不利于维护和管理. 如果在其他的模块中去调用视图函 ...

  9. matlab添加toolbox失败的解决办法

    matlab添加toolbox有三种方法: 1.在网上下载对应的文件,再复制到matlab安装路径中的toolbox文件夹里. 结果:失败.仍然显示不能用该模块. 2.由于笔者的学校有买正版,所以可以 ...

  10. css3动画添加间隔

    因项目需要,需要在元素上实现动画效果,并且需要有动画间隔.坑爹的是animation-delay只有在第一次动画开始的时候才起效. 在网上找了很多方法,最终的方法基本都是改动画规则,比如 @keyfr ...