springcloud子模块之间的通信
1.搭建公共模块common
2.在common层搭建domain层user
package cn.itsource.domain; public class User { private Long id; private String username; private String password; public User() { } public User(Long id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }
3.服务层编写接口
1.导入依赖:服务层依赖common层
<dependency> <groupId>cn.itsource.springcloud</groupId> <artifactId>springcloud-common-user</artifactId> <version>...</version> </dependency>
2.创建controller
/** * 用户提供者服务 */ @RestController public class UserProviderController { /** * 提供者方法,orderServer消费者来调用 * @param id * @return */ // @RequestMapping(value = "/user/{id}",method = RequestMethod.GET) @GetMapping("/user/{id}") public User getUserById(@PathVariable("id")Long id){ System.out.println("UserProviderController.getUserById被调用了......"); return new User(id,"zs:"+id , "123"); } }
4.
1.依赖common模块
<dependency> <groupId>cn.itsource.springcloud</groupId> <artifactId>springcloud-common-user</artifactId> <version>...</version> </dependency>
2.
/**
* SpringMvc提供的一个基于Rest风格的http调用工具
* @return
*/
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
3.
/** * 订单消费者服务 */ @RestController public class OrderConsumerController { @Autowired private RestTemplate restTemplate ; /** * 该方法是浏览器来调用 * @param id * @return */ @GetMapping("/order/user/{id}") public User getUserById(@PathVariable("id") Long id){ System.out.println("OrderConsumerController.getUserById被调用了......"); String url = "http://localhost:2000/user/"+id; User user = restTemplate.getForObject(url, User.class); return user; } }
一.单节点故障
1.什么是EurekaServer单节点故障
如果只有一个EurekaSever,如果EurekaSever挂了那么整个微服务都不可用
2.解决方案
EurekaServer高可用集群
二.EurekaServer集群
1.搭建EurekaServer集群
创建两个本地域名 C:\Windows\System32\drivers\etc\hosts
127.0.0.1 peer1
127.0.0.1 peer2
修改注册中心eureka-server-1000
server:
port: 1000
eureka:
instance:
hostname: peer1
client:
registerWithEureka: false #禁用注册中心向自己注册
fetchRegistry: false #不让注册中心获取服务的注册列表
serviceUrl:
defaultZone: http://peer2:1001/eureka/
#注册中心的注册地址 ,其他微服务需要向这个地址注册
搭建第二个注册中心eureka-server-1001 - 复制
server:
port: 1001
eureka:
instance:
hostname: peer2
client:
registerWithEureka: false #禁用注册中心向自己注册
fetchRegistry: false #不让注册中心获取服务的注册列表
serviceUrl:
defaultZone: http://peer1:1000/eureka/
#注册中心的注册地址 ,其他微服务需要向这个地址注册
3.修改EurekaClient (UserServer ,OrderServer)
eureka:
client:
serviceUrl:
defaultZone: http://peer1:1000/eureka/,http://peer2:1001/eureka/ #注册中心地址
...
五.Ribbon
ribbon是负载均衡器,是基于RestTemplate ,它赋予了RestTemplate 负载均衡的能力
一.集群和负载均衡原理
二.提供者user-server集群
1.创建user-server服务2001 - 赋值
2.修改配置
eureka: client: serviceUrl: defaultZone: http://peer1:1000/eureka/,http://peer2:1001/eureka/ #注册中心地址 instance: prefer-ip-address: true #使用ip地址注册 instance-id: user-server1 #指定服务的id server: port: 2000 spring: application: name: user-server
注意:instance-id需要修改 , 而 spring.application.name 不需要修改 , 端口需要修改
3.修改主类名,pom中的名字,parent中的模块增加
三.order-server集成Ribbon
1.导入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
2.修改RestTemplate的Bean的定义
/** * SpringMvc提供的一个基于Rest风格的http调用工具 * @LoadBalanced :ribbon的负载均衡标签,赋予RestTemplate有负债均衡的能力 */ @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); }
@LoadBalanced :ribbon的负载均衡标签,赋予RestTemplate有负债均衡的能力
3.修改Controller调用方式
@GetMapping("/order/user/{id}") public User getUserById(@PathVariable("id") Long id){ System.out.println("OrderConsumerController.getUserById被调用了......"); //String url = "http://localhost:2000/user/"+id; String url = "http://user-server/user/"+id; User user = restTemplate.getForObject(url, User.class); return user; }
修改效果: String url = "http://user-server/user/"+id;
ribbon默认使用的轮询策略
六.Feign
一.什么是Feign
基于Ribbon封装的客户端负载均衡器
二.Feign的集成 - springcloud-dept-server-4000
1.导入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
2.配置类开启Feign
@SpringBootApplication @EnableFeignClients("cn.itsource.client") public class DeptServerApplication4000 ...
3.编写Feign的接口
/** * @FeignClient(value="user-server") : 针对于用户服务调用的 Fiegn的客户端接口 * value属性就是该接口要调用的目标服务的名字 * Feign是如何实现服务调用的: * 1.通过@FeignClient(value="user-server")标签上的服务名字能够找到要调用的目标服务 * 2.通过接口中的方法的 @GetMapping的url路径找到目标服务的controller的方法 , * 所以要保证Feign客户端接口的方法和目标服务的对应的方法要完全一致。 * */ @FeignClient(value="user-server") public interface UserFeignClient { @GetMapping("/user/{id}") User getUserById(@PathVariable("id")Long id); }
Feign客户端接口的方法和目标服务的对应的方法要完全一致
4.调用
@RestController public class DeptConsumerController { @Autowired private UserFeignClient userFeignClient ; /** * 该方法是浏览器来调用 * @param id * @return */ @GetMapping("/dept/user/{id}") public User getUserById(@PathVariable("id") Long id){ User user = userFeignClient.getUserById(id); //使用Feign的接口调用 return user; } }
七.Hystrix
一.雪崩效应
一个微服务的故障导致整个微服务调用链全部瘫痪
二.Hystrix介绍
解决服务器故障(雪崩)的一个组件 ,它可以实现:隔离 ,熔断 ,降级,缓存
-
隔离 :包括线程池隔离和信号量隔离,限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。
-
熔断 :当请求次数达到规定的阀值都出现服务故障(超时),Hystrix就把服务标记为短路状态.
正常情况下,断路器处于关闭状态(Closed),如果调用持续出错或者超时,电路被打开进入熔断状态(Open),后续一段时间内的所有调用都会被拒绝(Fail Fast),一段时间以后,保护器会尝试进入半熔断状态(Half-Open),允许少量请求进来尝试,
如果调用仍然失败,则回到熔断状态
如果调用成功,则回到电路闭合状态; -
降级 :高并发情况下 ,为了保证一些主要的服务有足够的资源不出问题 ,会认为的关掉一些无关紧要的服务,然后返回一些托底的数据,给用户一个友好的提示。
-
缓存 :Hystrix内部会把请求做缓存
三.Ribbon集成Hystrix - springcloud-order-server-3000
1.导入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
2.controller方法贴注解
/** * 该方法是浏览器来调用 * @HystrixCommand :开启方法的短路功能 , 如果方法出现异常,会调用 fallbackMethod * 指向的方法 ,然后返回托底数据 */ @HystrixCommand(fallbackMethod = "getUserByIdFallback") @GetMapping("/order/user/{id}") public JsonResult getUserById(@PathVariable("id") Long id){ System.out.println("OrderConsumerController.getUserById被调用了......"); String url = "http://user-server/user/"+id; User user = restTemplate.getForObject(url, User.class); return JsonResult.me().setData(user); }
3.托底方法
public JsonResult getUserByIdFallback(@PathVariable("id") Long id){ return JsonResult.me().setSuccess(false) .setMessage("服务展示不可用,请骚后重试[服务降级]"); }
注意:托底方法的参数和返回结果要和原方法一致
四.Feign集成Hystrix - springcloud-dept-server-4000
1.开启Hystrix
feign: hystrix: enabled: true #开启熔断支持 client: config: remote-service: #服务名,填写default为所有服务 connectTimeout: 30000 readTimeout: 30000 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 30000
2.修改Fiegn客户端接口
@FeignClient(value="user-server" ,fallback = UserFeignClientFallback.class) public interface UserFeignClient { @GetMapping("/user/{id}") User getUserById(@PathVariable("id")Long id); }
fallback = UserFeignClientFallback.class : 该类是当前接口的实现类 ,也是托底数据所在的处理类
3.托底实现
@Component public class UserFeignClientFallback implements UserFeignClient { @Override public User getUserById(Long id) { System.out.println("托底数据执行...."); return new User(-1L,"托底数据",""); } }