數據庫選型之MySQL(固態硬盤)


  劉勇    Email: lyssym@sina.com

       本博客記錄作者在工作與研究中所經歷的點滴,一方面給自己的工作與生活留下印記,另一方面若是能對大家有所幫助,則幸甚至哉矣!

簡介

       鑒於高頻中心庫task(核心業務處理與存儲邏輯)部分占用機器較多,為節省成本,調研數據庫或緩存,以期滿足高頻生產的需求:1)峰值1w條/s;2)峰值60w條/m。本着節省成本的角度,本文對開源、免費的數據庫MySQL在固態硬盤下從事務處理條目下展開測試,測試目標平均寫入速率達10000條/s 以上則能滿足要求。

測試環境

       硬件環境

       10.1.120.34:Intel Core I5-4590, 主頻:3.30G,  內存:16G, 有固態硬盤

       軟件環境:

       10.1.120.34: Cent OS 6.5,  MySQL 5.6.26 (社區版)

       表結構:

 1 DROP TABLE IF EXISTS `transaction`;  2 CREATE TABLE `transaction` (  3   `tradedate` datetime DEFAULT NOT NULL,  4   `symbol` varchar(6) DEFAULT NOT NULL,  5   `symbolname` varchar(8) DEFAULT NOT NULL,  6   `trdmintime` varchar(6) DEFAULT NOT NULL,  7   `startprice` decimal(9,3) DEFAULT NOT NULL,  8   `highprice` decimal(9,3) DEFAULT NOT NULL,  9   `lowprice` decimal(9,3) DEFAULT NOT NULL, 10   `endprice` decimal(9,3) DEFAULT NOT NULL, 11   `change` decimal(9,3) DEFAULT NOT NULL, 12   `changeratio` decimal(6,3) DEFAULT NOT NULL, 13   `minvolume` decimal(10,0) DEFAULT NOT NULL, 14   `minamout` decimal(16,3) DEFAULT NOT NULL, 15   `unix` bigint(20) DEFAULT NOT NULL, 16   `market` varchar(3) DEFAULT NOT NULL
17 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
table transaction

       配置文件:即數據庫配置文件,見/etc/my.cnf

 1 # read_rnd_buffer_size = 2M  2 datadir=/var/lib/mysql  3 socket=/var/lib/mysql/mysql.sock  4 innodb_flush_log_at_trx_commit = 2
 5 innodb_autoinc_lock_mode = 2
 6 query_cache_type = 1
 7 query_cache_size = 20M  8 innodb_buffer_pool_size = 2G  9 innodb_flush_method = O_DSYNC 10 # Disabling symbolic-links is recommended to prevent assorted security risks 11 symbolic-links=0
my.cnf

性能測試

       事務處理

       針對高頻生產的應用需求,本文構造高頻中心庫系統的數據結構,從事物處理角度,對本地節點MySQL進行寫入操作,分別存儲數據量為60K、100K、600K條數據,對其速率進行測試。需要指出,由於常見I/O訪問的瓶頸主要受限於寫入測試,本文只針對寫入操作進行測試,暫不考慮讀取操作或者混合讀寫方式,若寫入操作不滿足要求,其它操作無需測試。

       本文采用寫入多條數據執行事務處理。因為10.1.120.34上采用固態硬盤作為存儲介質,其安裝有MySQL,根據應用場景,第一種從遠程訪問,即測試主機10.1.25.50訪問MySQL,第二種從本地訪問10.1.120.34訪問MySQL。以下分別從事務處理條目為1000、2000和3000下展開測試。

       以1000條數據為基礎執行事務處理,結果見表-1。

表-1  1000條下事務處理MySQL測試結果

節點

數據庫IP

數據量(K)

平均寫入速率(條/s)
遠程節點 10.1.120.34 60 2328
遠程節點 10.1.120.34 100 2366
遠程節點 10.1.120.34 600 2372
本地節點 10.1.120.34 60 14936
本地節點 10.1.120.34 100 16526
本地節點 10.1.120.34 600 21169

       以2000條數據為基礎執行事務處理,結果見表-2。

表-2  2000條下事務處理MySQL測試結果

節點

數據庫IP

數據量(K)

平均寫入速率(條/s)
遠程節點 10.1.120.34 60 2318
遠程節點 10.1.120.34 100 2333
遠程節點 10.1.120.34 600 2320
本地節點 10.1.120.34 60 12714
本地節點 10.1.120.34 100 17914
本地節點 10.1.120.34 600 20214

        以3000條數據為基礎執行事務處理,結果見表-3。

表-3  3000條下事務處理MySQL測試結果

節點

數據庫IP

數據量(K)

     平均寫入速率     (條/s)
  遠程節點   10.1.120.34         60      2319
  遠程節點   10.1.120.34       100      2377
  遠程節點   10.1.120.34       600      2429
  本地節點   10.1.120.34        60     11202
  本地節點   10.1.120.34       100     17587
  本地節點   10.1.120.34       600     18577

       小結

       從表1-3可知:1)在遠程節點訪問MySQL,即使采用固態硬盤,其速率還是較慢,無法滿足需求;2)在本地節點,訪問MySQL,則能夠滿足高頻生產的需求。

       批處理

       為比較批處理方式和事務處理方式的性能,本文針對其進行比較測試。

       每1000條數據,執行一次批處理,測試結果如表-4。

