分布式数据库中间件Sharding-JDBC介绍

news2024/9/20 15:05:23

前文中介绍了分布式数据库中间件Mycat的一些特性,作为对比本文简要介绍Sharding-JDBC的一些特性以及分片的实现原理,进行对比分析以了解。


1、ShardingSphere介绍

ShardingSphere是一套开源的分布式数据库中间件解决方案,目前由Sharding-JDBC和Sharding-Proxy两款独立的产品组成,2020年4⽉16⽇正式成为 Apache 软件基⾦会的顶级项⽬。

  • Sharding-JDBC:定位为轻量级Java框架,在Java的JDBC层提供的额外服务,支持任意实现JDBC规范的数据库。
  • Sharding-Proxy:定位为透明化的数据库代理端,通过实现数据库二进制协议,对异构语言提供支持。目前提供MySQL和PostgreSQL协议。

ShardingSphere利用分布式场景下关系型数据库的计算和存储能力,提供标准化的数据分片、分布式事务和数据库治理功能,可以将任意数据库转换为分布式数据库,适用于如Java同构、异构语言、容器、云原生等各种多样化的应用场景。

1.1 设计理念

ShardingSphere采用Database Plus的设计理念,致力于构建数据库上层的标准和生态,利用连接、增强和可插拔的方式在生态中补充数据库所缺失的能力。

Database Plus:一种分布式数据库系统的设计理念。旨在碎片化的异构数据库上层构建生态,在最大限度的复用数据库原生存算能力的前提下,进一步提供面向全局的扩展和叠加计算能力(例如:数据分片、数据加密等)。使应用和数据库间的交互面向Database Plus构建的标准,从而屏蔽数据库碎片化对上层业务带来的差异化影响。

在这里插入图片描述

1)连接:打造数据库上层标准

通过对数据库协议、SQL方言以及数据库存储的灵活适配,快速构建多模异构数据库上层的标准,同时通过内置DistSQL为应用提供标准化的连接方式。

2)增强:数据库计算增强引擎

在原生数据库基础能力之上,提供分布式及流量增强方面的能力。前者可突破底层数据库在计算与存储上的瓶颈,后者通过对流量的变形、重定向、治理、鉴权及分析能力提供更为丰富的数据应用增强能力。

3)可插拔:构建数据库功能生态

ShardingSphere的可插拔架构划分为3层,它们是:L1内核层、L2功能层、L3生态层

  • L1内核层:是数据库基本能力的抽象,其所有组件均必须存在,但具体实现方式可通过可插拔的方式更换。主要包括查询优化器、分布式事务引擎、分布式执行引擎、权限引擎和调度引擎等。
  • L2功能层:用于提供增量能力,其所有组件均是可选的,可以包含零至多个组件。组件之间完全隔离,互无感知,多组件可通过叠加的方式相互配合使用。主要包括数据分片、读写分离、数据库高可用、数据加密、影子库等。 用户自定义功能可完全面向Apache ShardingSphere定义的顶层接口进行定制化扩展,而无需改动内核代码。
  • L3生态层:用于对接和融入现有数据库生态,包括数据库协议、SQL解析器和存储适配器,分别对应于Apache ShardingSphere以数据库协议提供服务的方式、SQL方言操作数据的方式以及对接存储节点的数据库类型。
1.2 产品规划

随着版本的不断迭代,ShardingSphere的功能也变得多元化起来:从最开始Sharding-JDBC 1.0版本只有数据分片,到2.0版本开始支持数据库治理,再到3.0版本Sharding-Proxy上线并支持分布式事务,再到4.0进入Apache基金会,再到如今5.0版本的可插拔式设计。其宗旨是构建数据库上层的标准和生态,建立统一标准和规范,完善数据库能力。

在这里插入图片描述

1.3 Sharding-JDBC

接下来重点介绍Sharding-JDBC框架,Sharding-JDBC定位为轻量级Java框架,在Java的JDBC层提供的额外服务。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。

  • 适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC;
  • 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, HikariCP等;
  • 支持任意实现JDBC规范的数据库,目前支持MySQL,PostgreSQL,Oracle,SQLServer以及任何可使用JDBC访问的数据库。

在这里插入图片描述

