接上篇《29.Zuul的FallBack回退机制》  Spring Cloud版本为Finchley.SR2版

上一篇我们介绍了有关Zuul回退的相关知识,本篇我们来学习使用Sidecar支持异构平台的微服务,
本部分官方文档:https://cloud.spring.io/spring-cloud-static/Finchley.SR4/single/spring-cloud.html#_polyglot_support_with_sidecar
注:好像Finchley.SR2的文档已经挂了,最新的是Finchley.SR4的文档。

目录

一、Sidecar的作用

二、搭建一个Sidecar服务

三、异构服务对接Sidecar

四、异构服务状态同步

五、Sidecar的不足之处

六、不使用Sidecar引用异构服务


一、Sidecar的作用

我们的微服务系统里面不一定只使用Java这一种语言,有一部分微服务可能是其他语言(如Node.js或PHP等)。此时我们可以使用Sidecar把异构的微服务纳入到Spring Cloud的生态圈中。

Sidecar的灵感来源自“Netflix Prana”,它包含了一个HTTP的API,用于获取给定服务的所有实例(按主机和端口)。说的通俗一点,Sidecar除了实现了Zuul代理网关的作用,还提供了一个HTTP服务,其他非Java语言(或非JVM语言)的服务,可以对接该HTTP服务,实现一个类似健康检查的端点服务。所以Sidecar不仅可以代理异构应用的服务,也可以通过其健康检查服务的调用结果向Eureka报告应用程序是启动还是关闭。

使用Sidecar对接第三方服务的结构如下:

图片摘自:https://www.jianshu.com/p/e970b9a4e61a
在上图中,纯Java架构的online服务,通过访问Sidecar服务,就可以访问第三方服务,这里Sidecar本质就是一个Zuul的网关代理。而第三方程序通过实现健康检查服务,加上注册到Sidecar的配置,Sidecar可以检测第三方程序是否健康。而所有应用都是注册在Eureka服务上,被发现和被调用的。

说白了,Sidecar就是异构服务的一个壳子,来使得异构服务能够接入Spring Cloud的生态圈。

二、搭建一个Sidecar服务

我们需要在应用中实现以下几点,来搭建一个Sidecar服务:
(1)创建一个Maven工程(默认引入Spring Boot、Spring Cloud以及Eureka的依赖),在POM文件中引入Sidecar的依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-netflix-sidecar</artifactId>
</dependency>

(2)在Spring Boot启动类上添加@EnableSidecar注解,该注解包含了@EnableCircuitBreaker, @EnableDiscoveryClient, 以及@EnableZuulProxy注解,分别实现了Hystrix断路器、Eureka服务发现以及Zuul网关代理的效果。(3)在配置文件中配置应用的端口号、应用名以及Sidecar的服务地址,例如:

server:
  port: 5678
spring:
  application:
    name: sidecar

sidecar:
  port: 8000
  health-uri: http://localhost:8000/health.json

注:sidecar.port属性代表非java应用的健康监听端口。
sidecar.health-uri是一个可以在非JVM应用程序上访问的uri,它模拟了一个Spring Boot健康指示器。它应该返回一个类似于以下内容的JSON文档:

{
  "status":"UP"
}

即对接Sidecar的非java应用要实现health服务,并在服务正常运行时返回上述内容的JSON串。

完成以上几步就可以实现一个Sidecar服务了。我们下面动手创建一个Sidecar服务。

首先新建一个Maven工程:


然后在POM文件中引入Spring Cloud的父工程和“eureka”、“Sidecar”的依赖:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <artifactId>microserver-sidecar</artifactId>
  
  <parent>
    <groupId>com.microserver.cloud</groupId>
    <artifactId>microserver-spring-cloud</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>

   <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-sidecar</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
  
</project>

注意,这里为了便于版本统一管理,该工程的parent父工程和我们User、Movie工程一样,均依赖于microserver-spring-cloud工程(此父工程统一引入了spring-cloud-dependencies的Finchley.SR2版,以及spring-boot-starter-parent-2.0.6.RELEASE的parent,这个在前面的章节已经讲过)。然后编写启动类MicroserverSidecarApplication.java:

package com.microserver.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.sidecar.EnableSidecar;

@SpringBootApplication
@EnableSidecar
public class MicroserverSidecarApplication {
    public static void main(String[] args) {
        SpringApplication.run(MicroserverSidecarApplication.class, args);
    }
}

这里添加了@EnableSidecar注解以启用Sidecar。

然后在src/main/resource下新建application.yml主配置文件,添加以下配置:

spring:
  application:
    name: microservice-sidecar
server:
  port: 8070
eureka:
  client:
    serviceUrl:
      defaultZone: http://user:password123@eureka1:8761/eureka
  instance:
    prefer-ip-address: true
sidecar:
  port: 8060
  health-uri: http://localhost:8060/health.json

这里我们定义了应用的名称、端口号,对接Eureka注册中心的Url,以及sidecar服务监听的非Java应用的端口号和健康检查地址。

此时我们的一个Sidecar应用就创建好了。

三、异构服务对接Sidecar

我们这里创建一个Node.js的服务,作为一个异构服务来对接Sidecar。
首先我们创建一个node-service.js脚本文件:

注:这里为了方便查看,我直接把脚本文件放在microserver-sidecar工程里了,本来是和microserver-sidecar工程没有关系的。

