Ktor整合nacos注册中心

说起微服务,对于一直使用 java 生态的用户来说,首先想到的应该是 spring cloud 。Spring cloud 已经成为了 java 微服务中重要的标杆。但是同样是 jvm 语言的 kotlin 就没有这样好的环境了,虽然 kotlin 可以使用 spring 生态,而且 spring 在逐步整合 kotlin 的特性。

ktor 是 JetBrains 开发的 kotlin 框架,完全基于 kotlin。kror 提供了官方提供了很多 feature 使用。但是在使用过程中总会有一些功能是官方没有提供的。这时候就需要我们自己去完成。

ktor 程序是有一系列的feature组成的。通过feature,我们可以自由的更改请求和响应。通过 install 方法将 feature 安装到应用里。例如:

1
2
3
4
5
6
7
8
9
fun Application.main() {
    install(DefaultHeaders)
    install(CallLogging)
    install(Routing) {
        get("/") {
            call.respondText("Hello, World!")
        }
    }
}

而官方提供的一系列 feature 中,不可能满足我们所有的需求,此时就需要自定义我们的feature。

针对自定义feature,官方也给了一篇简短的文档来说明如何自定义。定义一个 feature 主要是实现新的 ApplicationFeature 接口的伴生对象,并且去实现它的方法。

这里面主要有一个属性 key 和一个方法 install

1
2
3
public val key: AttributeKey<TFeature>

public fun install(pipeline: TPipeline, configure: TConfiguration.() -> Unit): TFeature

key 属性是一个唯一的标识,用来标识当前的 feature。而 install 方法为 feature 的主要实现功能。

install 方法中可以初始化 feature 功能。

通过查阅 nacos 的官方文档,可以了解到如何将服务注册到 naocs 上。在install里完成逻辑代码,install里面的逻辑只会执行一次,但是如果想每次请求和响应都需要执行方法,那么可以使用 pipeline.intercept

以下是 naocs 的注册实现,当然还有很多功能去完成。方法内有 NacosCOnfig 方法,通过该方法来读取 ktor 的 application.conf 配置文件。其中一些配置是我们需要写在 application.conf 中的,比如 nacos 的端口和地址。

1
2
3
4
nacos {
    port: 8848
    address: 127.0.0.1
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@KtorExperimentalAPI
override fun install(pipeline: ApplicationCallPipeline, configure: Configuration.() -> Unit): NacosDiscover {
    val nacosConfig = NacosConfig()
    val config = HoconApplicationConfig(ConfigFactory.load())
    val ktorConfig = config.config("ktor")
    val ktorPort = ktorConfig.propertyOrNull("deployment.port")?.getString()?.toInt() ?: 8080
    val configuration = Configuration().apply(configure)
    val feature = NacosDiscover(configuration)
    val addr = InetAddress.getLocalHost();
    val serverAddress = addr.hostAddress
    // 应用启动时进行
    val naming = NamingFactory.createNamingService("${nacosConfig.nacosAddress}:${nacosConfig.nacosPort}")
    val instance = Instance()
    instance.ip = serverAddress
    instance.port = ktorPort
    instance.serviceName = feature.serverName
    instance.isHealthy = true
    val mateData = HashMap<String, String>()
    mateData["framework"] = "ktor"
    instance.metadata = mateData
    naming.registerInstance(feature.serverName, instance)
    return feature
}

具体代码可以看 Github ktor-nacos ,这样就完成了服务注册。

当服务注册到 naocs 上的时候,此时就需要通过客户端进行请求。所以需要编写客户端的 feature。

客户端的 feature 主要作用是通过服务名获取服务的详细信息,然后去请求对应的服务。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
override fun install(feature: NacosClient, scope: HttpClient) {

    val nacosConfig = NacosConfig()
    val naming = NamingFactory.createNamingService("${nacosConfig.nacosAddress}:${nacosConfig.nacosPort}")
    scope.requestPipeline.intercept(HttpRequestPipeline.Render) {
        val instances = naming.getAllInstances(context.url.host).filter { it.isHealthy and it.isEnabled }
        val selectedNode = instances[currentNodeIndex]
        context.url.host = selectedNode.ip
        context.url.port = selectedNode.port
        currentNodeIndex = (currentNodeIndex + 1) % instances.size
    }
}

并且添加了负载均衡,每次将请求转发到不同的服务上。

通过对 ktor 的基本了解,主要是通过编写 feature 和 pipeline 进行插件功能的实现。目前 ktor 的生态还很不完善,只提供了基础的组件,还有很多组件需要自己去整合完成,还需要社区不断的贡献。

项目已经开源到Github上。youngxhui/ktor-nacos

补充一个 ktor 资源网站 https://www.kotlinresources.com/#

https://ktor.io/docs/advanced-features.html

https://github.com/piomin/sample-kotlin-ktor-microservices

相关内容