springcloud学习总结

1. 传统单体应用架构

程序在编写完成之后会被打包并部署为一个具体的应用。Java Web项目打包成WAR包,Java项目打包成JAR包。

但是随着用户人数的增加,一台机器可能满足不了系统的负载,此时我们就会考虑水平扩展。

面对上述情况,我们通常会增加服务器的数量,并将打包好的应用拷贝到不同服务器,然后通过负载均衡器实现应用的水平扩展。

缺点

// 1. 应用维护困难       随着时间推移项目逐渐变大,一旦项目变得庞大而复杂,就很难进行二次开发与维护。

// 2. 可靠性低          因为所有模块都运行在一个进程中,任何一个模块出现问题,都会导致整个进程崩溃,进而影响到整个应用。

// 3. 不利于技术更新     如果需要更改某个技术,可能需要将整个应用重新开发。





2. SOA架构

针对传统单体架构的问题,企业开始通过SOA【面向服务的架构】来解决。

SOA:把应用中相近的功能聚合到一起,以服务的形式提供出去。即:他将原来的单体架构细分为不同的子系统,再由各个子系统互相调用所需的服务。

优点

// 1. 将项目拆分成若干个子项目,不同的团队可以负责不同的子项目,从而提高开发效率。

// 2. 把模块拆分,使用接口通信,降低了模块之间的耦合度。

// 3. 能够升级单个服务而无需重写整个应用。

缺点

// SOA中各个相互独立的服务还是部署在同一个Tomcat实例,随着业务功能的增多,会导致SOA服务越来越复杂。





3. 微服务架构

微服务架构:是一种架构风格和架构思想。

它倡导我们在传统单体架构的基础上,将系统按照功能拆分为更加细粒度的服务。

所拆分的每一个服务都是一个独立的应用,单独部署。这些应用对外提供公共的API,可以独立承担对外服务的职责。

围绕着这一思想的一系列体系结构【开发,测试,部署等等】,我们就可以称它为“微服务架构”。

优点

// 1. 每个微服务可以独立部署      当某个微服务发生变更时,不需要重新部署整个项目。

// 2. 技术选型灵活               各个微服务的技术选型可以不一样,当需要对某个微服务技术升级时,不需要面临对整个项目的重新开发。

// 3. 复杂度可控                 每个微服务专注单个功能,体积小,复杂度低,便于维护。

// 4. 易于容错                   当某个服务发生故障时,在设计良好的情况下,其他服务一般不会被影响。

// 5. 易于扩展                   单个服务可以水平扩展,比如:订单服务访问高,我可以对其多部署几个服务。

SOA与微服务区别

SOA项目分为多个子系统,粗粒度。微服务项目分为多个微服务,细粒度。

SOA项目服务部署在一起,互相依赖。微服务项目每个微服务可以独立部署。









4. 微服务的拆分建议

  1. 通过业务功能分解并定义与业务功能相对应的服务。
  2. 按照动词或用例分解,并定义负责特定操作的服务。例如:一个负责完成订单的航运服务。
  3. 通过定义一个对给定实体或资源的所有操作负责的服务。例如:一个负责管理用户账户的账户服务。





补充. 分布式微服务与集群的关系

分布式:多个独立的计算机集合,每个计算机做不同的事,共同支撑一个系统。

集群:多个独立的计算机集合,每个计算机做相同的事,共同支撑某一个服务。

分布式中的每一个节点都可以做集群。






5. 微服务架构的组件

前言:开发微服务架构的项目,我们一般采用如下组件。

// 1. 微服务注册中心           注册系统中所有服务的地方。

// 2. 服务注册                服务提供方将自己的调用地址注册到服务注册,用于让服务调用方能够方便快速地调用自己

// 3. 服务发现                服务调用方从注册中心找到自己要调用的服务的地址。

// 4. 负载均衡                服务提供方以多实例的形式提供服务,使用负载均衡能让服务调用方连接到合适的服务节点。

// 5. 服务容错                通过一系列保护机制,保证服务调用者在调用到异常服务时能快速返回结果,免得长时间等待。

// 6. 服务网关                服务调用的唯一入口,一般用来实现用户鉴权,动态路由,负载均衡,限流等功能。

// 7. 分布式配置中心           将本地的配置信息注册到配置中心统一管理。      为什么要统一管理呢?  各个微服务的配置文件可能不一样,而且配置在本地,如果要修改配置,修改完需要重启。有了分布式配置中心,就可以解决这些问题。 


// 微服务实例的开发             springBoot
// 服务注册                    eureka    zookeeper    nacos    consul   
// 服务发现                    feign     dubbo
// 负载均衡                    ribbon    
// 服务容错                    hystrix   sentinal
// Api网关                     zuul      gateway
// 分布式配置中心               springcloud config    nacos





