如何在OceanBase v4.2 中快速生成随机数据

news2024/11/15 4:07:24

在使用传统数据库如 MySQL 和 Oracle 时,由于缺乏多样化的随机数据生成方案,或者实现成本过高,构造随机数据的开发成本受到了影响。OceanBase在老版本中虽然有相应的解决方案,但语法复杂和性能较差等问题仍然存在。

现在,OceanBase v4.2 实现了简洁、高效且批量的随机数据插入操作。以下是一个 SQL 示例,它可向 t1 表中批量插入 100 行数据,每行均包含四个随机数值以及一个随机生成的字符串。

create table t1 (c1 varchar(10), c2 bigint, c3 bigint, c4 bigint, c5 bigint);

insert into t1 select     
  randstr(10, random()) c1,
  random() c2,
  zipf(1, 100, random(3)),
  normal(0, 1, random()),
  uniform(1, 100, random())
from 
  table(generator(100));

select * from t1;

背景

我们在实践中发现,功能测试、压力测试、PoC 等等场景下都会涉及到随机数据生成,OceanBase v4.2 之前的版本存在两类问题:

  • 随机函数种类少,不支持数据分布控制,需要手写 UDF 或 PL 包。
  • 多行数据生成时,需要用 CONNECT BY 或 CTE,它们不仅语法复杂,而且数据行数较多时存在性能问题

下面用两个场景来说明我们亟需更好用的接口。

场景一:OceanBase 测试。

OceanBase 拥有大量的 mysqltest 测试用例,但这些用例中创建的表一般都不超过百行数据,导致一些潜在场景覆盖不到。为了增加覆盖率,我们需要给表中灌入更多数据,但在 v4.2 版之前这并不是一件容易事:

  • insert into values 方法手工构造 values 很费劲,有多少行数据就要构造多少组值。
  • insert into select 方法构造多行数据需要使用复杂的语法,并且性能不高,导致很少有工程师使用。
  • 需要测试数据倾斜场景时,必须手工构造倾斜值,最后设计出来的 case 倾斜值的 NDV 大部分都是1、2 或者3,测试效果大打折扣。
  • 需要测试长字符串场景时,只能使用 repeat、lpad、rpad 这类函数来构造长字符串,这些方法构造出来的字符串很有规律,通过存储层 lz、zstd 等压缩算法处理后占用空间会很小,也可能导致测试效果不尽人意。

场景二:OceanBase PoC。

两年前,我的一个同事在周末从 PoC 现场给我打电话咨询如何生成 1000 万行数据插入到数据库中,我给他介绍了 CTE 法和 CONNECT BY 法,但这两个方法都因为性能太差用不起来。最后他使用了“手工倍增法”:

Create table t1 (c1 bigint);
Insert into t1 values (1);
Insert into t1 select * from t1; // 现在 t1 包含 2 行数据
Insert into t1 select * from t1; // 现在 t1 包含4行数据
Insert into t1 select * from t1; // 现在 t1 包含8行数据
Insert into t1 select * from t1; // 现在 t1 包含16行数据
…
Insert into t1 select * from t1; // 现在 t1 包含65536行数据
…

为了让传统 MySQL 客户快速的体验 OceanBase 极速的性能,我们可以在 QuickStart 中让他构建一个十万行的表来体验极速查询性能。构建十万行数据,无论是 insert into values 方法,还是“手工倍增法”,导数体验都很糟糕

OceanBase v4.2 提供了全新的多行数据导入功能,彻底解决了上述痛点。它包含如下特性:

  1. 简洁易记的导数语法。
  2. 支持任意长度的随机字符串生成函数。
  3. 支持分布函数,轻松构造倾斜数据。
  4. Oracle 模式下引入原生内置随机函数,解决 PL 包性能不足问题。

OceanBase v4.2 随机行数据生成方法

随机数

为 MySQL 和 Oracle 模式统一增加了一套原生函数,提供完善的功能和最好的性能。

  • 无论 MySQL 还是 Oracle 模式,都增加同名函数,丰富了函数种类。
  • 无论 MySQL 还是 Oracle 模式,都提供原生内置函数,性能最优。
  • 随机函数支持传入种子值,使得随机序列可复现,对测试友好。

