Spring Cloud Alibaba Sentinel 集群流量控制

news2024/11/28 8:22:36

为什么要进行集群流控

假设集群中有 10 台机器,我们给每台机器设置单机限流阈值为 10 QPS,理想情况下整个集群的限流阈值就为 100 QPS。不过实际情况下流量到每台机器可能会不均匀,会导致总量没有到的情况下某些机器就开始限流。因此仅靠单机维度去限制的话会无法精确地限制总体流量。而集群流控可以精确地控制整个集群的调用总量,结合单机限流兜底,可以更好地发挥流量控制的效果。

集群流控中共有两种身份

  • Token Client:集群流控客户端,用于向所属 Token Server 通信请求 token。集群限流服务端会返回给客户端结果,决定是否限流。
  • Token Server:即集群流控服务端,处理来自 Token Client 的请求,根据配置的集群规则判断是否应该发放 token(是否允许通过)。

Token Server 集群限流服务端

两种启动方式

  • 独立模式(Alone),即作为独立的 token server 进程启动,独立部署,隔离性好,但是需要额外的部署操作。独立模式适合作为 Global Rate Limiter 给集群提供流控服务。
    在这里插入图片描述
    在独立模式下,我们可以直接创建对应的 ClusterTokenServer 实例并在 main 函数中通过 start 方法启动 Token Server。

  • 嵌入模式(Embedded),即作为内置的 token server 与服务在同一进程中启动。在此模式下,集群中各个实例都是对等的,token server 和 client 可以随时进行转变,因此无需单独部署,灵活性比较好。但是隔离性不佳,需要限制 token server 的总 QPS,防止影响应用本身。嵌入模式适合某个应用集群内部的流控。
    在这里插入图片描述
    在 embedded 模式下通过API转换集群流控身份:

http://:/setClusterMode?mode=<xxx>

其中 mode 为 0 代表 client,1 代表 server,-1 代表关闭。注意应用端需要引入集群限流客户端或服务端的相应依赖。

独立模式示例

本文只介绍独立模式示例。我们的示例使用SPI方式初始化流控规则等。

  1. 添加 maven 依赖
<!-- Token Server 依赖 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-cluster-server-default</artifactId>
    <version>${sentinel.version}</version>
</dependency>

<!-- 支持Nacos数据源 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <version>${sentinel.version}</version>
</dependency>
  1. 添加SPI配置
    在这里插入图片描述
    com.alibaba.csp.sentinel.init.InitFunc 文件配置如下
com.yyoo.sentinel.server.func.MyClusterServerInitFunc

注:此处配置遵循Java的SPI规则即可,不做过多详解。

  1. MyClusterServerInitFunc 代码
package com.yyoo.sentinel.server.func;

import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterFlowRuleManager;
import com.alibaba.csp.sentinel.cluster.server.config.ClusterServerConfigManager;
import com.alibaba.csp.sentinel.cluster.server.config.ServerTransportConfig;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.init.InitOrder;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.fasterxml.jackson.core.type.TypeReference;

import java.util.List;
import java.util.Properties;
import java.util.Set;

/**
 * 集群流控,服务端  规则 + Namespace + ServerTransportConfig 使用 Nacos 动态推送
 */
@InitOrder(1) // 用于定义执行顺序
public class MyClusterServerInitFunc implements InitFunc {

    /**
     * Nacos 地址
     */
    public static final String NACOS_ADDRS = "localhost:8848";

    /**
     * 对应 Nacos 的命名空间 ID
     *
     *  fd315d16-12ef-4d67-b8e2-8dfe2e6667b5
     *  855e91a2-60e7-48c3-aa3f-27aa2f8a0f73
     */
    public static final String NACOS_SENTINEL_NAMESPACE = "fd315d16-12ef-4d67-b8e2-8dfe2e6667b5";

    /**
     * Nacos group id
     */
    public static final String NACOS_SENTINEL_GROUPID = "Sentinel_Demo_Group";

    /**
     * 集群限流规则 dataID
     * 获取到的值为规则列表,如: List<FlowRule>
     */
    public static final String NACOS_SENTINEL_CLUSTER_RULES_DATAID = "Cluster-Flow-Rule";

