phpMyAdmin浏览数据页面卡死

我们使用phpMyAdmin经常是一进去就直接展开数据库,点击表名查看数据,这样可以清楚的了解表的结构方便写 SQL。默认情况下是显示 25 条数据,即使有几亿行也很快。

但最近我换了一个 read 账号登录,点击表名的时候直接卡死了

应该是查询卡住了,命令行连上数据库,show full processlist发现有个查询确实卡住了:

一开始只关注到状态是Creating Sort Index,再结合使用 write 账号登录打开却很快的现象,认为是 read 账号没有 create 权限,导致卡着了(没有权限的话应该是直接报错的)。但是查了下 read 账号其实给的就是全部权限,一度陷入了僵局。

调整心态,回到原点,还是从「使用 write 账号登录打开却很快」的现象出发,查看日志,发现 write 账号进入的话点击表名浏览数据使用的 SQL 没有ORDER BY,那就是自动加的,查了下,phpMyAdmin 会自动保存上一次对字段排序的操作,再次操作字段能取消排序,但问题是我现在已经无法进入浏览页面了。

那考虑是不是能在哪里设置,关闭这个。页面上有个浏览模式设置,但这个试了下好像没啥用。

还是看下官方文档吧,找到了设置项,需要把$cfg['Servers'][$i]['table_uiprefs']$cfg['RememberSorting']设置为false。这个功能还是好的,但在多人使用同一账号,数据量又比较大的情况下,还是关闭比较好,关闭也不影响排序功能,只是排序的操作不会保存下来。

Since release 3.5.0 phpMyAdmin can be configured to remember several things (sorted column $cfg['RememberSorting'], column order, and column visibility from a database table) for browsing tables. Without configuring the storage, these features still can be used, but the values will disappear after you logout.

然后还得把已经保存的设置项清除掉,位置在数据库:phpmyadmin(默认)表:pma__table_uiprefs,把这个表清空即可又回到之前丝滑的感觉了。

参考资料

https://stackoverflow.com/questions/33809816/phpmyadmin-automatically-adding-order-by-to-browse

https://docs.phpmyadmin.net/en/latest/config.html#cfg_Servers_table_uiprefs

tomcat设置remote JVM debug后stop失败

最近突然出现执行 tomcat/bin/shutdown.sh 停止 tomcat 失败的情况,报错如下:

看了一下 catalina.sh: line 365 就是 stop 那里执行失败了,然后调用系统的 kill -15 杀死进程

再仔细看看报错,发现有端口被占用、dt_socket failed to initialize 等提示,觉得应该是加了 debug 命令的原因,去掉就好了。

但这个感觉也不太好,不能因噎废食呀。搜了下相关情况,发现是 JAVA_OPTS 用的不对,应该用 CATALINA_OPTS,因为 CATALINA_OPTS 变量在 stop 的时候不会被使用(如上图)。

所以最优的做法是使用 CATALINA_OPTS 变量设置 remote debug 相关参数。

 

参考资料

解决tomcat shutdown时的地址被占用问题,https://my.oschina.net/u/1770666/blog/370620

https://stackoverflow.com/questions/11222365/catalina-opts-vs-java-opts-what-is-the-difference

现代化的PHP-写好注释

注释

有个段子:程序员最恨写注释和不写注释的人。个人认为注释主要作用是方便别人或者自己以后能快速理解这段代码逻辑和提升开发效率,这样要说的是如何使用注释来提升开发效率。

众所周知,PHP 是弱类型语言,变量的类型是可以变的,但在实际业务中,一个变量或者函数的返回值往往是确定的,确定的类型能提升我们的编码效率,也能把一些低级的错误(弱类型不代表无类型)扼杀在摇篮里。

PHP 主要通过类型声明来说明变量的类型,PHP7 开始允许更多的函数参数类型限定。比如下面这个例子,声明入参是 int 类型,但使用了 array 函数来处理,PhpStorm 能给出实时的提醒。

调用函数参数错误的话也有提示:

但 PHP 会有隐式类型转换,如上面传入浮点数的时候并没有提示错误,因为这也是合理的。不过 PHP 可以开启严格模式来检查此类错误。

PHP 内置的类型声明基本上够用了,但一般使用注释来实现更加丰富的功能。PHPDoc 是注释 PHP 代码的非正式标准,它有许多不同的标记可以使用。PhpStorm 能根据函数/类方法自动生成基本的标记:

基本标记 @param@return 也很好理解,参数和返回值,作用和 PHP 自带的类型声明差不多,主要用来限制调用方传参和使用返回值。除了这两个标记之外,还有很多其它比较好用的标记。

Continue Reading...

GitHub 研发链 travis-ci 和 codecov 介绍

经常混迹于 GitHub 的话就会发现很多项目都有一些徽章,出现最多的就数这两个了:

这些徽章都是可以点击的,第一个点进去是 https://travis-ci.org/,travis-ci 是一个 CI(Continuous integration,持续集成) 平台,主要提供集群编译、单测、集成测试的环境。.org 的服务对公有仓库免费,.com 面向私人、团队、公司的项目提供商业支持(收费)。使用起来非常简单,使用 Github 帐号登录进去,就能看见开始界面:

核心就是.travis.yml的文件配置,一开始可以根据自己的语言选择初始的配置文件:https://docs.travis-ci.com/user/customizing-the-build#Specifying-Runtime-Versions。我这边的项目使用的是 Python,初始配置是:

官方注释可以说非常详细,我就不画蛇添足做说明了,根据自己代码实际情况做调整即可:

配置好之后再 push 代码,就能在 travis-ci 页面上看见项目的构建、测试结果了:

点击图标就能生成我们需要的 MD 语法的代码了,粘贴进 README.MD 中就能显示了。

第二个徽章是 codecov.io(单测覆盖率统计平台),接入过程也很简单,也是不同语言选择不同的配置文件,codecov 可以无缝衔接 travis-ci,只需要在原来的配置文件上稍作修改即可,核心就是生成单测的结果文件。修改后的 .travis.yml

在原来的基础上多了 codecov nose 插件的下载和运行单测时多了--with-coverage等参数。最后还是再次 push 代码就能看见单测覆盖率报告了:

codecov 还有自己的配置文件:codecov.yml。用来实现一些定制化需求,比如说我需要排除一些模块,不进入覆盖率统计:

徽章生成代码的话在setting中可以找到:

除了上面介绍的这两个徽章,还可以通过 shields.io 平台生成一些其它的徽章,甚至可以自定义,比如 https://img.shields.io/badge/Python-2.7-brightgreen.svg 就可以生成一个表示 Python 版本的徽章,别人能看懂就行。

当然徽章不是重点,不是越多的越牛逼,重要的是规范整个研发流程。上面说的两个其实都是属于 CI(持续集成)中最具代表性的两个环节,算是入门了。关于 CI 是一个很大的话题了,这个有机会以后再说一下。

参考资料:

开源项目徽章集锦,https://segmentfault.com/a/1190000004278253

使用 Python nose 组织 HTTP 接口测试

现在前端 Web、移动端 APP 开发基本上是面向接口编程,后端各种 HTTP 接口已经提供好了,大家只要实现逻辑交互和展示就行。那么问题来了,这么多接口如何方便的进行测试呢?根据个人经验,我认为需要解决三个问题:1. HTTP 接口多种多样,测试程序如何统一?2. 测试程序如何规范组织?3. 接口间有上下文依赖,如何解决?

HTTP 接口多种多样,测试程序如何统一?

后端接口可能来自各个系统,GET/POST 协议的、遵循 RESTful 规范的,使用 session 认证、token 认证的,各式各样的接口都存在。但无论怎么变都无法脱离 HTTP 协议。因为组内的技术栈是 Python,这就很容易想到使用 Python 的 requests 库。首先我们使用requests.Session()会话对象,来进行会话保持和 Header、Cookie 等处理。这里我们可以简单封装一个 HttpSession 类,把一些常用操作和设置封装一下:

通过HttpSession()来获取一个requests session对象,后续的 HTTP 请求都通过它发起。requests 提供 get()、post() 等各种方法调用,但这会让测试代码显得不统一,这里我们直接调用底层的 request 方法,该方法几乎提供了发起一个 HTTP 请求需要的所有参数,非常强大。

这样每一个 HTTP 接口的测试都可以通过准备参数发起请求断言结果三板斧来解决。

测试程序如何规范组织?

前面我们已经解决了如何快捷的发起一个 HTTP 请求的问题,这让我们几行代码就可以测试一个接口的返回值。但你会发现新的问题又来了,各种脚本散乱在一堆,返回值解析各种中间变量,各种配置硬编码在代码中,测试结果全靠 print,这时 nose 框架就派上用场了。nose 是 Python 最流行的一个单测框架,提供测试 case 设置标签、测试 case 查找、强大的断言函数,格式化/可视化报告输出等功能。这样就可以像写单测一样写 HTTP 接口测试了。我们可以把一类接口的测试放在一个类里面,甚至可以把基础变量的定义放在基础测试类里面,其它测试类继承这个基类。

HttpTest基类只做了两个工作:1. 创建http会话对象;2. 读取配置文件到类变量config中。配置文件是一个很好的编程实践,这让我们测试程序和数据能够分离,可以通过调用不同的配置文件来测试不同环境的接口,让我们测试程序不光能做线下测试,还能做线上回归和监控,切换成本非常低。

我这里选择 yaml 语法来组织配置信息,yaml 语法风格类似 json,自带基础数据结构,但更加易于书写和阅读,非常适合做配置文件。通过-env=xxx指定配置文件路径(或者 nose.cfg 配置文件中指定),使用 ruamel.yaml 来解析 yaml,转换为 Python 中能直接操作的数据结构。

这一切都放在setUpClass方法中,在具体测试 case 运行之前就已经准备好这些工作了。 Continue Reading...

WordPress通用优化策略及常用插件推荐

WordPress 安装很方便,可以说是开箱即用。但是随着文章增多,访问量增大,会发现 WordPress 很“慢”。这是 WordPress 本身的 PHP 运行机制导致的,每篇文章都要去数据库读取,而且 WordPress 为了支持各种功能,现在已经非常臃肿,每次请求都要加载很多东西。但正是 WordPress 的功能强大,让我们也能很方便的做各种优化。

0x1 使用最新版本的 PHP 和 MySQL

毫无疑问升级基础运行环境是提高性能最好的方式之一。特别的 PHP7 和 MySQL 5.7 较之前的版本性能提升很大。还可以根据服务器配置适当调整 PHP-FPM 和 MySQL 参数

0x2 使用缓存

这里的缓存有两层意思,一是 PHP 层面的运行数据缓存,二是文章页面静态化。这里推荐几个插件来解决这个问题:

Redis Object Cache

一款持久对象缓存插件。其实 WordPress 本身带有对象缓存功能,但是是把序列化的对象缓存在文件中,效果不是很好。这个插件通过重写 object-cache.php 文件,把对象缓存到 Redis。直观的感受就是不光前台页面加载速度快了,而且后台响应速度提升更大。

Cache Enabler

keycdn 公司开发的一款页面静态化缓存的插件。相比 wp-supercache 等插件更加简洁和强大。建议按照官方说明进行增强设置,官方的配置有一点小问题,当你的永久链接格式设置为 xxx.html 时 $cache_uri(默认是 $request_uri)没有后面的 / 拼凑的文件路径不对(xxx.htmlindex.html),需要改成 ${cache_uri}/index.html,这样虽然访问首页时中间会多个 / 但也不影响。

我使用的是 Nginx,除了正常设置 gzip 外还开启了 gzip_static 参数,让 Nginx 在读取文件的时候优先读取带 gz 后缀的静态文件,不用再做 gzip 压缩。

顺带推荐一个 gzip 检查网站:https://www.giftofspeed.com/gzip-test/

不过使用高级设置后需要把缓存有效期设置为 0(永不失效),可能会造成缓存不会被更新(正常情况下更新文章缓存会被更新)。这里我是通过删除缓存文件然后访问自己 sitemap 中的链接来刷新缓存:

https://gist.github.com/iyaozhen/53e6a57a2f7e945ba1161953959a7cb2

Nginx open_file_cache

上一步我们已经将网站静态化,访问一般的文章页面,其实相当于打开 html 文件,但文件打开关闭也是有开销的,这个能否优化呢?答案是可以的,nginx 提供了 open_file_cache 功能,简单配置即可

此配置是让 nginx work 保持最常访问的文件句柄,不是缓存文件内容(nginx 发送文件是内核态直接发送的,不用应用层用户态保持文件内容),对于中小站点很实用,我们可以通过 sudo lsof -p pid 查看进程打开的文件句柄。这一通骚操作后,TTFB 能降到 10ms 以下。

0x3 使用 CDN 和图片压缩

用户有时候感觉网站慢,更多的是静态资源加载慢。页面上的 JS、CSS、图片等都需要消耗服务器带宽。而且中国地域辽阔,跨地区、跨运营商更是问题。这时就需要 CDN 了。现在国内各个云都在相互竞争,CDN 比较便宜,免费的也有很多。我之前使用的是七牛云,不过自从服务器迁到腾讯云之后, CDN 也换到了腾讯(免费12个月)。这里推荐同为 keycdn 出的 CDN Enabler 插件,能将页面中的链接替换为 CDN 链接。同时推荐使用 WP SmushCompress JPEG & PNG images 压缩图片(有条件的还可以付费开启 webp),还有使用 BJ Lazy Load 实现图片懒加载(显著提高首屏加载速度)。最后不要忘记站点和 CDN 都配置一下防盗链。

0x4 升级到 HTTP2

HTTP2 支持请求复用,能提高50-70%的加载速度。首先要配置 HTTPS,再简单的配置下就能支持 HTTP2 了。当然静态资源使用的 CDN 最好也要支持 HTTP2,目前国内厂商基本都支持。

0x5 配置dns-prefetchpreconnectprerender等资源加载参数

Continue Reading...

WordPress 国内优化

众说周知 WordPress 是全球使用量第一的开源博客系统,本博客就是基于此搭建的。但是 WordPress 在国内有些水土不服,有些地方没有考虑中国的国情(GFW),需要做一些小优化。以下代码直接添加在主题或者子主题的模板函数 (functions.php)文件中即可,此文件可在后台直接编辑(外观->编辑)。

1. 移除 Google CDN 字体。英文博客使用 web-font 还是很不错,各个平台使用同一种字体,极大地提升了用户体验,但是中文博客基本用不上,而且 Google CDN 被墙,还会极大影响页面加载速度,所以还是直接去掉吧。

2. Gravatar 地址替换。WordPress 默认使用的几个 Gravatar 头像地址都被墙了,建议替换为 V2ex 提供的 CDN 地址(支持 HTTP2)。注意,官方地址路径为 /avatar,V2ex 的 CDN 为 /gravatar。

3. 使用最新的 jQuery 以及使用 CDN(BootCDN,支持 HTTP2)。需要注意测试,可能有些插件会有兼容问题。

4. 移除自动 dns-prefetch。WordPress 4.6 增加了 dns-prefetch 功能,他会分析页面注入的 js 等脚本然后,加入 DNS 预加载列表。wp-includes/general-template.php:

当然这个功能出发点是好的,但是有些域名解析很慢,预加载可能会拖慢速度,而且我也不需要使用 emoji 和 Google 字体(默认预加载了这两项)。

建议使用插件 instant-articles 来手动设置 DNS 预加载。

目前本博客只进行了这几点国内环境的特色优化,若其它小伙伴还有什么黑科技欢迎交流。当然除了中国特色,也有一些很有效的通用优化策略:WordPress通用优化策略及常用插件推荐

参考资料:

最近针对 V2EX 的 Gravatar 头像加载做了一个优化,https://www.v2ex.com/t/141485

https://www.wpbeginner.com/wp-themes/replace-default-wordpress-jquery-script-with-google-library/

