SpringCloud

总结

  1. 1个中心: eureka 注册中心
  2. 2个基本点: Ribbon,Hystrix
  3. 3个工具: Feign 集成,Zuul 网关,Config 配置中心
  4. 4个监控: Hystrix Dashboard,turbine,sleuth,zipkin

什么是Spring Cloud?

  1. SpringCloud是基于SpringBoot的一整套实现微服务的框架。它提供了微服务开发所需的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等组件。最重要的是,基于SpringBoot,会让开发微服务架构非常方便。
  2. Spring cloud是一个工具集,集成多个工具集,来解决微服务中的各种问题
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

eureka注册表(zookeper,eureka,nacos、consul、etcd)

所有微服务都需要注册到注册中心,通过注册表互相发现,服务之间调用

  1. 注册: 服务提供者启动时,向 eureka 一次次反复注册,直到注册成功为止
  2. 拉取注册表: 服务发现者 每30秒拉取一次注册表(刷新注册表)
  3. 心跳: 每30秒发送一次心跳数据,eureka 连续 3次收不到 一个服务的心跳,会删除这个服务
  4. 自我保护模式: 一般由于网络不稳定或中断,15分钟内,85%以上服务器出现心跳异常,则会自动进入保护模式,在保护模式,所有服务都 不删除,网络恢复后,可以自动退出保护模式,恢复正常。(zookeper 没有保护模式,3次心跳后会自动删除服务)

SpringCloud技术组成

eureka: 微服务治理,服务注册和发现
ribbon: 负载均衡,请求重试
hystrix: 断路器,服务降级、熔断
feign: ribbon + hystrix 集成,并提供声明式客户端
zuul: API 网关,提供微服务的统一入口,并提供统一的权限验证
config: 配置中心
bus: 消息总线,配置刷新
sleuth+zipkin: 链路跟踪
hystrix dashboard 和 turbine: hystrix 数据监控

eureka搭建

  1. 启动类注解: @EnableEurekaServer
  2. application.yml中做好配置
  3. 引入依赖(eureka)

eureka和zookeeper区别

eureka: 强调AP(可用性),集群结构:对等结构,互相注册,互相拉取
zookeeper: 强调CP(一致性),集群结构:主从结构

远程调用(RestTemplate)

说明:SpringBoot 提供的
类似于HttpClient,可以发送 http 请求,并处理响应。RestTemplate 简化了 RestAPI 调用,只需要使用它的一个方法,就可以完成请求,响应,json 转换
方法:
getForObject(url,转换类型.class,提交的参数)
postForObject(url,协议体数据,转换的类型.class)

RestTemplate和Dubbo远程调用的区别

RestTemplate:Rest API ,http 调用,效率低,是一整套的,解决了熔断,配置等
Dubbo:RPC调用,java的序列化,效率高,但只是一个远程调用

Ribbon

在这里插入图片描述

Ribbon负载均衡

作用: 负载均衡,请求重试
Ribbo 对 RestTemplate 做了封装,增强了RestTemPlate的功能。利用AOP进行的增强

  1. 获得地址
  2. 轮询一个服务的主机地址列表
  3. RestTemPlate负载执行最终调用

Ribbon重试

说明:一种容错机制,当调用远程服务失败,可以自动重试调用

  • 添加重试依赖
  • 配置重试参数(yml中配置):
    MaxAutoRetries–单台服务器的重试次数
    MaxAutoRetriesNextServer:更换服务器的次数
  • 配置连接超时(java代码证设置):
    ConnectTimeout:与远程服务建立网络连接的超时时间
    ReadTimeout:连接已建立,请求已发送,等待响应的超时时间

Hystrix(断容器)

系统容错工具
比如 A 服务调用远程 B 服务

  • 降级: 调用远程服务失败(宕机,500,超时),可以降级执行当前服务中心的一段代码,向客户端返回结果(B 服务可以根据业务需求来返回)
  • 熔断: 当访问量过大,出现大量的失败,可以做过热保护,A 与 B 断开远程服务,不再调用,通过 降级 向客户端返回结果
    作用: 出现缓存穿透进行限流,防止故障传播,雪崩效应

Hystrix降级搭建

说明:hystrix 默认降级超时时间是 1 秒,可以自行配置,超时要大于 ribbon总的重试时间,否则 ribbon 重试可能无效。

  1. hystrix 添加依赖
  2. 启动类添加注解**@EnableCircuitBreaker** 启动 hystrix
  3. 在方法上添加降级代码:
//当调用远程服务失败,跳转到指定的方法执行降级代码
    @HystrixCommand(fallbackMethod = "getItemsFB") //"getItemsFB"方法名,可以自定义,再写该方法执行的结果代码

Hystrix熔断(降级配置默认有熔断)

断路器打开的条件:条件都是可以配置的

  • 10秒内20次请求(必须首先满足),并且 50%失败

断路器打开后,所有请求直接执行降级代码,断路器打开后几秒,会进入半开状态,客户端调用会尝试向后台服务发送一次调用,如果调用失败,断路器可以自动关闭,恢复正常,如果任然失败,继续保持打开状态几秒…

Hystrix故障监控

Hystrix 利用 Actuator工具,来暴露 Hystrix 的故障日志

Actuator

springboot 提供的日志监控工具,可以暴露项目中多种监控信息

  1. 健康状态
  2. 系统环境变量
  3. spring容器中所有的对象
  4. spring mvc映射的所有路径

Actuator配置

  1. 添加依赖
  2. yml配置暴露监控数据
# 配置暴露监控数据
management:		# m.e.w.e.i=health    只暴露健康状态
  endpoints:	# m.e.w.e.i=["health", "beans", "mappings"]  暴露指定的多个监控
    web:		# m.e.w.e.i="*"		暴露所有的监控
      exposure:
        include: "*"

Hystrix Dashboard(监控)

仪表盘项目是一个完全独立的项目,与其他项目都无关,也不用向注册表注册

  1. 添加hystrix dashboard 依赖
  2. 在启动类上添加 @EnableHystrixDashboard
  3. yml-允许对哪台服务器开启监控

Feign(Hystrix,远程调用(RestTemplate),Ribbon,)

Feign远程调用,核心就是通过一系列的封装和处理,将以JAVA注解的方式定义的远程调用API接口,最终转换成HTTP的请求形式,然后将HTTP的请求的响应结果,解码成JAVA Bean,放回给调用者。
在这里插入图片描述
在这里插入图片描述

集成工具

  • 声明式客户端:只需要声明一个抽象接口,就可以通过接口做远程调用,不需要再使用 RestTemplate 来调用,默认不启用 Hystrix,推荐不使用,需要自己配置
// 调用远程的商品服务,获取订单的商品列表
// 通过注解,配置:
// 1. 调用哪个服务
// 2. 调用服务的哪个路径
// 3. 向路径提交什么参数数据
@FeignClient(name="item-service")
public interface ItemClient {
    @GetMapping("/{orderId}")
    JsonResult<List<Item>> getItems(@PathVariable String orderId);
}
  • Hystrix 降级和熔断
  • ribbon 负载均衡和重试
#调整 ribbo的重试参数,针对所有服务的通用配置
# Feign 集成了ribbon,重试默认配置如下
ribbon:
  MaxAutoRetries: 0
  MaxAutoRetriesNexServer: 1

RabbitMQ消息服务器(rabbitmq,activemq,rocketmq,tubemq)

在这里插入图片描述

RabbitMQ概念

RabbitMQ是一种消息中间件,用于处理来自客户端的异步消息。服务端将要发送的消息放入到队列池中。接收端可以根据RabbitMQ配置的转发机制接收服务端发来的消息。RabbitMQ依据指定的转发规则进行消息的转发、缓冲和持久化操作,主要用在多服务器间或单服务器的子系统间进行通信,是分布式系统标准的配置

RabbitMQ角色

**生产者(provider):**消息的创建者,负责创建和推送数据到消息服务
**消费者(consumer):**消息的接收方,用于处理数据和确认消息
**代理:**就是 RabbitMQ 本身,用于扮演快递角色,本身不产生消息

rabbitmq有哪些组件以及发送流程?

  1. ConnectionFactory(连接管理器):应用程序与RabbitMQ之间建立连接的管理器
  2. Channel(信道):消息推送使用的通道
  3. Exchange(交换器):用于接收、分配消息
  4. Queue(队列):用于存储生产者的消息
  5. RoutingKey(路由键):用于把生产者的数据分配到交换器上
  6. BindKey(绑定键):用于把交换器的消息绑定到队列上
  • 生产者把生产的小心通过channel发送到Exchange上,Exchange通过绑定的router
    key来选择Queue,消费者监听到Queue上有新的消息,就消费调此消息;

RabbitMQ六种工作模式

