SpringCloud

SpringCloud

微服务架构四大问题(本质网络不可靠)

1.  服务很多,客户端要怎么去访问?

2.  服务很多,服务之间要怎么通讯?

3.  服务很多,如何治理?

4.  服务很多,服务挂了怎么办?


解决方案:
	springcloud  生态!!!
	
	1. springcloud netflix(一站式解决方案)
		问题一:api网关,zuul组件
		问题二:Feign--HttpClient   Http通讯方式,同步、阻塞
		问题三:服务注册与发现:Eureka
		问题四:熔断机制:Hystrix
	
	2. springcloud alibaba(一站式解决方案)---更简单!!!
		
	
	3. dubbo+zookeeper(半自动,需要整合别的)---这套方案并不完善!!!
		问题一:api网关(没有,找第三方组件!!!,或者自己实现)
		问题二:Dubbo RPC(远程过程调用)
		问题三:ZooKeeper(注册中心)
		问题四:熔断机制:没有需要借助(Hystrix)
		
		
新概念:服务网格---Server Mesh	

知识模块:
    1. API(网关)
    2. HTTP/RPC(通讯协议)
    3. 注册和发现(高可用、多线程相关)
    4. 熔断机制

常见面试题

1.1 什么是微服务?

	微服务架构是一种架构模式,或者说是一种架构风格,它提倡将单个应用程序划分成一组小的服务,每个服务运行在其独立的自己的进程中,服务之间互相协调,互相配置,为用户提供了最终价值,服务之间采用轻量级的通讯机制互相沟通,每个服务都围绕着具体的业务进行构建,并且能够被独立的部署在生成环境中,另外。应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建,可以有一个非常轻量级的集中式管理来协调这些服务,可以使用不同的语言来编写服务,也可以使用不同的数据存储。

技术维度理解:

	微服务化的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底地解耦合,每一个微服务提供单个业务功能的服务,一个服务做一件事情,从技术角度来看就是一种小而独立的处理过程,类似进程的概念,能够自行单独启动或销毁,拥有自己独立的数据库。	

1.2 微服务之间是如何独立通讯的?

HTTP与RPC

1.3 SpringCloud和Dubbo有哪些区别?

技术条目 Dubbo SpringCloud
服务注册中心 Zookeeper SpringCloud Netfilx Eureka
服务调用方式 RPC REST API
服务监控 Dubbo-monitor Spring Boot Admin
熔断器 不完善 Spring Boot Netflix Hystrix
服务网关 Spring Cloud Netflix Zuul
分布式配置 Spring Cloud Config
服务追踪 Spring Cloud Sleuth
消息总线 Spring Cloud Bus
数据流 Spring Cloud Stream
批量任务 Spring Cloud Task

最大的区别:Spring Cloud抛弃了Dubbo的RPC通讯,采用的是基于HTTP的REST方式。

​ 严格来说,这两种方式各有优势,虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生RPC带来的问题。而且REST相比RPC更为灵活,服务提供方和调用方的依赖只依赖一纸契约,不存在代码级别的强依赖,这在强调快速演化的服务环境下,显得更加合适。

1.4 SpringCloud和SpringBoot的关系,请你谈下对它们的理解

1. SpringBoot是专注于快速方便的开发单个个体微服务。
2. SpringCloud是关注全局的微服务协调调整整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,为各个微服务之间提供:**配置管理、服务发现、熔断器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等集成服务。**
3. SpringBoot可以离开SpringCloud独立使用、开发项目,但是SpringCloud不能离开SpringBoot,属于依赖关系。
4. **SpringBoot专注于快速、方便的开发单个个体微服务,SpringCloud专注全局的服务治理框架。**

1.5 什么是服务熔断?什么是服务降级?

1.6 微服务的优缺点分别是?说下你在项目开发中遇到的坑?

优点:

1.	每个服务足够内聚,足够小,代码容易理解,这样能聚焦一个指定的业务功能或业务需求(单一职能原则)
2.	开发简单,开发效率高,一个服务可能就是专一的只干一件事
3.	微服务能够被小团队单独开发,这个小团队是2-5人的开发人员组成
4.	微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的
5.	微服务能使用不同的语言开发
6.	易于和第三发集成,微服务允许容易且灵活的方式**集成自动部署**,通过**持续集成工具**,如jenkins,Hudson,bamboo
7.	微服务易于被一个开发人员理解、修改和维护,这样小团队能够更关注自己的工作成果。不需要通过合作才能体现价值
8.	微服务允许你利用融合最新技术
9.	**微服务只是业务逻辑的代码,不会和HTML、CSS或其他界面混合**
10.	每个微服务都有自己的存储能力,可以有自己的数据库,也可以统一数据库

缺点:

1. 开发人员要处理分布式系统的复杂性(四大问题)
2. 多服务运维难度,随着服务的增加,运维的压力也在增大
3. 系统部署依赖
4. 服务间通信成本
5. 数据一致性
6. 系统集成测试
7. 性能监控

1.7 你所知道的微服务技术栈有哪些?

微服务条目 落地技术
服务开发 SpringBoot、Spring、SpringMVC
服务配置与管理 Neflix的Archius、阿里的Diamond等
服务注册与发现 Eureka、Consul、Zookeeper等
服务调用 Rest、RPC、gRPC
服务熔断器 Hystrix、Envoy等
负载均衡 Ribbon、Nginx等
服务接口调用(客户端调用服务的简化工具) Fegin等
消息队列 Kafka、RabbitMQ、ActiveMQ等
服务配置中心管理 SpringCloudConfig、Chef等
服务路由(API网关) Zuul等
服务监控 Zabbix、Naglos、Metrics、Specataor等
全链路追踪 Zipkin、Brave、Dapper等
服务部署 Docker、OpenStack、Kubernetes等
数据流操作开发包 SpringCloudStream(封装与Redis、Rabbit、Kafka等发送接收消息)
事件消息总线 SpringCloud Bus

1.8 Eureka和Zookeeper都可以提供服务注册与发现的功能,请说下两者的区别?

一、SpringCloud简述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bLp42smv-1602404068837)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200921224101571.png)]

​ SpringCloud是基于SpringBoot的一套微服务解决方案,包括服务注册与发现、配置中心、全链路监控、服务网关、负载均衡、熔断器等组件,除了基于NetFlix的开源组件做高度抽象封装之外,还有一些选型中立的开源组件。

​ SpringCloud利用SpringBoot的开发便利性,巧妙地简化了分布式系统基础的开发,SpringCloud为开发人员提供李快速构建分布式系统的一些工具,包括配置管理、服务发现、熔断器、微代理、事件总线、全局锁、决策竞选、分布式会话等,他们都可以用SpringBoot开发风格做到一键启动和部署。

​ SpringBoot并没有重复造轮子,它只是将目前各家公司开发的比较成熟,经得起实际考验的服务框架组合起来,通过SpringBoot风格进行再封装,屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。

​ SpringCloud是分布式微服务架构下的一站式解决方案,是各个微服务架构落地技术的集合体,俗称微服务全家桶。

二、Eureka服务注册与发现(注册中心)

1.1 什么是Eureka?

​ 是Netflix的一个子模块,也是核心模块之一,Eureka是基于REST的服务,用于定位服务,以实现云端中间服务发现和故障转移,服务注册与发现对于微服务来说是非常重要的,有了服务注册与发现,只需使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,比如Zookeeper

Eureka工作流程图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ggkOrAUr-1602404068839)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200922154018245.png)]

三大角色:

  1. Eureka Server:提供服务的注册与发现(注册中心)
  2. Server Provider:将自身服务注册到Eureka Server,从而使消费者能够找到所需的服务
  3. Server Consumer:服务消费者从Eureka Server中获取注册服务列表,从而找到要消费的服务

1.2 代码流程实现

启动Eureka注册中心报错:

Unable to start web server; nested exception is org.springframework.boot.web.server.WebS

解决方案:统一SpringBoot与SpringCloud的版本!!!!