    /**
     * 集群流控作用域(默认对应集群应用的 project.name 应用名)
     * 获取到的值为 Set<String> 类型,即为应用名列表
     */
    public static final String NACOS_SENTINEL_NAMESPACES_DATAID = "Cluster-Name-Space";

    /**
     * 集群流控 Server 端配置
     * 获取到的值为 ServerTransportConfig 类型
     */
    public static final String NACOS_SENTINEL_SERVER_TRANSPORT_CONFIG_DATAID = "Cluster-Server-Config";

    @Override
    public void init() throws Exception {

        Properties nacosPro = new Properties();
        nacosPro.put(PropertyKeyConst.SERVER_ADDR,NACOS_ADDRS);
        nacosPro.put(PropertyKeyConst.NAMESPACE,NACOS_SENTINEL_NAMESPACE);
        // 配置 Nacos 动态规则数据源 (此处只定义了限流规则,其他规则如:热点参数规则可按此示例配置即可)
        ClusterFlowRuleManager.setPropertySupplier(namespace -> {
            ReadableDataSource<String, List<FlowRule>> ds = new NacosDataSource<>(nacosPro, NACOS_SENTINEL_GROUPID, NACOS_SENTINEL_CLUSTER_RULES_DATAID,
                    source -> JsonUtil.toGenericBean(source, new TypeReference<List<FlowRule>>(){}));
            return ds.getProperty();
        });

        // 配置从 Nacos 动态获取应用集群作用域NameSpace(即默认为集群的project.name)
        ReadableDataSource<String, Set<String>> nameSpaceDS = new NacosDataSource<>(nacosPro, NACOS_SENTINEL_GROUPID, NACOS_SENTINEL_NAMESPACES_DATAID,
                source -> JsonUtil.toGenericBean(source, new TypeReference<Set<String>>(){}));
        ClusterServerConfigManager.registerNamespaceSetProperty(nameSpaceDS.getProperty());


        // 配置从 Nacos 动态获取 Token Server 的配置
        ReadableDataSource<String, ServerTransportConfig> serverTransportConfigDS = new NacosDataSource<>(nacosPro, NACOS_SENTINEL_GROUPID, NACOS_SENTINEL_SERVER_TRANSPORT_CONFIG_DATAID,
                source -> JsonUtil.toGenericBean(source, new TypeReference<ServerTransportConfig>(){}));
        ClusterServerConfigManager.registerServerTransportProperty(serverTransportConfigDS.getProperty());

    }
}


服务端还可以通过 ClusterServerConfigManager.setMaxAllowedQps(); 设置 token server 最大允许的总 QPS(maxAllowedQps),来对 token server 的资源使用进行限制,防止在嵌入模式下影响应用本身

  1. 服务端启动类
package com.yyoo.sentinel.server;

import com.alibaba.csp.sentinel.cluster.server.ClusterTokenServer;
import com.alibaba.csp.sentinel.cluster.server.SentinelDefaultTokenServer;

public class Main {

    public static void main(String[] args) throws Exception {
        ClusterTokenServer tokenServer = new SentinelDefaultTokenServer();
        tokenServer.start();
    }

}

直接执行main函数启动即可

注:Server启动后,日志可以在~/logs/csp/ 文件夹下查看 sentinel-record.log。如需配置日志路径等,请查阅 Spring Cloud Alibaba Sentinel 控制台 一文中关于客户端配置文件部分。

客户端SPI配置类

package com.yyoo.sentinel.config;

import com.alibaba.csp.sentinel.cluster.ClusterStateManager;
import com.alibaba.csp.sentinel.cluster.client.config.ClusterClientAssignConfig;
import com.alibaba.csp.sentinel.cluster.client.config.ClusterClientConfigManager;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.init.InitOrder;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.fasterxml.jackson.core.type.TypeReference;

import java.util.List;
import java.util.Properties;

/**
 * 集群流控,服务端  规则 + Namespace + ServerTransportConfig 使用 Nacos 动态推送
 */
@InitOrder(1) // 用于定义执行顺序
public class MyClusterServerInitFunc implements InitFunc {

    /**
     * Nacos 地址
     */
    public static final String NACOS_ADDRS = "localhost:8848";

