月度归档:2016年09月

简要了解 MySql 5.5/5.6/5.7/8 出现的新特性

 

概述

中秋假期的前夕的9月12日,MySQL 8.0.0 放出了 Development Milestone Release。是开源数据库的一大新闻。

要知道MySQL的上一个版本号仅仅是 5.7。在MySQL归属于Oracle公司之后,版本号的飞速提升也开始了,按此趋势,预计不日将会赶超Oracle自家商业数据库产品……

发布之际,简要的了解和比较一下 MySQL 5.5/5.6/5.7/8 之间的区别和特性。

如有错误,烦请指出。

MySQL的开发周期

在比较之前,首先提一下MySQL的开发周期.

MySQL一个大版本的开发,大致经历如下几个阶段:

  • Feature Development
  • Feature Testing
  • Performance Testing
  • Lab Releases
  • Development Milestone Releases
  • General Availability Release(GA)

Feature Development

也即是所谓的特性开发阶段。这个阶段是常规的功能点确定,代码开发,完成CR以及QA等常规的开发流程。

在一系列的测试以及bugfix之后,当QA “signs off” 即测试通过之后,会合并到TRUNK之中。

Feature Testing

即特性测试阶段。

特性测试的阶段,从质量保证的角度出发,MySQL的测试工作将会有以下的关注点:

  • 完成新特性的基本测试工作
  • 未出现性能衰减/特性的倒退
  • 至少达到80%的代码覆盖率

一个新特性达到要能被合并到TRUNK之中,需要满足如下条件:

  • 没有任何已知的错误,包括那些微小的错误
  • 没有任何已知的性能衰减/特性的倒退
  • 代码覆盖率达到预期
  • 自动化测试集中需要有这一新特性的回归测试用例

Performance Testing

作为应用的基础组件,性能是绝大多数开发人员都在关注的问题。在特性测试完成之后,将要进行的是性能测试。

性能测试主要关注两个指标:吞吐量和响应时间。

针对于吞吐量的测试,会有如下的特点:

  • 并发测试范围从8到1024个连接
  • 使用诸如sysbench这类开源软件,进行简单OLTP(基本的事务处理)的测试,每个测试时间在5-10min范围内,随着数据集以及系统配置而定
  • 针对特定场景也会有相应的测试用例
  • 测试数据会被存储到数据库中,以便比较或者确定测试的基准值

而对于响应时间的测试,则会有如下的特点:

  • 在单个被测试线程上完成测试
  • 准备两方面测试用例,分别考验计算复杂型场景和IO密集型场景

Lab Releases

实验室发布是在用户对某一特性有着强烈的兴趣时,发布的快照版本,通常还没有合并到TRUNK之中。

实验室发布版本存在的特性,并不会保证在正式版等版本中存在。如果想要尝鲜,可以访问labs.mysql.com。

Development Milestone Releases

上述步骤结束之后,到了DMR阶段,也就是本次 8.0 版本所处的阶段。

DMR将会是一个重复迭代的阶段,下一个DMR版本将会包含上一个DMR版本的新特性或者功能修复。并且,DMR了的MySQL将会支持所有的平台,DMR状态下的MySQL的代码质量是达到了可供发布的水准的。

DMR看起来像是游戏的公测版本,每3-6个月会发布一个版本,每个DMR版本的MySQL会有一个特性需求收集截止时间点,新增的特性会历经开发、测试的历程,合并到TRUNK之中,变为下一个DMR。

总之,DMR的目的就是能够时常发布,让用户和客户能够反馈需求,体验新版本。

General Availability Release(GA)

终于,在n个DMR之后,MySQL表现稳定,需求“无可”增加,客户满意,质量过关。

基于最后一个DMR版本,会发布GA版本,即我们可以“放心”使用在生产环境中的MySQL。

每个GA版本的发布周期间隔在18-24个月。

版本比较

对于这些MySQL版本,如果想要了解之间的差异,一个可行的办法是阅读GA版本的Release Notes。

MySQL 的近几个版本发行时间间隔并不太大:

版本 GA 版本发布时间
5.5.8 2010-12-03
5.6.10 2013-02-05
5.7.9 2015-10-21

大约2年会有一个较大更新的版本会发出。

新特性

对于使用者而言,新特性应该是关注的第一焦点。下面会针对版本列出一些个人认为有特点的新特性。

5.5

InnoDB 作为默认存储引擎

InnoDB 因为支持事务、行级别锁而广为人知,并广泛应用。但是在之前的版本中,InnoDB并不是默认的存储引擎。在5.5中,InnoDB成为了默认的存储引擎。

