Spring Clould Sidecar整合异构服务(Finchley版本)

本节我们主要讨论一下异构平台(比如,nodejs、python、php等提供的Rest接口服务)的服务,怎么通过spring cloud组件对这些服务注册到eureka中心以及与在微服务中怎么和异构平台的服务进行通信。这里主要是通过spring cloud的sidecar来构建异构平台的服务注册与通信。

sidecar灵感来自Netflix Prana。它可以获取注册中心的所有微服务实例的信息(例如host,端口等)的http api。也可以通过嵌入的Zuul代理来代理服务调用,该代理从Eureka获取其路由条目。 Spring Cloud配置服务器可以通过主机查找或通过嵌入的Zuul直接访问。

涉及到的服务如下:

服务名 端口 用途
eureka-server 8100 服务注册与发现
nodeSidecar 8130 异构服务对接服务
node 3000 nodejs服务
consumer 8106 消费者服务,与node服务存在声明式调用

1.1 Sidecar

1.1.1 Sidecar服务

先来看一下引入Sidecar需要做一些什么。

1. 添加 Maven 依赖,很简单,甚至不需要eureka-client的依赖,因为它已经整合至 Sidecar 的依赖中
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-netflix-sidecar</artifactId>
    </dependency>
</dependencies>
2. 接下来是注解,在 Sidecar 主类上添加@EnableSidecar注解,我们来看看这个注解包含些什么
@EnableCircuitBreaker
@EnableZuulProxy
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(SidecarConfiguration.class)
public @interface EnableSidecar {

}

包含了网关 Zuul 以及微服务结构中不可或缺的熔断器 Hystrix

3. 最后是配置文件,在application.yml中添加如下配置
server:
  port: 8130
spring:
  application:
    name: nodeSidecar
eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:9090/eureka/
sidecar:
  port: 3000
  health-uri: http://localhost:${sidecar.port}/health

声明服务名和注册中心地址都没什么问题,最核心的就是 sidecar 的几个配置,包括

  • sidecar.port 监听的 Node 应用的端口号,
  • sidecar.health-uri Node 应用的健康检查接口的 uri

1.1.2 健康检查接口

需要注意的是:Node.js 的微服务应用必须实现一个/health健康检查接口,Sidecar 应用会每隔几秒访问一次该接口,并将该服务的健康状态返回给 Eureka,该接口只需要返回{ status: 'UP' }这样一串Json即可。


var http = require('http');
var url = require("url");
var path = require('path');

// 创建server
var server = http.createServer(function(req, res) {
    // 获得请求的路径
    var pathname = url.parse(req.url).pathname;
    res.writeHead(200, { 'Content-Type' : 'application/json; charset=utf-8' });
    if (pathname === '/index') {
        res.end(JSON.stringify({ "index" : "欢迎来到首页" }));
    }
    else if (pathname === '/health') {
        res.end(JSON.stringify({ "status" : "UP" }));
    }
    // 其他情况返回404
    else {
        res.end("404");
    }
});
// 创建监听,并打印日志
server.listen(3000, function() {
    console.log('listening on localhost:3000');
});

1.2 服务注册

