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}:8100/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访问。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容