openGauss源码解析(31)

openGauss源码解析:第3章公共组件源码解析(7)

3.6 多维监控

数据库是企业的关键组件,数据库的性能直接决定了很多业务的吞吐量。为了简化数据库维护人员的调优,openGauss对数据库运行进行了多维度的监控,并且开发了一些维护特性,比如WDR(wordload dignostic report,工作负荷诊断报告)性能诊断报告、慢SQL诊断、会话性能诊断、系统KPI(key performance indicator,关键性能指标)辅助诊断等,帮助维护人员对数据库的性能进行诊断。这些监控项都以视图的方式对外呈现,集中在DBE_PERF模式下。WDR Snapshot除了自身快照的元数据,其他数据表来源也是DBE_PERF schema下的视图。WDR Snapshot数据表命名原则:snap_{源数据表},根据这个关系可以找到snap表所对应的原表。对这些视图的解释参照openGauss的官网(https://opengauss.org)中《开发者指南》手册的“DBE_PERF schema”章节。

性能视图的源代码在“openGauss-server\src\common\backend\catalog\performance_views.sql”文件中(网址为:https://gitee.com/opengauss/openGauss-server/blob/master/src/common/backend/catalog/performance_views.sql,安装后会复制到安装路径的“performance_views.sql”下)。在数据库初始化阶段由initdb读取这个文件在数据库系统中创建相应的视图。这些视图遵循了openGauss通用视图的实现逻辑,即视图来自函数的封装,这些函数可能是内置函数,也可能是存储函数。OS运行的性能视图“dbe_perf.get_global_os_runtime”的相关代码如下:

CREATE OR REPLACE FUNCTION dbe_perf.get_global_os_runtime

(OUT node_name name, OUT id integer, OUT name text, OUT value numeric, OUT comments text, OUT cumulative boolean)

RETURNS setof record

AS $$

DECLARE

row_data dbe_perf.os_runtime%rowtype;

query_str := 'SELECT * FROM dbe_perf.os_runtime';

FOR row_data IN EXECUTE(query_str) LOOP

......

END LOOP;

return;

END; $$

LANGUAGE 'plpgsql' NOT FENCED;

CREATE VIEW dbe_perf.global_os_runtime AS

SELECT DISTINCT * FROM dbe_perf.get_global_os_runtime();

global_os_runtime视图来自存储函数get_global_os_runtime的封装,在存储函数内访问“dbe_perf.os_runtime”视图、os_runtime视图的SQL语句为“CREATE VIEW dbe_perf.os_runtime AS SELECT * FROM pv_os_run_info();”。pv_os_run_info是内置函数,而内置函数负责读取数据库系统的监控指标,pv_os_run_info函数的相关代码如下:

Datum pv_os_run_info(PG_FUNCTION_ARGS)

{

FuncCallContext* func_ctx = NULL;

/* 判断是不是第一次调用 */

if (SRF_IS_FIRSTCALL()) {

MemoryContext old_context;

TupleDesc tup_desc;

/* 创建函数上下文 */

func_ctx = SRF_FIRSTCALL_INIT();

/*

* 切换内存上下文到多次调用上下文

*/

old_context = MemoryContextSwitchTo(func_ctx->multi_call_memory_ctx);

/* 创建一个包含5列的元组描述模板*/

tup_desc = CreateTemplateTupleDesc(5, false);

TupleDescInitEntry(tup_desc, (AttrNumber)1, "id", INT4OID, -1, 0);

TupleDescInitEntry(tup_desc, (AttrNumber)2, "name", TEXTOID, -1, 0);

TupleDescInitEntry(tup_desc, (AttrNumber)3, "value", NUMERICOID, -1, 0);

TupleDescInitEntry(tup_desc, (AttrNumber)4, "comments", TEXTOID, -1, 0);

TupleDescInitEntry(tup_desc, (AttrNumber)5, "cumulative", BOOLOID, -1, 0);

/* 填充元组描述模板 */

func_ctx->tuple_desc = BlessTupleDesc(tup_desc);

/* 收集系统信息 */

getCpuNums();

getCpuTimes();

getVmStat();

getTotalMem();

getOSRunLoad();

(void)MemoryContextSwitchTo(old_context);

}

/*设置函数的上下文,每次函数调用都需要*/

func_ctx = SRF_PERCALL_SETUP();

while (func_ctx->call_cntr < TOTAL_OS_RUN_INFO_TYPES) {

/* 填充所有元组每个字段的值 */

Datum values[5];

bool nulls[5] = {false};

HeapTuple tuple = NULL;

errno_t rc = 0;

rc = memset_s(values, sizeof(values), 0, sizeof(values));

securec_check(rc, "\0", "\0");

rc = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls));

securec_check(rc, "\0", "\0");

if (!u_sess->stat_cxt.osStatDescArray[func_ctx->call_cntr].got) {

ereport(DEBUG3,

(errmsg("the %s stat has not got on this plate.",

u_sess->stat_cxt.osStatDescArray[func_ctx->call_cntr].name)));

func_ctx->call_cntr++;

continue;

}

values[0] = Int32GetDatum(func_ctx->call_cntr);

values[1] = CStringGetTextDatum(u_sess->stat_cxt.osStatDescArray[func_ctx->call_cntr].name);

values[2] = u_sess->stat_cxt.osStatDescArray[func_ctx->call_cntr].getDatum(

u_sess->stat_cxt.osStatDataArray[func_ctx->call_cntr]);

values[3] = CStringGetTextDatum(u_sess->stat_cxt.osStatDescArray[func_ctx->call_cntr].comments);

values[4] = BoolGetDatum(u_sess->stat_cxt.osStatDescArray[func_ctx->call_cntr].cumulative);

tuple = heap_form_tuple(func_ctx->tuple_desc, values, nulls);

SRF_RETURN_NEXT(func_ctx, HeapTupleGetDatum(tuple));

}

/* 填充结束,返回结果 */

SRF_RETURN_DONE(func_ctx);

}

