springcloud

一、单体应用和微服务

1.1 Monolith单体应用(单体应用)架构

1.1.1 什么是单体应用架构

项目所有的资源都在一个应用中,打包成一个war包,使用一个tomcat去运行,运行在一个进程中

1.1.2 单体应用特点

  • 优点
    • 部署项目快
    • 成本投入小
    • 容易运行/测试
  • 缺点
    • 一个模块挂了,整个项目都受影响
    • 单个tomcat更能处理的并发有限,可以做集群,但是不方便局部(某一个模块)扩展
    • 维护/开发/升级比较麻烦
    • 代码臃肿,编译,打包都比较慢
    • 技术选型单一
    • 数据库选型单一

1.2 MicroService(微服务)架构(一种架构思想)

1.2.1 什么是微服务架构

微服务就是把一个大的系统,拆分成多个小的服务,每个微服务只专注一个业务 ,每个服务有各自的进程, 微服务之间使用网络通信协议进行数据交互(通常是基于HTTP的RESTful API)。

1.2.2 微服务特点

  • 优点
    • 数据库选型多样化
    • 技术选型多样化
    • 每个微服务专注一个业务
    • 每个维护有自己的进程
    • 微服务之间通过网络协议进行通信
    • 方便做局部拓展
    • 开发/维护/升级更方便
  • 缺点
    • 成本高
    • 技术要求比较高
    • 部署麻烦

二、SpringCloud

2.1 概念

  • Spring cloud是一个基于Spring Boot实现的服务治理工具包,用于微服务架构中管理和协调服务的。
  • Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Springcloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。

2.2 SpringCloud五大组成部分

  • 服务发现——Netflix Eureka
  • 客服端负载均衡——Netflix Ribbon\Feign
  • 断路器——Netflix Hystrix
  • 服务网关——Netflix Zuul
  • 分布式配置——Spring Cloud Config

2.3 SpringCloud和Dubbo的区别

  • dubbo是rpc框架
  • SpringCloud是一系列微服务解决方案
  • dubbo给予tcp
  • SpringCloud基于http
  • dubbo在通信方面的性能高于SpringCloud
  • Dubbo是阿里巴巴服务化治理的核心框架
  • SpringCloud是Spring的产品

三、SpringCloud入门微服务场景模拟

3.1 搭建注册中心

  • 创建多模块工程
springcloud-parent
  springcloud-eureka-server-1000 //注册中心EurekaServer 
  springcloud-order-server-3000  //订单服务EurekaClient ,消费者
  springcloud-user-server-2000   //用户服务EurekaClient ,提供者
  • springcloud-parent管理依赖
    boot版本和spring-cloud.version必须对应(如下图)
    在这里插入图片描述
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.5.RELEASE</version>
</parent>

<groupId>cn.xxx.springcloud</groupId>
<artifactId>springcloud-parent</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties>
<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>
  • springcloud-eureka-server-1000导入依赖
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
  • 主配置类
/**
 * @EnableEurekaServer :开启注册中心
 */
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication1000 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication1000.class);
    }
}
  • 配置文件application.yml
server:
  port: 1000
eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false #禁用注册中心向自己注册
    fetchRegistry: false  #不让注册中心获取服务的注册列表
    serviceUrl:
      defaultZone: http://localhost:1000/eureka/
      #注册中心的注册地址 ,其他微服务需要向这个地址注册

3.2 搭建提供者服务

  • 创建模块springcloud-user-server-2000
  • 导入依赖
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
  • 创建配置类
@SpringBootApplication
@EnableDiscoveryClient
public class UserServerApplication2000 {
    public static void main(String[] args) {
        SpringApplication.run(UserServerApplication2000.class);
    }
}
  • 配置文件application.yml
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1000/eureka/ #注册中心地址
server:
  port: 2000
spring:
  application:
    name: user-server

3.3 搭建消费者服务

  • 创建模块springcloud-order-server-3000
  • 导入依赖
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

  • 创建配置类
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServerApplication3000 {
    public static void main(String[] args) {
        SpringApplication.run(OrderServerApplication3000 .class);
    }
}

  • 配置文件application.yml
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1000/eureka/ #注册中心地址
server:
  port: 3000
spring:
  application:
    name: order-server

3.4 EurekaServer集群

  • 创建俩个本地域名(C:\Windows\System32\drivers\etc\hosts)
127.0.0.1 peer1
127.0.0.1 peer2

  • 修改Eureka-Server-1000的yml文件
spring:
  profiles:
    active: peer1
---
server:
  port: 1000
eureka:
  instance:
    hostname: peer1 #主机
  client:
    registerWithEureka: false #禁止注册中心向自己注册
    fetchRegistry: false #禁止注册中心拉取注册地址清单
    serviceUrl: #微服务向注册中心注册的地址
      defaultZone: http://peer2:1001/eureka/
