openGauss源码解析(160)
openGauss源码解析:AI技术(7)
4. 数据库交互部分源码解析
首先来看一下数据库需要调整的参数是如何在程序中存储的。数据库的参数可能是布尔型的,如off或on,也可以是整数型的或浮点型的。但是,计算机算法(如强化学习、全局搜索算法等)只能接受数值结果,因此需要数值化。这就需要定义一个名为Knob的类,封装数据库的参数。
class Knob(object):
def __init__(self, name, knob):
…
# 将整形数值转换为数据库可以接受的字符串型字面量
def to_string(self, val):
…
# 将字符串型的字面量转换为数值型
def to_numeric(self, val):
…
当DB_Agent类需要被告知要调节的参数时,通过Knob类将待调优的参数包装起来,并作为该类的一个属性存储在内存中。
DB_Agent类实现了对数据库行为的封装,是X-Tuner与数据库进行交互的唯一接口,该类的代码实现如下:
class DB_Agent:
def __init__(self, host, host_user, host_user_pwd,
db_user, db_user_pwd, db_name, db_port, ssh_port=22):
…
# 设置语句的执行时间不限
self.set_knob_value("statement_timeout", 0)
# 初始化数据库的特征指标接口
self.metric = openGaussMetric(self)
def check_connection_params(self):
# 检查数据库连接参数是否正确
…
def set_tuning_knobs(self, knobs):
# 设置调优参数,参数类型为RecommendedKnobs, 该类在knob.py文件中定义
if not isinstance(knobs, RecommendedKnobs):
raise TypeError
self.knobs = knobs
self.ordered_knob_list = self.knobs.names()
…
def exec_statement(self, sql, timeout=None):
# 在数据库内执行SQL语句,是通过调用gsql命令来实现的
command = "gsql -p {db_port} -U {db_user} -d {db_name} -W {db_user_pwd} -c \"{sql}\";".format(
db_port=self.db_port,
db_user=self.db_user,
db_name=self.db_name,
db_user_pwd=self.db_user_pwd,
sql=sql
)
…
def is_alive(self):
# 检查数据库是否运行
...
def exec_command_on_host(self, cmd, timeout=None, ignore_status_code=False):
# 在数据库的宿主机上执行shell命令
...
def get_knob_normalized_vector(self):
# 获取待调优参数的结果,并将其进行归一化(映射到0与1之间)。返回结果是一个列表
nv = list()
for name in self.ordered_knob_list:
val = self.get_knob_value(name)
nv.append(self.knobs[name].to_numeric(val))
return nv
def set_knob_normalized_vector(self, nv):
# 与get_knob_normalized_vector()方法对应,参数nv表示normalized_vector,即都是已经映射到0与1之间的、经过数值化的参数值,将这些参数值设置到数据库上
restart = False
for i, val in enumerate(nv):
name = self.ordered_knob_list[i]
knob = self.knobs[name]
self.set_knob_value(name, knob.to_string(val))
restart = True if knob.restart else restart
# 如果这些待设置的参数中有需要重启数据库的,则重启数据库以便使设置后的参数生效
if restart:
self.restart()
def get_knob_value(self, name):
# 单独获取某个参数的值,该参数值是不经标准化的
check_special_character(name)
sql = "SELECT setting FROM pg_settings WHERE name = '{}';".format(name)
_, value = self.exec_statement(sql)
return value
def set_knob_value(self, name, value):
# 单独设置某个参数的值,该参数值是不经标准化的,通过gs_guc命令设置数据库参数值
logging.info("change knob: [%s=%s]", name, value)
try:
self.exec_command_on_host("gs_guc reload -c \"%s=%s\" -D %s" % (name, value, self.data_path))
except ExecutionError as e:
if str(e).find('Success to perform gs_guc!') < 0:
logging.warning(e)
def reset_state(self):
# 重置数据库的状态,例如对 pg_stat_database等系统表进行重置
self.metric.reset()
def set_default_knob(self):
# 设置数据库的参数值为默认值,该默认值通过knob类型指定,即在对应的配置文件中指定的值
restart = False
for knob in self.knobs:
self.set_knob_value(knob.name, knob.default)
restart = True if knob.restart else restart
self.restart()
def restart(self):
# 重启数据库
...
def drop_cache(self):
# 对于openGauss数据库来说,drop cache可以使每次benchmark的跑分更加稳定,但是这需要root权限
# 如果用户需要drop cache,则可以向/etc/sudoers中写入'username ALL=(ALL) NOPASSWD: ALL'
...