首页 文章 精选 留言 我的

精选列表

搜索[提高],共10000篇文章
优秀的个人博客,低调大师

想提高查询性能,用GaussDB(DWS) in表达式还是or表达式?

摘要:在本文中,我将重点分析在各种通用场景下,IN 运算符和 OR 运算符查询的性能差异,并探索这些性能差异背后的原因,目的是为了帮助DWS用户最大化的提升其查询性能。 本文分享自华为云社区 《GaussDB(DWS) in表达式还是or表达式》 ,作者:一只小兵。 前言 适用版本:【9.1.0(及以上)】 声明式查询语言(如 SQL)的最初想法是,用户直接要求数据库管理系统 (DBMS) 给出其想要的答案,而无需考虑其计算方式与计算过程。DBMS的查询优化器负责确定查询的最高效执行计划。理想情况下,如果您使用不同的 SQL 命令提出相同的问题,DBMS应该选择相同的最佳计划。遗憾的是,实际情况并非总是如此,查询性能通常取决于用户编写查询的方式。有时对SQL 进行简单的改写即能得到显著的性能提升。 在WHERE语句中使用IN和OR运算符对查询的结果做过滤是上述问题的代表场景之一,如下面的查询语句范例,它们产生的查询结果是一致的,但执行的时间可能不同: 在本文中,我将重点分析在各种通用场景下,IN 运算符和 OR 运算符查询的性能差异,并探索这些性能差异背后的原因,目的是为了帮助DWS用户最大化的提升其查询性能。 TL;DR: IN运算符在部分场景性能远优于OR运算符,在其他场景下两种运算符性能基本一致。本文推荐在查询中尽量使用IN运算符,对于具有大量谓词的查询尤其如此 。 实验数据准备 声明:本文重点比较IN运算符与OR运算符的执行性能差异,差异比例可做参考,查询的绝对执行时间则无参考价值。 -- 建表, DWS列存,hstore_opt表,并声明id列为primary key。 CREATE TABLE item( id INTEGER NOT NULL, name VARCHAR(30), price INTEGER, quantity INTEGER, primary key (id) ) WITH (orientation=COLUMN, enable_hstore_opt=TRUE); -- 随机插入两百万行数据。 INSERT INTO item SELECT id, SUBSTR(MD5(RANDOM()::text), 0, 20) AS name, (RANDOM() * 10000)::int AS price, (RANDOM() * 10000)::int AS quantity FROM generate_series(1, 2000000) AS t(id); -- Merge all data from hstore delta table info CU. select hstore_full_merge('item'); 本实验使用Hstore OPT列存表,开启Turbo执行引擎。由于Hstore Opt表在单行数据插入时,会先插入delta表,并异步写成CU中。本文为了去除查询delta表对实验数据的影响,手动执行一次merge,保证所有delta表中数据都已写入CU。 单一属性过滤 我们首先比较使用单一列过滤的性能差异,大部分复制查询的内部都包含对单一列进行过滤的场景。 单个索引属性 首先,当单一属性上声明了索引,我们检验在WHERE 子句中使用单个 IN 运算符和使用多个 OR 子句运行相同的查找的性能差异。上诉语句声明中,id列声明为唯一列,DWS会自动为此列创建索引,我们使用此列进行下列的实验。我们首先运行IN语句,然后运行OR语句,并不断的增加条件中需要查找的ID个数。 -- IN expression SELECT * FROM item WHERE id IN (...); -- OR expression SELECT * FROM item WHERE id = ? OR id = ? OR ... ; 下图显示了性能数据对比。理论上,两个查询在同一张表上计算相同的结果,优化器应该总能能选出最优的执行方式,从而上述个查询执行的时间应该相同。然而,当过滤条件较少时,两种表达式的执行时间相差不大。而随着过滤条件的个数增加,IN运算符的执行速度远快于OR运算符。当过滤条件个数为1000时,IN运算符比OR运算符快了10倍(48ms vs 501ms)。 为了理解出现这种情况的原因,让我们来看一下上面两种运算符分别对应的执行计划的差异: postgres=# explain SELECT * FROM item where id in (1559267,311557,234010,1863199,876092,580136,1116400,575622,380796,1518233); QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- id | operation | E-rows | E-memory | E-width | E-costs ----+------------------------------------------+--------+----------+---------+--------- 1 | -> Row Adapter | 10 | | 43 | 63.79 2 | -> Vector Streaming (type: GATHER) | 10 | | 43 | 63.79 3 | -> CStore Index Heap Scan on item | 10 | 16MB | 43 | 57.79 4 | -> CStore Index Ctid Scan | 10 | 1MB | 0 | 38.12 Predicate Information (identified by plan id) --------------------------------------------------------------------------------------------------------------------------- 3 --CStore Index Heap Scan on item Recheck Cond: (id = ANY ('{1559267,311557,234010,1863199,876092,580136,1116400,575622,380796,1518233}'::integer[])) 4 --CStore Index Ctid Scan Index Cond: (id = ANY ('{1559267,311557,234010,1863199,876092,580136,1116400,575622,380796,1518233}'::integer[])) postgres=# explain SELECT * FROM item WHERE id = 1559267 OR id = 311557 OR id = 234010 OR id = 1863199 OR id = 876092 OR id = 580136 OR id = 1116400 OR id = 575622 OR id = 380796 OR id = 1518233; QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- id | operation | E-rows | E-memory | E-width | E-costs ----+-----------------------------------------------------------------+--------+----------+---------+--------- 1 | -> Row Adapter | 10 | | 43 | 61.99 2 | -> Vector Streaming (type: GATHER) | 10 | | 43 | 61.99 3 | -> CStore Index Heap Scan on item | 10 | 16MB | 43 | 55.99 4 | -> CStore Index Or(5, 6, 7, 8, 9, 10, 11, 12, 13, 14) | 10 | 1MB | 0 | 36.25 5 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.62 6 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.62 7 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.62 8 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.62 9 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.62 10 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.62 11 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.62 12 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.62 13 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.62 14 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.62 Predicate Information (identified by plan id) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 3 --CStore Index Heap Scan on item Recheck Cond: ((id = 1559267) OR (id = 311557) OR (id = 234010) OR (id = 1863199) OR (id = 876092) OR (id = 580136) OR (id = 1116400) OR (id = 575622) OR (id = 380796) OR (id = 1518233)) 5 --CStore Index Ctid Scan Index Cond: (id = 1559267) 6 --CStore Index Ctid Scan Index Cond: (id = 311557) 7 --CStore Index Ctid Scan Index Cond: (id = 234010) 8 --CStore Index Ctid Scan Index Cond: (id = 1863199) 9 --CStore Index Ctid Scan Index Cond: (id = 876092) 10 --CStore Index Ctid Scan Index Cond: (id = 580136) 11 --CStore Index Ctid Scan Index Cond: (id = 1116400) 12 --CStore Index Ctid Scan Index Cond: (id = 575622) 13 --CStore Index Ctid Scan Index Cond: (id = 380796) 14 --CStore Index Ctid Scan Index Cond: (id = 1518233) IN运算符首先进行Index Ctid Scan扫描主键索引以获取满足条件的行ctid,索引过滤的条件为IN条件。获取到所有满足的Ctid后,进行Index Heap Scan查询原表,获取并返回所有用户所需列。 OR运算符也是首先进行Index Ctid Scan扫描主键索引表,但索引的过滤条件为单个谓词,每个OR条件都需要执行一次查找。查找完成后进行Index OR汇总,最后也是进行Index Heap Scan查询原表。 OR运算符性能较差的原因在于需要为每个谓词做一次索引扫描并建立一个位图,即id = 1 为一个位图,id = 2 为一个位图等等。随后进行按位或组合这些位图。在谓词个数为1000时,需要进行1000次索引扫描并生成1000个位图,与只进行一此索引扫描的IN运算符相比,效率大大降低。并且随着谓词个数的增加,性能差别会逐步拉大。 单个未索引属性 接下来,我们基于单个未索引属性(price)进行相同的比较:一个使用单个 IN 子句,另一个使用多个带有相等谓词的 OR 子句。然后,我们增加每个查询的谓词个数。 -- IN expression SELECT * FROM item WHERE price IN (...); -- OR expression SELECT * FROM item WHERE price = ? OR price = ? OR ... ; 下图显示了性能数据对比。IN表达式的性能依旧优于OR表达式,并且性能差距相比索引属性更大。在谓词个数为1000时,性能差别达到了40倍(150ms vs 6399ms)。 让我们依旧通过生成的执行计划来看差异的原因: postgres=# explain SELECT * FROM item where price in (1988,5547,6631,4931,5752,2119,9647,3724,5146,873); QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------- id | operation | E-rows | E-memory | E-width | E-costs ----+----------------------------------------+--------+----------+---------+---------- 1 | -> Row Adapter | 1921 | | 43 | 19105.85 2 | -> Vector Streaming (type: GATHER) | 1921 | | 43 | 19105.85 3 | -> CStore Scan on item | 1921 | 1MB | 43 | 19015.85 Predicate Information (identified by plan id) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ --------------------------- 3 --CStore Scan on item CU Predicate Filter: (price = ANY ('{1988,5547,6631,4931,5752,2119,9647,3724,5146,873}'::integer[])) Pushdown Predicate Filter: (((price >= 873) AND (price <= 9647)) AND ((price = 1988) OR (price = 5547) OR (price = 6631) OR (price = 4931) OR (price = 5752) OR (price = 2119) OR (price = 9647) OR (price = 3724) OR (price = 5146) OR (price = 873))) postgres=# explain SELECT * FROM item where price = 1988 OR price = 5547 OR price = 6631 OR price = 4931 OR price = 5752 OR price = 2119 OR price = 9647 OR price = 3724 OR price = 5146 OR price = 873; QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- id | operation | E-rows | E-memory | E-width | E-costs ----+----------------------------------------+--------+----------+---------+---------- 1 | -> Row Adapter | 1921 | | 43 | 31356.73 2 | -> Vector Streaming (type: GATHER) | 1921 | | 43 | 31356.73 3 | -> CStore Scan on item | 1921 | 1MB | 43 | 31266.73 Predicate Information (identified by plan id) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 3 --CStore Scan on item Filter: ((price = 1988) OR (price = 5547) OR (price = 6631) OR (price = 4931) OR (price = 5752) OR (price = 2119) OR (price = 9647) OR (price = 3724) OR (price = 5146) OR (price = 873)) Pushdown Predicate Filter: ((price = 1988) OR (price = 5547) OR (price = 6631) OR (price = 4931) OR (price = 5752) OR (price = 2119) OR (price = 9647) OR (price = 3724) OR (price = 5146) OR (price = 873)) 从计划上来看,IN运算符与OR运算符的执行算子一致,唯一不同的是Predicate Information。IN运算符生成的是CU Predicate Filter, OR运算符生成的是Filter。 CU Predicate Filter意味着此过滤条件下推到了存储层过滤,这样的做法可以减少了性能消耗。原因在于其直接在读CU(DWS列存表单列数据的基本存储单位)的时候就将不必要的数据过滤掉,而无需将其先填入Batch(DWS执行引擎中单列数据的基本存储单位)中,然后在执行器中进行过滤。 除此以外,可以看到IN运算符的过滤条件为ANY,而OR运算符的过滤条件为OR。当起ANY条件下推到存储层时,存储层会生成一个临时的哈希表,并将条件中的谓词都存入哈希表中。相比多个OR条件,在进行过滤时,只需进行一次哈希比较,而无需逐个谓词比较,算法复杂度由O(N)变成了O(1),大大的提升了执行性能。 需要注意的是,截止到本文撰写的时间,只有部分场景的IN运算符支持下推到存储层。让我们来看一下当不支持下推到存储层时,执行层执行IN运算符的性能如何。 为了方便起见,这里不特意构造不下推的语句了,而是简单的通过设置GUC参数enable_cu_predicate_pushdown来关闭存储层下推: postgres=# set enable_cu_predicate_pushdown = off; SET 以下是性能数据比较: 可以看到,虽然IN + 执行层运算相比IN直接下推到存储层运行的性能较差,但相差不远。及时没有下推到存储层,IN运算符的性能相比OR运算符依旧有较大的提升。 让我们来分析一下是IN运算符在执行层的执行的计划: postgres=# explain SELECT * FROM item where price in (1988,5547,6631,4931,5752,2119,9647,3724,5146,873); QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------- id | operation | E-rows | E-memory | E-width | E-costs ----+----------------------------------------+--------+----------+---------+---------- 1 | -> Row Adapter | 1921 | | 43 | 19105.85 2 | -> Vector Streaming (type: GATHER) | 1921 | | 43 | 19105.85 3 | -> CStore Scan on item | 1921 | 1MB | 43 | 19015.85 Predicate Information (identified by plan id) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ --------------------------- 3 --CStore Scan on item Filter: (price = ANY ('{1988,5547,6631,4931,5752,2119,9647,3724,5146,873}'::integer[])) Pushdown Predicate Filter: (((price >= 873) AND (price <= 9647)) AND ((price = 1988) OR (price = 5547) OR (price = 6631) OR (price = 4931) OR (price = 5752) OR (price = 2119) OR (price = 9647) OR (price = 3724) OR (price = 5146) OR (price = 873))) 可以看到,其生成的Predicate Information 与OR条件同样为“Filter”。表示其未下推到存储层执行过滤。但是在执行层,DWS依旧会为IN运行符生成临时哈希表,将O(N)的算法复杂度优化到O(1)。所以其性能依旧远远好于OR表达式,且随着谓词个数增多,性能优势越明显。 多属性过滤 接下来,我们评估在两个属性列上分布使用IN运算符与OR运算符进行过滤的差异。首先,我们评估当两个属性都是/不是索引列的情况,然后我们评估两个属性中只有一个属性是/不是索引列的情况。 TL;DR: 在多属性场景下,DWS为IN查询与OR查询生成的计划是相同的,故他们的执行性能一致。在此等场景下,使用IN运算符与OR运算符并无差别。 两个索引属性 首先基于两个属性(name、price)创建一个复合索引(idx_item_name_quantity): postgres=# create index idx_item_name_quantity on item (name, quantity); CREATE INDEX 使用复合索引中两个属性(name、price)过滤的查询如下: SELECT * FROM item WHERE (name, quantity) IN (('a', 1), ('b', 2)); SELECT * FROM item WHERE (name='a' AND quantity=1) OR (name='b' AND quantity=2) 执行计划如下: postgres=# explain SELECT * FROM item WHERE (name, quantity) IN (('a', 1), ('b', 2)); QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------- id | operation | E-rows | E-memory | E-width | E-costs ----+------------------------------------------+--------+----------+---------+--------- 1 | -> Row Adapter | 2 | | 43 | 17.24 2 | -> Vector Streaming (type: GATHER) | 2 | | 43 | 17.24 3 | -> CStore Index Heap Scan on item | 2 | 16MB | 43 | 11.24 4 | -> CStore Index Or(5, 6) | 2 | 1MB | 0 | 7.22 5 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.61 6 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.61 Predicate Information (identified by plan id) -------------------------------------------------------------------------------------------------------------------------- 3 --CStore Index Heap Scan on item Recheck Cond: ((((name)::text = 'a'::text) AND (quantity = 1)) OR (((name)::text = 'b'::text) AND (quantity = 2))) 5 --CStore Index Ctid Scan Index Cond: (((name)::text = 'a'::text) AND (quantity = 1)) 6 --CStore Index Ctid Scan Index Cond: (((name)::text = 'b'::text) AND (quantity = 2)) OR运算符与IN运算符的执行计划一模一样,可以知道他们的执行性能将一致,这里就进行性能数据比较了。 从上述计划可以看到,DWS优化器先将IN语句转换为OR语句,然后针对语句中的每个谓词条件,执行一次索引扫描获取对应的Ctid,并生成位图,然后进行位图OR运行合并,最后进行原表扫描获取所有的查询列。 两个未索引属性 首先将上述创建的索引删除: postgres=# drop index idx_item_name_quantity; DROP INDEX 基于两个未索引属性的查询如下: SELECT * FROM item WHERE (name, quantity) IN (('a', 1), ('b', 2)); SELECT * FROM item WHERE (name='a' AND quantity=1) OR (name='b' AND quantity=2) IN语句与OR语句的执行计划也是一致的: postgres=# explain SELECT * FROM item WHERE (name, quantity) IN (('a', 1), ('b', 2)); QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------- id | operation | E-rows | E-memory | E-width | E-costs ----+----------------------------------------+--------+----------+---------+---------- 1 | -> Row Adapter | 2 | | 43 | 16564.78 2 | -> Vector Streaming (type: GATHER) | 2 | | 43 | 16564.78 3 | -> CStore Scan on item | 2 | 1MB | 43 | 16558.78 Predicate Information (identified by plan id) --------------------------------------------------------------------------------------------------------------------------------------- 3 --CStore Scan on item Filter: ((((name)::text = 'a'::text) AND (quantity = 1)) OR (((name)::text = 'b'::text) AND (quantity = 2))) Pushdown Predicate Filter: ((((name)::text = 'a'::text) AND (quantity = 1)) OR (((name)::text = 'b'::text) AND (quantity = 2))) postgres=# explain SELECT * FROM item WHERE (name='a' AND quantity=1) OR (name='b' AND quantity=2) QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------- id | operation | E-rows | E-memory | E-width | E-costs ----+----------------------------------------+--------+----------+---------+---------- 1 | -> Row Adapter | 2 | | 43 | 16564.78 2 | -> Vector Streaming (type: GATHER) | 2 | | 43 | 16564.78 3 | -> CStore Scan on item | 2 | 1MB | 43 | 16558.78 Predicate Information (identified by plan id) --------------------------------------------------------------------------------------------------------------------------------------- 3 --CStore Scan on item Filter: ((((name)::text = 'a'::text) AND (quantity = 1)) OR (((name)::text = 'b'::text) AND (quantity = 2))) Pushdown Predicate Filter: ((((name)::text = 'a'::text) AND (quantity = 1)) OR (((name)::text = 'b'::text) AND (quantity = 2))) 根据计划可以看出,在此情况下,DWS并不会针对IN表达式进行临时表哈希优化,也不会下推到存储层进行过滤。 一个属性有索引 + 一个属性无索引 接下来,我们检验一个属性(id)索引,一个属性(price)无索引的过滤情况。 查询语句如下: SELECT * FROM item WHERE (id, price) IN ((1, 1), (2, 2)); SELECT * FROM item WHERE (id=1 AND price=1) OR (id=2 AND price=2) 在此场景下IN语句与OR语句生成的执行计划也是一致的,故其性能基本相同: postgres=# explain SELECT * FROM item WHERE (id, price) IN ((1, 1), (2, 2)); QUERY PLAN ----------------------------------------------------------------------------------------- id | operation | E-rows | E-memory | E-width | E-costs ----+------------------------------------------+--------+----------+---------+--------- 1 | -> Row Adapter | 1 | | 43 | 17.27 2 | -> Vector Streaming (type: GATHER) | 1 | | 43 | 17.27 3 | -> CStore Index Heap Scan on item | 1 | 16MB | 43 | 11.27 4 | -> CStore Index Or(5, 6) | 2 | 1MB | 0 | 7.25 5 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.62 6 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.62 Predicate Information (identified by plan id) -------------------------------------------------------------------------- 3 --CStore Index Heap Scan on item Recheck Cond: ((id = 1) OR (id = 2)) Filter: (((id = 1) AND (price = 1)) OR ((id = 2) AND (price = 2))) 5 --CStore Index Ctid Scan Index Cond: (id = 1) 6 --CStore Index Ctid Scan Index Cond: (id = 2) postgres=# explain SELECT * FROM item WHERE (id=1 AND price=1) OR (id=2 AND price=2); QUERY PLAN ----------------------------------------------------------------------------------------- id | operation | E-rows | E-memory | E-width | E-costs ----+------------------------------------------+--------+----------+---------+--------- 1 | -> Row Adapter | 1 | | 43 | 17.27 2 | -> Vector Streaming (type: GATHER) | 1 | | 43 | 17.27 3 | -> CStore Index Heap Scan on item | 1 | 16MB | 43 | 11.27 4 | -> CStore Index Or(5, 6) | 2 | 1MB | 0 | 7.25 5 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.62 6 | -> CStore Index Ctid Scan | 1 | 1MB | 0 | 3.62 Predicate Information (identified by plan id) -------------------------------------------------------------------------- 3 --CStore Index Heap Scan on item Recheck Cond: ((id = 1) OR (id = 2)) Filter: (((id = 1) AND (price = 1)) OR ((id = 2) AND (price = 2))) 5 --CStore Index Ctid Scan Index Cond: (id = 1) 6 --CStore Index Ctid Scan Index Cond: (id = 2) 从计划可以看出,针对有索引属性( id), DWS会先进行索引扫描过滤,后进行位图合并。在最后扫描原表数据时,再把另外一个属性的过滤条件加上。 总结 根据上述的实验可以发现,在对单个属性进行过滤时,DWS对带有 IN 查询始终表现出对 OR 查询相当或更好的性能。对于具有大量谓词的查询尤其如此。 关于下推到存储层的优化,截止到本文发布时间,只有在IN运算符是除与WHERE语句中才会生效,并且IN查询单一属性的类型有要求,目前支持INT, NUMERIC,DATE,VARCHAR等,对于其他类型则不支持下推。而在执行层使用临时哈希表加速的功能适用于所有类型,并且为了平衡哈希本身带来的消耗与使用哈希获取的性能收益,只有当IN运算符中条件个数较多时才生效,如大于10个。 当根据多个属性进行过滤时,IN 和 OR 查询具有相同的性能,DWS优化器为两种查询生成的计划是一致的。 因此,我们建议您尽量使用 IN 子句,以最大化的提升查询的性能。 点击关注,第一时间了解华为云新鲜技术~ 询问AI

