使用Spring Boot+gRPC构建微服务并部署到Istio
作为Service Mesh
和云原生技术的忠实拥护者,我却一直没有开发过Service Mesh的应用。正好最近受够了Spring Cloud的“折磨”,对Kubernetes也可以熟练使用了,而且网上几乎没有Spring Boot微服务部署到Istio的案例,我就开始考虑用Spring Boot写个微服务的Demo并且部署到Istio。项目本身不复杂,就是发送一个字符串并且返回一个字符串的最简单的Demo。
题外话:我本来是想用Spring MVC写的——因为周围有的同学不相信Spring MVC也可以开发微服务,但是Spring MVC的各种配置和依赖问题把我整的想吐,为了少掉几根头发,还是用了方便好用的Spring Boot。
本项目的所有代码都上传到了GitHub,地址: https://github.com/WenDev/spring-boot-istio-demo 如果有帮助的话不要吝啬你的Star和Fork呀,如果遇到了问题或者有写得不够好的地方也欢迎提出issue,非常感谢~
本文同时也发表在我的个人网站:www.wendev.site,欢迎前往我的个人网站阅读。
为什么要用Istio?
目前,对于Java技术栈来说,构建微服务的最佳选择是Spring Boot
而Spring Boot一般搭配目前落地案例很多的微服务框架Spring Cloud
来使用。
Spring Cloud看似很完美,但是在实际上手开发后,很容易就会发现Spring Cloud存在以下比较严重的问题:
- 服务治理相关的逻辑存在于Spring Cloud Netflix等SDK中,与业务代码紧密耦合。
- SDK对业务代码侵入太大,SDK发生升级且无法向下兼容时,业务代码必须做出改变以适配SDK的升级——即使业务逻辑并没有发生任何变化。
- 各种组件令人眼花缭乱,质量也参差不齐,学习成本太高,且组件之间代码很难完全复用,仅仅为了实现治理逻辑而学习SDK也并不是很好的选择。
- 绑定于Java技术栈,虽然可以接入其他语言但要手动实现服务治理相关的逻辑,不符合微服务“可以用多种语言进行开发”的原则。
- Spring Cloud仅仅是一个开发框架,没有实现微服务所必须的服务调度、资源分配等功能,这些需求要借助Kubernetes等平台来完成。但Spring Cloud与Kubernetes功能上有重合,且部分功能也存在冲突,二者很难完美配合。
替代Spring Cloud的选择有没有呢?有!它就是Istio
。
Istio彻底把治理逻辑从业务代码中剥离出来,成为了独立的进程(Sidecar)。部署时两者部署在一起,在一个Pod里共同运行,业务代码完全感知不到Sidecar的存在。这就实现了治理逻辑对业务代码的零侵入——实际上不仅是代码没有侵入,在运行时两者也没有任何的耦合。这使得不同的微服务完全可以使用不同语言、不同技术栈来开发,也不用担心服务治理问题,可以说这是一种很优雅的解决方案了。
所以,“为什么要使用Istio”这个问题也就迎刃而解了——因为Istio解决了传统微服务诸如业务逻辑与服务治理逻辑耦合、不能很好地实现跨语言等痛点,而且非常容易使用。只要会用Kubernetes,学习Istio的使用一点都不困难。
为什么要使用gRPC作为通信框架?
在微服务架构中,服务之间的通信是一个比较大的问题,一般采用RPC或者RESTful API来实现。
Spring Boot可以使用RestTemplate
调用远程服务,但这种方式不直观,代码也比较复杂,进行跨语言通信也是个比较大的问题;而gRPC
相比Dubbo等常见的Java RPC框架更加轻量,使用起来也很方便,代码可读性高,并且与Istio和Kubernetes可以很好地进行整合,在Protobuf和HTTP2的加持下性能也还不错,所以这次选择了gRPC来解决Spring Boot微服务间通信的问题。并且,虽然gRPC没有服务发现、负载均衡等能力,但是Istio在这方面就非常强大,两者形成了完美的互补关系。
由于考虑到各种grpc-spring-boot-starter
可能会对Spring Boot与Istio的整合产生不可知的副作用,所以这一次我没有用任何的grpc-spring-boot-starter
,而是直接手写了gRPC与Spring Boot的整合。不想借助第三方框架整合gRPC和Spring Boot的可以简单参考一下我的实现。
编写业务代码
首先使用Spring Initializr
建立父级项目spring-boot-istio
,并引入gRPC
的依赖。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>
<modules>
<module>spring-boot-istio-api</module>
<module>spring-boot-istio-server</module>
<module>spring-boot-istio-client</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>site.wendev</groupId>
<artifactId>spring-boot-istio</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-istio</name>
<description>Demo project for Spring Boot With Istio.</description>
<packaging>pom</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-all</artifactId>
<version>1.28.1</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
然后建立公共依赖模块spring-boot-istio-api
,pom文件如下,主要就是gRPC的一些依赖:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-boot-istio</artifactId>
<groupId>site.wendev</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-boot-istio-api</artifactId>
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-all</artifactId>
</dependency