DRDS分布式SQL引擎—执行计划介绍

摘要: 本文着重介绍 DRDS 执行计划中各个操作符的含义,以便用户通过查询计划了解 SQL 执行流程,从而有针对性的调优 SQL。

DRDS分布式SQL引擎 — 执行计划介绍

前言

数据库系统中,执行计划是对 SQL 如何执行的形式化表示,往往由若干关系操作符构成,用户可以通过对应的 EXPLAIN 命令查看,并通过执行计划大致了解 SQL 的执行过程和执行方式,如全表扫描还是索引扫描,归并连接还是哈希连接等。执行计划可以为用户进行 SQL 调优提供重要依据。

DRDS 执行计划

与多数数据库系统类似,DRDS 在处理 SQL 时,会通过优化器生成执行计划,该执行计划由关系操作符构成一个树形结构,反映 DRDS 如何执行 SQL 语句;不同的是,DRDS 本身不存储数据,更侧重考虑分布式环境中的网络 IO 开销,将运算下推到各个分库(如 RDS/MySQL)执行,从而提升 SQL 执行效率。用户可通过 EXPLAIN 命令查看 SQL 的执行计划。

本文着重介绍 DRDS 执行计划中各个操作符的含义,以便用户通过查询计划了解 SQL 执行流程,从而有针对性的调优 SQL。文中示例均基于如下表结构:

CREATE TABLE `sbtest1` (`id`  INT(10) UNSIGNED NOT NULL,`k`   INT(10) UNSIGNED NOT NULL DEFAULT '0',`c`   CHAR(120)        NOT NULL DEFAULT '',`pad` CHAR(60)         NOT NULL DEFAULT '',KEY `xid` (`id`),KEY `k_1` (`k`)
) dbpartition BY HASH (`id`) tbpartition BY HASH (`id`) tbpartitions 4

先通过一个例子整体了解 DRDS 执行计划的树形结构。

mysql> explain select a.k, count(*) cnt from sbtest1 a, sbtest1 b where a.id = b.k and a.id > 1000 group by k having cnt > 1300 order by cnt limit 5, 10;
+---------------------------------------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                                                                                      |
+---------------------------------------------------------------------------------------------------------------------------------------------------+
| TmpSort(sort="cnt ASC", offset=?2, fetch=?3)                                                                                                      |
|   Filter(condition="cnt > ?1")                                                                                                                    |
|     Aggregate(group="k", cnt="COUNT()")                                                                                                           |
|       BKAJoin(id="id", k="k", c="c", pad="pad", id0="id0", k0="k0", c0="c0", pad0="pad0", condition="id = k", type="inner")                       |
|         MergeSort(sort="k ASC")                                                                                                                   |
|           LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?) ORDER BY `k`")        |
|         UnionAll(concurrent=true)                                                                                                                 |
|           LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE ((`k` > ?) AND (`k` IN ('?')))") |
| HitCache:false                                                                                                                                    |
+---------------------------------------------------------------------------------------------------------------------------------------------------+
9 rows in set (0.01 sec)

如上,DRDS EXPLAIN 的结果总体分为两部分:执行计划和其他信息。

  • 执行计划

    执行计划以缩进形式表示操作符之间的 "父-子" 关系。示例中,Filter 是 TmpSort 的子操作符,同时是 Aggregate 的父操作符。从真正执行的角度看,每个操作符均从其子操作符中获取数据,经当前操作符处理,输出给其父操作符。为方便理解,将以上执行计划转换为更加直观的树形结构:
    


  • 其他信息

    除执行计划外,EXPLAIN 结果中还会有一些额外信息,目前仅有一项 `HitCache` 。需要说明的是,DRDS 会默认开启 PlanCache 功能,`HitCache` 表示当前 SQL 是否命中 PlanCache。

    开启 PlanCache 后,DRDS 会对 SQL 做参数化处理,参数化会将 SQL 中的大部分常量用 ? 替换,并构建一个参数列表。在执行计划中的体现就是,LogicalView 的 sql 中会有 ? ,在部分操作符中会有类似 ?2 的字样,这里的 2 表示其在参数列表中的下标,后续会结合具体的例子进一步阐述。

EXPLAIN 语法