1.3.1 Sharding-JDBC主要功能

Sharding-JDBC主要支持数据分片、分布式事务和数据库治理功能。

在这里插入图片描述

  1. 数据分片
    1. 分库分表:将数据分片进行垂直拆分和水平拆分
    2. 读写分离:根据SQL语义的分析,将读操作和写操作分别路由至主库与从库
    3. 分片策略:基于分片键和不同的分片算法实现分片
    4. 分布式主键:内置的分布式主键生成器,例如UUID、SNOWFLAKE
  2. 分布式事务
    1. 标准化的事务接口:begin/commit/rollback接口实现
    2. XA强一致性事务:AP、TM和RM模型保证分布式事务一致性
    3. 柔性事务:BASE事务模型实现事务的最终一致性
  3. 数据库治理
    1. 数据库网关:SQL方言自动翻译功能,将不同类型的数据库方言自动翻译为后端数据库所使用的方言
    2. 流量治理:计算节点的过载保护和数据节点限流
    3. 数据加密:数据加密功能,实现数据的合规化改造治理
    4. 可视化链路跟踪:多种监控性能和监控指标,实现监控仪表盘和应用链路跟踪
1.3.2 Sharding-JDBC处理流程

Sharding-JDBC定位为Java框架,对于开发人员只需要使用调用JDBC API访问数据库,只要正确使用DataSource、Connection、Statement 、ResultSet 等API接口,直接操作数据库即可,实现“创建DataSource->获取Connection->构建Statement->执行SQL语句->处理ResultSet”完整的流程。Sharding-JDBC就是将原来的DataSource、Connection等接口扩展成 ShardingDataSource、ShardingConnection,对外暴露的JDBC操作接口与JDBC规范中的接口完全一致。因此,Sharding-JDBC适用于任何基于JDBC的ORM框架,并完美兼容任何第三方的数据库连接池。

在这里插入图片描述

2、Sharding-JDBC核心原理

2.1 分片概念

数据分片通常将原本一张数据量很大的表根据分片规则和分片键拆分为表结构完全一样的小数据量的表,如下图所示,每张表只存储大表中的一部分数据。当SQL执行时会通过不同的分片策略,访问不同的库和分片中的数据。
在这里插入图片描述

2.1.1 表概念
  1. 逻辑表:相同结构的水平拆分数据库(表)的逻辑名称,是SQL中表的逻辑标识。比如图中的t_prod,拆分后数据库中已经不存在这张表,取而代之的是t_prod_n这些表,t_prod就称为这些拆分表的逻辑表。
  2. 真实表:数据库中真实存在的物理表,比如图中的t_prod_0…t_prod_3
  3. 数据节点:分库分表后不可再分割的最小的数据单元,由数据源名称和数据表组成,比如t_prod_db_1.t_prod_0就表示一个数据节点
  4. 绑定表:指代分片规则一致的一组分片表,比如t_prod和t_order均按照分片键id进行分片,则t_prod和t_order为绑定表。使用绑定表进行多表关联查询时,必须使用分片键进行关联,否则会出现笛卡尔积关联或跨库关联,从而影响查询效率。
  5. 广播表:指所有的分片数据源中都存在的表,表结构及其数据在每个数据库中均完全一致。适用于数据量不大且需要与海量数据的表进行关联查询的场景,如字典表、参数表。
  6. 单表:指所有的分片数据源中仅唯一存在的表。适用于数据量不大且无需分片的表。
2.1.2 分片算法

Sharding-JDBC对分片键基于一定的分片规则实现数据分片,从执行SQL的角度来看分片算法理解为一种路由机制。Sharding-JDBC支持以下内置的分片算法:

  1. 精确分片算法(PreciseShardingAlgorithm):用于单个字段作为分片键,SQL中有“=”和“IN”等条件的分片,需要在标准分片策略(StandardShardingStrategy)下使用。
  2. 范围分片算法(RangeShardingAlgorithm):范围分片算法用于单个字段作为分片键,SQL 中有“BETWEEN AND、>、<、>=、<=”下使用。
  3. 复合分片算法(ComplexKeysShardingAlgorithm):用于多个字段作为分片键的分片操作,同时获取到多个分片健的值,根据多个字段处理业务逻辑。需要在复合分片策略(ComplexShardingStrategy)下使用。
  4. Hint分片算法(HintShardingAlgorithm):上边的算法中我们都是解析语句提取分片键,并设置分片策略进行分片。但有些时候我们并没有使用任何的分片键和分片策略,可还想将SQL路由到目标数据库和表,就需要通过手动干预指定SQL的目标数据库和表信息,这也叫强制路由。