pom

<properties>
        <spring.version>5.2.8.RELEASEspring.version>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
        <springfox.swagger2.version>2.9.2springfox.swagger2.version>
        <mybatisplus.version>3.4.0mybatisplus.version>
        <mysql.version>8.0.21mysql.version>
        <java.version>1.8java.version>
        <spring.boot.autoconfigure.version>2.3.3.RELEASEspring.boot.autoconfigure.version>
        <jackson.version>2.11.2jackson.version>
        <swagger.version>2.9.2swagger.version>
    properties>


    <dependencyManagement>
        <dependencies>


            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-eureka-serverartifactId>
            dependency>
            

            
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-dependenciesartifactId>
                <version>2.3.4.RELEASEversion>
                <type>pomtype>
                <scope>importscope>
            dependency>
            

            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-dependenciesartifactId>
                <version>Hoxton.SR8version>
                <type>pomtype>
                <scope>importscope>
            dependency>
            

            
            <dependency>
                <groupId>com.baomidougroupId>
                <artifactId>mybatis-plus-boot-starterartifactId>
                <version>${mybatisplus.version}version>
            dependency>
            

            
            <dependency>
                <groupId>org.springframeworkgroupId>
                <artifactId>spring-webmvcartifactId>
                <version>${spring.version}version>
            dependency>
            

            <dependency>
                <groupId>mysqlgroupId>
                <artifactId>mysql-connector-javaartifactId>
                <version>8.0.21version>
            dependency>

            <dependency>
                <groupId>org.springframeworkgroupId>
                <artifactId>spring-webartifactId>
                <version>5.2.8.RELEASEversion>
            dependency>

            
            <dependency>
                <groupId>com.fasterxml.jackson.coregroupId>
                <artifactId>jackson-coreartifactId>
                <version>${jackson.version}version>
            dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.coregroupId>
                <artifactId>jackson-databindartifactId>
                <version>${jackson.version}version>
            dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.coregroupId>
                <artifactId>jackson-annotationsartifactId>
                <version>${jackson.version}version>
            dependency>
            

            
            <dependency>
                <groupId>io.springfoxgroupId>
                <artifactId>springfox-swagger2artifactId>
                <version>${swagger.version}version>
            dependency>
            <dependency>
                <groupId>io.springfoxgroupId>
                <artifactId>springfox-swagger-uiartifactId>
                <version>${swagger.version}version>
            dependency>
            

            
            <dependency>
                <groupId>mysqlgroupId>
                <artifactId>mysql-connector-javaartifactId>
                <version>${mysql.version}}version>
            dependency>
            

            
            <dependency>
                <groupId>org.mybatisgroupId>
                <artifactId>mybatisartifactId>
                <version>3.5.5version>
            dependency>
            <dependency>
                <groupId>org.mybatisgroupId>
                <artifactId>mybatis-springartifactId>
                <version>2.0.5version>
            dependency>
            <dependency>
                <groupId>org.springframeworkgroupId>
                <artifactId>spring-jdbcartifactId>
                <version>${spring.version}version>
            dependency>
            

            
            <dependency>
                <groupId>org.slf4jgroupId>
                <artifactId>slf4j-log4j12artifactId>
                <version>1.7.25version>
            dependency>
            

            
            <dependency>
                <groupId>org.apache.shirogroupId>
                <artifactId>shiro-spring-boot-web-starterartifactId>
                <version>1.6.0version>
            dependency>
            


            
            <dependency>
                <groupId>org.springframeworkgroupId>
                <artifactId>spring-testartifactId>
                <version>${spring.version}version>
                <scope>testscope>
            dependency>
            


            
            <dependency>
                <groupId>junitgroupId>
                <artifactId>junitartifactId>
                <version>4.12version>
                <scope>testscope>
            dependency>
            


            <dependency>
                <groupId>ch.qos.logbackgroupId>
                <artifactId>logback-classicartifactId>
                <version>1.2.3version>
            dependency>

            
            <dependency>
                <groupId>javax.servletgroupId>
                <artifactId>javax.servlet-apiartifactId>
                <version>4.0.1version>
                <scope>providedscope>
            dependency>
            

            
            <dependency>
                <groupId>ch.ethz.ganymedgroupId>
                <artifactId>ganymed-ssh2artifactId>
                <version>262version>
            dependency>
            


        dependencies>
    dependencyManagement>