EXPLAIN 用于查看 SQL 语句的执行计划,语法如下:

EXPLAIN explainable_stmtexplainable_stmt: {SELECT statement| DELETE statement| INSERT statement| REPLACE statement| UPDATE statement
}

操作符介绍

本小节详细介绍 DRDS 执行计划中各个操作符的含义。

LogicalView

LogicalView 是从底层数据源获取数据的操作符。从数据库的角度来看,使用 TableScan 命名更符合常规,但考虑到 DRDS 本身不存储数据,而是通过 SQL 从底层数据源获取,因此,该操作符中会记录下推的 SQL 语句和数据源信息,这更像一个 "视图"。该 "视图" 中的 SQL,通过优化器的下推,可能包含多种操作,如投影、过滤、聚合、排序、连接和子查询等。

以下通过示例说明 EXPLAIN 中 LogicalView 的输出信息及其含义:

mysql> explain select * From sbtest1 where id > 1000;
+-----------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                                                          |
+-----------------------------------------------------------------------------------------------------------------------+
| UnionAll(concurrent=true)                                                                                             |
|   LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?)") |
| HitCache:false                                                                                                        |
+-----------------------------------------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)

LogicalView 的信息由三部分构成:

  • tables:底层数据源对应的表名,以 . 分割,其前是分库对应的编号,其后是表名及其编号,对于连续的编号,会做简写,如 [000-127],表示表名编号从 000 到 127 的所有表。
  • shardCount:需要访问的分表总数,该示例中会访问从 000 到 127 共 128 张分表。
  • sql:下发至底层数据源的 SQL 模版。这里显示的并非真正下发的 SQL 语句,DRDS 在执行时会将表名替换为物理表名;另外,SQL 中的常量 10 被 ? 替换,这是因为 DRDS 默认开启了 PlanCache 功能,对 SQL 做了参数化处理。

UnionAll

UnionAll 是 UNION ALL 对应的操作符,该操作符通常有多个输入,表示将多个输入的数据 UNION 在一起。以上示例中,LogicalView 之上的 UnionAll 表示将所有分表中的数据进行 UNION。

UnionAll 中的 concurrent 表示是否并行执行其子操作符,默认为 true。

UnionDistinct

与 UnionAll 类似,UnionDistinct 是 UNION DISTINCT 对应的操作符。如下:

mysql> explain select * From sbtest1 where id > 1000 union distinct select * From sbtest1 where id < 200;
+-------------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                                                            |
+-------------------------------------------------------------------------------------------------------------------------+
| UnionDistinct(concurrent=true)                                                                                          |
|   UnionAll(concurrent=true)                                                                                             |
|     LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?)") |
|   UnionAll(concurrent=true)                                                                                             |
|     LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` < ?)") |
| HitCache:false                                                                                                          |
+-------------------------------------------------------------------------------------------------------------------------+
6 rows in set (0.02 sec)

MergeSort

MergeSort,归并排序操作符,通常有多个子操作符。DRDS 中实现了两种排序:基于有序数据的归并排序和对无序数据的内存排序。如下:

mysql> explain select *from sbtest1 where id > 1000 order by id limit 5,10;
+---------------------------------------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                                                                                      |
+---------------------------------------------------------------------------------------------------------------------------------------------------+
| MergeSort(sort="id ASC", offset=?1, fetch=?2)                                                                                                     |
|   LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?) ORDER BY `id` LIMIT (? + ?)") |
| HitCache:false                                                                                                                                    |
+---------------------------------------------------------------------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)

MergeSort 操作符包含三部分内容:

  • sort:表示排序字段以及排列顺序,id ASC 表示按照 id 字段递增排序,DESC 表示递减排序。
  • offset:表示获取结果集时的偏移量,同样由于对 SQL 做了参数化,示例中的 offst 表示为 ?1 ,其中 ? 表示这是一个动态参数,其后的数字对应参数列表的下标。示例中 SQL 对应的参数为 [1000, 5, 10],因此,?1 实际对应的值为 5
  • fetch:表示最多返回的数据行数。与 offset 类似,同样是参数化的表示,实际对应的值为 10

Aggregate

Aggregate 是聚合操作符,通常包含两部分内容:Group By 字段和聚合函数。如下:

mysql> explain select k, count(*) from sbtest1 where id > 1000 group by k;
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                                                                                                                |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Aggregate(group="k", count(*)="SUM(count(*))")                                                                                                                              |
|   MergeSort(sort="k ASC")                                                                                                                                                   |
|     LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT `k`, COUNT(*) AS `count(*)` FROM `sbtest1` WHERE (`id` > ?) GROUP BY `k` ORDER BY `k`") |
| HitCache:true                                                                                                                                                               |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)

Aggregate 包含两部分内容:

  • group:表示 GROUP BY 字段,示例中为 k 。
  • 聚合函数:= 前为聚合函数对应的输出列名,其后为对应的计算方法。示例中 count(*)="SUM(count(*))" ,第一个 count(*) 对应输出的列名,随后的 SUM(count(*)) 表示对其输入数据中的 count(*) 列进行 SUM 运算得到最终的 count(*)

由此可见,DRDS 将聚合操作分为两部分,首先将聚合操作下推至底层数据源做局部聚合,最终在 DRDS 层面对局部聚合的结果做全局聚合。另外,DRDS 的最终聚合是基于排序做的,因此,会在优化器阶段为其添加一个 Sort 子操作符,而 Sort 操作符又进一步通过下推 Sort 转换为 MergeSort

再来看一个 AVG 聚合函数的例子,如下:

mysql> explain select k, avg(id) avg_id from sbtest1 where id > 1000 group by k;
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN|
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Project(k="k", avg_id="sum_pushed_sum / sum_pushed_count")|
|   Aggregate(group="k", sum_pushed_sum="SUM(pushed_sum)", sum_pushed_count="SUM(pushed_count)")|
|     MergeSort(sort="k ASC")|
|       LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT `k`, SUM(`id`) AS `pushed_sum`, COUNT(`id`) AS `pushed_count` FROM `sbtest1` WHERE (`id` > ?) GROUP BY `k` ORDER BY `k`")|
| HitCache:false|
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
5 rows in set (0.01 sec)

DRDS 会将 AVG 聚合函数转换为 SUM / COUNT,再分别根据 SUM 和 COUNT 的下推规则,将其转换为局部聚合和全局聚合。用户可自行尝试了解其他聚合函数的执行计划。

注意:DRDS 会将 DISTINCT 操作转换为 GROUP 操作,如下:

mysql> explain select distinct k from sbtest1 where id > 1000;
+-----------------------------------------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                                                                                        |
+-----------------------------------------------------------------------------------------------------------------------------------------------------+
| Aggregate(group="k")                                                                                                                                |
|   MergeSort(sort="k ASC")                                                                                                                           |
|     LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT `k` FROM `sbtest1` WHERE (`id` > ?) GROUP BY `k` ORDER BY `k`") |
| HitCache:false                                                                                                                                      |
+-----------------------------------------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.02 sec)

TmpSort

TmpSort,表示在内存中对数据进行排序。与 MergeSort 的区别在于,MergeSort 可以有多个子操作符,且每个子操作符返回的数据都已经排序。TmpSort 仅有一个子操作符。

TmpSort 对应的查询计划信息与 MergeSort 一致,请参考 MergeSort。

Project

Project 表示投影操作,即从输入数据中选择部分列输出,或者对某些列进行转换(通过函数或者表达式计算)后输出,当然,也可以包含常量。以上 AVG 的示例中,最顶层就是一个 Project,其输出 k 和 sum_pushed_sum / sum_pushed_count ,后者对应的列名为 avg_id 。

mysql> explain select '你好, DRDS', 1 / 2, CURTIME();
+-------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                        |
+-------------------------------------------------------------------------------------+
| Project(你好, DRDS="_UTF-16'你好, DRDS'", 1 / 2="1 / 2", CURTIME()="CURTIME()") |
|                                                                                     |
| HitCache:false                                                                      |
+-------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)

可见,Project 的计划中包括每列的列名及其对应的列、值、函数或者表达式。

Filter

Filter 表示过滤操作,其中包含一些过滤条件。该操作符对输入数据进行过滤,若满足条件,则输出,否则丢弃。如下是一个较复杂的例子,包含了以上介绍的大部分操作符。

mysql> explain select k, avg(id) avg_id from sbtest1 where id > 1000 group by k having avg_id > 1300;
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN  |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Filter(condition="avg_id > ?1")  |
|   Project(k="k", avg_id="sum_pushed_sum / sum_pushed_count")  |
|     Aggregate(group="k", sum_pushed_sum="SUM(pushed_sum)", sum_pushed_count="SUM(pushed_count)")  |
|       MergeSort(sort="k ASC")  |
|         LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT `k`, SUM(`id`) AS `pushed_sum`, COUNT(`id`) AS `pushed_count` FROM `sbtest1` WHERE (`id` > ?) GROUP BY `k` ORDER BY `k`") |
| HitCache:false  |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
6 rows in set (0.01 sec)

在以上 AVG 示例的 SQL 基础上添加了having avg_id > 1300 ,执行计划最上层添加了一个 Filter 操作符,用于过滤所有满足 avg_id > 1300 的数据。

有读者可能会问,WHERE 中的条件为什么没有对应的 Filter 操作符呢?在 DRDS 优化器的某个阶段,WHERE 条件的 Filter 操作符的确是存在的,只是最终将其下推到了 LogiacalView 中,因此可以在 LogicalView 的 sql 中看到 id > 1000 。

NlJoin

NlJoin,表示 NestLoop Join 操作符,即使用 NestLoop 方法进行两表 Join。DRDS 中实现了两种 JOIN 策略:NlJoin 和 BKAJoin,后者表示 Batched Key Access Join,批量键值查询,会从左表取一批数据,构建一个 IN 条件拼接在访问右表的 SQL 中,从右表一次获取一批数据。

mysql> explain select a.* from sbtest1 a, sbtest1 b where a.id = b.k and a.id > 1000;
+----------------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                                                               |
+----------------------------------------------------------------------------------------------------------------------------+
| Project(id="id", k="k", c="c", pad="pad")                                                                                  |
|   NlJoin(id="id", k="k", c="c", pad="pad", k0="k0", condition="id = k", type="inner")                                      |
|     UnionAll(concurrent=true)                                                                                              |
|       LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?)")  |
|     UnionAll(concurrent=true)                                                                                              |
|       LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT `k` FROM `sbtest1` WHERE (`k` > ?)") |
| HitCache:false                                                                                                             |
+----------------------------------------------------------------------------------------------------------------------------+
7 rows in set (0.03 sec)

NlJOIN 的计划包括三部分内容:

  • 输出列信息:输出的列名,示例中的 JOIN 会输出 5 列 id="id", k="k", c="c", pad="pad", k0="k0" 。
  • contition:连接条件,示例中连接条件为 id = k 。
  • type:连接类型,示例中是 INNER JOIN,因此其连接类型为 inner 。

BKAJoin

BKAJoin,Batched Key Access Join,表示通过批量键值查询的方式进行 JOIN,即从左表取一批数据,构建一个 IN 条件拼接在访问右表的 SQL 中,从右表一次获取一批数据进行 JOIN。

mysql> explain select a.* from sbtest1 a, sbtest1 b where a.id = b.k order by a.id;
+-------------------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                                                                  |
+-------------------------------------------------------------------------------------------------------------------------------+
| Project(id="id", k="k", c="c", pad="pad")                                                                                     |
|   BKAJoin(id="id", k="k", c="c", pad="pad", id0="id0", k0="k0", c0="c0", pad0="pad0", condition="id = k", type="inner")       |
|     MergeSort(sort="id ASC")                                                                                                  |
|       LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` ORDER BY `id`")        |
|     UnionAll(concurrent=true)                                                                                                 |
|       LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`k` IN ('?'))") |
| HitCache:false                                                                                                                |
+-------------------------------------------------------------------------------------------------------------------------------+
7 rows in set (0.01 sec)

