转载

Spring sidecar模式

起Eureka

在 https://start.spring.io/ 勾选Eureka Server

Application加上EnableEurekaServer:

@SpringBootApplication
@EnableEurekaServer
public class CloudApplication {

	public static void main(String[] args) {
		SpringApplication.run(CloudApplication.class, args);
	}

}

application.properties配置文件:

server.port=8761
spring.application.name=eureka-server
eureka.instance.hostname=localhost
eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=false
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

完整的pom如下:

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.0.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>cloud</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>cloud</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Hoxton.RC1</spring-cloud.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
		</repository>
	</repositories>

</project>

起来后查看http://localhost:8761

Spring sidecar模式

准备非java服务端

用Django生成web项目

使用Django生成一个HelloWorld的web项目。

django-admin startproject HelloWorld

创建完成后可以看到下面的目录树:

$ cd HelloWorld/
$ tree
.
|-- HelloWorld
|   |-- __init__.py
|   |-- settings.py
|   |-- urls.py
|   `-- wsgi.py
`-- manage.py

说明:

  • HelloWorld: 项目的容器。
  • manage.py: 一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。
  • HelloWorld/ init .py: 一个空文件,告诉 Python 该目录是一个 Python 包。
  • HelloWorld/settings.py: 该 Django 项目的设置/配置。
  • HelloWorld/urls.py: 该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"。
  • HelloWorld/wsgi.py: 一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目。

接下来就可以启动了:

python3 manage.py runserver 0.0.0.0:8000

配置url

urls.py

