前言介绍
本章节提供一个基于Eurka的服务注册中心,两个服务提供者之后分别使用Ribbon、Fegin方式进行调用,测试负载均衡。
服务提供者Service Provider 本质上是一个 Eureka Client,它在服务启动时,会调用服务注册方法,向 Eureka Server注册接口服务信息,包括地址、端口、服务名、入参、返回值等。当Eureka Server收到注册信息后,会维护在自己的注册列表,如下;
1private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry 2 = new ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>();
服务消费者Service Consumer 本质也是一个 Eureka Client,它在服务启动时,也会向 Eureka Server 注册服务信息。同时在启动后会从Eureka Server 上获取所有实例的注册信息,包括 IP 地址、端口等,并缓存到本地。这个获取有一定的延时,因此我们在实际开发过程中如果服务方尚未启动完成,调用方不要着急启动避免造成调用失败。
案例说明
本案例在itstack-demo-springcloud-02工程中提供单个服务注册、服务提供方、Ribbon调用、Fegin调用,通过修改端口启动2个提供方来模拟测试负载均衡。
环境准备
1、jdk 1.8
2、Spring Boot 2.0.6.RELEASE
3、Spring Cloud Finchley.SR2
代码示例
1itstack-demo-springcloud-02 2├── itstack-demo-springcloud-eureka-client 3│ └── src 4│ └── main 5│ ├── java 6│ │ └── org.itstack.demo 7│ │ ├── web 8│ │ │ └── EurekaClientController.java 9│ │ └── EurekaClientApplication.java 10│ └── resources 11│ └── application.yml 12├── itstack-demo-springcloud-eureka-server 13│ └── src 14│ └── main 15│ ├── java 16│ │ └── org.itstack.demo 17│ │ └── EurekaServerApplication.java 18│ └── resources 19│ └── application.yml 20├── itstack-demo-springcloud-feign 21│ └── src 22│ └── main 23│ ├── java 24│ │ └── org.itstack.demo 25│ │ ├── service 26│ │ │ └── FeignService.java 27│ │ ├── web 28│ │ │ └── FeignController.java 29│ │ └── FeignApplication.java 30│ └── resources 31│ └── application.yml 32└── itstack-demo-springcloud-ribbon 33 └── src 34 └── main 35 ├── java 36 │ └── org.itstack.demo 37 │ ├── service 38 │ │ └── RibbonService.java 39 │ ├── web 40 │ │ └── RibbonController.java 41 │ └── RibbonApplication.java 42 └── resources 43 └── application.yml
完整代码欢迎关注公众号:bugstack虫洞栈 | 回复“SpringCloud专题”进行下载
itstack-demo-springcloud-eureka-client | 服务提供方
提供一个查询用户信息的简单方法,在配置文件中通过修改端口启动2次,模拟双实例应用,为调用方负载做准备。
web/EurekaClientController.java | 注意@EnableEurekaClient用于向注册中心提供服务
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@EnableEurekaClient 7@RestController 8public class EurekaClientController { 9 10 @Value("${server.port}") 11 private int port; 12 13 @RequestMapping(path = "/api/queryUserInfo", method = RequestMethod.GET) 14 public String queryUserInfo(@RequestParam String userId) { 15 return "Hi 微信公众号:bugstack虫洞栈 | " + userId + " >: from eureka client port: " + port; 16 } 17 18}
EurekaClientApplication.java | 服务启动类
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@SpringBootApplication 7public class EurekaClientApplication { 8 9 public static void main(String[] args) { 10 SpringApplication.run(EurekaClientApplication.class, args); 11 } 12 13}
application.yml | 配置文件链接服务注册中心,8001\8002分别配置启动
1server: 2 port: 8001 / 8002 3 4spring: 5 application: 6 name: itstack-demo-springcloud-eureka-client 7 8eureka: 9 client: 10 serviceUrl: 11 defaultZone: http://localhost:7397/eureka/
itstack-demo-springcloud-eureka-server | 单个服务注册中心
服务注册中心用于承载接口提供方向上注册,同时正在调用方链接后可以获取指定应用的服务实例。
EurekaServerApplication.java | 通过注解@EnableEurekaServer启动服务注册与发现中心
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@SpringBootApplication 7@EnableEurekaServer 8public class EurekaServerApplication { 9 10 public static void main(String[] args) { 11 SpringApplication.run( EurekaServerApplication.class, args ); 12 } 13 14}
application.yml | 服务注册中心配置文件,端口7397和我们之前写netty的服务的端口一致
1server: 2 port: 7397 3 4eureka: 5 instance: 6 hostname: localhost 7 client: 8 registerWithEureka: false 9 fetchRegistry: false 10 serviceUrl: 11 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ 12 13spring: 14 application: 15 name: itstack-demo-springcloud-eureka-server
itstack-demo-springcloud-feign | Feign服务调用方
Feign 是一个声明式的 Web Service 客户端,它的目的就是让 Web Service 调用更加简单。它整合了 Ribbon 和 Hystrix,从而让我们不再需要显式地使用这两个组件。Feign 还提供了 HTTP 请求的模板,通过编写简单的接口和插入注解,我们就可以定义好 HTTP 请求的参数、格式、地址等信息。接下来,Feign 会完全代理 HTTP 的请求,我们只需要像调用方法一样调用它就可以完成服务请求。
Feign 具有如下特性:
可插拔的注解支持,包括 Feign 注解和 JAX-RS 注解
支持可插拔的 HTTP 编码器和解码器
支持 Hystrix 和它的 Fallback
支持 Ribbon 的负载均衡
支持 HTTP 请求和响应的压缩
service/FeignService.java | 注解方式调用,方便易用。@FeignClient会在调用时进行解析服务到具体的http://ip:port/
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@FeignClient(value = "itstack-demo-springcloud-eureka-client") 7public interface FeignService { 8 9 @RequestMapping(value = "/api/queryUserInfo", method = RequestMethod.GET) 10 String queryUserInfo(@RequestParam String userId); 11 12}
web/FeignController.java | 使用接口提供服务 From Feign
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@RestController 7public class FeignController { 8 9 @Resource 10 private FeignService ribbonService; 11 12 @RequestMapping(path = "/api/queryUserInfo", method = RequestMethod.GET) 13 public String queryUserInfo(@RequestParam String userId) { 14 return ribbonService.queryUserInfo(userId) + " From Feign"; 15 } 16 17}
FeignApplication.java | 注解@EnableEurekaClient、@EnableFeignClients、@EnableDiscoveryClient获取调用注册中心服务
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@SpringBootApplication 7@EnableEurekaClient 8@EnableDiscoveryClient 9@EnableFeignClients 10public class FeignApplication { 11 12 public static void main(String[] args) { 13 SpringApplication.run(FeignApplication.class, args); 14 } 15 16}
application.yml | eureka服务配置,从注册中心获取可用服务
1server: 2 port: 9001 3 4spring: 5 application: 6 name: itstack-demo-springcloud-feign 7 8eureka: 9 client: 10 serviceUrl: 11 defaultZone: http://localhost:7397/eureka/
itstack-demo-springcloud-ribbon | Ribbon服务调用方
Ribbon是一个基于 HTTP 和 TCP 的客户端负载均衡器。它可以通过在客户端中配置 ribbonServerList 来设置服务端列表去轮询访问以达到均衡负载的作用。
当 Ribbon 与 Eureka 联合使用时,ribbonServerList 会被 DiscoveryEnabledNIWSServerList 重写,扩展成从 Eureka 注册中心中获取服务实例列表。同时它也会用 NIWSDiscoveryPing 来取代 IPing,它将职责委托给 Eureka 来确定服务端是否已经启动。
service/RibbonService.java | 接口式硬编码调用不太易于维护,因此也是比较少用的方式
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@Service 7public class RibbonService { 8 9 @Autowired 10 private RestTemplate restTemplate; 11 12 public String queryUserInfo(String userId) { 13 return restTemplate.getForObject("http://ITSTACK-DEMO-SPRINGCLOUD-EUREKA-CLIENT/api/queryUserInfo?userId=" + userId, String.class); 14 } 15 16}
web/RibbonController.java | 使用接口提供服务 From Ribbon
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@RestController 7public class RibbonController { 8 9 @Resource 10 private RibbonService ribbonService; 11 12 @RequestMapping(path = "/api/queryUserInfo", method = RequestMethod.GET) 13 public String queryUserInfo(@RequestParam String userId) { 14 return ribbonService.queryUserInfo(userId) + " From Ribbon"; 15 } 16 17}
RibbonApplication.java | 通过注解@LoadBalanced注册rest模版,用于Ribbon接口调用
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@SpringBootApplication 7@EnableEurekaClient 8@EnableDiscoveryClient 9public class RibbonApplication { 10 11 public static void main(String[] args) { 12 SpringApplication.run(RibbonApplication.class, args); 13 } 14 15 @Bean 16 @LoadBalanced 17 RestTemplate restTemplate() { 18 return new RestTemplate(); 19 } 20 21}
application.yml | eureka服务配置,从注册中心获取可用服务
1server: 2 port: 9002 3 4spring: 5 application: 6 name: itstack-demo-springcloud-ribbon 7 8eureka: 9 client: 10 serviceUrl: 11 defaultZone: http://localhost:7397/eureka/
测试验证
1、启动服务注册中心itstack-demo-springcloud-eureka-server
2、分别启动itstack-demo-springcloud-eureka-client,修改端口8001、8002启动两次提供两个服务
3、启动itstack-demo-springcloud-feign
4、启动itstack-demo-springcloud-ribbon
5、访问服务注册中心http://localhost:7397/
6、访问服务提供方;http://localhost:8001/api/queryUserInfo?userId=111 | 说明服务正常
1Hi 微信公众号:bugstack虫洞栈 | 111 >: from eureka client port: 8001
7、访问Feign服务调用放,每次刷新会看到负载均衡调用到不同端口服务:http://localhost:9001/api/queryUserInfo?userId=111
1Hi 微信公众号:bugstack虫洞栈 | 111 >: from eureka client port: 8002 From Feign 2 3Hi 微信公众号:bugstack虫洞栈 | 111 >: from eureka client port: 8001 From Feign
8、访问Ribbon服务调用放,每次刷新会看到负载均衡调用到不同端口服务:http://localhost:9002/api/queryUserInfo?userId=111
1Hi 微信公众号:bugstack虫洞栈 | 111 >: from eureka client port: 8001 From Ribbon 2 3Hi 微信公众号:bugstack虫洞栈 | 111 >: from eureka client port: 8002 From Ribbon
综上总结
1、在使用SpringCloud时我们可以很轻松的使用到注册中心与很简单的方式去做服务调用
2、以上负载均衡,都是以轮询访问的方式实现的,实际开发过程中还会有一些依赖于机器性能、GC、调用量、响应时间等计算的权重值来做负载IRule
3、服务注册中心,负责维护注册的服务列表,同其他服务注册中心一样,支持高可用配置
4、服务提供方,作为一个 Eureka Client,向 Eureka Server 做服务注册、续约和下线等操作,注册的主要数据包括服务名、机器IP、port、域名等
5、服务消费方,作为一个 Eureka Client,向 Eureka Server 获取 Service Provider 的注册信息,并通过远程调用/负载均衡与 Service Provider 进行通信