EMQ持久化数据库Oracle,EMQ源码分析(五):Mnesia数据库

前言

基于EMQ2.3.11。Mnesia是分布式电信数据库管理系统,有以下特性:DBMS查询语言

数据持久性:表是持久化到存储的

集群复制:表可以在多个节点上复制

原子事务:支持事务

透明:对编程来说是透明的

实时数据搜索:查询速度很快

一、Mnesia表的创建参数

1、type 表类型

【取值】set:唯一键值,1:1,一个键一条记录

ordered_set:唯一键值,1:1,带排序

bag:1:n,一个键可以映射很多条记录

2、record_name 记录名称

【取值】记录名

所有表中的记录都必须是同一个记录的实例

3、ram_copies 内存复制

【取值】节点列表

可以指定要备份到哪些节点的内存中去,不保证事务更新。可以定时刷盘。

4、disc_copies 磁盘复制

【取值】节点列表

指定要备份到哪些节点的内存和磁盘中去,内存操作表格,磁盘追加操作日志。

5、disc_only_copies 强制磁盘复制

【取值】节点列表

指定备份到哪些节点的磁盘中去,操作都是基于磁盘操作,速度慢。

6、index 索引

【取值】属性名或整数列表

指定额外维护的索引表的元组位置

7、local_content 本地内容

【取值】true/false,默认false

表名对其他节点是已知的,但数据只在自己节点上。

8、majority

【取值】true/false,默认falsetrue:大多数表的副本都必须同步成功更新(保证数据一致性)

false:不需要立刻同步,副本数据可能某段时间不一致

9、snmp

【取值】SNMP键类型

将基于集合的表自动变为简单网络管理协议(SNMP)有序表。

10、attributes

【取值】Record的属性列表

指定要插入哪些属性到表中。

EMQ的表都是内存复制,而且是用的自行开发的ekka_mnesia库。

EMQ路由表是bag类型,因为一个Topic可能有多个Node都会订阅,是一个类似Map的表:-record(mqtt_route,

{ topic :: binary(),

node :: node()

}).

ok = ekka_mnesia:create_table(mqtt_route, [

{type, bag},

{ram_copies, [node()]},

{record_name, mqtt_route},

{attributes, record_info(fields, mqtt_route)}]);

EMQ的session是set类型,因为必须要保证clientId唯一性:-record(mqtt_session,

{ client_id :: binary(),

sess_pid :: pid(),

clean_sess :: boolean()

}).

%% Global Session Table

ok = ekka_mnesia:create_table(mqtt_session, [

{type, set},

{ram_copies, [node()]},

{record_name, mqtt_session},

{attributes, record_info(fields, mqtt_session)}]);

二、Mnesia表操作

这里只简单的记录EMQ用到过的表格操作是什么含义。

1、select 按条件读取表格

【原型】

select(Tab, MatchSpec [, Lock]) -> transaction abort | [Object]Tab:表名

MatchSpec:匹配参数

Lock:是否加锁读取