1. 随机函数。

RANDOM([N]):随机生成一个 64 位整数。N 是整数,为随机种子,可选。

RANDSTR(N, gen):随机生成长度为 N 的字符串,gen 为随机方法,可选值为:

    • RANDOM
    • NORMAL - 生成的字符串服从正态分布 
    • UNIFORM - 生成的字符串服从均匀分布
    • ZIPF - 生成的字符串服从齐夫分布
    • 任意常数 - 生成同一个字符串

1700795000

2.分布控制。

NORMAL(<mean> , <stddev> , <gen>):正态分布(高斯分布),返回一个符合正态分布(normal distribution,又称高斯分布)的浮点数。

1700795127

UNIFORM(<min> , <max> , <gen>):均匀分布,返回一个符合均匀分布(uniform distribution)的整数或浮点数。

1700795190

ZIPF(<s> , <N> , <gen>):齐夫分布,返回一个符合齐夫分布(zipf distribution)的整数。齐普夫定律是语言学专家Zipf在研究英文单词出现的频率时,发现如果把单词出现的频率按由大到小的顺序排列,则每个单词出现的频率与它的名次的常数次幂存在简单的反比关系,这种分布就称为Zipf定律,它表明在英语单词中,只有极少数的词被经常使用,而绝大多数词很少被使用。实际上,包括汉语在内的许多国家的语言都有这种特点。这个定律后来在很多领域得到了同样的验证,例如著名的28定律。 

1700795260

随机函数部分,我们在已有的 rand() 浮点随机数函数基础上,引入了直接生成整数值的 random() 函数,直接生成随机字符串的 randstr() 函数。同时,还引入了 normal、uniform、zipf 等几个分布控制函数,这使得我们能轻松控制生成数据的分布规律。

关于生成器表达式是一个比较新的概念,特别说明如下:

  • 每个随机分布函数都需要一个生成器表达式(gen)作为其最后一个参数。生成器表达式可以是常量或变量:
    • 如果是常量,则随机分布函数的结果是常量。
    • 如果是变量,则随机分布函数的结果是可变的。
  • 任何可转换为64位整数的表达式都可以用作生成器表达式。
  • 任何随机分布函数的随机性都直接与其生成器表达式的随机性相关。对于大多数实际目的,random() 函数是随机生成整数值的最佳选择。
  • 由数据生成函数生成的序列不能保证有序且没有间隙。这是因为数字可能会以并行的方式、不同步地生成。

行数据生成

Table function是一种在SQL语言中使用的函数,它能够返回一张数据表作为结果。与传统的SQL函数只能返回标量值不同,table function 可以返回多行、多列的数据集。 我们新增 generator 函数,并允许在 table function 中调用它,最终返回 N 行数据。语法为:table(generator(N)); 

N 是一个大于等于0的64位正整数。

使用举例:

OceanBase(TEST@TEST)>SELECT COUNT(*) FROM TABLE(GENERATOR(100000));
+----------+
| COUNT(*) |
+----------+
|   100000 |
+----------+
1 row in set (0.02 sec)

select normal(0, 1, random()) from table(generator(5));
+------------------------+
| NORMAL(0, 1, RANDOM()) |
|------------------------|
|           0.227384164  |
|           0.9945290748 |
|          -0.2045078571 |
|          -1.594607893  |
|          -0.8213296842 |
+------------------------+

select randstr(1, zipf(1, 5, random())) str from table(generator(5));
+------------------------+
|                    str |
|------------------------|
|                     A  |
|                     D  |
|                     A  |
|                     A  |
|                     C  |
+------------------------+

table generator 也可以和其它表做 join:


OceanBase(admin@test)>create table t1 (c1 bigint);
Query OK, 0 rows affected (0.18 sec)

OceanBase(admin@test)>insert into t1 values (1), (2);
Query OK, 2 rows affected (0.03 sec)
Records: 2  Duplicates: 0  Warnings: 0