优秀的个人博客,低调大师

提高API采用率的关键:快速创建有效的API监控任务

为什么需要API监控? 在当今数字化时代,企业应用程序及网站越来越依赖于外部 API 和第三方应用程序提供商。例如一家电商公司,他们的网站可能同时会接入多个外部API,包括支付、物流、广告等服务。如果在用户购买商品时,恰巧出现了支付API故障,就会导致用户无法完成付款动作,从而影响公司的整体营收。API的可靠性直接关系到公司的业务运转。当应用程序中的API出现问题时,会影响到整个网站或应用程序的性能,甚至会导致网站或应用程序直接崩溃。因此,API监控变得至关重要。 监控宝API监控 监控宝提供的API监控能够利用全球近百个监测点,实时监控API的运行状况,包括可用性、正确性、响应时间等性能数据。通过实时告警和历史统计分析,帮您快速发现并解决问题,节约企业的运维成本,减少业务损失。监控宝的API监控能够: 实时监控get、post、put、delete、head、options六种API请求方式,覆盖绝大部分的接口调用格式。 支持JSON、XML、Text、Response Header、状态码验证及Postman,JMeter脚本导入。 通过断言功能监测正确性,支持监控多步请求,从而实现对整个业务流程的监控。 API监控包括可用性、正确性、响应时间、可用率、故障率、正确率、平均可用率、平均正确率、平均响应时间、错误总时长、错误总次数、故障总时长、故障总次数13个监控指标。判断和计算规则如下: 创建监控任务 配置入口:API监控>任务管理 单击创建项目创建API监控任务,需要配置监控任务的基本信息、事务设置、监控设置和告警设置。 设置基本信息 在创建API监控任务页面设置监控任务的基本信息,包括定义任务名称、选择项目是否加入分类。如下图所示。 任务名称 输入任务名称,以便于查找和区分监控对象。您需要为监控任务设置一个有代表性的名称,例如您需要监控在淘宝中提交订单的业务流程,则可设置监控任务名称为“淘宝-提交订单”。 项目是否加入分类 为方便管理自己创建的监控任务,您可为当前监控任务选择一个项目分类。您还可以单击创建分类,新建一个项目分类作为当前监控任务的分类。 设置初始变量 您可利用变量来存储值,动态地提取HTTP响应数据,并在多个请求之间动态地传递数据和状态。比如,添加请求1时,可通过设置变量$a来动态提取Response Header中的Date值。然后在添加请求2时,使用变量a作为断言的目标值。使用变量时需要提前初始化变量,即为变量赋默认值。 在创建API监控任务的事务设置页面,单击设置初始化变量,添加并管理初始变量,如下图所示。 设置自定义变量 在自定义变量页面区域,单击添加变量添加一个变量,设置变量名称和变量值。自定义变量仅应用于本监控任务。注意:变量名称必须以$符号开头,并且是纯字母组成。除自定义变量外,您可以查看系统变量及自定义系统变量,系统变量可用于所有监控任务的API请求。 设置系统变量 在系统变量页面区域,单击自定义页签,单击添加变量添加系统变量,定义变量名称和变量描述信息。注意:在自定义系统变量时,变量名称必须以$public_开头。在系统变量页面区域,单击公共函数页签,查看可用的系统变量,详细说明见下表。 设置事务 在创建API监控任务的事务设置中添加并管理需要监控的API请求。 您能够直接导入脚本来添加API请求,也可手动添加和设置API请求。添加API请求后,可直接复制已添加的请求来创建新的请求。 通过导入脚本添加API请求 为快速创建多条API请求,单击导入脚本,在打开的对话框中直接输入脚本内容并导入。导入成功后,监控宝根据导入的脚本自动创建对应的API请求。在打开的导入脚本对话框,单击查看实例了解脚本样式,脚本支持Postman和JMeter格式。您可以直接使用Postman中生成的脚本。 手动添加API请求 单击添加请求,打开请求编辑页面,如下图所示。 根据实际需要设置各项内容,详细说明见下表。 复制API请求 为避免重复设置,添加API请求后,您可单击【复制按钮】复制当前API请求作为一条新的API请求,根据需要修改相应内容即可。 移动API请求 当添加多个API请求,如果需要调换请求的先后顺序,鼠标拖动目标请求移动到目标位置。 添加请求间隔 单击添加请求间隔,输入发送API请求的时间间隔,例如设置“10s”,则发送一次API请求后,等待10s发送第二次API请求。 测试API监控请求 添加API请求后,为保证正常监控,需检查是否能请求成功。单击验证测试来测试请求并查看测试结果,如下图所示。 请求成功即可用,所有请求都成功时,监控任务(即整个业务流程)的状态为正常且可用,单击展开>返回结果,查看请求的返回结果。添加断言时才能测试请求的正确性,所有请求都正确时监控任务的正确性为“是”,单击展开>变量与断言,查看断言详情。 设置监控 在创建API监控任务的监控设置中,设置监测点和监控频率,如下图所示。 监测点选择相应的监测点对目标API进行监测。您可以选择多个监测点也可以创建/选择一个监测点分组。所选择的监测点或监测点分组的成员均用来监测目标网API。 选择监测点:根据需求选择多个监测点。 选择监测点分组:选择或创建监测点分组。若分组内监测点成员有所变化,任务创建后仍会同步。 注意:选择监测点分组后,监测点分组中的所有监测点都发生故障时才会向您发送告警消息。 监控频率:监控宝执行监控的时间间隔,例如选择2分钟,则监控宝每隔2分钟就执行一次监控。 设置告警 在创建API监控任务的告警设置中,设置常规告警重试次数,连续连续告警提醒,告警线,企业IM通知及告警方式,如下图所示。 告警设置项说明如下表所示: 小结 在过去的封闭系统中,如果出现故障,只会对该系统内的应用程序产生影响,而对于现在大部分企业来说,一个故障就会影响到整个生态系统。监控宝可以利用全球近百个监测点,实时监控API的运行状况,保障企业运维效率及用户体验。点击此处,马上申请监控宝免费试用名额

