引言

中国地震前兆观测台网经过“九五”、“十五”和“背景场”等项目建设,已经完成从模拟观测向数字化、网络化观测的转变,成为具备较大规模的前兆观测台网。国家地震前兆台网中心(以下简称国家中心)作为前兆台网的国家级中心,承担全国数据汇集、管理和共享服务职能。国家中心前兆数据库汇集全国前兆台网产出的所有观测数据、预处理数据和产品数据,提供给地震预测预报、地球科学研究人员使用。截至2017年底,国家中心前兆数据库汇集了约810个台站、3400套观测仪器的数据,占用存储空间达7.6TB。

国家中心主要通过2种方式提供前兆数据服务:

(1)直接连接数据库:主要针对中国地震台网中心内部的预报人员使用分析预报软件连接到国家中心前兆数据库进行数据浏览、绘图和分析。

(2)访问国家前兆台网中心网站:服务内容包括数据查询、在线绘图和数据下载。这种方式主要对地震系统其他单位的用户和非地震行业用户提供前兆数据服务。

目前,前兆数据库账户管理缺少相应的限制手段,多个用户可以使用相同的公共账号直接访问数据库;公共账号的密码难以修改,导致账户私下传播;很多软件随意连接国家中心前兆数据库,个别软件甚至同时打开几十、上百个连接,占用数据库资源,严重影响数据库性能。

Oracle数据库管理系统只能对当前连接的用户活动进行查询,不能进行细粒度控制,不能提供用户使用数据的情况统计,数据库审计功能也较弱(Shaul等,2009)。虽然Oracle有额外的审计软件包,但是价格昂贵,只支持事后审计分析,不具备实时控制用户行为的功能。为此,国家中心采用目前信息技术领域流行的数据服务架构,开发了地震前兆数据库系统共享接口软件,该接口软件可以实现细粒度的用户访问审计与控制,从而提高数据库的安全性,同时采取数据压缩、缓存等技术来提升访问性能。

1 共享接口设计
1.1 技术思路及总体设计

为了解决前兆数据库可随意直连的问题,考虑在客户端应用系统和数据库之间增加1层接口软件,实现数据库与应用的解耦。该软件须满足:①访问速度快。目前,前兆数据应用的瓶颈在于数据访问的速度,增加接口软件层会带来访问速度上的损失,需要通过技术手段来降低对速度的影响。②软件易于安装和使用,支持不同类型的编程语言。目前访问前兆数据需要安装庞大的Oracle客户端。③软件具有一定的透明性,用户不需要知道数据库的表结构等细节就可以方便地获取想要的数据。④持续稳定地运行,否则对数据的应用会造成不良影响。

为此,我们设计了2个方案:

(1)在接口软件中进行TNS(Oracle客户端与服务端使用的通信协议)数据的透明传输,任何标准的Oracle客户端都可以把接口软件当作Oracle服务器进行通信(权元文,2011殷泰晖等,2012)。然而,该方案存在若干问题,如:TNS协议没有开源,需要花费大量时间进行反向研究;为达到对数据使用情况的统计与审计的目的,要解析应用软件发出的SQL语句的语义;TNS不支持数据的压缩。总体来说,该方案的开发难度大、周期长。

(2)抛弃Oracle客户端,接口软件和应用软件使用其它通信协议来进行数据传输。只有对开源的服务器软件进行定制开发后,流行的标准协议(如HTTP、FTP)才能用于前兆数据的传输。对于单一的数据传输目的,可以使用类似FTP的自定义协议。这个方案的优点是工作量较少,对客户端来说更透明;缺点是现有基于Oracle客户端的应用软件需要改造,使用新的协议读取数据。

国家中心的主要业务是软件、硬件系统的运行维护,没有足够的时间与人力资源研究TNS协议与SQL语句解析,综合各方面的因素,本文最终使用第2个方案开发共享接口软件。

1.2 技术架构

地震前兆数据共享接口软件主要使用Java、Socket(网络套接字)、JDBC(Java数据库编程接口)、MessagePack等平台与技术,接口的技术架构示意图如图 1所示。


