【DIY】基于共享内存的数据库映射

基于共享内存的数据库映射

概述

随着各类行业软件对性能追求越来越高,因此对数据库处理的速度提出了新的挑战。然而大部分复杂的业务处理往往依赖体量较大的关系数据(如:Oracle,Mysql,PostgresSQL等),虽然这些关系数据库的功能已经足够的强大,但这些数据库的性能方面在某些场合又未必能满足我们的要求。因此,一些NOSQL的数据库(如:Redis、MongoDB、LevelDB等)逐渐占领了一部分市场。同时内存数据库(如:Sqlite、Oracle TimesTen、eXtremeDB等)也被广泛的使用。

本文主要讨论,将关系数据库中的数据映射至(共享)内存,然后在内存中对其进行操作。使用共享内存方式和OCI/OCCI接口对ORACLE数据库的表或视图进行内存映射,当然也不局限于ORACLE数据库,理论上是可适用大部分关系数据库,甚至结构化的文件(CSV,XML,JSON等)。同时,共享内存的使用为多进程共享业务数据提供了基础。

共享内存

提到共享内存就要先说说Linux进程间通信(IPC:InterProcess Communication)

,linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的。进程通信的目的主要是,传输数据、资源共享、进程控制等。常用的进程间通信手段包括:管道、信号、消息队列、共享内存、信号量、套接字(SOCKET)等。

共享内存是在多个正在运行的进程之间传递数据的一种非常有效的方式。共享内存的具体实现是不同进程共享的内存分配同一段物理地址,如下图:

如图所示,进程1的逻辑地址空间和进程2的逻辑地址空间映射到同一块物理内存,从而实现该内存上数据的共享或数据传递。

相关函数:

int shmget(key_t ey,size_t size, int shmflg);

创建共享内存

void *shmat(int shm_id, const oid *shm_addr, int shmflg);

将共享内存连接到进程

int shmdt(const void *shmaddr)

断开共享内存连接

int shmctl(int shmid, int cmd, struct shmid_ds *buf)

共享内存管理

1.2 OCI/OCCI

Oracle 调用接口 (OCI) 是最全面、性能最高、基于原生“C”语言的 Oracle 数据库接口,它可以提供 Oracle 数据库的全部功能。OCI 为构建各种语言专用接口(如 Oracle JDBC-OCI、http://ODP.Net、Oracle 预编译器、Oracle ODBC 和 Oracle C++ Call Interface (OCCI)驱动程序)提供了基础。

OCCI是基于OCI的Oracle数据库的C++接口,是对OCI的进一步封装,简化了接口调用,提供了更加优化的用户适用体验。

出于性能和稳定性的考虑,该工程将以OCI作为接口的技术选型。

系统模型

整体模型

根据功能与依赖关系将系统模型分为四个层次,分别为:持久化成、内存数据层、逻辑层、应用层。并且上层对下层具有依赖关系,每一层通过接口进行解耦,如下图所示:

持久化层

持久化层作为永久存储数据媒介,同时也是内存数据映射的来源。

持久化形式可以是关系数据库,K-V数据库或格式化文件。该层对外提供两个主要的接口,LoadData()和WriteBack(),类结构如下图:

为上一层“内存数据层”提供数据接口。

内存数据层

该层使用共享内存方式提供数据,可为多个进程通过数据共享,内存结构包括:

  1. 共享内存头,存储共享内存的基本信息,如:共享内存名、IPCKEY、内存块大小、创建时间,以及进程块和表信息块的首地址偏移量。该区域是共享内存数据使用的入口,可以方便的得到进程信息的偏移量,表信息的偏移量。
  2. 进程信息,当进程链接(attach)到共享内存区域时,会将该进程的信息写入进程信息区。写入信息包括:
  1. 进程组号:标识进程所属的组,比如,管理进程/业务进程/监控进程/回写进程。
  2. 进程ID:进程的逻辑编号非系统PID,是进程在进程组内的唯一标识。
  3. 进程启动时间:进程启动并链接到共享内存的时间。
  4. 进程状态:进程当前的状态,比如,运行/停止等。
  1. 表信息,是对关系数据库或结构化文件数据的二维抽象即“表”,由Load进程将持久化层的数据信息和数据内容加载到共享内存中。数据“表”信息包括:表名、文件名(内存映射文件)、最大记录条数、单条记录大小、只读标志、告警百分比、回写标志、数据首地址等信息。
  2. 数据域,存放表数据的内存段,当Load进程向共享内存加载数据时,根据单条记录的大小和记录最大条数等信息,计算出表数据的偏移量,并根据偏移量得到表数据的存储首地址,将数据依次存入表数据区。该区域为上一层“逻辑层”提供数据访问。

内存数据层关键数据接口如下:

对上层提供主要接口为IDataManager,这里只实现了CShmManager,即基于共享内存的数据存储,当然也可以实现普通内存的实例。

逻辑层

逻辑层的主要目的是为应用层提供方便灵活的数据操作接口,该层提供了各种数据操作的封装,可以是基于sql的标准查询语言,也可以是基于容器的操作,从而实现内存数据的增、删、改、查等操作。

如下图:

  1. CDAO为逻辑层提供的入口。
  2. CDML是接口类,提供了数组操作的基本接口。
  3. CIndex,对表操作的索引封装。
  4. CKey,索引键值封装。
  5. CSqlTools,sql操作的封装,支持标准sql进行数据操作。
  6. CSqlBase,标准sql封装,使用flex/bison进行语法解析和此法解析,为CSqlTools提供基本操作。
  7. ContainerTools,基于容器的K-V数据操作。
  8. CShareMemory,指向共享数据层的共享内存数据封装。

2.5应用层

应用层为用户提供API,应用进程通过API可以实现共享数据操作接口。比如实现业务的业务进程、监控进程、管理进程等。

API入口CFrameWork,提供InitFrameWork(),Connect(),DisConnect()等接口。

3总结

上文描述了将数据库或结构化文件的数据映射至(共享)内存的数据模型,由于篇幅原因精简了实际工程的数据结构。整体模型由低到高分为四个层级,简述了数据加载至(共享)内存,通过内存数据建立内存数据库(实现增、删、改、查功能),提供应用层API接口,建立应用进程,最终共享内存数据的过程。

发布了27 篇原创文章 · 获赞 6 · 访问量 3681

猜你喜欢

转载自blog.csdn.net/xk_xx/article/details/104189139
今日推荐