优秀的个人博客,低调大师

Java 引入预览版虚拟线程功能,大幅提高应用吞吐量

OpenJDK 的 JEP 425 :虚拟线程(预览版)功能提案显示: Java 平台将引入虚拟线程特性。虚拟线程是轻量级线程,可显著地减少编写、维护和观察高吞吐量并发应用程序的工作量。 Java 开发人员一直依赖线程作为并发服务器应用程序的构建块,每个方法中的语句都在一个线程内执行,每个线程提供一个堆栈来存储局部变量和协调方法调用,以及报错时的上下文捕获。线程是 Java 的并发单元,也是 Java 工具的核心基础:调试器逐步执行线程方法中的语句,分析器则可视化多个线程的行为。 目前,JDK 将其平台线程实现为操作系统 (OS) 线程的包装器,JDK 中每个实例都是一个平台线程,平台线程在底层操作系统线程上运行 Java 代码 ,并在代码的整个生命周期内捕获 OS 线程。平台线程数受限于 OS 线程数,而OS 线程的成本很高,不能占用太多。因此,目前 JDK 的这种线程实现方法限制了其应用程序的吞吐量,使吞吐量远低于硬件支持的水平。 关于虚拟线程 虚拟线程java.lang.Thread是在底层操作系统线程(OS 线程)上运行 Java 代码,但在代码的整个生命周期内不捕获 OS 线程的实例。这意味着许多虚拟线程可以在同一个 OS 线程上运行 Java 代码,从而有效地共享它。 虚拟线程是由 JDK 而不是操作系统提供的线程的轻量级实现,也是用户模式线程的一种形式。用户模式线程在 Java 的早期版本中被称为“绿色线程”,当时操作系统线程的概念还不够成熟和普及, Java 的所有绿色线程都共享一个 OS 线程(M:1 调度),随着线程概念的发展,绿色线程最终被现在的平台线程超越,实现为 OS 线程的包装器(1:1 调度),而最新引入的虚拟线程采用 M:N 调度,其中大量 (M) 虚拟线程被调度为在较少数量 (N) 的 OS 线程上运行。 更高的吞吐量 开发者可以选择使用虚拟线程还是平台线程,但虚拟线程在高吞吐量的服务器应用程序中表现更好。比如下面这段休眠一秒钟的代码就创建了大量的虚拟线程,程序首先获得一个ExecutorService,它为每个提交的任务创建一个新的虚拟线程,然后提交 10000 个任务并等待所有任务完成:: try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { IntStream.range(0, 10_000).forEach(i -> { executor.submit(() -> { Thread.sleep(Duration.ofSeconds(1)); return i; }); }); } // executor.close() is called implicitly, and waits 现代硬件可以很容易地支持 10000 个虚拟线程同时运行这样的代码。如果该程序使用为每个任务都创建一个新平台线程的 ExecutorService,例如 Executors.newCachedThreadPool() ,那么它将尝试创建 10000 个平台线程,也就意味着 10000 个 OS 线程,那么这个程序在大多数操作系统上都会崩溃。又或者这个程序使用从池中获取平台线程的 ExecutorService,如 Executors.newFixedThreadPool(200),也好不到哪去。 ExecutorService 将创建 200 个平台线程供这 10000 个任务共享,任务将按顺序运行而不是同时运行,程序需要很长时间才能跑完。 对于上述程序来说,具有 200 个平台线程的池只能实现每秒 200 个任务的吞吐量,而虚拟线程可以实现大约每秒 10000 个任务的吞吐量(在充分预热之后)。此外,如果将示例程序中的 10000 更改为 1,000,000 ,则程序将提交 1,000,000 个任务,创建 1,000,000 个并发运行的虚拟线程,并且(在充分预热后)达到大约 1,000,000 个任务/秒的吞吐量。 总而言之,虚拟线程不是更快的线程 —— 它们运行代码的速度并不比平台线程快。它们的存在是为了提供规模(更高的吞吐量),而不是速度(更低的延迟)。 如何启用虚拟线程? 目前虚拟线程在其他多线程语言中被广泛使用(例如 Go 中的 goroutine 和 Erlang 中的进程,在 C++ 中也是一个稳定特性),但在 Java 中还是一个预览 API,默认禁用。如要在 JDK XX 上尝试该功能,则必须通过以下方法启用预览 API: 使用 javac --release XX --enable-preview Main.java 编译程序,并使用 java --enable-preview Main 运行 使用源代码启动器时,使用 java --release XX --enable-preview Main.java 运行程序 使用 jshell 时,用 jshell --enable-preview 启动 有关虚拟线程的更多信息可在 OpenJDK 的JDK Issue-8277131中查看,目前该提案于 2021/11/15 创立,目前还处于 JEP 流程的第一阶段,距离稳定版本还需要一段时间。

