OceanBase 中 schema 的定义与应用

背景

经常在OceanBase 的问答社区 里看到一些关于 “schema 是什么” 的提问。

先纠正一些同学的误解, OceanBase 中的 Schema 并不简单的等同于 Database,本次分享将探讨 OceanBase 中的Schema是什么,及一些大家经常遇到的问题。 

具体而言,在 OceanBase 的 MySQL 模式、Oracle 模式以及其自身的元数据管理模块中,Schema 的概念和应用是存在差异的。

1691459740

1691459773

OB MySQL 模式中 schema 的概念

       Schema 是 Database 的同义词。SQL 中可以使用 Schema 关键字代替 Database 关键字,例如使用 CREATE SCHEMA 代替 CREATE DATABASE 等。

OB Oracle 模式中 schema 的概念

       在 OB 的 Oracle 模式中,Schema 是指一个用户所拥有的数据库对象的集合,用于权限管理和命名空间隔离,我个人把他理解成一个 “用户空间”。Schema 对象是指在某个 Schema 中的数据库对象,例如 Schema 中的表、视图、索引等;非 Schema 对象是指不属于某个 Schema 的数据库对象,例如用户、角色、表空间等。

       用户在创建时会拥有一个缺省的 Schema,其 Schema 名就等于用户名。如果有权限的话,用户还可以访问和使用其他的 Schema。在访问一个 Schema 中的对象时,如果没有指明该对象属于哪一个 Schema,系统就会自动给对象加上缺省的 Schema 名称。

       如果当前 user 拥有访问或修改其他 schema 对象的权限,可以通过 alter session set current_schema = other_schema_name; 切换到其他 schema 中进行各种操作。

OB 元数据管理模块中 schema 的概念

       Oceanbase 元数据管理模块里的 schema 泛指一切需要在集群范围内同步的数据库对象元信息,包括但不限于 table、database、user 等元信息。此外,Oceanbase 的 schema 是多版本的,内存中的 schema 信息在集群范围的同步是最终一致的。

schema 里有什么?

       schema 是什么解释完了,在社区里又会看到有人问,schema 是元信息,那么元信息里包含了哪些东西?

1691459787

       上面的回答中其实有个小的疏漏,因为各种数据库对象的元数据信息只会受 DDL 的影响,“预估行数” 属于不受 DDL 的影响,只受 DML 影响的统计信息,所以其实并不是表的元信息,table schema 中也不会对其进行记录。

       元信息里具体包含了哪些东西,可以参见 src/share/schema 路径下的代码。例如如果想看 table schema 中记录了哪些 table 的元数据信息,看 ob_table_schema.h 中的 ObTableSchema 及其父类有哪些类成员即可。

1691459798

DDL 执行过程

       上面回答了 schema 是什么、有什么的问题。因为 schema 只会通过 DDL 进行修改,所以这里简单提一下 DDL 的执行过程,方便大家在遇到 DDL 相关问题时进行排查。

       DDL 不会被优化器处理,而是作为 command 发送到 RootServer,由 RootServer(下简称 rs) 进行处理。在 OceanBase 里的执行流程如下:

1691459810

       以一个最常见的建表语句为例:

       create table 命令会在 obs 上对建表语句进行 resolve,把建表的信息存到 create_table_arg 中,把 create_table_arg 发 rpc 给 rs,rs 接下来会来执行如下操作:

  • 检查 obs 在 resolve 时使用的的 schema 版本是否最新(采用乐观锁的方法解决,如果非最新,则对这条 DDL 进行整体重试);
  • 从 __all_sys_stat 里获取一个租户内单调递增的新 table id;
  • 把 create_table_arg 里提供的信息插入到 __all_table_history 等内部表里用于持久化
  • 在 __all_ddl_operation 中记录 ddl 的变更日志(用于增量刷新等场景)
  • publish schema(通知各节点把 schema 刷到内存里)

1691461106

       其他 observer 接收到 RS 发送的 publish schema 的命令之后,就会把内部表中的改动增量加载到内存(schema cache)中,这也就是我们经常听到别人说的 “刷 schema”。

       rs 上的 ddl_service 调用 publish_schema() 将新的 schema 版本号广播给所有 obs 实际发生了什么?

  1. rs 自己所在的 obs 直接调用 refresh_schema。
  2. 给每个 alive obs 发送 switch_schema 的命令,参数为最新 schema_version。
  3. 各个 obs 收到指令后,生成一个 ObSchemaRefreshTask 异步刷新任务,通过这行这个任务把自己的 schema 刷到最新。

1691459823

附另一张图:

  • 图中上面的部分是在执行 DDL,RS 的 DDL service 服务会负责写内部表和通知各 observer 节点把元数据的修改加载到内存的 schema cache 中;
  • 下面的部分是在执行 query 的过程,过程中几乎都会读取内存中 schema cache 的元信息。

1691459832

一开始客户在社区里提的那个问题中的 GV$OB_SERVER_SCHEMA_INFO 可以理解为每台 ObServer 每个租户已经刷新的最新版本的 schema 的信息,这个视图用户比较关注的 schema 信息是 REFRESHED_SCHEMA_VERSION、SCHEMA_COUNT、SCHEMA_SIZE,其含义如下:

  • REFRESHED_SCHEMA_VERSION:对应租户在对应机器已刷新到的 schema 版本。
  • RECEIVED_SCHEMA_VERSION:对应租户在对应机器已已经接收到的 RS 发过来的最新刷新任务的 schema 版本。
  • SCHEMA_COUNT:对应 schema 版本下,各 schema 对象数目的总和(table 数目 + database 数目 +…)。
  • SCHEMA_SIZE:对应 schema 版本下,各 schema 对象总共所占的内存大小(B)。
obclient> select * from oceanbase.GV$OB_SERVER_SCHEMA_INFO\G
*************************** 1. row ***************************
                    SVR_IP: 11.158.31.20
                  SVR_PORT: 22602
                 TENANT_ID: 1002
  REFRESHED_SCHEMA_VERSION: 1690109029768968
   RECEIVED_SCHEMA_VERSION: 1690113309637344
              SCHEMA_COUNT: 1583
               SCHEMA_SIZE: 1537240
MIN_SSTABLE_SCHEMA_VERSION: -1
1 row in set (0.01 sec)

DDL 和 schema 的问题排查方法

       既然都说了这么多了,那就再说下 DDL 和 schema 比较常见的几类问题。这一部分欢迎大家补充更好的排查问题方法~

执行 DDL 语法报错了,我该怎么改语法呢?

       客户经常会在试着自己把正在用的数据库上的元数据往 OceanBase 开源版本上倒腾,比如前几天见到一个客户希望把 pg 里的分区表定义放到 OB MySQL 模式的租户下执行下,但是报错了,然后就会认为 OB 不支持分区表。

CREATE TABLE value_stream_dashboard_counts (
    id bigint NOT NULL,
    namespace_id bigint NOT NULL,
    count bigint NOT NULL,
    metric smallint NOT NULL
)
PARTITION BY RANGE (id);

1691459848

       我们遇到这种问题应该怎么查 OB MySQL 模式下的对应语法呢?大家一般可能回去查各种各样的 OB 语法文档,但是 OB 语法随着兼容性的逐步完善而日新月异,文档内容其实没办法保证和真实支持的语法强一致(甚至连最终一致都不能保证)。想起师兄和我说的一句话:“文档很喜欢骗人,但是代码从不会说谎”,OB 社区版支持的所有语法其实都写在一个叫 sql_parser_mysql_mode.y 的 yacc 文件里。

       看完这个文件里的语法规则,我们就很容易把上面那条 SQL 改成 OB MySQL 模式下可以执行成功的 SQL。

CREATE TABLE value_stream_dashboard_counts (
    id bigint NOT NULL,
    namespace_id bigint NOT NULL,
    count bigint NOT NULL,
    metric smallint NOT NULL
)
PARTITION BY RANGE (id)(
     PARTITION p0 VALUES LESS THAN (100),
     PARTITION p1 VALUES LESS THAN (200),
     PARTITION p2 VALUES LESS THAN (300),
     PARTITION p3 VALUES LESS THAN MAXVALUE
);

执行 DDL 报了不太明确的错,我该怎么排查失败原因呢?

       比如,我执行了一条 DDL,它报错了,报错说我的 check 约束里出现了不允许被包含在 check 约束里的表达式,但具体是什么表达式不被允许?是 c1,是 =,是 sysdate(),还是 c1 = sysdate()?

obclient> create table t1(c1 int, check (c1 = sysdate()));
ERROR 3814 (HY000): An expression of a check constraint contains disallowed function.

       先查一下报错语句的 trace_id。

select last_trace_id();
+------------------------------------+
| last_trace_id()                    |
+------------------------------------+
| Y584A0B9E1F14-00060127094761A8-0-0 |
+------------------------------------+
1 row in set (0.00 sec)

       那我们就通过 grep Y584A0B9E1F14-00060127094761B0-0-0 observer.log* 去捞下 observer 的日志。

1691459866

       这个 trace 对应的第一条 warning 日志说 :deterministic expr is wrongly specified in CHECK constraint(这条日志其实写的不对,本意应该是 not deterministic expr is wrongly specified in CHECK constraint),大概意思就是说 check 约束里面有个(非)确定性的表达式,这个是不被允许的。

       那么究竟什么表达式是非确定性的表达式呢?这个就需要根据日志里给出的文件和行号 ob_raw_expr_util.cpp:1856 去看一眼代码了,在网页上可以直接跳到具体某个函数的定义里,例如 ObRawExpr::is_non_pure_sys_func_expr。

       这里列出了所有 not deterministic 的表达式,其中就包含我们用到的 sysdate。

1691459880

       所以我们就可以大概知道 check 约束里的表达式需要保证多次执行都能得到同样的结果吧。像 sysdate 这种输出当前时间的表达式在多个不同的时间执行多次,结果必定是不一样的,所以不允许出现在 check 约束里。这里我们还可以趁机了解下还有哪些表达式属于 not deterministic 的。

执行 DDL 捞不到有用的日志怎么办?

       例如我执行了一个创建 database 的 DDL,结果报错了。

obclient> create database xiaofeng_db;
ERROR 4016 (HY000): Internal error

obclient> select last_trace_id();
+------------------------------------+
| last_trace_id()                    |
+------------------------------------+
| Y584A0B9E1F14-00060127094761B4-0-0 |
+------------------------------------+
1 row in set (0.00 sec)

拿着 trace id 捞日志,grep Y584A0B9E1F14-00060127094761B4-0-0 observer.log*,结果是 rpc error。

1691459893

回忆一下刚才说的 DDL 执行过程,DDL arg 会发到 RS 上执行,所以这种情况大概率是在 RS 上执行的时候出了什么幺蛾子,所以我们还需要通过 grep Y584A0B9E1F14-00060127094761B4-0-0 rootservice.log* | vi - 继续 grep 以下 RS 的日志,然后在日志文件里根据错误码 -4016 搜下 ret=-4016最早出现的地方。

       然后我们就可以发现日志里说是在 ob_root_service.cpp 文件的 2887 行报的错,报错原因是:create_database failed, because db_name is forbidden。这种问题大家先自己根据报错日志里的文件和行号简单分析下原因,如果还是没头绪的话,再找 OB 的技术支持同学协助分析。

       翻一下这个文件,哦,原来是是我为了构造在 RS 报错的场景故意在这里加了一个报错的错误码,说只要 create database 的 database_name 叫 xiaofeng_db,就报错 4016 OB_ERR_UNEXPECTED。

排查 DDL 和 schema 的问题时忽略 rootservice.log 日志是很常见的情况,曾经亲眼见过很多非常有经验的 OceanBase 内核研发专家不止一次因为这个问题浪费大量时间排查简单一个的小 bug。大家切记这类问题在 observer.log 没线索时,还要去看下 rootservice.log。

1691459923

刷 schema hang 住了怎么办?

       刷 schema hang 住是因为在把内部表的数据加载到内存中的过程中会进行一些 schema 的合法性校验,如果校验失败,就说明持久化在内部表里的元数据信息出问题了,这时 observer 就会 hang 住,什么都干不了。因为一旦元数据都错了,基于错误的元数据无论是执行 DDL、DML,还是执行查询 query ,都是错上加错,很容易产生大量正确性问题。这种情况出现的概率极低,但问题十分严重。

       如果执行 DDL hang 住了,并且在 RS 的日志里出现类似于 “Trying so hard to die” 和 “schema meta is still not consistent after rebuild, need fixing” 的信息,表明恢复环境需要人工接入去修改 OB 内部表中的错误信息,风险较高,建议及时找 OB 的技术支持同学帮忙排查问题根因及协助你恢复环境(如果是 OB 社区版,可以加入钉钉群:33254054 并 @群管理员)。

参考资料

MySQL 模式数据库对象概述:MySQL 模式数据库对象

Oracle 模式数据库对象概述:Oracle 模式数据库对象

研木在社区问答区的回答:4.0的GV$OB_SERVER_SCHEMA_INFO视图中的SCHEMA是什么 - #3,来自 坤易 - OceanBase - 社区问答- OceanBase社区-分布式数据库

OB 源码:oceanbase/src/share/schema/ob_table_schema.h at 9940650223427978ac634ff0d7423ab53c74a95e · oceanbase/oceanbase · GitHub

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PDF——压缩大小的方法

方法一:QQ浏览器->格式转换->PDF转纯图PDF

萌啦数据行业数据在哪看,萌啦ozon行业数据怎么看

在跨境电商的浪潮中,数据已成为商家决策的重要基石。萌啦Ozon数据行业分析板块,作为连接商家与市场动态的桥梁,为商家提供了丰富的行业洞察与精准的市场指导。本文将带您深入探索萌啦Ozon数据行业分析板块的功能,揭秘如何在这片数…

IDEA中实现springboot热部署

IDEA中实现springboot热部署 热部署: 每一次修改代码后会自动更新&#xff0c;无需每次重启 依赖(pom.xml) 修改后记得Reload一下 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><…

重生归来之挖掘stm32底层知识(1)——寄存器

概念理解 要使用stm32首先要知道什么是引脚和寄存器。 如下图所示&#xff0c;芯片通过这些金属丝与电路板连接&#xff0c;这些金属丝叫做引脚。一般做软件开发是不需要了解芯片是怎么焊的&#xff0c;只要会使用就行。我们平常通过编程来控制这些引脚的输入和输出&#xff0c…

农业电商服务系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;会员管理&#xff0c;商家管理&#xff0c;商品分类管理&#xff0c;商品信息管理&#xff0c;农产品监督管理&#xff0c;助农信息管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页…

7000长文:一文读懂Agent,大模型的下一站

什么是Agent&#xff1f;为什么是Agent&#xff1f; 大模型除了Chat外还能做什么用&#xff1f; 当我们将大型模型视为“核心调度器“时&#xff0c;它就变成了我们的Agent。借助任务规划、记忆及外部工具等能力&#xff0c;大型模型能够识别出应该执行的任务以及执行方式&…

解锁自动化新境界:KeymouseGo,让键盘和鼠标动起来!

文章目录 解锁自动化新境界&#xff1a;KeymouseGo&#xff0c;让键盘和鼠标动起来&#xff01;背景&#xff1a;为何选择KeymouseGo&#xff1f;KeymouseGo简介安装KeymouseGo简单函数使用应用场景常见问题与解决方案总结 解锁自动化新境界&#xff1a;KeymouseGo&#xff0c;…

在WPF中自定义控件时如何选择基类

在WPF中需要自定义控件&#xff0c;首要要选择需要继承的基类 FrameworkElement 这是常用的最低级的基类。通常&#xff0c;只有当希望重写OnRender()方法并使用DrawingContext从头绘制内容时&#xff0c;才会继承该类。 Control 当从头开始创建控件时&#xff0c;这是最常用…

Vue2知识点

注意:笔记内容来自网络 1Vue指令 指令是指&#xff1a;带有v-前缀的特殊标签属性 1.1 v-html v-html&#xff08;类似 innerHTML&#xff09; 使用语法&#xff1a;<p v-html"intro">hello</p>&#xff0c;意思是将 intro 值渲染到 p 标签中 类似 i…

【 ACM独立出版,见刊后1个月检索!!!】第二届通信网络与机器学习国际学术会议(CNML 2024,10月25-27)

第二届通信网络与机器学习国际学术会议&#xff08;CNML 2024&#xff09; The 2nd International Conference on Communication Networks and Machine Learning 官方信息 会议官网&#xff1a;www.cn-ml.org The 2nd International Conference on Communication Networks an…

JavaEE: 深入探索TCP网络编程的奇妙世界(二)

文章目录 TCP核心机制TCP核心机制二: 超时重传为啥会丢包?TCP如何对抗丢包?超时重传的时间设定超时时间该如何确定? TCP核心机制 书接上文~ TCP核心机制二: 超时重传 在网络传输中,并不会一帆风顺,而是可能出现"丢包情况"~ 为啥会丢包? 产生丢包的原因有很多…

倒序循环(一)

题目描述 输入一个正整数n&#xff0c;输出从 n~ 1 递减的序列。 输入格式 一行一个整数 n 输出格式 n 行&#xff0c;每行一个符合题目要求的整数 样例数据 样例输入#1 5样例输出#1 5 4 3 2 1样例输入#2 6样例输出#2 6 5 4 3 2 1数据范围 对于100%的数据&#xff…

C语言浮点型数据在内存中的存储(23)

文章目录 前言一、浮点数在内存中的存储练习引入浮点数的存储浮点数存的过程 二、浮点数取的过程E不全为0或不全为1E全为0E全为1 三、再回顾练习总结 前言 哎&#xff0c;之前写了一篇&#xff0c;可是中途退出没保存&#xff0c;只能再写一遍了~   浮点数在内存中的存储跟整…

python线程(python threading模块、python多线程)(守护线程与非守护线程)

文章目录 Python多线程入门1. Python多线程概述2. threading模块基础- Thread 类: 这是一个代表线程的类。可以通过创建Thread类的实例来新建一个线程。- Lock 类: 在多线程环境中&#xff0c;为了防止数据错乱&#xff0c;通常需要用到锁机制。Lock类提供了基本的锁功能&#…

ArcGIS10.2/10.6安装包下载与安装(附详细安装步骤)

相信从事地理专业的小伙伴来说&#xff0c;应该对今天的标题不会陌生。Arcgis是一款很常用的地理信息系统软件&#xff0c;主要用于地理数据的采集、管理、分析和展示。目前比较常见的版本有ArcGIS 10.2和ArcGIS 10.6。 不可否认&#xff0c;Arcgis具有强大的地图制作、空间分…

第4步CentOS配置SSH服务用SSH终端XShell等连接方便文件上传或其它操作

宿主机的VM安装CENTOS文件无法快速上传&#xff0c;也不方便输入命令行&#xff0c;用SSH终端xshell连接虚拟机的SSH工具就方便多了&#xff0c;实现VM所在宿主机Win10上的xshell能连接vm的centos要实现以下几个环节 1、确保宿主机与虚拟机的连通性。 2、虚拟机安装SSH服务&…

针对Docker容器的可视化管理工具—DockerUI

目录 ⛳️推荐 前言 1. 安装部署DockerUI 2. 安装cpolar内网穿透 3. 配置DockerUI公网访问地址 4. 公网远程访问DockerUI 5. 固定DockerUI公网地址 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…

AJAX(一)HTTP协议(请求响应报文),AJAX发送请求,请求问题处理

文章目录 一、AJAX二、HTTP协议1. 请求报文2. 响应报文 三、AJAX案例准备1. 安装node2. Express搭建服务器3. 安装nodemon实现自动重启 四、AJAX发送请求1. GET请求2. POST请求(1) 配置请求体(2) 配置请求头 3. 响应JSON数据的两种方式(1) 手动&#xff0c;JSON.parse()(2) 设置…

毕业设计选题:基于ssm+vue+uniapp的校园商铺系统小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

分发饼干00

题目链接 分发饼干 题目描述 注意点 1 < g[i], s[j] < 2^31 - 1目标是满足尽可能多的孩子&#xff0c;并输出这个最大数值 解答思路 可以先将饼干和孩子的胃口都按升序进行排序&#xff0c;随后根据双指针 贪心&#xff0c;将当前满足孩子胃口的最小饼干分配给该孩…