5. SpringBoot与SpringCloud的区别

SpringCloud

它是在SpringBoot的基础上构建的,它不是一个具体的技术,而是一个简化分布式系统构建的工具集。

Spring Cloud中包含多个子项目,如:Spring Cloud Netflix,Spring Cloud Config,Spring Cloud Starters等。


SpringBoot

它是一个用来开微服务实例的。









6. SpringCloud与Dubbo区别

Spring Cloud:本身也是基于SpringBoot开发而来,SpringCloud是一系列框架的有序集合,就是把非常流行的微服务的技术整合到一起。

dubbo:本身只是众多分布式开发中解决问题的一种方式,它主要是做服务调用,而spring cloud 是一系列的有序集合。






7. Spring Cloud for Alibaba

spring cloud中的几乎所有的组件都使用Netflix公司的产品【eureka,hystrix,rabbin,zuul,config...】,然后在其基础上做了一层封装【比如推出openFeign(对feign进行了一个升级),推出了gateWay来替换zuul】,还增加了几个没什么大作用的组件,然后就推出来了。

然而Netflix公司的18年12月12日宣布的服务旗下产品进行维护,发现组件Eureka,Hystrix等 已经停止更新,而其他的众多组件预计会在明年(即2020年)停止维护。如此一来,SpringCloud就要凉凉了。

所以开发者们急需其他的一些替代产品,此时spring cloud alibaba就来了,它是由阿里巴巴提供的。Spring Cloud 这时就急了鸭,他就与spring cloud alibaba达成合作,将Spring cloud alibaba整合到sping cloud,将其作为Spring Cloud 下的子项目。

整合之后,依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。




说说Spring Cloud Alibaba的版本号

SpringCloud的版本号是英文方式。因为springcloud是微服务的解决方案,他会有很多子项目,每个子项目都维护这自己的版本号,为了避免冲突,就使用了伦敦地铁站的名字作为版本号。以首字母作为顺序,a,b,c,d....排列。

再说咱们国人开发的,我们没有用英文名,还是数字那种方式。

SpringCloud for alibaba:https://spring.io/projects/spring-cloud-alibaba









8. 说说Hystrix

一个讲的特别好的视频:https://www.bilibili.com/video/BV1nX4y1K748?p=13
Hystrix:是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库、防止出现级联失败也就是雪崩效应。
在目前更加主流的cloud alibba中用 Sentinel 来代替它。

雪崩效应举例:

// A为服务提供者

// B为服务调用者

// C和D是B的服务调用者

// 随着时间的推移,当A的不可用引起B的不可用,并将不可用逐渐放大到C和D时,整个服务就崩了。

// 总结:造成雪崩的原因
// 1. 服务提供者不可用(程序BUG,缓存击穿,大量用户请求等)
// 2. 服务消费者不可用(同步等待造成的资源耗尽)
// 3. 重试加大流量(用户重试,代码逻辑重试)
// 说人话:一个服务不可用,导致一系列服务不可用。我们就是要解决这个问题~~~~~~~~~~~~~~~~~~~~


// 解决雪崩的方案:
// 1. 采用缓存。
// 2. 请求合并,将相同的请求进行合并然后调用批处理接口。
// 3. 服务熔断,当一定时间内,异常请求比例到达阈值时,启动熔断,停止具体服务调用,通过fallback快速返回托底数据  。
// 4. 服务降级,服务熔断以后,客户端调用自己本地方法返回兜底数据。
// 5. 隔离,分为线程池隔离与信号量隔离。通过判断线程池或信号量是否已满,超出容量的请求直接降级,从而达到限流的作用。


// 熔断和降级区别:
// 降级是出错了返回托底数据。
// 熔断是出错了会在一段时间不再访问服务,直接返回托底数据。一段时间后,又关闭熔断尝试放一个请求去访问服务,根据执行情况来确定是否关闭或开启熔断。

8.1 Hystrix实现熔断的原理

8.2 基于Feign使用Hystrix的降级

openfeign依赖默认集成了hystrix依赖,所以无需添加hystrix依赖。

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class SpringcloudConsumerApplication {
	public static void main(String[] args) {
		SpringApplication.run(SpringcloudConsumerApplication.class, args);
	}
}
// @FeignClient注解中指定 fallback 拖地数据类
@FeignClient(value = "cloud-provider",configuration = FeignConfig.class,fallback = UserClientFallback.class)
public interface UserClient {
	
	@RequestMapping("/provider/user/listUser")
	public List<User> listUser();
	
	@RequestMapping("/provider/user/getUserById")
	public User getUserById(@RequestParam("userId") Integer userId);
}
// 创建实现类【需要加入IOC容器】,实现远程接口。该实现类用于返回托底数据

