返回首页

gbase数据、南大通用产品文档:GBase8s数据库服务器线程对共享缓冲区的访问

更新日期:2024年09月11日

数据库服务器线程通过一系列队列访问共享缓冲区,并且使用互斥和锁定来同步访问以及
保护数据。

FIFO/LRU 队列
缓冲区为高速缓存而容纳数据。数据库服务器使用最近最少使用 (LRU) 队列来替换高速
缓存的数据。GBase 8s 还有一个先进先出 (FIFO) 队列。设置 LRU 队列数时,您实际上
正在设置 FIFO/LRU 队列数。
使用 BUFFERPOOL 配置参数可指定有关缓冲池的信息,包括要在数据库服务器共享内
存已设置时要创建的 LRU 队列数目的信息,还包括控制将共享内存缓冲区清空到磁盘的
频率的 lru_min_dirty 和 lru_max_dirty 的值信息。
要提高事务吞吐量,请增加 lru_min_dirty 和 lru_max_dirty 值。然而,请勿更改
lru_min_dirty 和 lru_max_dirty 值之间的差额。
LRU 队列的组成部分
每个 LRU 队列由一对已链接的列表组成,如下所示:
• FLRU(可用的最近最少使用的)列表,它跟踪队列中可用的或未修改的页
• MLRU(已修改的最近最少使用的)列表,它跟踪队列中已修改的页
可用或未修改的页列表称为队列对的 FLRU 队列,而已修改的页列表称为 MLRU 队
列。这两个不同的列表使您无需在队列中搜索可用或未修改的页。下图说明了 LRU 队列
的结构。
图: LRU 队列




GBase 8s 管理员指南
南大通用数据技术股份有限公司
- 126 -
按最近最少使用的顺序排序的页
当数据库服务器处理对从磁盘读取页的请求时,它必须决定在内存中替换哪个页。 数据
库服务器不是随机选择一个页,而是假定最近引用的页比一些时间没有引用的页更有可能
在今后得到引用。因此,数据库服务器不会替换最近访问的页,而是替换最近最少访问的
页。通过维护按最近最少使用到最近最多使用顺序排序的页,数据库服务器可以方便地在
内存中定位最近最少使用的页。
LRU 队列和缓冲池管理
在处理开始之前,所有页缓冲区都是空的,并且每个缓冲区都由某个 FLRU 队列的条目
代表。这些缓冲区在 FLRU 队列中是平均分布的。要计算每个队列中的缓冲区的数目,
请将缓冲区总数除以 LRU 队列数。缓冲区和 LRU 队列的数目是在 BUFFERPOOL 配
置参数中指定的。
当需要用户线程来获取缓冲区时,数据库服务器将随机选择一个 FLRU 队列,并使用列
表中最旧的或最近最少使用的条目。如果可以锁存最近最少使用的页,该页将从队列中除
去。
如果 FLRU 队列已锁定并且不能锁存结束页,那么数据库服务器将随机选择另一个
FLRU 队列。
如果用户线程正在共享内存中搜索特定的页,那么将从存储在缓冲区表中的控制信息中获
取该页的 LRU 队列的位置。
正在执行的线程在完成其工作后将释放缓冲区。如果该页已修改,那么缓冲区将放置在
MLRU 队列的最近最多使用的一端。如果已读取该页但未修改,那么缓冲区将返回到
FLRU 队列的最近最多使用的一端。有关如何监视 LRU 队列的信息,请参阅监视缓冲池
活动。
要配置的 LRU 队列数
配置多个 LRU 队列有两个用途:
• 它们将减少用户线程对队列的争用。
• 它们允许多个清除程序清空来自 LRU 队列的页并使脏页的百分比维持在可接受的水
平。
根据计算机上提供的 CPU 数目推荐 LRUS 的初始值。如果您的计算机是单处理器的,
那么一开始请将 BUFFERPOOL 配置参数中的 lrus 值设置为 4。如果您的计算机是多处
理器的,请使用以下公式:
LRUS = max(4, (number_CPU_VPs))
在为 BUFFERPOOL 配置参数中的 lrus 提供了初始值后,请使用 onstat -R 监视 LRU
队列。如果发现脏 LRU 队列的百分比一直超过 lru_max_dirty 的指定值,请增加为
lrus 指定的值以添加更多的 LRU 队列。
例如,假设将 lru_max_dirty 设置为 70,并且一直发现有 75% 的 LRU 队列是脏的。
请考虑增加 lrus 的值。如果增加 LRU 队列的数目,就会缩短各个队列的长度,从而减

