Elasticsearch 中的 `文档`,`索引`,`节点`,`分片`

对Elasticsearch中常用的文档索引节点分片做出一些介绍和解释。清楚一些入门的基础概念。

文档

  1. 可被搜索最小单元
  2. 理解成关系型数据库一条记录
  3. json对象组成

格式

名称 解释
_index 文档所属的索引名
_type 文档所属的类型名
_id 文档唯一ID
_source 文档原始的json数据
_all 整合所有字段内容到该字段
_version 文档的版本信息
_score 相关性打分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"_index" : "moves",
"_type" : "_doc",
"_id" : "253",
"_version" : 1,
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"title" : "Interview with the Vampire: The Vampire Chronicles",
"year" : 1994,
"id" : "253",
"@version" : "1",
"genre" : [
"Drama",
"Horror"
]
}
}

索引

  1. 索引是文档的容器,是一类文档的集合
  2. index体现了逻辑空寂的概念,每个索引都有自己的Mapping定义,用于定义包含的文档的字段名和字段类型
  3. shard 体现了物理空间的概念:索引中的数据分散在shard上

Mapping 定义文档字段的类型
Setting 定义不同的数据分布(分片)

RDBMS ES
table index(type)
Row Doucment
Column Field
Schema Mapping
SQL DSL

相关操作

//查看索引相关信息
GET index_name

//查看索引的文档总数
GET index_name/_count

//查看前10条文档,了解文档格式
POST index_name/_search

//_cat API

查看indices
GET /_cat/indices/kibana*?v&s=index

节点

Master-eligible 和 Master

  • 每个节点启动后,默认就是一个Master eligible 节点
    • 可以设置node.master:false 禁止
  • Master-eligible节点可以参加选主流程,成为Master
  • 当第一个节点启动时,它会将自己选举成Master节点
  • 每个节点上都保存了集群的状态,只有Master节点才能修改集群的状态休息
    • 集群中必要的信息
      • 所有节点信息
      • 所有索引和其他相关的Mapping/Setting
      • 切片的路由信息
    • 任意节点都能修改信息会导致数据的不一致性

Data Node

  • 可以保存数据的节点,负责保存分片数据。

Coordinating Node

  • 负责接受Client的请求,将请求分发到合适的节点,最终把结果汇集到一起
  • 每个节点默认都起到了 Coordinating Node 职责

Hot & warm Node

  • 不同硬件配置的Data Node,用来实现 Hot & Warm 架构,降低集群的部署成本

Machine Learning Node

  • 负责排机器学习的job,用来异常检测

配置节点

  • 开发环境一个节点可以承担多个角色
  • 生成环境中,遵循单一职责原则
节点类型 配置参数 默认值
maste eliginle node.master true
data node.data true
ingest node.ingest true
Coordinating only 每个节点模式都是Coordinating
Machine Learning node.ml true (需要 enable x-pack)

分片

  • 主分片,用来决定数据水平扩展的问题。通过主分片,可以将数据分布到集群内所有节点上
    • 一个分片是一个运行Lucene的实例
    • 主分片数据索引创建时指定,后续不允许修改,除非Reindex
  • 副本,用来解决数据高可用的问题。分片是主分片的拷贝
    • 副本分片数,可以动态调整
    • 增加副本数,还可以再一定程度上提高服务的可用性(吞吐)

设定

  • 对于生成环境中分片的设定,需要提前做好容量规划
    • 分片数设置过小
      • 导致后续无法增加节点实现水平扩展
      • 单个分片的数据量太大,导致数据重复分配耗时
    • 分片数过大,7.0开始,默认主分片设置1
      • 影响搜索结果的相关性打分,影响统计结果的准确性
      • 单个节点上过多的分片,导致资源的浪费,影响性能

查看集群状态

1
GET /_cluster/health

MySQL误操作的语法与回滚

前段时间我们有个开发同学写了一条更新语句没有加上where条件更新了全库,后来通过了阿里的DTS进行了恢复。但是这个也勾起了我的好奇,如果是自建的系统我们该如何通过binlog恢复数据呢,我们又该怎么预防这些毁灭性的语句呢