生产者:

package cn.qf.controller;

import cn.qf.pojo.entity.Goods;
import cn.qf.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @author cxf
 * @date 2020/9/22 19:15
 * @msg 商品生产者接口
 */

//提供Restful服务
@RestController
@RequestMapping("/goods")
public class GoodsController {
     

    @Autowired
    private GoodsService goodsService ;

    @GetMapping("/showAll")
    public List<Goods> showAllGoods(){
     
       return  goodsService.allGoods();
    }
}

消费者:

//配置Restful风格数据传递模板
package cn.qf.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * @author cxf
 * @date 2020/9/22 19:34
 * @msg 配置类
 */

@Configuration
public class ConfigBean {
     
    
    //将RestTemplate放入spring容器中
    @Bean
    public RestTemplate getRestTemplate(){
     
        return new RestTemplate();
    }
}


package cn.qf.controller;

import cn.qf.pojo.entity.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

/**
 * @author cxf
 * @date 2020/9/22 19:30
 * @msg 消费者接口
 */

@RestController
@RequestMapping("/consumer")
public class ConsumerController {
     

    //理解:消费者不应该有业务层
    //RestTemplate  供我们直接调用就可以了


    //三个核心参数
    // url 、 请求的参数实体 、 返回的参数类型
    @Autowired
    private RestTemplate restTemplate ;

    private static final String REST_URL_PREFIX = "http://localhost:8001" ;

    @RequestMapping("/getAllGoods")
    public List<Goods> getAllGoods(){
     
        return restTemplate.getForObject(REST_URL_PREFIX+"/goods/showAll",List.class);
    }


}

将各个节点加入Eureka注册中心

节点pom
<dependencies>

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-eurekaartifactId>
        dependency>
        

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-actuatorartifactId>
        dependency>
        

        <dependency>
            <groupId>cn.qfgroupId>
            <artifactId>spring-cloud-apiartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>

        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
        dependency>

        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
        dependency>
        

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starterartifactId>
        dependency>
        

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-testartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-jettyartifactId>
        dependency>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
        dependency>
        

        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>
    dependencies>
节点 application.yml
#服务器配置
server:
  #配置端口
  port: 8001

#配置数据库连接池
spring:
  application:
    name: spring-cloud-provider-goods
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    username: root
    password: 123456
    hikari:
      minimum-idle: 5
      idle-timeout: 600000
      maximum-pool-size: 10
      auto-commit: true
      pool-name: MyHikariCP
      max-lifetime: 1800000
      connection-timeout: 30000
      connection-test-query: SELECT 1

#mybatis-plus配置
mybatis-plus:
  #配置扫描的实体类路径
  type-aliases-package: cn.qf.pojo.entity
  #配置扫描的mapper.xml文件的路径
  mapper-locations: classpath*:mapper/*.xml

#Eureka注册中心,客户端的配置(将该服务节点注册到哪里)
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7666/eureka/
  instance:
    instance-id: springcloud-provider-8001 #修改Eureka上的默认状态描述信息!!!

#info配置(点击Eureka注册中心监控页面上Status选项的连接出现的文字内容!!!)
info:
  #配置应用的名称
  app.name: springcloud-provider
  #公司的名称
  company.name: myTets

节点启动类
package cn.qf;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @author cxf
 * @date 2020/9/22 19:12
 * @msg 启动类
 */

@SpringBootApplication
@EnableEurekaClient   //在服务启动后,将该节点自动注册到Eureka注册中!!!
public class Provider_Goods_8001 {
     

    public static void main(String[] args) {
     
        SpringApplication.run(Provider_Goods_8001.class, args);
    }
}