    /**
     * 对应 Nacos 的命名空间 ID
     *
     *  fd315d16-12ef-4d67-b8e2-8dfe2e6667b5
     *  855e91a2-60e7-48c3-aa3f-27aa2f8a0f73
     */
    public static final String NACOS_SENTINEL_NAMESPACE = "fd315d16-12ef-4d67-b8e2-8dfe2e6667b5";

    /**
     * Nacos group id
     */
    public static final String NACOS_SENTINEL_GROUPID = "Sentinel_Demo_Group";

    /**
     * 集群限流规则 dataID
     * 获取到的值为规则列表,如: List<FlowRule>
     *     和 Server 端一致
     */
    public static final String NACOS_SENTINEL_CLUSTER_RULES_DATAID = "Cluster-Flow-Rule";


    /**
     * 集群流控 Client 端配置
     * 获取到的值为 ClusterClientConfig 类型
     */
    public static final String NACOS_SENTINEL_CLIENT_TRANSPORT_CONFIG_DATAID = "Cluster-Client-Config";

    @Override
    public void init() throws Exception {
        // Nacos 配置
        Properties nacosPro = new Properties();
        nacosPro.put(PropertyKeyConst.SERVER_ADDR,NACOS_ADDRS);
        nacosPro.put(PropertyKeyConst.NAMESPACE,NACOS_SENTINEL_NAMESPACE);

        // 集群客户端获取限流规则,此处和非集群模式一样
        ReadableDataSource<String, List<FlowRule>> ds = new NacosDataSource<>(nacosPro, NACOS_SENTINEL_GROUPID, NACOS_SENTINEL_CLUSTER_RULES_DATAID,
                source -> JsonUtil.toGenericBean(source, new TypeReference<List<FlowRule>>(){}));
        FlowRuleManager.register2Property(ds.getProperty());

        // 获取集群客户端配置(客户端还有一个 ClusterClientConfig 配置需要请自行配置)
        /**
         * serverHost: token server host
         * serverPort: token server 端口
         * requestTimeout: 请求的超时时间(默认为 20 ms)
         */
        ReadableDataSource<String, ClusterClientAssignConfig> clientConfigDs = new NacosDataSource<>(nacosPro, NACOS_SENTINEL_GROUPID, NACOS_SENTINEL_CLIENT_TRANSPORT_CONFIG_DATAID,
                source -> JsonUtil.toGenericBean(source, new TypeReference<ClusterClientAssignConfig>(){}));
        ClusterClientConfigManager.registerServerAssignProperty(clientConfigDs.getProperty());

        // 设置当前应用为 Token Client。
        /**
         * 此处推荐使用 API http://<ip>:<port>/setClusterMode?mode=<xxx> 进行设置
         * 我们采用独立的 Token Server 模式,所以此处初始化直接写死的。
         * 0:表示 Token Client
         * 1:表示 Token Server
         * -:表示未设置,默认 -1
         */
        ClusterStateManager.applyState(0);
    }
}

客户端如果使用了Spring Cloud Alibaba ,可以使用 application.yml 配置动态数据源的

spring:
  application:
    name: mySentinelDemo # 此为客户端应用名(注意同集群流控的namespace 作用域相对应)
  cloud:
    sentinel:
      enabled: true 
      datasource: # 如果使用了 InitFunc 此可以不用配置
        myFlowRules:
          server-addr: ${my.nacos.server-addr}
          namespace: ${my.nacos.sentinel-namespace}
          group-id: Sentinel_Demo_Group
          data-id: Cluster-Flow-Rule
          data-type: json
          rule-type: flow

关于使用 application.yml 配置动态数据源请查阅我们 Spring Cloud Alibaba Sentinel 动态规则扩展 一章

我们此处还是使用的 SPI InitFunc 方式,因为使用 application.yml 配置方式只能配置动态规则,我们此处的其他配置还是得使用 InitFunc 的方式。

集群限流配置规则

FlowRule

集群流控的配置依然使用FlowRule