准备好eureka,nodeSidecar,node服务。按顺序启动eureka->node服务->nodeSidecar

  • 访问Eureka的WebUIhttp://localhost:8100/eureka-server,nodeSidecar服务以被注册到Eureka上,并且状态为UP。
    eureka webui
  • 访问 Sidecar 的首页http://localhost:8130/,提供了三个接口
    eureka webui
  • 访问hosts/nodeSidecar可以的到 nodeSidecar 实例的一些信息
    [
        {
            "host": "192.168.216.1",
            "port": 3000,
            "uri": "http://192.168.216.1:3000",
            "metadata": {
                "management.port": "8130"
            },
            "serviceId": "NODESIDECAR",
            "secure": false,
            "instanceInfo": {
                "instanceId": "localhost:nodeSidecar:8130",
                "app": "NODESIDECAR",
                "appGroupName": null,
                "ipAddr": "192.168.216.1",
                "sid": "na",
                "homePageUrl": "http://192.168.216.1:3000/",
                "statusPageUrl": "http://192.168.216.1:8130/actuator/info",
                "healthCheckUrl": "http://192.168.216.1:8130/actuator/health",
                "secureHealthCheckUrl": null,
                "vipAddress": "nodeSidecar",
                "secureVipAddress": "nodeSidecar",
                "countryId": 1,
                "dataCenterInfo": {
                    "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
                    "name": "MyOwn"
                },
                "hostName": "192.168.216.1",
                "status": "UP",
                "overriddenStatus": "UNKNOWN",
                "leaseInfo": {
                    "renewalIntervalInSecs": 30,
                    "durationInSecs": 90,
                    "registrationTimestamp": 1537408212824,
                    "lastRenewalTimestamp": 1537408361916,
                    "evictionTimestamp": 0,
                    "serviceUpTimestamp": 1537408212022
                },
                "isCoordinatingDiscoveryServer": false,
                "metadata": {
                    "management.port": "8130"
                },
                "lastUpdatedTimestamp": 1537408212824,
                "lastDirtyTimestamp": 1537408211890,
                "actionType": "ADDED",
                "asgName": null
            },
            "scheme": null
        }
    ]
    
    可以看到,该实例维护了 Node 应用的访问地址"uri": “http://localhost:3000”,这也是接下来要说的:其他微服务可以通过 Sidecar 的服务名声明式调用 Node 服务。

1.3 声明式服务调用

以上,我们已经验证了 Eureka 可以通过 Sidecar 间接的管理基于 Node 的微服务。而在微服务体系中,还有非常重要的一点,就是服务间的调用。Spring Cloud 允许我们使用服务名进行服务间的调用,摒弃了原先的固定写死的 IP 地址,便于服务集群的横向拓展及维护。那么,Non-JVM 的微服务与其他服务间是否可以通过服务名互相调用呢,答案是可以的。

1.3.1 被调用

我们假设下面一个场景,node服务提供了/index接口,返回json字符串。而 consumer服务需要访问node服务拿到返回的json数据。也就是 consumer服务需要访问 node服务 的/index接口拿到json字符串。

1. 在 node服务中实现/index接口,返回json字符串
// 创建server
var server = http.createServer(function(req, res) {
    // 获得请求的路径
    var pathname = url.parse(req.url).pathname;
    res.writeHead(200, { 'Content-Type' : 'application/json; charset=utf-8' });
    // 访问http://localhost:8060/,将会返回{"index":"欢迎来到首页"}
    if (pathname === '/index') {
        res.end(JSON.stringify({ "index" : "欢迎来到首页" }));
    }
    // 访问http://localhost:8060/health,将会返回{"status":"UP"}
    else if (pathname === '/health') {
        res.end(JSON.stringify({ "status" : "UP" }));
    }
    // 其他情况返回404
    else {
        res.end("404");
    }
});
2. consumer作为 node 服务的调用者,需要声明 Client 接口,代码如下
@FeignClient("nodeSidecar")
public interface NodeServiceClient {
    @GetMapping("/index")
    String getIndex();
}

注意到@FeignClient注解中调用的服务名填写的是 nodeSidecar (大小写不敏感),因为自始至终 Eureka 中注册的是 Sidecar 的信息,而 Sidecar 实例维护了 node服务 的地址信息,所以它可以将请求转发至 node服务。

1.3.2 调用其它微服务

其他微服务可以通过 Sidecar 实例的服务名间接调用 Node 服务。同样的,node服务 也可以通过服务名调用其它微服务,这要归功于@EnableZuulProxy。

访问http://localhost:8130/consumer/index惊讶的发现,这和我们访问http://localhost:8106/index结果是一样的,这是由于 Sidecar 引入了 Zuul 网关,它可以获取 Eureka 上注册的服务的地址信息,从而进行路由跳转。因此,node访问其它微服务的地址格式为:http:localhost:8130/{serviceName}/method

另外,可以直接使用eureka的HTTP接口集成异构服务。由于eureka也是通过HTTP协议的接口暴露自身服务的,因此我们可以在node.js中手动发送HTTP请求实现服务的注册、查询和心跳功能。eureka接口描述信息可以在官方github的wiki中找到。但是这种方式存在弊端:

  • 无法使用Spring Cloud组件Ribbob,Hystrix等提供的便利;
  • 无法通过服务名访问其它微服务,其它服务的ip,port需暴露给node服务供http访问。

猜你喜欢

转载自blog.csdn.net/AaronSimon/article/details/83001362