从零开始学习微服务架构(三)
作为一名IT从业者,懈怠是一件奢侈的事情,因为在IT圈,原地踏步就等于退步。
本章节开始讲从微服务开发角度详细介绍如何搭建微服务框架以及各个组件如何使用。
-
如何选择合适的微服务架构
目前国内主流的微服务开发框架分三类:
- 官方SpringCloud。官方主要是以Netflix组件为基础,可以快速构建分布式系统。比如我们熟悉的注册中心Eureka、配置中心Config、网关Zuul、负载均衡Ribbon、断路器Hystrix等等。组件众多,功能健全,非常适用于构建比较大型的企业级分布式系统。
- Dubbo。以阿里的Dubbo高性能RPC框架作为核心,再配合zookeeper等其他辅助开源组件,来构建分布式系统。性能超高,但生态圈不够完善,辅助功能较少,非常适合拥有研发团队的互联网公司用来构建高性能互联网应用服务。
- SpringCloud Alibaba。如果是SpringCloud和Dubbo两套迥异的框架让你难以选择,那么SpringCloud Alibaba也许就是解决你纠结的一个神器。既可以使用SpringCloud的组件进行编程,也可以非常方便的接入阿里分布式应用。
-
开始
本章节我们选择基于官方SpringCloud推荐的组件来构建微服务框架。
一个最基本的微服务框架至少由以下组件构成:
1. 注册中心。我们选择使用Eureka来构建注册中心。
1)Eureka需要依赖spring-cloud-starter-netflix-eureka-server这个starter来构建,其完整pom.xml文件如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4 <modelVersion>4.0.0</modelVersion> 5 <parent> 6 <groupId>com.example</groupId> 7 <artifactId>ymlspringcloudparent</artifactId> 8 <version>0.0.1-SNAPSHOT</version> 9 </parent> 10 <groupId>com.example</groupId> 11 <artifactId>eurekaserver</artifactId> 12 <version>0.0.1-SNAPSHOT</version> 13 <name>eureka-server</name> 14 <description>Demo project for Spring Boot</description> 15 16 <properties> 17 <java.version>1.8</java.version> 18 <spring-cloud.version>Greenwich.SR1</spring-cloud.version> 19 </properties> 20 21 <dependencies> 22 <dependency> 23 <groupId>org.springframework.cloud</groupId> 24 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> 25 </dependency> 26 27 <dependency> 28 <groupId>org.springframework.boot</groupId> 29 <artifactId>spring-boot-starter-test</artifactId> 30 <scope>test</scope> 31 </dependency> 32 </dependencies> 33 34 <dependencyManagement> 35 <dependencies> 36 <dependency> 37 <groupId>org.springframework.cloud</groupId> 38 <artifactId>spring-cloud-dependencies</artifactId> 39 <version>${spring-cloud.version}</version> 40 <type>pom</type> 41 <scope>import</scope> 42 </dependency> 43 </dependencies> 44 </dependencyManagement> 45 46 <build> 47 <plugins> 48 <plugin> 49 <groupId>org.springframework.boot</groupId> 50 <artifactId>spring-boot-maven-plugin</artifactId> 51 </plugin> 52 </plugins> 53 </build> 54 55 <repositories> 56 <repository> 57 <id>spring-milestones</id> 58 <name>Spring Milestones</name> 59 <url>https://repo.spring.io/milestone</url> 60 </repository> 61 </repositories> 62 63 </project>
2)对启动文件增加注解@EnableEurekaServer
1 package com.example.demo; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 7 @EnableEurekaServer 8 @SpringBootApplication 9 public class EurekaServerApplication { 10 11 public static void main(String[] args) { 12 SpringApplication.run(EurekaServerApplication.class, args); 13 } 14 15 }
3)配置文件application.yml
1 server: 2 port: 9761 3 eureka: 4 instance: 5 hostname: peer1 6 7 ###### 集群配置用(单机不需要配置) 8 client: 9 register-with-eureka: false 10 fetch-registry: false 11 service-url: 12 defaultZone: http://peer2:8761/eureka/ 13 ###### 集群配置用 14 spring: 15 application: 16 name: eureka-server
OK,只需要简单的3步,我们的注册中心就已经成功构建完成。启动服务后,可通过http://localhost:9761通过浏览器查看注册中心。
2. 网关。构建网关有两个选择,一个是zuul,另外一个是gateway。
zuul是Netflix开源的网关组件,在早期微服务架构中被广泛使用。zuul是基于servlet实现的,代码比较简单,但是性能也一般,不支持异步请求;
gateway是SpringCloud针对zuul功能和性能不足的另一个官方替代品,gateway基于webflux实现,比zuul的架构要复杂很多,内置了很多zuul没有的功能,支持异步请求。
我们分别使用zuul和gateway来构建网关服务,对比在使用上有和区别:
1)使用zuul构建需要依赖spring-cloud-starter-netflix-zuul这个starter,其pom.xml文件内容如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4 <modelVersion>4.0.0</modelVersion> 5 <parent> 6 <groupId>com.example</groupId> 7 <artifactId>ymlspringcloudparent</artifactId> 8 <version>0.0.1-SNAPSHOT</version> 9 </parent> 10 <groupId>com.example</groupId> 11 <artifactId>servicezuul</artifactId> 12 <version>0.0.1-SNAPSHOT</version> 13 <name>service-zuul</name> 14 <description>Demo project for Spring Boot</description> 15 16 <properties> 17 <java.version>1.8</java.version> 18 <spring-cloud.version>Greenwich.SR1</spring-cloud.version> 19 </properties> 20 21 <dependencies> 22 <dependency> 23 <groupId>org.springframework.boot</groupId> 24 <artifactId>spring-boot-starter-web</artifactId> 25 </dependency> 26 <dependency><!-- 注册中心的客户端 --> 27 <groupId>org.springframework.cloud</groupId> 28 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> 29 </dependency> 30 <dependency><!-- zuul网关依赖 --> 31 <groupId>org.springframework.cloud</groupId> 32 <artifactId>spring-cloud-starter-netflix-zuul</artifactId> 33 </dependency> 34 35 <dependency> 36 <groupId>org.springframework.boot</groupId> 37 <artifactId>spring-boot-starter-test</artifactId> 38 <scope>test</scope> 39 </dependency> 40 </dependencies> 41 42 <dependencyManagement> 43 <dependencies> 44 <dependency> 45 <groupId>org.springframework.cloud</groupId> 46 <artifactId>spring-cloud-dependencies</artifactId> 47 <version>${spring-cloud.version}</version> 48 <type>pom</type> 49 <scope>import</scope> 50 </dependency> 51 </dependencies> 52 </dependencyManagement> 53 54 <build> 55 <plugins> 56 <plugin> 57 <groupId>org.springframework.boot</groupId> 58 <artifactId>spring-boot-maven-plugin</artifactId> 59 </plugin> 60 </plugins> 61 </build> 62 63 </project>
对启动文件添加注释@EnableZuulProxy
1 package com.example.demo; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 6 import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 7 import org.springframework.cloud.netflix.zuul.EnableZuulProxy; 8 9 @SpringBootApplication 10 @EnableEurekaClient 11 @EnableDiscoveryClient 12 @EnableZuulProxy 13 public class ServiceZuulApplication { 14 15 public static void main(String[] args) { 16 SpringApplication.run(ServiceZuulApplication.class, args); 17 } 18 19 }
配置文件内容application.yml内容如下:
1 server: 2 port: 9769 3 spring: 4 application: 5 name: service-zuul 6 7 ###### 注册服务到注册中心 8 eureka: 9 client: 10 service-url: 11 defaultZone: http://localhost:9761/eureka/ 12 13 ##### 配置微服务路由 14 zuul: 15 routes: 16 api-a: 17 path: /api-a/** 18 serviceId: service-ribbon 19 api-b: 20 path: /api-b/** 21 serviceId: service-feign
文件中需要注意的是在zuul中对服务路由的配置方式。
2)使用gateway构建需要依赖spring-cloud-starter-gateway这个starter,其pom.xml文件内容如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4 <modelVersion>4.0.0</modelVersion> 5 <parent> 6 <groupId>com.example</groupId> 7 <artifactId>ymlspringcloudparent</artifactId> 8 <version>0.0.1-SNAPSHOT</version> 9 </parent> 10 <groupId>com.example</groupId> 11 <artifactId>servicegateway</artifactId> 12 <version>0.0.1-SNAPSHOT</version> 13 <name>service-gateway</name> 14 <description>Demo project for Spring Boot</description> 15 16 <properties> 17 <java.version>1.8</java.version> 18 <spring-cloud.version>Greenwich.SR1</spring-cloud.version> 19 </properties> 20 21 <dependencies> 22 <dependency> 23 <groupId>org.springframework.cloud</groupId> 24 <artifactId>spring-cloud-starter-gateway</artifactId> 25 </dependency> 26 <dependency> 27 <groupId>org.springframework.cloud</groupId> 28 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> 29 </dependency> 30 31 <dependency> 32 <groupId>org.springframework.boot</groupId> 33 <artifactId>spring-boot-starter-test</artifactId> 34 <scope>test</scope> 35 </dependency> 36 </dependencies> 37 38 <dependencyManagement> 39 <dependencies> 40 <dependency> 41 <groupId>org.springframework.cloud</groupId> 42 <artifactId>spring-cloud-dependencies</artifactId> 43 <version>${spring-cloud.version}</version> 44 <type>pom</type> 45 <scope>import</scope> 46 </dependency> 47 </dependencies> 48 </dependencyManagement> 49 50 <build> 51 <plugins> 52 <plugin> 53 <groupId>org.springframework.boot</groupId> 54 <artifactId>spring-boot-maven-plugin</artifactId> 55 </plugin> 56 </plugins> 57 </build> 58 59 </project>
启动文件内容如下:
1 package com.example.demo; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 7 @SpringBootApplication 8 @EnableEurekaClient 9 public class ServiceGatewayApplication { 10 11 public static void main(String[] args) { 12 SpringApplication.run(ServiceGatewayApplication.class, args); 13 } 14 15 }
配置文件application.yml内容如下:
1 server: 2 port: 8081 3 spring: 4 application: 5 name: service-gateway 6 cloud: 7 8 ##### 微服务路由配置 9 gateway: 10 discovery: 11 locator: 12 enabled: true 13 lower-case-service-id: true 14 routes: 15 - id: service-hi 16 uri: lb://SERVICE-HI 17 predicates: 18 - Path=/demo/** 19 filters: 20 - StripPrefix=1 21 22 ##### 注册到注册中心 23 eureka: 24 client: 25 service-url: 26 defaultZone: http://peer1:9761/eureka/
需要注意gateway中对于路由的配置与zuul中有所不同。
3. 微服务版的helloword。
现在我们使用spring web来构建一个输出helloworld的api接口
pom.xml文件内容如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4 <modelVersion>4.0.0</modelVersion> 5 <parent> 6 <groupId>com.example</groupId> 7 <artifactId>ymlspringcloudparent</artifactId> 8 <version>0.0.1-SNAPSHOT</version> 9 </parent> 10 <groupId>com.example</groupId> 11 <artifactId>eurekaclient</artifactId> 12 <version>0.0.1-SNAPSHOT</version> 13 <name>eureka-client</name> 14 <description>Demo project for Spring Boot</description> 15 16 <properties> 17 <java.version>1.8</java.version> 18 <spring-cloud.version>Greenwich.SR1</spring-cloud.version> 19 </properties> 20 21 <dependencies> 22 <dependency> 23 <groupId>org.springframework.cloud</groupId> 24 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> 25 </dependency> 26 <dependency> 27 <groupId>org.springframework.boot</groupId> 28 <artifactId>spring-boot-starter-web</artifactId> 29 </dependency> 30 31 <dependency> 32 <groupId>org.springframework.boot</groupId> 33 <artifactId>spring-boot-starter-test</artifactId> 34 <scope>test</scope> 35 </dependency> 36 </dependencies> 37 38 <dependencyManagement> 39 <dependencies> 40 <dependency> 41 <groupId>org.springframework.cloud</groupId> 42 <artifactId>spring-cloud-dependencies</artifactId> 43 <version>${spring-cloud.version}</version> 44 <type>pom</type> 45 <scope>import</scope> 46 </dependency> 47 </dependencies> 48 </dependencyManagement> 49 50 <build> 51 <plugins> 52 <plugin> 53 <groupId>org.springframework.boot</groupId> 54 <artifactId>spring-boot-maven-plugin</artifactId> 55 </plugin> 56 </plugins> 57 </build> 58 59 <repositories> 60 <repository> 61 <id>spring-milestones</id> 62 <name>Spring Milestones</name> 63 <url>https://repo.spring.io/milestone</url> 64 </repository> 65 </repositories> 66 67 </project>
启动类
1 package com.example.demo; 2 3 import org.springframework.beans.factory.annotation.Value; 4 import org.springframework.boot.SpringApplication; 5 import org.springframework.boot.autoconfigure.SpringBootApplication; 6 import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 7 import org.springframework.web.bind.annotation.RequestMapping; 8 import org.springframework.web.bind.annotation.RequestParam; 9 import org.springframework.web.bind.annotation.RestController; 10 11 @EnableEurekaClient 12 @SpringBootApplication 13 @RestController 14 public class EurekaClientApplication { 15 16 public static void main(String[] args) { 17 SpringApplication.run(EurekaClientApplication.class, args); 18 } 19 20 /** 21 * 微服务版helloworld 22 * @return 23 */ 24 @RequestMapping(value = "/helloworld") 25 public String helloWorld() { 26 return "Hello World"; 27 } 28 29 }
配置文件application.yml
1 server: 2 port: 9762 3 spring: 4 application: 5 name: service-hi 6 eureka: 7 client: 8 service-url: 9 defaultZone: http://localhost:9761/eureka/
OK,现在注册中心构建成功,网关服务构建成功,helloworld微服务也构建成功了,将这3个服务依次启动,并在网关服务中配置helloworld服务的路由,即可成功访问:
在浏览器中输入:http://localhost:8081/service-hi/helloworld
可以看到输出结果:Hello World
以上是一个微服务版的helloworld例子。例子虽然简单,但是仍然完成了从服务注册,到网关路由以及服务消费的全过程。以下是架构图.
当然在生产环境的服务器框架中,还有很多比如认证、授权、负载均衡、断路保护、动态配置中心、监控、链路跟踪等等辅助生态功能。在后续的章节中我们再慢慢介绍。