BKAJoin 的计划内容与 NlJoin 相同,这两个操作符命名不同,旨在告知执行器以何种方法执行 JOIN 操作。另外,以上执行计划中右表的 LogicalView 中 k IN ('?') 是优化器构建出来的对右表的IN查询模板。

LogicalModifyView

如上文介绍,LogicalView 表示从底层数据源获取数据的操作符,与之对应的,LogicalModifyView 表示对底层数据源的修改操作符,其中也会记录一个 SQL 语句,该 SQL 可能是 INSERT、UPDATE 或者 DELETE。

mysql> explain update sbtest1 set c='Hello, DRDS' where id > 1000;
+--------------------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                                                                   |
+--------------------------------------------------------------------------------------------------------------------------------+
| LogicalModifyView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="UPDATE `sbtest1` SET `c` = ? WHERE (`id` > ?)") |
| HitCache:false                                                                                                                 |
+--------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.03 sec)mysql> explain delete from sbtest1 where id > 1000;
+-------------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                                                            |
+-------------------------------------------------------------------------------------------------------------------------+
| LogicalModifyView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="DELETE FROM `sbtest1` WHERE (`id` > ?)") |
| HitCache:false                                                                                                          |
+-------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.03 sec)

LogicalModifyView 查询计划的内容与 LogicalView 类似,包括下发的物理分表,分表数以及 SQL 模版。同样,由于开启了 PlanCache,对 SQL 做了参数化处理,SQL 模版中的常量会用 ? 替换。