几种情况

  • delete误删数据行
  • drop table 或者 truncate table
  • drop database

预防

不带where条件的预防

在update | delete 时候经常有小机灵不带where条件的情况,这种场景下mysql设置了安全模式。

1
2
//查看是否打开安全模式
SHOW VARIABLES LIKE '%sql_safe_updates%'

全局设置安全模式

对新打开会话生效,重启数据库失效

1
set global sql_safe_updates  = 1 | 0  ; 

当前会话设置

1
set sql_safe_updates  = 1 | 0  ;  

重启后也生效的方案

Server System Variables
MySQL的系统变量貌似不能在配置文件中进行修改,但是可以在重启的时候启动一个init脚本变相实现

  1. 在mysql.cnf下添加
1
2
#init
init-file='/etc/mysql/conf.d/init.sql'
  1. init.sql 写入
1
set global sql_safe_updates  = 1;
  1. 重启数库

误删行的恢复

MyFlash,美团的一个开源产品,使用它是因为中文文档够详细它级基本原理也有说明介绍。而且它自持表级的回滚和按语句的回滚

安装

  1. 下载源码
    1
    git clone git@github.com:Meituan-Dianping/MyFlash.git
  2. 进入MyFlash/binary测试
    1
    ./flashback -h
  3. 如果能正常参看到帮助信息,设置软链接
    1
    ln /usr/local/src/MyFlash/binary/flashback  -s /usr/bin/

配置 binlog

1
2
3
4
5
6
7
8
9
10
11
12
log_bin=ON
log_bin_basename=/var/lib/mysql/mysql-bin
log_bin_index=/var/lib/mysql/mysql-bin.index

或者

log-bin = bin-log
binlog_format = row #行的日志格式

重启

service mysqld start

查看是否配置成功

1
show variables like '%log_bin%'

测试MyFlash

  1. 进入binlog目录
  2. flashback --binlogFileNames=./bin-log.000001
  3. 执行闪回文件
    1
    mysqlbinlog --skip-gtids  binlog_output_base.flashback | mysql --socket=/var/lib/mysql/mysql.sock test
    如果出现
    1
    mysqlbinlog: unknown variable 'default-character-set=utf8'

那么屏蔽mysql配置里的

1
#default-character-set = utf8
  1. 回滚
    1
    mysqlbinlog --skip-gtids  binlog_output_base.flashback | mysql --socket=/var/lib/mysql/mysql.sock test

误删表/库

误删表库的操作binlog日志可以恢复DML,但是DDL就GG了。

恢复

恢复表/库需要做的是做定期的数据库备份

  1. 取最近的一次全量备份
  2. 用备份恢复出一个临时库
  3. 从binlog日志里取出0点以后的数据
  4. 把这些日志进行回放

ps.为了加快回滚速度可以知道相应表/库的数据进行恢复

其他手段

延迟备份

这个我一直认为是我和运维同学意淫出来的功能,后面查了下才知道MySQL5.6后已经支持了这个配置 CHANGE MASTER TO MASTER_DELAY。但是这个配置在自建集群中可以灵活配置,在一些云产品中就可能存在设置不了的情况了。

规范的数据库流程/权限/操作规范

  1. 做到权限最小化,只给业务开发DML权限,DDL可以走工单
  2. 删除数据表之前先对表进行改名操作,然后观察一段时间确保吴影响
  3. 改表名加固定后缀,并且管理员只能删除固定后缀的表

未来一年的小计划

7-9月随笔总结

2019年09月25日

  1. Mysql知识基本OK了
  2. GO语言算入门
  3. 网络协议提高学习优先级
  4. 同步GO 实现网络协议
  5. Elasticsearch需要,但手册完善暂无需求推动可以滞后
  6. 算法很重要,但回报较后。延迟

so

名称|优先级|学习渠道|预计耗时|2019年09月25日备注
:-:|:-:|:-:|:-:|:-:|:-:|
网络协议(TCP)|P1|书《TCP/IP羊皮书》|2019年10月-11月(2个月)|优先
GO语言网络编程|P1|结合协议 GO语言实现|2019年10月-11月(2个月) |优先
Elasticsearch|p2|光头的教程/文档/笔记|2020年01月(1个月)| 项目组尝试切换搜索引擎切换