简单模式(direct),工作模式(direct),发布和订阅模式(Fanout),路由模式(driect),主题模式(topic),RPC模式

  1. 简单模式(默认direct交换机):
    生产者代码:
public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //建立连接
        ConnectionFactory f=new ConnectionFactory();
        f.setHost("192.168.64.140");
        f.setPort(5672);    //默认端口可以省略
        f.setUsername("admin");
        f.setPassword("admin");
        Connection conn=f.newConnection();
        Channel c=conn.createChannel(); //创建通信通道
        //定义队列让服务器创建队列 helloworld
        //队列的参数:helloworld,是否是持久队列,是否排他(独占)队列,是否自动删除
        c.queueDeclare(
                "helloworld",   //队列名字
                false,          //是否持久数据
                false,          //可以共享的队列
                false,          //不自动删除
                null);
        //消息发送到 helloworld队列
        //1.默认的交换机(讲第三个模式时再解释)
        //3.其他的消息属性配置,如果没有给null值
        c.basicPublish("",
                "helloworld",
                null,
                "Hello world!".getBytes());
        System.out.println("消息已经发送");
    }
}

消费者代码:

public class Consumer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //连接
        ConnectionFactory f=new ConnectionFactory();
        f.setHost("192.168.64.140");
        f.setUsername("admin");
        f.setPassword("admin");
        Channel channel=f.newConnection().createChannel();
        //创建 helloworld队列(队列如果已经存在,不会重复创建)
        channel.queueDeclare("helloworld", false,false,false,null);

        DeliverCallback deliverCallback=new DeliverCallback() {
            @Override
            public void handle(String consumerTag, Delivery message) throws IOException {
                byte[] a= message.getBody();    //取出消息
                String msg=new String(a);
                System.out.println("收到:"+msg);
            }
        };
        CancelCallback cancelCallback=new CancelCallback() {
            @Override
            public void handle(String consumerTag) throws IOException {

            }
        };
        //消费数据,等待从队列接收数据
        //第二个参数:由服务器对消息进行自动确认
        channel.basicConsume("helloworld", true,deliverCallback,cancelCallback);
    }
}
  1. 工作模式(默认direct交换机):
    生产者代码:
public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {

        //连接
        ConnectionFactory c=new ConnectionFactory();
        c.setHost("192.168.64.140");
        c.setPort(5672);
        c.setUsername("admin");
        c.setPassword("admin");
        Channel conn=c.newConnection().createChannel();
        //定义队列
        //定义队列让服务器创建队列 helloworld
        //队列的参数:helloworld,是否是持久队列,是否排他(独占)队列,是否自动删除
        conn.queueDeclare(
                "task_queue",
                true,  //数据是否持久化
                false,
                false,
                null);
        //发送消息
        //循环输入消息发送
        //输入消息:ger.err.e....er....er
        //消费者收到消息后,遍历
        while (true){
            System.out.println("输入消息:");
            String msg=new Scanner(System.in).nextLine();
            conn.basicPublish("",
                    "task_queue",
                     MessageProperties.PERSISTENT_TEXT_PLAIN,
                    msg.getBytes());
        }
    }
}

消费者代码:

public class Consumer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //连接服务器
        ConnectionFactory c=new ConnectionFactory();
        c.setHost("192.168.64.140");
        c.setPort(5672);
        c.setUsername("admin");
        c.setPassword("admin");
        Channel conn=c.newConnection().createChannel();
        //定义队列
        conn.queueDeclare("task_queue",
                true,   //是否持久数据
                false,  //可以共享的队列
                false,  //不自动删除
                null);
        //消费数据
        DeliverCallback deliverCallback= new DeliverCallback() {
            @Override
            public void handle(String consumerTag, Delivery message) throws IOException {
                //遍历消息字符串,每个点字符都暂停1秒
                String msg=new String(message.getBody());
                System.out.println("收到:"+msg);
                for (int i=0;i<msg.length();i++){
                    if ('.'== msg.charAt(i)){
                        try {
                            Thread.sleep(1000);
                        }catch (InterruptedException e){

                        }
                    }
                }
                //向服务器发送消息的回执
                //conn.basicAck(回执(long类型的编码),是否一次确认多条消息);
                conn.basicAck(message.getEnvelope().getDeliveryTag(),false);    //false只确认一条消息
                System.out.println("消息处理结果");
            }
        };
        CancelCallback cancelCallback=new CancelCallback() {
            @Override
            public void handle(String s) throws IOException {

            }
        };
        //必须在手动ACK模式下才有效
        conn.basicQos(1);   //合理的分发消息
        //其中 false 是手动确认,有回值,消息才会从缓存删除
        conn.basicConsume("task_queue",false, deliverCallback, cancelCallback);
    }
}
  1. Fanout( 发布和订阅模式):
  2. Direct(路由模式):
  3. Topic(主题模式):
    生产者代码:
public class producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //连接
        ConnectionFactory c=new ConnectionFactory();
        c.setHost("192.168.64.140");
        c.setPort(5672);
        c.setUsername("admin");
        c.setPassword("admin");
        Channel channel=c.newConnection().createChannel();
        //定义交换机
        channel.exchangeDeclare("topic_logs", BuiltinExchangeType.TOPIC);
        //发送消息,需要携带路由键(关键字)
        while (true){
            System.out.println("输入消息:");
            String msg=new Scanner(System.in).nextLine();
            System.out.println("输入路由键:");
            String key=new Scanner(System.in).nextLine();
            //第二个参数是路由键
            channel.basicPublish(
                    "topic_logs",  //交换机名字
                            key,       //定义路由键关键字
                    null,
                    msg.getBytes());    //需要将发送的消息转换为 Bytes数组
        }
    }
}

消费者代码:

public class Consumer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //连接
        ConnectionFactory c=new ConnectionFactory();
        c.setHost("192.168.64.140");
        c.setPort(5672);
        c.setUsername("admin");
        c.setPassword("admin");
        Channel channel=c.newConnection().createChannel();
        //定义随机队列 ,定义交换机,绑定关键词
        String  queue=channel.queueDeclare().getQueue();   //得到队列名字
        channel.exchangeDeclare("topic_logs", BuiltinExchangeType.TOPIC); //交换机类型
        System.out.println("输入绑定键,用空格隔开");
        //绑定关键字
        String s=new Scanner(System.in).nextLine();
        String[] a= s.split("\\s+");
        for (String key:a){
            channel.queueBind(queue, "topic_logs", key);
        }
        //正常的从队列当中消费数据
        DeliverCallback deliverCallback=new DeliverCallback() {
            @Override
            public void handle(String consumerTag, Delivery message) throws IOException {
                //取出消息数据
                String msg=new String(message.getBody());
                String Key=message.getEnvelope().getRoutingKey();
                System.out.println("收到:"+Key+"-"+msg);
            }
        };
        CancelCallback cancelCallback=new CancelCallback() {
            @Override
            public void handle(String consumerTag) throws IOException {

            }
        };
        //其中 true 是自动确认,有回值,消息才会从缓存删除
        channel.basicConsume(queue, true,deliverCallback,cancelCallback);
    }
}
  1. RPC 异步调用模式:

RabbitMQ怎么保证消息的稳定性

  1. 消息持久化: 持久化必须满足三个条件:Exchange(互换) 设置持久化,Queue(队列)() 设置持久化,Message(信息)持久化发送
  2. **ACK确认机制:**就是消费端消费完成要通知服务端,服务端才把消息从内存删除,一个消费者出了问题,没有同步消息给服务端,还有其他的消费端去消费,保证了消息不丢的case
  3. 设置集群镜像
  4. 消息补偿机制

RabbitMQ 服务解耦

RabbitMQ 来解决服务器之间的解耦的情况,中转,传递消息,A服务只需要向消息服务器发送消息,而不用考虑谁需要这些数据;下游服务如果需要数据,自行从消息服务器订阅消息,不再需要数据时则取消订阅即可
在这里插入图片描述

RabbitMQ 流量峰值

流量峰值: 某一时刻的请求达到高峰
可以使用 RabbitMQ来进行流量削峰,高峰情况下,瞬间出现的大量请求数据,先发送到消息队列服务器排队等待被处理,而我们的应用,可以慢慢的从消息队列接收请求数据进行处理,这样把数据处理时间拉长,以减轻瞬时压力

RabbitMQ 异步调用

RabbitMQ消息队列,订单数据可以发送到消息队列服务器,那么调用链路也就可以到此结束,订单系统则可以立即得到响应,整条链路的响应时间只有200毫秒左右。
在这里插入图片描述

RabbitMQ使用场景

  1. 单发送单接收: 简单的发送与接收,没有特别的处理
  2. 单发送多接收:
    在这里插入图片描述
  3. Publish / Subscribe: 发布、订阅模式,发送端发送广播消息,多个接收端接收
  4. Routing (按路线发送接收)
    在这里插入图片描述