Eureka注册中心POM
<dependencies>

        
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-eureka-serverartifactId>
            dependency>
        

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
        dependency>
        

    dependencies>
Eureka注册中心application.yml
server:
  port: 7666

#Eureka配置
eureka:
  instance:
    hostname: localhost  #Eureka服务端的实例名称
  client:
    register-with-eureka: false #表示是否向Eureka注册中心注册自己
    fetch-registry: false #fetch-registry如果为false,表示自己为注册中心
    service-url: #与Eureka注册中心交互的页面,监控页面
      defaultZone: http://${
     eureka.instance.hostname}:${
     server.port}/eureka/  #修改默认的Eureka注册中心访问地址
Eureka注册中心启动类
package cn.qf;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * @author cxf
 * @date 2020/9/22 20:08
 * @msg Eureka服务端的启动类
 */

//启动之后,访问http://localhost:7666
@SpringBootApplication
@EnableEurekaServer  //EnableEurekaServer,表示这是一个Eureka服务端的启动类,可以接受其他节点的注册
public class EurekaServer_7666 {
     

    public static void main(String[] args) {
     
        SpringApplication.run(EurekaServer_7666.class ,args);
    }
}

1.3 Eureka的自我保护机制(类似熔断机制)

​ 一句话总结:某一时刻某一个微服务不可用,Erueka不会立即清理,依旧会对该微服务的信息进行保存!!!

  1. 默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网网络分区故障发生时,微服务与Eureka注册中心之间无法正常通行,以上行为可能变得非常危险,因为微服务本身其实是健康的,此时本不应该注销这个服务。Eureka通过自我保护机制,来解决这个问题,单EurekaServer节点在短时间内丢失多个客户端时(可能发生了网络分区的故障),那么这个节点就会进入自我保护模式,一旦进入该模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就不会注销任何微服务)。当网络故障恢复后,该EurekaServer节点会自动退出自我保护模式。
  2. 在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例,当它收到心跳数重写恢复到阈值以上时,该EurekaServer节点就会自动退出自我保护模式,它的设计哲学就是宁可保留错误的服务注册表信息,也不会盲目注销任何可能健康的服务实例。一句话:好死不如赖活着!!!
  3. 综上,自我保护模式是一种应对网络异常的安全保护措施,使用自我保护模式,可以让Eureka集群更加健壮和稳定。
  4. 在SpringCloud中,可以使用eureka.server.enable-self-preservation = false,禁用自我保护模式。【不推荐关闭自我保护机制!!!】

禁用自我保护模式yml

eureka:
  server:
    enable-self-preservation = false

1.4 获取在Eureka注册中心注册的节点信息

pom
<dependencies>

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-eurekaartifactId>
        dependency>
        

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-actuatorartifactId>
        dependency>
        

        <dependency>
            <groupId>cn.qfgroupId>
            <artifactId>spring-cloud-apiartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>

        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
        dependency>

        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
        dependency>
        

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starterartifactId>
        dependency>
        

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-testartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-jettyartifactId>
        dependency>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
        dependency>
        

        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>
    dependencies>
application.yml
#服务器配置
server:
  #配置端口
  port: 8001

#配置数据库连接池
spring:
  application:
    name: spring-cloud-provider-goods
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    username: root
    password: 123456
    hikari:
      minimum-idle: 5
      idle-timeout: 600000
      maximum-pool-size: 10
      auto-commit: true
      pool-name: MyHikariCP
      max-lifetime: 1800000
      connection-timeout: 30000
      connection-test-query: SELECT 1

#mybatis-plus配置
mybatis-plus:
  #配置扫描的实体类路径
  type-aliases-package: cn.qf.pojo.entity
  #配置扫描的mapper.xml文件的路径
  mapper-locations: classpath*:mapper/*.xml

#Eureka注册中心,客户端的配置(将该服务节点注册到哪里)
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7666/eureka/
  instance:
    instance-id: springcloud-provider-8001 #修改Eureka上的默认状态描述信息!!!

#info配置(点击Eureka注册中心监控页面上Status选项的连接出现的文字内容!!!)
info:
  #配置应用的名称
  app.name: springcloud-provider
  #公司的名称
  company.name: myTets

后端接口
package cn.qf.controller;

import cn.qf.pojo.entity.Goods;
import cn.qf.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @author cxf
 * @date 2020/9/22 19:15
 * @msg 商品生产者接口
 */