半同步复制

半同步复制(Semisynchronous Replication)在MySQL 5.5中被支持(以插件形式实现)。

默认的MySQL通过异步模式进行复制,主库写入binlog之后,从库不一定能够被读取并处理,因为写入成功只是说明在主库上成功。主从不同步带来的问题相当之多,提升了开发难度。

而半同步复制则是主库需要有至少一个半同步从库,当一次写入操作进行之后,至少在主库和至少一个半同步从库上都完成了写入之后,用户才会收到已成功的信息。

半同步复制在这一程度上提高了数据的安全性。

5.6

MySQL 5.6 的主要变化在性能优化方面。有一些小的新特性也值得关注。

表中可以设置多个Timestamp属性

MySQL 5.5 中,如果设定多个Timestamp的属性为 ON UPDATE CURRENT_TIMESTAMP 时,这样的操作是不能完成的,这样的需求,通常要在业务代码中完成。

而到了 MySQL 5.6 中,这样的操作可以直接通过设定字段的属性即可完成。

InnoDB 支持全文索引

全文索引 MyISAM 存储引擎之前相对于InnoDB的一个“优势”特性,在MySQL 5.6中不复存在。

针对字符串型的字段(CHAR,VARCHAR或者TEXT),可以选择在创建表时增加这个类型的索引。也可以后续添加。

InnoDB的全文索引也使用的是倒排索引的设计,分词完成的词汇将会存储在独立的索引表之中。当包含全文索引的字段插入之后,会进行分词,同时先将分词结果进入内存缓存,之后再刷入索引表中,避免一次写入带来的大量附加的小规模的更改操作。

多线程复制

在MySQL 5.6中,会针对每一个数据库开启一个独立的复制线程,如果数据库压力平均的话,对于主从同步延迟会有一定的改善。但是如果数据操作都在一个数据库上,就不会有太多显著的效果了。

加入全局事务ID(GTID)

在MySQL 5.6前,如果从库宕机,重启之后需要进行同步,需要知道binlog文件名已经位置。

在MySQL 5.6中,加入了GTID(global transaction identifier)。GTID由source_id和transaction_id构成,source_id标识主库,transaction_id标识在数据库上进行的事务,格式即GTID = source_id:transaction_id。

在加入GTID之后,重启从库之后,不需要重新进行位置的指向,只需要连接到主库即可,剩下的步骤将会是自动的。

5.7

InnoDB

InnoDB地位进一步增强,这一次系统表已然变成了基于InnoDB存储引擎的表。并且也不能禁用InnoDB存储引擎了。

增强的多线程复制

在5.6中添加的多线程复制的增强版,针对每个数据库可以增加线程数进行同步,对5.7.9版本,在实际使用中,在机械盘的服务器上,原有业务高峰时主从同步延迟在10-30分钟左右,使用5.7.9之后基本实现了数据上的同步。

多源复制

即将多个主库的数据归并到一个从库的实例上。

之前的MySQL,每个从库都只能拥有一个主库,如今MySQL提供了官方的解决方案,用于将多个主库的数据同步到一个从库之上。

多源复制有一个关键概念,即频道(channel)。频道指代一个主从库之间用于同步binlog的连接,通过新增的FOR CHANNEL子句,指定一个非空的频道名称,按照先前版本的连接主库的方法,即可实现多源复制功能。

需要注意的是,当多个主库均写入同一张表时,是要自行处理主键冲突。

JSON数据类型操作

PostgreSQL 9.3开始,PostgreSQL中JSON成为了内置的数据类型。

作为被广泛使用的数据组织格式,之前版本的只能讲JSON格式数据按照字符串形式进行存储。

到了5.7之后,JSON支持也被加入。

JSON中的字符串在MySQL中会被转化成utf8mb4的字符集,给携带诸如emoji字符的数据的存储带来了方便。

对于JSON数据的结构特性,MySQL中对JSON的查询需要借助path expression以及JSON_EXTRACT方法进行查询。path expression的简要要点如下:

  • 以$符号开头
  • .符号紧接着的是对象中的key
  • [n]中表示的是数组中的第n个元素,n>=0
  • .[*]表示一个key下的所有对象
  • [*]表示一个key下所有的数组
  • exp_a**exp_b则表示path中带有exp_a与exp_b的值
  • key如果包含特殊字符,需要通过双引号包裹起来

更多操作参见手册。

innodb_buffer_pool_size参数动态修改

在之前的版本中,innodb_buffer_pool_size调整之后,需要重启数据库实例,这个对于线上业务几乎是不可接受的。硬件性能强悍的服务器,调整这一参数之后,MySQL的表现会有较为客观的提升。