private boolean clusterMode; // 标识是否为集群限流配置
private ClusterFlowConfig clusterConfig; // 集群限流相关配置项
private double count; // 限流的阀值(注意:根据均摊模式或全局模式的不同,阀值表示的意义也不一样)
private String resource; // 资源名称(Spring Boot / Spring Cloud alibaba 下会自动定义资源,资源名称根据url生成,可通过控制台查看自动定义的资源)

以上 clusterMode、count、resource为必须配置的字段,否则集群流控规则不会生效

在集群Token Client 无法与 Token Server 正常通信时,如果设置了可以降级为本地流控,那么FlowRule的其他参数也可以进行相应配置,请参考我们 Spring Cloud Alibaba Sentinel 流量控制 一章

集群流控规则配置类 ClusterFlowConfig 字段说明


	/**
	 * 代表全局唯一的规则 ID,Sentinel 集群限流服务端通过此 ID 来区分各个规则,因此务必保持全局唯一。
     * 一般 flowId 由统一的管控端进行分配,或写入至 DB 时生成。
     * 此字段必须
	 */
	private Long flowId;

    /**
     * 0:单机均摊模式:配置的阈值等同于单机能够承受的限额. 
     * 		比如:集群应用名称为myCloud,有3个应用,单机均摊阀值为10,那么集群的阀值为30
     * 1:全局模式:配置的阈值等同于整个集群的总阈值
     *  默认 0
     */
    private int thresholdType = ClusterRuleConstant.FLOW_THRESHOLD_AVG_LOCAL;
    /**
     * 在 client 连接失败或通信失败时,是否退化到本地的限流模式
     * 默认为 true
     */
    private boolean fallbackToLocalWhenFail = true;

    /**
     * 0: normal.
     */
    private int strategy = ClusterRuleConstant.FLOW_CLUSTER_STRATEGY_NORMAL;

    private int sampleCount = ClusterRuleConstant.DEFAULT_CLUSTER_SAMPLE_COUNT;
    /**
     * 统计滑动窗口的时间间隔长度(毫秒)
     *  默认:1000ms
     */
    private int windowIntervalMs = RuleConstant.DEFAULT_WINDOW_INTERVAL_MS;

    /**
     * 如果客户端保留令牌的时间超过resourceTimeout,则resourceTimeoutStrategy将起作用。
     */
    private long resourceTimeout = 2000;

    /**
     * 0:忽略
     * 1:释放token
     */
    private int resourceTimeoutStrategy = RuleConstant.DEFAULT_RESOURCE_TIMEOUT_STRATEGY;

    /**
	 * 如果请求(prioritized=true,优先级为true)被阻止,则acquireReuseStrategy将起作用。。
	 * 0:忽略并阻止。
	 * 1:再试一次。
	 * 2:努力直到成功。
     */
    private int acquireRefuseStrategy = RuleConstant.DEFAULT_BLOCK_STRATEGY;

    /**
     * 如果客户端脱机,服务器将删除客户端在clientOfflineTime之后持有的所有令牌。
     */
    private long clientOfflineTime = 2000;

Nacos 中的规则配置、namespace 规则作用域配置、Server和Client端的基础配置如下

注:以下配置都是根据我们的示例设置的 Nacos 的 namespace 、groupId、dataId

以上的配置总览如下

在这里插入图片描述

集群流控规则

在这里插入图片描述

[
    {
        "resource": "/test/flow1", 
        "limitApp": "default", 
        "grade": 1, 
        "count": 0, 
        "strategy": 0, 
        "refResource": null, 
        "controlBehavior": 0, 
        "warmUpPeriodSec": 10, 
        "maxQueueingTimeMs": 500, 
        "clusterMode": true, 
        "clusterConfig": {
            "flowId": 1, 
            "thresholdType": 0, 
            "fallbackToLocalWhenFail": true, 
            "strategy": 0, 
            "sampleCount": 10, 
            "windowIntervalMs": 1000, 
            "resourceTimeout": 2000, 
            "resourceTimeoutStrategy": 0, 
            "acquireRefuseStrategy": 0, 
            "clientOfflineTime": 2000
        }
    }
]

注意:此处我们设置的 count 为 0 。这是为了方便首次验证

集群流控作用域 namespace

在这里插入图片描述

Token Server 配置

在这里插入图片描述