OceanBase(admin@test)>select c1, random(1) from t1, table(generator(3));
+------+----------------------+
| c1   | random(1)            |
+------+----------------------+
|    1 | -6753783847308464280 |
|    2 | -6707106347154343346 |
|    1 |  -899926183391115878 |
|    2 | -8835543475904200562 |
|    1 | -2750444335953844424 |
|    2 |  7588216632478230601 |
+------+----------------------+
6 rows in set (0.00 sec)

OceanBase(admin@test)>explain select c1, random(1) from t1, table(generator(3));
+--------------------------------------------------------------------+
| Query Plan                                                         |
+--------------------------------------------------------------------+
| ================================================================== |
| |ID|OPERATOR                   |NAME       |EST.ROWS|EST.TIME(us)| |
| ------------------------------------------------------------------ |
| |0 |NESTED-LOOP JOIN CARTESIAN |           |398     |14          | |
| |1 | FUNCTION_TABLE            |FUNC_TABLE1|199     |1           | |
| |2 | MATERIAL                  |           |2       |2           | |
| |3 |  TABLE SCAN               |t1         |2       |2           | |
| ================================================================== |
| Outputs & filters:                                                 |
| -------------------------------------                              |
|   0 - output([t1.c1], [random(1)]), filter(nil), rowset=256        |
|       conds(nil), nl_params_(nil), batch_join=false                |
|   1 - output(nil), filter(nil)                                     |
|       value(generator(3))                                          |
|   2 - output([t1.c1]), filter(nil), rowset=256                     |
|   3 - output([t1.c1]), filter(nil), rowset=256                     |
|       access([t1.c1]), partitions(p0)                              |
|       is_index_back=false, is_global_index=false,                  |
|       range_key([t1.__pk_increment]), range(MIN ; MAX)always true  |
+--------------------------------------------------------------------+
19 rows in set (0.00 sec)

OceanBase(admin@test)>select /*+ parallel(2) */ c1, random(1) from t1, table(generator(3));
+------+----------------------+
| c1   | random(1)            |
+------+----------------------+
|    1 | -6753783847308464280 |
|    2 | -6707106347154343346 |
|    1 |  -899926183391115878 |
|    2 | -8835543475904200562 |
|    1 | -2750444335953844424 |
|    2 |  7588216632478230601 |
+------+----------------------+
6 rows in set (0.00 sec)

OceanBase(admin@test)>explain select /*+ parallel(2) */ c1, random(1) from t1, table(generator(3));
+--------------------------------------------------------------------+
| Query Plan                                                         |
+--------------------------------------------------------------------+
| ================================================================== |
| |ID|OPERATOR                   |NAME       |EST.ROWS|EST.TIME(us)| |
| ------------------------------------------------------------------ |
| |0 |NESTED-LOOP JOIN CARTESIAN |           |398     |14          | |
| |1 | FUNCTION_TABLE            |FUNC_TABLE1|199     |1           | |
| |2 | MATERIAL                  |           |2       |2           | |
| |3 |  PX COORDINATOR           |           |2       |2           | |
| |4 |   EXCHANGE OUT DISTR      |:EX10000   |2       |2           | |
| |5 |    PX BLOCK ITERATOR      |           |2       |1           | |
| |6 |     TABLE SCAN            |t1         |2       |1           | |
| ================================================================== |
| Outputs & filters:                                                 |
| -------------------------------------                              |
|   0 - output([t1.c1], [random(1)]), filter(nil), rowset=256        |
|       conds(nil), nl_params_(nil), batch_join=false                |
|   1 - output(nil), filter(nil)                                     |
|       value(generator(3))                                          |
|   2 - output([t1.c1]), filter(nil), rowset=256                     |
|   3 - output([t1.c1]), filter(nil), rowset=256                     |
|   4 - output([t1.c1]), filter(nil), rowset=256                     |
|       dop=2                                                        |
|   5 - output([t1.c1]), filter(nil), rowset=256                     |
|   6 - output([t1.c1]), filter(nil), rowset=256                     |
|       access([t1.c1]), partitions(p0)                              |
|       is_index_back=false, is_global_index=false,                  |
|       range_key([t1.__pk_increment]), range(MIN ; MAX)always true  |
+--------------------------------------------------------------------+
26 rows in set (0.00 sec)

无论是否开启并行执行,Table Generator 都是使用单线程来生成数据。不过不用担心性能问题,目前向存储层插入数据的过程才是瓶颈,单线程生成数据不是瓶颈。