过去 7-9月

  • 强化数据库方面知识
  • GO语言上手
  • Elasticsearch 了解大概用法

7月学习计划拟定

整理了下未来一年的学习计划,虽然不一定全搞定,但是总比没目标强。

时间:2019年6月24日-2020年6月24日
目标:夯实基础,扩宽知识面

基础知识

名称|优先级|学习渠道|预计耗时|2019年09月25日备注
:-:|:-:|:-:|:-:|:-:|:-:|
MySQL|P1|丁奇专栏|2019年6月-7月(2个月)|完成
操作系统|P2|书,专栏,教程|2019年8月-9月(2个月)|滞后
网络协议(TCP)|P2|书|2019年8月-9月(2个月)|优先
算法|P3|王争专栏|慢慢来|滞后

服务软件

ps:每月一个招聘网站上出现评率最高的软件使用,至少撸完文档。

名称 优先级 预计耗时
redis P1 2019年7月(1个月)
Nginx p1 2019年8月(1个月
kafka p1 2019年9月(1个月)
MongoDB P2 2019年10月(1个月)
Elasticsearch P3 2019年11月(1个月)
KIBANA p4 2019年12月(1个月)

技能扩展

名称|优先级|时间|2019年09月25日备注
:-:|:-:
GO|P1|抽空|优先-> web开发搞定,网络编程入手
前端|P2|抽空|

坚持

每天坚持看一小节PHP官方英文文档

幻读和间隙锁

幻读REPEATABLE-READ 重复读 隔离级别下发生在当前读场景,因为重复读有快照这一概念。既事务启动后的第一个语句创建快照,重复读也是默认的隔离级别,因此幻读是一个比较重要的点了。下面会结合或者照搬网络资料的一些案例来加深理解。

数据场景

表结构

1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE `t` (
`id` int(11) NOT NULL,
`c` int(11) DEFAULT NULL,
`d` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `c` (`c`)
) ENGINE=InnoDB;

insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20),(25,25,25);

幻读

下面的场景只是脑补,MySQL上的反馈不会和下面一样(MySQL真正运行这些语句有间隙锁来解决下面这些问题),因此实验时并不会真实的发生。

- session A session B session C
T1 begin;
select *from t where d = 5 for update;
result(5,5,5)
T2 update t set d=5 where id =0;
T3 select *frorm t where d = 5 from update;
result(5,5,5)(0,0,5)
T4 insert into t values(1,1,5);
T5 select *frorm t where d = 5 from update;
result(5,5,5)(0,0,5)(1,1,5)
T6 commit
  1. 在session A 中的几条select *frorm t where d = 5 from update;都是加了写锁的SQL语句,他们都使用了当前读
  2. 因为写锁在加的时候还没有相应的数据,所以session B/C的更新个插入操作都没有阻塞
  3. T5的select属于幻读,T3的不是。事务在前后两次查询同一个范围的时候,后一次看到了前一次查询没看到的行是幻读,幻读针对的是新插入的行,而不是当前读改变的行数据

幻读的问题

破坏语义

- session A session B session C
T1 begin;
select *from t where d = 5 for update;
T2 update t set d=5 where id =0;
update t set c=5 where id =0;
T3 select *frorm t where d = 5 from update;
T4 insert into t values(1,1,5);
update t set c=5 where id =1;
T5 select *frorm t where d = 5 from update;
T6 commit

在session B/C 中新加的2句SQL就是破坏了session A 中的语义,for update写锁,不让修改加锁的数据。但是在加锁时session B/C的数据还没有,语句破坏了for update不让修改的加锁声明

破坏数据一致性

- session A session B session C
T1 begin;
select *from t where d = 5 for update;
update t set d =100 where d =5;
T2 update t set d=5 where id =0;
update t set c=5 where id =0;
T3 select *frorm t where d = 5 from update;
T4 insert into t values(1,1,5);
update t set c=5 where id =1;
T5 select *frorm t where d = 5 from update;
T6 commit

