本地缓存模块架构与实现分析
1. 模块概述
本地缓存模块是cNetgate项目中的核心数据持久化组件,负责将内存中的数据定时持久化到本地存储中,确保数据在系统重启或异常情况下不会丢失。该模块采用分层设计,与内存缓存模块紧密配合,为系统提供了完整的数据管理解决方案。
1.1 主要功能
- 数据持久化:将内存缓存中的数据定时同步到本地SQLite数据库
- 数据恢复:系统重启时从本地数据库恢复数据到内存缓存
- 定时同步:支持配置同步周期,实现数据的定期持久化
- 数据管理:支持删除废弃的数据表,优化存储空间使用
- 南北向缓存:为北向数据通道和南向数据通道提供文件缓存支持
1.2 应用场景
- 系统重启后的数据恢复:确保系统重启后数据不丢失
- 网络异常时的数据缓存:当北向通道网络异常时,数据暂时缓存到本地文件
- 数据备份:作为数据的本地备份,防止数据意外丢失
- 历史数据查询:提供历史数据的查询能力
2. 架构设计
2.1 整体架构图
#mermaid-svg-LhWqDkBlBdgs1rCt{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LhWqDkBlBdgs1rCt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LhWqDkBlBdgs1rCt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LhWqDkBlBdgs1rCt .error-icon{fill:#552222;}#mermaid-svg-LhWqDkBlBdgs1rCt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LhWqDkBlBdgs1rCt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LhWqDkBlBdgs1rCt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LhWqDkBlBdgs1rCt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LhWqDkBlBdgs1rCt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LhWqDkBlBdgs1rCt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LhWqDkBlBdgs1rCt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LhWqDkBlBdgs1rCt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LhWqDkBlBdgs1rCt .marker.cross{stroke:#333333;}#mermaid-svg-LhWqDkBlBdgs1rCt svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LhWqDkBlBdgs1rCt p{margin:0;}#mermaid-svg-LhWqDkBlBdgs1rCt .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-LhWqDkBlBdgs1rCt .cluster-label text{fill:#333;}#mermaid-svg-LhWqDkBlBdgs1rCt .cluster-label span{color:#333;}#mermaid-svg-LhWqDkBlBdgs1rCt .cluster-label span p{background-color:transparent;}#mermaid-svg-LhWqDkBlBdgs1rCt .label text,#mermaid-svg-LhWqDkBlBdgs1rCt span{fill:#333;color:#333;}#mermaid-svg-LhWqDkBlBdgs1rCt .node rect,#mermaid-svg-LhWqDkBlBdgs1rCt .node circle,#mermaid-svg-LhWqDkBlBdgs1rCt .node ellipse,#mermaid-svg-LhWqDkBlBdgs1rCt .node polygon,#mermaid-svg-LhWqDkBlBdgs1rCt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LhWqDkBlBdgs1rCt .rough-node .label text,#mermaid-svg-LhWqDkBlBdgs1rCt .node .label text,#mermaid-svg-LhWqDkBlBdgs1rCt .image-shape .label,#mermaid-svg-LhWqDkBlBdgs1rCt .icon-shape .label{text-anchor:middle;}#mermaid-svg-LhWqDkBlBdgs1rCt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LhWqDkBlBdgs1rCt .rough-node .label,#mermaid-svg-LhWqDkBlBdgs1rCt .node .label,#mermaid-svg-LhWqDkBlBdgs1rCt .image-shape .label,#mermaid-svg-LhWqDkBlBdgs1rCt .icon-shape .label{text-align:center;}#mermaid-svg-LhWqDkBlBdgs1rCt .node.clickable{cursor:pointer;}#mermaid-svg-LhWqDkBlBdgs1rCt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LhWqDkBlBdgs1rCt .arrowheadPath{fill:#333333;}#mermaid-svg-LhWqDkBlBdgs1rCt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LhWqDkBlBdgs1rCt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LhWqDkBlBdgs1rCt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LhWqDkBlBdgs1rCt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LhWqDkBlBdgs1rCt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LhWqDkBlBdgs1rCt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LhWqDkBlBdgs1rCt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LhWqDkBlBdgs1rCt .cluster text{fill:#333;}#mermaid-svg-LhWqDkBlBdgs1rCt .cluster span{color:#333;}#mermaid-svg-LhWqDkBlBdgs1rCt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-LhWqDkBlBdgs1rCt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LhWqDkBlBdgs1rCt rect.text{fill:none;stroke-width:0;}#mermaid-svg-LhWqDkBlBdgs1rCt .icon-shape,#mermaid-svg-LhWqDkBlBdgs1rCt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LhWqDkBlBdgs1rCt .icon-shape p,#mermaid-svg-LhWqDkBlBdgs1rCt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LhWqDkBlBdgs1rCt .icon-shape rect,#mermaid-svg-LhWqDkBlBdgs1rCt .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LhWqDkBlBdgs1rCt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LhWqDkBlBdgs1rCt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LhWqDkBlBdgs1rCt :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
扩展层
存储层
核心层
应用层
插件模块
数据缓存模块
触发器模块
转发器模块
内存缓存
本地缓存模块
sqlite3模块
文件缓存
db文件
缓存文件
南北向缓存
北向缓存
南向缓存
2.2 模块关系
本地缓存模块与其他模块的关系如下:
- 与内存缓存模块:本地缓存模块是内存缓存模块的持久化层,负责将内存中的数据同步到本地存储
- 与插件模块:插件模块通过内存缓存模块间接与本地缓存模块交互,插件采集的数据最终会通过本地缓存模块持久化
- 与触发器模块:触发器模块监控内存缓存中的数据变化,当触发条件满足时执行相应动作,本地缓存模块确保这些数据的持久化
- 与转发器模块:当转发器模块的北向通道异常时,数据会通过本地缓存模块缓存到本地文件,待通道恢复后再转发
3. 核心数据结构
3.1 本地缓存主结构
typedef struct stLocalCache
{
string_t * p_path; // 缓冲区文件路径
timerCtx * p_timer; // 定时执行缓冲操作
sqlite3 * p_db; // 数据库对象
bool m_enable; // 是否启用
bool m_remove_unused; // 删除已经废弃的数据表
long m_sync_itval; // 同步周期,单位ms
long m_max_size; // 最大缓存大小
long m_max_expire; // 数据最久保存时间,每天更新
long m_sql_max_buff; // SQL最大缓冲尺寸
cJSON * p_tmp_root; // 临时根对象,用于构建同步数据
}localCache_t;
3.2 北向缓存结构
typedef struct stLocalCacheNorth
{
uint64_t max_count; ///< 最大缓存数量
uint32_t page_size; ///< 每页大小
uint32_t max_page; ///< 最大页数
char * p_path; ///< 缓存路径
tinySeqFile* p_tsf; ///< 顺序文件对象指针
}localCacheNorth_t;
3.3 南向缓存结构
typedef struct stLocalCacheSouth
{
pthread_t pth_read; ///< 读取线程
bool b_stop; ///< 停止标志
tinySeqFile * p_tsf; ///< 缓存队列指针
}localCacheSouth_t;
4. 主要功能实现
4.1 本地缓存初始化
函数:newLocalCache(cJSON * config)
功能:创建并初始化本地缓存对象
实现流程:
- m_enable:是否启用本地缓存
- p_path:缓存文件路径
- m_max_size:最大缓存大小
- m_sync_itval:同步周期(毫秒)
- m_max_expire:数据过期时间
- m_remove_unused:是否删除废弃数据表
- m_sql_max_buff:SQL最大缓冲尺寸
4.2 数据库表初始化
函数:localCache__init_tables__(localCache_t * ctx)
功能:初始化数据库表结构
实现流程:
- 调用localCache__create_db__创建数据库和表
- 如果m_remove_unused为true,调用localCache__adjust_db__删除废弃数据表
4.3 数据库创建
函数:localCache__create_db__(localCache_t * ctx)
功能:根据点表的站点名称创建数据库表
实现流程:
- id:自增主键
- createTime:创建时间,默认当前时间
- data:存储JSON格式的数据
4.4 数据库调整
函数:localCache__adjust_db__(localCache_t * ctx)
功能:删除数据库中已不存在于工程文件中的数据表
实现流程:
4.5 数据同步
函数:localCache_Sync(localCache_t * ctx)
功能:将内存缓存中的数据同步到本地数据库
实现流程:
- 创建临时JSON根对象
- 调用dataIteratorBySite遍历内存缓存中的数据
- 将数据转换为JSON格式并存储到临时对象中
- 构建INSERT SQL语句
- 执行SQL语句将数据插入到数据库表中
4.6 定时同步
函数:localCache_Start(localCache_t * ctx, bool sw)
功能:启动定时同步功能
实现流程:
- 创建定时器,设置回调函数为localCache__on_timer__
- 启动定时器,设置定时周期为m_sync_itval
- 停止定时器
4.7 定时器回调
函数:localCache__on_timer__(timerCtx * timer)
功能:定时器到期时执行数据同步
实现流程:
4.8 数据恢复
函数:localCache_RestoreIter(localCache_t* ctx, localCache_restorCb cb, void * usr)
功能:从本地数据库恢复数据到内存缓存
实现流程:
- 构建查询SQL语句
- 执行查询操作
- 调用回调函数localCache__on_read_db__处理查询结果
- 通过回调函数将数据恢复到内存缓存
4.9 按站点恢复数据
函数:localCache_RestoreByeSiteIter(localCache_t* ctx, const string_t * site, localCache_restorBySiteCb cb, void * usr)
功能:从本地数据库按站点恢复数据到内存缓存
实现流程:
4.10 北向缓存写入
函数:addLocalCache(localCacheNorth_t * cache, const void * data, uint32_t size)
功能:将北向数据写入本地缓存文件
实现流程:
4.11 北向缓存事件处理
函数:localCacheNorth__on_data__(void * ev)
功能:处理北向数据事件,将数据写入缓存
实现流程:
4.12 南向缓存读取
函数:locacheSouth__Read(localCacheSouth_t * cache, buffer_t * data)
功能:从南向缓存文件读取数据
实现流程:
4.13 南向缓存读取线程
函数:localCacheSouth__read_thread__(void * arg)
功能:南向缓存读取线程,处理缓存数据读取和发送
实现流程:
- 创建数据缓冲区
- 调用locacheSouth__Read读取数据
- 如果读取成功:
- 创建事件参数
- 创建事件对象
- 调用eventLoopEmit发送事件
4.14 南向缓存隧道就绪处理
函数:localCacheSouth__on_tunnel_ready__(void * evt_data)
功能:处理南向通道就绪事件,启动读取线程
实现流程:
4.15 南向缓存读取任务创建
函数:localCacheSouth__create_read_mission__(localCacheSouth_t * ctx)
功能:创建南向缓存读取线程
实现流程:
4.16 本地缓存释放
函数:localCache_release__(localCache_t * ctx)
功能:释放本地缓存对象资源
实现流程:
- 调用localCache_Sync同步数据
- 关闭数据库连接
4.17 北向缓存创建
函数:locacheNorth__Create()
功能:创建北向缓存对象并连接事件循环
实现流程:
4.18 北向缓存配置
函数:locacheNorth__SetOption(localCacheNorth_t * ctx, int opt, void * params)
功能:设置北向缓存选项
实现流程:
- LOCACHE_NORTH_OPT_MAX_COUNT:设置最大缓存数量
- LOCACHE_NORTH_OPT_PAGE_SIZE:设置每页大小
- LOCACHE_NORTH_OPT_MAX_PAGE:设置最大页数
- LOCACHE_NORTH_OPT_CACHE_PATH:设置缓存路径
- LOCACHE_NORTH_OPT_APPLY:应用配置,创建顺序文件
4.19 南向缓存创建
函数:locacheNorth__Create()
功能:创建南向缓存对象
实现流程:
4.20 南向缓存释放
函数:locacheSouth__Release(localCacheSouth_t * ctx)
功能:释放南向缓存对象资源
实现流程:
4.21 南向缓存配置
函数:locacheSouth__SetOption(localCacheSouth_t * ctx, int opt, void * params)
功能:设置南向缓存选项
实现流程:
- CACHE_SOUTH_OPTION_FILE_ENGINE:设置文件引擎
5. 工作流程
5.1 数据持久化流程
SQLite数据库定时器本地缓存内存缓存SQLite数据库定时器本地缓存内存缓存#mermaid-svg-TvMmUIdRKrMqdLS6{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TvMmUIdRKrMqdLS6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TvMmUIdRKrMqdLS6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TvMmUIdRKrMqdLS6 .error-icon{fill:#552222;}#mermaid-svg-TvMmUIdRKrMqdLS6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TvMmUIdRKrMqdLS6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TvMmUIdRKrMqdLS6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TvMmUIdRKrMqdLS6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TvMmUIdRKrMqdLS6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TvMmUIdRKrMqdLS6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TvMmUIdRKrMqdLS6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TvMmUIdRKrMqdLS6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TvMmUIdRKrMqdLS6 .marker.cross{stroke:#333333;}#mermaid-svg-TvMmUIdRKrMqdLS6 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TvMmUIdRKrMqdLS6 p{margin:0;}#mermaid-svg-TvMmUIdRKrMqdLS6 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-TvMmUIdRKrMqdLS6 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-TvMmUIdRKrMqdLS6 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-TvMmUIdRKrMqdLS6 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-TvMmUIdRKrMqdLS6 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-TvMmUIdRKrMqdLS6 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-TvMmUIdRKrMqdLS6 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-TvMmUIdRKrMqdLS6 .sequenceNumber{fill:white;}#mermaid-svg-TvMmUIdRKrMqdLS6 #sequencenumber{fill:#333;}#mermaid-svg-TvMmUIdRKrMqdLS6 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-TvMmUIdRKrMqdLS6 .messageText{fill:#333;stroke:none;}#mermaid-svg-TvMmUIdRKrMqdLS6 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-TvMmUIdRKrMqdLS6 .labelText,#mermaid-svg-TvMmUIdRKrMqdLS6 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-TvMmUIdRKrMqdLS6 .loopText,#mermaid-svg-TvMmUIdRKrMqdLS6 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-TvMmUIdRKrMqdLS6 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-TvMmUIdRKrMqdLS6 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-TvMmUIdRKrMqdLS6 .noteText,#mermaid-svg-TvMmUIdRKrMqdLS6 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-TvMmUIdRKrMqdLS6 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-TvMmUIdRKrMqdLS6 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-TvMmUIdRKrMqdLS6 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-TvMmUIdRKrMqdLS6 .actorPopupMenu{position:absolute;}#mermaid-svg-TvMmUIdRKrMqdLS6 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-TvMmUIdRKrMqdLS6 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-TvMmUIdRKrMqdLS6 .actor-man circle,#mermaid-svg-TvMmUIdRKrMqdLS6 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-TvMmUIdRKrMqdLS6 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}loop[每个表]定时触发枚举数据库表遍历内存数据(dataIteratorBySite)返回内存数据构建JSON对象执行插入操作返回执行结果同步完成
5.2 数据恢复流程
内存缓存SQLite数据库本地缓存系统启动内存缓存SQLite数据库本地缓存系统启动#mermaid-svg-nlUzaoKxyXEy9eRA{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nlUzaoKxyXEy9eRA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nlUzaoKxyXEy9eRA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nlUzaoKxyXEy9eRA .error-icon{fill:#552222;}#mermaid-svg-nlUzaoKxyXEy9eRA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nlUzaoKxyXEy9eRA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nlUzaoKxyXEy9eRA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nlUzaoKxyXEy9eRA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nlUzaoKxyXEy9eRA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nlUzaoKxyXEy9eRA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nlUzaoKxyXEy9eRA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nlUzaoKxyXEy9eRA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nlUzaoKxyXEy9eRA .marker.cross{stroke:#333333;}#mermaid-svg-nlUzaoKxyXEy9eRA svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nlUzaoKxyXEy9eRA p{margin:0;}#mermaid-svg-nlUzaoKxyXEy9eRA .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-nlUzaoKxyXEy9eRA text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-nlUzaoKxyXEy9eRA .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-nlUzaoKxyXEy9eRA .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-nlUzaoKxyXEy9eRA .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-nlUzaoKxyXEy9eRA .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-nlUzaoKxyXEy9eRA #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-nlUzaoKxyXEy9eRA .sequenceNumber{fill:white;}#mermaid-svg-nlUzaoKxyXEy9eRA #sequencenumber{fill:#333;}#mermaid-svg-nlUzaoKxyXEy9eRA #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-nlUzaoKxyXEy9eRA .messageText{fill:#333;stroke:none;}#mermaid-svg-nlUzaoKxyXEy9eRA .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-nlUzaoKxyXEy9eRA .labelText,#mermaid-svg-nlUzaoKxyXEy9eRA .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-nlUzaoKxyXEy9eRA .loopText,#mermaid-svg-nlUzaoKxyXEy9eRA .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-nlUzaoKxyXEy9eRA .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-nlUzaoKxyXEy9eRA .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-nlUzaoKxyXEy9eRA .noteText,#mermaid-svg-nlUzaoKxyXEy9eRA .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-nlUzaoKxyXEy9eRA .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-nlUzaoKxyXEy9eRA .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-nlUzaoKxyXEy9eRA .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-nlUzaoKxyXEy9eRA .actorPopupMenu{position:absolute;}#mermaid-svg-nlUzaoKxyXEy9eRA .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-nlUzaoKxyXEy9eRA .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-nlUzaoKxyXEy9eRA .actor-man circle,#mermaid-svg-nlUzaoKxyXEy9eRA line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-nlUzaoKxyXEy9eRA :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}loop[每个表]初始化本地缓存打开数据库返回数据库连接枚举数据表返回表列表查询表数据返回表数据恢复数据到内存(回调函数)返回恢复结果数据恢复完成
5.3 北向缓存流程
网络通道缓存文件北向缓存转发器网络通道缓存文件北向缓存转发器#mermaid-svg-Pk0zLFhJ35Wgxvdy{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Pk0zLFhJ35Wgxvdy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .error-icon{fill:#552222;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .marker.cross{stroke:#333333;}#mermaid-svg-Pk0zLFhJ35Wgxvdy svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Pk0zLFhJ35Wgxvdy p{margin:0;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Pk0zLFhJ35Wgxvdy text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Pk0zLFhJ35Wgxvdy .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-Pk0zLFhJ35Wgxvdy #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .sequenceNumber{fill:white;}#mermaid-svg-Pk0zLFhJ35Wgxvdy #sequencenumber{fill:#333;}#mermaid-svg-Pk0zLFhJ35Wgxvdy #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .messageText{fill:#333;stroke:none;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .labelText,#mermaid-svg-Pk0zLFhJ35Wgxvdy .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .loopText,#mermaid-svg-Pk0zLFhJ35Wgxvdy .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Pk0zLFhJ35Wgxvdy .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .noteText,#mermaid-svg-Pk0zLFhJ35Wgxvdy .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .actorPopupMenu{position:absolute;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-Pk0zLFhJ35Wgxvdy .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Pk0zLFhJ35Wgxvdy .actor-man circle,#mermaid-svg-Pk0zLFhJ35Wgxvdy line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-Pk0zLFhJ35Wgxvdy :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}alt[网络正常][网络异常]alt[网络恢复]尝试发送数据发送成功发送失败写入本地缓存(addLocalCache)存储到缓存文件(tinySeqFile_push)存储完成缓存成功读取缓存数据返回缓存数据提供缓存数据重新发送数据发送成功删除已发送数据更新缓存文件
5.4 南向缓存流程
事件循环缓存文件南向缓存南向通道事件循环缓存文件南向缓存南向通道#mermaid-svg-shQduCYpFf1LIGka{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-shQduCYpFf1LIGka .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-shQduCYpFf1LIGka .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-shQduCYpFf1LIGka .error-icon{fill:#552222;}#mermaid-svg-shQduCYpFf1LIGka .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-shQduCYpFf1LIGka .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-shQduCYpFf1LIGka .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-shQduCYpFf1LIGka .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-shQduCYpFf1LIGka .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-shQduCYpFf1LIGka .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-shQduCYpFf1LIGka .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-shQduCYpFf1LIGka .marker{fill:#333333;stroke:#333333;}#mermaid-svg-shQduCYpFf1LIGka .marker.cross{stroke:#333333;}#mermaid-svg-shQduCYpFf1LIGka svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-shQduCYpFf1LIGka p{margin:0;}#mermaid-svg-shQduCYpFf1LIGka .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-shQduCYpFf1LIGka text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-shQduCYpFf1LIGka .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-shQduCYpFf1LIGka .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-shQduCYpFf1LIGka .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-shQduCYpFf1LIGka .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-shQduCYpFf1LIGka #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-shQduCYpFf1LIGka .sequenceNumber{fill:white;}#mermaid-svg-shQduCYpFf1LIGka #sequencenumber{fill:#333;}#mermaid-svg-shQduCYpFf1LIGka #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-shQduCYpFf1LIGka .messageText{fill:#333;stroke:none;}#mermaid-svg-shQduCYpFf1LIGka .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-shQduCYpFf1LIGka .labelText,#mermaid-svg-shQduCYpFf1LIGka .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-shQduCYpFf1LIGka .loopText,#mermaid-svg-shQduCYpFf1LIGka .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-shQduCYpFf1LIGka .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-shQduCYpFf1LIGka .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-shQduCYpFf1LIGka .noteText,#mermaid-svg-shQduCYpFf1LIGka .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-shQduCYpFf1LIGka .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-shQduCYpFf1LIGka .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-shQduCYpFf1LIGka .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-shQduCYpFf1LIGka .actorPopupMenu{position:absolute;}#mermaid-svg-shQduCYpFf1LIGka .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-shQduCYpFf1LIGka .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-shQduCYpFf1LIGka .actor-man circle,#mermaid-svg-shQduCYpFf1LIGka line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-shQduCYpFf1LIGka :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}loop[缓存中有数据]通道就绪通知启动读取线程读取缓存数据(locacheSouth__Read)返回缓存数据发送数据就绪事件处理数据同步缓存文件缓存处理完成
6. 技术优势
6.1 分层设计
- 内存缓存层:提供快速的数据访问,满足实时性要求
- 本地缓存层:确保数据持久化,防止数据丢失
- 南北向缓存:为不同方向的数据通道提供专门的缓存支持
6.2 多存储方式
- SQLite数据库:适合结构化数据的存储和查询,用于持久化内存缓存数据
- 顺序文件:适合批量数据的存储和读取,性能更高,用于南北向通道缓存
6.3 灵活配置
- 同步周期:可配置的数据同步周期,平衡实时性和性能
- 缓存大小:可配置的缓存大小限制,避免存储空间过度使用
- 数据管理:支持自动删除废弃的数据表,优化数据库结构
6.4 高可靠性
- 定时同步:定期同步数据,减少数据丢失的风险
- 异常处理:完善的异常处理机制,确保系统稳定运行
- 数据验证:数据同步和恢复时的验证机制,确保数据一致性
6.5 高性能
- 批量操作:采用批量SQL操作,提高数据同步效率
- 异步执行:定时同步在后台执行,不影响主线程性能
- 内存优化:合理的内存使用策略,减少内存占用
7. 代码优化建议
7.1 功能完善
7.2 性能优化
7.3 可靠性提升
7.4 扩展性改进
8. 与其他模块的关系
8.1 与内存缓存模块的关系
本地缓存模块是内存缓存模块的持久化层,两者紧密配合,共同构成系统的数据管理核心:
- 数据流向:内存缓存 → 本地缓存 → 存储介质
- 依赖关系:本地缓存模块依赖内存缓存模块提供数据,通过dataIteratorBySite遍历内存数据
- 协作方式:内存缓存模块负责实时数据管理,本地缓存模块负责数据持久化和恢复
8.2 与插件模块的关系
插件模块通过内存缓存模块间接与本地缓存模块交互:
- 南向插件:采集设备数据 → 写入内存缓存 → 本地缓存持久化
- 北向插件:从内存缓存读取数据 → 转发到云端;当网络异常时,数据通过北向缓存模块写入本地文件
8.3 与触发器模块的关系
触发器模块监控内存缓存中的数据变化,当触发条件满足时执行相应动作:
- 数据来源:触发器模块从内存缓存获取数据,这些数据由本地缓存模块确保持久化
- 触发动作:触发器模块执行的动作可能会修改内存缓存中的数据,这些修改会通过本地缓存模块持久化
8.4 与转发器模块的关系
转发器模块负责将数据转发到云端或其他系统:
- 正常情况:转发器直接从内存缓存读取数据并转发
- 异常情况:当网络异常时,转发器将数据写入北向缓存,待网络恢复后再转发
- 南向通道:当南向通道就绪时,南向缓存模块读取本地缓存数据并发送
9. 总结
本地缓存模块是cNetgate项目中的核心数据持久化组件,通过分层设计和多存储方式,为系统提供了高效、可靠的数据持久化解决方案。该模块不仅确保了数据在系统重启或异常情况下不会丢失,还为南北向数据通道提供了缓存支持,提高了系统的整体可靠性和稳定性。
核心价值
- 数据安全:确保数据在各种情况下不会丢失,提高系统的数据安全性
- 系统可靠:在网络异常等情况下,通过本地缓存确保系统正常运行
- 性能优化:通过合理的缓存策略,优化系统性能,减少网络依赖
- 灵活扩展:模块化设计使得系统易于扩展和维护
技术亮点
- 分层架构:清晰的分层设计,职责明确,易于理解和维护
- 多存储引擎:结合SQLite和顺序文件,兼顾结构化和非结构化数据存储
- 智能同步:定时同步机制,平衡实时性和性能
- 南北向支持:为不同方向的数据通道提供专门的缓存支持
应用前景
随着工业物联网的发展,数据的重要性日益凸显,本地缓存模块作为数据持久化的核心组件,将在以下场景中发挥重要作用:
- 边缘计算:在边缘设备上,本地缓存模块可以减少对云服务的依赖,提高系统响应速度
- 工业现场:在网络环境不稳定的工业现场,本地缓存模块可以确保数据不会因网络波动而丢失
- 大规模部署:在大规模设备部署场景中,本地缓存模块可以减轻云端压力,提高系统整体性能
- 数据安全:对于敏感数据,本地缓存模块可以提供加密存储,增强数据安全性
通过持续的优化和扩展,本地缓存模块将为cNetgate项目提供更加完善的数据持久化解决方案,为工业物联网应用场景提供更加可靠、高效的数据管理能力。