优秀的个人博客,低调大师

KDE Plasma 5.22 发布,全面提高稳定性和可用性

KDE Plasma 5.22 现已发布。官方表示,该版本比以往更加可靠和稳定,通过在清理后台和重构代码,Plasma 桌面带来了更快的响应速度和性能。同时,将Plasma 全部转移到 Wayland(未来的显示协议)的工作仍在全面进行,以提供更好的体验和更强的稳定性。 自适应透明度 该版本具有自适应透明度,这意味着面板和面板部件通常是半透明的,但如果有任何最大化的窗口,就会变得完全不透明,以避免在用户需要集中注意力时出现任何视觉干扰。用户也可以设置面板总是半透明或总是不透明的。 搜索菜单项 全局菜单小程序现在可以让用户在 Wayland 上搜索菜单项。此外,当把鼠标悬停在面板上的任务管理器中的一个应用程序的图标时,会出现一个工具提示,以展示该应用程序打开的所有窗口的预览。并且该版本将使用 Plasma System Monitor 作为默认的系统监控应用程序。 系统设置 Plasma 5.22 的系统设置可以在一个快速页面上打开,让用户直接进入最常用的设置或者最常访问的设置。它包括一个改变墙纸设置,以对整体外观进行更多调整。此外,用户现在可以在设置中禁用软件的离线更新功能。 系统面板 该版本的系统面板(通常位于桌面的右下角)中的小工具在外观上更加一致,也更加实用。包括引入重新设计的数字时钟,以及点击时钟时弹出的日历外观,还有更加完善的音频音量小部件和剪贴板。 KRunner KRunner 是 Plasma 的迷你命令行启动器,现在可以显示多行文字,而不是单行。这意味着用户现在可以很方便地阅读长的字典定义。另外,KRunner 不再返回混乱的重复搜索结果,所以当用户搜索 "Firefox" 时,KRunner 现在只显示一个结果,而不是显示桌面应用程序、命令行应用程序、面板快捷方式等几个结果。 通知 在 Plasma 5.22 的 Wayland 会话中,通知小部件变得更加完善,如果用户正在分享或录制屏幕用于在线演示、课堂或视频,通知小部件会自动进入 "请勿打扰" 模式,暂停干扰性的弹出通知,直到用户完成。它还可以在从互联网下载被阻止时通知用户,更重要的是,当下载完成后,通知小工具可以知道并显示哪个应用程序将打开该文件。 KWin 和图形 KWin 是后台的窗口管理软件,从 Plasma 5.22 开始,KWin 支持 Wayland 上的可变刷新率/自由同步屏幕。这意味着,如果用户可以有多个屏幕,而且每个屏幕都设置不同的刷新率。此外,KWin 现在可以设置一个屏幕的过扫描值,这可以确保没有任何图像会在屏幕的边界之外被切断,也可以用来消除边缘的黑边。 其他 KWin Wayland 的改进包括 Present Windows 效果:当用户把光标移到屏幕的左上角时显示所有打开的窗口。它与 X11 上的效果完全一致。用户现在可以在垂直或水平方向上最大化窗口。支持插入外部显卡,KWin 会自动接收并配置它,而不需要重新启动 Plasma。 更多详细内容,请查看官方公告。

