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