node-service.js脚本文件编写如下内容:

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' });
  // 访问http://localhost:8060/,将会返回{"index":"欢迎来到首页"}
  if (pathname === '/') {
    res.end(JSON.stringify({ "index" : "欢迎来到首页" }));
  }
  // 访问http://localhost:8060/health,将会返回{"status":"UP"}
  else if (pathname === '/health.json') {
    res.end(JSON.stringify({ "status" : "UP" }));
  }
  // 其他情况返回404
  else {
    res.end("404");
  }
});
// 创建监听,并打印日志
server.listen(8060, function() {
  console.log('listening on localhost:8060');
});

我们不必学习Node.js的语法,我们只需要知道,该代码会启用一个运行在8060端口的服务,该服务提供两个端点供我们访问,一个是根节点“http://localhost:8060/”,会返回“{"index":"欢迎来到首页"}”的json串;一个是“http://localhost:8060/health.json”健康检查端点,会返回“{"status":"UP"}”的json串。

然后我们安装一下Node服务组件,详情见https://www.runoob.com/nodejs/nodejs-install-setup.html,这里不再赘述。

Node服务组件安装完毕后,启动Node应用的方式很简单,我们打开Windows的控制台,找到node-service.js脚本文件所在的路径,然后使用“node”指令+空格+脚本文件名称,就可以启动:
node node-service.js

当出现“listening on localhost:8060”字样时,证明已经在8060端口启动了一个Node服务了。

此时我们访问该Node服务的两个节点(“http://localhost:8060/”和“http://localhost:8060/health.json”):


发现可以成功访问,这里我们的异构服务搭建成功。


此时我们启动Eureka Server工程、Zuul工程、Sidecar工程:

这里我们要提前在Zuul中配置Sidecar的代理配置(如果没有ignored-services,就不用配):

zuul:
  ignored-services: '*'
  routes:
    microserver-provider-user: /user/**
    microservice-file-upload: /file-upload/**
    microservice-sidecar: /sidecar/**

查看Eureka Server主页,确认服务启动成功:

然后访问Zuul的routs端点,查看Zuul是否代理了Sidecar工程:

可以看到这里除了我们之前配置了User服务、文件上传服务的端口,这里还代理了Sidecar的所有端点。

然后通过Zuul网关,我们可以通过Zuul网关去访问Sidecar代理的Node服务:


发现访问成功,说明Sidecar成功代理了异构的非Java服务的所有端点。

我们在其它微服务调用异步微服务也很简单,这里我们以使用了Ribbon的Movie工程为例,在MovieController中,创建相关服务,使用restTemplate对象进行访问:

@GetMapping("/sidecar-test")
public String sidecar(){
    String result = this.restRemplate.getForObject("http://microservice-sidecar/", String.class);
    return result;
}

这里的HTTP服务的URI即是Sidecar在Eureka中注册的服务名。

此时启动Movie工程,访问其“/sidecar-test”服务,可以看到也成功访问:

四、异构服务状态同步

Sidecar会根据异构服务的状态,同步自己的状态。
在上面几个服务启动的情况下,我们可以看到Sidecar的应用状态是UP的:

然后我们将node-service.js中的health.json服务返回的status状态从UP,改为DOWN:

// 访问http://localhost:8060/health,将会返回{"status":"UP"}
else if (pathname === '/health.json') {
    res.end(JSON.stringify({ "status" : "DOWN" }));
}

重新启动Node服务,注意此时我们没有动Sidecar服务,刷新Eureka Server主页,发现Sidecar的状态也同步变更为DOWN了:

然后我们访问Sidecar服务的health节点,可以看到该服务自己就是DOWN的状态:

这就是Sidecar通过异构服务的health.json服务获知其健康状态,然后更新自己的健康状态,而对于Eureka,只需要感知Sidecar的状态即可。

五、Sidecar的不足之处

1、同一个host问题
目前使用Sidecar的时候,要求Sidecar服务和代理的异构服务必须保持在同一个host下,即在一个域下,部署在同一个服务器上。
如果我们需要实现Sidecar服务和代理的异构服务不在一个host下,就需要配置${eureka.instance.hosthome},具体配置详见官方文档中有关Eureka的“registering_a_secure_application”章节:
https://cloud.spring.io/spring-cloud-static/Finchley.SR4/single/spring-cloud.html#_registering_a_secure_application
虽然可以解决,但越复杂的配置,坑越多。

2、一个异构服务对应一个Sidecar
在上面的例子中,我们一个异构服务,就需要启动一个Sidecar服务去代理,如果异构服务比较多的话,我们要一个一个启动相同的Sidecar服务去代理每个异构服务,这明显不是一个好的方案。

六、不使用Sidecar引用异构服务

当然,Eureka也提供有不使用Sidecar就能注册至注册中心的方法,即使用Eureka提供的一套RESRful服务来实现:
https://github.com/netflix/eureka/wiki/Eureka-REST-operations
这里就要求异构服务需要实现这些RESRful服务来向Eureka注册。
这里我们需要根据项目实际情况,来决定是否需要使用哪种方式实现。

本部分代码下载地址:https://download.csdn.net/download/u013517797/12125514

参考:《51CTO学院Spring Cloud高级视频》
https://www.jianshu.com/p/e970b9a4e61a
https://blog.csdn.net/shenzhen_zsw/article/details/81009238

转载请注明出处:https://blog.csdn.net/acmman/article/details/104113870

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