图 1 地震前兆数据交换接口示意 Fig. 1 Illustration of precursor data exchange interface

(1)Java:一种跨平台解释型语言,适于开发网络通信程序,其开发资源丰富,效率高,运行速度较快(Eckel,2007)。Java使用内存垃圾回收机制,无需程序员管理内存,且运行占用内存较多的缺点可通过提高计算机配置避免。

(2)Socket:出于性能考虑,地震前兆数据交换接口不使用流行的J2EE、Web Service等需要在容器(如tomcat)内运行、消耗较多系统资源的框架,而直接使用TCP协议的Socket方式(Calvert等,2009),仿照FTP协议,实现由客户端发出命令、服务器应答的工作模式(图 2)。


图 2 地震前兆数据交换接口工作流程 Fig. 2 The work flow of precursor data exchange

(3)JDBC:接口软件未使用Hibernate等数据库对象持久化方案,而是直接使用JDBC操作数据库。地震前兆数据库的表数量超过1000,如果使用Hibernate将产生同样数量的实体类,在数据库增加新表时也要添加新的类代码。接口软件借鉴Hibernate的连接池技术,使用CP30实现数据库连接的重复使用及最大连接数限制。实践证明,使用连接池可避免反复打开、关闭数据库连接,在频繁访问数据库时有效提升访问性能。

(4)MessagePack:地震前兆数据是基于Oracle 10g的结构化数据,网络传输时需要转化为数据流,客户端再将数据流转换回结构化数据,MessagePack能完成数据的打包和解包。MessagePack是1个二进制对象序列化开源库,比JSON运行速度快,支持Java、C#、C++、Python等语言。Java版本的MessagePack主要包括2个类:MessagePacker和MessageUnpacker。

2 共享接口实现
2.1 软件工作流程

接口软件以服务器模式在3000端口进行侦听,等待客户端连接,采用交互式命令提供服务。目前,服务器可以接受的命令有:登录、获取基础信息、获取观测数据、获取被授权的台项信息等。接口软件工作流程见图 2

2.2 用户类型及访问控制

按照数据权限将接口软件的用户类型划分为预报用户、备份用户等。预报用户拥有最高数据权限,享有与直连数据库相同权限,其他用户可以设置为只能获取指定时间或学科的前兆数据。

为增强接口软件的安全性,防止冒用接口账号登陆下载数据,管理员可以根据需要设置客户端的IP地址,服务端会对连接的IP进行检验,拒绝非授权的访问。

2.3 接口命令格式及功能

(1)用户登录

命令格式为:Auth用户名口令。

客户端连接到服务器的3000端口后,发送登录命令,服务器端查询该用户名、口令及IP地址是否与数据库中的一致,返回登录成功或失败的信息到客户端。

(2)观测数据获取

命令1格式:GetDataByDate台站代码测点编码测项分量代码日期数据表名。

命令2格式:GetDataByIndex数据表名DateIndex列值。

获取观测数据的命令有2条,命令1用于获取指定台站的观测仪器某个测项分量某天数据,命令2用于获取数据表中DateIndex列大于某个指定值的数据,用于增量数据拉取。2条命令也可以用于获取观测日志。

命令的返回结果为MessagePack封装的数据流,数据以键值配对形式存储,类似JDBC的ResultSet类。服务器收到GetDataByDate命令后的处理流程见图 3,GetDataByIndex命令的处理流程与之类似。


图 3 GetDataByDate命令服务器处理流程 Fig. 3 Processing flow of the response of server to GetDataByDate command

将结果集记录用MessagePacker打包时,通过JDBC ResultSet的getMetaData方法来获得列名和列的类型等信息,对字符串和二进制类型使用不同打包方法,主要代码如下:

ResultSetMetaData rsm = rs.getMetaData();             //获得结果集元数据

     int colNum = rsm.getColumnCount();             //获得列数

     String str;

     for (int i = 1; i<= colNum; i++) {

        if (rsm.getColumnType(i) == Types.BLOB) {      //列数据为二进制

           oracle.sql.BLOB srcBlob = (oracle.sql.BLOB) rs.getBlob(i);

           if (srcBlob!= null && srcBlob.length() > 0) {

              InputStream srcIs = srcBlob.getBinaryStream();

              byte[] srcBuffer = new byte[(int) srcBlob.length()];

              int srcLen = srcIs.read(srcBuffer); //读取数据库中的二进制数据

              srcIs.close();

              packer.packBinaryHeader(srcLen);        //设置二进制包头

              packer.writePayload(srcBuffer);        //打包二进制数据

                 packer.packString(rsm.getColumnName(i));    //打包列名

              }

           } else {                 //非二进制数据都按字符串类型处理

              str = rs.getString(i);

              if (str!= null) {                              //忽略空值列

                 packer.packString(rsm.getColumnName(i));    //打包列名

                 packer.packString(rs.getString(i));        //打包列数据

              }

           }

        }

        packer.packNil(); //一行结束用nil(空)分隔

(3)基础信息获取

命令格式:GetBaseInfo基础信息表名。

基础信息表主要包括台站表(qz_dict_stations)、仪器类型表(qz_dict_instruments)、台站仪器表(qz_dict_stationinstruments)、台站测项分量表(qz_dict_stationitems)(周克昌等,2010)。基础信息表无增量更新机制,每次读取整张表的数据。服务器端处理流程与GetDataByDate命令类似。

(4)授权的台项信息获取

命令格式:GetAuthorizedStationItems。

该命令无参数。服务端返回所有向国家中心报数的在运行仪器的所有测项分量列表,列表的每1行对应1个测项分量的信息,包括台站代码、台站名称、测点编码、测项分量代码、测项分量名称、仪器名称、仪器型号、所属学科等信息。服务器端处理流程与GetDataByDate命令类似。

2.4 数据的缓存

接口软件对数据进行打包与转发的过程增加了时间开销,必然会降低客户端读取数据的速度。接口软件内置数据缓存功能,在内存中构造缓存区,以数据库中的行(对应1个测项分量1天的数据)为基本单元进行缓存,客户端读取数据时先按照主键到缓存中查找数据,如果缓存命中则直接返回数据而不必到数据库中查询,从而提高读取速度。缓存功能的主要技术特点如下:

(1)多线程访问控制。使用锁机制防止多线程并发访问时读写冲突造成数据损坏。

(2)缓存使用的内存空间达到设置的上限时,使用LRU算法(Tanenbaum等,2010)对缓存中的数据进行置换,将最近未使用的数据移出缓存。

(3)缓存数据的同步。前兆数据库的数据发生变化后,后台线程定时按照缓存中的主键查询数据库中对应行的DateIndex值,以此判断缓存中的数据是否需要更新。

2.5 客户端软件

客户端软件使用Socket连接到服务器端的3000端口,打开输入输出流发送和接收数据。除登录命令外,其他命令的返回数据均为服务器端用MessagePacker打包的数据流,必须用MessageUnpacker将其解包为结构化数据。客户端解包数据流的函数返回一个Map对象,遍历Map得到的主键和值即为某行的列名和数据。客户端与接口软件交互的流程见图 4


图 4 客户端取数流程 Fig. 4 The workflow of getting data by clients
2.6 接口运行和数据监控

接口软件可监控用户下载数据的情况,每天自动生成数据共享监控日报,发送到相关人员的邮箱。监控日报包括Word和Excel文件,其中Word文件内容为数据共享服务的总体情况,Excel文件内容为当天所有测项分量的原始和预处理数据推送和拉取情况。接口软件使用Java TimerTask类来定时生成监控日报,用apache的poi库操作Word和Excel文件。图 5为软件检查数据推送和拉取情况的流程。软件将所需数据一次读入内存中进行查找,避免频繁查询数据库,检查速度得到大幅提升。


图 5 测项分量数据推送及拉取检查 Fig. 5 The check for data push and pull
2.7 接口软件的关键技术

