- 引言
- 什么是sidecar
- 11 使用Sidecar步骤
- 12 Java调用非JVM程序接口
- 13 非JVM接口调用Java接口
- Python和SpringCloud整合实例
- 1 定义Python服务
- 2 定义SpringCloud注册中心
- 3 定义sidecar
- 4 定义Java服务
- 5 服务相互调用
1.引言
说到Python
这门语言,应该都会很熟悉,近几年来Python
大火,几乎都到了人人喊着:“人生苦短,我学Python
”的境地,确实Python
在机器学习方面有着得天独厚的优势,在Python
语言中拥有很多现成的机器学习函数库,然后在Web
开发中还是有着很多人使用Java
作为服务器的后台语言,尤其是近几年来微服务的兴起,也有着越来越多的人使用SpringCloud
(基于Java
语言实现的微服务框架),因此就产生了这么一个需求:能否将Python
的机器学习算法集成到SpringCloud
中,作为我们Web
系统的服务,当我们自己使用Python实现了一个新的机器学习算法的时候,可以同时为他人提供服务。用户在Web端提供数据,而Web平台提供算法进行计算,同时反馈给用户)。 要想实现上面的需求,其实就是存在着整合SpringCloud
整合Python
的必要性。因此我查了SpringCloud
的官网,还真的提供了整合Python
语言的解决方案(其实是整合第三方语言的解决方案)。这个解决方案叫做:sidecar
。通过使用**sidecar
**我们可以将Python
接口注册为SpringCloud
的一个服务,实现Java
(因为SpringCloud
是Java
语言的一款框架)和Python
的双向通信,即:Python
可以调用Java
语言的接口,同时Java
也可以调用Python
语言的接口。
2. 什么是sidecar
我们刚刚说了使用sidecar
可以将SpringCloud
和第三方语言整合,那什么是sidecar
呢?说白了sidecar
就是springcloud
提供的一个工具,使用该工具将第三方的rest
接口集成到springcloud
中来。那么如何使用sidecar
呢?首先我们看一下官网的描述。
2.1 Polyglot
支持Sidecar
(官网描述)
Spring Cloud Netflix Sidecar
包含一个简单的http api
来获取给定服务的所有实例(即主机和端口)。然后可以通过从Eureka
获取其路由条目的嵌入式Zuul
代理来代理服务调用。可以通过主机查找或通过Zuul
代理访问Spring Cloud Config
服务器。但是第三方程序必须执行健康检查,以便Sidecar
可以向应用程序启动或关闭时向eureka
报告**(意思就是说:第三方程序必须提供一个接口告诉Spring Cloud
自身是否还在运行?)**。如何使用Sidecar
呢?官网给出了如下的步骤:
2.1.1 使用Sidecar
步骤
- 添加Java包依赖
如果要在项目中包含Sidecar
,需要使用org.springframework.cloud
和artifact id spring-cloud-netflix-sidecar
的依赖。
- 注解启动
Sidecar
使用@EnableSidecar
创建Spring Boot
应用程序。此注释包括@EnableCircuitBreaker
,@EnableDiscoveryClient
和@EnableZuulProxy
。
- 修改配置
配置Sidecar
,应该将sidecar.port
和sidecar.health-uri
添加到application.yml
。sidecar.port
属性是非jvm
应用程序正在侦听的端口。这样,Sidecar
可以使用Eureka
正确注册该应用。sidecar.health-uri
是可以在非jvm
应用程序上访问的,可以模拟Spring Boot
健康指标。它应该返回一个json
文档,如下所示:
{
"status":"UP"
}
- 1
- 2
- 3
以下是Sidecar
应用程序的application.yml
示例:
server:
port: 5678
spring:
application:
name: sidecar
sidecar:
port: 8000
health-uri: http://localhost:8000/health.json
2.1.2 Java调用非JVM程序接口
我们使用Sidecar
将第三方程序接口(比如Python
)注册到SpringCloud
之中,如何使用Python
接口呢?这时候就非常简单了,此时我们就可以将Python
接口当作Java
接口进行调用(其实时通过springcloud
去调用Sidecar
,然后通过Sidecar
去转发我们的程序请求)。
2.1.3 非JVM接口调用Java接口
因为非JVM
应用 被注册到SpringCloud
之中,对于第三方应用程序来说,整个SpringCloud
的内容,我们都可以进行调用了,比如我们有一个Java服务叫做customers
,那么我们就可以通过url来调用,比如http://localhost:5678/customers
(假设Sidecar
在端口5678
上),因为配置服务器(configserver
)也属于SpringCloud的一个服务,因此非JVM
语言也可以调用配置服务器的配置,比如使用如下的url
: http:// localhost:5678/configserver
2.2 Sidecar
总结
看了官网的描述,似乎我们还是抓不住重点,到底应该如何结合Sidecar
和第三方程序呢?依旧是如此的茫然。下面我着重说一下官网提供的重点:
-
Sidecar
是一个用于监听非JVM应用程序(可以是Python
或者Node
或者Php
等等)的一个工具,通过Sidecar
可以实现Java
和第三方应用程序的双向交互 - 第三方应用程序必须要实现一个接口,实时向
Sidecar
报告自己的状态,告诉Sidecar
自己还在运行着。 -
Sidecar
应用程序必须和第三方应用程序运行在同一台电脑上,也就是说他们之间是localhost
,不能是ip
访问(官网未提及)
3.Python
和SpringCloud
整合实例
前面说了这么多理论性的东西,似乎我们只知道了一个事情:通过Sidecar
可以实现SpringCloud和第三方应用程序的整合,就比如我们的Python,可以利用Sidecar
将Python
集成到我们的微服务中来,然后我们就可以利用Python
强大的机器学习算法了。
说了这么多,往往不如一个实例来的更加直接,现在我就使用Python
来和SpringCloud
整合。在我的程序结构如下所示:
-
python
接口中会提供一个服务功能:获取Python
用户名和密码,用户名为:python
,密码为python
。同时python
应该还提供一个健康接口,报告自己的健康状态 -
Java
服务会提供两个接口(JavaUser,PythonUser)
,JavaUser
方法用于获得Java
用户名和密码,用户名为:java
,密码为java
。PythonUser
方法会调用python
服务,获得Python
用户名和密码。
3.1 定义Python服务
在Python
中,我使用flask
提供Web
服务,代码如下:
import json
from flask import Flask, Response
app = Flask(__name__)
@app.route("/health")
def health():
result = {'status': 'UP'}
return Response(json.dumps(result), mimetype='application/json')
@app.route("/getUser")
def getUser():
result = {'username': 'python', 'password': 'python'}
return Response(json.dumps(result), mimetype='application/json')
app.run(port=3000, host='0.0.0.0')
代码解释:
-
Python
服务监听3000
接口 -
health
方法用于给Sidecar
提供健康接口,用于实时向Sidecar
提供自己的健康状态。 -
getUser
是Python
向外界提供的服务,提供Python
用户的用户名和密码
3.2 定义SpringCloud
注册中心
application.properties
配置文件
server.port=8000
spring.application.name=eureka-server
eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/
eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=false
main
方法
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
代码解释:
- 注册中心启动端口:
8000
3.3 定义sidecar
main
方法
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.sidecar.EnableSidecar;
@EnableSidecar
@SpringBootApplication
public class PySidecarApplication {
public static void main(String[] args) {
SpringApplication.run(PySidecarApplication.class, args);
}
}
application.properties
配置文件
spring.application.name=py-sidecar
server.port=8001
sidecar.port=3000
sidecar.health-uri=http://localhost:${sidecar.port}/health
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000
ribbon.ConnectTimeout=5000
ribbon.ReadTimeout=5000
eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/
代码解释:
* main
方法使用了@EnableSidecar
注解
* sidecar.port
代表第三方程序运行的端口(比如上方的Python
),所以监听端口为3000
* server.port
代表sidecar
运行的端口
* spring.application.name
代表sidecar
的应用名字**(后面要用到)**
* sidecar.health-uri
是Python
健康接口,应指向python
的健康服务
3.4 定义Java服务
Java服务
package com.example.demo;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class JavaController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/java-user")
public String JavaUser() {
return "{'username': 'java', 'password': 'java'}" ;
}
@RequestMapping("/python-user")
public String PythonUser() {
return restTemplate.getForEntity("http://py-sidecar/getUser", String.class).getBody();
}
}
main
方法
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringCloudApplication
public class RibbonConsumerApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonConsumerApplication.class, args);
}
}
application.properties
spring.application.name=java-service
server.port=8002
eureka.client.service-url.defaultZone=http://localhost:8000/eureka/
代码解释:
-
server.port
代表Java
服务运行的端口 -
spring.application.name
代表Java
服务应用的名字**(后面要用到)** - 在
PythonUser
方法中,Java
调用了Python
服务,将Python
用户返回**(注意:在这里Java
语言调用了Python
的接口,实现了Java
和Python
的通信)** - 在
JavaUser
方法中,直接返回了Java
用户的信息
3.5 服务相互调用
在服务调用之前,我们先回顾一下代码都做了什么样子的事情:
- 定义了一个
Python
服务,运行在端口3000
- 定义了一个
sidecar
,运行在短就8001
,监听Python端口3000
,应用名字为py-sidecar
- 定义了一个
Java
服务,运行在端口8002
,应用名字为java-service
- 服务的启动顺序:Python服务,注册中心,
py-sidecar
,java-service
3.5.1 调用Java原生服务
对于Java原生服务的调用没有什么特别,直接访问URL即可,如:http://localhost:8002/java-user
3.5.2 Java调用Python服务
在java-service
服务的PythonUser
中,Java
调用了Python
的服务,使用restTemplate
模板,通过:http://{service_id}/{method}
实现了对Python
服务的调用**(这里我们调用的时Java
的端口,返回的是Python
的数据内容)**
3.5.3 通过sidecar
调用Java
服务
我们使用了sidecar
,所以我们可以使用sidecar
实现对Java
服务的调用,比如:http://{host}:{port}/{service_id}/{method}
,其中:
-
host
是sidecar
的主机地址 -
port
是sidecar
的端口地址 -
service_id
是Java
服务的id
-
method
是Java
服务的具体方法地址
如果我们想通过sidecar
获得Java
用户的对象,可以这么写:http://localhost:8001/java-service/java-user
3.6 实例代码的下载地址