SpringCloud环境搭建

1.为什么需要使用

  • 单体应用
    一个应用,作为一个完整的服务,提供给用户。
    各个模块高度耦合,不便于后期维护;
    某个部分出问题了,整个服务不可用;
    局部拓展,比如整个应用中的用户模块,在注册有优惠活动时,难以抵住压力,可能需要进行集群扩展
  • 微服务
    很多微小的服务,组成提供给用户的完整的服务。
    是一种架构模式,SpringCloud是其一个具体的实现方式。
    各个服务低耦合,通过网络协议(Http,RPC)进行通信,传输数据。
  • SpringCloud
    基于SpringBoot实现的服务治理工具包,用于在微服务架构中管理和协调服务。
  • SpringCloud和Dubbo
    Dubbo是RPC的框架
    SpringCloud是一系列微服务解决方案
    Dubbo基于TCP
    SpringCloud于Http
    其实Http也是基于TCP,所以Dubbo通信方面的性能高于SpringCloud

2.搭建

2.1基础搭建

2.1.1. 注册中心

  • 注册中心原理
    微服务启动时会把自己的通信地址(ip+端口:服务名)注册到注册中心
    微服务会从注册中心拉取一份地址清单
    当服务发起调用时,就会从拉取的地址清单中找到目标服务地址,进行调用
    注册中心使用心跳机制实现服务的动态上下线,间隔单位时间,检查服务的健康状态,将下线的微服务从地址清单中删除掉,其他微服务同步地址清单
  • 搭建
    1. Spring官网上找到SpringCloud的EurekaClient部分
      选择PROJECTS
      第一
      选择SpringCloud第二步
      选择Learn下的参考文档第三步
      选择一个网页第四步
      找到Eurekake Client第5步

    2. Idea中新建一个Maven SpringBoot项目
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      修改pom.xml为如下:
      这里使用的SpringBoot版本如下:<version>2.0.5.RELEASE</version>

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
      	<modelVersion>4.0.0</modelVersion>
      	<parent>
      		<groupId>org.springframework.boot</groupId>
      		<artifactId>spring-boot-starter-parent</artifactId>
      		<version>2.0.5.RELEASE</version>
      	</parent>
      	<groupId>com.demo.springcloud</groupId>
      	<artifactId>eureka-server</artifactId>
      	<version>0.0.1-SNAPSHOT</version>
      	<name>eureka-server</name>
      
      	<properties>
      		<java.version>1.8</java.version>
      	</properties>
      
      	<dependencies>
      		<dependency>
      			<groupId>org.springframework.boot</groupId>
      			<artifactId>spring-boot-starter-web</artifactId>
      		</dependency>
      
      		<dependency>
      			<groupId>org.projectlombok</groupId>
      			<artifactId>lombok</artifactId>
      			<optional>true</optional>
      		</dependency>
      		<dependency>
      			<groupId>org.springframework.boot</groupId>
      			<artifactId>spring-boot-starter-test</artifactId>
      			<scope>test</scope>
      			<exclusions>
      				<exclusion>
      					<groupId>org.junit.vintage</groupId>
      					<artifactId>junit-vintage-engine</artifactId>
      				</exclusion>
      			</exclusions>
      		</dependency>
      	</dependencies>
      
      	<build>
      		<plugins>
      			<plugin>
      				<groupId>org.springframework.boot</groupId>
      				<artifactId>spring-boot-maven-plugin</artifactId>
      			</plugin>
      		</plugins>
      	</build>
      
      </project>
      
    3. pom.xml中加入spring-cloud的依赖和eureka的依赖
      <spring-cloud.version>Finchley.SR1</spring-cloud.version>

      <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
         </dependency>
      
      <dependencyManagement>
      	<dependencies>
      		<dependency>
      			<groupId>org.springframework.cloud</groupId>
      			<artifactId>spring-cloud-dependencies</artifactId>
      			<version>${spring-cloud.version}</version>
      			<type>pom</type>
      			<scope>import</scope>
      		</dependency>
      	</dependencies>
      </dependencyManagement>
      
    4. resources增加 application.yml

      server:
        port: 1000
      
      eureka:
        instance:
          hostname: localhost #主机名,此处为注册中心
        client:
          registerWithEureka: false #不允许注册中心服务注册到注册中心
          fetchRegistry: false      #不允许注册中心服务,拉取服务地址列表
          serviceUrl:
            defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #注册中心地址
      
      
    5. 主配置类上开启Eureka服务
      @SpringBootApplication
      @EnableEurekaServer

    6. 启动后浏览器访问localhost:1000

    7. 在此基础上搭建多模块的maven,结构如下:
      springcloud-parent
      – springcloud-eureka-server-1000
      – springcloud-user-server-2000
      –springcloud-order-server-3000
      springcloud-parent为空的Maven父项目,包含下面3个的内容
      此处的1000-3000为服务的端口,eureka-server为Eureka服务端,
      user-server和order-server均为其Eureka客户端。