PhyTableOperation

PhyTableOperation 表示对某个物理分表执行一个操作。该操作符目前仅用于 INSERT INTO ... VALUES ...。

mysql> explain insert into sbtest1 values(1, 1, '1', '1'),(2, 2, '2', '2');
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                                                                                                                                                 |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| PhyTableOperation(tables="SYSBENCH_CORONADB_1526954857179TGMMSYSBENCH_CORONADB_VGOC_0000_RDS.[sbtest1_001]", sql="INSERT INTO ? (`id`, `k`, `c`, `pad`) VALUES(?, ?, ?, ?)", params="`sbtest1_001`,1,1,1,1") |
| PhyTableOperation(tables="SYSBENCH_CORONADB_1526954857179TGMMSYSBENCH_CORONADB_VGOC_0000_RDS.[sbtest1_002]", sql="INSERT INTO ? (`id`, `k`, `c`, `pad`) VALUES(?, ?, ?, ?)", params="`sbtest1_002`,2,2,2,2") |
|                                                                                                                                                                                                              |
| HitCache:false                                                                                                                                                                                               |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)

示例中,INSERT 插入两行数据,每行数据对应一个 PhyTableOperation 操作符,PhyTableOperation 操作符的内容包括三部分:

  • tables:物理表名,仅有唯一一个物理表名。
  • sql:SQL 模版,该 SQL 模版中表名和常量均被参数化,用 ? 替换,对应的参数在随后的 params 中给出。
  • params:SQL 模版对应的参数,包括表名和常量。

其他信息

HitCache

DRDS 会默认开启 PlanCache 功能,HitCache 用于告知用户当前查询是否命中 PlanCache。如下,第一次运行 HitCache 为 false,第二次运行为 true。

mysql> explain select * From sbtest1 where id > 1000;
+-----------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                                                          |
+-----------------------------------------------------------------------------------------------------------------------+
| UnionAll(concurrent=true)                                                                                             |
|   LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?)") |
| HitCache:false                                                                                                        |
+-----------------------------------------------------------------------------------------------------------------------+
3 rows in set (0.01 sec)mysql> explain select * From sbtest1 where id > 1000;
+-----------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                                                          |
+-----------------------------------------------------------------------------------------------------------------------+
| UnionAll(concurrent=true)                                                                                             |
|   LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?)") |
| HitCache:true                                                                                                         |
+-----------------------------------------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)

小结

以上介绍了 DRDS 5.3 的 EXPLAIN 命令,以及执行计划中每个操作符的含义,相信可以为用户调优 SQL 提供极大得便利。

DRDS 5.3 已经在阿里云正式上线,除全新设计的执行计划外,性能也有大幅提升,并支持原生事务、Outline 和 Plan Cache 等功能。后续支持复杂查询的只读实例、回收站、基于事务的广播表写入等功能也将相继上线,敬请期待。

 原文链接

本文为云栖社区原创内容,未经允许不得转载。


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

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

相关文章

易商云页面认证失败是什么情况_Serverless 云原生框架 Malagu:认证与授权