2.1.3 分片策略

分片策略是一个抽象的概念,实际的分片操作是由分片键+分片算法实现的。

  1. 标准分片策略:适用于单分片键,此策略支持PreciseShardingAlgorithm和RangeShardingAlgorithm 两个分片算法。
  2. 复合分片策略:支持多分片键,同样支持对SQL语句中的“=、>、<、>=、<=、IN、BETWEEN AND”的分片操作。
  3. 行表达式分片策略:支持对 SQL语句中的“=、IN”的分片操作,但只支持单分片键。这种策略通常用于简单的分片,不需要自定义分片算法,可以直接在配置文件中写规则。
  4. Hint分片策略:对应Hint分片算法,通过指定分片健而非从 SQL中提取分片健的方式进行分片的策略。
2.2 数据分片原理

Sharding-JDBC数据分片的原理如图所示,分为“SQL解析->执⾏器优化->SQL路由->SQL改写->SQL执⾏->结果归并”过程。

在这里插入图片描述

2.2.1 SQL解析

SQL解析分为词法解析和语法解析。先通过词法解析器将SQL拆分为一个个不可再分的单词,再使用语法解析器对SQL进行理解,并最终提炼出解析上下文。解析上下文包括表、选择项、排序项、分组项、聚合函数、分页信息、查询条件以及可能需要修改的占位符的标记。

SELECT id, name FROM t_user WHERE status = 'ACTIVE' AND age > 18

以上SQL语句,解析之后抽象的语法树如下:

在这里插入图片描述

通过对抽象语法树遍历,提炼出分片所需的上下文,上下文包含查询字段信息(Field)、表信息(Table)、查询条件(Condition)、排序信息(Order By)、分组信息(Group By)以及分页信息(Limit)等,并标记出 SQL中有可能需要改写的位置。

2.2.2 执行器优化

由Federation执行引擎(开发中)提供支持,对关联查询、子查询等复杂查询进行优化,同时支持跨多个数据库实例的分布式查询,内部使用关系代数优化查询计划,通过最优计划查询出结果。

2.2.3 SQL路由

SQL路由根据解析上下文匹配数据库和表的分片策略,并生成路由路径。对于携带分片键的SQL,根据分片键的不同可以划分为单片路由(分片键的操作符是等号)、多片路由(分片键的操作符是IN)和范围路由(分片键的操作符是BETWEEN)。简单点理解就是可以根据配置的分片策略计算出SQ该在哪个库的哪个表中执行,而SQL路由又根据有无分片健区分出分片路由和广播路由。

在这里插入图片描述

1)分片路由
用于根据分片键进行路由的场景,又细分为直接路由、标准路由和笛卡尔积路由这3种类型。

  • 直接路由:满足直接路由的条件相对苛刻,它需要通过Hint(使用HintAPI直接指定路由至库表)方式分片,并且是只分库不分表的前提下,则可以避免SQL解析和之后的结果归并。
  • 标准路由:当分片运算符是等于号时,路由结果将落入单库(表);当分片运算符是BETWEEN或IN时,则路由结果不一定落入唯一的库(表),因此一条逻辑SQL最终可能被拆分为多条用于执行的真实SQL。
  • 笛卡尔积路由:它无法根据绑定表的关系定位分片规则,因此非绑定表之间的关联查询需要拆解为笛卡尔积组合执行。