2.1.2. 提供者服务

  1. 引入依赖

    <!--EurekaClient依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!--webmvc支持,EurekaClient启动需要该依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
  2. application.yml

    server:
      port: 2000
    
    eureka:
      instance:
            instance-id: user-server-2000  #实例id
            prefer-ip-address: true   #使用ip注册到注册中心
      client:
        serviceUrl:
          defaultZone: http://localhost:1000/eureka/
    
    #服务名称
    spring:
      application:
        name: user-server-2000
    
  3. 刷新local:1000,看是否有user-server-2000 ,有则成功
    在这里插入图片描述

2.1.3. 消费者服务

步骤同上,增加order-server-3000

2.1.4. 修改IP注册

eureka:
	  instance:
	        instance-id: user-server-2000  #实例id
	        prefer-ip-address: true   #使用ip注册到注册中心
#服务名称
	spring:
	  application:
	    name: user-server-2000

2.2EurekaServer高可用集群

2.2.1为何使用

如果只有一个EurekaSever,如果EurekaSever挂了那么整个微服务都不可用

2.2.2搭建

  1. 创建两个本地域名 C:\Windows\System32\drivers\etc\hosts

    127.0.0.1 peer1
    127.0.0.1 peer2

  2. 修改注册中心eureka-server-1000

       server:
         port: 1000
       eureka:
         instance:
           hostname: peer1
         client:
           registerWithEureka: false #禁用注册中心向自己注册
           fetchRegistry: false  #不让注册中心获取服务的注册列表
           serviceUrl:
             defaultZone: http://peer2:1001/eureka/
             #注册中心的注册地址 ,其他微服务需要向这个地址注册
    
  3. 搭建第二个注册中心eureka-server-1001 - 复制

     server:
    	      port: 1001
    	    eureka:
    	      instance:
    	        hostname: peer2
    	      client:
    	        registerWithEureka: false #禁用注册中心向自己注册
    	        fetchRegistry: false  #不让注册中心获取服务的注册列表
    	        serviceUrl:
    	          defaultZone: http://peer1:1000/eureka/
    	          #注册中心的注册地址 ,其他微服务需要向这个地址注册
    
  4. 修改Eureka客户端

    eureka:
      client:
        serviceUrl:
          defaultZone: http://peer1:1000/eureka/,http://peer2:1001/eureka/ #注册中心地址
          ...
    

2.3Ribbon

2.3.1使用restTemplate发送服务间请求

  • 主配置类配置RestTemplate
@Bean
public RestTemplate restTemplate(){

    return new RestTemplate();

}
  • 控制层调用
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/getById/{id}")
    public User getById(@PathVariable("id")Long id){

         	 通过ip地址+端口发送请求
          	String url = "http://localhost:2000/user/getById/"+id;

            User user = restTemplate.getForObject(url, User.class);
            return user;

    }

2.3.2当服务有多个时,使用Ribbon进行负载均衡

  • 引入Ribbon依赖
<!--ribbon依赖,依赖处理服务调用时,多个服务集群时,进行负载均衡-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
  • 主配置类的RestTemplate加上@LoadBalanced注解
/**
     * Spring管理RestTemplate,注入即可发送请求
     * @LoadBalanced : 赋予restTemplate负载均衡的能力
     * @return
     */
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate(){

        return new RestTemplate();

    }
  • 控制层使用服务名称进行调用
   @GetMapping("/getById/{id}")
    public User getById(@PathVariable("id")Long id){

//          通过ip地址+端口发送请求
//          String url = "http://localhost:2000/user/getById/"+id;
//          通过服务名调用:user-server
            String url = "http://user-server/user/getById/"+id;

            User user = restTemplate.getForObject(url, User.class);
            return user;

    }

2.3.3负载均衡策略

  • 默认轮询
  • 自定义配置,主配置类配置IRule即可
/**
* 负载均衡规则:随机,默认轮询
* @return
*/
@Bean
public IRule myRule(){

   return new RandomRule();

}

2.4Feign

2.4.1使用场景

基于Ribbon,使得服务间调用像是本地调用一样

2.4.2搭建

  • 新建模块springcloud-pay-server-4000
  • pom.xml引入feign支持
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  • 新建接口UserFeignClient
/**
 * 表明这是Feign的接口,指定服务名称
 */
@FeignClient("user-server")
public interface UserFeignClient {

    /**
     * 和服务调用处一致
     * @param id
     * @return
     */
    @GetMapping("/user/getById/{id}")
    public User getById(@PathVariable("id")Long id);

}
  • 主配置类开启Feign支持
    @EnableFeignClients
  • 控制层调用
@Autowired
 private UserFeignClient feignClient;

  @GetMapping("/getById/{id}")
  public User getById(@PathVariable("id")Long id){

//          通过feignClient接口进行调用
          User user = feignClient.getById(id);
          return user;

  }

2.5Hystrix