认证与授权组件 malagu/security 。Malagu 框架结合传统后台管理系统和云计算平台的认证与授权理念&#xff0c;并借鉴了 Spring Security 设计思想&#xff0c;抽象了一套通用的认证与授权模型。Spring Security 对前后端分离架构支持不是特别友好&#xff0c;Malagu 框架在这…

sharepoint文件夹本地同步_mac文件同步软件-Resilio Sync Home

Resilio Sync Mac版是Mac平台上的一款文件同步软件&#xff0c;Resilio Sync Mac版使用起来非常的简单、方便。你可以通过链接、秘钥或二维码的方式共享你电脑里的任意文件夹&#xff0c;接收方也可以把共享文件存放在任意位置。Resilio Sync Home Pro for mac(文件同步软件)​…

(需求实战_进阶_01)SSM集成RabbitMQ 关键代码讲解、开发、测试

背景&#xff1a; 为了减轻服务器的压力&#xff0c;现在原有项目的基础上集成消息队列来异步处理消息! 此项目是企业真实需求&#xff0c;项目的代码属于线上生产代码&#xff0c;直接用于生产即可&#xff01; 此项目采用MQ发送消息模式为:路由模式&#xff0c;如果对RabbitM…

浅谈Service Mesh体系中的Envoy

摘要&#xff1a; 提到Envoy就不得不提Service Mesh&#xff0c;说到Service Mesh就一定要谈及微服务了&#xff0c;那么我们就先放下Envoy&#xff0c;简单了解下微服务、Service Mesh以及Envoy在Service Mesh中处于一个什么样的角色。背景最近因工作原因开始了解Service Mesh…

Java并发编程笔记之FutureTask源码分析

FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask&#xff0c;直接调用其run方法或者放入线程池执行&#xff0c;之后可以在外部通过FutureTask的get方法异步获取执行结果&#xff0c;因此&#xff0c;FutureTask非常适…

动动手指头, Feed 流系统亿级规模不用愁

戳蓝字“CSDN云计算”关注我们哦&#xff01;作者 | 少强责编 | 阿秃导读&#xff1a;互联网进入移动互联网时代&#xff0c;最具代表性的产品就是各种信息流&#xff0c;像是朋友圈、微博、头条等。这些移动化联网时代的新产品在过去几年间借着智能手机的风高速成长。这些产品…

(需求实战_进阶_02)SSM集成RabbitMQ 关键代码讲解、开发、测试

接上一篇&#xff1a;&#xff08;企业内部需求实战_进阶_01&#xff09;SSM集成RabbitMQ 关键代码讲解、开发、测试 https://gblfy.blog.csdn.net/article/details/104197309 文章目录一、RabbitMQ配置文件1. RabbitMQ生产者配置文件2. RabbitMQ消费者配置文件3. 连接配置文件…

vue 判断同一数组内的值是否一直_vue一些笔记

vuex action&#xff1a;尤雨溪在知乎回答了&#xff0c;区分 actions 和 mutations 并不是为了解决竞态问题&#xff0c;vuex 真正限制你的只有 mutation 必须是同步的这一点&#xff0c;只是为了devtools追踪状态变化&#xff0c;或者说出于单一职责原则。https://www.zhihu.…

机器学习从业人员到底做什么?

这篇文章是系列文章的第1部分,第2部分将阐述AutoML和神经架构搜索、第3部分将特别地介绍Google的AutoML。 关于机器学习人才的稀缺和公司声称他们的产品能够自动化机器学习而且能完全消除对ML专业知识需求的承诺经常登上媒体的新闻头条。在TensorFlow DevSummit的主题演讲中&a…

黑科技揭秘:面对海量的文本翻译任务,阿里翻译团队是如何解决的

摘要&#xff1a; 对国际化企业来说语言问题是亟待突破的重要关口。面对海量的文本翻译任务&#xff0c;昂贵低效的人工翻译显然不能满足需求&#xff0c;利用计算机自动进行文本翻译的机器翻译才是解决这个问题的关键。阿里翻译团队在机器翻译领域做了大量技术储备&#xff0c…

(需求实战_进阶_03)SSM集成RabbitMQ 路由模式关键代码讲解、开发、测试

