热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MnesiaClusterTable在线增字段

Erlang集群中MnesiaTable如何在不影响正常业务的情况下增加减少字段?如何使用假如我们有

Erlang 集群中Mnesia Table 如何在不影响正常业务的情况下增加/减少字段?

预备知识

  • rebar3 dynamic configuration
  • rebar3 relx release打完整包与升级包
  • appup 升级release cookbook 规则
  • 升级mnesia table 的transform_table/4

情景描述

如何使用 mnesia:transform_table/4 在Mnesia Table增加(或减少)字段?

假如我们有一个用于监控记录节点各种情况的app,命名这counter, 每秒要证明一下自己还活着,把计数 + 1。

-record(node_info, {name, count}).
{atomic,ok} = mnesia:create_table(node_info, 
 [{attributes, record_info(node_info)}, 
 {ram_copies, [node()]}]);

使用一个gen_server每秒计数 + 1.

update_count() ->
 Fun = fun() ->
 [Client] = mnesia:read(?TABLE, node()),
 mnesia:write(Client#node_info{count = Client#node_info.count + 1})
 end,
{atomic, ok} = mnesia:sync_transaction(Fun).

mnesia node_info table 记录逻辑完整代码可见

这样,我们先release一下0.1.0版本的包,并把它跑起来

我们把release并启动的流程写在脚本 ./script/0.1.0-alice-start.sh 里。

#!/bin/bash
rm -rf _build
git checkout mnesia-upgrade-0.1.0-alice
export RELX_REPLACE_OS_VARS=true
export NODENAME=alice@127.0.0.1
export COOKIE=zhongwen
rebar3 release
_build/default/rel/counter/bin/counter-0.1.0-alice console

我们把release的包叫做counter-0.1.0-alice并使用git在这些代码上打上mnesia-upgrade-0.1.0-alice的Tag(方便后面切换版本)

关于 RELX_REPLACE_OS_VARS 的说明请看 rebar3 dynamic configuration

release完成后以console的方式启动。

启动后可以看到在console里面每5秒打印一次node_info表里面的内容。

=PROGRESS REPORT==== 13-Nov-2016::13:53:36 ===
 application: sasl
 started_at: 'alice@127.0.0.1'
Eshell V7.3 (abort with ^G)
(alice@127.0.0.1)1> [[{node_info,'alice@127.0.0.1',2}]]
[[{node_info,'alice@127.0.0.1',3}]]
[[{node_info,'alice@127.0.0.1',4}]]
...

需求升级(单节点时增加字段smp_support)

现在需要增加再加一个字段叫smp_support来记录节点是否支持smp

1.增加smp_support字段

-record(node_info, {name, count, smp_support}).

2.增加transform函数来改变表的结构和内容

-module(counter_db_transform).
-export([add_smp_support_to_node_info_table/0]).
-export([del_smp_support_to_node_info_table/0]).

add_smp_support_to_node_info_table() ->
 Fun =
 fun({node_info, Node, Count}) ->
 {node_info, Node, Count, undefined};
 (Record) -> Record
 end,
 NewAttrList = [node, count, smp_support],
 {atomic, ok} = mnesia:transform_table(node_info, Fun, NewAttrList),
 ok.

del_smp_support_to_node_info_table() ->
 Fun =
 fun({node_info, Node, Count, _}) ->
 {node_info, Node, Count};
 (Record) -> Record
 end,
 NewAttrList = [node, count],
 {atomic, ok} = mnesia:transform_table(node_info, Fun, NewAttrList),
 ok.
  • add_smp_support_to_node_info_table/0 用于升级
  • del_smp_support_to_node_info_table/0 用于降级

http://erlang.org/doc/man/mnesia.html#transform_table-4

Argument Fun can also be the atom ignore, which indicates that only the metadata about the table is updated. Use of ignore is not recommended, but included as a possibility for the user do to an own transformation.

这里的ignore就是只改变表的结构,但是不会对返回ignore的值作任何修改,也就是还是原来的record,我们并没有用到。

3.升级的appup.src我们定义的规则为

{"0.2.0",
 [
 {"0.1.0", [
 {load_module, counter_db_schema},
 {add_module, counter_db_transform},
 {apply, {counter_db_transform, add_smp_support_to_node_info_table, []}},
 {update, counter_collect_server, {advanced, delete_id}}

 ]}
 ],
 [
 {"0.1.0", [
 {apply, {counter_db_transform, del_smp_support_to_node_info_table, []}},
 {delete_module, counter_db_transform},
 {load_module, counter_db_schema},
 {update, counter_collect_server, {advanced, add_id}}
 ]}
 ]
}.

具体的appup.src规则(load_module, add_module, delete_module, update, apply)可以参照 cookbook 。

全部的代码都已完成,把代码打上mnesia-upgrade-0.2.0-alice的Tag,

接下来操作一下如何升级counter-0.1.0-alice到counter-0.2.0-alice。

升级脚本写在 ./script/upgrade-0.1.0-alice-to-0.2.0-alice.sh

#!/bin/bash
git checkout mnesia-upgrade-0.2.0-alice
export RELX_REPLACE_OS_VARS=true
export NODENAME=alice@127.0.0.1
export COOKIE=zhongwen
rebar3 release
rebar3 relup
rebar3 tar
mv _build/default/rel/counter/counter-0.2.0-alice.tar.gz _build/default/rel/counter/releases/0.2.0-alice/counter.tar.gz
_build/default/rel/counter/bin/counter-0.1.0-alice upgrade 0.2.0-alice

相比于0.1.0的release完整包的操作,我们在打0.2.0包是使用的升级包的方式,

release => relup => tar => 使用bin/counter-0.1.0-alice upgrade 0.2.0-alice升级。

执行此脚本后结果如下

===> tarball /Users/zhongwen/github/erlang-rock/mneisa-cluster-hot-upgrade-record-structure/counter/_build/default/rel/counter/counter-0.2.0-alice.tar.gz successfully created!
Release 0.2.0-alice not found, attempting to unpack releases/0.2.0-alice/counter.tar.gz
Unpacked successfully: "0.2.0-alice"
Installed Release: 0.2.0-alice
Made release permanent: "0.2.0-alice"

说明升级成功,我们再来去上面的console里面看一下每5秒钟打印的输出有木有了smp_support字段。

[[{node_info,'alice@127.0.0.1',124}]]
[[{node_info,'alice@127.0.0.1',125}]]
code change {169265188944133434916933618072298650122,
 {state,undefined,5000},
 delete_id}
[[{node_info,'alice@127.0.0.1',126,true}]]
[[{node_info,'alice@127.0.0.1',127,true}]]
[[{node_info,'alice@127.0.0.1',128,true}]]
(alice@127.0.0.1)6> mnesia:table_info(node_info, attributes).
[node,count,smp_support]
(alice@127.0.0.1)7> application:which_applications().
[{sasl,"SASL CXC 138 11","2.7"},
 {counter,"counter","0.2.0"},
 {mnesia,"MNESIA CXC 138 12","4.13.3"},
 {stdlib,"ERTS CXC 138 10","2.8"},
 {kernel,"ERTS CXC 138 10","4.2"}]

升级成功!

PS: code change 发生的原因是因为我们使用了appup.src里面使用update规则把state里面的id删掉了,有兴趣可以细看一下0.1.0升级和0.2.0的代码区别(在release如何运用code_change/3 热升级gen_server里面的state)。

需求再升级(在集群节点中再增加字段用于统计每个节点binary使用情况的binary)

counter applications的原来的目的就是集群中每个节点都把自己的情况以node()为key存到node_info表里面,然后可以在任意节点上看到集群上所有节点的node_info了,所以我们接下来,先建立一个集群环境,然后再在集群环境下尝试做升级。

1.创建2个节点alice bob互连并运行application counter-0.3.0

我们从头开始把counter-0.3.0作为base版本

把counter-0.2.0中的appup.src删掉,并把app.src rebar.config里面的版本号升级一下为0.3.0后打上mnesia-upgrade-0.3.0-alice Tag。

启动alice

脚本文件 ./script/0.3.0-alice-start.sh

#!/bin/bash
git checkout mnesia-upgrade-0.3.0-alice
export RELX_REPLACE_OS_VARS=true
export NODENAME=alice@127.0.0.1
export CLUSTER_NODENAME=bob@127.0.0.1
export COOKIE=zhongwen
rebar3 release
_build/default/rel/counter/bin/counter-0.3.0-alice console

正常启动alice时时结果如下

=PROGRESS REPORT==== 13-Nov-2016::14:32:24 ===
 application: sasl
 started_at: 'alice@127.0.0.1'
Eshell V7.3 (abort with ^G)
(alice@127.0.0.1)1> [[{node_info,'alice@127.0.0.1',2,true}]]
[[{node_info,'alice@127.0.0.1',3,true}]]

(alice@127.0.0.1)1> application:which_applications().
[{sasl,"SASL CXC 138 11","2.7"},
 {counter,"counter","0.3.0"},
 {mnesia,"MNESIA CXC 138 12","4.13.3"},
 {stdlib,"ERTS CXC 138 10","2.8"},
 {kernel,"ERTS CXC 138 10","4.2"}]
(alice@127.0.0.1)2> [[{node_info,'alice@127.0.0.1',4,true}]]
[[{node_info,'alice@127.0.0.1',5,true}]]

基本功能和0.2.0一样,不过会多一个节点互连功能,

把counter-0.3.0-alice的包名改成counter-0.3.0-bob后mnesia-upgrade-0.3.0-bob Tag。

脚本文件 ./script/0.3.0-bob-start.sh

#!/bin/bash
git checkout mnesia-upgrade-0.3.0-bob
export RELX_REPLACE_OS_VARS=true
export NODENAME=bob@127.0.0.1
export CLUSTER_NODENAME=alice@127.0.0.1
export COOKIE=zhongwen
rebar3 release
_build/default/rel/counter/bin/counter-0.3.0-bob console

正常启动bob里输出为

=PROGRESS REPORT==== 13-Nov-2016::14:38:34 ===
 application: sasl
 started_at: 'bob@127.0.0.1'
Eshell V7.3 (abort with ^G)
(bob@127.0.0.1)1> [[{node_info,'alice@127.0.0.1',113,true}],[{node_info,'bob@127.0.0.1',2,true}]]

可以看到在bob console里面已看到了alice节点的情况

我们再来确认一下alice是否能看到bob

(alice@127.0.0.1)1> [[{node_info,'alice@127.0.0.1',112,true}]]
[[{node_info,'alice@127.0.0.1',113,true}],[{node_info,'bob@127.0.0.1',1,true}]]

2.升级一个为了兼容旧代码的小版本

集群和单节点不一样的是,mnesia table是在alice bob之前 共享表结构和数据 的,如果我们先升级alice,那么没有升级的bob就会报错,因为bob上跑的是旧代码,他的node_info 没有binary字段,但alice升级就把node_info table升级成带binary字段的table了。这样bob就惨了。

所以我们一定要保证bob在alice升级完成后也不报错,所以在做真正升级时做一个兼容代码的小版本,让旧代码遇到新表数据时也不报错!

我们来做这个兼容小版本叫0.3.1

主要变动就是:

update_count() ->
 Fun = fun() ->
- [Client] = mnesia:read(?TABLE, node()),
- mnesia:write(Client#node_info{count = Client#node_info.count + 1,
- smp_support = erlang:system_info(smp_support)})
- end,
+ case mnesia:read(?TABLE, node()) of
+ [Client] when is_record(Client, node_info) ->
+ mnesia:write(Client#node_info{count = Client#node_info.count + 1,
+ smp_support = erlang:system_info(smp_support)
+ });
+ [{node_info, Name, Count, _SmpSupport, _Binary}] ->
+ mnesia:write({node_info, Name, Count + 1, erlang:system_info(smp_support), erlang:memory(binary)})
+ end
+ end,
 {atomic, ok} = mnesia:sync_transaction(Fun),
 io:format("~p~n", [[mnesia:dirty_read(?TABLE, Key) ||Key <- mnesia:dirty_all_keys(?TABLE)]]).