性能评测

在 OceanBase 中,我们对比了 Connect By、Recursive CTE 和 Table Generator 生成行数据性能,每行包含一列整数。生成 1000 万行数据,Table Generator 只需 2 秒,完全满足日常需求。

Oracle Mode Connect ByMySQL ModeRecursive CTETable Generator
生成1w行数据耗时0.02s0.83s0.002s
生成10w行数据耗时0.18s10s+(timeout)0.02s
生成100w行数据耗时Out Of Memory10s+(timeout)0.21s
生成1000w行数据耗时Out Of Memory10s+(timeout)2.05s

最佳实践

在了解基本概念后,下面给出一些常见的随机数据生成场景,以展示基本用法。

有主键表随机数据生成

推荐搭配 sequence 对象:

create table t1 (c1 bigint primary key, c2 bigint);
create sequence s1 cache 1000000 noorder;
Insert into t1 select s1.nextval, random() from table(generator(1000));
Insert into t1 select s1.nextval, random() from table(generator(1000));

Note:为了尽可能提高生成数据的性能,sequence cache 大小不要低于 100 万。

千万行级别的随机数据生成

推荐配合使用 OceanBase 4.1 推出“旁路导入”功能,以获得最高的性能。只需要添加append enable_parallel_dml parallel(8) hint 即可,此处使用了并行度8:

create table t1 (c1 bigint, c2 varchar(10));
Insert /*+ append enable_parallel_dml parallel(8) */ into t1 select random(), randstr(10, random()) from table(generator(10000000));

Note:考虑到 OceanBase 4.2 版本旁路导入的最佳实践,建议用一条 insert 语句完成单表全部数据插入,不要拆成多条 insert 来做。

生成包含多个宏块的数据

为了测试包含多个宏块的场景,我们需要插入大量的数据。但是偶尔我们会发现,即使插入了大量行,OceanBase 凭借其强大的压缩能力,把这些数据都给压缩没了。即使插入了数十万行,还装不满一个宏块。

Oracle 模式下为了解决这个问题,我们可以在建表时加上 NOCOMPRESS属性,这样,插入很少的数据就能装满一个宏块。例如:

create table t1 (c1 bigint, c2 varchar(10000)) NOCOMPRESS;
Insert /* append enable_parallel_dml parallel(8) */ into t1 select random(), repeat('a', 10000) from table(generator(10000000));

MySQL 模式下没有 NOCOMPRESS 选项,可以使用 randstr() 来生成足够长的随机串避免压缩。

create table t1 (c1 bigint, c2 varchar(10000));
Insert /* append enable_parallel_dml parallel(8) */ into t1 select random(), randstr(1000, random()) from table(generator(10000000));

测试并行执行场景推荐使用本方法,有助于提前暴露数据切分相关问题。

倾斜数据生成

我们可以让数据符合正态分布或 zipf 分布,这样就能构造出数据倾斜。例如下面随机生成 20 行数据,zipf 分布可以让小数字出现的频率更高:

OceanBase(TEST@TEST)>select zipf(1, 20, random()) from table(generator(20));
+---------------------+
| ZIPF(1,20,RANDOM()) |
+---------------------+
|                   0 |
|                   0 |
|                   4 |
|                   5 |
|                  12 |
|                   4 |
|                  16 |
|                   1 |
|                   2 |
|                   9 |
|                   0 |
|                   0 |
|                   0 |
|                   1 |
|                   3 |
|                   7 |
|                  11 |
|                  13 |
|                   1 |
|                   1 |
+---------------------+
20 rows in set (0.00 sec)

Note: zipf 生成的数字的分布的特点是小数字出现频率高,大数字出现频率低。

长短不一的字符串生成