"""HelloWorld URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from . import view

urlpatterns = [
    url(r'^health$', view.health),
    url(r'^instance_info$', view.instance_info),
    url(r'^query/(.+)/info$', view.query_server_info),
]

view.py

from django.http import HttpResponse,JsonResponse
import urllib
import json

# 健康检查API,用于Sidecar检查本Python服务的存活状态
def health(request):
    result = {
        "status":"UP"
    }
    print(result)
    return JsonResponse(result)

# 对外服务API,用于测试其他服务调用本Python服务即查询当前实例的信息
def instance_info(request):
    result = {
        "status":0,
        "msg":"sucess",
        "data":{
            "instance_name":"python_server"
        }
    }
    print(result)
    return JsonResponse(result)

# 查看指定服务的实例信息API,用于测试本Python服务调用其他已注册到Eureka上是服务
def query_server_info(request,server_name):
    print(server_name)

    sidecar_service_url = "http://localhost:6666/{instance_name}/instance_info".replace('{instance_name}',server_name);#sidecar获取服务信息API(实际Sidecar会将此请求转发到Sidecar代理的Python服务上)
    print("request_url: "+sidecar_service_url)
    req = urllib.request.urlopen(sidecar_service_url)
    res_data = req.read()

    print(str(res_data, encoding = "utf-8"))

    return JsonResponse(json.loads(res_data))

准备sidecar应用

在pom中加入依赖spring-cloud-netflix-sidecar,完整的pom如下:

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.0.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>cloud</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>cloud</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Hoxton.RC1</spring-cloud.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-netflix-sidecar</artifactId>
			<!--			<version>1.2.4.RELEASE</version><!–具体版本可自选–>-->
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
		</repository>
	</repositories>

</project>

应用主类Application上加上EnableSidecar,该注解包含@EnableCircuitBreaker, @EnableDiscoveryClient以及@EnableZuulProxy。

@SpringBootApplication
@RestController
@EnableSidecar
public class CloudApplication {

	public static void main(String[] args) {
		SpringApplication.run(CloudApplication.class, args);
	}

}

application.properties上加上注册中心的地址:

eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

##Sidecar注册到Eureka注册中心的端口
server.port=8666
## 服务的名称,在Eureka注册中心上会显示此名称(在生产环境中,此名称最好与Sidecar所代理服务的名称保持一致)
spring.application.name=sidecar

##Sidecar监听的非JVM服务端口
sidecar.port=8000
##非JVM服务需要实现该接口,[响应结果](#原有服务实现健康检查API)后面会给出注册配置
sidecar.health-uri=http://localhost:8000/health

#hystrix.command.default.execution.timeout.enabled: false
hystrix.metrics.enabled=false

sidecar.port属性是非jre程序监听的端口号,以使得Sidecar将该服务正确注册到Eureka。sidecar.health-uri是非jre应用提供的一个对外暴露的可访问uri地址,在该地址对应的接口中需要实现一个模仿Spring Boot健康检查指示器的功能。它需要返回如下信息:

{
status: "UP"
}

将Sidecar和非JVM服务部署在同一台机器上。

部署起来后可以看到sidecar注册到了Eureka并且状态是UP。

Spring sidecar模式

java客户端,测试服务可用性

本文使用feign来调用python服务,以测试sidecar形式在微服务中的可用性。

pom中加入spring-cloud-starter-openfeign,完整的pom如下:

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.0.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>callpython</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>callpython</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud-services.version>2.1.4.RELEASE</spring-cloud-services.version>
		<spring-cloud.version>Hoxton.RC1</spring-cloud.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-batch</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>
<!--		<dependency>-->
<!--			<groupId>org.springframework.cloud</groupId>-->
<!--			<artifactId>spring-cloud-openfeign-dependencies</artifactId>-->
<!--		</dependency>-->
		<dependency>
			<groupId>io.pivotal.spring.cloud</groupId>
			<artifactId>spring-cloud-services-starter-service-registry</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.batch</groupId>
			<artifactId>spring-batch-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<dependency>
				<groupId>io.pivotal.spring.cloud</groupId>
				<artifactId>spring-cloud-services-dependencies</artifactId>
				<version>${spring-cloud-services.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
		</repository>
	</repositories>

</project>

application.yml中加上配置eureka地址:

server:
  port: 8700
spring:
  application:
    name: gateway
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

添加Feign调用类:配置上sidecar在eureka上注册的应用名

@FeignClient(name = "sidecar")
public interface PythonFeign {
    @RequestMapping(value = "/instance_info", method = RequestMethod.GET)
    String getInstanceInfo() throws Exception;
}

添加Controller:

@RestController
public class InfoController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
	private PythonFeign pythonFeign;

	@GetMapping(value = { "/jvm_instance_info" })
	public Map getInstance() {
		Map<String, Object> retVal = new HashMap<>();
		retVal.put("staus", 0);
		retVal.put("msg", "sucess");
		Map<String, Object> instanceInfo = new HashMap<>();
		instanceInfo.put("instance_name", "JVM_Gateway");
		retVal.put("data", instanceInfo);
		return retVal;
	}

	@RequestMapping("/python_user")
	public String PythonUser() {
		String strTmp = restTemplate.getForEntity("http://127.0.0.1:8000/instance_info", String.class).getBody();
		return strTmp;
	}

	@GetMapping("/python_instance_info")
	public String getPythonInstanceInfo(){
		try {
			return pythonFeign.getInstanceInfo();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		return "";
	}
}

启动后,查看eureka可以看到服务已经注册上了:gateway那个应用。

Spring sidecar模式

启动后,访问http://127.0.0.1:8700/jvm_instance_info 测试本服务的可用性:

{
    "msg": "sucess",
    "staus": 0,
    "data": {
        "instance_name": "JVM_Gateway"
    }
}

调用 http://127.0.0.1:8700/python_instance_info 会调用到python服务:

{
  status: 0,
  msg: "sucess",
  data: {
    instance_name: "python_server"
  }
}

至此,可以看到Sidecar双向代理了python服务,把python服务纳入了基于SpringCloud的微服务中提供服务。

原文  http://yizhanggou.top/spring-sidecarmo-shi/
正文到此结束
Loading...