- LSM是一种不可变存储结构,将随机IO转化为顺序化,对文件的写减少了锁和闩锁的操作,使得写入并发访问。
- RUM,Btree针对读进行优化,增加空间开销;LSM写快,但读成本高,存储冗余空间开销大。
- MEMsstable 合并入磁盘后,自动进行clog清理- 事务上下文的状态与版本号的关系
commit状态存在全局提交版本号,running状态可能存在本地提交版本号,abort版本号为MAX,prepare需要等待,为两件段提交状态。 - mvccRow的形式存储多版本数据,数据版本以transnode新式存储
- 事务维护两个版本号,读版本号和提交版本号,
- global timestamp cache 本地最大读时间戳、最大提交事务时间戳- ODP收到sql请求,进行轻量解析,发达到OBS,OBS进行快速参数化
- 快速参数化,指对词法分析,并直接参数化,获取参数化后的文本及常量参数;元sql文本为query_sql,参数化后的文本为statement
- 使用参数化后的文本进行plan cache获取执行计划并执行,如果获取不到则需要解析执行计划
- 远程执行计划需要RPC调用OBS完成后将结果集传输到调度节点,而分布式执行计划需要分拆执行进行调度- 策略
- 关注索引
- 分区裁剪
- 查询并行度
- 联接顺序
- 跨机或并行联接的数据再分布方式
- 查询改写
- 优化慢SQL
- 关注请求流量均衡
- 关注RPC请求均衡
- 调优步骤
- 通过(g)v$sql_audit,SQL Trace和计划缓存视图查找待优化点
- 查看某条SQL执行计划
- 查询改写和联接调整,索引调整
系统化调优
- 查询慢SQL、占用资源多的SQL
- 通过调整primary zone、并发、表组、路由参数、热点分区等减少RPC、充分利用资源
单条SQL优化
针对单条SQL确认执行计划、trace判断问题
确认索引、统计数、分区剪裁、并行、表关联等是否有调整的空间- 悬挂事务
进入提交阶段,但由于某种原因,导致事务无法提交成功长事务
执行时间超过60s不提交的事务大事务
单个事务参与者的日志产生量大于0.5MB或者事务已经执行大于500ms问题分析方法
结合__all_virtual_trans_stat 和observer日志查询,其中observer日志需要根据trace_id和trans_id进行查询,一般来说,其中sending error packet包括sql具体错误码及trace_id。
state事务的状态,part_trans_action当前语句的状态有主连任
obs lease过期(默认10s)前,会发起连任,连任后原主副本角色不变无主选举
如果leader因某种原因不能服务,发起无主选举有主改选
RS发现或者手动切主,重新对副本切换更好的副本
除了手动切主和无主选举,其它自动选举由rs的leader coordinator组件发起- observer总内存设置,通过两个参数控制(memory_limit和memory_limit_percentage)将总内存划分给系统租户、500租户、业务租户,也有一些高优先级预留内存
租户内存有system_memory参数设置;租户内存包括memstore和kvcache、计划缓存等sql执行期的内存。内存有ctx和mod组成,sql执行时为PM内存
支持内存弱检测、跟踪static_id打印堆栈、dump内存元数据
memstore
- memstore中存储了分区的增量数据
- 有两种数据索引结构btree和hash
- memtable 以MvccRow的形式来存储多版本数据,数据版本以TransNode的形式构成链表,其中锁和事务相关信息也存储在其中
kvcahe
- kvcache是由可动态伸缩的内存组件组成,clog、block cache、row cache、bloom filter cache等
- 除此之外,还有很多内存组件,包括 Plan Cache(执行计划缓存)、SQL Area(SQL 执行期内存)、SQL AREA(SQL解析和优化使用的内存)、SQL AUDIT、Other AREA(分区事务管理等使用的内存)
- 在observer.log查询日志相关信息
- 或者在gv$sysstat中根据con_id(租户id)查找内存的汇总使用情况,包括active内存量、冻结内存等;==sysstat不包括malloc/mmap的内存==
- 日志中oops的内容,判读分配失败的原因,
- 如果ctx下mode内存一直在增长,那么可能存在内存泄漏
- v$memory 记录了各种模块的内存使用情况## mysql模式
- range分区,分区键只支持一列,init类型,可以添加和drop分区
- range columns分区,分区键可以是多列
- key分区 分区键只能是列,不限制类型
- list分区 分区键可以是多列,表达式
- list columns分区 不限制类型
- hash分区 分区键可以是表达式
- 二级分区,可两两组合,二级分区由二级确定存储
oracle模式
- range
- hash
- list- 由事务开启的第一条sql选择协调者
- 协调者负责rpc其它OBS执行sql并汇总
- 协调者调用obs,发送prepare请求;OBS持久日志,加锁,协调者收到prepare 请求回应后,回复客户端提交成功,然后发送commit请求,obs提交成功,日志,释放锁并回应。- 3级转储
- 冻结并写入L0 mini,70%触发转储
- L0达到2各时,压缩为L1 minor
- 5个minor合并为major
合并方式
- 全量合并
- 增量合并
- 渐近合并
- 并行合并
- 轮转合并- 数据备份 major sstable+minor sstable
- 日志备份clog
- 备份为集群级的备份,租户级别的恢复;恢复的时候允许通过白名单机制指定恢复的表或者库
- 数据备份对应一个backup_set,日志备份对应backup_piece
- 备份元信息
- 原库backup_set保存在__all_backup_set_files表,backup_piece保存在__all_backup_piece_files表,租户信息在原集群存储在__all_tenant和__all_tenant_history表中
- 备份介质上,分别保存在tenant_data_backup_info,tenant_clog_backup_info,tenant_name_info
日志备份
日志备份由分区的leader副本负责,默认日志备份周期为2分钟。
数据备份
数据备份包括元信息和宏块数据,基于restore point 的能力做数据快照保留,保证备份期间的数据能够保持全局一致性。
恢复架构
- 支持微妙级别的恢复精度
- 恢复流程,按照系统表、系统表日志、修正系统表、恢复用户表,用户日志。- 强同步模式下,备集群直接从主集群的主副本同步日志,不能自由选择上游副本
- 异步同步模式下,可按region级联的传输日志策略,就近选择上游副本- obp->obs
enable_server_detect运行探测,每1s探测一次,探测失败次数超过server_detecet_fail_threshold(5)时加入黑名单 - obp sock层面的三个探活参数
- obs->rs
每2s发送状态,当lease_time没有收到心跳,标记lease_expired,obs为inactive,累计server_permanent_offline_time,标记permanent_offline,obs为deleting。RS结合OBS磁盘状态进行obs的状态判断 - 通过obproxy的日志查询是由那个客户端发起的、交易响应时间等信息、obs的traceid; 到obs上查看traceid对应的交易信息
- proxy日志
digest审计日志、stat执行统计日志、slow日志更详细、error日志、limit限流日志。 - 也可使用sqlaudit视图查看sql的执行情况,查询相关的慢sql、占用资源多的SQL,然后进行分析
- 通过在应用端tcpdump,一个事务涉及的SQL,每个SQL的执行时间,进行初步的判断
- sql traceid 在sql audit中有记录,可在observer日志中查询,sql triaceid记录的就是observer 的trace id
- traceid由trace_id0和id1组成,trace_id在rcp的各个obs传递。
- observer也会记录慢日志,slow trans等,记录每个server的信息- explain [basic|extended] sql
- hint /* +monitor */, gv$sql_plan_monitor
- trace sql,查询sql的真实执行路径
set ob_enable_trace_log=1
show trace
- 查询explain视图
v$plan_cache_plan_stat、v$plan_cache_plan_explain## 位置信息
不同类型的表的location信息存储在三种不同的meta表中 - all_virtual_core_root_table 记录all_root_table的location
- all_root_table 记录集群中所有内置表的location
- all_virtual_meta_table 记录集群中所有租户的用户创建的表的分区location
副本类型
- 全能型副本(F)
- 日志型副本(L)
- 加密投票型副本(E)
- 只读型副本(R): 日志、memtable、sstable,非实时无选举- OB支持并行查询和DML
- DOP为并行度,默认开启分区DOP的并行,但分区内不并行
- dop=1 partiontion px,dop>1 block px
- 并行采用PX线程池,来抢占任务的方式执行
- 集群层面指定,px_workers_per_cpu_quota 每个cpu的最大并发线程;在租户层面,min_cpu*px_workers_per_cpu_quota为parallel_servers_target可配置的最大值
- 数据的分发,可分为,部分partion join、partion join、hash-hash、broadcast、random
- 关键视图,gv$sql_plan_statistics、gv$tenant_px_worker_stat、gv$sql_plan_monitor- ob的单元化,由于多租户、大集群的原因,可以有大单元,rpo等于零,配合primary zone的切换可以实现比主备库更快的切换和高性能。
- 分区表方案
- 分库分表可以采用ob-sharding,集成了sharding和proxy的功能- 结构迁移,关注对象、存储过程、代码、外键、DDL、环境字符集、
- 数据迁移设计
- 工具选择
- 校验设计、回流预案、双写预案
工具
- OMA迁移评估
- dbcat 结果转换
- obloader 离线迁移
- datax 异构数据同步
- oms实时迁移
OMS组件
store
jdbcwriter
checker
m-paxo负责选举和日志同步
日志按照分区进行同步,成员组信息包括paxos group 的成员列表和quorum信息
日志持久化内存的变化及事务状态等信息
trans_version通过keepalive消息同步到所有备机,为事务提供隔离性支持
日志服务维护副本的成员列表、leader等状态信息# 目录结构
etc存储配置文件,参数配置就在其中的observer.config.bin文件中;
log中有observer日志、rootservice日志、election选举日志,wf日志为warn以上的级别日志;日志格式中包含线程id、trace_id。
run目录存储了observer.pid
store目录存储clog、ilog、slog、sstable,前三种链接到/data/log1,后一种链接到/data/1中;sstable目录下有一个block_file文件,存放sstable数据
/ob_clog作用? sort_dir是否排序临时落盘/bin存放可执行文件
单进程多线程
- pidstat -p pid -t
- net io
- disk io
- dag 用于partition的转储、合并、迁移等
- clog writer
- election worker 选举线程
- misc timer 定时器线程
- sql/transaction worker线程是分租户的
- 租户的线程数由unit_cpu和每个cpu的woker数决定, 租户的线程数繁忙程度可以在observer日志中查看,采用dump tenant info 关键字查询 - parser(OceanBase使用lex进行词法分析,使用yacc进行语法分析,将SQL语句生成语法分析树)==词法语法分析==
- resolver(resolver将根据数据库元信息将SQL请求中的token翻译成对应的对象(例如库、表、列、索引等),生成的数据结构叫做Statement Tree)==语义分析==
- transformer(查询重写本质上是一个模式匹配的过程,先基于规则对SQL语句进行重写(这些规则如:恒真恒假条件简化、视图合并、内连接消除、子查询提升、外连接消除等等),之后进入基于代价的重写判定。相比总能带来性能提升的基于规则的重写,基于代价的重写多了代价评估这一步(需要查询优化器参与):基于访问对象的统计信息以及是否有索引,在进行了重写之后会对重写前后的执行计划进行比较,如果代价降低则接受,代价不减反增则拒绝。在迭代了基于代价的重写之后,如果接受了重写的SQL,内部会再迭代一次基于规则的重写,生成终态的内核认为的“好”SQL并给到查询优化器模块)==等价变换==
- optimizer(查询优化器是数据库管理系统的“大脑”,它会枚举传入语句的执行计划,基于代价模型和统计信息对每一个执行计划算出代价,并最终选取一条代价最低的执行计划。OceanBase的查询优化器基于System-R框架,是一个bottom-up的过程,通过选择基表访问路径、连接算法和连接顺序、最后综合一些其他算子来计算代价,从而生成最终的执行计划。)==计算选择优化生成最佳执行计划==
- code generator(优化器负责生成最佳的执行计划,但其输出的结果并不能立即执行,还需要通过代码生成器将其转换为可执行的代码)==生成可执行的代码==
- excutor,对于本地执行作业,从顶端算子开始,根据算子自身的逻辑完成整个执行过程;对于远程或分布式计划,分成多个可以调度的子计划,通过RPC将其发送给相关的节点执行。- 资源单元定义cpu、内存、IO、存储空间、会话等资源单元
- 资源池定义由多少资源单元组成、及zone列表
- 租户创建指定资源池及zone列表,主zone等
- cpu和内存可以超卖,resource_hard_limit参数控制
- 每10s打印一次dump tenant info,可以看到租户的规格、线程、队列及请求统计等信息
- unit可以在obs之间均衡,enable_rebalance控制unit和分区副本的均衡,resource_soft_limit小于100时,可以unit迁移。- 锁存储在行上,可能在磁盘或内存中,
- 在事务提交过程中,会有短暂的读写互斥,lock for read
- 视图
trans_lock_stat
lock_wait_stat
lcl_op_interval死锁检查- 两台observer之间的延迟应小于200ms,ntp偏差不超过100ms - 选取优先成员列表中版本号大的成员、clog日志数量多的
- 事务版本通过keepalive消息同步到所有的节点,为事务的隔离性提供支持
- RS负责集群的各类管理服务,使用paxos协议实现高可用
- observer通过心跳的方式,定期2s向rootservice汇报自己的进程状态,RS为每个OBS标识短暂下线和永久下线状态
- 每个租户一个GTS,__all_dummy表的leader作为gts服务提供者,时间来源于leader本地时钟; 有主改选gts,新leader获取旧leader最大已经授权的时间戳作为新leader时间戳授权的基准值,无主选举,需要等待lease过期。- 单集群可单点、单机房高可用、多机房高可用
- 一主多备份,为主备集群容灾提供保障,减少跨城的带宽,为升级、切换、容灾提供便利
- 多可用区模式,减少跨机房的网络流量
- 多AZ、单集群
- 单AZ、多集群 ==与一主多备相同==
- 多AZ、多集群## 路由机制
odp路由通过解析sql中的库、表名,通过obs的系统表获取分区的obs对应信息、分区的ddl及分区规则等,根据路由规则选择目标server。
内部表all_virtual_proxy_schema、all_vitrual_proxy_partition_info、all_virtual_proxy_partition、all_virtual_proxy_sub_partition
连接管理
- 客户端连接用于客户端和odp之间建立连接,服务端会话用于odp与obs之间建立连接。
- show processlist 查询当前租户的会话数量及会话ID
- show proxynet connection 查看ODP上所有网络连接的内部属性,可将网络的客户端和服务端对应起来
- show proxysession 查看ODP上所有租户连接的全部client session的内部状态
- show proxysession attribute 详细ODP client session信息,包括相关server session信息
- show proxysession stat 详细client session内部统计信息
- show proxysession variables 查看client session 变量
- 中止session,kill proxyssession 终止client session,kill proxysession (cs_id|connection_id)ss_id(show proxysession attribute id 获得)
- connection_id 为session id ,也为server session_id
路由规则
按照距离远近LDC(本地、同城、异地)、obs是否合并、zone的读写类型
强一致性读,只能将路由到对应分区的leader obs
弱一致性读,登录认证、强一致性读但没有指定表名等情况下
- 主备均衡路由(默认)
- 备优先路由
- 不合并备优先路由
路由参数 proxy_route_policy, 一致性参数ob_read_consistency
有只读zone的情况: - 只读zone优先路由
- 仅发送只读zone的路由
- 不合并zone优先## redo
在线redo和归档redo
undo
用于恢复事务
临时表
临时表产生的redo较少(undo的redo),但会生成undo
流程
创建undo的redo
创建数据块的redo
写入redo缓冲区
修改undo段
修改数据块- 一致读
“发现”要修改的行时,所完成的获取就是一致读
- 当前读
得到实际更新所需要修改的行时,获取的是当前读
ITL entries(在数据块中)存储undo记录指针,每个undo记录又会包含之前的ITL槽中包含的指针信息
itl里面记录了事务信息,回滚段的入口,事务类型等等
当会话开始一个事务,它先取得一个undo段,从那个undo段头的事务表中取得一条记录,然后增加该记录的wrap#值,将state修改为active,事务完成时,将state值设回free,将scn写入scn列,
事务xid中有undo段id+事务槽+重用次数组成
itl中的uba指包括由事务为该块生成的undo记录所在块的系列号,undo段头的uel记录下一个可用事务表槽- 段区块行 - system、sysaux、临时表空间、undo表空间、用户表空间
- 参数文件、跟踪文件(dump_dest)、警告文件(alert)、数据文件、临时文件、控制文件、redo、密码文件、块改变跟踪文件、闪回日志(数据库块的前印象)
- SGA、PGA、UGA(会话相关),UGA可能在pga或者sga中分配
- SGA包括java pool、large pool、shared pool(游标、存储过程、状态对象、字典缓存)、stream pool、null pool(块缓存、redo缓存、固定SGA)
- 专用/共享服务器连接进程,==一个连接包括多个会话==
- 后台进程,Pmon进程监视器、Smon系统监视器、reco分布式数据库恢复、ckpt监测点进程、DBWn数据块写入器、LGWR日志写入器、ARCn归档进程、DIAG诊断性进程、FBDA闪回数据归档进程、DBRM数据库资源管理器进程、GEN0通用任务执行进程、其它,rac中有很对缓存和锁的特有进程
- 用于大规模排序操作和散列操作、临时表、结果集- explain plan for SQL语句,select * from table(dbms_xplan.display)
- 之前已经执行过的SQL语句的执行计划
dbms_xplan.display_cursor(sql_id,cursor_child_no)
dbms_xplan还包括display、display_awr、sqlset、sql_paln_baseline - sqlplus中使用set autotrace on
- dbms_session.session_trace_enable(id)- DML锁(tx、TM)、DDL锁、latch、pin等
-
Paxos
Basic paxos
- 一个议题由(编号、值)组成
- 准备阶段,提议者和接受者首先对提议编号,达成回应承诺,提议者得到大多数的响应才能发起接受阶段请求
- 接受阶段,接受者只响应承诺的最大提议编号的请求,多数派达成一致则议题达成一致
Basic paxso存在的问题
- 多个提议者同时提交议案,可能提案编号重复,导致多次协商
- 2轮RPC性能差
Multi-paxos
- 先通过paxos确定领导者,leader通过不断续租lease的方式,连任
- 在领导者状态稳定的情况下,后续提议直接有leader发起,只进行接受阶段
raft
选举leader
- follower按照先来先服务的原则,针对大于自己的任期编号投出一张选票
- 由于日志中有任期编号,所以日志完整性高的follower拒绝给日志完整性低的follower投票
leader职责
- leader周期性的给follower发送心跳消息
- 提供客户端服务,并同步日志到follower
区别
- raft中只有日志较完整的节点才能当选leader,而且日志必须是连续的
- raft通过任期、领导者心跳信息、随机选举超时时间、先来先服务、大多数选票等保证一个任期只有一位领导## NLJ
- 用于任何条件
- 小表作为驱动表,内表有索引的情况
- 变体,blocked NLJ、index NLJ
- 内表可能会被物化
hash
- 大多数情况下hash join比其它方式效率更高
- 读取大多数行
- 通常将利用小表创建hash table(hash table较小有更好的效率),然后逐行扫描较大的表
- 只支持等值连接
- hash 支持切分多个
merge
- 需要有足够的内存
- 两张表大小相当
- merge适合两个输入表已经有序的情况,在大部分数据需要读取的情况下或者内表没有索引
- 是否支持不等联结?
小结
- NLJ提供更好的响应时间,而merge/hash有更大的吞吐量
- merge/hash适合处理大结果集
- hash并行能力更强
- merge/hash都需要对输入表全表扫描- 脏读:一个事务读到其它事务尚未提交的数据
- 不可重复读:由于其它事务的修改或删除,导致两次读到的数据不一致
- 幻读:由于其它事务的插入或修改,新增了满足条件的新结果集,导致两次读的结果集不一致
隔离级别
RU、RC、RR、串行化
幻读需要可串行隔离级别才可避免,oracle不是真实的可串行化