表-4  1000條下批處理與事務處理MySQL測試結果

方式

數據庫IP

數據量(K)

平均寫入速率(條/s)
批處理 10.1.120.34 60 15974
批處理 10.1.120.34 100 16328
批處理 10.1.120.34 600 17633
事務處理 10.1.120.34 60 14936
事務處理 10.1.120.34 100 16526
事務處理 10.1.120.34 600 21169

       每2000條數據,執行一次批處理,測試結果如表-5。

表-5  2000條下批處理與事務處理MySQL測試結果

方式

數據庫IP

數據量(K)

平均寫入速率(條/s)
批處理 10.1.120.34 60 14840
批處理 10.1.120.34 100 16310
批處理 10.1.120.34 600 17364
事務處理 10.1.120.34 60 12714
事務處理 10.1.120.34 100 17914
事務處理 10.1.120.34 600 20214
       每3000條數據,執行一次批處理,測試結果如表-6。

表-6  3000條下批處理與事務處理MySQL測試結果

節點

數據庫IP

數據量(K)

平均寫入速率(條/s)
批處理 10.1.120.34 60 14641
批處理 10.1.120.34 100 16371
批處理 10.1.120.34 600 17593
事務處理 10.1.120.34 60 11202
事務處理 10.1.120.34 100 17587
事務處理 10.1.120.34 600 18577

         小結

        從表4-6測試結果來看,在寫入數據量少時,批處理方式較事務方式速率快一些,但是隨着訪問數據量增加,事務處理方式稍微快一些。

 

總結

       從上述測試結果來看,以固態硬盤作為存儲介質,在本地訪問MySQL可以滿足高頻生產的需求。此外,鑒於高頻生產高負載的需求,優先選擇事務處理方式。

 

附錄