@Component
public class UserClientFallback implements UserClient {
	@Override
	public List<User> listUser() {
		System.out.println("托底数据");
		return null;
	}
	
	@Override
	public User getUserById(Integer userId) {
		System.out.println("托底数据");
		return null;
	}
}
server:
  port: 8001

spring:
  application:
    name: cloud_consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

feign:
  hystrix:
    enabled: true  # 开启hystrix支持


logging:
  level:
    com.lihao: debug

此时,我们的基于Feign的Hystrix服务降级就实现了。但是这种方法,调用方不能捕获服务异常的原因。

// @FeignClient注解中指定 *****fallbackFactory****** 的托底数据类
@FeignClient(value = "cloud-provider", configuration = FeignConfig.class, fallbackFactory = UserClientFallback.class)
public interface UserClient {
	
	@RequestMapping("/provider/user/listUser")
	public List<User> listUser();
	
	@RequestMapping("/provider/user/getUserById")
	public User getUserById(@RequestParam("userId") Integer userId);
}
// 这种方式就能获取服务异常的原因了

// 通过实现FallbackFactory接口来达到获取服务异常的原因。
@Slf4j
@Component
public class UserClientFallback implements FallbackFactory<UserClient> {
	
	// 实现FallbackFactory会要求实现create(Throwable throwable)方法。   通过在该方法中通过匿名内部类的方式实现拖地数据
	@Override
	public UserClient create(Throwable throwable) {
		return new UserClient() {
			@Override
			public List<User> listUser() {
				log.info("异常原因:"+throwable);
				System.out.println("拖地数据");
				return null;
			}
			
			@Override
			public User getUserById(Integer userId) {
				log.info("异常原因:"+throwable);
				System.out.println("拖地数据");
				return null;
			}
		};
	}
}

8.4 Hystrix的熔断实现

我们可以对Hystrix的默认熔断配置进行修改。比如说:默认是5秒重试,我们可以改。【这种方式可能是用于配置全局的,我不确定。我看有些视频里面时将其配置注解里面的】

# 1. 熔断后休眠时间:sleepWindowInMilliseconds
# 2. 熔断触发最小请求次数:requestVolumeThreshold
# 3. 熔断触发错误比例阈值:errorThresholdPercentage
# 4. 熔断超时时间:timeoutInMilliseconds

hystrix:
  command:
    default:
      circuitBreaker:
        # 打开熔断器 默认true
        enabled: true

        #这两个属性是互斥操作,只能开启其中一个
        # 强制让服务拒绝请求
        forceOpen: true
        # 强制让服务接收请求
        forceClosed: true
        #这两个属性是互斥操作,只能开启其中一个





        # 意思是,当发生熔断后,几秒后重试
        # 熔断后休眠时长,默认值5秒
        sleepWindowInMilliseconds: 5000
        # 意思是,当发生熔断后,几秒后重试




        # 意思是,如果你的请求数量在10秒内达到了20个,并且有超过百分之50都是错误的。就会触发。【必须10秒内达到20个请求】

        # 熔断触发最小请求次数,默认值是20
        requestVolumeThreshold: 10
        # 触发熔断错误比例阈值,默认值50%
        errorThresholdPercentage: 50

        # 意思是,如果你的请求数量在10秒内达到了20个,并且有超过百分之50都是错误的。就会触发。【必须10秒内达到20个请求】

      execution:
        isolation:
          thread:
            # 熔断超时设置,默认为1秒
            timeoutInMilliseconds: 2000
// 我所了解到的  Hystrix实现熔断

// 注意该种方式,需要额外导入hystrix的依赖,才能使用hystrix的注解。

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>













// 自己没有演示成功,待后期确认
	@RequestMapping("/getUserById22222222222")
	@HystrixCommand(fallbackMethod = "getUserById22222222222Fallback", commandProperties = {
		@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,value = "10"),
		@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE, value = "50"),
		@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS, value = "5000")
	})
	public User getUserById22222222222(Integer userId) {
		if (userId == 1) {
			return userClient.getUserById22222222222(userId);
		} else {
			int a = 1 / 0;
		}
		return userClient.getUserById22222222222(userId);
	}
	
	public User getUserById22222222222Fallback(Integer userId) {
		System.out.println("熔断触发,返回托底数据");
		return null;
	}





9. Feign

Feign:是一个声明式WebService客户端,使用Feign能让编写WebService客户端更加简单,它的使用方法是定义一个接口,然后在上面添加注解。不再需要拼接URL,参数等操作。

  • 集成Ribbon的负载均衡功能
  • 集成了Hystrix的熔断器功能
  • 支持请求压缩
  • 大大简化了远程调用的代码,同时功能还增强啦
  • Feign以更加优雅的方式编写远程调用代码,并简化重复代码

