实现细节
集群二进制模式演进
集群运行时支持 SmartEDB 的二进制模式架构演变(BSE)功能,因此单个集群中的节点能够拥有不同的数据库架构。要启用二进制演变模式,应用程序必须在所有节点的 mode_mask 字段中设置 BINARY_EVOLUTION 标志。
使用 C/C++ API,可按如下方式完成:
mco_cluster_params_t cl_params;
...
mco_cluster_params_init(&cl_params);
...
cl_params.mode_mask |= MCO_CLUSTER_MODE_BINARY_EVOLUTION; /* use BSE */
使用 Java API,
Database.Parameters params = new Database.Parameters();
...
params.clusterParams = new Database.ClusterParams(...);
...
params.clusterParams.mode |= Database.CLUSTER_MODE_BINARY_EVOLUTION;
使用 C# API,
Database.Parameters parameters = new Database.Parameters();
...
parameters.ClusterParameters = new Database.ClusterParams(...);
...
parameters.ClusterParameters.Mode |= Database.CLUSTER_MODE_BINARY_EVOLUTION;
请注意,如果节点 A 和 B 设置了 CLUSTER_MODE_BINARY_EVOLUTION 标志,但其模式完全相同,则这些节点之间的对象将不进行任何转换而直接发送。在这种情况下,使用二进制演进标志的唯一开销是在数据库头中分配的额外空间(在创建数据库时)。此空间用于存储来自其他节点的字典。
保存和加载集群数据库的快照
通过调用函数 mco_db_save() 可以保存集群数据库的快照。通过向 mco_cluster_db_open() 传递的 mco_cluster_params_t 结构中的以下两个字段,可以启用从快照(镜像文件)加载集群数据库的功能:
void * stream_handle;
mco_stream_read input_stream_reader;
这些字段对应于 mco_db_load() API 的前两个参数,其中 stream_handle 是输入流的句柄,input_stream_reader 是运行时用于读取输入的处理函数。如果这两个参数的值为 NULL,则 mco_cluster_db_open() 会调用 mco_db_open_dev(),否则会调用 mco_db_load()。默认情况下(在 mco_cluster_params_init() 中设置),这些值被设置为 NULL。 例如,使用如下代码,可以打开(创建)基于集群的内存数据库,或者从保存的数据库快照(镜像文件)中加载:
mco_size_sig_t file_reader(void* stream_handle /* FILE* */,
void* to, mco_size_t max_nbytes)
{
return (mco_size_t) fread(to, 1, max_nbytes, (FILE*)stream_handle);
}
mco_size_sig_t file_writer(void* stream_handle /* FILE* */,
const void* from, mco_size_t max_nbytes)
{
return (mco_size_t) fwrite(from, 1, max_nbytes, (FILE*)stream_handle);
}
main()
{
mco_db_h db;
mco_cluster_params_t cl_params;
mco_cluster_params_init(&cl_params);
<fill cl_params>
FILE *rfile = fopen("<image_file>", "r");
if (rfile) /* if image exists, load database */
{
cl_params.stream_handle = rfile;
cl_params.input_stream_reader = &file_reader;
}
mco_cluster_db_open("<db_name>",...., &cl_params);
<start mco_cluster_listen() thread>
mco_db_connect("<db_name>", &db);
<... Do some work ...>
mco_cluster_stop(db);
/* save database */
FILE *wfile = fopen("<image_file>", "w");
mco_db_save(wfile, &file_writer, db);
<close database>
}
集群事务窗口
在 SmartEDB 集群中,事务窗口功能允许应用程序将来自多个提交线程的事务数据合并到单个 send() 操作中,从而减少系统调用次数。对于小型事务,这可以显著提升集群数据库的整体性能。通过 C API 函数 mco_cluster_get_window_params() 和 mco_cluster_set_window_params(),您可以获取当前窗口参数并设置新的值。
事务窗口在结构体 mco_cluster_window_t 中定义了三个阈值:bsize、length 和 timeout。第一个阈值(bsize)表示缓冲事务数据的最大字节数;length 是缓冲事务的最大数量;timeout 是在将缓冲数据发送到其他节点之前的最大延迟(以毫秒为单位)。一旦达到这些阈值中的任何一个,缓冲的数据就会被发送出去。因此,缓冲的事务数量不会超过 mco_cluster_window_ttimeout。
窗口的初始参数是通过传递给 C API mco_cluster_db_open() 的 mco_cluster_params_t::window 设置的。默认情况下,length=0、bsize=0 和 timeout=1,这意味着窗口未启用,因为缓冲事务的最大数量(length)为零。如果集群中的一个节点将窗口长度设置为大于 0 的值,则所有其他节点也必须使用大于 0 的长度,但不同节点上的值可以不同。(请注意,窗口长度 = 1 大致相当于 length = 0)。窗口的 bsize 值可以为 0,这意味着“数据大小不受限”。
通常,窗口长度不应超过活跃写入线程的数量,否则数据将始终通过超时阈值发送。例如,如果应用程序只有一个写入线程,那么窗口就几乎没用了。通常,如果窗口长度设置为写入线程数量的 50% - 75%,效果最佳。窗口 bsize 的值可用于限制“大”事务中缓冲事务数据的大小。
集群与事务日志记录
在某些情况下,为了优化持久性数据库的 SmartEDB 集群性能,您可能希望使用 SmartEDB 事务日志记录功能,这为使用持久性数据库类提供了一种替代方案。要启用 SmartEDB 事务日志记录(TL),请使用集群模式标志 MCO_CLUSTER_MODE_START_DETACHED 创建一个不会立即连接到其他节点的集群数据库。这使得可以在创建数据库和节点连接到集群之间添加处理过程。具体来说,当启用 TL 时,可以通过调用 mco_translog_apply() 将事务日志应用于集群数据库。
例如,以下代码以分离模式打开集群数据库,应用事务日志,然后连接到其他集群节点:
main()
{
mco_db_h db;
mco_cluster_params_t cl_params;
mco_cluster_params_init(&cl_params);
<fill cl_params>
FILE *rfile = fopen(image_path, "r");
if (rfile) /* load image if exists */
{
cl_params.stream_handle = rfile;
cl_params.input_stream_reader = &file_reader;
}
/* start in detached mode */
cl_params.mode_mask |= MCO_CLUSTER_MODE_START_DETACHED;
mco_cluster_db_open(db_name,...., &cl_params);
mco_db_connect(db_name, &db);
/* Apply transaction log */
mco_translog_apply(db, log_path, MCO_TRANSLOG_ALL_LABELS);
/* Connect to other cluster nodes */
mco_cluster_attach(db, &cl_params);
<start mco_cluster_listen() thread>
/* Start transaction logging */
mco_translog_start(db, log_path, tl_start_data);
/* Save snapshot to ensure all remote transactions are saved */
FILE *wfile = fopen(image_path, "w");
mco_translog_db_save(wfile, &file_writer, db));
<... Do usual work ...>
mco_cluster_stop(db);
mco_translog_stop(db);
<close database>
}
分布式数据库 - 分片
分片和集群是两种不同的概念,它们的目的不同,架构也有所区别。分片用于实现数据库分区,而集群在默认配置下并不对数据库进行分区,而是复制所有内容。
集群可以用于在分片数据库中实现冗余。具体来说,每个分片不是一个单一节点,而是一个小型集群。其实现方式类似于《SmartEDB 高可用性用户指南》中描述的高可用性复制,但有一个关键区别:任何节点都可以充当主节点,接收 SQL 语句,并将更改复制到分片中的其他节点。
当使用 SmartEDB 集群对 SmartEDB 数据库进行分布式部署时,以下条件适用:
- 集群中的所有节点都是平等的,每个节点都能执行读写和只读操作。
- 只读事务始终是本地的(无需网络访问)。
- 写事务由集群运行时分发到集群中的所有或部分节点。
集群运行时打开标志
以下是可以在 mco_cluster_params.mode_mask 中指定的三个标志的说明,这些标志会影响特定的集群运行时行为:
MCO_CLUSTER_MODE_EARLY_DATA_SEND
通常情况下,在发起节点的提交第一阶段成功完成后,集群运行时会将事务数据发送到其他节点。这允许运行时减少因本地失败事务(例如,由于违反唯一性约束)而产生的网络流量。另一方面,在本地 phase_1 之前更早地发送数据可以减少执行分布式事务的总时间。MCO_CLUSTER_MODE_EARLY_DATA_SEND 标志强制集群运行时在 phase_1 之前发送数据。
MCO_CLUSTER_MODE_BINARY_EVOLUTION
此标志允许具有不同模式的节点加入到同一个集群中。请注意,启用此标志后,集群中禁止任何 DDL 操作。
MCO_CLUSTER_MODE_START_DETACHED
通常,mco_cluster_db_open() 函数会创建一个数据库,连接到集群中的其他节点,并同步数据库内容。MCO_CLUSTER_MODE_START_DETACHED 标志告知 mco_cluster_db_open() 函数仅创建数据库,跳过任何网络操作。要将此节点添加到集群中,应用程序稍后必须调用 mco_cluster_attach() 函数。