到了MySQL 5.7,这一参数终于可以在线调整了。

初始化工具

在之前的版本中,初始化系统表一般都会使用mysql_install_db脚本,到MySQL 5.7之后建议使用mysqld --initialize完成实例初始化。

在通过mysqld --initialize进行初始化时,需要加上--initial-insecure才能实现空密码登录,否则会将初始化的默认密码写入到错误文件中。

初始化完成之后,还需要使用MySQL 5.7版本的客户端登录,并且修改默认密码。

8.0

作为版本号突飞猛进的一个版本,在MySQL 8.0中新增了如下的特性:

用户角色

8.0中将会增强账号管理的功能,提供角色这一概念,即能组合权限,批量授权给某一用户。

增强的InnoDB

  • 自增id会写入到redo log中,这一改动使得数据库重启之后的自增值能恢复到重启前的状态
  • 增加了死锁检测开关innodb_deadlock_detect,可以在高并发系统中动态调整这一特性,提升性能

增强的JSON操作

  • 增加了->>操作符,使用这一操作符等同于对JSON_EXTRACT的结果进行JSON_UNQUOTE操作,简化了SQL语句
  • 增加了按JSON数据组织返回数据操作的两个方法:JSON_ARRAYAGG与JSON_OBJECTAGG。JSON_ARRAYAGG将某列的值按照一个JSON数据返回,而JSON_OBJECTAGG将列A作为键,列B作为值,返回一个JSON对象格式的数据

后续将会继续更新本文。

相关

[1]: What’s New in MySQL 5.7? (So Far)

InfluxDB使用笔记

 

概述

InfluxDB是 InfluxData 公司发布的一款开源时序数据库产品。

关于时序数据库,除了常用的ElasticSearch之外,InfluxDB也是一个选择。

InfluxDB 使用 go 语言编写。个人认为几个外在的优点在于:

  1. 无特殊依赖,几乎开箱即用(如ES需要Java);
  2. 自带HTTP管理界面,免插件配置(如ES的kopf或者head);
  3. 自带数据过期功能;
  4. 类SQL查询语句(再提ES,查询使用自己的DSL,虽然也可以通过sql插件来使用类SQL进行查询);
  5. 自带权限管理,精细到“表”级别;

这些好处官网都有提及。

关键概念

手册中对这些名词有了详细的定义,这里稍微提及一下。

time

Time 在 InfluxDB 中的每一行数据中都会存在。

Time 即数据生成时的时间戳。

类比更为熟悉的 MySQL 来说,InfluxDB 中的 Time 几乎可以看做是主键的代名词了。

field

Field 在 InfluxDB 中是必须的数据的组成部分。

Field 未被索引。这意味着如果查询field的话将会扫描所有数据,找出匹配项;手册上也建议不要在field中存储将会频繁查询的数据(存储区分度更高的数据)。

类比 MySQL,Field 可以看做没有索引的列。

tag

Tag 在 InfluxDB 中是可选的数据组成部分。

不同于 Filed,Tag 的数据会被索引。

类比 MySQL,Tag就是有索引的列。

measurement

InfluxDB 是时序数据库,时间数据 time 与 Tag 以及 Field 组合成了 Measurement。

类比 MySQL,Measurement可以看做的是表。

retention policy

应用程序记录日志的情况下,如果没有关注,很有可能会出现打爆硬盘的情况出现。运维同学一般会在服务器上部署自动清理脚本。

在InfluxDB中,合理的设置了 Measurement 的 Retention Policy 的情况下,无需太过担心磁盘被打爆的情况。

Retention Policy 可以看做是数据清理策略。基础应用个人认为应该关注如下的一些参数:

  • DURATION,即保存时间,有 m h d w INF几种,即分,小时,天,周以及无限(Infinity);
  • REPLICATION,即副本数,即会有多少份副本保留在集群之中。

point

Point 即同一时间戳产生的数据的集合。

series

Series 表示Measurement、Retention Policy、Tag都相同(tag的名称与值)的一组数据,Field不在考虑衡量范围之内。

基本操作

基本操作简单提及数据的 CURD 以及数据库管理方面的一些使用方式。

CURD

CREATE

在已创建数据库的前提下,新增数据,可以通过两种基本的方式进行数据的写入:

  • CLI
  • InfluxDB HTTP API

CLI

CLI 自然与 MySQL 类似,通过 InfluxDB 提供的 CLI 工具,使用类 SQL 语句进行写入。