Token Client 配置

在这里插入图片描述

示例验证

在客户端编写Controller url 为 /test/flow1 ,并访问即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/402339.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

因特网基础

1、因特网的概述 1-1、网络、互联网和因特网 网络&#xff08;Network&#xff09;是由若干节点&#xff08;Node&#xff09;和连接这些节点的链路&#xff08;Link&#xff09;组成。 多个网络还可以通过路由器相互连起来&#xff0c;这样就构成了一个覆盖范围更大的网络&…

【刷题笔记】--双指针--189. 轮转数组

题目&#xff1a; 思路1&#xff1a; 再设一个数组&#xff0c;通过下标的规律&#xff0c;进行更新数组。 关于这个平移的下标规律&#xff1a;%numbersize&#xff1b; 假设数组1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6&#xff0c;7 要整体…

MTK平台 Wireless Authentication Denied问题

这个问题一开始的现象是部分station无法连接某台AP。无线抓包后发现station和AP间进行了频繁的Auth认证,即station发送Auth包,ap回复Auth包出现 Expert: Wireless Authentication Denied (13: Requested authentication algorithm not supported)这样错误提示…

Lesson 9.2 随机森林回归器的参数

文章目录一、弱分类器的结构1. 分枝标准与特征重要性2. 调节树结构来控制过拟合二、弱分类器的数量三、弱分类器训练的数据1. 样本的随机抽样2. 特征的随机抽样3. 随机抽样的模式四、弱分类器的其他参数在开始学习之前&#xff0c;先导入我们需要的库。 import numpy as np im…

【项目精选】俄罗斯方块项目(视频+论文+源码)

点击下载源码 俄罗斯方块项目&#xff0c;基本功能包括&#xff1a;游戏主界面显示模块、方块及数据显示模块、方块移动控制模块、游戏界面颜色控制模块、游戏进度、等级控制模块等。本项目结构如下&#xff1a; &#xff08;1&#xff09;游戏主界面显示模块&#xff1a; 显示…

【密码学篇】密码行业标准汇总(GM)

【密码学篇】密码行业标准汇总&#xff08;GM&#xff09; 截止到2023年03月10日&#xff0c;共130个密码行业标准&#xff0c;适用商用密码应用与安全性评估等密码行业&#xff0c;可点击链接预览或下载标准—【蘇小沐】 文章目录【密码学篇】密码行业标准汇总&#xff08;GM…

【洛谷 P1044】[NOIP2003 普及组] 栈 题解(递归+记忆化搜索)

[NOIP2003 普及组] 栈 题目背景 栈是计算机中经典的数据结构&#xff0c;简单的说&#xff0c;栈就是限制在一端进行插入删除操作的线性表。 栈有两种最重要的操作&#xff0c;即 pop&#xff08;从栈顶弹出一个元素&#xff09;和 push&#xff08;将一个元素进栈&#xff…

常见数量关系分析

考点一相遇追及问题&#xff08;一&#xff09;直线型1. 单次相遇&#xff1a;相距两地&#xff0c;同时出发&#xff0c;相向而行。2. 单次追及&#xff1a;同时出发&#xff0c;同向而行。3. 直线型相遇追及问题公式总结&#xff08;二&#xff09;环线型环线型相遇追及问题公…

弹性存储-块存储和文件存储部分

存储通用知识 存储架构发展历程&#xff1a;直连存储-》存储网络-〉分布式存储/云存储 块存储、文件存储及对象存储使用场景 块存储、文件存储及对象存储性能对比 块存储及文件存储-块存储介绍 块存储EBS&#xff08;Elastic Block Storage&#xff09;是为了云服务器提…

CleanMyMac4.20新版本核心功能介绍

CleanMyMac4.20是Mac清理工具&#xff0c;具有很多功能。如‬删除大量不可见的缓存文件&#xff0c;可以批量删除未使用的DMG、不完整的下载以及其余的旧包。 与 CleanMyMac 3相比&#xff0c;新版本 UI设计焕然一新&#xff0c;采用了完全不同的风格。 CleanMyMac X4.20全新版…

在ubuntu上搭建SSH和FTP和NFS和TFTP