OceanBase(TEST@TEST)>select randstr(1+zipf(1, 20, random()), random()) from table(generator(20));
+-----------------------------------------+
| RANDSTR(1+ZIPF(1,20,RANDOM()),RANDOM()) |
+-----------------------------------------+
| 1E                                      |
| VM                                      |
| wxYJ                                    |
| zoBaL                                   |
| IhaZW                                   |
| 8z6jaVWxG92vs1kx                        |
| roDKzcJ2JS                              |
| IVwBKZsvix8z                            |
| 8D                                      |
| UTM                                     |
| 9alknanS                                |
| rSxQ9kD4lm                              |
| 9                                       |
| 9MXuz                                   |
| r                                       |
| i1c                                     |
| nE16vM52jW                              |
| XG1                                     |
| bSdeZi                                  |
| 2TuvyPMVSf                              |
+-----------------------------------------+
20 rows in set (0.00 sec)

批量插入单词

一些场景下,我们希望插入的字符串有一定规律,不要长得像乱码。比如,插入的内容是字典里的单词。可以通过预先构造一个单词表解决这个问题:

OceanBase(admin@test)>create table t1 (c1 int, c2 varchar(10));
Query OK, 0 rows affected (0.168 sec)

OceanBase(admin@test)>insert into t1 values (0, 'hello'), (1, 'world'), (2, 'movie');
Query OK, 3 rows affected (0.011 sec)
Records: 3  Duplicates: 0  Warnings: 0

OceanBase(admin@test)>create table t2 (c1 varchar(10));
Query OK, 0 rows affected (0.160 sec)

OceanBase(admin@test)>insert /*+ parallel(3) enable_parallel_dml */ into t2 select b.c2 from table(generator(1000)) a, t1 b where b.c1 = random() % 3;
Query OK, 1000 rows affected (0.015 sec)
Records: 1000  Duplicates: 0  Warnings: 0

插入部分 null 值

在数据集中掺入 null 值,常能有效暴露一些潜在 bug。MySQL 模式中可以用 if 来实现在随机数中掺 null,Oracle 模式下,可以用 decode 来实现。下面的例子里,都以 10% 的概率生成 null 值:

OceanBase(admin@test)>select  if(random(4) % 10 = 0, null, random(4)) from table(generator(10));
+-----------------------------------------+
| if(random(4) % 10 = 0, null, random(4)) |
+-----------------------------------------+
|                     5267436225003336391 |
|                                    NULL |
|                     -851690886662571060 |
|                     1738617244330437274 |
|                    -8073957877497551694 |
|                      885116094377146851 |
|                    -8183226488433301506 |
|                     6294187330509591201 |
|                    -8511555461190104804 |
|                     4732822798680798032 |
+-----------------------------------------+
10 rows in set (0.000 sec)
OceanBase(TEST@TEST)>select decode(mod(random(4),10), 0, null, random(4)) from table(generator(10));
+--------------------------------------------+
| DECODE(MOD(RANDOM(4),10),0,NULL,RANDOM(4)) |
+--------------------------------------------+
| 5267436225003336391                        |
| NULL                                       |
| -851690886662571060                        |
| 1738617244330437274                        |
| -8073957877497551694                       |
| 885116094377146851                         |
| -8183226488433301506                       |
| 6294187330509591201                        |
| -8511555461190104804                       |
| 4732822798680798032                        |
+--------------------------------------------+
10 rows in set (0.002 sec)

mysqltest 中如何生成稳定的随机数据

Mysqltest 要求数据必须稳定,否则每次回归的结果都不一样。我们只需要传入一个常数种子(seed)到随机函数中就可以保证每次插入到表中的数据是一样的。所谓 seed 就是给 random() 函数传入一个任意的常量值,seed 相同,每次执行输出的结果都相同。例如下面的例子中,3 就是 seed。

create table t1 (c1 int);
Insert into t1 select random(3) from table(generator(1000));

加速数据插入

配合并行DML(PDML)可以加速数据插入速度:

create table t1 (c1 int, c2 int);
Insert /*+ parallel(4) enable_parallel_dml */ into t1 select random(), random() from table(generator(10000000));

如果没有事务要求,也可以搭配上旁路导入功能,导数性能可以更高:

create table t1 (c1 int, c2 int);
Insert /*+ append parallel(4) enable_parallel_dml */ into t1 select random(), random() from table(generator(10000000));

Note:OceanBase v4.2 版本的旁路导入功能还不支持事务,我们计划在未来版本里添加事务支持。

附录:OceanBase 老版本随机数据生成方法

随机数

