当前位置: 首页 > news >正文

2022-09-01 mysql/stonedb-多线程并行遍历元组遇到的问题分析

摘要:

此前的文章中介绍了使用多核cpu去分子集的访问元组并解析数据,以提升访问性能的一般性思想。但是在工程实践中遇到了很多现实性的问题。

本文对遇到的问题做追踪。

数据结构决定算法

采用何种数据结构,决定了所能执行的操作。或者说,就是在设计程序时的数据模型,甚至于说是数学模型,决定了其上的操作。

重提这句话是目的, 在于说明做多线程并行时,困难点不在于线程的任务的包装,而在于更底层的模块中包含的数据,这些数据被封装在不同的类之后,模块的抽象级别和内聚程度。

这决定了在物理存储引擎之上的逻辑层,被限制到了何种程度,以及以何种粒度来使用物理引擎的数据结构。

依赖倒置: 下层决定了上层的逻辑,而非上层决定了下层的逻辑

设计模式的这个原则,目的首先是为了从横向对功能进行分解,其实也很好理解,更下层面临更多的要处理的细节,给上层提供的接口,必然是本层抽象之后的。必须首先对更底层的进行建模,然后逐层抽象,如果直接由上层的逻辑来决定下层模块的内部逻辑,表面上看起来符合问题分解和分治原则,但是现实情况是更上层由于受业务需求影响更大,导致承载的需求变动距离,架构设计层面更多考虑灵活性,这种灵活对于底层的数据模型而言是灾难性的。难以想象由于逻辑层的需求调整,导致物理层的存储实现方式的修改。

在理解了一些设计的常识之后,就可以理解下面所面临的困境了。

直接修改为多线程访问不同的元组子集所产生的问题:

一. 多线程切换后, 出现上一次本线程加载的pack数据无法访问,导致需要重新加载

问题现象:

可以参考: 2022-09-07 mysql/stonedb-多线程遍历元组问题分析_帝尊悟世的博客-CSDN博客

  1.  单个线程访问没问题
  2.  开启多个线程,但是其他线程不去处理,仅留一个线程处理,也没问题
  3. 开启多个线程并行处理, 切换到本线程之后,上一次加载的pack数据丢失
  4. 开启多线程并行处理,在每一次处理元组时都强制加载一次pack数据,处理结果正确。但是由于每次处理元组多加载pack数据,总耗时大于单线程时的处理

问题分析:

开启多个线程,但是只有一个线程去处理任务,不发生问题,那么

  1. 排除元组分割和任务数据的问题
  2. 排除对pack数据读取和解压的问题。

线程切换导致本线程已经读取的pack无法再读取, 有以下原因:

  1. 其他线程读取的pack数据覆盖了本线程读取的pack数据
    1. 排查思路是: pack数据读取后存放的位置 -> 锁定cache -> cache缓冲区的修改逻辑
    2. 需要思考是否此前的读取逻辑中,如何设计读取数据后的缓冲区
  2. 其他线程对本线程的数据产生了更多的临界区干扰
    1. MIterator指向了MulIndex, 与DimenGroup存在引用关系
    2. 对迭代器做深复制,只是复制了对底层数据的引用,下层数据还是位于临界区。采取类似并行HashJoin的任务模型做更多的模块关系的拷贝
      1. 这里存在可行性问题,并行HashJoin模块从输入到输出,以及其中的处理都与直接遍历迥异。需要更多的时间理解并行HashJoin对于模块的数据拷贝和单个任务中如何存放单个任务的数据缓存。
    3. 更下层的虚拟列和物理列与Pack和DPN的交互
      1. 提出这点主要是dump的位置正是在物理列中通过DPN拿到对Pack的引用发现没有数据,而对Pack数据的提取在于LockPack时。时序上位于遍历到Pack的开始时,调用LockPack加载下一次Pack的数据。
      2. 线程切换后,发生已经加载的Pack的数据丢失。具体为通过rc_attr拿数据时,是从物理列提取,此时Pack的数据是应位于cache内被使用。

问题解决:

问题的解决不是那么清晰,原因在于难以在不破坏其他模块的情况下,仅修改逻辑层的处理,就达到目的

  1. 线程读取Pack后的Cache与其他线程存在覆盖问题(需要更多的定位)
  2. 对虚拟列和物理列的所有逻辑,并未掌握全部细节
    1. 即使掌握了全部细节,如果该设计不符合需求,也面临被改造,那么就必须掌握所有相关模块的逻辑,从而保证改造不会出现未知风险。
  3. 同时面临AP领域业务知识的缺乏和数据库理论的具体实现的实践的缺乏

要解决这些问题,有一些做法,但是都需要耗费精力的投入和模块逻辑变动引发的连锁反应的风险,更别说所要面临的投入时间上的损耗

  1.  将逻辑层和物理层涉及到的【读取】相关的逻辑,都分析出来。逻辑层和物理层的设计思想和数学模型,都进行推演和总结
    1. 耗时难以评估
  2. 拆解出,单个线程,读取一次元组数据,所涉及的所有的模块的变量的修改
    1. cache缓冲区
    2. status统计信息
    3. SQL被yacc编译后保留的谓词信息
    4. DimenGroup (维度表)
    5. IndexTable (索引表)
    6. Mulindex/MIterator
  3. 在逻辑层, 对读取所涉及到的模块进行深拷贝, 对数据结构进行拷贝
    1. 可以对照并行HashJoin的处理
    2. 搞这么蛋疼的原因,就在于上面提到的,数据结构决定算法,底层模块决定了上层模块的逻辑。
      1. 作个对比, clickhouse用了个简单粗暴的做法,保持列的不变性,任何读取和插入都创建一个新的列来存放结果,原有的列保持只读。当做到了列的不变性时,就无所谓数据安全和并发的问题。毛子的暴力美学确实有一手。

相关文章:

  • MATLAB | 面积图、饼状图、水平柱状图的斜线填充(阴影填充)
  • IDEA开发环境初始化配置
  • 企业单位公众号如何上传附件(如Word,Excel,PPT等)
  • Java中二维数组练习题
  • 一步到位,在Ubuntu中开启MySQL Windows Navicat能远程访问
  • 关于 Math.random()生成指定范围内的随机数的公式推导
  • 抛砖系列之git仓库拆分工具git-filter-repo
  • 基于51单片机温度监控Proteus仿真设计_报警值可调
  • 海关 瑞数5.5 找后缀加密入口解析
  • Cadence OrCAD Capture 绘制总线的方法
  • 高薪程序员面试题精讲系列145之前后端如何交互?Swagger你用过吗?
  • MySQL高级十:索引
  • 8月更新| Java on Visual Studio Code
  • 【牛客刷题】每日一练——Java语法的强化
  • 【Java】基础语法 | OOP用法 | 集合框架
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • 30天自制操作系统-2
  • Android 架构优化~MVP 架构改造
  • Cookie 在前端中的实践
  • CSS盒模型深入
  • docker容器内的网络抓包
  • DOM的那些事
  • ES6--对象的扩展
  • Git同步原始仓库到Fork仓库中
  • If…else
  • JavaScript 基本功--面试宝典
  • Javascript设计模式学习之Observer(观察者)模式
  • JavaScript学习总结——原型
  • jquery cookie
  • js如何打印object对象
  • Nacos系列:Nacos的Java SDK使用
  • python docx文档转html页面
  • Redis的resp协议
  • 对象引论
  • 浮现式设计
  • 记录:CentOS7.2配置LNMP环境记录
  • 力扣(LeetCode)22
  • 前端路由实现-history
  • 入职第二天:使用koa搭建node server是种怎样的体验
  • kubernetes资源对象--ingress
  • linux 淘宝开源监控工具tsar
  • 数据可视化之下发图实践
  • #define用法
  • #LLM入门|Prompt#3.3_存储_Memory
  • (二)fiber的基本认识
  • (二)构建dubbo分布式平台-平台功能导图
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (力扣)1314.矩阵区域和
  • (转)负载均衡,回话保持,cookie
  • .libPaths()设置包加载目录
  • .NET BackgroundWorker
  • .Net CF下精确的计时器
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明