spring:
  profiles: peer1
---
server:
  port: 1001
eureka:
  instance:
    hostname: peer2 #主机
  client:
    registerWithEureka: false #禁止注册中心向自己注册
    fetchRegistry: false #禁止注册中心拉取注册地址清单
    serviceUrl: #微服务向注册中心注册的地址
      defaultZone: http://peer1:1000/eureka/
spring:
  profiles: peer2

  • 修改 springcloud-order-server-3000, springcloud-user-server-2000 的yml文件中的defaultZone
eureka:
  client:
    serviceUrl:
      defaultZone: http://peer1:1000/eureka/,http://peer2:1001/eureka/

四、Ribbon

4.1 概念

  • Ribbon是Netflix发布的云中间层服务开源项目,主要功能是提供客户端负载均衡算法。Ribbon客户端组件提供一系列完善的配置项,如,连接超时,重试等。
  • Ribbon是一个客户端负载均衡器,我们可以在配置文件中列出load Balancer后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算法。
  • Ribbon是一个客户端负载均衡器,它可以按照一定规则来完成多态服务器负载均衡调用,这些规则还支持自定义

4.2 负载均衡算法

  • 轮询算法(默认)
  • 随机
  • 权重
  • 响应权重
  • IP-hash

4.3 order-server集成

  • 导入依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

  • 修改RestTemplate的Bean的定义
/**
 * SpringMvc提供的一个基于Rest风格的http调用工具
 * @LoadBalanced :ribbon的负载均衡标签,赋予RestTemplate有负债均衡的能力
 */
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
    return new RestTemplate();
}

  • 修改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;
}

五、Feign

5.1 概念

  • 基于Ribbon封装的客户端负载均衡器
  • Feign是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单。
  • Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息。
  • 而Feign则会完全代理HTTP请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。
  • Feign整合了Ribbon和Hystrix(关于Hystrix我们后面再讲),可以让我们不再需要显式地使用这两个组件。

5.2 特点

  • 可插拔的注解支持,包括Feign注解和JAX-RS注解;
  • 支持可插拔的HTTP编码器和解码器;
  • 支持Hystrix和它的Fallback;
  • 支持Ribbon的负载均衡;
  • 支持HTTP请求和响应的压缩。
  • Feign是用@FeignClient来映射服务的。

5.3 集成

  • 导入依赖
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

  • 配置类开启Feign
@SpringBootApplication
@EnableFeignClients("cn.xxx.client")
public class DeptServerApplication4000 
...

  • 编写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);
}

  • 调用
@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断路器

6.1 作用

Hystrix是保证微服务群健壮框架,做了隔离,熔断,降级等操作.最终达到不会由于某一个服务出问题而导致雪崩现象,让整体群死掉.

6.2 主要功能

  • 隔离 :包括线程池隔离和信号量隔离,限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。

  • 熔断 :当请求次数达到规定的阀值都出现服务故障(超时),Hystrix就把服务标记为短路状态.

    正常情况下,断路器处于关闭状态(Closed),如果调用持续出错或者超时,电路被打开进入熔断状态(Open),后续一段时间内的所有调用都会被拒绝(Fail Fast),一段时间以后,保护器会尝试进入半熔断状态(Half-Open),允许少量请求进来尝试,
    如果调用仍然失败,则回到熔断状态
    如果调用成功,则回到电路闭合状态;
    
  • 降级 :高并发情况下 ,为了保证一些主要的服务有足够的资源不出问题 ,会认为的关掉一些无关紧要的服务,然后返回一些托底的数据,给用户一个友好的提示。

  • 缓存 :Hystrix内部会把请求做缓存

6.3 Ribbon集成Hystrix

  • 导入依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  • 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);
}
  • 拖底方法
public JsonResult getUserByIdFallback(@PathVariable("id") Long id){
    return JsonResult.me().setSuccess(false)
    .setMessage("服务展示不可用,请骚后重试[服务降级]");
}

6.4 Feign集成Hystrix

  • 开启Hystrix
feign:
  hystrix:
    enabled: true #开启熔断支持
  client:
    config:
      remote-service:           #服务名,填写default为所有服务
        connectTimeout: 30000
        readTimeout: 30000
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 30000
  • 修改Feign客户端接口
@FeignClient(value="user-server" ,fallback = UserFeignClientFallback.class)
public interface UserFeignClient {

    @GetMapping("/user/{id}")
    User getUserById(@PathVariable("id")Long id);
}
  • 托底实现
@Component
public class UserFeignClientFallback implements UserFeignClient {
    @Override
    public User getUserById(Long id) {
        System.out.println("托底数据执行....");
        return new User(-1L,"托底数据","");
    }
}

七、SpirngCloud集成ZUUL路由网关

7.1 概述

  • Zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用。
  • Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门,也要注册入Eureka.
  • Zuul是一个SpringCloud的网关组件 , 它是微服务的入口,网络关卡 ,通过Zuul我们可以实现请求的分发(负载均衡),鉴权,限流等等操作。