随机数生成针对Oracle和MySQL提供了不同的方法。

针对Oracle,提供了DBMS_RANDOM 包,示例如下:

OceanBase(TEST@TEST)>create table t1 (c1 int);
inQuery OK, 0 rows affected (0.350 sec)

OceanBase(TEST@TEST)>insert into t1 values (1),(2);
Query OK, 2 row affected (0.054 sec)

OceanBase(TEST@TEST)>SELECT DBMS_RANDOM.value FROM t1;
+-----------------------------------------+
| DBMS_RANDOM.VALUE                       |
+-----------------------------------------+
|  .7399915858834366379526638344258521027 |
| .49582434020991574649964366641874399825 |
+-----------------------------------------+
2 rows in set (0.001 sec)

OceanBase(TEST@TEST)>SELECT DBMS_RANDOM.random FROM t1;
+--------------------+
| DBMS_RANDOM.RANDOM |
+--------------------+
|        -1829272250 |
|         -302482048 |
+--------------------+
2 rows in set (0.001 sec)

OceanBase(TEST@TEST)>SELECT DBMS_RANDOM.string('u', 10) FROM t1;
+----------------------------+
| DBMS_RANDOM.STRING('U',10) |
+----------------------------+
| CXYOOFFTAK                 |
| ISQXVGILZS                 |
+----------------------------+
2 rows in set (0.003 sec)

OceanBase(TEST@TEST)>SELECT DBMS_RANDOM.string('l', 10) FROM t1;
+----------------------------+
| DBMS_RANDOM.STRING('L',10) |
+----------------------------+
| tesckgmuhd                 |
| qumsrewisr                 |
+----------------------------+
2 rows in set (0.006 sec)

OceanBase(TEST@TEST)>SELECT DBMS_RANDOM.normal() FROM t1;
+--------------------------------------------+
| DBMS_RANDOM.NORMAL()                       |
+--------------------------------------------+
| -.3707362774912783852056768030439781065643 |
|  -.661863938694328133730598207745367381443 |
+--------------------------------------------+
2 rows in set (0.002 sec)

而对于MySQL,则提供了rand() 函数,示例如下:

OceanBase(admin@test)>create table t1 (c1 int);
Query OK, 0 rows affected (0.143 sec)

OceanBase(admin@test)>insert into t1 values (1),(2);
Query OK, 2 rows affected (0.014 sec)
Records: 2  Duplicates: 0  Warnings: 0

OceanBase(admin@test)>select rand() from t1;
+---------------------+
| rand()              |
+---------------------+
|  0.3246343818722613 |
| 0.20731560718949474 |
+---------------------+
2 rows in set (0.005 sec)

可以看到,MySQL 模式下随机函数种类太少(云平台客户大部分使用的是 MySQL 模式)。虽然 Oracle 包提供的随机函数是比较丰富的,但目前因为实现缘故,在大批量数据插入场景使用 DBMS_RANDOM 包有比较大的性能开销。

行数据生成

为了生成 1000 行数据,老版本的 OceanBase 使用如下方法:

对于Oracle,使用Connect By方法,示例如下:

OceanBase(TEST@TEST)>SELECT COUNT(*)  FROM
    (SELECT * FROM dual CONNECT BY LEVEL <= 100000) a;
+----------+
| COUNT(*) |
+----------+
|   100000 |
+----------+
1 row in set (0.16 sec)

对于MySQL,使用Recursive CTE方法,示例如下:

OceanBase(admin@test)>WITH RECURSIVE cte1 (n) AS 
    (SELECT 1 UNION ALL SELECT n+1 FROM cte1 WHERE n < 10000 )
    SELECT COUNT(*) FROM cte1;
+----------+
| COUNT(*) |
+----------+
|    10000 |
+----------+
1 row in set (0.79 sec)

可以看到:语法的确是比较复杂,记起来不容易,两个方法的实现性能也不太良好。

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

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

相关文章

医学图像分割入门-UNet理论与实践

U-Net: 用于图像分割的深度学习网络 引言 在计算机视觉领域&#xff0c;图像分割是一项重要的任务&#xff0c;旨在将图像中的每个像素分配到预定义的类别或区域。传统的图像分割方法通常基于手工设计的特征和启发式算法&#xff0c;但随着深度学习的发展&#xff0c;基于深度…

负载均衡(理解/解析)

目录 什么是负载均衡 应用场景 网络服务和应用&#xff1a; 云计算和虚拟化&#xff1a; 负载均衡分类 硬件负载均衡器 软件负载均衡器 部署方式 硬件部署&#xff1a; 软件部署&#xff1a; 云部署&#xff1a; 路由模式&#xff1a; 算法实现 轮询法&#xff08;Round R…

java学习——消息队列MQ

上一篇传送门&#xff1a;点我 目前只学习了RabbitMQ&#xff0c;后续学习了其他MQ后会继续补充。 MQ有了解过吗&#xff1f;说说什么是MQ&#xff1f; MQ是Message Queue的缩写&#xff0c;也就是消息队列的意思。它是一种应用程序对应用程序的通信方法&#xff0c;使得应用…

Apache Zeppelin 命令执行漏洞复现(CVE-2024-31861)

0x01 产品简介 Apache Zeppelin 是一个让交互式数据分析变得可行的基于网页的开源框架&#xff0c;Zeppelin提供了数据分析、数据可视化等功能&#xff0c; 0x02 漏洞概述 Apache Zeppelin 中代码生成控制不当&#xff08;“代码注入”&#xff09;漏洞。攻击者可以使用 She…

Springboot集成Ehcache3实现本地缓存

如果只需要在单个应用程序中使用本地缓存&#xff0c;则可以选择Ehcache&#xff1b;它支持内存和磁盘存储&#xff0c;这里不以注解方式演示&#xff0c;通过自己实现缓存管理者灵活控制缓存的读写&#xff1b; 1、引入相关依赖 <!-- ehcache3集成start --><depende…

蓝色系UX/UI设计求职面试作品集模版figmasketchPPT可编辑源文件

页面数量: 20P 页面尺寸:1920*1080PX 交付格式&#xff1a;figma、sketch、PPT 赠送文件&#xff1a;24款高质量样机&#xff08;PSD格式&#xff09; 该作品集虽然只有20页&#xff0c;但可根据需求复制作品集里已有的页面作为模版来扩展您的设计项目 该作品集模版可编辑可修…

MySQL (索引 事务)

索引 索引是一种特殊的文件, 包含着对于数据库里所有数据的引用指针. 可以对表中的一列或多列创建索引, 并指定索引类型, 各类索引有各自的数据结构实现 索引的目的在于 快速定位, 检索数据 索引可以提高 查找 效率, 但会增加 增删改 的开销 索引创建好之后, 每次调用 查询操作…

探索顶级短视频素材库:多样化选择助力创作

在数字创作的浪潮中&#xff0c;寻找优质的短视频素材库是每位视频制作者的必经之路。多种短视频素材库有哪些&#xff1f;这里为您介绍一系列精选的素材库&#xff0c;它们不仅丰富多样&#xff0c;而且高质量&#xff0c;能极大地提升您的视频创作效率和质量。 1.蛙学网 蛙学…

华火电焰灶全国经销商加盟_优势怎么样_费用多少_华焰天下

随着科技的不断进步&#xff0c;电焰灶作为现代厨房的重要设备&#xff0c;其市场需求持续增长。华火电焰灶&#xff0c;凭借其独特的技术优势和广泛的市场前景&#xff0c;吸引了众多投资者的目光。本文将从华火电焰灶的优势、加盟费用以及华焰天下的机遇三个方面&#xff0c;…

【gdb调试】在ubuntu环境使用gdb调试一棵四层二叉树的数据结构详解

目录 &#x1f31e;1. 整体思路 &#x1f31e;2. 准备内容 &#x1f33c;2.1 配置.c文件 &#x1f33c;2.2 准备测试程序 &#x1f33c;2.3 GDB调试基础 &#x1f31e;3. GDB调试四层二叉树 &#x1f33c;3.1 测试程序分析 &#x1f33c;3.2 gdb分析 &#x1f33b;1. …

OpenHarmony轻量系统开发【3】代码编译和烧录