pv_os_run_info函数可以分为3段:

(1) 调用CreateTemplateTupleDesc函数和TupleDescInitEntry函数定义元组描述信息。
(2) 调用getCpuNums函数、getCpuTimes函数、getVmStat函数、getTotalMem函数、getOSRunLoad函数收集系统信息。
(3) 把收集的u_sess信息填充到元组数据中,最后返回给调用者。openGauss提供了实现返回结果的通用SQL函数的实现步骤和方法,它们是SRF_IS_FIRSTCALL、SRF_PERCALL_SETUP、SRF_RETURN_NEXT和SRF_RETURN_DONE。从代码可以看出,pv_os_run_info的实现流程也是遵循openGauss通用的SQL函数实现方法。

系统指标的收集来自读取系统信息,对数据库系统中一些模块进行打点(打点就是按照规格采集指定数据,用以记录系统运行的一些关键点)。很多打点集中在两个方面: 事务执行次数和执行时间。从而推断最大时间、最小时间、平均时间。这些比较分散,代码逻辑相对简单,这里不再进行介绍。只需要根据内置函数读取的变量查看这些变量赋值的地方就可以追踪具体的实现位置。

openGauss数据库主要维护特性的实现代码在“openGauss-server\src\gausskernel\cbb\instruments”目录中,比如WDR、SQL百分位计算,这里不再进行介绍。

性能统计对openGauss的正常运行也会带来一定的性能损耗,所以这些特性都有开关控制。具体说明如下。

(1) 等待事件信息实时收集功能的开关为enable_instr_track_wait。
(2) Unique SQL信息实时收集功能的开关为enable_instr_unique_sql、enable_instr_rt_percentile。
(3) 数据库监控快照功能的开关为enable_wdr_snapshot。

其他功能也都有相应的GUC参数进行调节,根据平常使用的需要,可以打开具体维护项查看系统的运行情况。

posted @ 2024-04-29 15:43  openGauss-bot  阅读(22)  评论(0编辑  收藏  举报