Ribbon负载均衡策略:
  • 随机
  • 轮询
  • 权重
  • 响应时间
  • 重试

Feign自身已经集成了Ribbon,因此使用Feign的时候,不需要额外引入依赖。

Feign内置的ribbon默认设置了请求超时时长,默认是1000【超过1秒就超时】,可以修改ribbon内部有重试机制,一旦超时,会自动重新发起请求。如果不希望重试可以关闭配置:

# 修改服务地址轮询策略,默认是轮询,配置之后变随机

springcloud-provider:   # 提供方的 application 的 name
  ribbon:
    #轮询
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule  # 设置负载均衡策略为轮询

    ConnectTimeout: 10000 # 连接超时时间   是指去尝试连接服务的时间,连接10秒还连接不起就超时。

    ReadTimeout: 2000 # 数据读取超时时间   是指建立连接后,调用服务,超过2秒还没相应就超时。

    MaxAutoRetries: 1 # 最大重试次数

    MaxAutoRetriesNextServer: 0 # 最大重试下一个服务次数(集群的情况才会用到)

    OkToRetryOnAllOperations: false # 无论是请求超时 或者 连接超时都进行重试

也阔以用这种方式来改,将feignName指定为你要调的服务。如果想所有都用这个配置,feignName改成default

9.1 使用Feign

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
// 消费方主启动类上加 @EnableFeignClients

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableCircuitBreaker
public class SpringcloudConsumerApplication {
	public static void main(String[] args) {
		SpringApplication.run(SpringcloudConsumerApplication.class, args);
	}
}
// 在消费方创建一个接口【推荐将其写在 common模块】

@FeignClient(value = "springcloud-provider")  // value的值:提供方的 application 的 name。
public interface UserClient {
	
        // 要求路径必须写完整
	@RequestMapping("/provider/user/listUser")
	public List<User> listUser(); // 和提供方的方法一样
	
}
@RestController
@RequestMapping("/consumer/user")
public class ConsumerUserController {
	
	@Autowired
	private UserClient userClient;
	
	@RequestMapping("/listUser")
	@HystrixCommand(fallbackMethod = "backListUser")
	public List<User> listUser(){
		int a = 1/0;
		return userClient.listUser();
	}
	
	public List<User> backListUser(){
		List<User> list = new ArrayList<>();
		User user = new User();
		user.setName("张三");
		list.add(user);
		return list;
	}
}

9.2 Feign集成Hystrix

# 消费方开启Feign熔断

feign:
  hystrix:
    enabled: true # 开启Feign的熔断功能
// 实现刚才编写的UserClient,作为FallBack的处理类

@Component
public class UserClientFallback implements UserClient{

        /***
         * 服务降级处理方法
         * @param id
         * @return
         */
	@Override
	public List<User> listUser() {
		List<User> list = new ArrayList<>();
		User user = new User();
		user.setName("张三");
		list.add(user);
		return list;
	}
}
@FeignClient(value = "springcloud-provider",fallback = UserClientFallback.class) // 在@FeignClient注解中,指定FallBack处理类。
public interface UserClient {
	
	@RequestMapping("/provider/user/listUser")
	public List<User> listUser();
	
}

9.3 Feign的日志级别配置

通过loggin.level.xx=debug来设置日志级别。然而这个对Feign客户端不会产生效果。
因为@FeignClient注解修饰的客户端在被代理时,都会创建一个新的Feign.Logger实例。我们需要额外通过配置类的方式指定这个日志的级别才可以。

实现步骤:

  1. 在application.yml配置文件中开启日志级别配置
  2. 编写配置类,定义日志级别bean。
  3. 在接口的@FeignClient中指定配置类
  4. 重启项目,测试访问
# 在消费方的配置文件中

# com.lihao 包下的日志级别都为Debug
logging:
  level:
    com.lihao: debug
// 在消费方创建Feign配置类,定义日志级别

@Configuration
public class FeignConfig {

    /***
     * Feign支持4中级别:
     *	  NONE:不记录任何日志,默认值
     *	  BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
     *	  HEADERS:在BASIC基础上,额外记录了请求和响应的头信息
     *	  FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据
     *
     * @return
     */
    @Bean
    public Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }
}
@FeignClient(value = "springcloud-provider",fallback = UserClientFallback.class,configuration = FeignConfig.class) // 指定配置类
public interface UserClient {
	
	@RequestMapping("/provider/user/listUser")
	public List<User> listUser();
	
}

原文地址:https://www.cnblogs.com/itlihao/p/14521694.html