分析结果 数据结果

session A : (5,5,100)
session B : (0,5,5)
session C : (1,5,5)

从上面来看数据是没问题的,那么我们的binlog日志该如何记录呢

如果保持隔离不加锁

1
2
3
4
5
6
7
8

update t set d=5 where id =0;
update t set c=5 where id =0;

insert into t values(1,1,5);
update t set c=5 where id =1;

update t set d =100 where d =5; //`这句会破坏数据一致性`

这份binlog回滚后数据明显不对,update t set d =100 where d =5 同时更新了 session B 插入的那一句,回滚结果出现了不一致pass。


如果把seesionA扫描过程中的语句都加写上锁 d = 5 那么SQL执行顺序如下

1
2
3
4
5
6
7
8
9

insert into t values(1,1,5);
update t set c=5 where id =1;

update t set d =100 where d =5;//这句又有问题了

update t set d=5 where id =0;
update t set c=5 where id =0;

这份binlog回滚后数据,d=5的这一次更新又会造成数据的不一致。

间隙锁(gap lock)

行锁只能锁住行,但是新插入记录这个动作要更新的是记录之间的间隙,因此,为了解决幻读,InnoDB引入了间隙锁这个概念,并且间隙锁是在可重复读下的产物

MySQL 优化的谚语

MySQL在优化的时候有很多需要注意的知识点,但是有的展开去记录的确会占用太多的篇幅,这边做了一些一句话就可以描述出来的知识点。后面的知识点也是只需点一下就可以回忆起来的。

  1. 查询条件做函数运算会用不到索引
  2. 数字和字符串做比较,会默认吧字符串转化为数字。
  3. show processlist 可以查看当前状态下锁和事务的情况
  4. 在事务中 select 在一条长事务后 或者 大量 update 后查询会为保持一致性读会回滚 更新后的数据
  5. lock in share mode 隔离级别是当前读

mysql order rand 性能优化

往往是一些不起眼的东西更暗含玄机,记得以前有个这样的需求,在网站首页给用户随机推荐词库中的10个热门行业词,而且每一次都要不一样。我们使用了最简单的实现方式,MySQL里order by rand() 排序取出前10个。但是上线后发现这样写的性能尤其底下。

场景

表结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14

create table words
(
id int unsigned auto_increment
primary key,
class_name varchar(255) not null comment '分类名称',
pid int null
)
comment '行业词库';

create index words_class_name_index
on words (class_name);


SQL 语句

1
explain  select pid,class_name from words order by rand() limit 3

rand

这里的 Extra Using temporary 使用临时表 Using filesort 使用排序

临时表

临时表分为内部临时表和外部临时表,内部临时表是属于一种轻量级保持在会话中的表结构,它一般是用于性能优化的。外部临时表用于一些特性的业务场景(我还没找到这个场景)。减少临时表的使用可以有效的提高SQL查询的效率

外部临时表

创建

1
2
3
4
5
6
7
8
create temporary table words_temp
(
id int unsigned auto_increment
primary key,
class_name varchar(255) not null comment '分类名称',
pid int null
)
comment '行业词库临时表';

修改

1
insert into words_temp values(1,'test',1);

查找

1
select * from words_temp

注意事项

  1. 账号有建立临时表的权限
  2. 不能多次关联临时表
  3. 临时表活在连接里,关闭就没了
  4. 临时表不能重命名,不能show tables查看

内部临时表

1
select pid,class_name from words order by rand() limit 3

上述语句的执行流程

  1. 创建一个内存临时表,表里会有2个字段,第一个是double类型,第二个是varchar类型,这个表没有建索引。
  2. 从数据表中,按主键顺序取出所有的值,调用rand() 生成一个 0-1的随机小数,把这个小数和按主键取出来的值放入上面的临时表。
  3. 在内存临时表中按照double类型的字段排序
  4. 初始化 sort_buffer 把临时表的数据放入 sort_buffer进行排序
  5. 返回前3条结果

磁盘临时表&&内存临时表

