HSQLDB使用HA-JDBC集群分析
现对hsql数据库集群进行测试,分析其集群的可用性、可靠性、可运维性以及性能等方面。
1. 对hsql数据库分别进行内嵌模式、服务模式,与结合HA-JDBC集群进行测试,分析其的可用性、可靠性、可运维性以及性能等方面。
HSQLDB (HyperSQLDataBase) 是用JAVA编写的关系型数据库。它提供一个小而快速,支持多线程与事务的引擎,具有内存和硬盘存储表方式,支持embedded模式和server模式。它集成包括强大的命令行工具SQL Tool和简单的GUI管理工具等。
• 其源码基于深入研究数据库理论和SQL标准
• 对SQL特征的支持领先于其他开源软件
• 三种事务控制模型,包括基于锁和MVCC模型
• 完全支持多线程
• 支持内存数据表操作方式和大数据存储硬盘方式
• 支持与外部文件中的数据源,如CSV文件中的文本表格可以作为SQL表方式
• 单个LOB大小没有内存限制支持CLOB和BLOB存储可达64TB
• 磁盘表(缓存的表)高达8TB和text表达256GB每
• 每个字符串或二进制项目的大小仅受内存限制
• 支持快速启动和关闭以及内部增量备份功能
• 在线和离线备份功能
• 支持数据库脚本转存
一个 HyperSQL 数据库被称为一个编目。按照数据存储方式的不同分为 3 种不同类型的编目。
• mem: 将所有的实体存储在 RAM 中,其生存周期与 JVM 相同,当 JVM被关闭后数据库实例将被关闭而销毁。
• file: 存储在文件系统中。
• res: 存储在 Java 的资源文件中,例如一个 jar包。这种类型的永远是只读的。
mem: 类型,数据在内存中保留,可以被用于测试或者一个应用的复杂缓存,这种类型的数据库是不产生任何存储文件的。
file: 文件类型,通常保留有 2 到 5 个文件,这些文件具有相同的名字,但是扩展名
不相同。这些文件也被保留在同一个文件目录中。
例如,数据库被命名为 “test”,那么在文件方式中将会有下面的一些文件存在:
• test.properties
• test.script
• test.log
• test.data
• test.backup
• test.lobs
properties:属性文件中,保留了一些与数据库有关的配置。
script:脚本文件包含和定义了表格和其他的一些数据库对象,同时也包含没有缓存的表格数据。
log:日志文件保存了数据库进行的修改记录。
data:数据文件包含了缓存过的表格和一个数据文件最后状态的压缩备份文件。在一个 HyperSQL 数据库中中,所有的这些文件都是必须的,任何时候都不能被删除。
在一些目录中,可能没有 test.data 和 test.backup 文件。
对于其他的一些文件 HyperSQL 数据库有可能将实例连接到其他格式化过的文件文本文件,例如 CSV 列表。
在磁盘上 "test" 编码被打开并开始使用后,一个test.log file 文件用于记录数据库所做的修改。这个文件可以被在数据库被正常关闭后删除。否则,这个文件用于在一次非正常关闭后用于回滚数据库的改变。
test.lck 文件用于记录数据库的打开状态,这个文件将会在数据库实例被正常关闭的时候删除。注:test.lck 文件用于记录数据库的打开状态,这个文件将会在数据库实例被正常关闭的时候删除。
在一些非正常的数据库关闭,文件 test.data.old 将会被创建而随后被删除。这些文件不应该被用户手工删除的,而应该由数据库实例自行删除。如果这些文件存在,那么在数据库引擎的下一次启动时将会被数据库引擎自行删除。
res: 编目是存储的一个小型和只读类型的数据库。
通常来说 JDBC 可以访问所有的数据库。JDBC 通常只用于连接数据库,当 JDBC 完成数据库连接后,将会使用java.sql.Connection 对象提供的一系列方法来返回访问的数据。访问HyperSQL 使用的是 JDBC,但是针对数据库特性的不同而采用不同的连接字符串。例如:如果数据库为 file:database 类型,数据被命名为 "testdb"。同时这个数据库文件与你发布的应用程序在相同的目录下,你可以使用下面的代码来创建一个数据库连接:
Connection c =DriverManager.getConnection("jdbc:hsqldb:file:testdb","SA", "");
数据库文件的路径格式可以在 Windows 和 Linux 下 用反斜杠来指定。因此在相同磁盘路径下相对路径和绝对路径便可以用上面的方法进行识别。例如,如果你的数据库路径在 Linux 下为 /opt/db/testdb,同时你在Windows的 C 盘下创建了相同的目录结构,你可以在 Windows 和 Linux 下使用相同的连接字符串如下:
Connection c =DriverManager.getConnection("jdbc:hsqldb:file:/opt/db/testdb","SA", "");
当使用相对路径的时候,这个路径指向为相对但却 JVM 运行时的路径。请参考JDBCConnection的API 文档来获得更多的内容。路径名与数据库文件名在数据库和连接被第一次被创建的时候按照大小写敏感的方式命名的。但是,如果在随后使用其他连接来连接一个已经打开的数据库的时候,如果你使用了全部大写的连接字符串,那么你也会连到已经打开的这个数据库。换句话说,第二次的连接和第一次的连接是等效的。这种考虑方式是很有必要的,因为 Windows 在路径上是大小写不敏感的。
mem: 数据库,会用关键字 mem: 来进行定义的。对于 mem: 数据库而言,其路径仅仅是其名字。一些 mem: 数据库可以与其名字同时显式存在。在下面的例子中,数据库被称为 "mymemdb":
Connection c =DriverManager.getConnection("jdbc:hsqldb:mem:mymemdb","SA", "");
res: 数据库采用 res: 关键字。这个方式的数据库为一个 Java 的资源文件,数据库的路径为 Java 路径 (与 class 的路径一样)。在下面的例子中,"resdb" 是数据库文件的在 class 目录 "org/ my/path"下的根节点。一个 Java 资源存储的是一个压缩格式,当其在调用的时候,将会在内存中解压。因为这个原因 res: 数据库不能存储大量数据同时永远是只读的。
Connection c =DriverManager.getConnection("jdbc:hsqldb:res:org.my.path.resdb","SA", "");
在第一次进行数据库访问的时候,将会创建一个数据库,一些基本数据结构将会被初始化,一些辅助线程也会被启动。当这些完成以后,一些 Java 应用程序将会用 JDBC 进行连接的调用。当 SQL 命令 "SHUTDOWN" 被执行,全局数据结构和辅助线程将会被销毁。注:只有一个 Java 进程可以访问数据库 file: 。如果 file: 数据库为只读类型的数据库,或者创建的是一个 res: 数据库,有可能从 Java 进程中创建多个连接。
相对于很多应用程序而言,内存模式更快,但是数据不能被转换,也不能通过网络进行连接。最主要的麻烦是不能从你的应用程序外连接数据库。这样的话,你不能从应用程序外检查你的数据,你也不能用其他的第三方数据库工具在你的应用程序正在运行的时候来查看你的数据。
服务器模式能提供最大的可用性。当数据库引擎在 Java 虚拟机中运行的时候,你可以打开一个或者多个数据库编目。它侦听来自网络上的同一台计算机或其他计算机上的程序的连接,它将会转换这些连接成为in-process数据库连接。
不同的程序可以连接到服务器和检索或更新的信息。客户端工具和程序使用 HyperSQL JDBC 驱动来连接数据库服务器。在大多数的服务器模式中,数据库服务器可以在服务器运行期间处理无限数量的数据库,或者处理数据库连接请求。
服务器模式也很适合在开发的时候运行。这个模式将运行你在你的应用程序运行的时候通过第三方工具查询数据库中的数据。
HSQLDB 提供三种服务器的运行模式,基于在客户端和服务器之间使用的协议不同而定义。下面章节进行了简要的讨论,更多详细内容将会在 HyperSQL 网络监听器章节进行讨论。
这种方式能够提供最快的数据库访问。HSQL 也优先建议使用这个协议来进行数据库的访问。运行数据库的监听器的命令与前面讨论的运行数据库访问客户端的命令类似。下面的命令格式描述了如何启动一个名为 "mydb.*" 的数据库,数据库的公开名为"xdb"。公开名称对用户隐藏了文件名。
java -cp ../lib/hsqldb.jar org.hsqldb.server.Server--database.0 file:mydb --dbname.0 xdb
命令参数 --help 被用于将所有参数的列表显示出来。
这个方法将会让数据库服务器通过 HTTP 服务器的方式来提供数据库服务。使用这种方式的主要原因是基本的客户端/服务器模式可能应为反获取的作用而拒绝访问,你可以通过这种方式来绕过防火墙。Hyper HTTP Server 是一种特殊的 Web 服务,它运行 JDBC 客户端通过 HTTP 协议进行访问。这个服务模式同时也可以作为一个通用的小的静态页面 Web 服务器。为了运行 HTTP 服务器,将下面命令行中的 main 类替换掉就可以了:
org.hsqldb.server.WebServer
命令参数 --help 被用于将所有参数的列表显示出来。
这种方法的访问同样也是使用 HTTP 协议。这种方法的服务将会使用一个不同的 servlet 引擎 (或一个应用服务)。例如,Tomcat 或 Resin 来提供数据库服务。
Servlet 模式不能从 servlet 模式中独立启动。HSQLDB 中的 servlet 类应该被安装到一个应用服务器上来提供连接服务。数据库将会作为应用服务器的一个独立启动项。你可以通过参考程序代码 src/org/ hsqldb/server/Servlet.java 来获得更多,更详细的内容。HTTP Server 和 Servlet 模式仅仅可以通过 JDBC 客户端使用。这两种方式不能提供 Web 前台方式来访问数据库访问。
请注意,如果你只可在你的应用程序中使用数据库引擎。在这种情况下,连接到一个数据库类型,你可以使用内存模式的数据库或者使用独立服务器。
H2数据库提供了一组命令行工具,如果你需要了解这些工具,使用参数-?,如:
java -cp h2*.jarorg.h2.tools.Backup -?
命令行工具有:
• Backup创建数据库备份
• ChangeFileEncryption 允许改变文件加密密码和数据库的加密算法
• Console 启动基于浏览器的H2控制台
• ConvertTraceFile转换 .trace.db 文件到JAVA应用和SQL脚本
• CreateCluster从一个独立的数据库服务创建集群
• DeleteDbFiles 删除所有的数据库文件
• Recover恢复损坏的数据库
• Restore从数据库备份中恢复数据库
• RunScript 运行数据库SQL脚本
• Script 为数据库备份或迁移导出SQL脚本
• Server 启动H2服务模式
• Shell命令行工具
这些工具也能在程序中通过调用相应的方法来使用,相关详细的调用说明,请参考JavaDoc文档http://www.h2database.com/html/tutorial.html#command_line_tools。
一个运行中数据库的并发控制模型可以被改变。通过拥有DBA角色的用户可以使用此语句进行修改:
SET DATABASE TRANSACTION CONTROL { LOCKS | MVLOCKS |MVCC }
HyperSQL 2已经完全重新设计,以支持不同的事务隔离模式。
在MVCC模型,没有共享锁,读锁。独占锁被用来在单独的行,但它们的使用是不同的。一个事务同时读取并修改同一个表时,通常不需要等待其他事务。
SQL标准的隔离级别被用户的应用程序使用,但这些隔离级别都将转换为MVCC隔离级别READ CONSISTENCY 或者 SNAPSHOT ISOLATION。
当事务运行在READ COMMITTED级别上,通常不会发生任何冲突。如果运行在这样一个级别的一个事务,要修改已经被另一个未提交事务修改的行,则引擎将该事务挂起,直到其他事务已经提交,本次事务再自动继续。这样的事务隔离级别称为READ CONSISTENCY。
死锁是完全可以避免。在理论上,冲突是可能的,如果每个事务在等待一个不同的行由其他事务修改。在这种情况下,其中的一个事务被立即终止(回滚),除非设置被修改了< set database transaction rollback on conflict statement >。当此设置更改为FALSE,会话即避免执行导致死锁的语句并返回一个错误,但不会回滚之前的操作。应用程序应该快速执行的替换语句以至于继续或回滚事务。这样使得与其他一些发生死锁而不回滚的数据库引擎兼容。
当事务运行在REPEATABLE READ 或 SERIALIZABLE隔离级别时,冲突更有可能会发生。在这两个隔离级别之间的操作没有差异。这个隔离级别被称为SNAPSHOT ISOLATION。
在这种模式下,当两个事务的持续时间重叠,如果第一个事务已修改了一行行和第二事务想要修改同一行,第二个事务的操作将失败。即使在第一个事务已经提交,也是同样的情况。数据库引擎将使第二个事务失效并且回滚其所有修改。如果该设置被更改为false< set database transaction rollback on conflict statement >,那么第二次交易将只返回一个错误,而不回滚。应用程序必须执行的替换语句以至继续或回滚事务。
在MVCC模式,READ UNCOMMITTED 提升至 READ COMMITTED,因为新的架构是基于多版本行未提交的数据和多个版本可能存在某些行。
MVCC下,当一个事务是只读取数据,那么它将会执行一直到完成,其他事务将不会对其产生影响。这并不取决于事务是只读的或其隔离模式。
下载文件:hsqldb-2.3.4.zip
下载地址:http://hsqldb.org/download/
1. 远程连接Linux服务器,这里进入到 usr/local/ 目录
2. 上传安装文件至hsql目录下;(可自行设定安装目录)
3. 解压该安装文件
4. 确认已经安装了JDK,和已经配置了JAVA_HOME环境变量,例如:
6. 进入到hsqldb目录,新建启动脚本文件runServer.sh,如下:
#!/bin/sh
dir=$(dirname "$0")
java -cp "$dir/hsqldb.jar"org.hsqldb.server.Server
5. 新建server.properties文件,内容如下:
server.port = 9001
server.database.0 = mem:memdb1
server.dbname.0 = memdb1
server.silent = true
server.trace = true
server.remote_open = true
说明:
Value |
Default |
Description |
server.database.0 |
file:test |
the catalog type, path and file name of the first database file to use |
server.dbname.0 |
"" |
lowercase server alias for the first database file |
server.database.n |
NO DEFAULT |
the catalog type, path and file name of the n'th database file in use |
server.dbname.n |
NO DEFAULT |
lowercase server alias for the n'th database file |
server.silent |
true |
no extensive messages displayed on console |
server.trace |
false |
JDBC trace messages displayed on console |
server.address |
NO DEFAULT |
IP address of server |
server.tls |
false |
Whether to encrypt network stream. If this is set to true, then in normal situations you will also need to set properties system.javax.net.ssl.keyStore andsystem.javax.net.ssl.keyStorePassword, as documented elsewhere. The value of server.tls impacts the default value of server.port. |
server.daemon |
false |
Whether the server is run as a daemon |
server.remote_open |
false |
Allows opening a database path remotely when the first connection is made |
7. 启动hsqldb服务(如果没有执行权限则需要更改h2_server.sh文件权限)
8. 在win下可以通过runManagerSwing.bat进行打开控制台进行访问:
当 HyperSQL 服务器运行的时候,客户端程序可以通过hsqldb.jar 中的HSQLDB JDBC 驱动来连接数据库。如何使用 JDBC 连接数据库服务器的方法你可以参考 JDBCConnection 的 Java文档。这个文档位于HSQLDB 分发包的 /doc/apidocs 目录中。下面是用 hsql: 协议的示例程序来连接一个数据库,这个数据库使用默认端口(9001) 来等候数据库客户端进行连接。
如果使用的是 HyperSQL HTTP服务器,http: 协议和连接字符串将会有点不同:
Connection c =DriverManager.getConnection("jdbc:hsqldb:http://localhost/xdb","SA", "");
注: 在上面的连接 URL,这里并没有提到数据库文件,这个你需要在运行数据库
的时候明确数据库名。作为替代方案,通用的一个名字将会被定义为数据库名。0
将会被使用。如果你同时启动了多个数据库实例的话,你可以可以参考 HyperSQL
网络监听器章节来获得连接字符串的的相关信息。
如前面章节所描述的, java.sql.Connection 对象被用来连接访问数据库,但是数据库访问的性能却是由你数据库的运行方式决定的。经常性的打开和关闭数据库连接将会对数据库性能造成不小的压力,好的习惯应该是在一次数据库连接中尽可能多的完成所需要的所有操作。一个数据库连接应该被尽可能的重用,当长时间不再需要进行数据库连接的时候再将这个连接关闭。
相对数据库服务器连接来说,重用是非常重要的。一个数据库服务器的连接都会使用一个 TCP 端口,每次连接的时候,相关的服务端口将会被操作系统分配,当连接被关闭的时候,连接使用的 TCP 端口将会被服务器释放。如果在一个客户端发出了非常多的连接请求,操作系统可能不能再接纳新的连接而拒绝客户端的连接服务请求。一个 java.sql.Connection 对象有些方法是返回java.sql.* 对象。所有的这些对象将会在连接关闭的时候而销毁,因此这些对象都是可以被重用的。但是,如果你不再需要这些对象,你应该主动的将连接关闭。java.sql.DatabaseMetaData 对象用于返回数据库的 metadata。java.sql.Statement被用来执行查询和数据修改。java.sql.Statement可以在一次连接中执行多个 SQL 脚本。java.sql.PreparedStatement被用来重复执行一条 SQL 语句。这个 SQL 语句执行栈通常包含有参数,这样可以在每次新执行的时候来指定不同的参数变量。当 java.sql.PreparedStatement 对象被创建后,数据库引擎将会下一次的重复使用重新编译 SQL 栈,直到java.sql.PreparedStatement 对象被关闭。
作为一个重复执行的操作,使用 java.sql.PreparedStatement 将会比java.sql.Statement 对象快很多。java.sql.CallableStatement对象被用来执行一个 SQL 的调用。SQL 调用可能会包
含有很多的参数,而且每一次调用的时候,所使用的参数也有可能不相同。 与java.sql.PreparedStatement 类似,数据库引擎将会在调用前重新编译SQL 栈,直到java.sql.CallableStatement 对象被关闭。java.sql.Connection对象中包含有一些处理数据库连接和通信的方法。commit() 方法等同于数据库使用的 COMMIT 方法,将对数据库的修改提交。rollback()方法等同于数据库的 ROLLBACK 方法,将对数据库的修改撤回。setSavepoint (字符串)方法等同于 SQL 中使用的 SAVEPOINT,同时将会返回一个java.sql.Savepoint 对象。rollback 方法将会让数据库撤回到你的SAVEPOINT。Java API 中关于JDBCConnection,JDBCDriver,JDBCDatabaseMetadata,JDBCResultSet,JDBCStatement,JDBCPreparedStatement等 JDBC 中的方方法都能被HSQLDB 支持并整合到 HSQLDB 的数据库中了。
所有正在运行的数据库都可以通过命令 SHUTDOWN 来关闭,这个命令的使用和一个SQL 命令的使用相同。当 SHUTDOWN 命令被执行,所有正在运行的数据库命令将会被回滚。同时编目文件将会被保存到一个表单中,以便于下次快速启动。数据库关闭时候使用的表单可以通过命令 SHUTDOWN COMPACT 命令来创建。这个命令将会重写.data 文件。这个文件保存有 CACHED 表中的所有数据,同时被压缩。
这个命令应该在进行大量插入,更新或者删除之前使用,以增加数据库的效率,因为上面的操作将会大量操作数据库的缓存表。修改数据库结构,例如删除或者修改也将会大量使用缓存表和索引,这个时候将会在磁盘空间上创建大量未使用的空间,这时候你可以提前使用下这个命令,将缓存进行保存。当最后的一个数据库连接被 JDBC 关闭后,数据库并不会被直接关闭。当最后的连接被关闭后,你可以使用命令 shutdown=true 能够指向最早连接数据库的一个连接(打开数据库的连接)来强制关闭数据库。Connection c=DriverManager.getConnection("jdbc:hsqldb:file:/opt/db/testdb;shutdown=true","SA","");这样设计的好处是在软件项目的开发和测试阶段,但是在测试完成后,数据库可能不会自动的被关闭。这种方式不推荐在正式的应用程序中使用。
当服务器实例被启动或者内存模式数据库被启动后,如果你的链接字符串没有提供正确的数据库名字,那么一个新的数据库将会按照你给出的路径被创建。这个创建的新数据库将会使用你在连接字符串中使用的用户名和密码。用户名和密码是都是大小写敏感的(默认用户 SA 是一个特例,它的密码是大小写不敏感的)。
如果在连接字符串中没有指定用户名和密码,HSQLDB 将会使用 SA 用户名为默认的用户名,SA 的密码为空。你也可以通过参数来指定是否创建一个新的数据库。这个特性可能对新用户有些干扰,如果你为一个已经存在的数据库使用了错误的连接路径,这个参数将不会创建一个新的数据库。从调试的角度出发,你可以使用连接参数 ifexists=true 来对数据库的连接进行限制,这个参数只会避免在连接的时候创建一个新的数据库。在这种情况下,如果数据库不存在,那么 getConnection() 方法将会抛出一个异常。Connectionc=DriverManager.getConnection("jdbc:hsqldb:file:/opt/db/testdb;ifexists=true","SA", "");数据库还有很多其他的可选参数,这些参数的细节将会在系统管理和开发问题的章节中进行讨论。你可以在你的第一次数据库连接字符串中指定跟多的参数,而不仅仅局限于上面提到的参数。因为第一次的数据库连接将有可能创建一个新的数据库,你可能希望在这个数据库里面指定更多的内容。
HSQLDB 支持临时表和三种持久化表。
TEMP (临时)表是不写入磁盘,它仅仅只维持一个Connection对象的生命周期。每一个TEMP表仅对操作它的Connection来说是可见的,其他和数据库并发的连接只能访问自己的TEMP表备份。从1.8.0版本开始, TEMP表的定义遵循SQL标准的GLOBAL TEMPORARY类型。表的定义是持久的,但每个新的连接只能看到它自己的表,而这些表刚开始是空的。当连接提交以后,临时表里的内容默认会被清空。如果临时表的定义语句里边包括ON COMMIT PRESERVE ROWS,那么当连接提交发生时,临时表的内容将被保存。三种类型的持久化表一次是 MEMORY(内存)表, CACHED(缓存)表和 TEXT(文本符)表。
Memory 表是使用 CREATE TABLE 命令的默认表类型。Memory 表数据全部驻留在内存中,但是对于表结构或内容的任何修改都被写入到<dbname>.script 文件中。script 文件在下次数据库打开的时候被 MEMORY 读取,里边的所有内容在MEMORY 表中重新创建。所以跟TEMP 表不同, MEMORY 表被默认为是持久的。
CACHED 表是在使用 CREATE CACHED TABLE 命令的时候生成的。它只有索引或部分数据是驻留在内存中的,所以可以允许生成大容量表而不用占用几百兆的内存。 CACHED表的另外一个优点,即使它存储了大量的数据,数据库引擎只需花费很短的时间就可以启动。它的不足是在速度上有所降低。如果你的数据集相对小的时候,尽量不要使用 CACHED表。在小容量和大容量表共存的实际应用中,最好对小容量的表使用默认的 MEMORY 表。
TEXT 表是在 1.7.0 版本中开始支持的,它使用 CSV(逗号分割数值)或其他分隔符的文本文件作为数据源。你可以指定一个已有的 CSV 文件(比如其它数据库或程序导出的数据)作为TEXT 表的数据源,你也可以指定一个空文件用数据库引擎来填充数据。 TEXT 表的内存利用效率比较高,因为它只缓存部分文本数据和所有的索引。 TEXT 表的数据源如果需要的话,可以重新分配到不同的文件。建立一个 TEXT 表所需的两个命令的详细资料请查看 TEXT 表一章。
在 Memory-Only 数据库里, MEMORY 表和 CACHED 表的声明都看视作为非持久化的内存表声明。这种模式中是不允许声明 TEXT 表的。
测试场景,分为几种场景测试,分别对单节点单数据库方式与两台主机两个数据库分别多个线程插入查询增量的数据,进行性能分析,比较集群的性能损耗的,以及对集群的可用性,分别对两个server进行停止服务模拟宕机的情况,验证其可用性。
1、硬件配置:
Ø CPU:Intel(R) Core(TM) i5-4590 CPU @ 3.30GHz * 2(2核处理器)
Ø 内存:2G
Ø 磁盘:75G
2、软件配置:
Ø 操作系统:CentOSLinux release 7.1.1503(Linux version3.10.0-229.14.1.el7.x86_64)
Ø HSQLDB数据库:2.3.4
Ø HA-JDBC:3.0.3
Ø JDK: 1.7.0_79
测试场景:启动5个线程,每个线程20万条记录,并发插入数据库。数据库分别以内嵌模式与服务器模式启动。
测试步骤:
1. 内嵌程序测试,需要打包到服务上运行。
2. 服务器模式测试,需要启动hsqldb服务。详情请看安装与使用章节。
3 . 程序预先执行的语句如下:
SET DATABASE TRANSACTION CONTROL MVCC;
CREATE TABLE TEST_TABLE(id VARCHAR(36),name VARCHAR(100));
4. 执行测试的插入语句如下:
INSERT INTO TEST_TABLE VALUES('测试id','测试name');
5.为了对比网络方面的影响,同时给出远程服务模式,通过客户端在另外的机器上调用,与直接打包客户端放到测试主机上,分别得出两部分远程服务模式的测试数据。
n 测试结果
新增记录100万 |
|||
模式/插入记录 |
第一次 |
第二次 |
第三次 |
内嵌模式 |
7248(ms) |
7305(ms) |
6851(ms) |
远程服务模式(同机器) |
17888(ms) |
17496(ms) |
17866(ms) |
远程服务模式(不同机器) |
65740(ms) |
64588(ms) |
65918(ms) |
内嵌模式:
远程服务模式(同机器):
远程服务模式(不同机器):
测试场景:启动三个线程组,每个线程组启动5个线程,每个线程20万条记录,分别并发执行插入、删除、查询数据库操作。数据库分别以内嵌模式与服务器模式启动对比测试。
测试步骤:
1. 内嵌程序测试,需要打包到服务上运行。
2. 服务器模式测试,需要启动hsqldb服务。详情请看安装与使用章节。
3 . 程序预先执行的语句如下:
SET DATABASE TRANSACTION CONTROL MVCC;
CREATE TABLE TEST_TABLE(id VARCHAR(36),name VARCHAR(100));
INSERT INTO TEST_TABLE VALUES('测试id_s','测试name_s';
4. 执行测试的插入语句如下:
INSERT INTO TEST_TABLE VALUES('测试id','测试name');
5. 执行测试的删除语句如下:
DELETE FROM TEST_TABLE WHERE ID = '测试id';
6. 执行测试的查询语句如下:
SELECT * FROM TEST_TABLE WHERE ID = '测试id_s';
10.为了对比网络方面的影响,同时给出远程服务模式,通过客户端在另外的机器上调用,与直接打包客户端放到测试主机上,分别得出两部分远程服务模式的测试数据。
内嵌模式:
远程服务模式(同机器):
远程服务模式(不同机器):
n 测试结果
单机单数据库 |
|
|
|
执行新增、删除、查询操作 |
|
|
|
模式/插入记录 |
第一次 |
第二次 |
第三次 |
内嵌模式 |
41604(ms) |
41139(ms) |
43406(ms) |
远程服务模式(同机器) |
48455(ms) |
51278(ms) |
48090(ms) |
远程服务模式(不同机器) |
159602(ms) |
163102(ms) |
158430(ms) |
测试场景:使用两台主机,同上述配置,分别以服务器模式启动两个数据库服务。启动5个线程,每个线程20万条记录,并发插入集群数据库。
测试步骤:
1. 分别在两台机器上启动hsqldb服务。
2. 程序用上HA-JDBC作为JDBC代理,通过其配置实现故障容错,集群的能力配置如下:
<ha-jdbc xmlns="urn:ha-jdbc:cluster:3.0"> <sync id="diff"> <property name="fetchSize">1000</property> <property name="maxBatchSize">100</property> </sync> <cluster default-sync="diff" balancer="load" meta-data-cache="none" dialect="net.sf.hajdbc.dialect.hsqldb.HSQLDBDialect" transaction-mode="parallel" auto-activate-schedule="0 * * ? * *" failure-detect-schedule="0 * * ? * *"> <database id="db1" location="jdbc:hsqldb:hsql://172.16.21.139;mem:memdb1"> <user>SA</user> <password></password> </database> <database id="db2" location="jdbc:hsqldb:hsql://172.16.21.131;mem:memdb2"> <user>SA</user> <password></password> </database> </cluster> </ha-jdbc>
3. 程序预先执行的语句如下:
SET DATABASE TRANSACTION CONTROL MVCC;
CREATE TABLE TEST_TABLE(id VARCHAR(36),nameVARCHAR(100));
4. 执行测试的插入语句如下:
INSERT INTO TEST_TABLE VALUES('测试id','测试name');
n 测试结果
两台主机,两台数据库集群 |
|||
新增记录100万 |
|||
模式/插入记录 |
第一次 |
第二次 |
第三次 |
远程服务模式 |
137268(ms) |
136088(ms) |
133876(ms) |
主机一:
主机二:
测试场景:使用两台主机,同上述配置,分别以服务器模式启动两个数据库服务。客户端启动三个线程组,每个线程组启动5个线程,每个线程20万条记录,分别并发执行插入、删除、查询数据库操作。
测试步骤:
1. 分别在两台机器上启动hsqldb服务。
2. 程序用上HA-JDBC作为JDBC代理,通过其配置实现故障容错,集群的能力配置同测试场景一。
3 . 程序预先执行的语句如下:
SET DATABASE TRANSACTION CONTROL MVCC;
CREATE TABLE TEST_TABLE(id VARCHAR(36),name VARCHAR(100));
INSERT INTO TEST_TABLE VALUES('测试id_s','测试name_s';
4. 执行测试的插入语句如下:
INSERT INTO TEST_TABLE VALUES('测试id','测试name');
5. 执行测试的删除语句如下:
DELETE FROM TEST_TABLE WHERE ID = '1';
6. 执行测试的查询语句如下:
SELECT * FROM TEST_TABLE WHERE ID = '测试id_s';
n 测试结果
主机一:
主机二:
两台主机,两台数据库集群 |
|
|
|
执行新增、删除、查询操作 |
|
|
|
模式/测试次数 |
第一次 |
第二次 |
第三次 |
远程服务模式 |
>30min |
>30min |
- |
注意: 当测试的删除语句为:
DELETE FROM TEST_TABLE WHERE ID = '测试id';
或者:DELETE FROM TEST_TABLE WHERE name = '测试id' LIMIT 1;
HA-JDBC会出现以下情况:
并发集群的时候,会判断db2结果不一致,导致认为db2故障,其状态更新为非激活状态,这里配置的自动激活时间为一分钟,所以每隔一分钟从新通过db1同步一次数据,从新设置状态为激活状态。
其中第二条语句执行完成后,db1与db2是能保持一致的:
两台主机,两台数据库集群 |
|||
执行新增、删除、查询操作 |
|||
模式/测试次数 |
第一次 |
第二次 |
第三次 |
远程服务模式 |
276163(ms) |
299697(ms) |
297852(ms) |
测试场景:使用两台主机,同上述配置,起分别两个数据库服务,并对其进行集群配置,启动三个线程组,每个线程组启动5个线程,每个线程20万条记录分别起4个线程并发新增、删除、查询记录,然后分析停掉db1或db2数据库服务,查看其结果。
1. 集群情况下,客户端启动线程组执行新增记录语句,插入100万条记录:
INSERT INTOTEST_TABLE VALUES('测试id','测试name');
2. 写入中途停止db2,后台有异常报出:
3. db1仍能继续数据写入:
4. 重启db2,发现已经没表了!!!
后台一直在执行同步操作,但是都同步不了。
5. 只能在db2重建表,后台终于能同步成功了
2. db2仍能继续数据写入:
3. 重启db1,就知道同样会没表了~
后台同样一直在执行同步操作,但是都同步不了。
4. 在db1重建表,后台终于能同步成功了
1. 内嵌模式改成使用server模式后,性能会损耗15%-20%。
2. Server模式,如果客户端与db服务在不同的机器上,经过网络后也会有比较大的性能损耗(上面数据是在当前我测试本机与网络)。
3. Server模式采用用ha-jdbc集群后,插入相同记录的时间要多一倍到两倍。
4. Server模式采用用ha-jdbc集群后并发增删查下,体现出来的性能下降不只一个等级,这里测试几次仍这样。无论通过配置同步方式为full还是diff,transaction-mode为parallel或serial,仍一样的情况,这里需要后续验证。
5. 无论是db1数据库或者db2数据库停止后,集群仍能正常工作,能起到故障转移,但是重启服务后,因为采用内存数据库存储方式,需要重建相关表后才能完成自动同步。