2.5.1为什么使用

  • 雪崩
    一个微服务的故障导致整个微服务调用链全部瘫痪
  • 什么是Hystrix
    解决服务器故障(雪崩)的一个组件 ,它可以实现:隔离 ,熔断 ,降级,缓存
  • 隔离 :包括线程池隔离和信号量隔离,限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。
  • 熔断 :当请求次数达到规定的阀值都出现服务故障(超时),Hystrix就把服务标记为短路状态.
    正常情况下,断路器处于关闭状态(Closed),如果调用持续出错或者超时,电路被打开进入熔断状态(Open),后续一段时间内的所有调用都会被拒绝(Fail Fast),一段时间以后,保护器会尝试进入半熔断状态(Half-Open),允许少量请求进来尝试,
    如果调用仍然失败,则回到熔断状态
    如果调用成功,则回到电路闭合状态;
  • 降级 :高并发情况下 ,为了保证一些主要的服务有足够的资源不出问题 ,会认为的关掉一些无关紧要的服务,然后返回一些托底的数据,给用户一个友好的提示。
  • 缓存 :Hystrix内部会把请求做缓存

2.5.2Ribbon搭建Hystrix

  1. pom.xml引入Hystrix
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    
  2. 主配置类加上@EnableCircuitBreaker
  3. 调用方法处加注解,并设置托底方法,完成托底方法
    /**
    * @HystrixCommand(fallbackMethod = "getUserIdFallback") :
    *                  该请求需要做出问题时熔断处理,指定托底方法返回数据给用户
    * @param id
    * @return
    */
    @GetMapping("/getById/{id}")
    @HystrixCommand(fallbackMethod = "getUserIdFallback")
    public User getById(@PathVariable("id")Long id){
    
    //          通过ip地址+端口发送请求
    //          String url = "http://localhost:2000/user/getById/"+id;
    //          通过服务名调用:user-server
           String url = "http://user-server/user/getById/"+id;
    
           User user = restTemplate.getForObject(url, User.class);
           return user;
    
    }
    
    public User getUserIdFallback(@PathVariable("id")Long id){
       return new User(id,"不知何许人也","用户服务暂不可用");
    }
    
  4. 断开调用的微服务,进行访问

2.5.3Feign搭建Hystrix

  1. application.yml开启feign
    #feign的hsytrix开启
    feign :
      hystrix :
        enabled : true
    
    
  2. Feign的客户端接口注解加上托底类
    /**
     * 表明这是Feign的接口,指定服务名称
     */
    @FeignClient(value = "user-server",fallback = UserFeignClientFallBack.class)
    public interface UserFeignClient {
    
        /**
         * 和服务调用处一致
         * @param id
         * @return
         */
        @GetMapping("/user/getById/{id}")
        public User getById(@PathVariable("id")Long id);
    
    }
    
    1. . 托底类实现客户端接口,重写托底方法
    @Component
    public class UserFeignClientFallBack implements UserFeignClient {
    
        @Override
        public User getById(Long id) {
            return new User(-1L,"不知何许人也","用户服务暂不可用");
        }
    }
    

2.6Zuul

2.6.1基本概念

Zuul是一个SpringCloud的网关组件 , 它是微服务的入口,网络关卡 ,通过Zuul我们可以实现请求的分发(负载均衡),鉴权,限流等等操作。

2.6.2搭建基本

  1. 引入依赖
<!--zuul依赖路由分发,过滤-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
 </dependency>
  1. 配置文件
zuul:
  ignoredServices: "*"        #拦截请求,使不能通过服务名访问
  prefix: "/service"
  routes:
    pay-server: "/pays/**"  #pay-server服务可以通过/pays/**访问 http://localhost:5000/service/pays/pay/getById/1
  1. 主配置类@EnableZuulProxy
  2. 访问http://localhost:5000/service/pays/pay/getById/1

2.6.3Zuul原理

- 正常流程:
  - 请求到达首先会经过pre类型过滤器,而后到达routing类型,进行路由,请求就到达真正的服务提供者,执行请求,返回结果后,会到达post过滤器。而后返回响应。
- 异常流程:
  - 整个过程中,pre或者routing过滤器出现异常,都会直接进入error过滤器,再error处理完毕后,会将请求交给POST过滤器,最后返回给用户。
  - 如果是error过滤器自己出现异常,最终也会进入POST过滤器,而后返回。
  - 如果是POST过滤器出现异常,会跳转到error过滤器,但是与pre和routing不同的时,请求不会再到达POST过滤器了。

2.6.4自定义Filter实现登录检查

自定义过滤器,继承ZuulFilter抽象类,实现其中的方法

/**
 * 自定义Zuul过滤器,实现登录检查
 */
@Component
public class MyZuulFilter extends ZuulFilter{

    public static final String PRE_TYPE = "pre";

    public static final int PRE_FILTER_ORDER = 5;

    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return PRE_FILTER_ORDER;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {

        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        HttpServletResponse response = ctx.getResponse();
        response.setContentType("text/json;charset=utf-8;");

        if(!StringUtils.hasLength(request.getHeader("token"))){
            try {
                response.getWriter().write("请登录先...");
                ctx.setSendZuulResponse(false);
                ctx.setResponseStatusCode(HttpServletResponse.SC_UNAUTHORIZED);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值