2)广播路由:对于不携带分片键的SQL,则采取广播路由的方式。根据SQL类型又可以划分为全库表路由、全库路由、全实例路由、单播路由和阻断路由这5种类型。

  • 全库表路由:全库表路由用于处理对数据库中与其逻辑表相关的所有真实表的操作,主要包括不带分片键的DQL和DML以及DDL等
  • 全库路由:全库路由用于处理对数据库的操作,包括用于库设置的SET类型的数据库管理命令,以及TCL这样的事务控制语句。
  • 全实例路由:全实例路由用于DCL操作,授权语句针对的是数据库的实例。
  • 单播路由:单播路由用于获取某一真实表信息的场景,它仅需要从任意库中的任意真实表中获取数据即可。
  • 阻断路由:阻断路由用于屏蔽 SQL 对数据库的操作,比如use database
2.2.4 SQL改写

SQL改写是将SQL改写为在真实数据库中可以正确执行的语句。SQL改写分为正确性改写和优化改写。

  • 正确性改写:在包含分表的场景中,需要将分表配置中的逻辑表名称改写为路由之后所获取的真实表名称。另外还包括包括补列和分页信息修正等内容。
  • 优化改写:在不影响查询正确性的情况下,对性能进行提升的有效手段。分为单节点优化和流式归并优化

在这里插入图片描述

2.2.5 SQL执行

SQL执行引擎采用一套自动化的执行引擎,负责将路由和改写完成之后的真实SQL安全且高效发送到底层数据源执行。

在这里插入图片描述

SQL执行引擎分为准备阶段和执行阶段:

1)准备阶段

准备阶段用于准备执行的数据,分为结果集分组和执行单元创建两个步骤。

  • 结果集分组:将SQL的路由结果按照数据源的名称进行分组
  • 通过上一步骤获得的路由分组结果创建执行的单元

2)执行阶段

执行阶段用于真正的执行SQL,它分为分组执行和归并结果集生成两个步骤

  • 分组执行将准备执行阶段生成的执行单元分组下发至底层并发执行引擎,并针对执行过程中的每个关键步骤发送事件。
  • 归并结果集生成通过在执行准备阶段的获取的连接模式,生成内存归并结果集或流式归并结果集,并将其传递至结果归并引擎,以进行下一步的工作
2.2.6 SQL结果归并

SQL结果归并是将多个执行结果集归并以便于通过统一的JDBC接口输出。结果归并从功能上分为遍历、排序、分组、分页和聚合5种类型;从结构划分,可分为流式归并、内存归并和装饰者归并。

  • 遍历归并:将多个数据结果集合并为一个单向链表,在遍历完成链表中当前数据结果集之后,将链表元素后移一位,继续遍历下一个数据结果集即可
  • 排序归并:每个数据结果集自身是有序的,因此只需要将数据结果集当前游标指向的数据值进行排序即可,不需要对所有的结果集进行全量的排序,节省了内存的消耗
  • 分组归并:分为流式分组归并和内存分组归并, 流式分组归并要求SQL的排序项与分组项的字段以及排序类型(ASC或DESC)必须保持一致。如果不一致,需要将所有的结果集数据加载至内存中进行分组和聚合。
  • 聚合归并:使用聚合函数进行比较、累加和求平均值
  • 分页归并:通过装饰者模式来增加对数据结果集进行分页的能力,将无需获取的数据过滤掉。

在这里插入图片描述

3、Sharding-JDBC和Mycat对比

Mycat和ShardingSphere(Sharding-JDBC)都是非常流行的开源分布式数据库中间件,各自具有一些独特的功能,也有很多企业成功应用的案例。二者之间的特性对比如下表所示:

特性MycatSharding-JDBC
开发语言JavaJava
开源协议GPL-2.0/GPL-3.0Apache-2.0
数据库多种多种
连接数
应用语言任意Java
代码入侵需修改代码
性能损耗略高损耗低
无中心化
管理控制台Mycat-webShardingUI
分库分表单库多表/多库单表支持
多租户方案支持
读写分离支持支持
分片策略定制化支持支持
分布式主键支持支持
标准化事务接口支持支持
XA强一致性事务支持支持
柔性事务支持
配置动态化开发中支持
编排治理开发中支持
数据脱敏支持
可视化链路跟踪支持
多节点操作支持支持
跨库关联跨库2表JOIN
IP白名单支持
SQL黑名单支持
存储过程支持

Mycat是一个分布式数据库中间件,对前端来说相当于一个数据库代理。ShardingSphere定位为关系型数据库中间件,旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力,而并非实现一个全新的关系型数据库。目前来看接入Apache基金会的ShardingSphere体系更加完善,社区更加活跃。