//提供Restful服务
@RestController
@RequestMapping("/goods")
public class GoodsController {
     

    @Autowired
    private GoodsService goodsService;


    //获取一些信息,得到具体的微服务
    @Autowired
    private DiscoveryClient client;

    @GetMapping("/showAll")
    public List<Goods> showAllGoods() {
     
        return goodsService.allGoods();
    }


    //注册进来的微服务,获取一些信息
    @GetMapping("/getDiscovery")
    public Object discovery() {
     
        //获取微服务列表的清单
        List<String> services = client.getServices();
        System.out.println("discovery==>services" + services);

        //得到一个具体的微服务信息  ,服务id  ===》 spring.application.name
        List<ServiceInstance> instances = client.getInstances("spring-cloud-provider-goods");

        System.out.println("discovery==>instances" + instances);
        for (ServiceInstance instance : instances) {
     
            System.out.println(
                    instance.getHost() + "\t" +
                            instance.getPort() + "\t" +
                            instance.getUri() + "\t" +
                            instance.getServiceId() + "\t"
            );
        }

        return this.client;
    }
}

1.5 Eureka集群配置

Eureka集群搭建原理图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T11OU575-1602404068843)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200922222530181.png)]

服务端的yml配置

server:
  port: 7666

#Eureka配置
eureka:
  instance:
    hostname: eureka7666.com  #Eureka服务端的实例名称
  client:
    register-with-eureka: false #表示是否向Eureka注册中心注册自己
    fetch-registry: false #fetch-registry如果为false,表示自己为注册中心
    service-url: #与Eureka注册中心交互的页面,监控页面
      #单机:defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      #集群(关联):
      defaultZone: http://eureka7777.com:eureka7777.com/eureka/,http://eureka7888.com:eureka7888.com/eureka/  #修改默认的Eureka注册中心访问地址

客户端(节点)的yml配置

#服务器配置
server:
  #配置端口
  port: 8001

#配置数据库连接池
spring:
  application:
    name: spring-cloud-provider-goods
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    username: root
    password: 123456
    hikari:
      minimum-idle: 5
      idle-timeout: 600000
      maximum-pool-size: 10
      auto-commit: true
      pool-name: MyHikariCP
      max-lifetime: 1800000
      connection-timeout: 30000
      connection-test-query: SELECT 1

#mybatis-plus配置
mybatis-plus:
  #配置扫描的实体类路径
  type-aliases-package: cn.qf.pojo.entity
  #配置扫描的mapper.xml文件的路径
  mapper-locations: classpath*:mapper/*.xml

#Eureka注册中心,客户端的配置(将该服务节点注册到哪里)
eureka:
  client:
    service-url:
      #单机:defaultZone: http://localhost:7666/eureka/

      #集群:
      defaultZone: http://localhost:7666/eureka/,http://localhost:7777/eureka/,http://localhost:7888/eureka/
  instance:
    instance-id: springcloud-provider-8001 #修改Eureka上的默认状态描述信息!!!

#info配置(点击Eureka注册中心监控页面上Status选项的连接出现的文字内容!!!)
info:
  #配置应用的名称
  app.name: springcloud-provider
  #公司的名称
  company.name: myTets

1.6 Eureka的CAP原则与Zookeeper的对比

什么是CAP??

  1. C(Consistency)强一致性

  2. A(Availablility)可用性

  3. P(Partition tolerance)分区容错性

    CAP的三进二:CA、AP、CP

CAP理论的核心

  1. 一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求。
  2. 根据CAP原理,将NoSQL数据库分成满足CA原则,满足CP原则和满足AP原则三大类:
    1. CA:单点集群,满足一致性,可用性的相同,通常可扩展性较差。
    2. CP:满足一致性,分区容错性的系统,通常性能不是特别高。
    3. AP:满足可用性,分区容错性的系统,通常可能对一致性要求低一些。

Eureka作为服务注册中心,Eureka比Zookeeper好在哪里?

1. Zookeeper保证的是CP
	当想注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性要求要高于一致性。但是Zookeeper会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30-120s,且选举期间整个Zookeeper集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因为网络问题使得Zookeeper集群失去master节点是较大概率会发生的事件,虽然服务最终能够恢复,但是漫长的选举事件导致的注册长期不可用是不能容忍的。
2.Eureka保证的AP

​ Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册时,如果发现连接失败,则自动切换至其他节点,只要一台Eureka还在,就能保住注册服务的可用性,只不过查到的信息可能不是最新的,除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:

  1. Eureka不再从注册列表汇总移除因为长时间没收到心跳而应该过期的服务。
  2. Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上(即保证当前节点依然可用)。
  3. 当网络稳定时,当前实例新的注册信息会被同步到其他节点中。

因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像Zookeeper那样使整个注册服务瘫痪。

三、Ribbon(负载均衡)—面向服务

什么是负载均衡(Load Balance)???

​ 简单地来说,就是将用户发送的请求平均的分发给各个服务器,从而达到整个服务系统的高可用!!!

负载均衡的简单分类

1. 集中式LB

​ 即在服务的消费方和提供方之间使用独立的LB设施,如Nginx,由该设施负责把访问请求通过某种策略转发至服务的提供方!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q35LrDCj-1602404068848)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200923164858772.png)]

2. 进程式LB

​ 将LB逻辑集成在消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。

3.1 POM


3.2 自定义Ribbon的负载均衡算法

IRule负载均衡算法接口

实现类:

  1. AvailabilityFilteringRule:会过滤掉出问题的服务,对剩下的服务进行轮询。
  2. RoundRobinRule:轮询
  3. RandomRule:随机
  4. RetryRule:会先轮询服务,如果服务出问题,会在一定的时间内重试。
package cn.myrule;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

/**
 * A loadbalacing strategy that randomly distributes traffic amongst existing
 * servers.
 *
 * @author stonse
 *
 */
public class RandomRule extends AbstractLoadBalancerRule {
     


    private int total = 0 ; //服务被调用调用的次数

    private int currentIndex = 0 ; // 当前提供服务的节点


//    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    public Server choose(ILoadBalancer lb, Object key) {
     
        if (lb == null) {
     
            return null;
        }
        Server server = null;

        while (server == null) {
     
            if (Thread.interrupted()) {
     
                return null;
            }

            //获得活着的服务
            List<Server> upList = lb.getReachableServers();

            //获得全部的服务
            List<Server> allList = lb.getAllServers();

            int serverCount = allList.size();
            if (serverCount == 0) {
     
                /*
                 * No servers. End regardless of pass, because subsequent passes
                 * only get more restrictive.
                 */
                return null;
            }

//            //生成区间随机数
//            int index = chooseRandomInt(serverCount);
//
//            //从活着的服务中,随机获取一个
//            server = upList.get(index);
            
            //自定义负载均衡算法
            
            //判断调用的次数
            if (total < 5) {
     
                Server server1 = upList.get(currentIndex);
                total ++ ;
            }else{
     
                total = 0 ;
                currentIndex ++ ;
                if (currentIndex > allList.size()) {
     
                    currentIndex = 0 ;
                }
                Server server2 =  upList.get(currentIndex);
            }
            
            

            if (server == null) {
     
                /*
                 * The only time this should happen is if the server list were
                 * somehow trimmed. This is a transient condition. Retry after
                 * yielding.
                 */
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
     
                return (server);
            }

            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }

        return server;

    }

    protected int chooseRandomInt(int serverCount) {
     
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

    @Override
    public Server choose(Object key) {
     
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
     
        // TODO Auto-generated method stub

    }
}

四、Feign(负载均衡)—面向接口