地震前兆数据库系统共享接口软件主要使用了以下关键技术:

(1)表结构的自适应。前兆数据库有1000多张表,观测数据表的结构相似,均值产品表和基础信息表结构都不相同,某些基础信息表含有BLOB字段。开发接口软件时必须考虑到表的字段和类型的不同。通过读取表的相关元数据,获得字段的名称和类型等信息,对不同的表结构使用相同的处理,而不是对具体的字段名和类型编程,从而实现表结构的自适应。

(2)接口传输速度的提升。接口软件通过使用连接池、数据缓存、数据压缩等技术减少或避免数据转发带来的性能损失。大部分前兆数据精度非常高,数据变化的位数少,可以达到很高的压缩率(约为原体积的$ {}^{1}\!\!\diagup\!\!{}_{10}\;-{}^{1}\!\!\diagup\!\!{}_{8}\;$)。网速较慢时压缩数据能够大幅减少网络传输时间。

(3)接口软件用多线程模型响应客户端请求,增强了软件的稳定性。当某个客户端出错造成异常时,不会影响到其它客户端。经过实际测试,接口软件持续运行半年没有出现异常退出的情况。

3 接口软件的测试

以河北昌黎后土桥的磁通门仪器变化记录水平分量的1年秒钟值数据(数据量大约240MB)为例,对接口软件的功能与性能进行了测试,结果见表 1。可以推测,当接口软件的缓存命中率达到50%时,访问速度与使用JDBC直连数据库相当。

表 1 接口测试结果 Table 1 Test result for interface software
4 结语

开发共享接口软件的目的是提供前兆数据的只读访问,同时进行审计与控制。接口软件主要面向2类用户:数据同步用户和分析预报用户。数据同步用户一般为远程用户,拥有自己的前兆数据库,使用接口来获取增量数据,这类用户适合用压缩方式传输数据。截至2017年11月,中国地震局第二监测中心等用户通过本接口,获取了804个地震台站2815套观测仪器约800GB的前兆数据。分析预报用户在局域网内使用数据,数据缓存可以减弱或消除接口层的数据转发带来的速度影响。为慎重起见,在经过更严格的测试之前,还不能将接口软件推广到分析预报用户。

接口软件对用户的访问行为进行测项分量级别的细粒度记录,通过对这些访问日志进行分析,可以统计数据使用情况,也可以获得用户感兴趣的热点数据等,为今后数据库系统优化和数据服务提供依据。

下一步,将根据用户反馈和接口运行情况,对软件进行完善,包括增加用户常用的访问类型、增强接口的友好性等。此外,还可以使用更经济的硬件资源(比如低端服务器甚至PC机)来构建分布式缓存系统,同时优化缓存的置换算法,提高缓存命中率,进一步提升接口的数据传输速度。

参考文献
Calvert K. L., Donahoo M. J., 2009. Java TCP/IP Socket编程.周恒民, 译.北京: 机械工业出版社, 28-29.
Eckel B., 2007.Java编程思想.陈昊鹏, 译.北京: 机械工业出版社, 45-47.
权元文, 2011. 基于TNS的Oracle数据库安全增强系统设计与实现[J]. 电脑编程技巧与维护, (20): 142-144, 171. DOI:10.3969/j.issn.1006-4052.2011.20.062
Shaul J., Ingram A., 2009.Oracle安全实践.李桢, 译.北京: 科学出版社, 5-6.
Tanenbaum A. S., Bo H., 2017.现代操作系统.4版.陈向群, 马洪兵, 译.北京: 机械工业出版社, 240-245.
殷泰晖, 李帅, 2012. 基于TNS协议的Oracle数据库安全性改进方法[J]. 合肥工业大学学报(自然科学版), 35(2): 193-196. DOI:10.3969/j.issn.1003-5060.2012.02.013
周克昌, 蒋春花, 纪寿文, 等, 2010. 地震前兆数据库系统设计[J]. 地震, 30(2): 143-151. DOI:10.3969/j.issn.1000-3274.2010.02.016