让这代码可以跑新旧表结果的数据。

所有改动可以使用以下命令看到

git diff mnesia-upgrade-0.3.0-alice mnesia-upgrade-0.3.1-alice

升级alice 0.3.0 到 0.3.1

./script/upgrade-0.3.0-alice-to-0.3.1-alice.sh

#!/bin/bash
git checkout mnesia-upgrade-0.3.1-alice
export RELX_REPLACE_OS_VARS=true
export NODENAME=alice@127.0.0.1
export CLUSTER_NODENAME=bob@127.0.0.1
export COOKIE=zhongwen
rebar3 release
rebar3 relup --upfrom 0.3.0-alice
rebar3 tar
mv _build/default/rel/counter/counter-0.3.1-alice.tar.gz _build/default/rel/counter/releases/0.3.1-alice/counter.tar.gz
_build/default/rel/counter/bin/counter-0.3.0-alice upgrade 0.3.1-alice

成功提示

===> Resolved counter-0.3.1-alice
===> tarball /Users/zhongwen/github/erlang-rock/mneisa-cluster-hot-upgrade-record-structure/counter/_build/default/rel/counter/counter-0.3.1-alice.tar.gz successfully created!
Release 0.3.1-alice not found, attempting to unpack releases/0.3.1-alice/counter.tar.gz
Unpacked successfully: "0.3.1-alice"
Installed Release: 0.3.1-alice
Made release permanent: "0.3.1-alice"

