本文共 11239 字,大约阅读时间需要 37 分钟。
本文内容都是实际操作后得到的,是基本没有错误的,命名格式本次比较随意
springcloud概念:Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
“微服务架构”在这几年非常的火热,以至于关于微服务架构相关的开源产品被反复的提及(比如:netflix、dubbo),Spring Cloud也因Spring社区的强大知名度和影响力也被广大架构师与开发者备受关注。
总的来说就是把一个系统分成多个比如淘宝的用户管理和商品页面各自用一些服务器部署,一个项目的各个模块可以遍布在成千上万台服务器上
eureka概念:Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。
Eureka包含两个组件:Eureka Server和Eureka Client。 Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。 Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器。 在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。 Eureka Server之间通过复制的方式完成数据的同步,Eureka还提供了客户端缓存机制,即使所有的Eureka Server都挂掉,客户端依然可以利用缓存中的信息消费其他服务的API。综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。
总的来说就是把各个服务找到结合起来
ribbon概念:Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。
通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。
Spring Cloud Ribbon只是一个工具类框架,它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在于每一个Spring
Cloud构建的微服务和基础设施中。因为微服务间的调用,API网关的请求转发等内容,实际上都是通过Ribbon来实现的,包括后续我们将要介绍的Feign,它也是基于Ribbon实现的工具。
所以,对Spring Cloud Ribbon的理解和使用,对于我们使用Spring Cloud来构建微服务非常重要。
总结比如淘宝的用户模块可能有同样的数千台服务器,可能你每一次访问你的主页,给你提供数据的服务器可能是不同,有的服务器压力过大就由其他的服务器给你提供服务
feign概念:Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。
在Spring Cloud中,使用Feign非常简单——创建一个接口,并在接口上添加一些注解,代码就完成了。Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。 Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。 Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这两者的强大功能外,还提供了一种声明式的Web服务客户端定义的方式。 Spring Cloud Feign帮助我们定义和实现依赖服务接口的定义。在Spring Cloud feign的实现下,只需要创建一个接口并用注解方式配置它,即可完成服务提供方的接口绑定,简化了在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发量。 Spring Cloud Feign具备可插拔的注解支持,支持Feign注解、JAX-RS注解和Spring MVC的注解。
总结就是不用将服务的ip端口等手动去写到文件中,那样工作量很大
hystrix概念:在分布式系统架构中多个系统之间通常是通过远程RPC调用进行通信,也就是 A 系统调用 B 系统服务,B 系统调用 C 系统的服务。当尾部应用 C 发生故障而系统 B 没有服务降级时候可能会导致 B,甚至系统 A 瘫痪,这种现象被称为雪崩现象。所以在系统设计时候要使用一定的降级策略,来保证当服务提供方服务不可用时候,服务调用方可以切换到降级后的策略进行执行。
设计原则:资源隔离(线程池隔离和信号量隔离)机制:限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其它服务调用。 限流机制:限流机制主要是提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源。 熔断机制:当失败率达到阀值自动触发降级(如因网络故障、超时造成的失败率增高),熔断器触发的快速失败会进行快速恢复。 降级机制:超时降级、资源不足时(线程或信号量)降级 、运行异常降级等,降级后可以配合降级接口返回托底数据。 缓存支持:提供了请求缓存、请求合并实现 通过近实时的统计/监控/报警功能,来提高故障发现的速度 通过近实时的属性和配置热修改功能,来提高故障处理和恢复的速度
总结就是避免服务器全部崩盘死掉,因为各个模块彼此间有依赖,一个的崩溃可能会导致其他的崩溃,所以有了这个容错机制,保证一个的崩溃不会影响到其他的服务器
项目构建
1创建microserver空的maven包当作文件夹
2在项目中添加sping modul(eureka_service)
修改application.yml文件 在启动类上添加注解@EnableEurekaServer
server: port: 8761eureka: client:#要不要去注册中心获取其他服务的地址 fetch-registry: false#自己就是注册中心,不用注册自己 register-with-eureka: false
运行后打开浏览器可以访问到
3添加microserver_procider_user modul 使用sping初始化选择如下工具
修改application.yml配置文件 然后创建实体类 创建服务层 创建控制类 启动类添加注解@EnableDiscoveryClient 运行(运行前请确保数据库有相应的数据)
server: port: 8000spring: application: #name不能使用_不然后面的http请求要报错,http请求中不能有_,也可能是版本问题 name: microservice-provider-user jpa: show-sql: true datasource: url: jdbc:mysql:///test?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT driver-class-name: com.mysql.jdbc.Driver username: root password:eureka: instance: prefer-ip-address: true
package com.example.proj.entity;import lombok.Data;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Table;import javax.persistence.*;@Data@Entity@Table(name = "user")public class user { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String username; private String password;}
package com.example.proj.dao;import com.example.proj.entity.user;import org.springframework.data.jpa.repository.JpaRepository;public interface userDao extends JpaRepository{ }
package com.example.proj.controller;import com.example.proj.dao.userDao;import com.example.proj.entity.user;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.util.Optional;@RestController@RequestMapping("/user")public class UserController { @Autowired private userDao dao; @RequestMapping("/findById/{id}") public user findById(@PathVariable("id") Integer id) { Optionaloptional = dao.findById(id); if (optional.isPresent()) return optional.get(); else return null; }}
中间遇到了一个错误搞了一个多小时心态都给我搞崩了,没有任何报错就是访问不了,来回找问题,后面百度,尝试一番才发现是启动类的位置不对,启动类我将他放到了最外层目录下面一下就没问题了
异常This application has no explicit mapping for /error, so you are seeing this as a fallback.
4创建microservice_consumer_user(同样是在主结构下创建一个模块选择需要的)
修改application.yml文件 创建实体类 创建userController类实现访问逻辑 同样启动类上面要加注解@EnableDiscoveryClient
server: port: 8010spring: application: name: microservice-consumer-usereureka: instance: prefer-ip-address: true
package com.example.proj.microservice_consumer_user.entity;import lombok.Data;@Datapublic class user { private Integer id; private String username; private String password;}
package com.example.proj.microservice_consumer_user.controller;import com.example.proj.microservice_consumer_user.entity.user;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.client.RestTemplate;@RestController@RequestMapping("/user")public class userController { @RequestMapping("/{id}") public user getOne(@PathVariable("id") Integer id) { RestTemplate restTemplate = new RestTemplate(); return restTemplate.getForObject("http://localhost:8000/user/findById/" + id, user.class); }}
5负载均衡实现先创建一个提供者按前面的提供者的创建一样的
生产者8001,服务名为microservice_provider_user_copy修改application.yml文件
同样启动类需要添加依赖@EnableDiscoveryClient
server: port: 8001spring: application: #端口不一样,同时这个name必须一样 name: microservice-provide-user jpa: show-sql: true datasource: url: jdbc:mysql:///test?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8 driver-class-name: com.mysql.cj.jdbc.Driver username: root password: rooteureka: instance: prefer-ip-address: true
实体类中添加一句
//上面的添加在原来的提供者中,下面的添加到新的提供者中以供区分@Transientprivate String source = "EurekaProvider";@Transientprivate String source = "EurekaProviderRibbon";
测试时修改url中的端口看新的是否创建成功
准备做好了就要开始实现负载均衡了
需要现在消费者中添加pom依赖包
org.springframework.cloud spring-cloud-starter-netflix-ribbon
消费者启动类中添加如下代码
@Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); }
消费者controller中代码改为
package com.example.proj.microservice_consumer_user.controller;import com.example.proj.microservice_consumer_user.entity.user;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.client.RestTemplate;@RestController@RequestMapping("/user")public class userController { @Autowired private RestTemplate restTemplate; @RequestMapping("/{id}") public user getOne(@PathVariable("id") Integer id) { return restTemplate.getForObject("http://microservice-provider-user/user/findById/" + id, user.class); }}
消费者实体中添加代码去匹配生产者
private String source;
一切准备就全部启动,结果如下,可以看出已经实现了
6使用feign来简化开发
先创建consumerfeign 勾选如下依赖
修改application.xml文件
server: port: 8020spring: application: name: microservice-consumer-user-feigneureka: instance: prefer-ip-address: true
创建实体类
package com.example.proj.microservice_consumer_user_feign.entity;import lombok.Data;@Datapublic class User { private Integer id; private String username; private String password; private String source;}
创建feign客户端
package com.example.proj.microservice_consumer_user_feign.feign;import com.example.proj.microservice_consumer_user_feign.entity.User;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;@FeignClient("microservice-provider-user")public interface UserFeignClient { @RequestMapping("/user/findById/{id}") public User findById(@PathVariable("id") Integer id);}
创建controller类
package com.example.proj.microservice_consumer_user_feign.controller;import com.example.proj.microservice_consumer_user_feign.entity.User;import com.example.proj.microservice_consumer_user_feign.feign.UserFeignClient;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/user")public class UserController { @Autowired private UserFeignClient userFeignClient; @RequestMapping("/{id}") public User getOne(@PathVariable("id") Integer id) { return userFeignClient.findById(id); }}
启动类添加注解@EnableFeignClients,启动测试
7服务C宕机,导致服务B宕机,从而导致服务A宕机,最终整个商城无法使用,所以hystrix就有用了
首先创建模块选择相关依赖
修改application.xml文件
server: port: 8030spring: application: name: microservice-user-feign-hytrixeureka: instance: prefer-ip-address: true client: service-url: defaultZone: http://localhost:8761/eureka/
entity,feign两个模块复制前面的feignconsumer
修改controller类只是在前面feign中的controller中加了一个方法和一个注解
package com.example.proj.microservice_consumer_user_feign_hystrix.controller;import com.example.proj.microservice_consumer_user_feign_hystrix.entity.User;import com.example.proj.microservice_consumer_user_feign_hystrix.feign.UserFeignClient;import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/user")public class UserController { @Autowired private UserFeignClient userFeignClient; @HystrixCommand(defaultFallback = "cannoFind") @RequestMapping("/{id}") public User getOne(@PathVariable("id")Integer id){ return userFeignClient.findById(id); } private User cannoFind(){ User user=new User(); user.setId(-1); return user; }}
启动类上添加注解
@EnableFeignClients @EnableCircuitBreaker @EnableDiscoveryClient
目前就这么搭建了一个项目后面会在这个给基础上加上网关zuul微服务网关然后运行,发现访问8030正常,然后关掉一个生产者发现另一个生产者正常一个返回这个
码字不易
转载地址:http://pqrwi.baihongyu.com/