但是 CLI 毕竟不是使用 InfluxDB 作为后端存储的好方式,InfluxDB 也提供了非常方便的HTTP API 供开发者们使用。

InfluxDB 的特点是无结构的,即文档中提到的 schemaless,可以随时的动态增添数据域和表,所以使用时直接写入,无需考虑关系型数据库中类似建表等过程。

不过,CLI 虽然不能做到随时随地的的使用,但是类 SQL 语句还是在特定场景下还是有应用空间的(例如使用默认的Web管理端)。

CLI 写入数据时,语法相当简单,只需要使用:INSERT 数据 这样的语句即可。但是数据部分有InfluxDB自己的一些协议,目前在使用的规则叫做 Line Protocol。

Line Protocol

文档中已有详细描述,这里总结一下,简单来说,个人认为可以关注如下的特点:

  • 第一个字段是表名
  • 如果有tag,表名之后使用英文逗号分隔,以k=v的方式逐个列出
  • field在前两部分之后,用空格分隔开,之后所有的field,也使用英文逗号分隔,以k=v的方式逐个列出
  • 如果要指定时间戳,那么在field之后,通过空格分隔,将纳秒级别的时间戳写入
  • 在 tag 的键,值,以及 field 的键中包含, 、= 以及空格的,需要进行转义(变为\, \= \),field 的值可以通过 英文双引号 包裹起来(但是双引号决定了这个值必然是一个字符串)
  • 数据分为 string int64 float64 boolean 几种类型
  • string 最大存储的长度为64KB
  • float64 是默认的的类型,如果整数值要存成整数,需要在数字后通过字母 i 标明

InfluxDB HTTP API

InfluxDB 启动后,会默认监听 8086 端口,在这一端口上可以通过 HTTP POST 的方式,请求 /write ,写入数据。

写入方式手册已很清楚,即将 Line Protocol 格式的的数据提交到 InfluxDB 之上。

需要注意的是,InfluxDB 在通过HTTP方式操作时,需要注意下HTTP的状态码,尤其要注意204这一状态码,InfluxDB在返回这一状态码时认为请求合理但是并未完成,当返回这一个数值是需要注意HTTP的body段中附加的错误信息。至于4xx与5xx则是真的存在错误的情况。

时序相关

既然是时序数据库,那么时间作为重要的维度需要单独一提。

通过 Line Protocol 写入数据时,如果没有指定时间,将会根据系统时间指定时间,所以手册中提到:

If you do not specify a timestamp for your data point InfluxDB uses the server’s local nanosecond timestamp in UTC.

这个和 ES 的默认行为不太相同,所以这里需要注意。

如果要人工指定时间,需要按照 RFC3389 里提及的格式指定,即指定一个ns级别的时间戳,形如1465839830100400200。

RETRIEVE

与 CREATE 这一动作相同,数据的获取同样可以通过在 CLI 中执行InfluxQL(即InfluxDB中定义的类 SQL 语言),或者通过 HTTP API 提交查询语句的方式进行。通过 HTTP API 访问的话,InfluxDB会返回JSON格式的数据。

InfluxDB使用类 SQL 语言进行查询,确实是降低了使用的门槛,类似 SQL 的 SELECT GROUP BY LIMIT ORDER BY 操作的用法参见手册。

GROUP BY

值得一提的是,作为时序数据库,InfluxDB在查询上有一些时间相关的操作,例如 GROUP BY 操作可以按照时间戳进行聚合,获得每个时间片级别上的聚合数据。即通过 GROUP BY time(interval) 方法进行聚合,interval 即支持的时间片,支持的范围有:

时间片单位 范围
u 微秒
ms 毫秒
s 秒
m 分钟
h 小时
d 天
w 周

比如 time(3d) 表示按照3天作为周期进行聚合。

同时 fill() 方法也是一个有意思的功能,使用 GROUP BY 之后,如果某个聚合的结果内没有值,可以通过 fill() 设定为自己需要的值。更详细的用法参见手册。

INTO

如果说上述的的一些操作看起来和平常使用的关系型数据库没有特别大的区别的话,我想从 INTO 开始,InfluxQL就体现出时序数据库的一些特点了。

比如机器性能数据的采集,数据点多了之后,很可能我们期望能够看到的不是单一时间点上的数据,而是机器阶段性的表现和趋势,这样的数据自然可以通过聚合具体的采集数据获得,但是为什么不直接读取已经聚合完成的数据并展现呢?重复的计算是对机器性能的巨大浪费。

通常情况下,我们可能需要编写程序完成这样的工作,但是在InfluxDB中,可以通过内置的 INTO 语句来完成,无需额外的工作。

