admin

  • 你一定要了解的Terraform

    ·

    HashiCorp正在筹备IPO,预计市值超100亿美金(参考)。创始人(参考)2011年大学毕业,2012年创建HashiCorp,2021年上市,又将是一个科技传奇。HashiCorp在Github上最受欢迎的项目就是Terraform,已经可以断定,Terraform会是未来资源编排服务的事实标准。

    Terraform在国内的使用还不是很多,讨论也不太多。这里就聊一下为什么开发者会选择Terraform,为什么企业应该选择Terraform作为资源编排的标准:

    1. Terraform目前已经支持了众多云厂商及其其他资源厂商,也可以反过来说,各个厂商都已经支持了terraform,对于各类云资源的管理,Terraform已经成为了IaC的事实标准。广泛的支持,让开发者不需要重复去学习和编写各个云厂商的API脚本,而是通过开源的方式,大家共用共建的Terraform内核能力,然后直接使用Terraform的描述性语言完成工作,直接复用了由开源社区构建的底层能力。

    2. 虽然各个云产生也都有自己的资源管理服务,例如AWS的CloudFormation、Azure的Azure Resource Manager、阿里云的ROS等。但对一家中/大型企业来说,通常都是使用了多云的资源,那么选择第三方的服务才是最简洁、效率最高的方式。无需重复适配各家厂商自己定义的规范和API。

    3. Terraform让基于云环境的Devops理念渗透到了底层资源上。通过tf脚本定义资源,创建资源后,后续流程可以根据tfstate状态文件,自动化的开始后续应用部署流程,无需人为介入,可以实现自动化的环境与资源部署,自动化与下游系统通信与衔接。

    4. 对于开发者来说,即便是在一家小企业,使用Terraform也是最合理的选择,一方面为未来的多云扩展做好了准备。另一方面,对于开发者自己,掌握了Terraform,应该是在市场上更加有竞争力的一种技能,可以应对更大规模、更复杂环境下的资源管理。

    5. 通过脚本语言定义资源,更加清晰,如果一个应用要在多个环境,部署很多的不同资源,还需要跨团队的协作,使用Terraform,就实现了用”代码描述资源”,也就是大家常说的IaC(Infrastuctur as Code),更加清晰,更加容易保障多环境部署资源的一致性,也有很好的传承性,新人进来也不需要用文档或者口口相传去解释环境应该如何部署。在传统架构下是这样,在多云时代,这个优势又被放大了。

    最后,关于HashiCorp和云厂商的关系,大家可以结合前两天Bluedavy那篇《国内云计算市场格局将走向何方》中的”惊悚建议”一起来看,应该更有意思。在开源厂商与云厂商的”竞合”中,可以说,开源厂商再下一城,未来更多的PaaS层会以各种方式去重塑云计算的市场格局。

    下面是一个简单的例子,可以简单直观的理解一下什么是Terrafrom。

    这时官方文档中国一个关于定义一个AWS EC2实例的代码(参考),这里省略了前面的安装和配置过程(注:需要配置一个Access Key用以授权)

    provider "aws" {
      profile = "default"
      region  = "us-west-2"
    }
    resource "aws_instance" "app_server" {
      ami           = "ami-830c94e3"
      instance_type = "t2.micro"
      tags = {
        Name = "ExampleAppServerInstance"
      }
    }

    当然,实际的过程中,”resource”中通常还会提供更多的参数来自定义你需要的实例,例如VPC网络配置、安全组等。

    之后,只需要使用如下执行命令,就可以完成资源的创建和创建后资源信息的查询:

    terraform init    // 初始化环境与版本
    terraform apply   // 实际创建资源
    terraform show    // 查看资源创建状态
  • 云数据库产品能力更新

    • [Azure] MySQL Flexible Server开始支持跨区域的备份能力:参考
    • [AWS] Aurora 发布 2.10.1版本(注:2.x.x是指兼容MySQL 5.7的版本):参考
    • [AWS] Aurora 发布新版本支持PostgreSQL 12.7版本,PostgreSQL社区该版本发布时间为5月13日(参考),Aurora大概在5个月时间完成小版本跟进:参考
    • [AWS] RDS Proxy开始支持MySQL 8.0版本:参考。使用RDS Proxy支持”连接池”(具备更好的扩展性,参考)、切换更加平滑等。
    • [AWS] RDS PostgreSQL支持13.4、12.8等版本。13.4和12.8社区版本发布时间是08月12日
    • [AWS] MemoryDB for Redis新增11个区域支持:参考
    • [GCP] Cloud SQL的优化建议开始支持闲置实例、规格过大、磁盘不足等建议:参考
    • [GCP] Cloud Spanner开始支持PostgreSQL兼容的接口:参考
    • [GCP] Cloud Spanner支持通过对Query打标而进行性能数据统计:参考
    • [阿里云] AnalyticDB PostgreSQL版开始支持”基础版”实例,大幅降低小规格建仓成本:参考
    • [阿里云] 开始支持MongoDB 5.0版本,在所有云厂商的一方产品中率先支持该版本:参考
    • [阿里云] 杭州、深圳地区金融云RDS开始支持云盘加密功能:参考
    • [腾讯云] TDSQL-C(原CynosDB)开始支持MySQL 8.0:参考
    • [腾讯云] 数据传输的订阅功能开始支持TDSQL MySQL版:参考
    • [华为云] GaussDB(for Redis)开始慢日志、公网SSL加密、Lua脚本等功能:参考
    • PostgreSQL 14正式发布:参考,Percona上的相关解读:参考
    • [OceanBase​] 发布3.2版本;开源发布3.1.1版本

    云产品其他重要更新

    • 阿里云计划在2020年新开韩国和泰国区域:参考
    • Percona再AWS上用Sysbench分别测试了EC2上AMD、Intel、Graviton(ARM)的实例性能情况:参考
    • [AWS] EC2的Mac实例新增更多区域支持:参考。AWS EC2竟然支持MacOS的实例…。
    • [AWS] EC2控制台开始支持从全球视角展示所有相关资源:参考。就问你爽不爽!!
    (more…)
  • 云数据库产品能力更新

    • [Azure] Flexible Server开始支持跨区域的备份能力
    • [AWS] Aurora 发布新版本支持PostgreSQL 12.7
    • [AWS] RDS Proxy开始支持MySQL 8.0版本
    • [GCP] Cloud SQL的优化建议开始支持闲置实例、规格过大、磁盘不足等建议
    • [GCP] Cloud Spanner开始兼容PostgreSQL
    • [阿里云] AnalyticDB PostgreSQL开始支持”基础版”
    • [阿里云] 开始支持MongoDB 5.0版本
    • [腾讯云] TDSQL-C(原CynosDB)支持MySQL 8.0
    • [华为云] GaussDB(Redis)支持慢日志、SSL加密等功能
    • [社区] PostgreSQL 14正式发布
    • [OceanBase] 发布3.2版本;开源发布3.1.1版本

    云产品其他重要更新

    • [阿里云] 阿里云计划在2020年新开韩国和泰国区域
    • [AWS] EC2的Mac实例新增更多区域支持
    • [AWS] EC2控制台开始支持从全球视角展示所有相关资源(就问你爽不爽!!)
    • 中国数据库技术大会DTCC在北京举行“DTCC 2021在北京国际会议中心隆重召开。大会以“数造未来”为主题,国内各个数据库相关厂商悉数亮相” 。

    阿里云PolarDB-X正式开源

    “我们将阿里最核心的云原生数据库技术进行开源,希望开发者和客户通过开源版本快速使用阿里云数据库产品技术,并参与到技术产品的迭代过程中来,共建云原生分布式数据库生态。”阿里云数据库负责人李飞飞表示。

    阿里云发布首个一站式敏捷数据仓库解决方案

    该方案结合一站式数据管理平台DMS及云原生数据仓库AnalyticDB(以下简称ADB),真正实现了库仓一体的技术架构,提供在线数据实时入仓、T+1周期性快照、按需建仓等能力,数据延时低至秒级,持续赋能业务在线化,令企业在线数据释放最大价值。

    OceanBase 发布3.2版本;开源版本3.1.1发布

    杨传辉透露:OceanBase 3.2 是今年 6 月 1 日产品发布会宣布进入 3.0 时代后的首个重大版本。3.2 版围绕兼容性、HTAP 混合负载、小规格性价比等几大核心能力,在 Oracle/MySQL 兼容、易用性、稳定性、性能和功能等诸多方面做了迭代增强与优化升级。

    2021年10月18日,在第十二届中国数据库技术大会(DTCC2021)上,OceanBase CTO杨传辉分享了“一体化架构的原生分布式数据库”主题演讲,并公布了 OceanBase开源项目的进展以及开源版3.1.1的正式发布。

    “腾讯云TDSQL X 昆山农商银行”新一代核心系统上线

    昆山农商行新一代核心系统采用长亮V8技术,无缝衔接国产分布式数据库TDSQL,并融入微服务、读写分离、多源同步等技术…所有集群运行在一套TDSQL集群中。架构上,昆山农商行采用“两地三中心”部署,数据库“一主三备”,中心间数据强同步,实现中心级别灾难快速自动恢复,且数据零丢失。

    阿里云数据库 X 中电金信发布“实时数仓系统”和“智慧水务”解决方案

    共同推动阿里云云原生数据库的技术与生态构建,赋能行业数字化转型。其中,“智慧水务”解决方案在数据库层依托阿里云数据库PolarDB、AnalyticDB等系列产品首次实现了完整的全国产化方案。“实时数仓系统”基于AnalyticDB产品,从采集、治理到服务整个流程,实现数据的高效流转…

    GaussDB数据库培训服务上线

    本次上线的数据库培训服务主要包括华为openGauss数据库工程师培训(HCIA-openGauss)、华为GaussDB数据库工程师培训(HCIA-GaussDB)、华为GaussDB数据库高级工程师培训(HCIP-GaussDB-OLTP)等3项课程,涵盖数据库基础知识、GaussDB数据库产品介绍及SQL语法、性能调优、数据库关键特性解析等内容,全方位解锁数据库知识,让您轻松Get数据库专业技能。

    TiDB 登陆亚马逊云科技 Marketplace(中国区)

    企业级开源分布式数据库 TiDB 登陆亚马逊云科技 Marketplace(中国区),通过亚马逊云科技 Marketplace(中国区)网站 ,用户可以快速部署和使用 TiDB,获得更顺滑的 TiDB 分布式数据库云端体验。” 

    巨杉数据库入选”2021信创产业独角兽100强”

    由中科院旗下权威媒体《互联网周刊》联合eNet研究院、德本咨询调研评选的“2021信创产业独角兽100强”名单揭晓公布,巨杉数据库作为国产数据库,凭借在基础软件领域的产品技术优势入选榜单” 。以数据库为主的企业入选的还有:达梦、人大金仓、南大通用、神舟通用、巨杉数据库、PingCAP、易鲸捷、爱可生等。

    3306π-上海站:GreatSQL && Databend 

    2021年3306π上海站-开源数据库技术交流,于10.23日在上海虹口逸仙路宝丰联酒店圆满举办。”

    万里数据库开源生态负责人叶金荣老师现场带来《面向金融级 MGR 应用场景优化》的技术主题分享,分别从GreatSQL新增金融级应用场景特性、稳定性和性能提升工作及万里数据库研发团队修复的严重MGR bug等方面展开阐述

    BohuTang在3306π介绍了云原生开源数仓系统Databend架构及展望,BohuTang2021年3月从青云离职和朋友们组建了:Datafuse Labs, 使用 Rust 研发一款开源的、完全面向云架构的新式数仓,用于提供极速的弹性扩展能力,致力于打造一个按需、按量计费的数据分析云平台。

    长沙·中国1024程序员节举行,围绕国产基础软件展开

    “长沙·中国1024程序员节是CSDN和长沙市政府相关机构联合主办的年度大会。主要围绕中国核心基础软件和先进计算技术,首聚十大中国数据库掌门人…

    小编”离散”的点评

    • 最近一周是云栖大会,所以阿里云数据库的相关发布也会比较多。
    • 什么?AWS EC2竟然支持MacOS的实例…
    • Azure云的MySQL托管形态Flexible Server一直在快速更新,虽然当前依旧处于Preview。
    • AWS Aurora支持了PostgreSQL 12.7版本,该社区版本发布时间为5月13日,Aurora的PostgreSQL研发团队需要5个月的时间完成一个小版本的改造支持。再比如,Aurora的12.6版本支持时间为6月,社区该版本发布时间为2月。考虑到,Aurora需要做的改造,这个速度应该是比较快的。
    • AWS RDS在10月初支持了13.4和12.8版本,该社区版本发布时间为08月12日,可以看到AWS RDS团队对于对PostgreSQL社区最新社区版本支持大概延迟2个月,考虑到需要适配AWS RDS后端系统,2个月也还是比较快的。
    • 近几年,开源、分布式数据库和分析型数据库是创业的热点之一,整个领域都非常活跃。
    • 上周末,OB的”礼物求赞”的事情发酵的有些厉害,不过,希望OB继续加油,中国开源继续加油。话说,其实技术运营并不好做,需要比预想的更大的投入,这点PingCAP是做得非常成功的,值得学习。

    最后,文中原本很多的参考链接,由于微信公众号的限制都删除了,如需延伸阅读,大家可以点击左下角”阅读原文”后查看。另外,如有错误或者投稿可以通过orczhou@gmail.com联系本文作者。

  • 今天云栖大会第二天,主要以产品技术为主。相比第一天,要更加面向开发者。主要的产品技术发布也都是放在这一天,阿里云数据库的很多重磅发布也是放在今天。

    百花齐放的开源

    这次大会上,阿里云数据库负责人李飞飞正式宣布“PolarDB-X开源“。随之,对应的代码也已经在Github(参考)上放出。PolarDB-X的前身是阿里集团去IOE核心产品DRDS,经过了面向云的改进,提供了原生的一体化的分布式能力,全面升级为现在的PolarDB-X,这次开源,应该是这个产品面向未来发展跨出的一大步。

    最近两天,除了云栖大会之外,数据库的年度盛会DTCC也在同步进行。在DTCC上,OceanBase也正式发布了开源版本3.1.1,提供了更强的MySQL兼容能力、开放了更多底层API、对第三方生态也提供更友好的支持等。

    此外,在主会场的计算巢平台发布中,PingCAP也是其重要的生态伙伴。阿里云计算巢(参考)是一个面向云端第三方服务商的平台,通过用户主动授权可以更加简单让第三方服务商在用户环境中构建相应的应用。

    在全球来看,开源已经是非常成熟的模式了,无论是运作还是商业化,都是非常成熟的。但是,在中国开源模式还有很多内容去探索,非常期待后续的发展。

    进击的“PolarDB”:将云原生进行到底

    这次李飞飞还对外重磅发布了PolarDB的“计算、内存、存储全解耦“的云原生架构。PolarDB产品技术在云原生的道路上再向前跨进一步,也是国内外领先的一步,首次实现了计算、内存、存储的三层解耦,提供内存池化、多主架构、HTAP实时分析等产品能力。自PolarDB产品上市以来,这应该是又一次大的技术跨越,相比Aurora等友商有一定的技术代差。后续,非常期待这个能力,进一步完成标准的产品化与规模化。

    面向政企市场

    多次被提及的“政企市场”

    这次数据库的产品发布中,听到了多次“政企市场”。一个是PolarDB-X的开源中,标题为“助理政企构建原生MySQL分布式数据库”。另外,在DBStack的发布过程中也提到,“将云原生能力轻量化输出到政企行业“。可以看到,目前阿里云已经在公共云市场全面领先,但是大量的政企线下市场还待开发,这次重磅发布很多产品能力建设都聚焦于此,可以看到未来,这这部分市场还将有着非常激烈的竞争。

    其他

    这次还发布了提供离在线一体、MPP架构、具备Serverless云原生能力的AnalyticDB,轻量级的混合云方案DBStack(链接),企业级智能化的RDS,企业级一站式在线数据库管理平台DMS,书籍《云原生数据库原理与实践》,data in use的加密技术等,就不一一详述了。

  • 在前面两篇文章,较为系统介绍了B-TreeB+-Tree的基础。本文则以InnoDB为例,来看看B+-Tree内部排序的实现。

    简单回顾B-Tree存储

    在前面B-Tree基础文章中,我们了解到在一个B-TreeB+-Tree的“节点”通常可以存放很多的“索引入口”。在数据库实践中,通常一个“节点”大小为16KB8KB。一个索引入口的结构一般是:\( (k_i,p_i,\alpha_i) \) 、 \( (k_i,p_i) \)、\( (k_i,\alpha_i) \),具体的,在叶子节点上通常为\( (k_i,\alpha_i) \),而非叶子节点则为: \( (k_i,p_i) \)。

    那么,在实际的设计中,一个“节点”可以存储多个“索引入口”,在非叶子节点,主要存储键值和到子节点的指针,即 \( (k_i,p_i) \);叶子节点中,则存储键值和相关数据,即\( (k_i,\alpha_i) \)。

    问题描述

    在很多的B+-Tree实现中,一个节点可以存储几十、甚至数百个的“索引入口”。而我们在前面看到的示意图中,看起来节点内部的数据似乎是按照键值排好序的,但在实际实现中,这里以InnoDBB+-Tree实现为例,问题要更复杂一些,主要考虑如下:

    • B+-Tree中的“数据”\( \alpha_i \)可能是变长的,并且内容很大,例如200~300个Bytes。例如,在InnoDB的Clustered Index中,表结构是 id int, nick varchar(32),realname varchar(32),birthday date,password char(32),email varchar(60),字符集是utf8mb4
    • 查询搜索是一方面,还需要更快的写入速度,从而提升数据库的事务吞吐量
    • 依旧需要节点内部非常便利的顺序查找,以满足搜索、范围扫描等需要

    以“堆”的形式存储

    为了满足变长、快速存储的要求,InnoDB页面内部使用了典型的“堆”的形式组织数据,这也是数据库数据存储实现的一般模式。即,每次数据写入时,将数据存储在堆的“顶端”(或者中间的空洞),如右图:

    • 对于最后写入的新记录\( (31,\alpha_5) \),不考虑排序,直接放在“堆顶端”
    • 每条记录的大小不同,按“堆”遍历时,可以根据每条记录的元信息,到一条记录的头部(即本记录的尾部)

    但在B+-Tree中遍历时,更多的是需要顺序遍历,例如键值搜索、范围查找等场景。那么,按“堆”存储的记录,就需要一种顺序遍历的方式。

    B+-Tree页内搜索实现概述

    逻辑实现说明

    一种直观的思维是这样,在页面的某个特殊区域,新建一个“数组”(记录指针或偏移),顺序排列所有的记录。每次需要搜索时,则在该数据中进行二分或插值搜索。这种存储模式的优势是,简单而直接,且易于维护。但对于关系型数据库来说,如果数据写入或更新频繁,那么这个数组的维护会有非常频繁的数据拷贝。

    InnoDB的实现(我后面要去看看Jim Gray的那本书,看看是否有描述这些细节)并没有使用这种直接的实现,而是做了一些变化:

    • 在每条被存储的记录Header部分,都存储了按排序顺序的下一条记录的位置(页内偏移量),所以InnoDB的页内记录可以看做是一个按键值大小排序的链表
    • 页面开辟了一片区域(Page Directory)存储“部分”页内记录的偏移,这些记录的选取与Skip List实现类似。即按排序顺序,并按一定的间隔取部分记录放到Page Directory中,并将Page Directory间隔两个记录之间在页内的所有记录称为一个SlotPage Directory中的这条记录则可以称为一个SlotSlot Header

    上右图是在GitHub上搜索到的由SmartKeyerror绘制的关于Page Directory的示意图[6],是比较准确且直观的。

    所以,在进行搜索时(InnoDB的实现):

    • 首先,在Page Directory中的各个Slot Header中做二分查找
    • 然后,再在Slot中进行线性搜索,即逐个向前比较

    InnoDB中,一个Slot有4~8个记录,所以,可以认为一个500条记录的页面,需要做的比较次数约为(考虑平均每个slot中6条记录):

    $$
    log_2(\frac{500}{6}) + \frac{6}{2} \approx 9.38
    $$

    在实际中,可能会有多次CPUCache Miss发生,所以实际的成本比看起来的9.38次要略微高一些,但作为粗略预估,这个计算也是合理的。

    InnoDB 物理存储实现说明

    厘清物理层的实现,还是稍微花了一些时间的。在Jeremy Cole 2013 Efficiently traversing InnoDB B+Trees with the page directory 中对于Page Directory实现页内搜索做了比较详细的说明,并且在讨论中也一些有意思的讨论。但,对于其中的几个问题做了一些验证,还是有一些更细致的补充说明。

    上面,SmartKeyerror绘制的关于Page Directory图在逻辑上是没有太大问题的,但就物理实现,则容易引起一些误解,故绘制了新的示意图如右下,以更准确的反映InnoDB物理存储的结构:

    • Page Directory就是一个存储页内偏移的“数组”,就是右图的深红色部分
    • 每个slot使用2 Bytes,存储的是对应记录的页内偏移

    相比于逻辑结构,物理结构上,需要注意的是:

    • “记录”在页内物理位置,并不是按键值大小排列,而通常是按照插入时间向下生长的
    • Page Directory存储在页面的底部,从高位地址向低位地址扩展;此外,SlotInnoDB中的逻辑概念

    更多关于Page Directory实现细节

    一般的了解了Page Directory的实现逻辑以及概述,基本上就可以了,也算是清楚了InnoDB页内搜索的实现。本小结为一个扩展阅读部分,描述更多关于slot结构、搜索、查找的细节。

    InnoDB的代码参考

    在了解Page Directory的过程中,还是阅读了部分InnoDB的代码,主要是innobase/page/page0page.c以及相关的代码。在该文件中,也有很多的注释可以阅读。这里列举部分函数,算是验证一下上述的部分理解。这里的示例代码来自版本:MySQL-4.1.7

    InnoDB 代码中的Page Directory

    page0page.c 中的注释

    这段注释在page0page.c文件中,是InnoDB最早、也是最为原始的关于page directoryslot的说明与介绍,非常建议阅读。

    另外,这段注释中最后:50 x 4 bytes = 200 bytes这部分估算应该是有错误的,应该是50 x 2 bytes = 100 bytes。在16KB的页面中,2 bytes存储偏移量是够了的,而实际实现中也是2 bytes

    #define PAGE_DIR_SLOT_SIZE  2

    当然,如果一定要“找补”,那么也可以把每条记录中用于存放slot中记录数量的4-bit也算进来的话,那么平均一个slot需要:

    $$ 2+\frac{6*4}{8} \approx 5 $$

    /*          THE INDEX PAGE
                ==============
    
    The index page consists of a page header which contains the page's
    id and other information. On top of it are the the index records
    in a heap linked into a one way linear list according to alphabetic order.
    
    Just below page end is an array of pointers which we call page directory,
    to about every sixth record in the list. The pointers are placed in
    the directory in the alphabetical order of the records pointed to,
    enabling us to make binary search using the array. Each slot n:o I
    in the directory points to a record, where a 4-bit field contains a count
    of those records which are in the linear list between pointer I and
    the pointer I - 1 in the directory, including the record
    pointed to by pointer I and not including the record pointed to by I - 1.
    We say that the record pointed to by slot I, or that slot I, owns
    these records. The count is always kept in the range 4 to 8, with
    the exception that it is 1 for the first slot, and 1--8 for the second slot.
    
    An essentially binary search can be performed in the list of index
    records, like we could do if we had pointer to every record in the
    page directory. The data structure is, however, more efficient when
    we are doing inserts, because most inserts are just pushed on a heap.
    Only every 8th insert requires block move in the directory pointer
    table, which itself is quite small. A record is deleted from the page
    by just taking it off the linear list and updating the number of owned
    records-field of the record which owns it, and updating the page directory,
    if necessary. A special case is the one when the record owns itself.
    Because the overhead of inserts is so small, we may also increase the
    page size from the projected default of 8 kB to 64 kB without too
    much loss of efficiency in inserts. Bigger page becomes actual
    when the disk transfer rate compared to seek and latency time rises.
    On the present system, the page size is set so that the page transfer
    time (3 ms) is 20 % of the disk random access time (15 ms).
    
    When the page is split, merged, or becomes full but contains deleted
    records, we have to reorganize the page.
    
    Assuming a page size of 8 kB, a typical index page of a secondary
    index contains 300 index entries, and the size of the page directory
    is 50 x 4 bytes = 200 bytes. */

    从这里也可以看出来,因为InnoDB的页内地址很多地方是用的2 Bytes的存储偏移量,所以InnoDB单个页面大小也受此限制,最大为 \( 2^{16} \text{Bytes} = 64 \text{KB} \)。(参考:innodb_page_size

    page_dir_get_nth_slot

    该函数输入是一个页面指针,返回该页面的第\( n \)个slot的指针。下右为InnoDB中的源码,下左则是代码部分对应的示意图:

    Gets pointer to nth directory slot. */
    UNIV_INLINE
    page_dir_slot_t* page_dir_get_nth_slot(
                /* out: pointer to dir slot */
        page_t* page,   /* in: index page */
        ulint   n)  /* in: position */
    {
        ut_ad(page_header_get_field(page, PAGE_N_DIR_SLOTS) > n);
        return(page + UNIV_PAGE_SIZE - PAGE_DIR
                        - (n + 1) * PAGE_DIR_SLOT_SIZE);
    }

    其他的优化

    在 G. Graefe 2010 Modern B-Tree Techniques 中概述了B-Tree中使用Interpolation Search优化Binary Search的选择问题。关于这个问题,G. Graefe在另一篇Survey性质的论文中,较为系统的描述使用插值优化的一些相关技术:B-tree indexes, interpolation search, and skew.[2]

    这篇论文[2]介绍了很多使用插值优化二分查找的考虑,但对于InnoDB似乎并不适用,主要原因是,在InnoDB中很多的Key都不是整数,且Key的类型会比较复杂,例如字符串、多字段组合等,并没有很简单的插值计算。此外,在当前的InnoDB实现中,各个Slot并没有存储实际的Key值,而是存储Key所在的页内偏移,即如果要进行Key比较,则一定要跳转到页面的其他位置,而这与论文中的描述想避免CPUCache Miss的理念是冲突的。

    一些遗留的问题:

    • 一个slotPAGE_DIR_SLOT_MAX_N_OWNED就是8,那么如果b-tree结构的相同key就超过8个,如何处理? (可能就直接截断就可以了,在搜索slot的时候需要注意处理这种情况)

    B-tree indexes, interpolation search, and skew.

    这是一篇研究B-Tree内部搜索性能的文章。B-Tree的最为主要的访问成本是从存储到内存,但作者认为,在某些场景下,需要关注CPU和内存处理的成本。这里的“某些场景”作者认为在变得更为重要,具体的,“某些场景”包括:

    • 现在的内存变得很大,页面命中率变得非常高,只有很少的页面需要从存储读取
    • 由于B-Tree的特性,页面读取的效率已经非常优秀了,已经是对数级的了

    此外,作者还注意到:硬件技术的发展上,更多的是带宽的提升,而不是延迟的提升,这包括两个方面(磁盘到内存、内存到CPU)。

    所以,作者把注意力放到了CPU处理效率的提升上。作者在论文中的预估是这样:在这个场景下,如果一个页面中有500个索引入口,那么页面内部的二分查找,就需要做:\( log_{2}500 \approx 18 \) 次比较操作以及对应的内存访问操作。

    这里做过了一些初步的测试,在当代的CPU中,通常都会有32KBL1 Cache ,故这里的部分事实已经不成立了。不过还是把这篇论文看完,看看作者的思考是什么。

    相比于二分查找,插值查找则每次从区间的某个相对位置开始进行搜索,这个相对位置则使用插值的方式获得,而不是简单的从中点开始(二分查找)。如果,键值模型恰好是一个线性模型的时候,这个时候线性插值的效率就会非常完美。而现实中,确实很多就是线性分布的。这篇文章的目的:The topic and purpose of this paper is to survey techniques that avoid the worst case of interpolation search. 看看有哪些技术,避免差值查找的糟糕情况发生。

    更细致的关于B-Tree和CPU Cache相关的讨论:[GL 01] G Graefe, P Larson: B-tree indexes and CPU caches. ICDE 2001, 349-358.

    一些研究的方向:

    • 最为直接的:使用一个类似的B-Tree结构,可能是二叉树、红黑树等
    • 为了让这部分索引能够更快速,能够让其存放到CPU缓存中,会考虑删除前缀或后缀
    • 此外,考虑利用B-Tree的多层索引,与CPU的多级缓存进行适配

    阅读这篇论文的收获是了解大家考虑问题的方法,大家的思考方式,以及对各种技术边界的拓展。例如,

    • 了解到大家对于程序实现的考虑,如何去思考处理器技术对于程序效率的影响,L1 Cache、L2 Cache以及指令Cache等如何影响CPU的效率。这些技术远看,其实并不算特别复杂,但是有了这些思考,对于计算机性能、架构的理解是不一样的。包括这里提到的一个论文中的观点:L1 Cache for Instruction 和 L2 Cache for Data 对于事务处理技术更为重要。这个观点就很有意思,当然,在当下,当然未必适用,但是这个思考方式可能是很重要的。如果对于这些技术非常了解,才有可能写出,诸如Redis、ClickHouse、DuckDB等这些性能非常极致的产品(大概是这样吧)。

    再比如这两篇论文中的一些计算,可以看到如何考虑程序的效率,包括CPU时间、存储时间等。

    在这里的一些考虑,看看他的计算和实现吧:在当时(这篇论文时候),一次\( \text{Page Access} \) 计为 \( 8ms \) ,传输时间为 \( 0.1ms \),如果页面中有 256 个索引入口。

    考虑一个计算指标( “utility” of a disk page )即:

    $$
    \frac{\text{counter of comparison}}{\text{page access latency} + \text{page transfer time}}
    $$

    那么,256个入口,一个典型的二分查找需要约:\( \log_2{256} \) 次比较,则:\( utility = \frac{8}{8+0.1} = 0.987 \);

    那么,如果页面大小增加到当前的八倍,那么需要的比较次数:\( \log_2{256*8} = 11 \),延迟依旧是 \( 8ms \) ,传输时间则为:\( 8*0.1 ms \),则:\( utility = \frac{11}{8+0.8} = 1.25 \)

    根据这里的计算,最优的页面大小,应该远远大于各个数据库系统中实际使用值。对于现代CPU来说,相比于处理指令,处理性能需要优先考虑cache miss以及pipeline stalls。在一些论文中对相关问题做了一些量化分析,有一些可以参考的结论,例如在事务处理时,最为重要的是L1的指令缓存和L2的数据缓存([ADH 99].)。所以实现的主要考虑包括:代码量(具体的某个功能模块)的多少、复杂度,以及L2 Data Cache Miss。

    页大小

    概述:对于非叶子节点(尤其是靠近根节点的),使用非常大的页面大小是有一定道理的,但叶子节点则不应该页面太大。非叶子节点的使用率是非常高的,并且数量相比于叶子节点要少很多;但叶子节点,则不同。当需要读取某个叶子节点时,通常只是为了读取某一条记录(典型的OLTP场景),为了一条记录而读取过大的页面,会导致内存利用率的降低,反而会导致整体的性能降低。

    在实践场景中,如果这个问题很关键或者有人对这个问题感兴趣,是可以做一些量化的分析的。把整个流程的时间、命中率、数据大小等相关的因素都考虑上,然后做一个最优化的分析。只是呢,B-Tree是一个比较古老的话题,大家对于这个数据结构的关注可能没有那么高了。

    分裂和合并的选择

    分裂与合并,不同的实现会有一些不同选择,包括:

    • 提前分裂,例如页面的占用率超过了一定的比率就进行分裂;结合插值算法考虑,如果页面里面的值,可以非常好的分裂为两个非常适合插值的区间,也可以考虑优先进行分裂。
    • 在某些实现中,删除的时候,从不触发合并,而是在某种“碎片整理”的时候才进行合并或分裂处理

    回退到二分查找

    在数据分布非常倾斜的情况,插值查找的效率可能会非常糟糕。需要考虑回退到二分查找。一些常见的策略是这样:

    • 例如,进行了3、4次差值查找还没有找到目标,那么可以回退到二分查找
    • 可以考虑根据第一、二次查找的效率做一些预估,预估效果差,则回退到二分查找
    • 在差值查找中,考虑使用二分查找做一些修正,最终后再退回二分查找

    正规化处理

    • key是字符串的时候,通常需要考虑先进行一定的正规化处理,以可以更好的进行大小比较。
    • 前缀删除。和一般的索引/搜索技术一样,如果有公共前缀可能会大大降低效率。

    回归差值

    在进行了一些插值计算后,可以考虑使用这些值进行回归计算。

    相关性分析

    可以对一个节点内的值,先进行一次回归分析,并考虑定期进行回归分析,从而判断插值搜索的效果。

    一个感受:在SSD推出之初,有很多人认为,B-Tree可能不再适用于数据库的存储(或其他场景的存储),可能要有更有的存储结构适配新的硬件(SSD)。但实际的情况是,在现在的几乎所有的存储硬件中,B-Tree依旧非常成功。这是因为,B-Tree所解决的问题本质并没有改变:内存访问的速度/成本远高于“磁盘”(HDD或者SDD、甚至S3等块存储)存储设备。这时候,B-Tree这种多路、平衡树结构依旧非常有效。(注:LSM-Tree 在很多模型下,也是非常适用的,这是另一个问题)

    名词说明

    • B+TreeB+-Tree 均指B+-Tree
    • 一般的,B-Tree指狭义的、经典的B-Tree,该结构主要参考:了解 InnoDB 的索引结构:B-Tree 基础
    • 有时候,B-Tree也会指代B+-Tree或其他B-Tree变种;这种用法也是非常广泛的,例如,在MySQL/InnoDB的文档中,仅使用B-Tree,而更为准确的说是B+-Tree
    • “节点”(Node)、“页面”(Page)、“数据块”、“块”(Block)等均指存储B-TreeB+-Tree的节点,即树结构的节点,内部可以存储多个键值。在不同的语境下,大家会用不同的词,例如通常在算法课程/书籍中,会更多的使用“节点”(Node);而在数据库实现中,则更喜欢用“页面”(Page)或“块”(Block);更为细节的,如果在内存中,则更多的时候用“页面”(Page),在磁盘上,则更多的“块”(Block)。各种情况下混用的也很多,并没有什么问题。
    • “记录”(record)、“行”(row)、tuple都是表示表中的一行记录,通常包含多个字段数据。
    • 索引入口(Entry)等是指完整的“键值对”,在叶子节点中,通常包括\( (k_i, a_i) \);在非叶子节点中可能的形式是:\( (k_i,p_i, a_i) \) 或 \( (k_i, p_i) \)
    • TAOCP 是 “The Art of Computer Programming”的缩写

    参考

    本文主要参考内容为:

  • 8月7日 游西湖

    ·

    早上七点,苏堤集合。绕道曲院风荷,经过玉带晴虹,回到苏堤,经过压堤桥、苏堤春晓、望山桥、锁澜桥,到达花港观鱼,再到西湖国宾馆。

    夏天,太阳起得很早,起得早的人却不多。一行5人,全程总计约4公里,不紧不慢,先到G20展馆二楼喝茶叙旧,之后到紫微厅午餐。

    次日,一家人再到湖畔茶居,饮茶一杯,贪享半日湖光美景。

    (more…)