以服务⽹格(ServiceMesh)⽅式整合现有服务到微服务(基
于SpringCloud)架构中
为什么要以服务⽹格(Service Mesh)⽅式整合现有服务
转眼间来到了2019年,新年新的开始,来⼀起看看2018年还没有实现的愿望吧。作为⼀个SpringCloud的拥趸者,⼀直在⼼头惴惴不安的就是如何让SpringCloud的微服务架构⼀统天下,实现所有服务在微服务架构下的⼤同。
话说回来,为啥要以⽅式来整合现有服务呢?如果您正在使⽤SpringCloud构建⾃⼰的微服务架构,您可能会使⽤Eruka Server作为服务注册中⼼,使⽤Eureka Client进⾏服务注册,最后使⽤Ribbon进⾏服务调⽤(如下图1 服务治理机制),这些组件使⽤起来都⾮常简单易⽤,能使我们迅速搭建起微服务架构的应⽤。但在公司的架构演变过程中全部在短时间内使⽤基于SpringCloud进⾏微服务化显然是不现实,需要我们将现有服务也按照微服务架构的思想进⾏整合,进⽽逐渐下线旧服务。还有就是公司部分服务使⽤⾮JAVA语⾔构建(如Python),在短时间将这些服务改造成基于SpringCloud的微服务显然是不现实的,也是不符合架构演进的原则的,或者这些⾮JAVA服务已经很稳定⽆需专门进⾏微服务化的改造,这样同样需要采⽤微服务架构的思想整合这些服务。
说到这⾥,您可能会问这该如何整合?如果您研究过Eureka,你可能会直接在现有服务中实现使⽤进⾏服务注册进⽽给给其他系统或服务提供服务,当然还需在现有服务中实现⼀个类似ribbon调⽤客户端调⽤所有在Eureka注册中⼼已经注册的服务,这样⼀来显⽰是对现有服务改动太⼤了,那我们是不是能将服务注册和服务调⽤从现有服务中抽离出⼀个代理服务呢?答案是肯定。这就是提出⽹格服务的根本出发点,此时我们将这个代理服务叫做Sidecar。在服务⽹格中Sidecar还扩展了重试/超时、监控、追踪等功能。
什么是服务⽹格ServiceMesh
先来看下的官宣说法:
服务⽹格(Service Mesh)是致⼒于解决服务间通讯的基础设施层。它负责在现代云原⽣应⽤程序的复杂服务拓扑来可靠地传递请求。
实际上,Service Mesh 通常是通过⼀组轻量级⽹络代理(Sidecar proxy),与应⽤程序代码部署在⼀起来实现,⽽⽆需感知应⽤程序本⾝。
服务⽹格的特点
应⽤程序间通讯的中间层
轻量级⽹络代理
应⽤程序⽆感知
解耦应⽤程序的重试/超时、监控、追踪和服务发现
理解服务⽹格(Service Mesh)
如果⽤⼀句话来解释什么是 Service Mesh,可以将它⽐作是应⽤程序或者说微服务间的 TCP/IP,负责服务之间的⽹络调⽤、限流、熔断和监控。对于编写应⽤程序来说⼀般⽆须关⼼ TCP/IP 这⼀层(⽐如通过 HTTP 协议的 RESTful 应⽤),同样使⽤ Service Mesh 也就⽆须关系服务之间的那些原来是通过应⽤程序或者其他框架实现的事情,⽐如 Spring Cloud、OSS,现在只要交给 Service Mesh 就可以了。
服务⽹格架构
Service Mesh 作为 sidecar 运⾏,对应⽤程序来说是透明,所有应⽤程序间的流量都会通过它,所以对应⽤程序流量的控制都可以在Service Mesh 中实现。
如何整合现有服务到微服务架构中
对于整合现有服务,在理解了服务⽹格(Service Mesh)架构(如图2 服务⽹格架构)的基础上,我们也可以在现基于SpringCloud的微服务架构中,通过使⽤服务⽹格⼀样的运⾏⽅式(即Sidecar)来实现现有服务的注册与调⽤(即服务治理),如图3 。
什么是Sideca
在服务⽹格中,已经有、、、、等开源项⽬,但这些均不能直接将服务注册到Eureka Server中,所以需要⽤SpringCloud的⽅式⽣成运⾏Sidecar。
在基于SpringCloud的微服务中,有Spring Cloud Netflix Sidecar,它包含⼀个简单的http api去获取⼀个已知服务的所有实例(例如主机和端⼝)。你也可以通过嵌⼊的Zuul代理(Zuul中有⼀个代理功能)对代理的服务进⾏调⽤,Zuul从Eureka服务注册中⼼获取所有的路由记录(route entries)。通过host发现(host lookup)或者Zuul代理可以直接访问Spring Cloud Config。⾮jvm需要应该实现⼀个健康检
查,Sidecar能够以此来报告给Eureka注册中⼼该应⽤是up还是down状态。总之,Sidecar是作为⼀个代理的服务来间接性的让其他语⾔可以使⽤Eureka等相关组件。通过与Zuul的来进⾏路由的映射,从⽽可以做到服务的获取,然后可以使⽤Ribbon,Feign对服务进⾏消费,以及对Config Server的间接性调⽤。
准备Sidecar应⽤
为了更好的理解Sidecar,我们在这⾥单独起⼀个应⽤叫作Sidecar,此应⽤只⽤作给其他⾮JVM服务做代理。构建Sidecare应⽤,需要添加以下依赖,如下
1 2 3 4 5<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-sidecar</artifactId>
<version>1.2.4.RELEASE</version><!--具体版本可⾃选--> </dependency>
启⽤Sidecar,创建⼀个Spring Boot应⽤程序,并在在应⽤主类上加上@EnableSidecar注解。该注解包
含@EnableCircuitBreaker, @EnableDiscoveryClient以及@EnableZuulProxy,将Sidecar和⾮JVM服务部署在同⼀台机器上(也可以部署在同⼀机器上,但为了好管理和理解,最好部署在同⼀台机器上)。
配置Sidecar,在l中添加sidecar.port和sidecar.health-uri。sidecar.port属性是⾮jre程序监听的端⼝号,这就是Sidecar可以正确注册应⽤到Eureka的原因。sidecar.health-uri是⾮jre应⽤提供
的⼀个对外暴露的可访问uri地址,在该地址对应的接⼝中需要实现⼀个模仿Spring Boot健康检查指⽰器的功能。它需要返回如下的json⽂档。(注:通过返回⼀个json,其⽤status字段来标识你的应⽤的服务状态,是up还是down,sidecar会将该状态报告给eureka注册中⼼从⽽实现你的服务的状态可⽤情况。简单的说就是⽤来控制sidecar代理服务的状态!)
1 2 3 4 5 6 7 8 9server:
port: 6666 ##Sidecar注册到Eureka注册中⼼的端⼝
spring:
application:
name: sidecar ## 服务的名称,在Eureka注册中⼼上会显⽰此名称(在⽣产环境中,此名称最好与Sidecar所代理服务的名称保持⼀致)
sidecar:
port: 8000 ##Sidecar监听的⾮JVM服务端⼝
health-uri: localhost:8000/health ##⾮JVM服务需要实现该接⼝,[响应结果](#原有服务实现健康检查API)后⾯会给出注册配置
⾄此,Sidecar应⽤就准备好了,具体代码可参见 《增加github链接》。
启动Sidecar应⽤,观察Eureka注册中⼼,发现Sidecar应⽤已经注册到注册中⼼但是状态显⽰down,这是因为Sidecar应⽤代理的服务还没有
原有服务实现健康检查API
对于Sidecar来说,如果能准确的代理⾮JVM服务,则需要实时检查⾮JVM服务的健康状态并实时将结果同步到Eureka注册中⼼,以便服务消费⽅能及时准确地获取到可调⽤的服务,所以原有⾮JVM服务需要实现⼀个简单的健康检查API,具体json结构如下
1 2 3{
"status":"UP" }
Node.js服务
接下来我们以Node.js服务作为现有服务来模拟接⼊SpringCloud微服务的流程。
由于Node.js社区⼗分活跃,可选的Rest服务框架⾮常多。⽐较主流的有express,koa, hapi等,⾮常轻量易扩展的也有像connect这样的,这⾥笔者考虑到众基础和⽂档丰富度,选择使⽤来开发这样⼀个可以接⼊Spring Cloud的Rest服务。
准备Node.js服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59var express = require('express');
var utils = require("./utils");
var http = require("http");
var app = express();
// 健康检查API,⽤于Sidecar检查本nodejs服务的存活状态
<('/health', function (req, res) {
res.set("Content-Type", "application/json;charset=utf-8");
console.NowFormatDate() + " request: " + req.url);
var response = {
"status":"UP"
};
res.send(JSON.stringify(response));
})
// 对外服务API,⽤于测试其他服务调⽤本nodejs服务即查询当前实例的信息
<('/instance_info', function(req,res){
res.set("Content-Type", "application/json;charset=utf-8");
console.NowFormatDate() + " request: " + req.url);
var response = {
"status":0,
"msg":"sucess",
"data":{
"instance_name":"nodejs_server"
}
};
res.send(JSON.stringify(response));
})
// 查看指定服务的实例信息API,⽤于测试本nodejs服务调⽤其他已注册到Eureka上是服务
<('/query/:server_name/info', function(req,res){
res.set("Content-Type", "application/json;charset=utf-8");
var response = null;
var instance_name = req.params.server_name;
console.NowFormatDate() + " request: %s, querying server_name :" , req.url, instance_name);
// 获取服务的实例信息
var sidecarServiceUrl = "localhost:6666/{instance_name}/instance_info".replace('{instance_name}',instance_name);//sidecar获取服务信息API(实际Sidecar会将此请求转发到Sidecar代理的Python服务上)
<(sidecarServiceUrl,function(data){
var str="";
<("data",function(chunk){
str+=chunk;
})
<("end",function(){
console.String());
String();
})
})
res.send(response);
})
// nodejs服务启动
var server = app.listen(8000, function () {
var host = server.address().address
var port = server.address().port
console.log("应⽤实例,访问地址为 %s:%s", host, port)
})
此时启动Node.js服务,再次观察Eureka注册中⼼,发现之前注册到注册中⼼的Sidecar应⽤状态变为UP正常状态了,这可以说明Sidecar 确实及时准确的将被代理服务的状态反映到注册中⼼了。换⾔之,注册中⼼显⽰的Sidecar应⽤的状态其实是被代理服务的状态。
准备⽤于调⽤Node.js服务的测试服务
为了测试Node.js服务的在基于SpringCloud的微服务中的可⽤性,本⽂选取微服务中常⽤的⽹关作为Node.js服务的调⽤⽅来测试Node.js 服务的可⽤性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 l
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance" xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.haozi</groupId>
<artifactId>gateway</artifactId>微服务注册中心有哪些
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>gateway</name>
<description>MService Gateway</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Camden.SR5</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
&porting.outputEncoding>UTF-8</porting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
<dependency>
<groupId></groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18## l
server:
port: 8700
spring:
application:
name: gateway
eureka:
client:
register-with-eureka: true
fetch-registry: true
serviceUrl:
defaultZone: center.chuangzhi8:8761/eureka/
zuul:
routes:
express_servcie: #此路由的意思是:将请求路径的⼀级⽬录是/express的请求全部转发到服务id为Sidecar的服务上 path: /express/** #路由路径
serviceId: sidecar #服务id
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论