接上一篇&#xff1a;&#xff08;企业内部需求实战_进阶_02&#xff09;SSM集成RabbitMQ 关键代码讲解、开发、测试 https://gblfy.blog.csdn.net/article/details/104214033 上一篇给大家介绍了在RabbitMQ 的管控台中&#xff0c;将队列绑定到指定的交换机上&#xff1b;这片…

在计算机中dos代表什么意思,Boot是什么意思

Boot是什么意思如果你去问一个学计算机的人&#xff0c;“启动”是计算机中的那个单词?回答一定是Boot。可是&#xff0c;Boot原来的意思是靴子&#xff0c;“启动”与靴子有什么关系呢?原来&#xff0c;这里的Boot是bootstrap(鞋带)的缩写&#xff0c;它来自一句谚语&#x…

你知道哪些情况下不该使用深度学习吗?

深度学习不适用于什么样的任务&#xff1f;依我之见&#xff0c;以下这些主要场景的深度学习弊大于利。01低成本或者低承诺问题深网是非常灵活的模型&#xff0c;有着许多架构和节点类型&#xff0c;优化器和正则化策略。根据应用&#xff0c;你的模型可能会有卷基层&#xff0…

秒后面的单位是什么_单位与国际单位制是如何由来的?

2013年国庆期的一则网络消息说&#xff0c;11万人看升旗留下了5吨垃圾。有人认为这是一则假消息&#xff0c;因为5吨&#xff1d;5000千克&#xff0c;110000500022千克/人&#xff0c;而每人携带22千克&#xff08;44斤&#xff09;的垃圾是不可能的。以前还看过一个说法&…

(需求实战_进阶_04)SSM集成RabbitMQ 通配符模式 关键代码讲解、开发、测试

背景&#xff1a; 为了减轻服务器的压力&#xff0c;现在原有项目的基础上集成消息队列来异步处理消息! 此项目是企业真实需求&#xff0c;项目的代码属于线上生产代码&#xff0c;直接用于生产即可&#xff01; 此项目采用MQ发送消息模式为:通配符模式&#xff0c;如果对Rabbi…

halo多人正在连接服务器,在线人数过低 《光晕2》PC版多人服务器下月关闭

这也许是一个让粉丝略伤感的消息&#xff0c;《光晕2(Halo2)》PC多人游戏服务器将在下个月永久关闭。343 Industries注意到服务器的峰值在线人数一直仅有20人&#xff0c;因此做出了关闭服务器的决定。343 Industries在Halo Waypoint中说道&#xff1a;“我们很遗憾地宣布&…

纯Python实现鸢尾属植物数据集神经网络模型

摘要&#xff1a; 本文以Python代码完成整个鸾尾花图像分类任务&#xff0c;没有调用任何的数据包&#xff0c;适合新手阅读理解&#xff0c;并动手实践体验下机器学习方法的大致流程。 尝试使用过各大公司推出的植物识别APP吗&#xff1f;比如微软识花、花伴侣等这些APP。当你…

【明人不说暗话】我就只讲进程与线程

戳蓝字“CSDN云计算”关注我们哦&#xff01;作者 | 阮一峰责编 | 阿秃进程&#xff08;process&#xff09;和线程&#xff08;thread&#xff09;是操作系统的基本概念&#xff0c;但是它们比较抽象&#xff0c;不容易掌握。最近&#xff0c;我读到一篇材料&#xff0c;发现有…

(需求实战_进阶_05)SSM集成RabbitMQ 通配符模式 关键代码讲解、开发、测试

接上一篇&#xff1a; 文章目录一、RabbitMQ 配置文件1. RabbitMQ 生产者配置文件更新二、启动项目2.1. 启动项目2.2. 清空控制台三、管控台总览3.1. 登录管控台3.2. 交换机中查看绑定队列总览四、验证测试4.4. 生产者①请求4.5. 生产者②请求五、启动RabbitMQ5.1. 进入sbin目录…

两台邮件服务器共用一个公网地址,两个不同域邮件服务器的互通

两个不同域的邮件服务的互通如图&#xff0c;有两个不同域的邮件服务器(postfix)通过一个DNS服务器实现互通。首先说明一下IP分配情况服务器1qq.cometh0(VMnet2)&#xff1a; ip:192.168.2.2 netmask:255.255.255.0 gw 192.168.2.1 hostname:mail.qq.com服务器2(qq.neteht0VMne…