Skip to content

Neo4j 物理架构

磁盘存储结构

数据文件布局

  • data/databases/:存储数据库文件
    • graph.db/:默认数据库目录
      • neostore:核心元数据文件
      • neostore.nodestore.db:节点数据存储
      • neostore.relationshipstore.db:关系数据存储
      • neostore.propertystore.db:属性数据存储
      • neostore.labeltokenstore.db:标签存储
      • neostore.relationshiptypetokenstore.db:关系类型存储
      • neostore.labelscanstore.db:标签扫描存储
  • data/logs/:存储事务日志
    • debug.log:调试日志
    • neo4j.log:主日志文件
    • query.log:查询日志
    • http.log:HTTP请求日志
    • transaction.log:事务日志

核心数据文件

节点存储文件

  • neostore.nodestore.db:存储节点基本信息
    • 节点ID到属性的映射
    • 节点标签信息
    • 节点关系指针
  • 文件格式:固定大小的记录,每个节点占用固定字节
  • 访问方式:直接寻址,通过节点ID计算偏移量

关系存储文件

  • neostore.relationshipstore.db:存储关系数据
    • 关系ID
    • 起始节点ID
    • 结束节点ID
    • 关系类型ID
    • 关系属性ID
  • 文件格式:固定大小的记录
  • 访问方式:直接寻址,支持双向遍历

属性存储文件

  • neostore.propertystore.db:存储属性数据
    • neostore.propertystore.db.arrays:数组属性
    • neostore.propertystore.db.strings:字符串属性
    • neostore.propertystore.db.index:属性索引
  • 文件格式:可变大小的记录
  • 压缩机制:字符串和数组数据支持压缩

标签存储文件

  • neostore.labeltokenstore.db:存储标签定义
  • neostore.labeltokenstore.db.names:存储标签名称
  • neostore.labelscanstore.db:加速标签查询

内存布局

JVM内存分配

  • 堆内存(Heap):用于Java对象存储
    • 节点和关系对象
    • 查询执行计划
    • 事务状态
  • 堆外内存(Off-Heap):用于直接内存访问
    • 缓存数据
    • 大对象存储
    • 网络缓冲区

缓存层次结构

页面缓存

  • 作用:缓存磁盘数据页
  • 实现:基于内存映射文件(mmap)
  • 大小配置:通过dbms.memory.pagecache.size参数设置
  • 管理策略:LRU(最近最少使用)算法

对象缓存

  • 节点缓存:缓存节点对象
  • 关系缓存:缓存关系对象
  • 属性缓存:缓存属性对象
  • 配置参数dbms.memory.heap.size控制堆内存大小

查询缓存

  • 作用:缓存频繁执行的查询结果
  • 配置参数dbms.query_cache_size设置缓存大小
  • 失效策略:数据修改时自动失效

索引物理结构

原生索引

  • 实现:基于Lucene 5.x
  • 存储位置data/index/目录
  • 索引类型
    • 单属性索引
    • 复合属性索引
    • 全文索引
  • 更新机制:事务提交时异步更新

标签索引

  • 实现:基于Bitset
  • 存储文件neostore.labelscanstore.db
  • 查询性能:O(1)复杂度
  • 适用场景:标签过滤查询

空间索引

  • 实现:基于R树
  • 支持数据类型:点、线、面
  • 查询类型
    • 距离查询
    • 包含查询
    • 相交查询

事务日志机制

WAL日志

  • 存储位置data/databases/graph.db/neostore.transaction.db.*
  • 文件大小:默认100MB,可配置
  • 写入策略:预写式日志,事务提交前先写入日志
  • 日志格式:二进制格式,包含事务操作记录

检查点机制

  • 作用:将内存中的数据刷新到磁盘
  • 触发条件
    • 时间间隔(默认15分钟)
    • 日志大小(默认2GB)
  • 执行过程
    1. 停止写入新的事务日志
    2. 将内存中的数据刷新到磁盘
    3. 更新检查点信息
    4. 开始写入新的事务日志

日志清理

  • 策略:保留最近的日志文件
  • 配置参数dbms.tx_log.rotation.retention_policy
  • 支持的策略
    • 基于时间
    • 基于文件数量
    • 基于大小

存储引擎工作原理

页面管理

  • 页面大小:默认8KB,可配置
  • 页面类型
    • 数据页:存储节点、关系、属性数据
    • 索引页:存储索引数据
    • 元数据页:存储页面管理信息
  • 页面分配:使用空闲列表管理空闲页面