结合手册中的例子:

即在2015-08-18T00:00:00Z到2015-08-18T00:30:00Z的时间范围内,将每12分钟在santa_monica区域的水位的平均值存入average表中。

如是,如果要了解平均值,无需重复计算原始数值。

对于实际业务来说,统计接口PV/UV的场景很适合使用这一个子句,因为阶段统计中,并不关心具体的访问用户,而是期望了解趋势(对于UV的定义需要结合实际的业务场景)。

LIMIT & SLIMIT

LIMIT 限制的是数据的行数,而 SLIMIT 限制的则是返回的 Series 的个数,如果二者都要限制,则先设定 LIMIT,之后再设定 SLIMIT。

OFFSET & SOFFSET

分页是查询数据的一个基本方式,InfluxQL中通过 OFFSET 以及 SOFFSET 进行。

类似 LIMIT & SLIMIT, OFFSET 是针对数据行的翻页,SOFFSET 是针对 Series 的翻页。

时序相关

时序数据库,自然查询的数据经常会与时间有关。前面提及的时间单位,在选定时间范围时,可以通过组合简化时间区间的确定。

例如选出当前时间前3天到5小时前的数据,那么只需要指定条件为time >= now() - 3d AND time < now() - 5h即可。

如果你愿意,也可以与 RFC3339 格式的时间做对比。

UPDATE & DELETE

InfluxDB不存在常规意义上的 UPDATE 和 DELETE 这些动作!需要注意!

InfluxDB的设计初衷是为了记录时序相关的数据,这些数据被认为是不常变的,并且是仅仅有一次写入操作的(瞬时应当是唯一的)。

综上,InfluxDB期望通过牺牲了数据的灵活性,换取了更好的写入与查询性能。

实例:grahios使用InfluxDB作为后端

grahios 是一个将 Nagios 性能数据,使用不同的后端数据收集工具(or 时序数据库)进行收集的工具。在之前的笔记 使用Grafana+InfluxDB展示Nagios监控数据 之中有所提及。

graphios 使用 InfluxDB 作为存储后端,首先完成的步骤,是将 PERFDATA 解析,之后按照 Line Protocol 拼装,发送到后端。

由于 InfluxDB 是 Schemaless 的,所以 graphios 无需进行提前建表这一操作,直接发送数据即记录。

比较让我关心的是 Line Protocol 的运用,参见提交 sha 值为 02098f 的 graphios_backends.p 的文件的667行的 format_metric 方法:

生成Measurement

使用了 Line Protocol 的情况下,输入变量path将会作为 Measurement的名称,这里的 path 即 Nagios 中的 HOSTCHECKCOMMAND 或者 SERVICEDESC Macro 的值,即检测服务的名称。例如磁盘就是 Disk。

生成Tags

所有的检测数据都会作为 tags 存在,目的应是便于查询。检测数据的格式形如:

DISK OK – free space: / 3326 MB (56%); | /=2643MB;5948;5958;0;5968

/ 15272 MB (77%);

/boot 68 MB (69%);

/home 69357 MB (27%);

/var/log 819 MB (84%); | /boot=68MB;88;93;0;98

/home=69357MB;253404;253409;0;253414

/var/log=818MB;970;975;0;980

橙色部分是 PERFDATA,将会被解析成Tags所需的格式:

/=2643MB,/boot=68MB,/home=69357MB,/var/log=818MB

由于 Nagios 中 / 一般被设定为需要转义的字符,所以,写入数据库是,可能会被转换为:

_=2643MB,_boot=68MB,_home=69357MB,_var_log=818MB

至于比如 PERFDATA 中的 WARNING CRITICAL 等标识去哪里了,可以看到提交 sha 值为8aa93b 的 graphios.py 文件的358行的 process_log方法,文件387行开始:

说明了实际上原始日志处理过后,只会有等号后的第一个数据存在。

生成Fileds

由于 Fileds 是InfluxDB数据不可缺少的一部分,但是实际上,由于没有索引的原因,查询时的成本比较大,所以 graphios 把 PERFDATA 的value作为数据的一个field value记录,个人任务因为这个value并没有足够的细节,具有足够的细节的数据已都做为tag存在。

生成时间戳

由于需要ns级别的时间戳,所以需要在检测的时间戳上乘以特定倍数即可。

查询

查询的工作,则交给Grafana这类专业的数据展现工具完成。

小结

以上是InfluxDB的基础使用笔记,数据库的诸如认证,部署,集群,以及使用上的如降采样(Downsampling)预计将会在后续笔记中提及。