RabbitMQ安装启动命令

说明:RabbitMQ 默认端口为 5672,服务器访问端口为 15672(http://192.168.64.140:15672)

  1. systemctl enable rabbitmq-server: 设置服务,开机自动启动
  2. systemctl start rabbitmq-server: 启动服务
  3. rabbitmq-plugins enable rabbitmq_management: 开启管理界面插件
  4. firewall-cmd --zone=public --add-port=15672/tcp --permanent
    firewall-cmd --reload:
    防火墙打开15672,管理端口
  5. systemctl restart rabbitmq-server: 重启 RabbitMQ
  6. rabbitmqctl add_user admin admin: 添加用户
  7. rabbitmqctl set_user_tags admin administrator: 新用户设置用户为超级管理员
  8. *rpm -ivh .rpm: 切换到 rabbimq 目录进行安装

RabbitMQ消息持久化

防止服务器崩溃,重启造成消息丢失,需要把消息保存到磁盘当中

队列持久化

xxx.queueDeclare

消息持久化

拼多多商城整合RabbitMQ

  1. pom.xml添加依赖
  2. 在启动类上添加 Bean 实例
	@Bean
	public Queue getQueue() {
		Queue q = new Queue("orderQueue", true);
		return q;
	}

Zuul(API网关,Hystrix,Ribbon)

  1. 微服务系统统一的调用入口
  2. 集成了 Ribbon,Hystrix
  3. 统一的权限校验

配置

  1. zuul依赖,eureka client依赖
  2. yml
  3. 启动类注解 @EnableZuulProxy

统一权限校验

通过 zuul 过滤器,可以判断用户是否有权限访问后台服务,如果没有权限可以阻止用户继续访问

添加过滤器

  1. 继承 ZuulProxy
  2. 添加 @Component

Zuul集成Ribbo

默认启动 负载均衡,默认不启动 重试

Zuul集成Hystrix(降级,熔断)

  1. 默认有Hystrix,不需要配置,
  2. 添加降级代码:实现 FallbackProvider接口,在子类中实现降级代码,还需要添加 @Component

Zuul 和 Feign的区别

  1. 都集成了 Hystrix,ribbon,都可以调用后台服务,Zuul 是一个独立的服务,不涉及到业务
  2. Zuul 部署在所有微服务项目之前,Feign 部署在微服务内部,服务和服务之间调用
  3. Feign 不推荐使用 Hystrix(一般在微服务前面进行降级和熔断,容易造成混乱),Zuul不推荐使用重试(会造成后台服务的压力,尽量不部署在最前面,越往后越好),实际开发中 Hystrix 一般写在 Zuul当中。

Config(配置中心)

将所有的配置文件(yml)都放在本地仓库(Gitee)
配置:

  1. 添加依赖 Config Server
  2. @EnableConfigServer

配置中心客户端

  1. 添加 config client依赖
  2. 新建配置文件:bootstrap.yml,添加配置

链路跟踪

spring cloud sleuth 可以跟踪调用链路,分析链路中每个节点的执行情况,一条调用链路中可能调用多个微服务,任何一个微服务不可用都可能造整个调用过程失败,

sleuth,Zipkin

生成链路监控日志,通过 RabbitMQ(解耦) 消息中间介发送给 Zipkin 进行图标模式
生成链路跟踪日志工具,例如:A–>B–>C–>D服务都会产生一个随机的服务 ID

Docker

镜像

镜像命令

docker run: 启动容器
docker images: 查看镜像列表
docker rmi xxx: 删除镜像,可以空格隔开一次性删除多个,也可以通过镜像的 id值删除
docker rmi -f xxx: 存在容器,不能直接删除,可以加 -f 强制删除
docker pull xxx: 下载镜像(后面加镜像名标签

容器

容器命令

docker history xxx: 查看镜像中设置的默认应用
docker ps -a: 查看所有容器,包括已关闭的容器
docker ps: 查看正在运行的容器
docker stop xxx: 停止,也可以是 ID
docker start xxx: 重启容器
docker rm xxx: 删除容器
docker rm -f xxx: 强制删除正在运行的容器
docker container prune: 清理所有已经退出的容器
docker run -d --name xxx tomcat: -d 是后台运行,不占用控制台,–name 是给容器命名
docker logs xxx: 查看容器日志
docker run -it --rm tomcat top: 退出后,容器自动关闭,自动删除
docker exec -it xxx pwd: 进入容器,在容器内执行命令

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值