数据库选型之MySQL(多线程并发)

刘勇    Email: lyssym@sina.com

       本博客记录作者在工作与研究中所经历的点滴,一方面给自己的工作与生活留下印记,另一方面若是能对大家有所帮助,则幸甚至哉矣!

简介

        鉴于高频中心库task部分占用机器较多,为节省成本,调研数据库或缓存。在数据库选型之MySQL(二)中,在固态硬盘本地访问MySQL可以满足其10000次/s操作的需求,由于实际环境中存在多个品种(多进程、多线程访问数据库)的业务需求,因此,本文采用多线程在固态硬盘本地访问MySQL展开测试,以期对高频中心库后期架构调整提供实践参考。需要指出,本文作者对该种节省成本的解决方案是不赞成的。

测试环境

        硬件环境

        10.1.120.34:Intel Core I5-4590, 主频:3.30G,  内存:16G, 有固态硬盘

        软件环境:

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

性能测试

        针对高频生产的应用需求,本文构造高频中心库系统的数据结构,采用多线程模拟业务需求对本地节点MySQL进行写入操作,分别存储数据总量为60K、100K、600K条数据,对其速率进行测试。需要指出,由于常见I/O访问的瓶颈主要受限于写入测试,本文只针对写入操作进行测试,暂不考虑读取操作或者混合读写方式,若写入操作不满足要求,其它操作无需测试。

        因为10.1.120.34上采用固态硬盘作为存储介质,其安装有MySQL,根据应用场景,分别从10、20、30个线程并发访问MySQL 展开测试。

        测试整个结果见图-1:

QQ截图20150919163126

图-1 完整测试结果

        10个线程

        从10个线程执行事务处理,需要指出,事务处理数据量固定为1000,以下多线程情况与之类同,不再赘述,10个线程的平均速率见表-1。

表-1  10个线程下每个线程平均访问MySQL测试结果

节点

数据库IP

数据量(K)

平均写入速率(条/s)
本地节点 10.1.120.34 60 4085
本地节点 10.1.120.34 100 4607
本地节点 10.1.120.34 600 3021

         20个线程

         从20个线程执行事务处理,20个线程的平均速率见表-2。

表-2  20个线程下每个线程平均访问MySQL测试结果

节点

数据库IP

数据量(K)

平均写入速率(条/s)
本地节点 10.1.120.34 60 1945
本地节点 10.1.120.34 100 2149
本地节点 10.1.120.34 600 1525

        30个线程

        从30个线程执行事务处理,30个线程的平均速率见表-3。

表-3  30个线程下每个线程平均访问MySQL测试结果

节点

数据库IP

数据量(K)

平均写入速率(条/s)
本地节点 10.1.120.34 60 1266
本地节点 10.1.120.34 100 1461
本地节点 10.1.120.34 600 879

小结

        从表1-3可知:1)随着线程数目增加,线程平均写入速率会减小,而且还很明显;2)随着访问的数据量的增加,以10万条至60万条为例,每个线程平均访问其速率下降也很明显。

        本文测试结果对高频中心库后续架构调整提供有一些实践参考,若以平均速率乘以线程个数来衡量,则该高频生产情形是满足需求的,但是若出现不平衡状况,则为节省成本采用将数据在固态硬盘本地入库落地来生产,然后辅以redis作为缓存来缓解访问系统访问压力的解决方案,本文作者是不赞成这种该方案的,希望对有类似业务需求的朋友有所帮助。

附录:

测试部分程序源代码:

  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 Transaction
 1 import java.sql.Date;
 2 import com.gta.mysql.Transaction;
 3 import com.gta.mysql.Test;
 4 
 5 public class RunThread extends Thread {
 6     private Transaction ts;
 7     private int symbolData;
 8     private Test test;
 9     
10     public RunThread(Transaction ts, int symbolData, Test test) {
11         this.ts = ts;
12         this.symbolData = symbolData;
13         this.test = test;
14     }
15     
16         
17     public void run() 
18     {
19         long start = getRunTime();
20         for(int i = 0; i < ThreadTest.NUM*1000; i++) {
21             ts.setTradedate(new Date(System.currentTimeMillis()));
22             ts.setSymbol(Integer.toString(symbolData));
23             symbolData++;
24             ts.setSymbolName("中国银行");
25             ts.setUnix(ts.getUnix()+1);
26             test.insertData(ts);
27         }
28         long end = getRunTime();
29         
30         System.out.println(ThreadTest.NUM*1000*1000/(end-start));
31     }
32 
33 
34     public long getRunTime()
35     {
36         return System.currentTimeMillis();
37     }
38 
39 }
Class RunThread
 1 import java.math.BigDecimal;
 2 import java.math.RoundingMode;
 3 import com.gta.mysql.Test;
 4 import com.gta.mysql.Transaction;
 5 
 6 public class ThreadTest {
 7     public static int MAX = 10;
 8     public static int NUM = Test.FIX/MAX;
 9     
10     
11     public static void main(String[] args) {
12         
13         Transaction [] ts = new Transaction[ThreadTest.MAX];
14         Test []test = new Test[ThreadTest.MAX];
15         int symbol = 100000;
16         for (int i = 0; i < ts.length; i++) {
17             ts[i] = new Transaction(null,
18                     "",
19                     "",
20                     "010000",
21                     new BigDecimal(15.857).setScale(3, RoundingMode.HALF_UP),
22                     new BigDecimal(18.550).setScale(3, RoundingMode.HALF_UP),
23                     new BigDecimal(13.147).setScale(3, RoundingMode.HALF_UP),
24                     new BigDecimal(16.383).setScale(3, RoundingMode.HALF_UP),
25                     new BigDecimal(0.151).setScale(3, RoundingMode.HALF_UP),
26                     new BigDecimal(1.550).setScale(3, RoundingMode.HALF_UP),
27                     new BigDecimal(5000000).setScale(3, RoundingMode.HALF_UP),
28                     new BigDecimal(500000000).setScale(3, RoundingMode.HALF_UP),
29                     System.currentTimeMillis(),
30                     "SSE");
31             test[i] = new Test();
32             
33         }
34 
35         
36         RunThread[] thread = new RunThread[ThreadTest.MAX]; 
37         for (int i = 0; i < thread.length; i++) {
38             test[i].initMySQL();
39             thread[i] = new RunThread(ts[i], symbol, test[i]);
40             symbol += ThreadTest.NUM*1000;
41         }
42         
43         for (int i = 0; i < thread.length; i++)
44             thread[i].start();
45         
46         while (true) {
47             try {
48                 Thread.sleep(1000);
49             } catch (InterruptedException e) {
50                 e.printStackTrace();
51                 test[0].down();
52             }
53         }
54         
55     }
56 
57 }
ThreadTest

  作者:志青云集
  出处:http://www.cnblogs.com/lyssym
  如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
  如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
  如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【志青云集】。
  本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。


原文地址:https://www.cnblogs.com/lyssym/p/4821788.html