一、SSH服务搭建使用如下命令安装 SSH 服务&#xff1b;ssh 的配置文件为/etc/ssh/sshd_config&#xff0c;使用默认配置即可。sudo apt-get install openssh-server开启 SSH 服务以后我们就可以在 Windwos 下使用终端软件登陆到 Ubuntu&#xff0c;比如使用 Mobaxterm。二、FT…

六零导航页(LyLme Spage)导航网站源码

六零导航页 (LyLme Spage)前端基于D.Young的 5IUX搜索 &#xff0c;后台使用笔下光年的Light Year Admin模板开发&#xff0c;包含多种搜索引擎&#xff0c;致力于简洁高效无广告的上网导航和搜索入口&#xff0c;沉淀最具价值链接&#xff0c;全站无商业推广&#xff0c;简约而…

滤波算法 | 无迹卡尔曼滤波(UKF)算法及其Python实现

文章目录简介UKF滤波1. 概述和流程2. Python代码第一个版本a. KF滤波b. UKF滤波第一个版本简介 上一篇文章&#xff0c;我们介绍了UKF滤波公式及其MATLAB代码。在做视觉测量的过程中&#xff0c;基于OpenCV的开发包比较多&#xff0c;因此我们将UKF的MATLAB代码转到python中&a…

运维视角:rabbitmq教程(四)工作模式

今天这篇文章&#xff0c;通过python代码来测试rabbitmq交换机以及队列的工作模式&#xff0c;以此更加透彻的理解它的工作方式 一、简单模式 1、测试代码 生产者代码&#xff1a; import pikauser_info pika.PlainCredentials(admin, admin) connection pika.BlockingCon…

ICG-Hydrazide,吲哚菁绿-酰肼,ICG-HZ结构式,溶于二氯甲烷等部分有机溶剂,

ICG-Hydrazide,吲哚菁绿-酰肼 中文名称&#xff1a;吲哚菁绿-酰肼 英文名称&#xff1a;ICG-Hydrazide 英文别名&#xff1a;ICG-HZ 性状&#xff1a;粉末或固体 溶剂&#xff1a;溶于二氯甲烷等部分有机溶剂 稳定性&#xff1a;-20℃密封保存、置阴凉干燥处、防潮 分子…

vue上实现左右关联滚动

先看效果&#xff1a; 代码&#xff1a; <template><div class"container"><!-- 左侧fixed导航区域 --><div class"left"><divv-for"item in leftList":key"item.id"class"left_item":class&…

Angular学习之ControlValueAccessor接口详解

ControlValueAccessor 是什么&#xff1f;为什么需要使用 &#xff1f;下面本篇文章就来带大家了解Angular中的ControlValueAccessor组件接口&#xff0c;希望对大家有所帮助&#xff01; ControlValueAccessor 是什么&#xff1f; 简单来说ControlValueAccessor是一个接口&am…

【Linux 网络编程2】应用层协议--http;序列化和反序列化,get和post请求传参的区别,cookie和sesion,编写一个简单的http

目录 1.序列化和反序列化 2.HTTP协议 3.编写一个简单的http 3.2.简单的http的使用 3.3.get和post请求传参的区别 4.http的状态码分类 5.cookie和sesion 1.序列化和反序列化 1.1.序列化和反序列化的优势 序列化将结构体转化为长字符串&#xff0c;便于传输&#xff1b;反序…

MyBatis源码用了哪些设计模式?

MyBatis源码用了哪些设计模式&#xff1f;前言一、创建型模式工厂模式单例模式建造者模式二、结构型模式适配器模式代理模式组合模式装饰器模式三、行为型模式模板模式策略模式迭代器模式总结前言 在 MyBatis 的两万多行的框架源码中&#xff0c;使用了大量的设计模式对工程架…

Oracle OCP 19c 考试(1Z0-083)中关于Oracle不完全恢复的考点(文末附录像)

欢迎试看博主的专著《MySQL 8.0运维与优化》 下面是Oracle 19c OCP考试&#xff08;1Z0-083&#xff09;中关于Oracle不完全恢复的题目: A database is configured in ARCHIVELOG mode A full RMAN backup exists but no control file backup to trace has been taken A media…