参考资料:

  1. 官网,https://shardingsphere.apache.org/document/current/cn/overview/
  2. https://blog.csdn.net/agonie201218/article/details/125164699
  3. https://blog.csdn.net/horses/article/details/106086208
  4. 分布式数据库中间件Mycat介绍

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

15个有用的JavaScript技巧

今天这篇文章&#xff0c;是我从网络上整理的一些常见的 JavaScript Tips。我在我的项目中使用了所有这些实用技巧&#xff0c;今天我想把它们分享给你&#xff0c;希望也能够帮助到你。 1.数字分隔符 为了提高数字的可读性&#xff0c;可以使用下划线作为分隔符。 const la…

pytorch学习记录

pytorch学习记录0.引言1.numpy 简单入门1.1.常用基础1.2.numpy其他学习2.pytorch 简单入门2.1.Pytorch的基本组成元素2.2.Pytorch构建神经网络2.3.进阶部分2.4.其他参考资料0.引言 一步一步积累吧。 一篇不错的博客 1.numpy 简单入门 1.1.常用基础 numpy中文手册 numpy官方…

【李宏毅】HW12

HW12一、作业描述1、Policy Gradient2、Actor-Critic二、实验1、simple2、medium3、strong三、代码一、作业描述 在这个HW中&#xff0c;你可以自己实现一些深度强化学习方法&#xff1a; 1、策略梯度Policy Gradient 2、Actor-Critic 这个HW的环境是OpenAI gym的月球着陆器。…

ubuntu | 重装ubuntu(VMware虚拟机环境)

前言 最近又把双系统的ubuntu搞崩了&#xff0c;在grub界面进不去&#xff0c;估计找不到启动项&#xff0c;被迫重装。 这次觉得还是windows系统好使&#xff0c;就用vmware虚拟机了。 一、安装vmware虚拟机 参考我之前的博客。 二、安装ubuntu 下载ubuntu18.04的iso文件…

15.2 浏览器中的进程

浏览器中的进程 start 上一篇文章&#xff0c;学习到了如何区分进程和线程。在这里再复习一下&#xff0c;进程类似于一个工厂&#xff0c;线程类似于工厂的工人&#xff0c;一个工厂可以有一个或多个工人。 1. 浏览器的进程 一个浏览器中有很多的进程&#xff0c;我以谷歌…

2023年的摸鱼小技巧:Python自动生成请假条【思路详解】

嗨害大家好鸭&#xff01;我是小熊猫~ 这不2023到了&#xff0c;新的一年&#xff0c;新的摸鱼 在办公室里的小透明来实现用Python来批量生成请假条&#xff0c; 这波啊&#xff0c;这波是智取&#xff01;&#xff01;&#xff01; Python资料电子书:点击此处跳转文末名片获…

Excel函数公式大全—SUMIF/SUMIFS函数

EXCEL系列文章目录 Excel系列文章是本人亲身经历职场之后萌发的想法&#xff0c;为什么Excel覆盖如此之广&#xff0c;几乎每个公司、学校、家庭都在使用&#xff0c;但是它深藏的宝藏功能却很少被人使用&#xff0c;PQ、BI这些功能同样适用于数据分析&#xff1b;并且在一些需…

内部成员之五:内部类

文章目录一、内部类分类&#xff1a;成员内部类vs局部内部类成员内部类实例化成员内部类每日一考一、内部类 1、Java中允许将类A声明在类B中&#xff0c;则类A就是内部类&#xff0c;类B为外部类。 分类&#xff1a;成员内部类vs局部内部类 成员内部类&#xff08;静态、非静…

【ElasticSearch7.X】学习笔记(三)

【ElasticSearch7.X】学习笔记五、集群部署5.1、相关概念5.1.1、集群 Cluster3.1.2、节点 Node5.2、下载安装5.3、 启动5.4、 测试六、进阶6.1、核心概念6.1.1、索引&#xff08;Index&#xff09;6.1.2、类型&#xff08;Type&#xff09;6.1.3、文档&#xff08;Document&…

Handler的学习