同样升级bob 0.3.0 到 0.3.1

./script/upgrade-0.3.0-bob-to-0.3.1-bob.sh

成功提示

===> Resolved counter-0.3.1-bob
===> tarball /Users/zhongwen/github/erlang-rock/mneisa-cluster-hot-upgrade-record-structure/counter/_build/default/rel/counter/counter-0.3.1-bob.tar.gz successfully created!
Release 0.3.1-bob not found, attempting to unpack releases/0.3.1-bob/counter.tar.gz
Unpacked successfully: "0.3.1-bob"
Installed Release: 0.3.1-bob
Made release permanent: "0.3.1-bob"

3. mnesia node_info table加入binary字段

这里我们从0.3.1升级到0.4.1(加了binary字段)上就和单节点上升级一样操作了,先升级alice,然后再升级bob即可。

主要就是跑以下2个脚本

./script/upgrade-0.3.1-alice-to-0.4.1-alice.sh

./script/upgrade-0.3.1-bob-to-0.4.1-bob.sh

因为步骤一样,所以就不在演示啦。看效果就是

bob alice都在线升级到了0.4.1。可以看到每个节点binary统计。

[[{node_info,'alice@127.0.0.1',90,true,41456}],
 [{node_info,'bob@127.0.0.1',87,true,29608}]]