3.1源码目录 下载完代码后&#xff0c;大家可以进入代码目录&#xff1a; 这里重点介绍几个比较重要的文件夹&#xff1a; 1 vendor文件夹 该文件夹存放的是厂商相关的配置&#xff0c;包括组件配置、HDF相关配置&#xff0c;代码目录如下&#xff1a; 可以看到有hisilicon文…

LLMs之ToolAlpaca:ToolAlpaca(通用工具学习框架/工具使用语料库)的简介、安装和使用方法、案例应用之详细攻略

LLMs之ToolAlpaca&#xff1a;ToolAlpaca(通用工具学习框架/工具使用语料库)的简介、安装和使用方法、案例应用之详细攻略 目录 ToolAlpaca的简介 0、《ToolAlpaca: Generalized Tool Learning for Language Models with 3000 Simulated Cases》翻译与解读 1、数据集列表 2…

连续上榜!Coremail连续十一次入选《中国网络安全行业全景图》

4月12日&#xff0c;国内专业权威咨询机构——安全牛&#xff0c;正式发布第十一版《中国网络安全行业全景图》&#xff08;以下简称“全景图”&#xff09;。该全景图包含了16项一级安全分类&#xff0c;108项二级安全分类&#xff0c;共收录454家网络安全厂商。 Coremail作为…

【保姆级】2024年OnlyFans订阅指南

OnlyFans是一个独特的社交媒体平台&#xff0c;它为创作者和粉丝提供了一个互动交流的空间。通过这个平台&#xff0c;创作者可以分享他们的独家内容&#xff0c;而粉丝则可以通过订阅来支持和享受这些内容。如果你对OnlyFans感兴趣&#xff0c;并希望成为其中的一员&#xff0…

D365开发-在视图按钮的js里,引用别的js里的公共方法

公共方法写法&#xff1a; "use strict"; var JJMC window.JJMC || {}; JJMC.SamMCommon JJMC.SamMCommon || {}; (function () { this.cloneRecord function (excludeAttrbuteNames){ / } }).call(JJMC.SamMCommon); 然后在需要调方法的command里面&#xff0c;之…

PNPM 8管理Node版本,卸载了旧版本Node找不到PNPM

前言 用 pnpm env 来管理 node 的版本&#xff0c;安装了新版本之后&#xff0c;卸载了之前的旧版本&#xff0c;调用 pnpm 报错 异常截图 解决方式 从终端获取报错文件到路径&#xff0c;进入编辑修改错误的 node bin 路径为正确的 node 启动路径即可也就是修改 "/Use…

vite+vue3+antDesignVue 记录-持续记录

记录学习过程 持续补充 每天的学习点滴 开始时间2024-04-12 1&#xff0c;报错记录 &#xff08;1&#xff09;env.d.ts文件 解决方法&#xff1a; 在env.d.ts文件中添加以下代码&#xff08;可以看一下B站尚硅谷的讲解视频&#xff09; declare module *.vue {import { Defi…

SpringBoot基于RabbitMQ实现消息延迟队列方案

知识小科普 在此之前&#xff0c;简单说明下基于RabbitMQ实现延时队列的相关知识及说明下延时队列的使用场景。 延时队列使用场景 在很多的业务场景中&#xff0c;延时队列可以实现很多功能&#xff0c;此类业务中&#xff0c;一般上是非实时的&#xff0c;需要延迟处理的&a…

宠物品牌出海 丨战略布局这样做让你爆单不停

宠物用品市场在电商领域增长迅速。面对国内市场竞争激烈&#xff0c;同质化严重&#xff0c;不少宠物用品公司开始寻求新的市场增长点&#xff0c;将目光转向国外市场。本文将探讨宠物品牌海外扩张的商机和策略&#xff0c;以便帮助其他公司应对挑战&#xff0c;抓住国际市场的…

利用国产库libhv动手写一个web_server界面(二)

目录 一、配置参数解析与响应 1.读取参数 2.设置参数 3.恢复默认参数 二、整体的界面实现以及交互效果 三、关于yaml文件乱码问题解决 四、参考文章 一、配置参数解析与响应 使用cJSON解析库&#xff0c;解析接收到的JSON数据字段&#xff0c;区别接收到的配置参数是请…