net/http

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

所以说搭建一个有许多应用的分布式系统比较难。Koding的Kite库旨在以一种简单快捷轻便的方式搭建分布式微服务应用。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()
}
Run()http.Serve
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())
}
http.Handlerkite.pingpongkite.ping
$ go run second.go
pong

为Kite添加方法

squarekite.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),可以获取令牌并验证用户提供的内容等等。

kitectlkitectl registerkite.key

我们将使用先前的例子,不过这次会把 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()Register()kite.keyRegister()
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()GetKites()
first

这一切都交给了调用方。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)并随意使用。欢迎贡献!让我知道你的想法。