tmp_table_size这个配置限制内存临时表的大小,默认16MB。如果临时表大小操作这个值就会转换为磁盘临时表。临时表默认是InnoDB引擎

优化

1
explain  select pid,class_name from words order by rand() limit 3

rand

这里的 Extra Using temporary 使用临时表 Using filesort 使用排序,性能开销都很高我们要尽量避免这种情况。

一些花里胡哨的算法这边就没记录了,写一个在项目中最常用的方法。

1.count words 把总值记录内存缓存或者文件缓存。
2.代码里取随机数rand(1,count_value)
3.得到如下语句

1
explain  select pid,class_name from words limit  代码随机出来的值,1

这样做每次影响行数仅为1行,并且有随机性。弊端是取多个值的时候要请求多条语句

mysql order by 排序优化

order by在实际开发环境中使用时还是有很多禁忌的,比如字段的长度,索引的使用,select尽量别用*等,我们来看下order by在MySQL里经历了哪些过程吧,并且学会合理的优化MySQL。

场景

表结构

1
2
3
4
5
6
CREATE TABLE `words` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`class_name` varchar(255) NOT NULL COMMENT '分类名称',
`pid` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='行业词库'

根据主键排序,可以看到extra 字段为空

1
explain select *from words order by id

explain1

根据字段排序,extra 的值为 Using filesort

1
explain select * from words order by pid

explain2

下面我们来优化这一条SQL

1
select pid from words where pid = 5  order by class_name

运行流程

上图可见未使用到索引的字段 extra 的值为 Using filesort 是使用到排序了的,索引采用 btree的存储数据自带顺序。在Using filesort的时候MySQL会为每个线程分配一个sort_buffer内存或者文件来进行排序。

排序

进行order by语句的时候,MySQL会优先把数据放进内存分配sort_buffer进行排序。

sort_buffer_size 为sort_buffer使用的内存值,超过会使用临时文件辅佐排序,每个临时文件的大小为sort_buffer_size。

max_length_for_sort_data (列长度值)决定了排序采用的算法是全字段还是rowid排序

查看

1
2
show variables like 'sort_buffer_size';
show variables like 'max_length_for_sort_data';

sort_buffer_size 太大会在并发场景较大的环境下容易造成资源耗尽的情况,建议2kb-2MB之间5.6默认是 848KB

全字段

这种排序方式是把需要用到的数据全部放到sort_buffer中,提升排序速度

eg.

1
select pid from words where pid = 5  order by class_name
  1. 初始化一个sort_buffer 确定放入 class_name,pid两个字段
  2. 找到 “pid = 5” 满足条件的数据的主键ID
  3. 回表主键ID索引取出整行,把class_name,pid放入 sort_buffer
  4. 取出下一个记录的主键ID
  5. 重复3-4
  6. sort_buffer按照class_name字段进行排序
  7. 返回数据给客户端

rowid排序

这种排序方式是应对字段较长,全部放入sort_buffer占用大量内存的情况

eg.

1
select pid from words where pid = 5  order by class_name
  1. 初始化 sort_buffer 确定投入 id,class_name
  2. 找到 “pid = 5” 满足条件的数据的主键ID
  3. 主键ID回表,把id,class_name放入sort_buffer
  4. 取出下一个记录的主键ID
  5. 重复3-4
  6. sort_buffer按照class_name字段进行排序
  7. 拿到 sort_buffer 中的主键ID回表取出 pid返回数据

总结

排序方法 优点 缺点
全字段 减少回表 sort_buffer占用量大
rowid sort_buffer体积小 需要去主键回表

优化

1
select pid from words where pid = 5 order by class_name
  1. 给class_name加上索引,让它变为顺序结构。
  2. 查询中没有class_name,用不到索引。
  3. 加上(pid,class_name)联合索引

联合索引

Q:为什么加class_name字段索引无法用到排序
A:

  1. 根据查找排序步骤,排序会在sort_buffer中进行
  2. 索引简化排序是需要再进入sort_buffer前就阻断掉。
  3. 因此就要把排序值放入where条件中,让MySQL知道需要排序字段的值而不是再去回表取获取

MySQL表空间释放

