以下代码提交到git:http://47.93.254.162:8090/open/registry_center.git
浏览更多open项目:http://47.93.254.162:8090/open
一、简介
SpringCloud:基于SpringBoot基础上开发的微服务框架,是一套完整的微服务解决框架,其内容包含服务治理、注册中心、配置管理、路由管理、代理转发、控制总线、全局锁、分布式会话等。中文网:https://springcloud.cc/spring-cloud-dalston.html#spring-cloud-feign-hystrix-fallback。
1. 微服务的解决方案:
①. 服务治理:Dubb(阿里巴巴)、Dubbox(当当网)、Eureka、Consul(Apache)。
②. 分布式配置中心:disconf(百度)、Archaius(Netflix)、QConf(360)、SpringCloud、Apollo(携程)。
③. 定时任务框架:xxl-job、elastic-job、task(SpringCloud)。
④. 服务追踪:hyra(京东)、sleuth(SpringCloud)。
2.框架结构
SpringCloud Config:配置中心。
SpringCloud Netflix:核心注解。
①. Eureka:服务治理、注册中心。
②. Hystrix: 服务保护框架。
③. Ribbon:客户端负载均衡。
④. Feign:基于ribbon和hystrix的声明式服务调用组件(类似于Dubbo,但dubbo走的是tcp协议,feign是http协议)。
⑤. Zuul:网关组件、提供智能路由,访问过滤。
架构图
二、服务治理Eureka(单机版)
1. 服务治理:用于解决在远程调用rpc中服务于服务之间的依赖关系,可实现服务调、负载均衡、容错、服务的注册与发现。
2. springboot搭建
①.pom文件引入
1 <!-- 管理依赖 --> 2 <dependencyManagement> 3 <dependencies> 4 <dependency> 5 <groupId>org.springframework.cloud</groupId> 6 <artifactId>spring-cloud-dependencies</artifactId> 7 <version>Finchley.M7</version> 8 <type>pom</type> 9 <scope>import</scope> 10 </dependency> 11 </dependencies> 12 </dependencyManagement> 13 <dependencies> 14 <!--SpringCloud eureka-server --> 15 <dependency> 16 <groupId>org.springframework.cloud</groupId> 17 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> 18 </dependency> 19 <!--spring-cloud 整合 config-server --> 20 <dependency> 21 <groupId>org.springframework.cloud</groupId> 22 <artifactId>spring-cloud-config-server</artifactId> 23 </dependency> 24 <!-- SpringBoot 整合Eureka客户端 --> 25 <dependency> 26 <groupId>org.springframework.cloud</groupId> 27 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> 28 </dependency> 29 </dependencies> 30 <!-- 解决依赖有问题 --> 31 <repositories> 32 <repository> 33 <id>spring-milestones</id> 34 <name>Spring Milestones</name> 35 <url>https://repo.spring.io/libs-milestone</url> 36 <snapshots> 37 <enabled>false</enabled> 38 </snapshots> 39 </repository> 40 </repositories>
②.application.yml文件
server: port: 8100 spring: application: name: eureka eureka: instance: hostname: 127.0.0.1 client: serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #集群版将以下改成true(是否将自己注册) register-with-eureka: false #是否检索服务信息 fetch-registry: false server: #关闭自我保护机制,保证不可用的服务及时删除(单机版使用) enable-self-preservation: false #心跳监测时间 eviction-interval-time-in-ms: 2000
③. 启动类(@EnableEurekaServer:开启EurekaServer即服务端)
@SpringBootApplication @EnableEurekaServer public class AppEureka { public static void main(String[] args) { SpringApplication.run(AppEureka.class, args); } }
④. 访问地址
这里模拟一个生产者(produce)和一个消费者(consumer)调用环境
produce搭建
1 <!-- 管理依赖 --> 2 <dependencyManagement> 3 <dependencies> 4 <dependency> 5 <groupId>org.springframework.cloud</groupId> 6 <artifactId>spring-cloud-dependencies</artifactId> 7 <version>Finchley.M7</version> 8 <type>pom</type> 9 <scope>import</scope> 10 </dependency> 11 </dependencies> 12 </dependencyManagement> 13 <dependencies> 14 <!-- SpringBoot整合Web组件 --> 15 <dependency> 16 <groupId>org.springframework.boot</groupId> 17 <artifactId>spring-boot-starter-web</artifactId> 18 </dependency> 19 <!-- SpringBoot整合eureka客户端 --> 20 <dependency> 21 <groupId>org.springframework.cloud</groupId> 22 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> 23 </dependency> 24 </dependencies> 25 <!-- 注意: 这里必须要添加, 否者各种依赖有问题 --> 26 <repositories> 27 <repository> 28 <id>spring-milestones</id> 29 <name>Spring Milestones</name> 30 <url>https://repo.spring.io/libs-milestone</url> 31 <snapshots> 32 <enabled>false</enabled> 33 </snapshots> 34 </repository> 35 </repositories>
application.yml
#服务启动端口号 server: port: 8200 #服务名称(服务注册到eureka名称) spring: application: name: app-produce #服务注册到eureka地址 eureka: client: service-url: defaultZone: http://localhost:8100/eureka/ #因为该应用为注册中心,不会注册自己(集群使用) register-with-eureka: false #是否需要从eureka上获取注册信息(集群使用) fetch-registry: false
resource(controller)层
1 @RestController 2 public class ProduceResource { 3 4 @RequestMapping("/produce") 5 public String produce() { 6 7 return "生成者返回正确消息..."; 8 9 } 10 11 }
启动类(@EnableEurekaClient: 客户端开启)
1 @SpringBootApplication 2 @EnableEurekaClient 3 public class AppProduce { 4 5 public static void main(String[] args) throws Exception { 6 SpringApplication.run(AppProduce.class, args); 7 } 8 9 }
consumer搭建
pom文件和application.yml配置文件和produce一直,只需该端口即可
ConsumerResource(Controller)搭建
1 @RestController 2 public class ConsumerResource { 3 4 @Autowired 5 private RestTemplate restTemplate; 6 7 @RequestMapping("/consumer/rest") 8 public String consumerRest() { 9 10 String productUrl = "http://product/produce"; 11 String productResult = restTemplate.getForObject(productUrl, String.class); 12 13 return productResult; 14 15 } 16 17 }
注意:这里使用restTemplate调用,getForXXX方法可返回指定对象。(这里采用手动调用,一般在项目中不这么使用,这里只记录知识点)。
启动类
1 @SpringBootApplication 2 @EnableEurekaClient 3 public class AppConsumer { 4 5 public static void main(String[] args) throws Exception { 6 SpringApplication.run(AppConsumer.class, args); 7 } 8 9 @Bean 10 @LoadBalanced 11 RestTemplate restTemplate() { 12 return new RestTemplate(); 13 } 14 15 }
注意:restTemplate() 方法作用是在RestTemplate在调用Produce时有负载均衡作用。
测试
三、服务治理Eureka(集群版)
1. 搭建
在微服务调用过程中,注册中心比较重要,但是一旦单机版出现故障会导致整个微服务无法访问,此时就需要对注册中心实现集群模式。
在Eureka集群中实际上将自己作为服务向其他服务注册中心注册自己,以此就可以形成一组相互注册的服务注册中心,实现服务清单的相互同步。
register-with-eureka: true 和 fetch-registry: true
Eureka1搭建过程
1 #eureka配置中心 2 server: 3 port: 8000 4 spring: 5 application: 6 name: eureka 7 eureka: 8 instance: 9 hostname: 127.0.0.1 10 client: 11 serviceUrl: 12 #拼接地址 13 defaultZone: http://127.0.0.1:8100/eureka/ 14 #集群版将以下改成true(是否将自己注册) 15 register-with-eureka: true 16 #是否检索服务信息 17 fetch-registry: true 18 #server: 19 #关闭自我保护机制,保证不可用的服务及时删除(单机版使用) 20 #enable-self-preservation: false 21 #心跳监测时间 22 #eviction-interval-time-in-ms: 2000
注意:这里启动的端口是8000,但注册的是8100
Eureka2搭建过程
1 #eureka配置中心 2 server: 3 port: 8100 4 spring: 5 application: 6 name: eureka 7 eureka: 8 instance: 9 hostname: 127.0.0.1 10 client: 11 serviceUrl: 12 #拼接地址 13 defaultZone: http://127.0.0.1:8000/eureka/ 14 #集群版将以下改成true(是否将自己注册) 15 register-with-eureka: true 16 #是否检索服务信息 17 fetch-registry: true 18 #server: 19 #关闭自我保护机制,保证不可用的服务及时删除(单机版使用) 20 #enable-self-preservation: false 21 #心跳监测时间 22 #eviction-interval-time-in-ms: 2000
这里注册的8000
生产者的application.yml
1 ###服务启动端口号 2 server: 3 port: 8300 4 ###服务名称(服务注册到eureka名称) 5 spring: 6 application: 7 name: app-produce 8 ###服务注册到eureka地址 单机版 9 #eureka: 10 # client: 11 # service-url: 12 # defaultZone: http://localhost:8100/eureka 13 14 ###服务注册到eureka地址 集群版 15 eureka: 16 client: 17 service-url: 18 defaultZone: http://localhost:8000/eureka,http://localhost:8100/eureka 19 ###因为该应用为注册中心,不会注册自己 20 register-with-eureka: true 21 ###是否需要从eureka上获取注册信息 22 fetch-registry: true
消费者的application.yml
1 #服务启动端口号 2 server: 3 port: 8200 4 #服务名称(服务注册到eureka名称) 5 spring: 6 application: 7 name: app-consumer 8 #服务注册到eureka地址 9 #eureka: 10 # client: 11 # service-url: 12 # defaultZone: http://localhost:8100/eureka/ 13 ###服务注册到eureka地址 集群版 14 eureka: 15 client: 16 service-url: 17 defaultZone: http://localhost:8000/eureka,http://localhost:8100/eureka 18 #因为该应用为注册中心,不会注册自己(集群使用) 19 register-with-eureka: true 20 #是否需要从eureka上获取注册信息(集群使用) 21 fetch-registry: true
其他代码不变。
2. 消费者模式:在Eureka启动时,会发送一个rest请求到服务注册中心获取对应服务信息,然后缓存到本地jvm中客户端每隔30秒后从服务器上更新一次,可以通过fetch-inte-vall-seconds=30进行修改eureka.client.registry的默认值。
3. Eureka的下线:在系统运行过程中,当服务器正常关闭时,会触发一个服务下线的rest请求给Eureka的server。当服务端接收到后会将该服务状态置为下线DOWN,并且将该下线的服务广播出去。
4. Eureka的失效剔除:对于服务实例由于网络故障、内存溢出等原因不能正常下线,服务端未收到下线请求,会导致服务列表中的实例无法正常提供服务。在Eureka server启动时会创建一个定时任务每个90秒将当前清单中超时的服务剔除出去。
5. Eureka的自我保护:默认情况下Eureka client端会定时想Eureka server发送心跳包,在默认90秒钟没有收到请求变会将该服务剔除。但是Eureka server在短时间内(60秒)丢失大量的实例心跳时,Eureka server会开启自我保护机制,不会剔除该服务。
1 #eureka配置中心 2 server: 3 port: 8000 4 spring: 5 application: 6 name: eureka 7 eureka: 8 instance: 9 hostname: 127.0.0.1 10 client: 11 serviceUrl: 12 #拼接地址 13 defaultZone: http://127.0.0.1:8100/eureka/ 14 #集群版将以下改成true(是否将自己注册) 15 register-with-eureka: true 16 #是否检索服务信息 17 fetch-registry: true 18 #server: 19 #关闭自我保护机制,保证不可用的服务及时删除(单机版使用) 20 enable-self-preservation: false 21 #心跳监测时间 22 eviction-interval-time-in-ms: 2000 23
客户端配置:
1 ###服务启动端口号 2 server: 3 port: 8300 4 ###服务名称(服务注册到eureka名称) 5 spring: 6 application: 7 name: app-produce 8 ###服务注册到eureka地址 单机版 9 #eureka: 10 # client: 11 # service-url: 12 # defaultZone: http://localhost:8100/eureka 13 14 #服务注册到eureka地址 集群版 15 eureka: 16 client: 17 service-url: 18 defaultZone: http://localhost:8000/eureka,http://localhost:8100/eureka 19 #因为该应用为注册中心,不会注册自己 20 register-with-eureka: true 21 #是否需要从eureka上获取注册信息 22 fetch-registry: true 23 # 心跳检测检测与续约时间 24 registry-fetch-interval-seconds: 30 25 instance: 26 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(客户端告诉服务端自己会按照该规则) 27 lease-renewal-interval-in-seconds: 1 28 ##Eureka服务端在收到最后一次心跳之后等待的时间上限,单位为秒,超过则剔除(客户端告诉服务端按照此规则等待自己) 29 lease-expiration-duration-in-seconds: 2
至此eureka结束。
四、服务治理consul
https://springcloud.cc/spring-cloud-consul.html、下载:https://www.consul.io/downloads.html
①添加环境变量:G:\linux\consul
②在cmd中运行:consul agent -dev -ui -node=cy 其中:-dev 以开发模式启动,-node 节点名称为cy,-ui 界面启动
③ui界面: http://localhost:8500
五、服务治理zookeeper
原理:在zookeeper中采用临时节点用服务名称作为键,以ip访问路径为值 来保存。
pom文件(生产者和消费者一样)
1 <!-- 管理依赖 --> 2 <dependencyManagement> 3 <dependencies> 4 <dependency> 5 <groupId>org.springframework.cloud</groupId> 6 <artifactId>spring-cloud-dependencies</artifactId> 7 <version>Finchley.M7</version> 8 <type>pom</type> 9 <scope>import</scope> 10 </dependency> 11 </dependencies> 12 </dependencyManagement> 13 <dependencies> 14 <!-- SpringBoot整合Web组件 --> 15 <dependency> 16 <groupId>org.springframework.boot</groupId> 17 <artifactId>spring-boot-starter-web</artifactId> 18 </dependency> 19 <!-- SpringBoot整合eureka客户端 --> 20 <dependency> 21 <groupId>org.springframework.cloud</groupId> 22 <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> 23 </dependency> 24 25 </dependencies> 26 <!-- 注意: 这里必须要添加, 否者各种依赖有问题 --> 27 <repositories> 28 <repository> 29 <id>spring-milestones</id> 30 <name>Spring Milestones</name> 31 <url>https://repo.spring.io/libs-milestone</url> 32 <snapshots> 33 <enabled>false</enabled> 34 </snapshots> 35 </repository> 36 </repositories>
application.yml
1 #生产者 2 server: 3 port: 8100 4 spring: 5 application: 6 name: zk-produce 7 cloud: 8 zookeeper: 9 connect-string: 127.0.0.1:2181
控制层
1 @RestController 2 public class ProduceResource { 3 4 @RequestMapping("/zk/produce") 5 public String consulPorduce() { 6 7 return "consul produce success"; 8 } 9 10 }
启动类
1 @SpringBootApplication 2 @EnableDiscoveryClient 3 public class AppZKProduce { 4 5 public static void main(String[] args) throws Exception { 6 SpringApplication.run(AppZKProduce.class, args); 7 } 8 }
yml
1 #生产者 2 server: 3 port: 8200 4 spring: 5 application: 6 name: zk-consumer 7 cloud: 8 zookeeper: 9 connect-string: 127.0.0.1:2181
控制层
1 @RestController 2 public class ConsumerResource { 3 4 @Autowired 5 private RestTemplate restTemplate; 6 7 @Autowired 8 private DiscoveryClient discoveryClient; 9 10 @RequestMapping("/zk/consumer") 11 public String consulConsumer() { 12 13 String produceUrl = "http://zk-produce/zk/produce"; 14 15 16 String reusltProduce = restTemplate.getForObject(produceUrl, String.class); 17 18 return reusltProduce; 19 } 20 21 @RequestMapping("/discoveryClient") 22 public List<ServiceInstance> discoveryClient() { 23 List<ServiceInstance> instances = discoveryClient.getInstances("zk-consumer"); 24 for (ServiceInstance serviceInstance : instances) { 25 System.out.println("url:" + serviceInstance.getUri()); 26 } 27 return instances; 28 29 } 30 }
启动类
1 @SpringBootApplication 2 @EnableDiscoveryClient 3 public class AppZKConsumer { 4 5 public static void main(String[] args) throws Exception { 6 SpringApplication.run(AppZKConsumer.class, args); 7 } 8 9 @Bean 10 @LoadBalanced 11 RestTemplate restTemplate() { 12 return new RestTemplate(); 13 } 14 }
本地调用
远程调用
zk注册内容
六、Zk和Eureka区别(集群)
CAP:请参考本博客的分布式事务原理。
当向注册中心查询服务实例时,允许返回几分钟前注册的信息,但不能接受服务down掉不可用。即当master节点由于网络故障与其他节点失去联系,剩余的节点会重新选举leader,在选举过程中30~120秒期间会zk不可用,导致整个服务处于短暂的瘫痪。
2. Eureka保证AP
在设计时优先保证可用性,其每个节点都是平等的,节点之间down掉不会影响正常的节点工作。Eureka客户端向Eureka注册时如果出现连接失败,则会自动切换至其他节点,只要有一台Eureka健在,就能保证服务的可用性,只是可能查询不到目前最新的(不保证强一致性)。Eureka还有一种自我保护机制,如果在15分钟内超过80%的节点都没有正常的心跳,Eureka server认为客户端与注册中心网络故障会出现以下2中情况。
①. Eureka不再从注册列表中移除长时间没有收到心跳而过期的服务。
②. Eureka仍能接收新的服务注册和请求,但不会同步到其他节点(目的是保证当前节点可用)。
当网络恢复时,当前实例新的注册信息会被同步到其他节点。因此当部分节点丢失后不会像zk那样会导致整个注册服务 出现短暂瘫痪。
七、other
1 @RestController 2 public class ConsumerResource { 3 4 @Autowired 5 private RestTemplate restTemplate; 6 7 @Autowired 8 private DiscoveryClient discoveryClient; 9 10 private Integer requestNum = 1; 11 12 /** 13 * 模拟本地负载均衡 14 * @return 15 */ 16 @RequestMapping("/loadBalancing") 17 public String loadBalancing() { 18 19 List<ServiceInstance> serviceList = discoveryClient.getInstances("zk-consumer"); 20 if(serviceList == null || serviceList.size() == 0) { 21 return null; 22 } 23 int index = requestNum % serviceList.size(); 24 requestNum++; 25 26 return serviceList.get(index).getUri().toString(); 27 } 28 29 @RequestMapping("/zk/consumer") 30 public String consulConsumer() { 31 32 String produceUrl = "http://zk-produce/zk/produce"; 33 34 35 String reusltProduce = restTemplate.getForObject(produceUrl, String.class); 36 37 return reusltProduce; 38 } 39 40 @RequestMapping("/discoveryClient") 41 public List<ServiceInstance> discoveryClient() { 42 43 List<ServiceInstance> instances = discoveryClient.getInstances("zk-consumer"); 44 for (ServiceInstance serviceInstance : instances) { 45 System.out.println("url:" + serviceInstance.getUri()); 46 } 47 48 return instances; 49 } 50 }
2.RestTemplate方法
1 @RequestMapping("/getForEntity") 2 public ResponseEntity<String> getForEntity(String name) { 3 4 Map<String, String> paramMap = new HashMap<>(); 5 String produceUrl = "http://zk-produce/zk/produce?name={name}"; 6 7 paramMap.put("name", name); 8 ResponseEntity<String> resultEntity = restTemplate.getForEntity(produceUrl, String.class, paramMap); 9 10 return resultEntity; 11 }
1 @RequestMapping("/zk/consumer") 2 public String consulConsumer() { 3 4 String produceUrl = "http://zk-produce/zk/produce"; 5 6 7 String reusltProduce = restTemplate.getForObject(produceUrl, String.class); 8 9 return reusltProduce; 10 }
原文:https://www.cnblogs.com/0ziyu0/p/10661344.html