总结

  • mnesia单节点table升级要直接使用mnesia:transform_table/4
  • mnesia集群table升级要先把所有节点的旧代码升级到兼容新旧table的小版本,再依次所有节点从小版本升级到真正需要的版本。

以上所述就是小编给大家介绍的《Mnesia Cluster Table 在线增字段》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 我们 的支持!


推荐阅读
  • .NetCoreWebApi生成Swagger接口文档的使用方法
    本文介绍了使用.NetCoreWebApi生成Swagger接口文档的方法,并详细说明了Swagger的定义和功能。通过使用Swagger,可以实现接口和服务的可视化,方便测试人员进行接口测试。同时,还提供了Github链接和具体的步骤,包括创建WebApi工程、引入swagger的包、配置XML文档文件和跨域处理。通过本文,读者可以了解到如何使用Swagger生成接口文档,并加深对Swagger的理解。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 突破MIUI14限制,自定义胶囊图标、大图标样式,支持任意APP
    本文介绍了如何突破MIUI14的限制,实现自定义胶囊图标和大图标样式,并支持任意APP。需要一定的动手能力和主题设计师账号权限或者会主题pojie。详细步骤包括应用包名获取、素材制作和封包获取等。 ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • 本文介绍了如何使用vue-awesome-swiper组件,包括在main.js中引入和使用swiper和swiperSlide组件,以及设置options和ref属性。同时还介绍了如何在模板中使用swiper和swiperSlide组件,并展示了如何通过循环渲染swipes数组中的数据,并使用picUrl属性显示图片。最后还介绍了如何添加分页器。 ... [详细]
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
  • 本文介绍了如何使用elementui分页组件进行分页功能的改写,只需一行代码即可调用。通过封装分页组件,避免在每个页面都写跳转请求的重复代码。详细的代码示例和使用方法在正文中给出。 ... [详细]
  • 先看看ElementUI里关于el-table的template数据结构:<template><el-table:datatableData><e ... [详细]
  • 本文介绍了使用readlink命令获取文件的完整路径的简单方法,并提供了一个示例命令来打印文件的完整路径。共有28种解决方案可供选择。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • GPT-3发布,动动手指就能自动生成代码的神器来了!
    近日,OpenAI发布了最新的NLP模型GPT-3,该模型在GitHub趋势榜上名列前茅。GPT-3使用的数据集容量达到45TB,参数个数高达1750亿,训练好的模型需要700G的硬盘空间来存储。一位开发者根据GPT-3模型上线了一个名为debuid的网站,用户只需用英语描述需求,前端代码就能自动生成。这个神奇的功能让许多程序员感到惊讶。去年,OpenAI在与世界冠军OG战队的表演赛中展示了他们的强化学习模型,在限定条件下以2:0完胜人类冠军。 ... [详细]
  • 本文介绍了如何使用n3-charts绘制以日期为x轴的数据,并提供了相应的代码示例。通过设置x轴的类型为日期,可以实现对日期数据的正确显示和处理。同时,还介绍了如何设置y轴的类型和其他相关参数。通过本文的学习,读者可以掌握使用n3-charts绘制日期数据的方法。 ... [详细]
author-avatar
刘家大宝688
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有