我们在需要释放MySQL磁盘空间的时候第一反应是删除或者归档一些历史数据,但是这样的做法不一定是绝对正确的,因为有时候删除数据也不一定会及时释放磁盘空间。


在项目中使用神策因为是私有化部署所以极度’珍惜‘磁盘空间,数据量的确太大了。那时候神策的工程师告诉我们可以删除一些不要的数据,但是磁盘空间无法及时归还而是标记删除后面优先使用这部分删除的空间。


带着上面的一些问题我逐步巩固了一些知识

MySQL的物理存储文件

myisam

  • .frm
    表相关元素信息都存放frm文件,包括表的一些结构的定义信息,共有特性
  • .myd
    myisam专用,用于存储myisam表数据
  • .myi
    myisam专用,用于存储myisam表的索引相关信息

InnoDB

.ibd 和 ibddate1 是二选一的,通过innodb_file_per_table来控制,ON表示独立文件存储不和系统表空间公用。5.6开始这个参数是默认打开的

  • .frm 同上
  • .ibd 独占表空间文件
  • ibdata1 默认表空间文件

删除数据

  1. innodb_file_per_table为ON时我们drop table时就会删除相应的.idb文件,而为OFF时就只会标记删除实际空间没释放。

  2. 在删除table中的一部分数据时,并不会释放磁盘的空间出来。delete命令不能回收表空间,只能标记出来删除的数据位置为可复用,数据进来后填补这些’空洞’。

回收表空间

既然delete不能释放表空间,那我们该怎么办呢?

  1. 我们可以新建立一张表结构一样的 B 表
  2. 把A表的数据导入B表
  3. 然后删除A表,B表重命名A表

可以使用alter table name engine=InnoDB完成上述操作

在5.6版本前这个过程不能在线完成。在5.6版本后对这个流程做了优化,可以在线进行

  1. 建立一个临时文件,扫描A表主键的所有数据页
  2. 用A的数据页生成B+树,存储到临时文件
  3. 生成临时文件过程中,记录实时更改的记录
  4. 临时文件生成后,将记录的更改日志文件同步过去。
  5. 用临时文件替换表A的数据文件

题外话

这边在扩充2个优化表的函数命令

  • analyze table t
    重新统计索引信息,不会修改数据
  • optimize table t
    等于 alter table name engine=InnoDB + analyze

刷脏页带来的数据库抖动怎么优化?

MySQL抖动优化

在公司上班的时候经常是上班了一看听云日志有块小的数据库勃起然后找到运维查看MySQL的状态,因为不是专业的DBA所以给回的数据查考价值有限。后台查了些文档,MySQL的一些配置也会造成这种抖动或者勃起

redo log 刷脏页

redo log在一些地方可能叫redo log buffer 或者 log buffer,在翻查一些质料后知道了通常说的 redo log 其实是分两个部分的。

  • 内存中的 redo log buffer
  • 磁盘上的 redo log file

redo log buffer 会在一下情况刷脏页

  • 写满数据
  • 内存不够用

刷脏页一下的情况会对敏感型业务有影响

  • 淘汰的脏页个数过多
  • 日志写满,更新堵塞

刷脏页配置调优

  1. 我们可以用类似 fio的工具来检查磁盘的IOPS,然后设置 INNODB_IO_CAPACITY参数,建议保存在75%。

  2. InnoDB刷脏页有个连坐机制,就是当flush掉一个脏页的时候会带上相邻内存的脏页一并刷新,它的目的是减少机械硬盘时代的随机IO,但是如果是用的SSD可以关闭这个机制 innodb_flush_neighbors 设置为 0 。

13个MySQL调优的配置参数

整理了13个Mysql常见的调优参数,类比项目中发现,如果是自建的MySQL服务基本要全部设置优化下,如果是云端的产品很多都是大厂已经调节过后的配置。我只是把参数都整理出来了,并且写了一些自己理解的描述和网上查考了一些回答。更权威的还是要撸下官网文档的~~

INNODB_BUFFER_POOL_SIZE

这是InnoDB里最重要的一个变量,它指定了buffer pool的大小,buffer pool通俗上来说是减少数据在硬盘上的I/O,buffer pool中的数据会定期的去刷盘(刷脏页),这个数值推荐位80%物理内存空间