測試部分源代碼:

  1 import java.sql.Date;
  2 import java.math.BigDecimal;
  3 
  4 public class Transaction {
  5     private Date tradedate; 
  6     private String symbol;
  7     private String symbolName;
  8     private String trdmintime;
  9     private BigDecimal startprice;
 10     private BigDecimal highprice;
 11     private BigDecimal lowprice;
 12     private BigDecimal endprice;
 13     private BigDecimal change;
 14     private BigDecimal changeratio;
 15     private BigDecimal minvolume;
 16     private BigDecimal minamout;
 17     private long unix;
 18     private String market;
 19     
 20     public Transaction(Date tradedate,
 21                         String symbol,
 22                         String symbolName,
 23                         String trdmintime,
 24                         BigDecimal startprice,
 25                         BigDecimal highprice,
 26                         BigDecimal lowprice,
 27                         BigDecimal endprice,
 28                         BigDecimal change,
 29                         BigDecimal changeratio,
 30                         BigDecimal minvolume,
 31                         BigDecimal minamout,
 32                         long unix,
 33                         String market)
 34     {
 35         this.symbol = symbol;
 36         this.symbolName = symbolName;
 37         this.trdmintime = trdmintime;
 38         this.startprice = startprice;
 39         this.highprice = highprice;
 40         this.lowprice = lowprice;
 41         this.endprice = endprice;
 42         this.change = change;
 43         this.changeratio = changeratio;
 44         this.minvolume = minvolume;
 45         this.minamout = minamout;
 46         this.unix = unix;
 47         this.market = market;
 48     }
 49 
 50     public void setTradedate(Date tradedate) {
 51         this.tradedate = tradedate;
 52     }
 53 
 54     public void setSymbol(String symbol) {
 55         this.symbol = symbol;
 56     }
 57 
 58     public void setSymbolName(String symbolName) {
 59         this.symbolName = symbolName;
 60     }
 61 
 62     public void setTrdmintime(String trdmintime) {
 63         this.trdmintime = trdmintime;
 64     }
 65 
 66     public void setStartprice(BigDecimal startprice) {
 67         this.startprice = startprice;
 68     }
 69 
 70     public void setHighprice(BigDecimal highprice) {
 71         this.highprice = highprice;
 72     }
 73 
 74     public void setLowprice(BigDecimal lowprice) {
 75         this.lowprice = lowprice;
 76     }
 77 
 78     public void setEndprice(BigDecimal endprice) {
 79         this.endprice = endprice;
 80     }
 81 
 82     public void setChange(BigDecimal change) {
 83         this.change = change;
 84     }
 85 
 86     public void setChangeratio(BigDecimal changeratio) {
 87         this.changeratio = changeratio;
 88     }
 89 
 90     public void setMinvolume(BigDecimal minvolume) {
 91         this.minvolume = minvolume;
 92     }
 93 
 94     public void setMinamout(BigDecimal minamout) {
 95         this.minamout = minamout;
 96     }
 97 
 98     public void setUnix(long unix) {
 99         this.unix = unix;
100     }
101 
102     public void setMarket(String market) {
103         this.market = market;
104     }
105 
106     public Date getTradedate() {
107         return tradedate;
108     }
109 
110     public String getSymbol() {
111         return symbol;
112     }
113 
114     public String getSymbolName() {
115         return symbolName;
116     }
117 
118     public String getTrdmintime() {
119         return trdmintime;
120     }
121 
122     public BigDecimal getStartprice() {
123         return startprice;
124     }
125 
126     public BigDecimal getHighprice() {
127         return highprice;
128     }
129 
130     public BigDecimal getLowprice() {
131         return lowprice;
132     }
133 
134     public BigDecimal getEndprice() {
135         return endprice;
136     }
137 
138     public BigDecimal getChange() {
139         return change;
140     }
141 
142     public BigDecimal getChangeratio() {
143         return changeratio;
144     }
145 
146     public BigDecimal getMinvolume() {
147         return minvolume;
148     }
149 
150     public BigDecimal getMinamout() {
151         return minamout;
152     }
153 
154     public long getUnix() {
155         return unix;
156     }
157 
158     public String getMarket() {
159         return market;
160     }
161 
162 }
Class Transcation
  1 import java.sql.*;
  2 import java.math.BigDecimal;
  3 import java.math.RoundingMode;
  4 
  5 public class Test {
  6     public static int PREFIX = 1000;        // 批處理量
  7     public static int FIX = 600;            // 操作數據 K
  8     private Connection conn;
  9     private PreparedStatement pstm;
 10     private String sql;
 11     private int count;
 12     
 13     public static void main(String[] args) {
 14         // TODO Auto-generated method stub
 15         
 16         Transaction ts = new Transaction(null,
 17                                         "",
 18                                         "",
 19                                         "010000",
 20                                         new BigDecimal(15.857).setScale(3, RoundingMode.HALF_UP),
 21                                         new BigDecimal(18.550).setScale(3, RoundingMode.HALF_UP),
 22                                         new BigDecimal(13.147).setScale(3, RoundingMode.HALF_UP),
 23                                         new BigDecimal(16.383).setScale(3, RoundingMode.HALF_UP),
 24                                         new BigDecimal(0.151).setScale(3, RoundingMode.HALF_UP),
 25                                         new BigDecimal(1.550).setScale(3, RoundingMode.HALF_UP),
 26                                         new BigDecimal(5000000).setScale(3, RoundingMode.HALF_UP),
 27                                         new BigDecimal(500000000).setScale(3, RoundingMode.HALF_UP),
 28                                         System.currentTimeMillis(),
 29                                         "SSE");
 30         
 31         Test test = new Test();
 32         int symbolData = 100000;
 33         test.initMySQL();
 34         
 35         long start = test.getRunTime();
 36         for(int i = 0; i < Test.FIX*1000; i++) {
 37             ts.setTradedate(new Date(System.currentTimeMillis()));
 38             ts.setSymbol(Integer.toString(symbolData));
 39             symbolData++ ;
 40             ts.setSymbolName("中國銀行");
 41             ts.setUnix(ts.getUnix()+1);
 42             test.insertData(ts);
 43         }
 44         long end = test.getRunTime();
 45         System.out.println("寫入速率為: " + Test.FIX*1000*1000/(end-start));
 46         
 47         test.down();
 48     }
 49     
 50     
 51     public void initMySQL()
 52     {
 53         String driver = "com.mysql.jdbc.Driver";
 54         String url = "jdbc:mysql://10.1.120.34:3306/hdfs";
 55         String user = "root";
 56         String password = "";
 57         
 58         try {
 59             Class.forName(driver);
 60             conn = DriverManager.getConnection(url, user, password);
 61             if (!conn.isClosed())
 62                 System.out.println("Start MySQL!");
 63         } catch (Exception e) {
 64             e.printStackTrace();
 65         }
 66         
 67         count = 0;
 68         sql = "insert into transaction" + " values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
 69         try {
 70             pstm = conn.prepareStatement(sql);
 71             conn.setAutoCommit(false);
 72         } catch (SQLException e) {
 73             e.printStackTrace();
 74         }
 75     }
 76     
 77     
 78     public void insertData(Transaction ts)
 79     {
 80         try {
 81             pstm.setDate(1, ts.getTradedate());
 82             pstm.setString(2,  ts.getSymbol());
 83             pstm.setString(3, ts.getSymbolName());
 84             pstm.setString(4, ts.getTrdmintime());
 85             pstm.setBigDecimal(5, ts.getStartprice());
 86             pstm.setBigDecimal(6, ts.getHighprice());
 87             pstm.setBigDecimal(7, ts.getLowprice());
 88             pstm.setBigDecimal(8, ts.getEndprice());
 89             pstm.setBigDecimal(9, ts.getChange());
 90             pstm.setBigDecimal(10, ts.getChangeratio());
 91             pstm.setBigDecimal(11, ts.getMinvolume());
 92             pstm.setBigDecimal(12, ts.getMinamout());
 93             pstm.setLong(13, ts.getUnix());
 94             pstm.setString(14, ts.getMarket());
 95     
 96             pstm.executeUpdate();
 97             count++;
 98             if (count == Test.PREFIX) {
 99                 conn.commit();
100                 conn.setAutoCommit(false);
101                 count = 0;
102             }
103                         
104         } catch (SQLException e) {
105             try {
106                 conn.rollback();
107             } catch (SQLException e1) {
108                 // TODO Auto-generated catch block
109                 e1.printStackTrace();
110             }
111             e.printStackTrace();
112         }
113     }
114     
115     
116     public long getRunTime()
117     {
118         return System.currentTimeMillis();
119     }
120     
121     
122     public void down()
123     {
124         try {
125             if (!conn.isClosed()) {
126                 conn.close();
127                 System.out.println("Close MySQL!");
128             }
129         } catch (Exception e) {
130             e.printStackTrace();
131         }
132     }
133 
134 }
Class Test

   


  作者:志青雲集
  出處:http://www.cnblogs.com/lyssym
  如果,您認為閱讀這篇博客讓您有些收獲,不妨點擊一下右下角的【推薦】。
  如果,您希望更容易地發現我的新博客,不妨點擊一下左下角的【關注我】。
  如果,您對我的博客所講述的內容有興趣,請繼續關注我的后續博客,我是【志青雲集】。
  本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接。


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM