OneCoder


  • 首页

  • 归档

  • 标签

  • 关于

  • 搜索

《High Performance MySQL》翻译(3) 第一章 并发控制

发表于 2013-03-27 | 阅读次数


并发控制

任何时刻当不止一个请求想要同时修改数据时候就产生了并发控制问题。从本章我们的观点来看,MySQL需要在两层关注这个问题:服务层和存储引擎层。并发控制是一个大话题,有很多相关的理论文献发表。所以,我们仅简介一下MySQL处理并发读写的方式。你将在本章的接下来的部分看到相关信息。

我们以Unix系统上的电子邮箱为例。传统的邮箱文件格式非常简单。邮箱中的所有信息是一个接一个的连接在一起的。因此读取和解析邮件信息都非常简单。邮件发送也非常简单:仅仅是在文件结尾加上新的信息。

但是当两个进程同时给同一个邮箱发送邮件的时候将会发生什么?很显然这回损坏邮箱,在邮箱文件结尾产生两个交错的信息。好的邮件收发系统采用锁的方式避免这种损坏。当一个客户端在邮箱锁住的时候试图发送信息,则它必须等待直到它获取锁。

这种结构在实践的时候运行良好,但是却没有提供任何并发的支持。因为同一时刻只有一个进程可以修改邮箱,在大规模邮箱的情况下这会带来问题。

阅读全文 »

《High Performance MySQL》翻译(2) 连接管理和安全 优化和执行

发表于 2013-03-26 | 阅读次数

接上篇,第一章 MySQL架构和历史

连接管理和安全


每个客户连接在服务内部都有一个独立的线程处理。查询在这个单独的线程内运行,线程轮流在CPU或核心上运行。线程在服务端被缓存,所以不必针对每个新来线程进行创建和销毁。(注2)。
当客户端(应用)连接到MySQL服务的时候,服务端需要进行认证。认证是基于用户名,来访主机和密码的。X.509认证也可用于通过SSL(安全套接层)进行的连接。当客户端已经连接的时候,服务端会对每个请求校验该客户端是否具有操作权限。(例如:校验该客户端是否具有在wolrd数据库的Country表执行SELECT操作的权限。)

优化和执行

MySQL解析查询请求,生成内部结构(解析树),然后执行多种优化。包括重写查询,决定读取表的顺序,选择要使用的索引等等。你可以在查询中通过特殊的关键字给优化器指示,以引导其决定操作步骤。你也可以向服务端询问各种优化的方向。这会让你知道服务端进行了如何的决策,这对你重构查询和表结构以及优化设定以使服务高效运行给出了可参考的点。我们将在第六章讨论优化的细节。

优化器并不真正关心表所使用的存储引擎,但是存储引擎影响服务端对查询的优化方式。优化器向存储引擎询问其某些功能特性以及特定操作的耗时和表数据的统计。例如,一些存储引擎支持索引,可以有效支持的查询。你可以在第四和第五章了解到更多关于索引和表结构优化的信息。

在解析查询之前,服务端先检查查询缓存,查询缓存仅保存SELECT语句及其结果。如果某个查询请求与缓存中某条信息一致,那么服务端无需在解析,优化或者执行查询,它可以直接返回存储结果。我们将在第七章进行详细的说明。


注2:MySQL5.5以后的版本支持线程池插件,一个小型的线程池可以提供很多连接。 

阅读全文 »

High Performance MySQL 翻译 第一章 MySQL架构和历史 - 逻辑架构

发表于 2013-03-25 | 阅读次数

《High Performance MySQL》是OneCoder正在阅读的书,利用茶余饭后时间进行的阅读和翻译,日积月累。

MySQL与其他数据库服务有很大的不同,它的架构特性使得它在广泛领域内成为一种实用而“廉价”的选择。MySQL并不是完美的,但是他足够灵活以适应特定的需求环境,如网络应用。同时,MySQL也可以支持嵌入式应用,数据仓库,内容索引和软件分发,高可用系统,联机事务处理等等。

为了充分的利用MySQL,你需要理解其设计,从而利用而不是抗拒它。MySQL在很多方面是灵活的。例如,它支持的硬件范围很广,你可以在各种硬件环境下配置和运行它,并且,它支持多种数据类型。然而,MySQL最不寻常和重要的特性是它的存储引擎,它在设计上将查询进程和其他服务任务与数据存储和检索分离。这种分离的特性让你可以据需选择数据的存储方式以及想要怎样的性能,特性和其他特征。

本章概要介绍MySQL的架构,存储引擎的主要区别及其重要性。最后将介绍一些历史背景和基准数据。我们视图通过简化细节和展示样例的方式介绍了MySQL。这个讨论对于数据库新手和其他数据库的专家都非常有帮助。

MySQL 逻辑架构

一个好的展现MySQL各个组件如何协同工作的图会帮助你更好的理解MySQL。图1-1展示了MySQL的逻辑架构。

图1-1

最上层是业务层,不局限于MySQL。他们大多是基于网络的客服端/服务端工具或者服务,需要进行连接管理,权限认证,安全等等。

第二层开始变得“有趣”。MySQL大部分的“大脑”都在这层,包括查询解析代码,分析,优化,缓存以及所有内嵌函数(如,dates, times, math 和 encryption)。提供的所有访问存储引擎的函数都在该层,例如:存储过程, 触发器和视图。

第三层包括存储引擎。他们负责存储和检索存储在MySQL中的所有数据。就跟GNU/Linue的各种可用的文件系统一样,不同存储引擎也有其优缺点。服务端通过存储引擎接口(API)与其通信。该API屏蔽了不同存储引擎的区别,使他们对查询层是透明的。该API包含了大量的底层函数,执行诸如"开始一个事务"或者"查询包含该主键的行"等操作。存储引擎不解析SQL(注1)或者与彼此通信;他们只负责响应来自服务端的请求。

注1:一个例外是在InnoDB引擎解析外键定义,因为MySQL服务本身并没有实现该功能。

阅读全文 »

Gradle初试

发表于 2013-03-19 | 阅读次数

Gradle是什么就不多说了,跟Maven是同类型的工具。Spring和Hibernate都早已经迁移了过来。官网地址:http://www.gradle.org。最新稳定版为1.4

Gradle Eclipse Plugin是spring的sts支持的。安装之:

Installing Gradle Tooling from update site
Alternatively you can install from update sites. The following update sites are available:

   * http://dist.springsource.com/snapshot/TOOLS/nightly/gradle (latest development snapshot)
   * http://dist.springsource.com/milestone/TOOLS/gradle (latest milestone build.)
   * http://dist.springsource.com/release/TOOLS/gradle (latest release)

Gradle的配置文件脚本是groovy语法的,Eclipse插件也安装之

http://dist.springsource.org/release/GRECLIPSE/e4.2/

将工程转换为Gradle工程。

然后编辑,配置文件即可。Gradle吸引人的地方就是文档相当的完善,对于一般使用者,最常用的就是依赖管理功能,文档地址:http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html

根据文档,先配置Gradle环境,

PATH=D:\Develop Software\gradle-1.4\bin

这里是为了能够在命令行中使用gradle。对于Eclipse 插件来说,其默认下载是使用的是1.2版本,如果强制指定我们下载的1.4版本,在某些操作的时候会报错。

可编辑gradle.bat(.sh)文件,设置JVM参数。

我们就在Eclipse中尝试gradle,通过configure->convert to gradle project,将工程变为Gradle管理的工程。

然后编写build.gradle配置文件。

 

apply plugin: 'java'
group='onecoder'
version='1.0'
repositories {
mavenCentral()
mavenRepo url: "https://oss.sonatype.org/content/repositories/opensymphony-releases"
mavenRepo url: "http://dev.anyframejava.org/maven/repo"
}
sourceSets {
main
}
dependencies {
compile "io.netty:netty:3.6.3.Final"
compile "ch.qos.logback:logback-core:1.0.7"
compile "org.slf4j:slf4j-api:1.7.3"
compile "javax.mail:mail:1.4.4"
compile "org.apache.httpcomponents:httpclient:4.2.2"
compile "org.hyperic:sigar:1.6.4"
compile "net.sourceforge.groboutils:groboutils-core:5"
}


然后fresh all一下,即可自动下载依赖了。相对pom.xml来说,配置文件看起来确实清晰简单多了。这里有很多配置,OneCoder还没有弄清楚,这里只是简单的试用,并且把个人联系的工程迁移了过来。细节问题,留待以后使用中慢慢研究吧。
 

阅读全文 »

Linux 指定MySQL服务运行的CPU核心(数)

发表于 2013-03-18 | 阅读次数

最近在利用mysqlslap对MySQL进行性能测试,但是测得的TPS、QPS的benchmark数据,从趋势上就跟网上“权威”的测试数据不同。这让OneCoder十分怀疑测试数据的准确性。

在定位问题的过程中,在独立于MySQL Server的机器上执行mysqlslap测试,测得的数据趋势正常。即初始随着并发数增大(一定范围内),TPS和QPS成上升趋势。这让我怀疑我之前在同一台服务器进行的测试,可能mysqlslap和MySQL Server争夺了CPU资源。

在一篇MySQL的测试报告中看到这样的话:

此外测试的机器具有 16 核,其中 12 核运行 mysqld ,另外 4 核运行 sysbench。

立马上网搜索指定方法。搜得Linux下的taskset命令

taskset -cp cpu序号 mysqld-pid  

即可指定mysqld服务使用的cpu核心。例如:

taskset -cp 0-47 12345

执行mysqlslap的时候,只需通过

taskset -c 48-63 mysqlslap xxxxxx

指定使用的cpu核心即可。准备给MySQL Server分配48核, mysqlslap 16核,测试看看效果。
 

阅读全文 »

数据结构 有序数组表示稀疏矩阵

发表于 2013-03-17 | 阅读次数

一般存储矩阵,自然想到二维数据。但是对于稀疏矩阵(0项很多),这无疑浪费的大量的空间。所以,这里考虑换一种表示方法。用一个三元组表示矩阵中的非零元素。

//(稀疏)矩阵数据结构, 待表示矩阵如下
// 15     0     0     22     0     -15
// 0     11     3     0     0     0
// 0     0     0     -6     0     0
// 0     0     0     0     0     0
// 91     0     0     0     0     0
// 0     0     28     0     0     0

#include <stdio.h>
#include <stdbool.h>
typedef struct {
     int col; // 列号
     int row; // 行号
     int value; // 值
} sparse_matrix;
void createMatrix(sparse_matrix *matrix);
void printMatrix(sparse_matrix *matrix);
void transposeMatrix(sparse_matrix *matrix, sparse_matrix *transposeMatrix);
#define GET_ARRAY_LEN(array,len) (len=(sizeof(array)/sizeof(array[0])));
int main() {   
     int length;
     sparse_matrix smatrix[9], transMatrix[9];
     createMatrix(smatrix);
     GET_ARRAY_LEN(smatrix,length);
     printMatrix(smatrix);
     printf("Array length is %d\n",length);
     transposeMatrix(smatrix, transMatrix);
     printf("Print transpose matrix: \n");
     printMatrix(transMatrix);
    return 0;
}
// 初始化稀疏矩阵
void createMatrix(sparse_matrix *matrix) {
     matrix[0].row = 6;// 0行元素存储行数
     matrix[0].col = 6;// 0列元素存储列数
     matrix[0].value = 8;
     matrix[1].row = 0;
     matrix[1].col = 0;
     matrix[1].value = 15;
     matrix[2].row = 0;
     matrix[2].col = 3;
     matrix[2].value = 22;
     matrix[3].row = 0;
     matrix[3].col = 5;
     matrix[3].value = -15;
     matrix[4].row = 1;
     matrix[4].col = 1;
     matrix[4].value = 11;
     matrix[5].row = 1;
     matrix[5].col = 2;
     matrix[5].value = 3;
     matrix[6].row = 2;
     matrix[6].col = 3;
     matrix[6].value = -6;
     matrix[7].row = 4;
     matrix[7].col = 0;
     matrix[7].value = 91;
     matrix[8].row = 5;
     matrix[8].col = 2;
     matrix[8].value = 28;
}

//打印稀疏矩阵
//最差时间复杂度:O(row * col * valueCount);
void printMatrix(sparse_matrix *matrix) {
     int i,j,k;
     int row = (*matrix).row;
     int col = (*matrix).col;
     int valueCount = (*matrix).value;
     int startIndex = 1;
     for (i = 0; i < row; i++) {
          for (k = 0; k < col; k++) {
               bool print = false;
               for (j = startIndex; j <= valueCount; j++) {
                    int curRow = (*(matrix + j)).row,
                    curCol = (*(matrix + j)).col;
                    if (i == curRow && k == curCol) {
                         printf("%d\t", (*(matrix+j)).value);
                         print = true;
                         startIndex++;
                    }
               }
               if (!print) {
                    printf("%d\t", 0);
               }
          }
          printf("\n");
     }
}
// 求稀疏矩阵的转置矩阵,即交换行列的位置
// 最差时间复杂度:O(col * valueCount);
void transposeMatrix(sparse_matrix *smatrix, sparse_matrix *transposeMatrix) {
     int i,n, rowNum = (*smatrix).row, colNum = (*smatrix).col, valueNum = (*smatrix).value;
     (*transposeMatrix).row = colNum;
     (*transposeMatrix).col = rowNum;
     (*transposeMatrix).value = valueNum;
     int index = 1;
     for (i = 0; i < colNum; i++) {
          for (n = 1; n <= valueNum; n++) {
               int curRow = (*(smatrix + n)).row,
                    curCol = (*(smatrix + n)).col,
                    curValue = (*(smatrix + n)).value;
               if (i == curCol) {
                    (*(transposeMatrix + index)).row = curCol;
                    (*(transposeMatrix + index)).col = curRow;
                    (*(transposeMatrix + index)).value = curValue;
                    index++;
               }
          }
     }
}

可以看到,相对于传统的使用二维数据的方式存储矩阵,该存储方式对于稀疏矩阵来说,无疑节省了大量空间。  但是对于矩阵的打印和转置来说,从数据量级看浪费了时间。所以,此种表示方式适用于矩阵中非零元素少的稀疏矩阵。尤其当矩阵中非零元素数量为cols * rows时,转置的时间复杂性为O(rows * cols * cols)。用时间换空间。

考虑再用少量空间,换一些时间。实现时间复杂度的为O(cols + elements)的快速转置:

// 快速转置算法,浪费少量空间,换取时间
// 直接计算转置后元素的存放位置
void fastTranspose(sparse_matrix *smatrix, sparse_matrix *transposeMatrix) {
     int i, rowNum = (*smatrix).row, colNum = (*smatrix).col, valueNum = (*smatrix).value;
     int row_terms[colNum + 1],
          startPos[colNum + 1];
     (*transposeMatrix).row = colNum;
     (*transposeMatrix).col = rowNum;
     (*transposeMatrix).value = valueNum;
     for (i = 0; i< colNum; i++) {
          row_terms[i] = 0; // 数组中的元素必须初始化
     }
     for (i = 1; i <= valueNum; i++) {
          int     curCol = (*(smatrix + i)).col;
          row_terms[curCol]++;//记录转置后,每行的元素个数
     }
     startPos[0] = 1;//初始化起始位置
     for (i = 1; i < colNum; i++) {
          startPos[i] = startPos[i-1] + row_terms[i-1];
     }
      for (i = 1; i <= valueNum; i++) {
           int curRow = (*(smatrix + i)).row,
                curCol = (*(smatrix + i)).col,
                curValue = (*(smatrix + i)).value;
           int j = startPos[curCol]++;// 计算出原矩阵中的元素在转置矩阵数据中的位置
           (*(transposeMatrix + j)).row = curCol;
           (*(transposeMatrix + j)).col = curRow;
           (*(transposeMatrix + j)).value = curValue;
      }
}

可见快速转置的主要思想就是直接计算出元素在转置矩阵中的顺序位置,直接存储。接下来是稀疏矩阵的乘法。

// 稀疏矩阵乘法运算, 以下面矩阵为例
// 0     0     1     1 * 0     0
//                         0     0 = 2     5
//                         0     2
//                         2     3
void matrixMulti(sparse_matrix *amatrix, sparse_matrix *bmatrix, sparse_matrix *resultMatrix) {
     int i, aRowNum = (*amatrix).row, aValueNum = (*amatrix).value;
     int j, bColNum = (*bmatrix).col, bValueNum = (*bmatrix).value;
     (*resultMatrix).row = aRowNum;//首先可知结果矩阵的行列数
     (*resultMatrix).col = bColNum;
     sparse_matrix tbMatrix[9];// 为了计算方便先求出被乘矩阵的转置矩阵,下面计算都利用转置矩阵
     fastTranspose(bmatrix, tbMatrix);
         int temp_sum = 0,
          row = (*(amatrix + 1)).row, // 矩阵A的起始行,即为结果的起始行
          col,
          rowBegin = 1,
          rIndex = 0;
     // 在循环内部控制循环的次数和起始
     for (i = 1; i <= aValueNum; ) {
          col = (*(tbMatrix + 1)).row; // 矩阵B的转置矩阵的行,即对应的列
          for (j = 1; j <= bValueNum + 1; ) {
               if (amatrix[i].row != row) {
                    storeValue(resultMatrix, row, col, temp_sum, &rIndex);
                i = rowBegin;
                    for (; col == tbMatrix[j].row; j++)
                         ;
                    col = tbMatrix[j].row;
                    temp_sum = 0;
               } else if (col != tbMatrix[j].row) {
                    storeValue(resultMatrix, row, col, temp_sum, &rIndex);
                i = rowBegin;
                col = tbMatrix[j].row;
                    temp_sum = 0;
               } else {
                    if (amatrix[i].col < tbMatrix[j].col) {
                         i++;
                    } else if (amatrix[i].col == tbMatrix[j].col) {
                         temp_sum += amatrix[i].value * tbMatrix[j].value;
                         i++;
                         j++;
                    } else {
                         j++;
                    }
               }
          }
          for (; row == (*(amatrix + i)).row; i++)
               ;
          rowBegin = i;
          row = (*(amatrix + i)).row;
     }
    (*resultMatrix).value = rIndex;
}

void storeValue(sparse_matrix *resultMatrix, int row, int col, int value, int *index) {
     if (value) {
          (*(resultMatrix + ++*index)).row = row;
          (*(resultMatrix + *index)).col = col;
          (*(resultMatrix + *index)).value = value;
     }
}

没有做太多错误边界的判断。计算结果:

初学乍练,如果有错误还望大家指出。这个乘法,OneCoder着实写了好久。算法的时间复杂度为:O(bColNum * aValueNum + aRowNum * bValueNum)。相对于传统的二维数组表示矩阵的计算来说,实现逻辑复杂好多。传统方式的时间复杂度为:O(aRowNum * aColNum * bColNum)。

阅读全文 »

MySQL 用户并发数限制问题解决

发表于 2013-03-15 | 阅读次数

对MySQL进行并发测试过程中遇到的一个小问题,记录一下。

用mysqlslap进行并发访问测试,在1024线程的时候报错:

bin/mysqlslap: Error when connecting to server: 1135 Can't create a new thread (errno 11); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug

Linux系统的open files数已经修改。当然仍然报错。ulimit -a命令,可查看当前系统限制情况

max user processes = 1024


通过ulimit -u 10000命令修改当前session的限制值,然后重启MySQL,问题解决。如果你想使此值永久生效,可配置在/etc/profile 中。

阅读全文 »

MySQL5.6.10 NoSQL API访问方式体验

发表于 2013-03-12 | 阅读次数

MySQL 近期发布5.6的GA版本,其中确实有很多不错的特性值得关注和尝试。NoSQL API的支持就是其中一个比较不错的亮点,我们这就来尝试一下。详细的特性介绍可访问:http://dev.mysql.com/tech-resources/articles/mysql-5.6.html 。

从MySQL官网了解到,通过Memcache的API即可访问MySQL的NoSQL API。

Many of the latest generation of web, cloud, social and mobile applications require fast operations against simple Key/Value pairs. At the same time, they must retain the ability to run complex queries against the same data, as well as ensure the data is protected with ACID guarantees. With the new NoSQL API for InnoDB, developers have all the benefits of a transactional RDBMS, coupled with the performance capabilities of Key/Value store.
MySQL 5.6 provides simple, key-value interaction with InnoDB data via the familiar Memcached API. Implemented via a new Memcached daemon plug-in to mysqld, the new Memcached protocol is mapped directly to the native InnoDB API and enables developers to use existing Memcached clients to bypass the expense of query parsing and go directly to InnoDB data for lookups and transactional compliant updates. The API makes it possible to re-use standard Memcached libraries and clients, while extending Memcached functionality by integrating a persistent, crash-safe, transactional database back-end. The implementation is shown here:


So does this option provide a performance benefit over SQL? Internal performance benchmarks using a customized Java application and test harness show some very promising results with a 9X improvement in overall throughput for SET/INSERT operations:

首先部署Server端的Memcache plugin集成环境。目前支持的系统为Linux, Solaris, and OS X,不支持windows。文档地址:http://dev.mysql.com/doc/refman/5.6/en/innodb-memcached-setup.html

由于我采用的tar包安装的MySQL,所以在安装memcache plugin的时候需要先安装libevent包。

yum install libevent

即可。

然后,安装libmemcached所需要的表

将插件设置成随服务启动而启动的守护插件

重启MySQL服务,安装完成。默认访问端口为11211。

下面来验证一下安装,简单的可以采用telnet的方式发送memcached命令

然后通过sql,在demo_test表中查询数据:

再通过Java代码操作一下,我们采用xmemcached作为client api。官方地址:https://code.google.com/p/xmemcached。Maven依赖:

<dependency >     
      <groupId >com.googlecode.xmemcached</groupId >
      <artifactId >xmemcached</artifactId >
      <version >1.4.1</version >
</dependency >

代码如下:

 /**
      * @param args
      * @author lihzh(OneCoder)
      * @blog http://www.coderli.com
      * @throws MemcachedException
      * @throws InterruptedException
      * @throws TimeoutException
      * @throws IOException
      * @date 2013 -3 -12 下午12:07:41
      */
     public static void main(String[] args) throws TimeoutException, InterruptedException, MemcachedException, IOException {
           MemcachedClient client = new XMemcachedClient("10.4.44.208" , 11211);
            // store a value for one hour(synchronously).
           client.set( "key", 3600, "onecoder");
            // Retrieve a value.(synchronously).
           Object someObject = client.get( "key");
            // Retrieve a value.(synchronously),operation timeout two seconds.
           someObject = client.get( "key", 2000);
           System. out.println(someObject);
     }

通过mysql客户端查询记录,成功存入:

这里测试的仅仅最基本的功能,如果想使用该功能,还需要做好传统数据表与memcache表的映射关系。具体可参考:http://dev.mysql.com/doc/refman/5.6/en/innodb-memcached-developing.html。

阅读全文 »

MySQL性能测试—前期知识储备

发表于 2013-03-08 | 阅读次数

今天是妇女节,先祝所有过节的女同胞们节日快乐:)

即将对MySQL进行性能测试。所以事先对MySQL的测试工作进行一番了解。主要考察性能测试的工具,MySQL的关键指标,以及一些基础的Benchmark数据,为测试用例和场景的规划做些准备。

先说说考量的指标(转载,网址找不到了,抱歉)

(1)QPS(每秒Query量)
QPS = Questions(or Queries) / seconds
mysql > show /*50000 global */ status like 'Question';
(2)TPS(每秒事务量)
TPS = (Com_commit + Com_rollback) / seconds
mysql > show status like 'Com_commit';
mysql > show status like 'Com_rollback';
(3)key Buffer 命中率
key_buffer_read_hits = (1-key_reads / key_read_requests) * 100%
key_buffer_write_hits = (1-key_writes / key_write_requests) * 100%
mysql> show status like 'Key%';
(4)InnoDB Buffer命中率
innodb_buffer_read_hits = (1 - innodb_buffer_pool_reads / innodb_buffer_pool_read_requests) * 100%
mysql> show status like 'innodb_buffer_pool_read%';
(5)Query Cache命中率
Query_cache_hits = (Qcahce_hits / (Qcache_hits + Qcache_inserts )) * 100%;
mysql> show status like 'Qcache%';
(6)Table Cache状态量
mysql> show status like 'open%';
(7)Thread Cache 命中率
Thread_cache_hits = (1 - Threads_created / connections ) * 100%
mysql> show status like 'Thread%';
mysql> show status like 'Connections';
(8)锁定状态
mysql> show status like '%lock%';
(9)复制延时量
mysql > show slave status
(10) Tmp Table 状况(临时表状况)
mysql > show status like 'Create_tmp%';
(11) Binlog Cache 使用状况
mysql > show status like 'Binlog_cache%';
(12) Innodb_log_waits 量
mysql > show status like 'innodb_log_waits';

其中QPS和TPS自然是重点考察的性能指标。其他指标可以作为每次测试数据的参考数据列出。如果遇到瓶颈,可能还需要考量当时系统的cpu,网络,磁盘的利用率情况。这个遇到具体问题再具体分析。

工具方面,首选考察的自然是MySQL自带的测试工具mysqlslap。

./mysqlslap -a --concurrency=50,100 --number-of-queries 1000 --iterations=5 --engine=myisam,innodb --debug-info -uroot -proot

一个简单的示例即可说明工具的使用情况,

-a 自动生成sql
--concurrency=50,100分别执行50,100并发,
--iterations=5 执行5次,引擎分别选用myisam和innodb引擎测试。

--number-of-queries    Limit each client to this number of queries (this is not
                      exact).(一个客户端执行的测试SQL数量上限,通过--only-print观察自动生成的sql的执行情况来看,该条数限制的是准备数据以外的SQL语句的条数)
--engine=myisam,innodb 分别用myisam和innodb引擎进行测试。

当然你也可以通过-q指定你想要测试的sql脚本,测试结束后,mysqlslap会给出你测试的相关数据。

关于mysqlslap的更多参数可参考:http://dev.mysql.com/doc/refman/5.1/en/mysqlslap.html
从目前来看上手还是比较容易的。通过执行的query数量和时间,很容易计算出tps和qps等指标。

SysBench

也是MySQL官网提到的一个benchmark工具。只是在64位系统下安装困难,限于网络环境和考虑到其功能和我们即将进行的测试场景,暂时放弃。

性能测试基础准备其他话题

在思考和验证怎样使用mysqlslap规划测试场景的过程中,收获到一些离散的细节问题,也在此一并记录一下。也许哪天,哪一条就会有所帮助。

打开MySQL general_log 记录执行的sql情况

默认情况下该属性是关闭的,通过set global general_log=ON 打开后,可在log文件中查看数据库执行的sql记录。该需求是OneCoder想要考察JDBC的batch insert的提交方式,究竟是数据库中是执行的多条insert然后commit还是一个insert values大列表的时候产生的。

对比批量插入数据 多条insert和一条insert 大values列表(values(),(),())方式,性能差别

从目前通过mysqlslap执行测试的效果来看,后者明显优于前者。前者1000条平均时间大约是0.2ms,而后者在0.1ms左右。该测试想法是在通过mysqldump到处已有数据的时候发现其sql文件的生成方式的时候以及联想到oracle到mysql的数据迁移工具的处理方式的时候想到的。

写入性能瓶颈的一个大误解

曾经极大的错误的认为单线程下mysql可处理的批量插入数据量就是该节点的瓶颈,所以只认为多线程并发写入优化只在NDB的环境下才有效。今天在看MySQL的一些benchmark图表曲线的时候,猛然惊醒,并发数和tps的曲线是类抛物线的就说明在一定并发数的范围内,TPS是有明显提高的。于是用以前的JDBC的代码,增加了几个线程,对同一个mysql并发写入,果然TPS成倍提升。

今天总结的大概就这么多,由于是事后回忆总结,不免有所遗漏,想起来再补充把。热烈欢迎指导。

阅读全文 »

MySQL Cluster写入效率测试

发表于 2013-02-27 | 阅读次数

MySQL Cluster使用到目前为止遇到渴望得到答案的问题,也是直接影响使用的问题就是MySQL Cluster的写入效率问题和Cluster是否适合大数据存储、如何配置存储的问题。

阅读全文 »
1 … 22 23 24 … 33
LiHongZhe

LiHongZhe

onecoder's blog.

326 日志
8 分类
RSS
Creative Commons
Links
  • 酷壳
  • 酸菜鱼
  • 私塾在线学习网
  • 煮酒品茶
  • 点滴技术博客
  • 思考者日记网·束洋洋
  • 开源视窗
  • 小弟子的网络之路
  • 寄存心–移动开发
  • TicmyBlog
  • 中国程序员人才网
  • 图表秀-在线图表制作
  • IT热血青年
© 2012 - 2022 LiHongZhe
由 Jekyll 强力驱动
主题 - NexT.Muse