当前位置:网站首页>分布式块设备复制:客户端
分布式块设备复制:客户端
2022-07-27 10:13:00 【坤昱】
分布式块设备复制,英文名称 Distributed Replicated Block Device,简称为 DRBD,它是一种由应用引导内核驱动工作、基于网络的块复制存储解决方案,主要用于服务器之间的磁盘分区、逻辑卷等进行数据镜像。当用户将数据写入本地磁盘时,还会将数据发送到网络中另一台主机的磁盘上,这样本地主机(主节点)与远程主机(同位节点)的数据就可以保证实时同步,当本地主机出现问题,远程主机上保留着一份相同的数据可以继续使用,保证了数据的安全。
DRBD的核心功能就是数据的镜像,其实现方式是通过网络来镜像整个磁盘设备或磁盘分区,将一个节点的数据通过网络实时的传送到另一个远程节点,保证两个节点间数据的一致性,这有点类似于一个网络 RAID 的功能。
章节预览:
1. DRBD节点间传输说明
2. DRBD客户端
2.1 部分功能函数分析
2.2 功能函数执行过程
2.3 drbdsetup执行过程
章节内容:
1. DRBD节点间传输说明
参考如下内容:
以每比特4KB(页)的存储粒度表示,
*以及几台TiB的存储大小,
*以及可能的小带宽复制,
*位图传输时间可能太长,
*如果以纯文本传输。
*
*我们试图减少传输的位图信息
*通过编码位极性的运行长度。
*
*实际上,我们从不需要编码“零”(运行长度为正)。
*但是我们必须存储第一位的值。
*因此,如果第一个运行长度
*给出设置或未设置的位数。
*
*我们假设大片区域要么完全固定要么不固定,
*任何运行长度方法都能提供很好的压缩效果,
*即使将运行长度编码为固定大小的32位/64位整数。
*
*尽管如此,也可能有极性每隔几位就翻转一次的区域,
*并以固定大小编码这些区域的运行长度序列
*整数比纯文本差得多。
我们想用最小的代码长度编码小的运行长度值,
*同时还能对大量的零进行编码。
*
*因此,我们需要一个可变长度的整数编码,VLI。
*
*在某些情况下,我们会产生比纯文本输入更多的码位。
*我们需要将不可压缩的块作为明文发送,跳过它们
*然后看看下一块是否压缩得更好。
*
*我们不太关心“优秀”的大压缩比
*运行长度(全部设置/全部清除):是否达到100倍
*或者1000不是什么大问题。
*我们不想在“嘈杂”的环境中浪费太多时间在短跑上
*位图的一部分。
*
*VLI的变体层出不穷,我们试验过:
**基于简单字节
**基于不同的位和不同的码字长度。
*
*为了避免另一个配置参数(位图压缩的选择
*算法)这是很难解释和调整,我们只是选择了一个
*在所有测试用例中结果最好的变体。
2. DRBD客户端
DRBD由客户端(drbdadm、drbdsetup、drbdmeta)、内核模块(drbd.ko、drbd_transport_tcp.ko)和相关脚本而构成,用以构建高可用性的集群。接下来,分析DRBD客户端执行流程。
打开user/v9/drbdadm_main.c文件,找到如下结构体:
struct adm_cmd *cmds[] = {
/* name, function, flags
* sort order:
* - normal config commands,
* - normal meta data manipulation
* - sh-*
* - handler
* - advanced
***/
&attach_cmd,
&disk_options_cmd,
&detach_cmd,
&new_peer_cmd,
&del_peer_cmd,
&new_path_cmd,
&del_path_cmd,
&connect_cmd,
&net_options_cmd,
...
drbd客户端采用数组形式定义一种任务类型,一种任务种类可能包括多个功能函数,如附加参数函数、磁盘选项函数、连接通讯函数等。参考大部分的任务种类:
struct adm_cmd new_minor_cmd;
struct adm_cmd new_resource_cmd;
struct adm_cmd res_options_cmd;
struct adm_cmd res_options_defaults_cmd;
struct adm_cmd attach_cmd;
struct adm_cmd disk_options_cmd;
struct adm_cmd disk_options_defaults_cmd;
struct adm_cmd resize_cmd;
struct adm_cmd new_peer_cmd;
struct adm_cmd del_peer_cmd;
struct adm_cmd new_path_cmd;
struct adm_cmd del_path_cmd;
struct adm_cmd connect_cmd;
struct adm_cmd net_options_cmd;
struct adm_cmd net_options_defaults_cmd;
struct adm_cmd peer_device_options_defaults_cmd;
struct adm_cmd disconnect_cmd;
struct adm_cmd detach_cmd;
struct adm_cmd del_minor_cmd;
struct adm_cmd proxy_conn_down_cmd;
struct adm_cmd proxy_conn_up_cmd;
struct adm_cmd proxy_conn_plugins_cmd;
struct adm_cmd proxy_reconf_cmd;
static const struct adm_cmd invalidate_setup_cmd;
static const struct adm_cmd forget_peer_setup_cmd;
接下来,演示功能函数大致调用方式(_adm_drbdmeta函数中通过command->function调用):
rv = parse_options(argc, argv, &cmd, &resource_names);
执行时传入的参数来获取是否属于有效函数及资源名称
config_file = config_file_from_arg(resource_names[0]);
获取资源
if (config_from_stdin)
config_save = config_file;
else
config_save = canonify_path(config_file);
加载资源内容
my_parse();
解析资源(任务类型->功能函数)
r = call_cmd(cmd, &ctx, EXIT_ON_FAIL);
执行功能函数
r = run_deferred_cmds();
保持任务进度,执行完成后释放资源并退出工具
2.1 部分功能函数分析
接下来,针对重要函数进行分析跟踪。
与内核通讯相关函数:
static struct genl_sock *genl_connect(__u32 nl_groups):
struct genl_sock *s = calloc(1, sizeof(*s));
...
s->s_fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_GENERIC);
...
用来初始化GenericNetlink描述符
genl_send(struct genl_sock *s, struct msg_buff *msg):
struct nlmsghdr *n = (struct nlmsghdr *)msg->data;
...
return do_send(s->s_fd, msg->data, n->nlmsg_len);
通过GenericNetlink描述符写入数据
int genl_recv_msgs(struct genl_sock *s, struct iovec *iov, char **err_desc, int timeout_ms):
struct nlmsghdr *nlh;
int c = genl_recv_timeout(s, iov, timeout_ms);
...
设置超时时间的方式接收由内核通过GenericNetlink发送的数据,这个函数的核心调用在genl_recv_timeout中,进入genl_recv_timeout函数:
pfd.fd = s->s_fd;
pfd.events = POLLIN;
if ((poll(&pfd, 1, timeout_ms) != 1) || !(pfd.revents & POLLIN))
...
n = recvmsg(s->s_fd, &msg, flags);
通过GenericNetlink描述符(调用genl_connect函数获取)读取数据
struct genl_sock *genl_connect_to_family(struct genl_family *family):
...
s = genl_connect(family->nl_groups);
...
if (genl_send(s, msg)) {
...
if (genl_recv_msgs(s, &iov, NULL, 3000) <= 0) {
...
进行对GenericNetlink初始化并与内核GenericNetlink服务模块建立连接,以获group id 及number id
2.2 功能函数执行过程
接下来,我们通过adm_create_md函数了解"drbdadm crate-md mystore.res"做了哪些操作(adm_create_md按次数执行,整个同步过程可能执行多次这个函数):
set_peer_in_resource(ctx->res, true);
设置对等资源(如net选项)
tb = run_adm_drbdmeta(ctx, "read-dev-uuid");
这个函数用来启动drbdmeta程序,接下来,进入函数内部:
if(pid == 0) {
...
rr = _adm_drbdmeta(&local_ctx,
SLEEPS_VERY_LONG|
DONT_REPORT_FAILED,
NULL);
通过m_system_ex -> m__system函数启动drbdmeta程序,然后找到user/shared/drbdmeta.c的main函数(开始执行drbdmeta程序):
...
int c = getopt_long(argc, argv, make_optstring(metaopt), metaopt, 0);
这个函数解析参数后,然后继续向下执行:
cfg = new_cfg();
分配配置,如ops、md_device_name、drbd_dev_name、minor(设备主版本号)等等,这里可以获取到与内核驱动建立交互的相关数据(vfs这种,如open)
if (parse_format(cfg, argv + ai, argc - ai, &ai)) {
...
}
继续跟进
struct format_ops f_ops[] = {
[DRBD_V06] = {
.name = "v06",
.args = (char *[]){"minor", NULL},
.parse = v06_parse,
.open = v06_md_open,
.close = generic_md_close,
.md_initialize = v06_md_initialize,
.md_disk_to_cpu = v06_md_disk_to_cpu,
.md_cpu_to_disk = v06_md_cpu_to_disk,
.get_gi = m_get_gc,
.show_gi = m_show_gc,
.set_gi = m_set_gc,
.outdate_gi = m_outdate_gc,
.invalidate_gi = m_invalidate_gc,
},
...
}
在parse_format函数中f_ops数组中,可以看到虚拟块设备函数描述
return cfg->ops->parse(cfg, argv + 1, argc - 1, ai);
open将读取各自的磁盘成员,并将“超级块”元数据复制到struct mem _cpu中
if (strcmp(cfg->drbd_dev_name, "-")) {
cfg->minor = dt_minor_of_dev(cfg->drbd_dev_name);
...
cfg->lock_fd = dt_lock_drbd(cfg->minor);
...
}
找到设备子版本号,并在退出函数之前,获得到内存锁
...
rv = command->function(cfg, argv + ai, argc - ai);
这里调用的是meta_create_md函数(不同的函数执行的功能不同),接着进入function(meta_create_md):
if (is_v09(cfg)) {
...
}
检查配置为DRBD_V09版本
...
err = cfg->ops->open(cfg);
执行open函数
if (err == VALID_MD_FOUND_AT_LAST_KNOWN_LOCATION) {
...
}
调整/检测备机(脱机)的元数据
err = err || cfg->ops->md_cpu_to_disk(cfg);
应该是缓存写入磁盘(由内核处理实际数据,这里是逻辑上的处理),最大一块(一次)大概为128M,可以在配置文件中设置
if (!err)
wipe_after_convert(cfg);
写入成功后,清除缓存
err = cfg->ops->close(cfg)
回到meta_create_md函数,执行close函数,退出meta_create_md函数,到这里一次同步完成
回到m__system函数...
*ex = rv;
返回结果到_adm_drbdmeta函数(_adm_drbdmeta函数功能由ctx->cmd来决定,也就是内部调用的command->function,可以作为本机同步,也可以作为对方机器同步等)
...
在内核篇讲述与内核的调用关系
}
...
回到run_adm_drbdmeta,继续向下执行:
if(!device_uuid) {
get_random_bytes(&device_uuid, sizeof(uint64_t));
}
获取uuid
if (send) {
uri = ssprintf("http://"HTTP_HOST"/cgi-bin/insert_usage.pl?"
"nu="U64"&ru="U64"&rs="U64,
ni.node_uuid, device_uuid, device_size);
make_get_request(uri);
}
如果本机为主节点,应发送数据同步请求
...
2.3 drbdsetup执行过程
drbdsetup目前发现在“/lib/drbd/drbd stop”时执行(外部调用,内部由别的工具调用),一般用在配置装载进kernel的DRBD模块,接下来进入user/v9/drbdsetup_main.c文件中的main函数:
return drbdsetup_main(argc, argv);
进入drbdsetup_main函数
if (!modprobe_drbd()) {
...
}
检查drbd.ko是否挂载
maybe_exec_legacy_drbdsetup(argv);
检查是否是drbdsetup-83或drbdsetup-84并执行
drbd_sock = genl_connect_to_family(&drbd_genl_family);
对GenericNetlink初始化并与内核GenericNetlink服务模块建立连接
if ((context & CTX_MINOR) && !cmd->lockless)
lock_fd = dt_lock_drbd(minor);
为打开的描述符加锁
rv = cmd->function(cmd, argc, argv);
调用功能函数
if ((context & CTX_MINOR) && !cmd->lockless)
dt_unlock_drbd(lock_fd);
为描述符解锁
...
函数执行完成,程序退出
边栏推荐
- FTP 服务器
- 解决ORCLE-ORA-01122 01110 01210
- [Linux] mariadb/mysql scheduled full backup script and data recovery
- Understanding of batchnorm2d() function in pytorch
- Voice data acquisition - real time voice data visualization
- Pyautogui realizes automatic office -rpa small case
- 线代003
- sql注入
- Matlab sound classification based on short-time neural network
- Color segmentation using kmeans clustering
猜你喜欢

NFS 服务器的搭建

Multipoint bidirectional republication and routing strategy

Echats关系图les-miserables的图表详细解析(和弦图)

女粉想要找男朋友,竟是为了...

Oracle view hard parsing

Based on LSM tree idea Net 6.0 C # write a kV database (case version)

Oracle查看硬解析

让人深思:句法真的重要吗?邱锡鹏组提出一种基于Aspect的情感分析的强大基线...

Oracle resizing data files

warning package.json: No license field报错
随机推荐
Sorting out some open source projects of speech recognition
Pygame: alien invasion
Des/3des/aes differences
多点双向重发布和路由策略
【精选】如何完美的写 PHP 代码的呢?
Local connection to remote server database under Windows platform (I)
Matlab-绘制日期和持续时间图
Matlab create text cloud
Matlab draws the system response under different damping
数学推理题:张王李赵陈五对夫妇聚会,见面握手
Discussion on a problem
Matlab-基于短时神经网络的声音分类
Fsm onehot 答题记录
备战金九银十Android面试准备(含面试全流程,面试准备工作面试题和资料等)
Matlab create the logo of MATLAB
Vs2019 Community Edition Download tutorial (detailed)
Matlab- draw date and duration diagram
flask_restful中的输出域(Resource、fields、marshal、marshal_with)
hdu5288(OO’s Sequence)
[Linux] install redis