Eureka注册中心,Nacos阿里注册中心,Ribbon负载均衡
SpringCloud
一系列框架的有序集合,基于SpringBoot将其整和了起来,简化开发
- SpringCloud和Dubbo对比:
- Dubbo使用PRC通讯协议
调用者通过配置或者注解调用注册中心的服务
<!--3.1配置dubbo包扫描,注解调用服务-->
<!--<dubbo:annotation package="com.yh" />-->
<!--3.2xml配置方式调用服务-->
<dubbo:reference id="demoService" interface="com.yh.ours.UserService" />
@Reference()
private UserService userService;
- SpringCloud使用RESTful完成通信
Dubbo性能强,小型微服务
SpringCloud功能多,大型微服务开发
- SpringBoot自身RPC调用
使用RestTemplate来完成
服务提供者:产品服务
server:
port: 8000
# 配置服务名称
spring:
application:
name: product
@RestController
@RequestMapping("/product")
public class IProductController {
@Autowired
private IProductService iProductService;
/*@RequestMapping("/findOne")
public Product findById(int id){
return iProductService.findById(id);
}*/
@RequestMapping("/findOne/{id}")
public Product findById(@PathVariable("id") int id){
return iProductService.findById(id);
}
}
服务消费者:订单服务
server:
port: 9000
@RestController
@RequestMapping("/orders")
public class IOrdersController {
@Autowired
private RestTemplate restTemplate;//用于完成RPC调用
@Autowired
private DiscoveryClient discoveryClient;;//该对象可以获取到注册中心中的具体的服务的信息。如服务的ip、端口信息
@RequestMapping("/find")
public Product find(int id){
//通过RestTemplate来完成直接远程调用服务
String serviceName="product";
//方法一:根据服务发现对象获取服务信息然后完成调用。注意该方法使用条件是Nacos做注册中心
//根据服务名获取注册的服务实例
Lsit<ServiceInstance> serviceList=discoveryClient.getInstances(serviceName);
//从中随机取出一个。用stram流来操作。
ServiceInstance aervice=serviceList.stream().findAny();
//完成RPC远程调用
Product forObject = restTemplate.getForObject("http://"+service.getHost()+":"+service.getPort()+"/product/findOne?id=1", Product.class);
//方法二:手动拼接服务信息完成调用。
//当被调用服务没有配置spring.application.name时,直接手动拼接
Product forObject = restTemplate.getForObject("http://localhost:8000/product/findOne?id=1", Product.class);
return forObject;
}
}
注入RestTemplate对象:
配置类或引导类注入即可
/*RestTemplate配置类,向容器中注入一个RestTemplate对象*/
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
SpringCloud服务治理
管理服务,如zookeeper的注册中心
下边三个为常用服务治理组件,其共功能相似
Eureka
分为服务端(即注册中心)和客户端(服务调用和地址存放者)
服务端需要自己搭建一个模块来实现
- 快速入门
服务端搭建
- 创建eureka-service模块
引入SpringBoot起步依赖和Web依赖
<!--导入SpringBoot起步依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 引入SpringCloud和eureka-server相关依赖
<!--导入Spring-Cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
- yaml中完成EurekaServer得相关配置
# 配置tomcat端口
server:
port: 8761
# eureka 配置
# eureka 一共有4部分 配置
# 1. dashboard:eureka的web控制台配置
# 2. server:eureka的服务端配置
# 3. client:eureka的客户端配置
# 4. instance:eureka的实例配置
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
register-with-eureka: false # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
fetch-registry: false # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
- 启动该模块:该模块即为注册中心
运行该模块引导类
引导类:必须添加@EnableEurekaServer注解来激活Eureka Server,新版本不需要
@SpringBootApplication
// 启用EurekaServer
@EnableEurekaServer
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class,args);
}
}
- 通过ip:8761访问
http://localhost:8761/
客户端搭建
建立与EurekaServer得连接并将服务注册到Eureka上
- 创建消费者模块,引入SpringBoot和web依赖
<!--导入SpringBoot起步依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 引入SpringCloud和eureka-client相关依赖
<!--导入Spring-Cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- yaml中完成对eureka的配置
server:
port: 9000
# eureka客户端配置
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
#配置应用名,在获取时需要使用
spring:
application:
name: eureka-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
- 完成基于eureka动态的RPC调用
除了要配置RestTemplate对象实现PRC,还需要直接注入DiscoveryClient对象来获取服务的动态ip和端口
RestTemplate配置类:
/*RestTemplate配置类,向容器中注入一个RestTemplate对象*/
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
Controller调用类
@RestController
@RequestMapping("/orders")
public class IOrdersController {
//注入RestTemplate,用来实现远程调用
@Autowired
private RestTemplate restTemplate;
//注入DiscoveryClient对象,用于动态获取服务ip和host
@Autowired
private DiscoveryClient discoveryClient;
//第一种访问时用?id=1来访问http://localhost:9000/orders/find?id=1
/* @GetMapping("/find")
public Product find(int id){
}*/
//第二种访问时用/1来访问http://localhost:9000/orders/find/1
@GetMapping("/find/{id}")
public Product find(@PathVariable("id") int id){
//演示discoveryClient 使用
//返回是集合是因为集群环境时同一服务可能被部署多份
List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER");//EUREKA-PROVIDER为eureka中注册得服务名
//判断集合是否有数据
if(instances == null || instances.size() == 0){
//集合没有数据
return null;
}
//获取单个服务实例
ServiceInstance instance = instances.get(0);
String host = instance.getHost();//获取ip
int port = instance.getPort();//获取端口
System.out.println(host);
System.out.println(port);
String url = "http://"+host+":"+port+"/ /product/findOne/"+id;
//String url=;//"http://localhost:8000/product/findOne?id=1"原来不变得写法
//通过RestTemplate来完成直接远程调用服务
Product forObject = restTemplate.getForObject(url, Product.class);
return forObject;
}
}
- 配置
- server服务端配置
server:
port: 8761
# eureka 配置
# eureka 一共有4部分 配置
# 1. dashboard:eureka的web控制台配置
# 2. server:eureka的服务端配置
# 3. client:eureka的客户端配置
# 4. instance:eureka的实例配置
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
register-with-eureka: false # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
fetch-registry: false # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
server:
enable-self-preservation: false # 关闭自我保护机制
eviction-interval-timer-in-ms: 3000 # 检查服务的时间间隔
- 实例(客户端)配置
server:
port: 8001
eureka:
instance:
hostname: localhost # 主机名
prefer-ip-address: true # 将当前实例的ip注册到eureka server 中。默认是false 注册主机名
ip-address: 127.0.0.1 # 设置当前实例的ip,自定义
instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port} # 设置web控制台显示的 实例id
lease-renewal-interval-in-seconds: 3 # 每隔3 秒发一次心跳包
lease-expiration-duration-in-seconds: 9 # 如果9秒没有发心跳包,服务器呀,你把我干掉吧~
client:
service-url:
defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: eureka-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
instance-id
eurake的自我保护机制:
eurekaServer默认开启,即当某注册的服务因网络等问题挂了,服务端在一定时间内保留该服务的一种保护机制
Eurake高可用
搭建多个EurakeServer,即搭建集群
搭建步骤:
-
创建2个eurekaServer模块
-
导入SpringgBoot起步依赖和SpringCloud依赖以及eurekaServer依赖和web依赖
<!--导入SpringBoot起步依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<!--导入Spring-Cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
- 修改yaml配置文件
互相注册
修改hostname: eureka-server-1时需要更改hosts文件
添加两个Server的配置
127.0.0.1 eureka-server-1
127.0.0.1 eureka-server-2
eurakeServer1:
# 配置tomcat端口
server:
port: 8761
# eureka高可用配置
eureka:
instance:
hostname: eureka-server-1 # 主机名
client:
service-url:
defaultZone: http://eureka-server-2:8762/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
#配置eureka名
spring:
application:
name: eureka-server-ha
eurakeServer2:
# 配置tomcat端口
server:
port: 8762
# eureka高可用配置
eureka:
instance:
hostname: eureka-server-2 # 主机名
client:
service-url:
defaultZone: http://eureka-server-1:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
#配置eureka名
spring:
application:
name: eureka-server-ha
-
启动两个Server服务
-
修改客户端配置文件
两个EurekaServer服务端分别注册
server:
port: 9000
# eureka客户端配置
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://eureka-server-2:8762/eureka,http://eureka-server-1:8761/eureka
#defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
#配置应用名,在获取时需要使用
spring:
application:
name: eureka-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
Consul
Nacos
注册中心+配置中心
- 解压缩
链接:https://pan.baidu.com/s/1QzeChU9VVMcObBCPUD4g_w
提取码:led9 - bin目录下启动startup.cmd
- 浏览器访问服务端http://localhost:8848/nacos
客户端配置
4. 导入依赖nacos–俩
<dependencies>
<!--导入Spring-Cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--nacos-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
- 消费端配置注册中心
server:
port: 8000
# nacos配置
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 配置nacos 服务端地址
application:
name: nacos-provider # 服务名称
- 消费端获取已注册的服务
RestTemplate执行RPC
DiscoveryClient来动态获取ip和端口
@RestController
@RequestMapping("/orders")
public class IOrdersController {
//注入RestTemplate,用来实现远程调用
@Autowired
private RestTemplate restTemplate;
//注入DiscoveryClient对象,用于动态获取服务ip和host
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/find/{id}")
public Product find(@PathVariable("id") int id){
//演示discoveryClient 使用
//返回是集合是因为集群环境时同一服务可能被部署多份
List<ServiceInstance> instances = discoveryClient.getInstances("nacos-provider");//EUREKA-PROVIDER为eureka中注册得服务名
//判断集合是否有数据
if(instances == null || instances.size() == 0){
//集合没有数据
return null;
}
//获取单个服务实例
ServiceInstance instance = instances.get(0);
String host = instance.getHost();//获取ip
int port = instance.getPort();//获取端口
System.out.println(host);
System.out.println(port);
String url = "http://"+host+":"+port+"/ /product/findOne/"+id;
//String url=;//"http://localhost:8000/product/findOne?id=1"原来不变得写法
//通过RestTemplate来完成直接远程调用服务
Product forObject = restTemplate.getForObject(url, Product.class);
return forObject;
}
}
Ribbon客户端负载均衡
客户端存放负载均衡策略
基于eureka学习
- 简化远程调用
原过程:RestTemplate调用getForObject方法传入url和class文件实现RPC而DiscoveryClient则根据注册中心中服务的名称来动态的获取注册中心中服务的ip和host端口号
简化:不在使用DiscoveryClient来动态获取ip和host
- 在配置类中声明RestTemplate时,添加注解@LoadBalanced
/*RestTemplate配置类,向容器中注入一个RestTemplate对象*/
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate2(){
return new RestTemplate();
}
}
- 在使用RestTemplate对象发起RPC请求时,将ip:host部分替换为服务提供方的应用名称即可
//注入RestTemplate,用来实现远程调用
@Autowired
private RestTemplate restTemplate;
/*使用ribbon来简化RPC*/
@GetMapping("/find2/{id}")
public Product find2(@PathVariable("id") int id){
//演示discoveryClient 使用
String url = "http://EUREKA-PROVIDER/ /product/findOne/"+id;
//String url=;//"http://localhost:8000/product/findOne?id=1"原来不变得写法
//通过RestTemplate来完成直接远程调用服务
Product forObject = restTemplate.getForObject(url, Product.class);
return forObject;
}
- 负载均衡
提供了7种负载均衡策略:
需要指定负载均衡策略和服务提供方的应用名称
实现:
- 配置类实现:配置负载均衡策略
/*Ribbon负载均衡策略配置类*/
@Configuration
public class MyRule {
@Bean
public IRule iRule(){
//随机策略
return new RandomRule();
}
}
引导类
使用注解@RibbonClient来指定服务提供方的应用名称和设置负载均衡的Bean的配置类
/*启动类*/
@SpringBootApplication
@EnableEurekaClient //该注解 在新版本中可以省略
/*
配置Ribbon的负载均衡策略
* name:设置 服务提供方的 应用名称
* configuration:设置负载均衡Bean
*/
@RibbonClient(name="EUREKA-PROVIDER",configuration = MyRule.class)
public class CustomerApp {
public static void main(String[] args) {
SpringApplication.run(CustomerApp.class);
}
}
- 配置实现
消费客户端配置:
server:
port: 9000
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
#defaultZone: http://eureka-server1:8761/eureka,http://eureka-server2:8762/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
defaultZone: http://localhost:8761/eureka
spring:
application:
name: eureka-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
# 配置的方式设置Ribbon的负载均衡策略
EUREKA-PROVIDER: # 设置的服务提供方的 应用名称
ribbon:
NFloadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 策略类