GBase 8s 管理员指南
南大通用数据技术股份有限公司
- 127 -
少页清除程序的工作。然而,您必须使用 CLEANERS 配置参数分配足够数量的页清除程
序(如下一节中所说明)。保留 lru_max_dirty 和 lru_min_dirty 之间相同的差额。
要分配的清除程序数
通常必须为应用程序经常更新的每个磁盘都配置一个清除程序。但是,除此之外还必须考
虑 LRU 队列的长度以及检查点的频率,如以下各段中所说明。
除了 LRU 队列数不够之外,另外一个影响页清除程序数是否跟得上清除的页数的因素是
您是否分配了足够的页清除程序线程数。在一些队列 中,脏页的百分比可能超过指定给
lru_max_dirty 的BUFFERPOOL 值,因为没有清除程序可用于清除这些队列。一段时间
过后,页清除程序可能实在赶不上了,这时缓冲池将会比您在 lru_max_dirty 中指定的百
分比还要脏。
例如,假设 CLEANERS 参数已设置为 8,以及将 LRU 队列数从 8 增加到 12。您不能
指望性能会有多大的提升,因为 8 个清除程序现在必须共享清除额外的 4 个队列的工
作。如果将 CLEANERS 的数值增加到 12,那么单个清除程序就可以更加有效地清除现
在已缩短的队列中的每个队列。
将 CLEANERS 设置得太小会导致出现检查点时性能变差,因为页清除程序必须在检查点
期间将所有已修改的页清空到磁盘。如果不配置足够数量的页清除程序,那么检查点会花
费更长的时间,导致整体的性能变差。
有关更多信息,请参阅清空缓冲池缓冲区。
已添加到 MLRU 队列的页数
页清除程序线程会定期将 MLRU 队列中已修改的缓冲区清空到磁盘。要指定清除开始的
点,请使用 BUFFERPOOL 配置参数指定 lru_max_dirty 的值。
通过指定页清除程序何时开始,lru_max_dirty 值会限制可附加到 MLRU 队列的页缓冲
区数。lru_max_dirty 的初始设置是 60.00,因此页清除会在队列所管理的缓冲区的百分
之六十被修改时开始。
实际上,页清除程序可以在若干条件下开始,但只有其中一个条件是 MLRU 队列达到
lru_max_dirty 值的情况。有关数据库服务器如何执行缓冲池清空的更多信息,请参阅将
数据清空到磁盘。
以下示例显示 lru_max_dirty 的值如何应用于 LRU 队列以指定页清除程序何时开始,从
而限制 MLRU 队列中的缓冲区数。
Buffers specified as 8000
lrus specified as 8
lru_max_dirty specified as 60 percent

Page cleaning begins when the number of buffers in the MLRU
queue is equal to lru_max_dirty.

GBase 8s 管理员指南
南大通用数据技术股份有限公司
- 128 -

Buffers per lru queue = (8000/8) = 1000

Max buffers in MLRU queue and point at which page cleaning
begins: 1000 x 0.60 = 600
MLRU 清除结束
还可以指定 MLRU 清除可以结束的点。BUFFERPOOL 配置参数中的 lru_min_dirty 值
指定 MLRU 队列中缓冲区的可接受百分比。例如,如果将 lru_min_dirty 设置为

启用Kerberos 认证后,加载导出报错
问题现象
华为定制Hadoop,
启用了Kerberos 认证,
配置gbase_hdfs_protocol=RPC,
从两
个不同的coor 节点执行加载任务,
报错分别为“Kerberos context has not been
initialized”和“AccessControlException: Failed to evaluate challenge:
GSSAPI error in client while negotiating security context ...”。
解决方法:
问题排查方法如下:
1)针对Kerberos context has not been initialized 错误,首先怀疑该节点
Kerberos 系统库版本过低(< 1.10),检查系统版本主为centos 7.3,kerberos
库版本为1.15,怀疑不成立。
2) 再次检查express.log 文件,发现/usr/lib64/libkrb5.so3.3: symbol
k5_dir_filenames,
version
krb5support_0_MIT
not
defined
in
libkrb5support.so.0”等信息,这可能是因为.so 文件版本冲突引起,但检查系
统目录/usr/lib64 下的libkrb5*.so 文件都来自相同的安装包,没有发现问题。
3)
检查
gclusterd

gbased
加载的动态库,发现引用了
/home/gbase/hadoopclient/kerberos/lib 下的非系统自带库文件,怀疑

GBase 8a MPP Cluster 最佳实践
5 FAQ
文档版本(2022-02-11)
南大通用数据技术股份有限公司
153
LD_LIBRARY_PATH 中指向了其它路径,打印LD_LIBRARY_PATH 变量,发现
/home/gbase/hadoopclient/kerberos/lib 被加入了LD_LIBRARY_PATH 中。
4) 检查.bashrc 和.bash_profile,
发现执行了一个hadoop 客户端初始化环境脚
本,
导致LD_LIBRARY_PATH 变量被更改。
该hadoop 客户端脚本用于在gbase 账号
下执行hdfs 客户端命令,
但不是8a 连接hadoop 加载和导出所需要的,
建议现场
从bash_profile 中删除该脚本。
5) 清理LD_LIBRARY_PATH 变量后,再次执行加载任务,不再报1)错误,
express.log 日志中也不再出现2)错误,并出现了Init creds ... OK”,表示
初始化Kerberos 票据成功。
6)
针对AccessControlException: Failed to evaluate challenge: GSSAPI error
in client while negotiating security context ...”错误,怀疑现场Hadoop
可能启用了HTTPS 传输协议,经检查确认已启用HTTPS 协议,建议配置参数
_gbase_hdfs_rpcconfig="dfs.encrypt.data.transfer=true,dfs.block.access.
token.enable=true"。
现场反馈配置后仍报相同错误,
后确认只在gcluster 上配
置了该参数,未在gnode 上配置。
7) 完成以上两个错误的处理后,重启8a 集群。执行加载任务,报错信息变为
“cannot read file ... Caused by: HdfsIOException: InputStreamImpl: all
nodes been tried and no valid replica can be read
for Block ...”
8)
检查
hadoopclient
目录下的配置文件
hdfs-site.xml
发现
“dfs.encrypt.data.transfer=false









