数据库选型之MySQL(普通硬盘)
刘勇 Email:lyssym@sina.com
本博客记录作者在工作与研究中所经历的点滴,一方面给自己的工作与生活留下印记,另一方面若是能对大家有所帮助,则幸甚至哉矣!
简介
鉴于高频中心库task部分(核心业务处理、存储逻辑)占用机器较多,为节省成本,调研数据库或缓存,以期满足高频生产的需求:1)峰值1w条/s;2)峰值60w条/m。本着节省成本的角度,本文对开源、免费的数据库MySQL和PostgreSQL从单一处理和批处理角度展开测试,测试目标平均写入速率达10000条/s 以上则能满足要求。
测试环境
硬件环境:
10.1.120.37:Intel Pentium, 主频:2.90G, 内存:6G
localhost: Intel Core I5, 主频:3.10G, 内存:4G
软件环境:
10.1.120.37:Cent OS 6.5, MySQL 5.6.25 (社区版)
localhost: Win7,MySQL 5.6.26(社区版)
表结构:
DROP TABLE IF EXISTS `transaction`;
CREATE TABLE `transaction` (
`tradedate` datetime DEFAULT NULL,
`symbol` varchar(6) DEFAULT NULL,
`symbolname` varchar(8) DEFAULT NULL,
`trdmintime` varchar(6) DEFAULT NULL,
`startprice` decimal(9,3) DEFAULT NULL,
`highprice` decimal(9,3) DEFAULT NULL,
`lowprice` decimal(9,3) DEFAULT NULL,
`endprice` decimal(9,3) DEFAULT NULL,
`change` decimal(9,3) DEFAULT NULL,
`changeratio` decimal(6,3) DEFAULT NULL,
`minvolume` decimal(10,0) DEFAULT NULL,
`minamout` decimal(16,3) DEFAULT NULL,
`unix` bigint(20) DEFAULT NULL,
`market` varchar(3) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
table transaction
性能测试
MySQL测试
对高频生产的应用需求,本文构造高频中心库系统的数据结构,从单一处理和批处理角度,对远程节点和本地节点(对比性能所用)MySQL进行写入操作,分别存储数据量为60K、100K、600K条数据,对其速率进行测试。需要指出,由于常见I/O访问的瓶颈主要受限于写入测试,本文只针对写入操作进行测试,暂不考虑读取操作或者混合读写方式,若写入操作不满足要求,其它操作无需测试。
单一处理,即每次处理一条数据,对其性能进行测试,结果见表-1。
表-1 单一处理MySQL测试结果
数据库IP | 数据量(K) | 平均写入速率(条/s) |
10.1.120.37 | 60 | 1533 |
10.1.120.37 | 100 | 1721 |
10.1.120.37 | 600 | 1772 |
localhost | 60 | 4889 |
localhost | 100 | 3875 |
localhost | 600 | 5057 |
从表-1可知:1)随着处理数据量增加,其写入速率急剧下降;2)从10.1.120.37和localhost来看,采用单一处理方式,较难满足高频生产需求。
批处理方式,分别从批量处理1000、2000、3000条数据出发,对其性能展开测试,结果见表-2。
表-2批处理MySQL测试结果
1000 | 2000 | 3000 | ||
数据库IP | 数据量(K) | 平均写入速率(条/s) | 平均写入速率(条/s) | 平均写入速率(条/s) |
10.1.120.37 | 60 | 1533 | 1575 | 1546 |
10.1.120.37 | 100 | 1721 | 1654 | 1614 |
10.1.120.37 | 600 | 1772 | 1710 | 1725 |
localhost | 60 | 2236 | 3033 | 3654 |
localhost | 100 | 2252 | 3589 | 3936 |
localhost | 600 | 2289 | 4717 | 4759 |
从表-2可知:1)增加批处理数据量,远程节点的写入速率变化不大,可能受限网络资源速率;2)采用批处理方式,很难满足高频生产系统需求,本地节点尚且很难满足,寄希望于远程节点则更加困难。
小结
从上述测试情况来看,单独采用MySQL数据库,其实是很难满足要求I/O要求,针对60w/m的峰值,即10次/ms,对于普通的物理介质存储方案(硬盘)来说,该要求是很难满足的。因此,若要考虑物理介质来存储,固态硬盘是一个选择方案,具体有待于测试。
PostgreSQL测试
由于PostgreSQL可以完全胜任任何中上规模的范围内的业务,因此,本文也针对PostgreSQL是否满足高频生产的应用需求展开性能测试。目前只针对本地节点从单一处理和批处理出发,分别存储上述数据量(见MySQL测试),若本地节点很难满足需求,远程节点也无需测试了。
每次处理一条数据,结果见表-3。
表-3单一处理PostgreSQL测试结果
数据库IP | 数据量(K) | 平均写入速率(条/s) |
localhost | 60 | 2055 |
localhost | 100 | 2303 |
localhost | 600 | 2102 |
分别从批量处理1000、2000、3000条数据出发,对其性能展开测试,结果见表-4。
表-4单一处理PostgreSQL测试结果
1000 | 2000 | 3000 | ||
数据库IP | 数据量(K) | 平均写入速率(条/s) | 平均写入速率(条/s) | 平均写入速率(条/s) |
localhost | 60 | 2167 | 1755 | 2342 |
localhost | 100 | 2200 | 2436 | 1423 |
localhost | 600 | 1952 | 2184 | 2201 |
小结
从上述测试结果来看,PostgreSQL针对本文目标应用场景的需求,差距甚远。本地节点尚且无法胜任需求,同时其CPU的处理能力也较远程节点强一些,因此不再对远程节点展开测试。
总结
经上述测试,PostgreSQL相对MySQL的写入速率稍微缓慢一些。针对节省成本的考虑,拟采用单一服务器来满足应用需求,难度巨大,主要集中于,针对60w/m的峰值,即10次/ms,对于普通的物理介质存储方案(机械硬盘)来说,该I/O要求是很难满足的。因此,若要考虑物理介质来存储,固态硬盘是一个选择方案,具体有待于测试。
附录:
测试程序核心源代码:
import java.sql.Date;
import java.math.BigDecimal; public class Transaction {
private Date tradedate;
private String symbol;
private String symbolName;
private String trdmintime;
private BigDecimal startprice;
private BigDecimal highprice;
private BigDecimal lowprice;
private BigDecimal endprice;
private BigDecimal change;
private BigDecimal changeratio;
private BigDecimal minvolume;
private BigDecimal minamout;
private long unix;
private String market; public Transaction(Date tradedate,
String symbol,
String symbolName,
String trdmintime,
BigDecimal startprice,
BigDecimal highprice,
BigDecimal lowprice,
BigDecimal endprice,
BigDecimal change,
BigDecimal changeratio,
BigDecimal minvolume,
BigDecimal minamout,
long unix,
String market)
{
this.symbol = symbol;
this.symbolName = symbolName;
this.trdmintime = trdmintime;
this.startprice = startprice;
this.highprice = highprice;
this.lowprice = lowprice;
this.endprice = endprice;
this.change = change;
this.changeratio = changeratio;
this.minvolume = minvolume;
this.minamout = minamout;
this.unix = unix;
this.market = market;
} public void setTradedate(Date tradedate) {
this.tradedate = tradedate;
} public void setSymbol(String symbol) {
this.symbol = symbol;
} public void setSymbolName(String symbolName) {
this.symbolName = symbolName;
} public void setTrdmintime(String trdmintime) {
this.trdmintime = trdmintime;
} public void setStartprice(BigDecimal startprice) {
this.startprice = startprice;
} public void setHighprice(BigDecimal highprice) {
this.highprice = highprice;
} public void setLowprice(BigDecimal lowprice) {
this.lowprice = lowprice;
} public void setEndprice(BigDecimal endprice) {
this.endprice = endprice;
} public void setChange(BigDecimal change) {
this.change = change;
} public void setChangeratio(BigDecimal changeratio) {
this.changeratio = changeratio;
} public void setMinvolume(BigDecimal minvolume) {
this.minvolume = minvolume;
} public void setMinamout(BigDecimal minamout) {
this.minamout = minamout;
} public void setUnix(long unix) {
this.unix = unix;
} public void setMarket(String market) {
this.market = market;
} public Date getTradedate() {
return tradedate;
} public String getSymbol() {
return symbol;
} public String getSymbolName() {
return symbolName;
} public String getTrdmintime() {
return trdmintime;
} public BigDecimal getStartprice() {
return startprice;
} public BigDecimal getHighprice() {
return highprice;
} public BigDecimal getLowprice() {
return lowprice;
} public BigDecimal getEndprice() {
return endprice;
} public BigDecimal getChange() {
return change;
} public BigDecimal getChangeratio() {
return changeratio;
} public BigDecimal getMinvolume() {
return minvolume;
} public BigDecimal getMinamout() {
return minamout;
} public long getUnix() {
return unix;
} public String getMarket() {
return market;
} }
Class Transaction
import java.sql.*;
import java.math.BigDecimal;
import java.math.RoundingMode; public class Test {
public static int PREFIX = 1000; // 批处理量
public static int FIX = 600; // 操作数据 K
private Connection conn;
private PreparedStatement pstm;
private String sql;
private int count; public static void main(String[] args) {
// TODO Auto-generated method stub Transaction ts = new Transaction(null,
"",
"",
"010000",
new BigDecimal(15.857).setScale(3, RoundingMode.HALF_UP),
new BigDecimal(18.550).setScale(3, RoundingMode.HALF_UP),
new BigDecimal(13.147).setScale(3, RoundingMode.HALF_UP),
new BigDecimal(16.383).setScale(3, RoundingMode.HALF_UP),
new BigDecimal(0.151).setScale(3, RoundingMode.HALF_UP),
new BigDecimal(1.550).setScale(3, RoundingMode.HALF_UP),
new BigDecimal(5000000).setScale(3, RoundingMode.HALF_UP),
new BigDecimal(500000000).setScale(3, RoundingMode.HALF_UP),
System.currentTimeMillis(),
"SSE"); Test test = new Test();
int symbolData = 100000;
test.initMySQL(); long start = test.getRunTime();
for(int i = 0; i < Test.FIX*1000; i++) {
ts.setTradedate(new Date(System.currentTimeMillis()));
ts.setSymbol(Integer.toString(symbolData));
symbolData++ ;
ts.setSymbolName("中国银行");
ts.setUnix(ts.getUnix()+1);
test.insertData(ts);
}
long end = test.getRunTime();
System.out.println("写入速率为: " + Test.FIX*1000*1000/(end-start)); test.down();
} public void initMySQL()
{
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://10.1.120.37:3306/hdfs";
String user = "root";
String password = ""; try {
Class.forName(driver);
conn = DriverManager.getConnection(url, user, password);
if (!conn.isClosed())
System.out.println("Start MySQL!");
} catch (Exception e) {
e.printStackTrace();
} count = 0;
sql = "insert into transaction" + " values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
try {
pstm = conn.prepareStatement(sql);
conn.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
} public void insertData(Transaction ts)
{
try {
pstm.setDate(1, ts.getTradedate());
pstm.setString(2, ts.getSymbol());
pstm.setString(3, ts.getSymbolName());
pstm.setString(4, ts.getTrdmintime());
pstm.setBigDecimal(5, ts.getStartprice());
pstm.setBigDecimal(6, ts.getHighprice());
pstm.setBigDecimal(7, ts.getLowprice());
pstm.setBigDecimal(8, ts.getEndprice());
pstm.setBigDecimal(9, ts.getChange());
pstm.setBigDecimal(10, ts.getChangeratio());
pstm.setBigDecimal(11, ts.getMinvolume());
pstm.setBigDecimal(12, ts.getMinamout());
pstm.setLong(13, ts.getUnix());
pstm.setString(14, ts.getMarket()); pstm.executeUpdate();
count++;
if (count == Test.PREFIX) {
conn.commit();
conn.setAutoCommit(false);
count = 0;
} } catch (SQLException e) {
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
} public long getRunTime()
{
return System.currentTimeMillis();
} public void down()
{
try {
if (!conn.isClosed()) {
conn.close();
System.out.println("Close MySQL!");
}
} catch (Exception e) {
e.printStackTrace();
}
} }
Class Test
作者:志青云集
出处:http://www.cnblogs.com/lyssym/p/4821490.html
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【志青云集】。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
数据库选型之MySQL(普通硬盘)的更多相关文章
- 数据库选型之MySQL(固态硬盘)
刘勇 Email: lyssym@sina.com 本博客记录作者在工作与研究中所经历的点滴,一方面给自己的工作与生活留下印记,另一方面若是能对大家有所帮助,则幸甚至哉矣! 简介 鉴于高频中心库 ...
- 数据库选型之MySQL(多线程并发)
刘勇 Email: lyssym@sina.com 本博客记录作者在工作与研究中所经历的点滴,一方面给自己的工作与生活留下印记,另一方面若是能对大家有所帮助,则幸甚至哉矣! 简介 鉴于高频中心库 ...
- nosql数据库选型
http://blogread.cn/it/article/6654 今天在书店里翻完了一遍<七天七数据库>.这本书简单介绍了postgreSQL,riak,mongodb,HBase,r ...
- {MySQL数据库初识}一 数据库概述 二 MySQL介绍 三 MySQL的下载安装、简单应用及目录介绍 四 root用户密码设置及忘记密码的解决方案 五 修改字符集编码 六 初识sql语句
MySQL数据库初识 MySQL数据库 本节目录 一 数据库概述 二 MySQL介绍 三 MySQL的下载安装.简单应用及目录介绍 四 root用户密码设置及忘记密码的解决方案 五 修改字符集编码 六 ...
- 重新学习MySQL数据库3:Mysql存储引擎与数据存储原理
重新学习Mysql数据库3:Mysql存储引擎与数据存储原理 数据库的定义 很多开发者在最开始时其实都对数据库有一个比较模糊的认识,觉得数据库就是一堆数据的集合,但是实际却比这复杂的多,数据库领域中有 ...
- MySQL数据库1初识MySQL
目录 Mysql 一.数据库是什么? 二.为啥使用数据库?(*****) 三.数据库的分类(*****) 1.关系型数据库 2.非关系型数据库 3.关系型与非关系型区别: 四.数据库MySQL的架构 ...
- MySQL数据库(一)—— 数据库介绍、MySQL安装、基础SQL语句
数据库介绍.MySQL安装.基础SQL语句 一.数据库介绍 1.什么是数据库 数据库即存储数据的仓库 2.为什么要用数据库 (1)用文件存储是和硬盘打交道,是IO操作,所以有效率问题 (2)管理不方便 ...
- [MySQL数据库之数据库相关概念、MySQL下载安装、MySQL软件基本管理、SQL语句]
[MySQL数据库之数据库相关概念.MySQL下载安装.MySQL软件基本管理.SQL语句] 数据库相关概念 数据库管理软件的由来 数据库管理软件:本质就是个C/S架构的套接字程序. 我们在编写任何程 ...
- laravel5 数据库配置(MySQL)
laravel5 数据库配置(MySQL) 首先有一个安装完成可以运行的laravel框架. 配置database.php 进入laravel根目录. 在config目录下找到database.php ...
随机推荐
- [转]Android应用中返回键的监听及处理
用户在点击手机的返回按钮时,默认是推出当前的activty,但是有时用户不小心按到返回,所以需要给用户一个提示,这就需要重写onkeydown事件,实现的效果如下: 标签: Android ...
- GNU make 指南
http://docs.huihoo.com/gnu/linux/gmake.html GNU make 指南 翻译: 哈少 译者按: 本文是一篇介绍 GNU Make 的文章,读完后读者应该基本掌握 ...
- 修改Linux默认启动级别或模式
在Linux中有7种启动级别,默认是X-Window,像是Windows的窗口模式,而Linux的操作和配置一般我们都采用输入命令的方式来完成,像DOS操作系统一样,如何让Linux一启动就进入这种模 ...
- .Net4.0并行库介绍——Cancellation Framework
在.net 4.0中,引入了一个新的类CancellationToken,这个类基本上集成了我们各种常用的取消方式,在并发任务中非常有用. 同步模式下的取消: 一种比较常见的需要支持取消功能的的是一些 ...
- win7 系统装SQLServer2000 成功
昨天在win7上装SQLServer数据库,写一下体会.首先,如果以前安装的话,要删除干净.我也找了半天的网络资料.1.把原来SQLServer的安装目录 C:\Program Files\Micro ...
- git ssh key配置
原文:https://blog.csdn.net/lqlqlq007/article/details/78983879 git clone支持https和git(即ssh)两种方式下载源码: 当使用 ...
- 使用Redisson实现分布式锁
原文:https://www.jianshu.com/p/cde0700f0128 1. 可重入锁(Reentrant Lock) Redisson的分布式可重入锁RLock Java对象实现了jav ...
- ArcGIS Engine中空间参照(地理坐标)相关方法总结转
ArcGIS Engine中空间参照(地理坐标)相关方法总结 来自:http://blog.csdn.net/u011170962/article/details/38776101 1.创建空间参考 ...
- GO -- 一个经验
加锁要在有用的的上下文再加锁, 不要加的范围多了, 否则被锁住.
- [翻译] TLMotionEffect 重力感应
TLMotionEffect 重力感应 https://github.com/jvenegas/TLMotionEffect This category adds a motion effect t ...