查看

1
SHOW variables LIKE "INNODB_BUFFER_POOL_SIZE"

QUERY_CACHE_TYPE

这个主要是管理查询缓存,但是高并发下并不推荐使用它并没有提升性能的作用

  • SQL hash值作为键,查询结果为值。这样即使相同语义的查询语句因为条件不同也会无法命中缓存
  • 数据表中有一条数据变动全表缓存作废,查询缓存失效会涉及并发访问控制,会加锁。

INNODB_LOG_FILE_SIZE

InnoDBredo log 文件大小,这边谈下自己的理解。每次更改数据会写入 buffer pool (内存),并且同时会写入文件日志redo log,因为写日志是顺序操作的所以会优于直接写入数据存储文件同时也保证了数据的一致性。这个值在6.5版本后是48M

查看

1
SHOW variables LIKE "INNODB_LOG_FILE_SIZE"

INNODB_FLUSH_LOG_AT_TRX_COMMIT

这个参数控制 ‘redo log buffer’数据写入日志文件并flush磁盘的时间点

0: log buffer 每秒写入 log file,并且log file flush 同时进行

1: 事务提交会将log buffer 写入 log file 并且flush(默认)

2: 事务提交会将 log buffer 写入 log file 但是flush不会同时进行,会每秒执行一次

ps: 设置为1最高的保证了数据的安全,设置为2最高的保证了效率,设置为0是折中方案

1
SHOW variables LIKE "INNODB_FLUSH_LOG_AT_TRX_COMMIT"

SYNC_BINLOG

是MySQL的二进制日志(binary log)同步到磁盘的频率

sync_binlog=0,当事务提交之后,MySQL不做fsync之类的磁盘同步指令刷新binlog_cache中的信息到磁盘,而让Filesystem自行决定什么时候来做同步,或者cache满了之后才同步到磁盘。这个是性能最好的。

sync_binlog=1,当每进行1次事务提交之后,MySQL将进行一次fsync之类的磁盘同步指令来将binlog_cache中的数据强制写入磁盘。

sync_binlog=n,当每进行n次事务提交之后,MySQL将进行一次fsync之类的磁盘同步指令来将binlog_cache中的数据强制写入磁盘。

这个参数默认是0,为了保证数据安全建议设置1

1
SHOW variables LIKE "SYNC_BINLOG"

INNODB_IO_CAPACITY

当刷新脏页时,控制每秒的IO量

1
SHOW variables LIKE "innodb_io_capacity"

INNODB_IO_CAPACITY_MAX

在紧急情况下刷脏页的IO量,innodb_io_capacity_max设置是所有buffer pool例的总限制。一般这个限制是官方建议是INNODB_IO_CAPACITY的2倍

INNODB_FLUSH_METHOD

控制数据文件及redo log的打开,刷写模式,有3个配置推荐用O_DIRECT

1
SHOW variables LIKE "INNODB_FLUSH_METHOD"

INNODB_BUFFER_POOL_INSTANCES

优化在搞并发环境下的吞吐量,5.6过后推荐配置8-16 按照mysql官方解释就是在高并发场景下分多个buffer pools 减少资源占用的问题

1
SHOW variables LIKE "INNODB_BUFFER_POOL_INSTANCES"

INNODB_THREAD_CONCURRENCY

默认是0,标识没有并发线程数限制,官方建议当并发用户数小于64 innodb_thread_concurrency=0

SKIP_NAME_RESOLVE

建议打开这个参数,如果MySQL上设置了DNS服务器,并且客服端IP在DNS没有对应的hostname,就会出现等待。打开这个参数可以跳过这个等待。

1
SHOW variables LIKE "SKIP_NAME_RESOLVE"

INNODB_STATS_ON_METADATA

5.5版本之前介意关闭,5.6以后默认关闭

default_storage_engine

MySQL5.6以后的版本默认都是InnoDB,查看或者更换这个参数可以

1
SHOW variables LIKE "default_storage_engine"

请我喝杯咖啡吧~