​ 类似于controller调用service

Feign集成了Ribbon

​ 利用了Ribbon维护了MicroServiceCloud-Dep的服务列表信息,并且通过轮询实现了客户端的负载均衡,而与Ribbon不同的是,通过Feign只需要定义服务绑定接口以声明式的方法,优雅而且简单的实现了服务的调用。

4.1 Feign使用步骤

1.POM

<dependencies>

        

        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-openfeignartifactId>
        dependency>

        



        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-ribbonartifactId>
        dependency>
        


        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starterartifactId>
        dependency>
        

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        

        
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
        dependency>
        

        
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
        dependency>
        

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
        dependency>
        


        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
        dependency>
        

        

        <dependency>
            <groupId>cn.qfgroupId>
            <artifactId>springcloud-beanartifactId>
        dependency>

        


        

        <dependency>
            <groupId>cn.qfgroupId>
            <artifactId>springcloud-serviceartifactId>
        dependency>

        

        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>


    dependencies>

五、Hystrix(服务熔断)

什么是服务雪崩

​ 在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以通过 HTTP/RPC 相互调用,在 Spring Cloud 中可以用 RestTemplate + LoadBalanceClientFeign 来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证 100% 可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet 容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的 “雪崩” 效应。为了解决这个问题,业界提出了 熔断器模型

什么是Hystrix?

​ 是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。

​ “熔断器”本身是一种开关装置,当某个服务单元发生故障之后,通过熔断器的故障监控(类似于熔断保险丝),想调用发返回一个服务预期的,可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方法无法处理的异常,这样就可以保证了服务调用发的线程不会被长时间、不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

能干嘛?

  1. 服务降级
  2. 服务熔断
  3. 服务限流
  4. 接近实时的监控
  5. 等等

六、Sentinel(服务熔断)

与Hystrix的对比

Sentinel Hystrix
隔离策略 信号量隔离 线程池隔离/信号量隔离
熔断降级策略 基于响应时间或失败比率 基于失败比率
实时指标实现 滑动窗口 滑动窗口(基于 RxJava)
规则配置 支持多种数据源 支持多种数据源
扩展性 多个扩展点 插件的形式
基于注解的支持 支持 支持
限流 基于 QPS,支持基于调用关系的限流 有限的支持
流量整形 支持慢启动、匀速器模式 不支持
系统负载保护 支持 不支持
控制台 开箱即用,可配置规则、查看秒级监控、机器发现等 不完善
常见框架的适配 Servlet、Spring Cloud、Dubbo、gRPC 等 Servlet、Spring Cloud Netflix

6.1 流控规则

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rOzlklY0-1602404068851)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200924230022836.png)]

基本介绍

流控模式

1、直接
2、关联
3、链路

流控效果

1.直接(快速失败----默认处理)

2.预热

、不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

能干嘛?

  1. 服务降级
  2. 服务熔断
  3. 服务限流
  4. 接近实时的监控
  5. 等等

六、Sentinel(服务熔断)

与Hystrix的对比

Sentinel Hystrix
隔离策略 信号量隔离 线程池隔离/信号量隔离
熔断降级策略 基于响应时间或失败比率 基于失败比率
实时指标实现 滑动窗口 滑动窗口(基于 RxJava)
规则配置 支持多种数据源 支持多种数据源
扩展性 多个扩展点 插件的形式
基于注解的支持 支持 支持
限流 基于 QPS,支持基于调用关系的限流 有限的支持
流量整形 支持慢启动、匀速器模式 不支持
系统负载保护 支持 不支持
控制台 开箱即用,可配置规则、查看秒级监控、机器发现等 不完善
常见框架的适配 Servlet、Spring Cloud、Dubbo、gRPC 等 Servlet、Spring Cloud Netflix

6.1 流控规则

[外链图片转存中…(img-rOzlklY0-1602404068851)]

基本介绍

流控模式

1、直接
2、关联
3、链路

流控效果

1.直接(快速失败----默认处理)

2.预热

3.排队等待

你可能感兴趣的