数据压缩

  • 字符串压缩:使用字典编码压缩重复字符串
  • 数组压缩:使用特殊编码压缩数组数据
  • 页面压缩:可选的页面级压缩

批量加载

  • 工具neo4j-admin import
  • 特点:绕过事务日志,直接写入数据文件
  • 适用场景:初始数据导入
  • 性能:支持每秒数百万条记录的导入速度

集群存储架构

因果集群存储

  • 核心节点:存储完整数据副本,处理写操作
    • 每个核心节点维护独立的数据文件
    • 事务通过Raft协议复制到所有核心节点
  • 只读副本:存储数据副本,处理读操作
    • 从核心节点复制数据
    • 不参与写操作确认

HA集群存储

  • 主节点:处理写操作,维护最新数据
  • 从节点:从主节点复制数据,处理读操作
  • 复制方式:基于事务日志的异步复制
  • 故障切换:主节点故障时自动选举新主节点

IO 优化策略

顺序写入

  • 事务日志:顺序写入,提高IO效率
  • 数据文件:批量写入,减少随机IO
  • 检查点:批量刷新,减少磁盘抖动

随机读优化

  • 页面缓存:缓存热点数据,减少磁盘IO
  • 预读取:根据访问模式预读取数据
  • 索引优化:使用索引减少全表扫描

存储硬件建议

  • SSD:推荐使用SSD存储,提高随机IO性能
  • RAID:使用RAID 10保证数据冗余和性能
  • 存储控制器:使用高性能存储控制器
  • 文件系统:推荐使用ext4、XFS或NTFS

版本差异

Neo4j 4.x 存储改进

  • 多数据库支持:每个数据库有独立的存储目录
  • 改进的事务日志:更高效的日志格式
  • 增强的索引:更快的索引创建和查询
  • 优化的页面缓存:更好的内存利用率

Neo4j 5.x 存储改进

  • 并行数据加载:支持并行导入数据
  • 改进的压缩算法:更高的压缩率
  • 优化的存储布局:减少磁盘空间占用
  • 增强的检查点机制:更快的故障恢复

常见问题(FAQ)

Q1: Neo4j的数据文件可以直接复制吗?

A1: 不建议直接复制运行中的Neo4j数据文件,可能导致数据损坏。应该使用neo4j-admin backup命令进行备份,或者在数据库关闭时复制数据文件。

Q2: 如何监控Neo4j的磁盘使用情况?

A2: 可以通过以下方式监控磁盘使用:

  • 使用du -sh data/命令查看数据目录大小
  • 通过Neo4j监控API获取磁盘使用指标
  • 使用Prometheus+Grafana监控磁盘使用率

Q3: Neo4j的事务日志会无限增长吗?

A3: 不会,Neo4j会自动清理旧的事务日志。可以通过dbms.tx_log.rotation.retention_policy参数配置保留策略,例如100M size表示保留最近100MB的日志。

Q4: 如何优化Neo4j的存储性能?

A4: 优化存储性能的方法包括:

  • 使用SSD存储
  • 适当配置页面缓存大小
  • 合理设置检查点间隔
  • 优化数据模型,减少不必要的属性
  • 使用批量导入工具导入大量数据

Q5: Neo4j支持哪些文件系统?

A5: Neo4j支持多种文件系统,包括:

  • Linux:ext4、XFS、Btrfs
  • Windows:NTFS
  • macOS:HFS+、APFS
  • 推荐使用ext4或XFS,具有更好的性能和稳定性

Q6: 如何迁移Neo4j的数据文件?

A6: 迁移数据文件的步骤:

  1. 关闭Neo4j服务
  2. 复制整个data目录到新位置
  3. 修改neo4j.conf中的dbms.directories.data参数
  4. 启动Neo4j服务

Q7: Neo4j的页面缓存大小如何配置?

A7: 页面缓存大小通过dbms.memory.pagecache.size参数配置,建议设置为系统可用内存的50%-70%,剩余内存留给JVM堆和操作系统。

Q8: 如何清理Neo4j的旧日志文件?

A8: 可以通过以下方式清理旧日志:

  • 使用neo4j-admin logs prune命令
  • 配置日志滚动策略
  • 定期手动清理旧日志文件
  • 使用日志管理工具自动清理