Files
rebar_server/game_server/apps/ms_cache
2026-05-19 11:30:21 +08:00
..
2026-05-19 11:30:21 +08:00
2026-05-19 11:30:21 +08:00
2026-05-19 11:30:21 +08:00
2026-05-19 11:30:21 +08:00
2026-05-19 11:30:21 +08:00

1、ms_cache服务 ms_cache是居于第三方mysql驱动开发的缓存功能;支持游戏节点内部署,做为游戏服的一部分;也支持独立部署,作为数据中心使用。 ms_cache使用会涉及到三个比较重要的东西 1、ms_cache的application的配置,指定ms_cache使用的数据库地址、类型、运作方式等 2、rebar3_cache_plugin插件工具,通过配置文件生成ms_cache缓存服务需要的适配文件 3、rebar3_cache_plugin插件插件需要的配置文件

2、ms_cache的application配置,内容格式如下 {ms_cache, [ {data_node, undefined}, % 缓存节点,undefined为缓存app启动在本节点 {cache_db_type, ets}, % 缓存在内存的储存位置 proc | ets | mnesia(mnesia暂不支持) {rw_mode, concurrency}, % 缓存读写模式 concurrency-并行读写(脏读脏写) serial-串行读写(经过缓存进程进行读写) {data_sync_mode, key}, % 缓存数据同步模式 key-同步主键(写库时需要根据key读取缓存表的数据,然后同步到数据库) data-同步数据 {data_fmt, record}, % 缓存数据存取的格式, record | map 默认为record {table_worker_count, 8}, % 每个内存表对应处理的进程数(哈希分组到各个进程) {db_save_time, 120000}, % (定时同步参数)缓存定期同步到数据库的时间间隔,单位毫秒;默认值 120000 {db_save_count, 1000}, % (定量同步参数)缓存待同步数量上限,达到数量触发同步数据库操作;默认值 1000 {db_driver, 'mysql-otp'}, % 使用的数据库驱动(当前只支持mysql-otp第三方驱动,可扩展支持mongo {db_user, "xrxdzadmin"}, % 数据库用户 {db_pass, "xrxdz@4399##"}, % 数据库密码 {db_host, "172.16.12.111"}, % 数据库地址 {db_port, 3306}, % 数据库端口 {db_name, "xrxdz_test_game"}, % 数据库名 {db_encoding, utf8}, % 数据库编码(mysql-otp驱动下没用到) {db_select_pool_name, select_pool_name}, % 数据库查询链接名 {db_select_pool_size, 32}, % 数据库查询链接池初始容量 {db_select_pool_overflow, 128}, % 数据库查询链接池可扩展容量 {db_update_pool_name, update_pool_name}, % 数据库更新链接名(增删改都使用该链接) {db_update_pool_size, 10}, % 数据库更新链接池初始容量 {db_update_pool_overflow, 0}, % 数据库更新链接池可扩展容量 %% 启动前修复数据,通过启动一个erlang节点来处理 {db_sync_options, #{ create_table => true, % 是否自动创建表 alter_table => true, % 是否自动修改表字段(修改主键的话删表重建) patch_run_mod => auto, % 补丁运行模式,auto-启动服务器时自动运行, {env,"ERLANG_RUN_PATCH"}-启动时系统设置了这个环境变量就运行 patch_prefix => "patch_", % 补丁文件的前缀名 limit => 7 % 最多检查近x条补丁,如有遗漏追加执行,外网建议设置为1 }} ]}

3、配置文件,.table结尾,内容格式如下

%% ==================================================================================================== %% 表配置说明 %% %% {表名, 字段名列表, 主键字段列表, [可选属性map结构]} %% %% {TabName, FieldList, PrimKeyList, [OptionMap]} %% %% TabName :: 数据库对应的表名,也是代码里对应的record名 %% %% FieldList :: [Field] 字段列表,对应mysql数据库表的字段 %% Field :: {Name, Type, Len, Common, Sync} %% Name :: 字段名 %% Type :: 类型,int | binary | list | map | atom | boolean | tuple | any(上面所有类型都可以,数据库用blob存储) %% Len :: 数据库表中该字段的长度,(Len=0Type= list | map | tuple, 则表示该字段数据库表用text来存储, binary和any则用blob来存储) %% Common :: 字段的说明 %% Sync :: 是否同步到数据库表,true | false (当Sync=false,表示该字段是临时数据,数据库表也没有该字段) %% %% PrimKeyList :: 表主键,为空默认表的第一个字段作为主键;多个字段表示联合主键 %% %% OptionMap :: 可选属性map结构,不配置则默认为#{};key对应的首个value为默认值,不存在key则为该默认值 %% #{ %% type => set | ordered_set, % 表类型,目前只支持set和ordered_set,参考ets用法 %% indexes => [], % 表索引,自动创建数据库表时自动创建索引 %% uid_field => undefined, % 唯一id字段,类似于唯一索引,undefined表示该表不需要唯一id字段(该字段主要是用来生成select max取表的最大唯一id值) %% pre_load => false | true, % 启动时是否全量加载数据 %% clear_all => false | true, % 表示可否通过ms_cache:delete_all_objects方法删除表的所有数据(慎用,不重要数据可以用该字段) %% db_save_time => 0 | N |... % (定时同步参数)缓存定期同步到数据库的时间间隔,单位毫秒;(默认读sys.config中ms_cache配置的db_save_time %% db_save_count => 0 | N |... % (定量同步参数)缓存待同步数量上限,达到数量触发同步数据库操作;(默认读sys.config中ms_cache配置的db_save_count %% merge_type => 0 | 1 | 2 | 3 % 合服类型,用于生成合服sql,0-保留主从服数据(默认值) 1-保留主服数据 2-保留从服数据 3-删除主从服数据, 4-不处理(合服后处理) %% }. %% ==================================================================================================== %% 测试表1, 单主键, 预加载 {im_test_1, [ {im_long, int, 20, "long type", true}, {im_shot, int, 4, "shot type", true}, {im_int, int, 11, "int type", true}, {im_atom, int, 20, "atom type", true}, {im_boolean, boolean, 8, "boolean type", true}, {im_binary, binary, 64, "binary type", true}, {im_tuple, tuple, 64, "tuple varchar type", true}, {im_list, list, 64, "list varchar type", true}, {im_map, map, 64, "map varchar type", true}, {im_tuple_text, tuple, 0, "tuple text type", true}, {im_list_text, list, 0, "list text type", true}, {im_map_text, map, 0, "map text type", true}, {im_any, any, 0, "any type db-type is blob", true}, {im_index, int, 20, "index for table", true} ], [im_long], #{ indexes=>[im_db_index], pre_load=>true } }.

%% 测试表2, 双主键(im_long + im_short {im_test_2, [ {im_long, int, 20, "long type", true}, {im_shot, int, 4, "shot type", true}, {im_int, int, 11, "int type", true}, {im_atom, int, 20, "atom type", true}, {im_boolean, boolean, 8, "boolean type", true}, {im_binary, binary, 64, "binary type", true}, {im_tuple, tuple, 64, "tuple varchar type", true}, {im_list, list, 64, "list varchar type", true}, {im_map, map, 64, "map varchar type", true}, {im_tuple_text, tuple, 0, "tuple text type", true}, {im_list_text, list, 0, "list text type", true}, {im_map_text, map, 0, "map text type", true}, {im_any, any, 0, "any type db-type is blob", true}, {im_compound_index1,int, 20, "compound index for table", true}, {im_compound_index2,int, 20, "compound index for table", true} ], [im_long, im_shot], #{ indexes=>[{im_compound_index1, im_compound_index2}] } }.

%% 其他说明 多key情况下,key的使用形式是tuple;所以不管是单key的字段,还是多key的每个字段,格式都不能为tuple index的创建,多个index用逗号隔开;复合索引用tuple表示

4、rebar3_cache_plugin插件及ms_cache库在rebar.config中配置如下

%% ms_cache做为第三方依赖库 {deps, [ mysql , mysql_poolboy , poolboy , ms_cache ]}.

%% 缓存插件定义 {plugins, [ {rebar3_cache_plugin, "0.1.0"} %% 缓存插件 ]}.

%% cache缓存插件配置(支持配置多个app的配置) {cache_opts, [ {game_server, [ % app名字 {i, "cache"}, % 缓存配置目录 {module_name_prefix, ""}, % 文件名前缀,""表示没有前缀名字 {module_name_suffix, "_c"}, % 文件名后缀,""表示没有后缀名字 {o_erl, "src/auto_gen/cache"}, % erl文件的输出目录 {o_hrl, "include/auto_gen/cache"}, % hrl文件的输出目录 {o_sql, "sql"}, % sql文件输出目录 {strings_as_binaries, true}, type_specs ]} ]}.

%% 使用命令如下,也可以配置在rebar.config自动执行 rebar3 cache clean rebar3 cache compile

5、常用方法调用

节点内调用 | 跨节点调用 ms_cache:lookup(Table, Key) | ms_cache:lookup(Node, Table, Key) ms_cache:lookup_by_key_index(Table, KeyIndex) | ms_cache:lookup_by_key_index(Node, Table, KeyIndex) ms_cache:update(Table, RecOrMap) | ms_cache:update(Node, Table, RecOrMap) ms_cache:delete(Table, Key) | ms_cache:update(Node, Table, Key) ms_cache:insert(Table, RecOrMap) | ms_cache:update(Node, Table, RecOrMap)

以下是一些常用的仅查询缓存数据的方法(忽略数据库里的数据,通常是一些预先将所有数据加载导内存的表才会用到这些功能) ms_cache:index_read(Table, Key, Pos) | ms_cache:index_read(Node, Table, Key, Pos) ms_cache:size(Table) | ms_cache:size(Node, Table) ms_cache:tab2list(Table) | ms_cache:tab2list(Node, Table) ms_cache:tab2list_foldl(Table, Fun, Acc) | ms_cache:tab2list_foldl(Node, Table, Fun, Acc)

以下是一些常用的仅查询数据库的方法(忽略缓存里的数据,通常是启服初始化的时候从数据库里获取数据,比如一次性读出角色表的多有名字写入ets用于业务唯一性检测) ms_cache:select_count(Table) | ms_cache:select_count(Node, Table) ms_cache:select_max(Table) | ms_cache:select_max(Node, Table) ms_cache:select_max(Table) | ms_cache:select_max(Node, Table) ms_cache:select_foldl(Table, Fun, Acc) | ms_cache:select_foldl(Node, Table, Fun, Acc)

ms_cache:lookup_by_key_index/2方法的使用说明 在多key表的情况下,按照第一个key获取对应的所有数据 在单key表的情况下,等同于 [ms_cache:lookup/2],注意返回值是个列表

6、其他说明

文件中定义了数据的record结构,并提供了record转map的功能; record生成时自动增加'_id'作为record的key map格式使用时,数据必需带上'_table'作为区分表的keymap该key对应的value为表名atom '_id' 和 '_table' 作为保留字段,在配置中不能作为数据的字段,为了便于阅读,id字段最好也别用

ms_cache库中包含 ms_cache 和 ms_cache_internal 模块 早期只有ms_cache_internal,和其他模块一起组成一个独立运行的缓存应用系统;(所以ms_cache提供的方法这里基本也有) ms_cache是后期为了简化部分业务逻辑,提高读写性能引入的,所以ms_cache有些接口是在业务的需求下定义的,并没有那么纯粹 ms_cache主要做的事情 1、通过ms_cache:init(Table, Owner, Args),指定进程可以操作Table表的哪些数据,我们也将该进程称为这些数据的宿主进程 Owner = any,表示可以操作Table表的所有数据,这里有个特殊的情况,表的key字段不能为原子any Owner = KeyOrIndex, 对于单key表,只能操作KeyOrIndex为主键的一条数据;对于多key表,可以操作第1个key未KeyOrIndex的多条数据 2、Owner /= any进程字典内可以指定存储一份ms_cache:init指定的可以操作的数据;并通过Args参数,可以自行决定调用方法将数据写入缓存的时机,缓存的数据能否被手动移除 3、宿主进程可以实时访问最新的数据,非宿主进程只能访问缓存ets的数据,是否需要最新取决于Args参数的设定