一、Spring Cloud Netflix简介
SpringCloud是一个基于SpringBoot实现的云应用开发工具,它为基于JVM的云应用开发中的配置故那里、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了简单的开发方式。
SpringCloud下包含了多个工程,其中的Spring Cloud Netflix提供了一系列搭建微服务基础架构的功能组件。
Netflix的部分组件及功能特性如下:
Eureka(服务注册与发现框架):一个基于REST风格的服务组件,用于定位服务,以实现云端的负载均衡和中间层服务器的故障转移
Hystrix(服务容错组件):容错管理工具,旨在通过控制服务和第三方库的节点,从而对延迟和故障提供强大的容村能力
Zuul(服务网关):边缘服务工具,提供动态路由、监控、贪心、安全等边缘服务
Ribbon(客户端负载均衡器):提供客户端负载均衡算法,将Netflix的中间层服务连接起来
Feign(声明式HTTP客户端):可以创建声明式、模板化的HTTP客户端,进行微服务调用
二、Eureka(服务注册与发现框架)
1、服务注册与发现
在进行普通架构的应用开发时,如果服务端提供了一个REST API或者Thrift API的服务,客户端为了能完成一次服务请求,需要知道服务实例的网络位置(IP:Port)。传统架构的应用都是运行在物理硬件之上,服务实例的网络位置时相对固定的。
但是在微服务架构之下,一个微服务可能会在某一时刻进行销毁重建,或是伸缩漂移,这样一来服务实例的网络位置就变得不可预知。为了解决这一问题,我们需要在微服务架构中引入了服务注册与发现功能。
服务发现有如下两种模式:
a、客户端服务发现(Client-Side Discovery)
客户端负责决定可用的服务实例的网络地址,以及围绕他们的负载均衡。客户端向服务注册表发送一个请求,服务注册表是一个可用服务实例的数据库。客户端使用一个负载均衡算法,去选择一个可用的服务实例,来响应这个请求。
一个服务实例被启动,他的网络地址会被写到注册表上,当服务实例终止,会从注册表中删除。这个服务实例的注册表通过心跳机制动态刷新。
b、服务端服务发现(Server-Side Discovery)
客户端通过负载均衡器向某个服务提出请求,负载均衡器向服务注册表发出请求,将每个请求转发往可用的服务实例。和客户端发现一样,服务实例启动时在服务注册表中注册,当服务实例销毁,将会从服务注册表中进行删除。
客户端无需关注发现的细节,只需要简单的向负载均衡器发送请求,实际上减少了编程语言框架需要完成的服务发现逻辑。
缺点是,除非部署环境能够提供负载均衡,否则负载均衡器是另外一个需要配置管理的高可用系统功能。
2、Eureka介绍
Eureka是一种基于REST的服务,主要用于AWS云中的定位服务,以实现中间层服务器的负载均衡和故障转移。Eureka提供了基于Java的客户端组件,使得与服务的交互更容易。客户端还有一个内置的负载均衡器,用于执行基本的轮训负载均衡。
Eureka架构体系图如下:
Eureka Server实例作为服务注册中心的角色,负责接受来自Eureka Client的服务注册,并加以保存。
Eureka Client内嵌于一个微服务中,会将当前实例作为服务实例注册到服务注册中心(Eureka Server),注册内容包括IP、Port和服务实例名称。消费者同样内嵌了Eureka Client,在进行服务调用的时候,可以通过Eureka提供的DiscoveryClient和服务实例的名称,从服务注册中心(Eureka Server)获取服务实例列表,然后得到服务实例的IP和Port,以完成服务调用。
3、示例代码
a、Eureka Server(服务注册中心)
1)在IDE中创建一个Maven项目,然后在该项目的pom.xml文件中,添加以下依赖。
org.springframework.boot spring-boot-starter-parent 1.5.1.RELEASE UTF-8 1.8
org.springframework.boot spring-boot-maven-plugin
org.springframework.cloud spring-cloud-starter-eureka-server
org.springframework.boot spring-boot-starter-test test org.springframework.cloud spring-cloud-dependencies Camden.SR5 pom import |
2)在src/main/java包下创建EurekaRegistryDemo类,并使用@EnableEurekaServer和@SpringBootApplication注解
@EnableEurekaServer @SpringBootApplication public class EurekaRegistryDemo { public static void main( String[] args ) { SpringApplication.run(EurekaRegistryDemo.class, args); } } |
3)在src/main/resources包下创建application.yml配置文件
server: port: 8080 #当前应用端口 spring: application: name: eureka-registry #应用名称 eureka: client: serviceUrl: defaultZone: http://localhost:8080/eureka/ #Eureka Server地址 register-with-eureka: false #因为自己是注册中心,所以不注册自己 fetch-registry: false instance: metadataMap: instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}} |
4)运行EurekaRegistryDemo.java,将会启动服务注册中心,访问地址为:localhost:8080
b、Eureka Client(服务提供者)
1)创建一个maven项目作为服务提供者,提供一个REST服务,并且通过Eureka Client,把服务实例注册到注册中心
项目pom.xml文件和上面Eureka Server相同。
2)在src/main/java包下创建以下java类
应用启动类:
@SpringBootApplication @EnableEurekaClient @EnableAutoConfiguration public class EurekaClientDemo {
public static void main(String[] args) { new SpringApplicationBuilder(EurekaClientDemo.class).web(true).run(args); } } |
REST服务接口:
public interface TestApi { @RequestMapping(value="/testhello/{name}", method=RequestMethod.GET) public String testHello(@PathVariable("name") String name); } |
REST服务实现类:
@RestController public class TestControl implements TestApi {
public String testHello(@PathVariable("name")String name) { return "Hello world,"+name; }
} |
3)在src/main/resources包下创建配置文件application.properties
这里的配置文件使用了另外一种文件格式,如果使用Eureka Server相同的文件格式也是可以的。
server.port=9090 spring.application.name=eureka.client eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka/ eureka.instance.appname=eureka.client.01 |
4)启动
EurekaClientDemo类,刷新注册中心页面,将会看到服务提供者实例已经注册到注册中心,并且可以直接在浏览器访问该实例暴露出来的REST服务
三、Feign(服务消费者)
Feign可以创建声明式、模板化的HTTP客户端,进行微服务调用。接下来我们将会使用Feign和Eureka Client编写一个服务消费者,从Eureka Server中查询到服务提供实例的调用地址,并完成服务调用。
1、创建maven项目,pom.xml文件中的依赖配置如下:
org.springframework.boot spring-boot-starter-parent 1.5.1.RELEASE UTF-8 1.8 org.springframework.boot spring-boot-maven-plugin
org.springframework.cloud spring-cloud-starter-feign
org.springframework.cloud spring-cloud-starter-eureka
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.cloud spring-cloud-dependencies Camden.SR5 pom import |
2、创建应用程序启动类FeginApplication,并且添加@SpringBootApplication和@EnableDiscoveryClient注解
@SpringBootApplication @EnableDiscoveryClient
public class FeginApplication { public static void main(String[] args) { SpringApplication.run(FeginApplication.class, args); }
} |
3、创建一个REST服务实现类,在实现类中使用Eureka提供的DiscoveryClient类,通过服务提供者实例的名称从注册中心中查询服务提供者实例的具体地址,然后使用Feign进行服务调用。在这里需要使用到服务提供者的REST服务接口,生成代理,进行服务调用,所以需要依赖服务提供者的服务接口。在服务提供者项目中将接口导出成jar,然后给当前项目依赖就可以。
@RestController public class TestService {
private TestApi computeClient; private static final String SERVER_NAME = "eureka.client";
@Autowired private DiscoveryClient discoveryClient; @RequestMapping(value = "/gethello/{name}", method = RequestMethod.GET) public String getHello(@PathVariable("name") String name) { Builder feignBuilder= Feign.builder().decoder(new ResponseEntityDecoder(new SpringDecoder(new ObjectFactory(){ public HttpMessageConverters getObject() throws BeansException { return new HttpMessageConverters(); } }))).client(new ApacheHttpClient()).contract(new SpringMvcContract()); computeClient = feignBuilder.target(TestApi.class,discoveryClient.getInstances(SERVER_NAME).get(0).getUri().toString()); return computeClient.testHello(name); } } |
代码说明:
a、discoveryClient.getInstances(SERVER_NAME).get(0).getUri().toString()
通过discoveryClient,从服务注册中心中,获取名为SERVER_NAME,即“eureka.client”的服务实例列表。因为当前只有一个服务提供者,所以直接取列表中的第一个实例的地址信息。
b、Feign默认的decoder需要在被调用的服务接口上添加@RequestLine(“GET /test/{name}”)才能被正常调用。在这里为了能直接支持@RequestMapping注解,所以构造Feign的时候添加了devoder,没有使用默认的
c、代码中没有使用默认的FeignClient进行调用,而是替换成了ApacheHttpClient
4、在src/main/resources包下,创建配置文件application.properties
server.port=7070 spring.application.name=eureka.test eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka/ eureka.instance.appname=eureka.test.01 |
5、启动应用后,可以在服务注册中心页面中看到服务消费者实例也注册到了注册中心里,此时在浏览器访问localhost:7070/gethello/aaa可以测试服务调用功能。