Docker实践(7) – 设置本地私有库registry

你看到了Docker官方有一个服务,人们可以公开分享他们的镜像(你可以付费设置为私有)。不过有些理由使你不想通过Hub分享镜像 – 一些企业喜欢把服务尽可能的留在内部,或者可能是你的镜像太大了,通过互联网传输会太慢,或者可能你只是在做试验想暂时保持私有,或者不想付费购买私有权限。不管是什么样的原因,有一个简单的解决方案。

问题

你想要一个本地托管你的镜像的方法。

方法

在你本地网络设置一个registry服务器。

讨论

要运行registry,在一个空间充足的机器执行如下命令:

  1. $ docker run -d -p 5000:5000 -v $HOME/registry:/var/lib/registry registry:2

此命令设置了docker主机的5000端口作为registry的服务端口并设置容器的/var/lib/registry为registry的存储目录,也就是registry在容器中存储文件的默认目录。
在需要访问registry服务器的docker机器上,给守护端添加如下选项(HOSTNAME是registry服务器的主机名或IP地址):–insecure-registry HOSTNAME.
你现在能执行docker push HOSTNAME:5000/image:tag命令把镜像推送到registry服务器。
如你所见,配置一个镜像存储在$HOME/registry的本地registry只用到了最基本的配置级别,很简单吧。如果你想扩大registry的存储规模和使服务更健壮,可以查看支持的存储驱动(https://github.com/docker/distribution/blob/v2.2.1/docs/storagedrivers.md),如存储到Amazon S3。
你可能想了解关于–insecure-registry的选项。为什么帮助用户保持服务安全性,Docker只允许你从具有签名HTTPS证书的registrys拉取镜像。我们关闭此安全选项是因为我们认为本地网络是安全的。

理解SaltStack(1) – 设计思想

你可以通过观察saltstack的行为来了解它是如何工作的。那就是说,很多事情发生在底层你很难注意到,就像数据文件在控制台传输。此系列文章说明saltstack是如何工作的,saltstack的子系统,以及saltstack模块化架构如何使用和扩展saltstack来管理你的整个基础架构。
在我们了解saltstack的特定组件之前,有必要了解关于SaltStack如何处理基础设施管理的方方面面。

实时通信

所有的salt minions都是同时接收到命令的。那意味着更新10或10000个系统所花的时间非常相近,并且能够在数秒钟内查询数千个系统。saltstack获取关于你基础设施的信息方法是实时查询的,而不是依赖数据库。

各司其职

salt minions只做属于它们自己的工作。Salt master发送的是一组轻量级的指令,基本上是包含”如果你是一个带有这些属性的minion:运行这些带参数的命令”。当接收到命令时,由salt minions判断是否与属性匹配。每个salt minion已经有需要存储在本地的所有命令,所以命令能够被执行和其结果很快地返回给salt master。salt master不需要为minion做任何工作,因为它能自己完成,常常能完成得更好。

高性能和可扩展性

Saltstack设计用于高性能和可扩展性。saltstack的通信系统在salt master与minions之间使用ZeroMQ或原始TCP建立一条持久的数据通道,给予saltstack相对于竞争方案相当大的性能优势。消息使用MessagePack进行高效序列化。在内部,salt使用Python Tornado作为一个异步网络库,而且使用了多线程和并发这些前沿的技术来进一步优化salt性能。
用户在生产环境中的单台master管理超过10000台minions并不是不常见,目前所知有越过35000台minions由单台salt master管理!salt已经证明了其在真实环境中的速度和可扩展性。

规范化一切

规范化是saltstack跨平台管理功能的关键。不管你的目标机器是Linux, Windows, MacOS, FreeBSD, Solaris, AIX,物理硬件,云主机或容器,salt命令和状态都运行一致。salt抽象每个操作系统,硬件类型和系统工具的详细信息以便你能正确地管理你的基础设施。
规范化一切还包括返回:salt命令返回以一致的数据结构的结果以方便解析和存储。

管理一切

salt几乎都能运行在安装有Python的所有设备。对于不支持Python的那些设备,你可以使用minion代理系统。这意味着能够被salt管理的唯一条件是支持任意的网络协议(甚至是你自己写的协议)。salt命令被发送到minion代理服务器,它将salt调用转换为本地协议,然后发送到设备。解析从设备返回的数据,然后放入数据结构并返回。

自动化一切

salt的事件驱动基础设施不仅让你能够自动化初始系统配置,也让你能够自动化扩展,修复和完成持续管理。salt用户自动部署和维护复杂的分布式网络应用程序和数据库,自定义应用程序,文件,用户帐户,标准包,云资源等。

可选编程

你不需要学习编程语言就能够使用salt的所有功能。salt的远程执行能力是CLI命令,状态系统使用YAML来描述系统的所需配置。
你仍然可以采取”基础设施即代码”的方法 – salt有许多工具来支持这点,包括强制的必要系统与命令式和声明性执行。Salt只是帮助你不需要编写Python或Ruby代码来描述你的基础设施。

模块化系统

一些管理工具认为它们是可扩展的,因为它们能够运行外部脚本。在saltstack中,一切都是可扩展性的。下一篇文章会介绍,甚至是底层的通信协议都是可互换的。salt有超过20个可扩展的子系统,意味着salt能够做的事件,你也可以自定义它怎样完成任务。
salt能够快速适应新的技术和管理新的应用,你永远都不会被别人的决定所困扰,管理你的基础设施哪一个方法最好。

插件

在下一篇文章,我们将介绍salt插件,以及它为什么对salt至关重要。

Docker实践(6) – 容器内部连接(不需要在主机上映射端口)

上一个技术点展示了如何通过暴露端口来开放你的容器到主机网络。不过当你只是想容器内部之间连接时,就不再想把端口暴露给主机网络或外部网络了。
在本文将介绍如何通过Docker link参数来实现这个目的,来确保外部无法访问你的内部服务。

问题

你想要允许容器内部之间的连接。

方法

通过docker的链接功能来允许容器相互通信。

讨论

继续我们wordpress的设置,我们打算从wordpress容器分离出mysql数据库,然后不通过端口映射方式来使它们能够相互通信。如图:
虚拟化技术
按照如下命令来运行容器,第一个和第二个命令相隔一分钟执行:

  1. $ docker run –name wp-mysql -e MYSQL_ROOT_PASSWORD=yoursecretpassword -d mysql
  2. $ docker run –name wordpress –link wp-mysql:mysql -p 10003:80 -d  wordpress

在第一个命令中,给容器设置了wp-mysql名称以便之后引用。并且提供一个环境变量(-e MYSQL_ROOT_PASSWORD=yoursecretpassword)来使mysql容器能够完成初始化。
在第二个命令中,以wordpress命名容器,并通过–link wp-mysql:mysql来连接wp-mysql与wordpress容器。注意链接不会等待链接容器启动完成,所以上一步的操作需要等待一分钟以便让mysql容器先完成启动。不过最好的方法是通过docker logs wp-mysql来查看mysql容器是否已经准备接受连接了。
在这个示例中最重要的是–link参数,这个参数使wordpress容器自动维护/etc/hosts文件来使wp-mysql mysql等名称指向mysql容器IP。

启动次序事项:容器必须按正确的次序来启动以便存在的容器映射能够正确的替换。目前为止链接的动态解析不是docker的一项功能。

为了能够让容器能够被连接,比如mysql容器,就需要在创建mysql镜像时暴露端口,如暴露3306端口,这个可以在Dockerfile使EXPOSE完成。
至于为什么为这样做,请参考http://dockone.io/article/455

Docker实践(5) – 通过端口连接容器

Docker容器从一开始就设计用来运行服务。在大多数情况下,会是一种HTTP服务或其它。其中很大一部分是通过浏览器访问的Web服务。
这会导致一个问题。如果你有多个运行在它们内部环境的80端口上的Docker容器,它们不能都通过你机器上的80端口访问。下一次技术点将介绍如何通过从你的容器暴露和映射一个端口来处理这个常见的情景。

问题

你想通过你机器上的端口使你的容器能够得到访问。

方法

使用docker的-p参数来映射容器的端口到你的主机。

讨论

在这个示例中我们准备用tutum-wordpress镜像。假设你要在主机上运行两个容器来创建不同的博客。因为很多人想要这样做,有人已经准备好一个镜像让其他人能够获取和启动。你可以使用docker pull命令来得到外部位置的镜像。默认下,镜像会从docker hub去下载。

  1. $ docker pull tutum/wordpress

运行第一个博客,执行如下命令:

  1. $ docker run -d -p 10001:80 –name blog1 tutum/wordpress

docker run命令以守护进程(-d),参数-p运行容器。它标识要映射主机的10001端口到容器的80端口,并设置了一个容器名称用来识别它(–nameblog1tutum/wordpress)。
你可以用同样的方法创建第二个博客:

  1. $ docker run -d -p 10002:80 –name blog2 tutum/wordpress

如果你现在运行这个命令,

  1. $ docker ps -a | grep blog

你会看到两个博客窗口列出,有它们的端口映射,类似如下:
9afb95ad3617 tutum/wordpress:latest “/run.sh”
➥ 9 seconds ago Up 9 seconds
3306/tcp, 0.0.0.0:10001->80/tcp blog1 31ddc8a7a2fd tutum/wordpress:latest
➥ “/run.sh” 17 seconds ago Up 16 seconds 3306/tcp, 0.0.0.0:10002->80/tcp blog2
你可以在浏览器中通过http://localhost:10001和http://localhost:10002访问这两个博客容器。
完成后要删除这些容器(假设你不想保留):

  1. $ docker rm -f blog1 blog2

如果需要,你现在应该能够通过自己管理端口映射来运行多个相同的镜像来提供不同的服务了。

Docker实践(4) – 使用socat查看Docker API流量详情

docker命令可能会偶尔地无法正常工作。大多数情况下是命令行参数没有输入正确,不过也有偶尔一些是严重的配置问题,如Docker二进制文件过期了。为了诊断此问题,查看你正在连接的docker daemon的数据流可能会有所帮助。

问题

你想用docker命令来调度一个问题。

方法

使用流量探测器来检查API调用并输出调用详情。

讨论

在此技术中你将在你的请求与服务器socket之间安放一个Unix域套接字代理来查看传过来了什么东西。现在需要root或sudo权限来做这件事。
要创建这个代理,需要用到socat命令。

socat是一个允许你在几乎任何类型的两个数据通道之间中继数据。

  1. $ sudo socat -v UNIX-LISTEN:/tmp/dockerapi.sock
  2.           UNIX-CONNECT:/var/run/docker.sock &

虚拟化技术
在这个命令中-v参数输出数据流的可读格式。UNIX-LISTEN让socat监听一个域套接字,UNIX-CONNECT让socat连接到Docker的域套接字。’&’使命令后台运行。
你的请求到docker的路由可以看下面。
所有的流量都将被socat看到并记录到你的终端。
虚拟化技术
一个简单的docker命令输出类似如下:
虚拟化技术
socat不仅仅是用来调试docker,也可以用来调试任何的网络服务。

Docker实践(3) – 移动docker到一个不同的分区

Docker把与你的容器和镜像相关的数据保存到一个目录下。由于可能会存储潜在的大量不同的镜像,这个目录会很快变得很大!
如果你的主机有不同的分区,你可能会更快遇到空间受限的问题。在这种情况下,你可能需要把Docker的数据目录移动到其它分区。

问题

你想要移动docker的数据

方法

停止docker daemon,使用-g参数指定新目录启动。

讨论

首先你需要停止你的docker daemon。
假设你想把docker数据放在/home/dockerusr/mydocker目录下,我们先把原来的目录迁移过来:

  1. cp -a /var/lib/docker/* home/dockerusr/mydocker/

然后启动docker:

  1. docker daemon -g /home/dockeruser/mydocker

这时候你通过执行docker images或docker ps -a就可以看到原来的镜像或容器。确认好之后就可以删除原来的数据了。
当然记得把此更改添加到配置文件。

Docker实践(2) – 以守护进程运行容器

当你逐渐了解docker后,你会开始考虑docker的其它用例,第一个首先是运行服务一样运行docker。

问题

你想作为一个服务在后台运行docker.

方法

docker run命令使用-d参数,和使用与容器管理相关的参数来定义服务特性。

讨论

Docker容器 – 像大多数进程 – 默认在前台运行。在后台运行docker容器最常见的方式是使用&控制操作符。即使这个可行,不过当你的日志输出到终端会话时可能会遇到麻烦,或者你使用nohup命令,它会当前目录创建一个日志输出文件,不过增加了一个日志管理的问题。而docker提供有在后台运行的功能,如:

  1. $ docker run -d -i -p 1234:1234 –name daemon ubuntu nc -l 1234

当docker run命令使用-d参数时,docker会以守护进程运行。-i参数使你能够与Telnet会话交互。-p参数使容器的1234端口绑定到主机。–name参数设置容器一个名称方便以后引用。最后,运行了一个监听在1234端口的echo服务器。
如果你现在连接并使用telnet发送消息,你使用docker logs命令会看到容器已经接收到消息,如图:
虚拟化技术
你看到以守护进程运行容器足够简单,但操作上仍有一些问题需要回答:
* 服务失败时会怎样?
* 服务终止时会怎样?
* 如果服务持续故障会怎样?
幸运地是docker为每个问题提供了参数!

虽然restart参数经常与-d参数一起使用,但技术上来说这不是必要的。

docker run –restart命令允许容器终止时应用一系列的规则(也称重启策略)。
重启策略可选值:
no – 容器退出时不重启
always – 容器退出时始终重启
on-failure[:max-retry] – 只在发生错误时重启
no策略很简单:当容器退出时,不重启容器。这个是默认值。
always也同样简单,不过值得简单介绍下:

  1. $ docker run -d –restart=always ubuntu echo done

此命令以守护进程运行容器,并在进程终止时始终重启容器(–restart=always)。执行了一个快速完成的echo命令,然后退出容器。
如果你执行以上命令然后执行docker ps命令,会看到类似的输出:
虚拟化技术
注意STATUS列告诉我们容器少于一秒前退出,正在重启。这是因为echo done命令立即退出了,docker就必须持续地重启容器。
最后on-failure策略只在容器以非0(非正常失败)状态码退出时重启:

  1. $ docker run -d –restart=on-failure:10 ubuntu /bin/false

此命令以守护进程运行(-d)和对尝试重启设置一个限制值(–restart=on-failure:10),超过此次数时不再重启。它运行一个简单的命令(/bin/false),会快速完成且肯定会失败。
如果你执行以上命令,等一分钟后执行docker ps -a,你会看到类似的输出:
虚拟化技术

Docker实践(1) – 设置守护进程对外开放

虽然默认下你的Docker daemon只允许在本机访问,但有时候也有充足理由让其他人访问。你可能有什么问题想让其他人远程调试,或者你可能想允许DevOps工作流来启动主机上的一个进程。

INSECURE!虽然这是一个强大且有用的技术,但是这认为是不安全的。一个开放的Docker daemon可能被其他人利用来获取系统权限。

问题

你想对其他人开放Docker服务器的访问权限

方法

以开放的TCP地址启动Docker daemon

讨论

以下图是这种技术的工作原理.
虚拟化技术
在你开放Docker daemon之前,首先得关闭它。如何关闭它取决于你的系统,如果你不清楚,先执行如下命令:

  1. $ sudo service docker stop

如果你得到如下信息:
The service command supports only basic LSB actions (start, stop, restart,
try-restart, reload, force-reload, status). For other actions, please try
to use systemctl.
表示你的系统启动管理是基于systemctl的,尝试如下命令:

  1. $ systemctl stop docker

如果这个可行,那么下面的命令将没有任务输出:

  1. ps -ef | grep -E ‘docker (-d|daemon)b’ | grep -v grep

一旦Docker daemon已经停止,你就可以使用以下的命令手动重启来打开对外用户的访问:

  1. docker daemon -H tcp://0.0.0.0:2375

此命令以守护进程启动docker,使用-H参数为定义主机服务器,使用TCP协议,监听所有IP(使用0.0.0.0),开放docker服务器标准端口2375。如果Docker提示daemon是一个无效子命令,尝试使用旧的-d参数。
之后你可以在外面使用如下命令来访问docker:

  1. $ docker -H tcp://<your host’s ip>:2375

注意你在本机也使用用此方法来连接docker,因为docker已经不再监听默认的地址。
如果你想让此更改永久生效(即使重启后),虽然更改docker的配置文件:
系统Ubuntu / Debian / Gentoo配置文件为:/etc/default/docker
OpenSuse / CentOS / Red Hat配置文件为:/etc/sysconfg/docker
在配置文件中找到DOCKER_OPTS,设置为以上的启动参数,如DOCKER_OPTS=”daemon -H tcp://0.0.0.0:2375″
如果你的系统使用的是systemd配置文件,那么在/usr/lib/systemd/system/service/docker中找到ExecStart行,设置为ExecStart=/usr/bin/docker daemon -H tcp://0.0.0.0:2375

开放docker daemon后,建议使用防火墙来限制对指定IP开放访问,而且不使用0.0.0.0,非常不安全。

MySQL性能调优 – 你必须了解的15个重要变量

1.DEFAULT_STORAGE_ENGINE

如果你已经在用MySQL 5.6或者5.7,并且你的数据表都是InnoDB,那么表示你已经设置好了。如果没有,确保把你的表转换为InnoDB并且设置default_storage_engine为InnoDB。
为什么?简而言之,因为InnoDB是MySQL(包括Percona Server和MariaDB)最好的存储引擎 – 它支持事务,高并发,有着非常好的性能表现(当配置正确时)。这里有详细的版本介绍为什么

2.INNODB_BUFFER_POOL_SIZE

这个是InnoDB最重要变量。实际上,如果你的主要存储引擎是InnoDB,那么对于你,这个变量对于MySQL是最重要的。
基本上,innodb_buffer_pool_size指定了MySQL应该分配给InnoDB缓冲池多少内存,InnoDB缓冲池用来存储缓存的数据,二级索引,脏数据(已经被更改但没有刷新到硬盘的数据)以及各种内部结构如自适应哈希索引。
根据经验,在一个独立的MySQL服务器应该分配给MySQL整个机器总内存的80%。如果你的MySQL运行在一个共享服务器,或者你想知道InnoDB缓冲池大小是否正确设置,详细请看这里

3.INNODB_LOG_FILE_SIZE

InnoDB重做日志文件的设置在MySQL社区也叫做事务日志。直到MySQL 5.6.8事务日志默认值innodb_log_file_size=5M是唯一最大的InnoDB性能杀手。从MySQL 5.6.8开始,默认值提升到48M,但对于许多稍繁忙的系统,还远远要低。
根据经验,你应该设置的日志大小能在你服务器繁忙时能存储1-2小时的写入量。如果不想这么麻烦,那么设置1-2G的大小会让你的性能有一个不错的表现。这个变量也相当重要,更详细的介绍请看这里
在进入下一个变量之前,让我们来快速提及一下innodb_log_buffer_size。“快速提及”是因为它常常不好理解并且往往被过度关注了。事实上大多数情况下你只需要使用小的缓冲 – 在事务被提交并写入到硬盘前足够保存你的小事务更改了。
当然,如果你有大量的大事务更改,那么,更改比默认innodb日志缓冲大小更大的值会对你的性能有一定的提高,但是你使用的是autocommit,或者你的事务更改小于几k,那还是保持默认的值吧。

4.INNODB_FLUSH_LOG_AT_TRX_COMMIT

默认下,innodb_flush_log_at_trx_commit设置为1表示InnoDB在每次事务提交后立即刷新同步数据到硬盘。如果你使用autocommit,那么你的每一个INSERT, UPDATE或DELETE语句都是一个事务提交。
同步是一个昂贵的操作(特别是当你没有写回缓存时),因为它涉及对硬盘的实际同步物理写入。所以如果可能,并不建议使用默认值。
两个可选的值是0和2:
* 0表示刷新到硬盘,但不同步(提交事务时没有实际的IO操作)
* 2表示不刷新和不同步(也没有实际的IO操作)
所以你如果设置它为0或2,则同步操作每秒执行一次。所以明显的缺点是你可能会丢失上一秒的提交数据。具体来说,你的事务已经提交了,但服务器马上断电了,那么你的提交相当于没有发生过。
显示的,对于金融机构,如银行,这是无法忍受的。不过对于大多数网站,可以设置为innodb_flush_log_at_trx_commit=0|2,即使服务器最终崩溃也没有什么大问题。毕竟,仅仅在几年前有许多网站还是用MyISAM,当崩溃时会丢失30s的数据(更不要提那令人抓狂的慢修复进程)。
那么,0和2之间的实际区别是什么?性能明显的差异是可以忽略不计,因为刷新到操作系统缓存的操作是非常快的。所以很明显应该设置为0,万一MySQL崩溃(不是整个机器),你不会丢失任何数据,因为数据已经在OS缓存,最终还是会同步到硬盘的。

5.SYNC_BINLOG

已经有大量的文档写到sync_binlog,以及它和innodb_flush_log_at_trx_commit的关系,下面我们来简单的介绍下:
a) 如果你的服务器没有设置从服务器,而且你不做备份,那么设置sync_binlog=0将对性能有好处。
b) 如果你有从服务器并且做备份,但你不介意当主服务器崩溃时在二进制日志丢失一些事件,那么为了更好的性能还是设置为sync_binlog=0.
c) 如果你有从服务器并且备份,你非常在意从服务器的一致性,以及能及时恢复到一个时间点(通过使用最新的一致性备份和二进制日志将数据库恢复到特定时间点的能力),那么你应该设置innodb_flush_log_at_trx_commit=1,并且需要认真考虑使用sync_binlog=1。
问题是sync_binlog=1代价比较高 – 现在每个事务也要同步一次到硬盘。你可能会想为什么不把两次同步合并成一次,想法正确 – 新版本的MySQL(5.6和5.7,MariaDB和Percona Server)已经能合并提交,那么在这种情况下sync_binlog=1的操作也不是这么昂贵了,但在旧的mysql版本中仍然会对性能有很大影响。

6.INNODB_FLUSH_METHOD

将innodb_flush_method设置为O_DIRECT以避免双重缓冲.唯一一种情况你不应该使用O_DIRECT是当你操作系统不支持时。但如果你运行的是Linux,使用O_DIRECT来激活直接IO。
不用直接IO,双重缓冲将会发生,因为所有的数据库更改首先会写入到OS缓存然后才同步到硬盘 – 所以InnoDB缓冲池和OS缓存会同时持有一份相同的数据。特别是如果你的缓冲池限制为总内存的50%,那意味着在写密集的环境中你可能会浪费高达50%的内存。如果没有限制为50%,服务器可能由于OS缓存的高压力会使用到swap。
简单地说,设置为innodb_flush_method=O_DIRECT。

7.INNODB_BUFFER_POOL_INSTANCES

MySQL 5.5引入了缓冲实例作为减小内部锁争用来提高MySQL吞吐量的手段。
在5.5版本这个对提升吞吐量帮助很小,然后在MySQL 5.6版本这个提升就非常大了,所以在MySQL5.5中你可能会保守地设置innodb_buffer_pool_instances=4,在MySQL 5.6和5.7中你可以设置为8-16个缓冲池实例。
你设置后观察会觉得性能提高不大,但在大多数高负载情况下,它应该会有不错的表现。
对了,不要指望这个设置能减少你单个查询的响应时间。这个是在高并发负载的服务器上才看得出区别。比如多个线程同时做许多事情。

8.INNODB_THREAD_CONCURRENCY

你可能会经常听到应该设置innodb_thread_concurrency=0然后就不要管它了。不过这个只在低负载服务器使用时才正确。然后,如果你的服务器的CPU或者IO使用接受饱和,特别是偶尔出现峰值,这时候系统想在超载时能正常处理查询,那么强烈建议关注innodb_thread_concurrency。
InnoDB有一种方法来控制并行执行的线程数 – 我们称为并发控制机制。大部分是由innodb_thread_concurrency值来控制的。如果设置为0,并发控制就关闭了,因此InnoDB会立即处理所有进来的请求(尽可能多的)。
在你有32CPU核心且只有4个请求时会没什么问题。不过想像下你只有4CPU核心和32个请求时 – 如果你让32个请求同时处理,你这个自找麻烦。因为这些32个请求只有4 CPU核心,显然地会比平常慢至少8倍(实际上是大于8倍),而然这些请求每个都有自己的外部和内部锁,这有很大可能堆积请求。
下面介绍如何更改这个变量,在mysql命令行提示符执行:

  1. SET global innodb_thread_concurrency=X;

对于大多数工作负载和服务器,设置为8是一个好开端,然后你可以根据服务器达到了这个限制而资源使用率利用不足时逐渐增加。可以通过show engine innodb statusG来查看目前查询处理情况,查找类似如下行:

  1. 22 queries inside InnoDB, 104 queries in queue

9.SKIP_NAME_RESOLVE

这一项不得不提及,因为仍然有很多人没有添加这一项。你应该添加skip_name_resolve来避免连接时DNS解析。
大多数情况下你更改这个会没有什么感觉,因为大多数情况下DNS服务器解析会非常快。不过当DNS服务器失败时,它会出现在你服务器上出现“unauthenticated connections” ,而就是为什么所有的请求都突然开始慢下来了。
所以不要等到这种事情发生才更改。现在添加这个变量并且避免基于主机名的授权。

10.INNODB_IO_CAPACITY, INNODB_IO_CAPACITY_MAX

* innodb_io_capacity:用来当刷新脏数据时,控制MySQL每秒执行的写IO量。
* innodb_io_capacity_max: 在压力下,控制当刷新脏数据时MySQL每秒执行的写IO量
首先,这与读取无关 – SELECT查询执行的操作。对于读操作,MySQL会尽最大可能处理并返回结果。至于写操作,MySQL在后台会循环刷新,在每一个循环会检查有多少数据需要刷新,并且不会用超过innodb_io_capacity指定的数来做刷新操作。这也包括更改缓冲区合并(在它们刷新到磁盘之前,更改缓冲区是辅助脏页存储的关键)。
第二,我需要解释一下什么叫“在压力下”,MySQL中称为”紧急情况”,是当MySQL在后台刷新时,它需要刷新一些数据为了让新的写操作进来。然后,MySQL会用到innodb_io_capacity_max。
那么,应该设置innodb_io_capacity和innodb_io_capacity_max为什么呢?
最好的方法是测量你的存储设置的随机写吞吐量,然后给innodb_io_capacity_max设置为你的设备能达到的最大IOPS。innodb_io_capacity就设置为它的50-75%,特别是你的系统主要是写操作时。
通常你可以预测你的系统的IOPS是多少。例如由8 15k硬盘组成的RAID10能做大约每秒1000随机写操作,所以你可以设置innodb_io_capacity=600和innodb_io_capacity_max=1000。许多廉价企业SSD可以做4,000-10,000 IOPS等。
这个值设置得不完美问题不大。但是,要注意默认的200和400会限制你的写吞吐量,因此你可能偶尔会捕捉到刷新进程。如果出现这种情况,可能是已经达到你硬盘的写IO吞吐量,或者这个值设置得太小限制了吞吐量。

11.INNODB_STATS_ON_METADATA

如果你跑的是MySQL 5.6或5.7,你不需要更改innodb_stats_on_metadata的默认值,因为它已经设置正确了。
不过在MySQL 5.5或5.1,强烈建议关闭这个变量 – 如果是开启,像命令show table status会立即查询INFORMATION_SCHEMA而不是等几秒再执行,这会使用到额外的IO操作。
从5.1.32版本开始,这个是动态变量,意味着你不需要重启MySQL服务器来关闭它。

12.INNODB_BUFFER_POOL_DUMP_AT_SHUTDOWN & INNODB_BUFFER_POOL_LOAD_AT_STARTUP

innodb_buffer_pool_dump_at_shutdown和innodb_buffer_pool_load_at_startup这两个变量与性能无关,不过如果你偶尔重启mysql服务器(如生效配置),那么就有关。当两个都激活时,MySQL缓冲池的内容(更具体地说,是缓存页)在停止MySQL时存储到一个文件。当你下次启动MySQL时,它会在后台启动一个线程来加载缓冲池的内容以提高预热速度到3-5倍。
两件事:
第一,它实际上没有在关闭时复制缓冲池内容到文件,仅仅是复制表空间ID和页面ID – 足够的信息来定位硬盘上的页面了。然后它就能以大量的顺序读非常快速的加载那些页面,而不是需要成千上万的小随机读。
第二,启动时是在后台加载内容,因为MySQL不需要等到缓冲池内容加载完成再开始接受请求(所以看起来不会有什么影响)。
从MySQL 5.7.7开始,默认只有25%的缓冲池页面在mysql关闭时存储到文件,但是你可以控制这个值 – 使用innodb_buffer_pool_dump_pct,建议75-100。
这个特性从MySQL 5.6才开始支持。

13.INNODB_ADAPTIVE_HASH_INDEX_PARTS

如果你运行着一个大量SELECT查询的MySQL服务器(并且已经尽可能优化),那么自适应哈希索引将下你的下一个瓶颈。自适应哈希索引是InnoDB内部维护的动态索引,可以提高最常用的查询模式的性能。这个特性可以重启服务器关闭,不过默认下在mysql的所有版本开启。
这个技术非常复杂,在大多数情况下它会对大多数类型的查询直到加速的作用。不过,当你有太多的查询往数据库,在某一个点上它会花过多的时间等待AHI锁和闩锁。
如果你的是MySQL 5.7,没有这个问题 – innodb_adaptive_hash_index_parts默认设置为8,所以自适应哈希索引被切割为8个分区,因为不存在全局互斥。
不过在mysql 5.7前的版本,没有AHI分区数量的控制。换句话说,有一个全局互斥锁来保护AHI,可能导致你的select查询经常撞墙。
所以如果你运行的是5.1或5.6,并且有大量的select查询,最简单的方案就是切换成同一版本的Percona Server来激活AHI分区。

14.QUERY_CACHE_TYPE

如果人认为查询缓存效果很好,肯定应该使用它。好吧,有时候是有用的。不过这个只在你在低负载时有用,特别是在低负载下大多数是读取,小量写或者没有。
如果是那样的情况,设置query_cache_type=ON和query_cache_size=256M就好了。不过记住不能把256M设置更高的值了,否则会由于查询缓存失效时,导致引起严重的服务器停顿。
如果你的MySQL服务器高负载动作,建议设置query_cache_size=0和query_cache_type=OFF,并重启服务器生效。那样Mysql就会停止在所有的查询使用查询缓存互斥锁。

15.TABLE_OPEN_CACHE_INSTANCES

从MySQL 5.6.6开始,表缓存能分割到多个分区。
表缓存用来存放目前已打开表的列表,当每一个表打开或关闭互斥体就被锁定 – 即使这是一个隐式临时表。使用多个分区绝对减少了潜在的争用。
从MySQL 5.7.8开始,table_open_cache_instances=16是默认的配置。

INNODB_LOG_FILE_SIZE:设置MySQL重做日志大小

什么是InnoDB事务日志

你有没有在文本编辑器中使用过撤消或重做的功能,想像一下编辑器在那种场景下的操作?我确信你应该使用过。你相信吗?事务型数据库有同样的功能。可能不完全一样,但原理是相同的。
就像当你编辑文字时始终有能力撤消数步的重要性一样,重做和撤消功能也对事务型数据一样重要。为什么呢?主要有两个原因:
1.回滚事务(那是撤消)
2.在数据库崩溃的情况下回放已提交的事务(那是重做)

撤消

当你使用的是事务存储引擎(假设是InnoDB),你更改一个记录时,更改并没有马上写入数据文件。
首先,它们被写入到一个硬盘上特定的文件叫做事务日志。同时,它们也更改了内存 – InnoDB缓冲池。现在新InnoDB页面包含了已更改的记录叫脏数据。
被复制到硬盘上特别区域的原始未被更改的页面叫做回滚段。
如果有人在提交之前使用ROLLBACK中断了一个事务,撤消操作就发生了 – 你的记录已经被还原到原始状态。
由于更改还没有被写入到数据文件,这个操作相当简单 – InnoDB仅仅需要从回滚段中提取旧页面,从内存中擦除脏页,并在事务日志中标记那个事务已经回滚。
所以你看,数据文件从没有被更改,因为在执行随机写操作以把脏数据刷新到硬盘之前你已经把所有更改取消了。

重做

当你提交事务,然后InnoDB确认你的提交,更改准备写入到实际的数据文件。
现在你认为它们会被马上写入到硬盘的数据文件,事实上不是这样的。为什么?因为这样做效率非常低。反而,更改仅仅被写入到事务日志(因为是顺序写,速度会很快,称为重做日志记录),而更改的记录仍然在日志中 – InnoDB缓冲池的脏页,过一定的时间才刷新到硬盘。
这时候MySQL崩溃了!
猜猜MySQL会怎样做?
如果MySQL(实际上是InnoDB)没有重做日志,仅仅是保留了脏页在内存中 – 所有未被刷新到硬盘已提交的事务将会永久丢失。
幸运的是,所以的更改总会写入到事务日志,
所以InnoDB需要做的就是在重做日志中找到上一次的checkpoint(已同步数据到硬盘的位置),然后重做未同步到硬盘已提交的事务。

日志大小

你可能想知道的一个事就是如何正确设置innodb_log_file_size的大小。规则很简单:
* 小日志文件使写入速度更慢,崩溃恢复速度更快
* 大日志文件使写入更快,崩溃恢复速度更慢
由于事务日志相当于一个写缓冲,而小日志文件会很快的被写满,这时候就需要频繁地刷新到硬盘,速度就慢了。如果产生大量的写操作,MySQL可能就不能足够快地刷新数据,那么写性能将会降低。
大的日志文件,另一方面,在刷新操作发生之前给你足够的空间来使用。反过来允许InnoDB填充更多的页面。
对于崩溃恢复 – 大的重做日志意味着在服务器启动前更多的数据需要读取,更多的更改需要重做,这就是为什么崩溃恢复慢了。

重做日志大小

最后,让我们来谈谈如何找出重做日志的正确大小。
幸运的是,你不需要费力算出正确的大小,这里有一个经验法则:
在服务器繁忙期间,检查重做日志的总大小是否够写入1-2小时。
你如何知道InnoDB写入多少,下面有一个方法:

  1. mysql> pager grep seq
  2. mysql> show engine innodb statusG select sleep(60); show engine innodb statusG
  3. Log sequence number 1777308180429
  4. Log sequence number 1777354541591
  5.  
  6. mysql> nopager
  7. mysql> select (1777354541591-1777308180429)*60/1024/1024;
  8. +——————————————–+
  9. | (1777354541591-1777308180429)*60/1024/1024 |
  10. +——————————————–+
  11. |                              2652.80696869 |
  12. +——————————————–+
  13. 1 row in set (0.00 sec)

在这个60s的采样情况下,InnoDB每小时写入2.6GB数据。所以如果innodb_log_files_in_group没有更改(默认是2,是InnoDB重复日志的最小数字),然后设置innodb_log_file_size为2560M,那么你实际上两个日志文件加起来有5GB,够你写两小时数据了。

更改重做日志大小

更改innodb_log_file_size的难易程度和能设置多大取决于你现在使用的MySQL版本。
特别地,如果你使用的是5.6之前的版本,你不能仅仅的更改变量,期望服务器会自动重启。
好了,下面是步骤:
1.在my.cnf更改innodb_log_file_size
2.停止mysql服务器
3.删除旧的日志,通过执行命令rm -f /var/lib/mysql/ib_logfile*
4.启动mysql服务器 – 应该需要比之前长点的时间,因为需要创建新的事务日志。
最后,需要注意的是,有些mysql版本(比如5.6.2)限制了重做日志大小为4GB。所以在你设置innodb_log_file_size为2G或者更多时,请先检查一下MySQL的版本这方面的限制。