https://wordpress.org/support/topic/remove-the-new-dns-prefetch-code/

一个诡异的 Chrome 视频播放(加载)问题

今晚上线了一个新的 web 页面,主要多了一个背景视频功能,大概是这样:http://thenewcode.com/samples/polina.html 。但上线后遇到一个问题,HTTPS 下背景视频很大概率不播放。线下测试的时候遇到过类似的问题,是因为 webserver 没有在 mime.types 文件添加video/mp4    mp4 mp4v mpg4浏览器不能识别的原因,但线上确定不是这个原因。

Chrome 抓包发现是视频文件请求 412 了,单独访问这个视频文件也是 412 偶现不能访问,但 http 下却没有这个问题。查了下 412 是连接建立先决条件失败,第一次遇到这个错误码,直接看状态码定义,看不出个所以然。看起来自己一时半会儿解决不了呀,马上把这个问题抛到公司的群里,一会儿得到了几个大神的回复:很大可能是 If-Match 和 ETag 对不上的问题。仔细看了下 412 的请求 headers 部分确实是这个现象。

可以看到,Chrome 在加载一个视频的时候是分段加载,当某一个请求 412 的时候会造成整个视频加载失败。群里的璐神给了一些参考资料,里面有一段说明:

在大型多 WEB 集群时,使用 ETag 时有问题,所以有人建议使用 WEB 集群时不要使用 ETag,其实很好解决,因为多服务器时, INode不一样,所以不同的服务器生成的 ETag 不一样,所以用户有可能重复下载(这时 ETag 就会不准),明白了上面的原理和设置后,解决方法也很容易,让 ETag 后面 二个参数,MTime 和 Size 就好了。只要 ETag 的计算没有 INode 参于计算,就会很准了。

觉得这个说得很有道理,决定改一下 Apache 服务器试试。看配置文件的时候发现,http 的配置下有一行 FileETag -INode -MTime Size 的配置,但是 https 下没有,把这一行也加到 https 的配置文件中果然就行了。

虽然问题是解决了,但是感觉还是没有找到根本原因的样子。看了下 Apache 的文档发现 FileETag 默认使用 MTime 和 Size 两个参数,因为集群部署代码时是串行的,且会改变文件的时间(OP 部署系统的锅,中间有一步进行了 cp 操作),所以应该是 MTime 不一样造成了每台服务器上应该是同一个文件的 ETag 不一样,而每个分片请求落在了不同的机器上,造成If-MatchETag对不上,不是之前猜测的 INode 问题。但感觉还是哪里不对,为什么If-MatchETag对上了的请求就没问题了,按照理解ETag是用来做缓存的,对不上很正常,web server应该返回完整内容呀。下班回家又仔细想了一下,觉得这个问题应该反过来思考,因为 Chrome 是分段加载视频,需要保证这个视频在加载过程中是没有变动的,这样才有意义,所以需要每次请求都对比 ETag。那么为什么其它浏览器没这个问题了,抓包发现 IE 没有分段下载功能,是当一个文件都加载完成后才播放。FireFox 没有带上 If-Match 的请求头:

Safari 也没有使用 If-Match 的请求头,因此就 Chrome 下有这个问题。If-Match 的说明也验证了我的猜想:

For GET and HEAD methods, used in combination with an Range header, it can guarantee that the new ranges requested comes from the same resource than the previous one. If it doesn't match, then a 416 (Range Not Satisfiable) response is returned.

当然我这个案例中错误码是 412(通常用作 PUT 方法更新资源出错时),不过这是一个意思,符合预期。

ETag 工作流程和生成算法补充:当客户端第一次向服务器请求资源时,服务器会返回资源并根据资源的一些信息生成 ETag 返回给客户端,客户端不需要了解 ETag 是如何生成的,只需缓存下 ETag 当下次请求时带上(If-None-Match: ETag)。表示如果这个资源的 ETag 和我请求的不一样则返回数据,一样则返回 304。

不同个 webServer 生成 ETag 的算法可能不一样,比如上面提到的 Apache 使用的是 INode MTime Size 三个文件属性计算而得:

参考资料:

Apache配置Etag详解 https://www.yudouyudou.com/jiaochengheji/wangzhanjianshe/262.html

https://httpd.apache.org/docs/2.4/mod/core.html#fileetag

https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/412

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Match

https://web.dev/http-cache/

https://stackoverflow.com/questions/44937/how-do-you-make-an-etag-that-matches-apache

创建 redis systemd 服务

服务器操作系统一直使用的是 ubuntu server,因为安装软件很方便,直接apt-get install就行。但使用 apt 安装 redis 版本比较旧,也没有新的源,所有只能自己编译安装了。不过有个问题,自己编译安装的启动和重启比较麻烦(启动:/usr/bin/redis-server /etc/redis/redis.conf,停止:/usr/bin/redis-cli shutdown)。我在想能不能使用类似 ubuntu service xxx restart 的指令。

搜索了一下发现可以使用upstart来实现这个需求,但是这个在 ubuntu 15.04 已经废弃了,推荐使用更先进的systemd。在 /etc/systemd/system/ 下创建一个 redis.service:

其中主要是定义了启动用户,启动命令,停止命令。有个设置比较重要Type=forking,可以理解为 systemd 是一个类似 supervise 的守护进程,forking 表示服务管理器是系统 init 的子进程,用于管理需要后台运行的服务。同时还需要修改 redis 的配置:

然后就可以使用sudo systemctl start redis命令启动 redis 了。同时支持 stop、restart 等常用指令。启动成功后运行 sudo systemctl status redis查看运行状态:

可以看见 redis 已经正常运行了。可以尝试使用 kill -9 命令把 redis 杀死,你会发现 redis 马上又会被拉起,这样能保证服务能一直运行(当然若是服务有问题一直蹦,谁也救不了你)。若需要开机启动还可以运行sudo systemctl enable redis命令加入到开启启动项里面。

我们平常自己写的程序也可以依样画葫芦写个配置文件,使用 systemctl 来做服务管理,这种方式更加先进,还有一些其它实用的功能。

 

参考资料:

Ubuntu systemd service file for Redis, https://gist.github.com/geschke/ab6afa91b2d9dfcd5c25

systemd - ArchWiki, https://wiki.archlinux.org/title/Systemd

How To Install and Configure Redis on Ubuntu 16.04 | DigitalOcean, https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-redis-on-ubuntu-16-04

Ubuntu 16.04 上安装 MySQL 5.7 的一些细节

最近腾讯云折扣力度比较大,在加上之前 DigitalOcean 上的 VPS 访问不是太顺畅,就把服务器迁回了国内。重装了一把 MySQL,遇到了一些细节上的问题,觉得很有意义,记录下。

首先使用 MySQL 官方的源安装,这个在一年前的《Ubuntu 平滑升级 MySQL 到 5.7》中描述过,具体过程不再赘述。说一些细节上的东西:

1. Ubuntu 16.04 要求 2017.01.01 后所有的源必须使用 SHA2 以上版本的摘要签名算法(https://wiki.debian.org/Teams/Apt/Sha1Removal)。目前来说具体表现是在执行sudo apt-get update时会显示一个警告“W: http://repo.mysql.com/apt/ubuntu/dists/xenial/InRelease: Signature by key A4A9406876FCBD3C456770C88C718D3B5072E1F5 uses weak digest algorithm (SHA1)”。访问一下网址确实看见使用的是 SHA1 签名,这个只能等待官方修复。

2. 安装过程中会要求设置 root 密码,这里你可以你直接回车(设置空密码),但实际上是给你创建了一个 auth_socket 的 root 用户,并不是空密码。

这时你登录的话需要使用 socket 方式连入:sudo mysql --protocol=socket --socket=/var/run/mysqld/mysqld.sock,注意这里需要用 root 权限运行,保证有足够权限读取 sock 文件,不然会默认使用当前用户进行传统的 ip+port 登录,这样肯定是登录不上的。登录上去就可以改 root 密码了,正常执行ALTER USER 'root'@'localhost' IDENTIFIED BY 'test';后发现密码并没有被改变(会报 warning),观察上面的截图会发现 root 账号的认证插件用的是auth_socket,我们需要这样执行命令ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'test';。就能回到传统的账号密码认证了。

3. 细心的同学可能已经发现了,多了一个mysql.sys的用户,按照官方的说法这是给 DBA 使用的,防止直接使用 root 账号带来的重命名和误删账号的问题。这个用户默认有一个初始密码,但在日志里面没找到(源码编译 MySQL 5.7 后 mysql_install_db –initialize 时会把密码记录到日志中)。这里索性重新设置一个密码(ALTER USER 'mysql.sys'@'localhost' IDENTIFIED BY 'test';)。

到这儿基本上已经安装完成了,但若你细心的话会发现在启动日志里面会有一些警告:

1. TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details). 这个是说explicit_defaults_for_timestamp缺省值已经废弃了,需要显式的在 my.cnf 设置 explicit_defaults_for_timestamp = 1