【示例】mnesia:select(mqtt_session, [{#mqtt_session{client_id = '$1', sess_pid = '$2', _ = '_'},[{'==', {node, '$2'}, Node}], ['$1']}])

2、write 写记录

【原型】write(Record) -> transaction abort | ok

write(Tab, Record, LockKind) -> transaction abort | okTab:表名

Record:记录值

LockKind:write写入锁,sticky_write粘滞写入锁

默认的write/1是本表+记录值+写入锁。sticky_write粘滞写入锁是一种用于优化锁获取的机制。如果您使用复制表的目的主要是为了容错(而不是为了快速读取访问),则粘滞锁可能是最佳选择。当获取粘滞写入锁时,将通知所有节点哪个节点被锁定。然后,来自同一节点的粘滞锁定请求将作为本地操作执行,而不与其他节点进行任何通信。即使在事务结束后,粘滞锁仍会留在节点上。

【示例】mnesia:write(Route).

3、delete 删除记录

【原型】delete({Tab, Key}) -> transaction abort | ok

delete(Tab, Key, LockKind) -> transaction abort | ok

和前面一致,默认用write写入锁,删除一行数据。

【示例】mnesia:delete({mqtt_trie_node, Topic})

4、delete_object 删除对象

【原型】delete_object(Record) -> transaction abort | ok

delete_object(Tab, Record, LockKind) -> transaction abort | ok

如果表是bag类型,一对多,可以用这个来删除所有数据,默认写入锁。

【示例】mnesia:delete_object(mqtt_route, R, write)

5、wread

【原型】wread({Tab, Key}) -> transaction abort | RecordList

read(Tab, Key, LockKind) -> transaction abort | RecordList

wread调用的read,使用写入锁(不可写)。

read的锁可以是:read、write、sticky_write。

【示例】mnesia:wread({mqtt_route, Topic})

6、ets

【原型】ets(Fun, [, Args]) -> ResultOfFun | exit(Reason)

调用一个非事务的函数,会去内存取本地ets表,速度很快,相当于取缓存。

【示例】EMQ只有一处用到了,在订阅树匹配的时候,因为只是读操作,但是操作次数太多,可以容忍脏读,所以用这个直接读内存:Matched = mnesia:ets(fun emqttd_trie:match/1, [Topic])

7、transaction 事务

【原型】transaction(Fun [[, Args], Retries]) -> {aborted, Reason} | {atomic, ResultOfFun}

以事务的方式执行Fun函数。

【示例】mnesia:transaction(Clean)

8、abort 中止事务

【原型】abort(Reason) -> transaction abort

主动表明事务执行失败,数据库恢复到事务之前的状态。

【示例】在进行delete_path的时候,递归到最后发现找不到指定节点,需要主动表明自己执行失败(因为是业务逻辑错误),所以使用了abort:mnesia:abort({node_not_found, NodeId})

9、dirty_read 脏读

【原型】dirty_read(Tab,Key)->ValueList | exit({aborted,Reason})

读取当前的数据,不需要事务。

【示例】mnesia:dirty_read(mqtt_session, ClientId)

10、dirty_delete_object 脏删

【原型】dirty_delete_object(Tab, Record)

删除当前数据,不需要事务。

【示例】remove_session(Session) ->

mnesia:dirty_delete_object(Session).

11、async_dirty 异步执行

【原型】async_dirty(Fun, [, Args]) -> ResultOfFun | exit(Reason)

不要事务地执行Fun函数。

【示例】只在路由表相关操作中使用到,因为增加路由表无需加锁:add_direct_route(Route) ->

mnesia:async_dirty(fun mnesia:write/1, [Route]).

12、dirty_all_keys

【原型】dirty_all_keys(Tab) -> KeyList | exit({aborted, Reason})

注意这里的dirty不是动词,而是只all_keys的脏操作版本,获取表的所有键值。

【示例】只在一处用到,路由表:topics() ->

mnesia:dirty_all_keys(mqtt_route).

参考资料

2、《腾讯云开发者文档:mnesia》(相当于手册的中文翻译,基本是机器翻译,很多错误)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
EMQ X Broker 支持多种持久化方式,包括 PostgreSQL 持久化。通过将数据写入 PostgreSQL 数据库,可以保证数据的可靠性和持久性,并且可以方便地进行数据的查询和分析。 要使用 PostgreSQL 持久化,需要进行以下步骤: 1. 安装 PostgreSQL 数据库,并创建一个数据库用于存储 EMQ X Broker 的数据。 2. 在 EMQ X Broker 的配置文件中设置 PostgreSQL 数据库的连接信息和相关参数,例如: ``` ## PostgreSQL ##-------------------------------------------------------------------- ## PostgreSQL database ##-------------------------------------------------------------------- ## The PostgreSQL database used by the EMQ X Broker for persistence. ## The default database is "emqx". ## ## Note: The specified user must be authorized to create tables and indexes ## in the database. ## ## Example: ## emqx.persistence.pgsql.server = postgresql://user:password@localhost:5432/emqx ## ## emqx.persistence.pgsql.server = postgresql://user:password@localhost:5432/emqx emqx.persistence.pgsql.server = postgresql://postgres:password@localhost:5432/emqx ``` 3. 启动 EMQ X Broker,数据将被写入 PostgreSQL 数据库中。 4. 可以使用 SQL 查询语句来查询和分析数据。 例如,以下 SQL 查询语句可以查询指定时间范围内的消息数量: ``` SELECT COUNT(*) FROM emqx_messages WHERE timestamp >= '2021-01-01 00:00:00' AND timestamp < '2022-01-01 00:00:00'; ``` 通过使用 PostgreSQL 持久化,可以实现 EMQ X Broker 数据的可靠存储和高效查询,为企业提供更加稳定和可靠的消息服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值