_gbase_hdfs_rpcconfig="dfs.encrypt.data.transfer=false,dfs.block.acces
s.token.enable=true"。
9) 再次执行加载任务,加载成功。

这两个方法允许在集合中向前或向后移动,这对于遍历稀疏集合非常有用。
l
如果前边的元素存在,PRIOR返回指定索引的前一个索引,否则返回NULL。如
c.PRIOR(c.FIRST)返回NULL。
l
如果后边的元素存在,NEXT返回指定索引的后一个索引,否则返回NULL。如
c.NEXT(c.LAST)返回NULL。
给定范围索引可以不存在,此时返回全为NULL。例如:
l
可变数组,索引如果超出c.LIMIT,返回null;
l
c.PRIOR(index)返回NULL;
l
c.NEXT(index)返回NULL。
TYPE Arr_Type IS VARRAY(10) OF NUMBER;
v_Numbers Arr_Type := Arr_Type();
BEGIN
v_Numbers.EXTEND(4);

GBase 8s PL/SQL手册
南大通用数据技术股份有限公司
- 84 -

v_Numbers (1) := 10;
v_Numbers (2) := 20;
v_Numbers (3) := 30;
v_Numbers (4) := 40;
DBMS_OUTPUT.PUT_LINE(NVL(v_Numbers.prior (3400), -1));
DBMS_OUTPUT.PUT_LINE(NVL(v_Numbers.next (3400), -1));
END;

-- Result:
-- -1
-- -1
对于字符串做索引的关联数组,prior和next是按照键值的排列的顺序来确认键值的。
CREATE OR REPLACE PROCEDURE P_5_26 AS
TYPE nt_type IS TABLE OF NUMBER;
nt nt_type := nt_type(18, NULL, 36, 45, 54, 63);
BEGIN
nt.DELETE(4);
DBMS_OUTPUT.PUT_LINE('nt(4) was deleted.');
FOR i IN 1..7 LOOP
DBMS_OUTPUT.PUT('nt.PRIOR(' || i || ') = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(nt.PRIOR(i)), 'NULL'));
DBMS_OUTPUT.PUT('nt.NEXT(' || i || ') = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(nt.NEXT(i)), 'NULL'));
END LOOP;
END;

--Result:
--nt(4) was deleted.
--nt.PRIOR(1) = NULL
--nt.NEXT(1) = 2
--nt.PRIOR(2) = 1
--nt.NEXT(2) = 3
--nt.PRIOR(3) = 2
--nt.NEXT(3) = 5
--nt.PRIOR(4) = 3
--nt.NEXT(4) = 5
--nt.PRIOR(5) = 3
--nt.NEXT(5) = 6
--nt.PRIOR(6) = 5
--nt.NEXT(6) = NULL
--nt.PRIOR(7) = 6
--nt.NEXT(7) = NULL

GBase 8s PL/SQL手册
南大通用数据技术股份有限公司
- 85 -


CREATE OR REPLACE PROCEDURE P_5_27 AS
TYPE NumList IS TABLE OF NUMBER;
n NumList := NumList(1, 2, NULL, NULL, 5, NULL, 7, 8, 9, NULL);
idx INTEGER;
BEGIN
DBMS_OUTPUT.PUT_LINE('First to last:');
idx := n.FIRST;
WHILE idx IS NOT NULL LOOP
DBMS_OUTPUT.PUT('n(' || idx || ') = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(n(idx)), 'NULL'));
idx := n.NEXT(idx);
END LOOP;
DBMS_OUTPUT.PUT_LINE('--------------');
DBMS_OUTPUT.PUT_LINE('Last to first:');
idx := n.LAST;
WHILE idx IS NOT NULL LOOP
DBMS_OUTPUT.PUT('n(' || idx || ') = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(n(idx)), 'NULL'));
idx := n.PRIOR(idx);
END LOOP;
END;

--Result:
--First to last:
--n(1) = 1
--n(2) = 2
--n(3) = NULL
--n(4) = NULL
--n(5) = 5
--n(6) = NULL
--n(7) = 7
--n(8) = 8
--n(9) = 9
--n(10) = NULL
--------------
--Last to first:
--n(10) = NULL
--n(9) = 9
--n(8) = 8
--n(7) = 7
--n(6) = NULL
--n(5) = 5

GBase 8s PL/SQL手册
南大通用数据技术股份有限公司
- 86 -

--n(4) = NULL
--n(3) = NULL
--n(2) = 2
--n(1) = 1