2. [Warning] Could not increase number of max_open_files to more than 5000 (request: 65535) 这是个常见的错误,一般修改 /etc/security/limits.conf 即可,但改了之后好像不奏效。这是因为在 /lib/systemd/system/mysql.service 配置中还有参数 LimitNOFILE 限制,把这里也修改了就可以了。

3. 还有日志中时间的时区和系统的不一致,看日志不方便。这是 5.7 新加的参数log_timestampshttps://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_log_timestamps),在 my.cnf 设置为 log_timestamps = SYSTEM 即可。

全部搞定后建议执行sudo mysql_secure_installation命令,做一些安全设置,比如禁止root远程登录、删除匿名用户、验证密码安全级别等。

最后介绍一个比较好用的命令:mysql_config_editor,解决命令行登录MySQL便捷性和安全性的问题。我们为了本地登录MySQL方便经常会写一些一键登录的小脚本。基本上都是直接执行 mysql -uroot -p'test' 命令,这样会带来一个问题,执行的命令会被记录在bash_history中,当然你也可以禁用bash_history的功能,但这样会失去一些便捷性,也不大方便追查历史的问题命令。而且在新版本中直接使用这种方式登录会有警告信息。

这时我们就可以使用 mysql_config_editor 来创建一个 login-path,登录时直接使用mysql --login-path=xxx即可。一个典型的创建指令:mysql_config_editor set --login-path=xxx --host=localhost --user=root --port=3306 --password,然后输入密码。这里需要注意一下,如果粘贴的密码中有特殊字符会有问题,需要加上引号。比如你的密码是 test!@#,需要复制文本 'test!@#' 进行粘贴。创建的文件默认在 ~/.mylogin.cnf,不过这是个二进制文件,看不出来啥(比较安全)。我们可以使用 mysql_config_editor print --all 命令来看看已经创建的 login-path:

这里也能看见密码是加密存储的,在一定程度上保证了安全。而且 .mylogin.cnf 文件可以分发给使用同一个MySQL-client的用户,提高了安全性也方便运维管理。很实用的功能,强烈推荐使用。

MySQL 每个版本都有很多安全性和性能的改进,值得去学习、研究。而且 MySQL 8(现在都流行跳版本)也快出来了,前景更是一片大好。

 

参考资料:

Change user password in MySQL 5.7 with “plugin: auth_socket”, https://www.percona.com/blog/2016/03/16/change-user-password-in-mysql-5-7-with-plugin-auth_socket/

Where is the MySQL 5.7 root password?, https://www.percona.com/blog/2016/05/18/where-is-the-mysql-5-7-root-password/

Do I need to change the mysql.sys password, https://askubuntu.com/questions/824139/do-i-need-to-change-the-mysql-sys-password

Can not increase max_open_files for Mysql max-connections in Ubuntu 15, https://stackoverflow.com/questions/30901041/can-not-increase-max-open-files-for-mysql-max-connections-in-ubuntu-15

本 Blog 不支持评论,如有疑问或建议请联系我,以完善内容,期望帮助到更多的同学