优秀的个人博客,低调大师

Google 提高 Android RAM 要求,低于 2GB 将强制使用 Android GO

外媒XDAdevelopers表示,其近日发现了一份泄露的 Google 文档,名为“Android 11 Go 版设备配置指南” (日期为 2020 年 4 月 24 日)。该文档内容显示, 对于新推出的配备 2GB RAM 或以下的低阶 Android 手机,Google计划强制预载 Android Go 版本系统。 一些具体内容如下: 从 Android 11 开始,具有 512MB RAM(包括升级)的设备将不符合预加载 GMS 的资格。 所有在 Android 11 上启动的新产品(如果它们具有 2GB 或更少的 RAM),必须为 ActivityManager.isLowRamDevice() API 返回 true,并作为 Android Go 设备启动。 从 2020 年第四季度开始,所有随 Android 10 一起启动的新产品(如果它们具有 2GB 或更少的 RAM),必须为 ActivityManager.isLowRamDevice()API 返回 true,并作为 Android Go 设备启动。 之前推出的标准 GMS 配置的 2GB RAM 设备,不应该通过 MRs 或 letter升级转换为 Android Go 配置。它们将保持标准的 Android版本。 也就是说,从 2020 年第四季度开始,任何运行 2GB 或更少 RAM 的新 Android 10 设备都必须使用 Android Go Edition。此外,任何使用 Android 11启动且具有 2GB 或更少 RAM 的设备也必须使用 Android Go。 不过已经上市的设备并不会受到影响。换句话说,对于已经在使用只有 1GB 容量的 Android 智能手机的用户来说,将不会有任何改变,其设备将像以前一样继续工作并接收更新。 谷歌的这些决定或许会让人们对低端 Android 设备的看法产生相当大的变化,将 Android Go 安装在 1GB 和 2G B设备上也意味着整体性能将会更好。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册