一、Handler到底有什么用呢&#xff1f; 首先看以下案例&#xff1a; public class MainActivity extends AppCompatActivity { Button btn;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activi…

vue这些原理你都知道吗?(面试版)

前言 在之前面试的时候我自己也经常会遇到一些vue原理的问题, 我也总结了下自己的经常的用到的,方便自己学习,今天也给大家分享出来, 欢迎大家一起学习交流, 有更好的方法欢迎评论区指出, 后序我也将持续整理总结~ 描述 Vue 与 React 区别 说明概念: vue:是一套用于构建用户…

虚拟化技术学习笔记3

1、KVM虚拟机管理工具部署 学习目标&#xff1a; 能够为KVM虚拟机管理工具部署准备环境 能够部署KVM虚拟机管理工具 1、KVM系统需求&#xff1a; 1&#xff09;Host system requirements: 1核心、2G内存、6G硬盘 2&#xff09;KVM hypervisor requirements&#xff1a; l…

U3D客户端框架(资源管理篇)之主资源加载器模块设计实现

一、主资源加载器模块设计实现 作用 主资源加载器是为面向用户而设计的上层应用层类&#xff0c;用户使用主资源加载器作为文件加载器加载文件&#xff0c; 加载器可以通过Assetbundle方式加载&#xff0c;Http方式加载资源。 UML类图设计 前置模块 主资源加载器需要引用到一…

Qt扫盲-QHash理论总结

QHash理论总结一、概述二、使用1. 添加 元素2. 获取元素3. 遍历元素4. 删除元素5. qHash()的散列函数6.算法复杂性一、概述 QHash是Qt的通用容器类之一。它和QMap一样是用来存储(键&#xff0c;值)对的工具&#xff0c;并提供快速查找与键相关联的值的功能。 QHash提供了与QMa…

密码学的一些常识01

序 作为一个小白&#xff0c;对称加密&#xff0c;非对称加密&#xff0c;数字签名&#xff0c;数字证书&#xff0c;CA&#xff0c;diff-helman&#xff0c;DES,AED,RSA……这些都不会。所以&#xff0c;百度启动&#xff0c;先初步了解。 实际应用 我是个小白……0基础的&…

sklearn中精确率、召回率及F1值得micro,macro及weighted算法

为什么要用精确率和召回率 有这样一个训练集&#xff0c;1000个人参加了结直肠癌CRC的检测&#xff0c;实际有0.5%的人得了CRC&#xff08;即5个人&#xff09;。用神经网络算法得到检测这样一个训练集能达到99%的准确率。从数值上判断该算法是不错的&#xff0c;因为只有1%的误…

springboot+disruptor再体验

Disruptor是一个高性能队列&#xff0c;常见的还有kafka、rabbitmq等&#xff0c;下面体验一下~ 1、Disruptor简介 Disruptor 是英国外汇交易公司LMAX开发的一个高性能队列&#xff0c;研发的初衷是解决内存队列的延迟问题&#xff08;在性能测试中发现竟然与I/O操作处于同样的…

[C++]STL之string的模拟实现

上一章我们对string的常见接口及使用进行了讲解&#xff0c;接下来我们将对一些常见的接口&#xff0c;包括构造函数&#xff0c;析构函数&#xff0c;运算符重载等等进行模拟实现.方便我们理解string接口实现的原理. 在讲解之前先说一下string的成员变量. 首先是字符串内容_…

微信小程序picker组件遇到的问题以及解决办法

一、picker基本概念二、遇到的问题三、如何解决四、延伸五、效果图一、picker基本概念 先来看一下官方文档中picker的基本概念&#xff1a; 从底部弹起的滚动选择器&#xff0c;现支持三种选择器&#xff0c;通过mode来区分&#xff0c;分别是普通选择器&#xff0c;时间选择器…

Bochs下载安装

文章目录下载Bochs配置BochsBochs Bochs是一个x86硬件平台的开源模拟器。它可以模拟各种硬件的配置。Bochs模拟的是整个PC平台&#xff0c;包括I/O设备、内存和BIOS。更为有趣的是&#xff0c;甚至可以不使用PC硬件来运行Bochs。事实上&#xff0c;它可以在任何编译运行Bochs的…