7.2 集成

  • 导入依赖
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.55</version>
    </dependency>
</dependencies>
  • 开启zuul配置
/**
 * @EnableZuulProxy :开启 网关
 * @EnableZuulServer
 */
@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
public class ZuulApplication5000
...
  • 配置yml文件
eureka:
  client:
    serviceUrl:
      defaultZone: http://peer1:1000/eureka/,http://peer2:1001/eureka/ #注册中心地址
  instance:
    prefer-ip-address: true #使用ip地址注册
    instance-id: zuul-server  #指定服务的id
server:
  port: 5000
spring:
  application:
    name: zuul-server
    
zuul:
  ignored-services: "*"   #禁止使用服务名字进行访问
  prefix: "/servers"  #统一的前缀
  routes: #配置路由,指定服务的访问路径
    dept-server: "/dept/**"
    user-server: "/user/**"
    order-server: "/order/**"
    ....
    
  retryable: true #开启重试
ribbon:
  ConnectTimeout: 2000  # 连接超时时间(ms)
  ReadTimeout: 2000 # 通信超时时间(ms)
  OkToRetryOnAllOperations: true # 是否对所有操作重试
  MaxAutoRetriesNextServer: 2 # 同一服务不同实例的重试次数
  MaxAutoRetries: 1 # 同一实例的重试次数
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMillisecond: 3000 # 熔断超时时长:3000ms

7.3 自定义过滤器

  • 新建类继承ZuulFilter
  • 复写四个方法
    • shouldFilter:返回一个Boolean值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
    • run:过滤器的具体业务逻辑。
    • filterType:返回字符串,代表过滤器的类型。包含以下4种:
      • pre:请求在被路由之前执行
      • routing:在路由请求时调用
      • post:在routing和errror过滤器之后调用
      • error:处理请求时发生错误调用
    • filterOrder:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。
  • 例子:
import com.alibaba.fastjson.JSON;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

@Component
public class LoginCheckFilter extends ZuulFilter{
    /** 过滤器的类型 */
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    /** 级别,顺序 */
    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        //获取请求上下文对象
        RequestContext currentContext = RequestContext.getCurrentContext();

        //获取请求对象
        HttpServletRequest request = currentContext.getRequest();

        //获取请求uri
        String requestURI = request.getRequestURI();

        //判断,如果是 /login请求 则不执行run方法
        if (requestURI.toUpperCase().contains("LOGIN")){
            return false;
        }

        return true;
    }

    @Override
    public Object run() throws ZuulException {
        //获取请求上下文对象
        RequestContext currentContext = RequestContext.getCurrentContext();

        //获取请求对象
        HttpServletRequest request = currentContext.getRequest();

        //获取响应对象
        HttpServletResponse response = currentContext.getResponse();

        //设置响应的数据格式及编码
        response.setContentType("application/json;charset=utf-8");

        //获取请求头中的 x-token
        String token = request.getHeader("x-token");

        //判断是否登录,没有x-token代表没有登录
        if (StringUtils.isBlank(token)){
            //返回没有访问权限的错误信息
            Map<String,String> map = new HashMap<>();
            map.put("success","false");
            map.put("errorMessage","没有登录,滚粗");
            //返回信息
            try {
                response.getWriter().print(JSON.toJSONString(map));
            } catch (IOException e) {
                e.printStackTrace();
            }

            //阻止放行,不会执行后面的filter,不会继续执行后面的
            currentContext.setSendZuulResponse(false);
        }

        return null;
    }
}

7.4 过滤器执行周期

在这里插入图片描述

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

7.5 使用场景

  • 请求鉴权:一般放在pre类型,如果发现没有访问权限,直接就拦截了
  • 异常处理:一般会在error类型和post类型过滤器中结合来处理。
  • 服务调用时长统计:pre和post结合使用

八、Config分布式配置中心

8.1 概念

在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是config server,二是config client。

  • 原理图
    在这里插入图片描述

8.2 集成

  • 使用码云创建远程仓库
    在这里插入图片描述
  • 导入依赖
<dependencies>
   <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
   </dependency>
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-config-server</artifactId>
   </dependency>
</dependencies>
  • 开启配置中心
/**
 * @EnableConfigServer:开启配置中心
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableConfigServer
public class ConfigServerApplication6000 
...
  • 配置yml文件
eureka:
  client:
    serviceUrl:
      defaultZone: http://peer1:1000/eureka/,http://peer2:1001/eureka/ #注册中心地址
  instance:
    prefer-ip-address: true #使用ip地址注册
    instance-id: config-server  #指定服务的id
server:
  port: 6001
spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/xxxxx/springcloud-config.git #配置远程仓库地址
          username: xxxxxxxxx
          password: xxxxxxxxxx
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值