一些杂事(二)

又出差了好久,出差就会攒一堆经验。不记下来,总觉得亏得慌。本来想要再起一个题目的,但是想到好像之前有一篇踩坑记录也叫这个题目来着,就延续这个题目了。

MySQL从备份恢复的经验

从备份恢复MySQL数据库表其实不是一件困难的事情。MySQL数据库备份本身就是一个SQL文件,从备份恢复数据库表,其实就是从头到尾执行以下这个SQL文件。不过,对于数据量很大的表,想要在短时间内恢复不容易。

数据库备份本身,是一个顺序的文本结构,而一句句地执行插入操作,其实构建了一个B-tree类型的数据结构。从扁平的文本,转换成方便索引的结构,自然需要一定的计算,以及I/O消耗,所以如果没有改任何配置,直接用命令行导入的话,效率非常地不理想。

所以我这两天就一直在研究这件事情。而且也学了一点点常用命令。假如你想中途暂停如何继续。有什么能够提高恢复效率的配置。

大家可能都知道,如何在命令行执行SQL文件。我首先知道的是这种方式:先通过用户名密码进入MySQL交互界面,然后运行

来把xxx.sql里的SQL一句句执行。这种方式真的相当慢,我也不知道是什么原因,但每一句都输出一个“Query OK”一定是原因之一。因为I/O的效率是很影响程序执行的效率的。在吃到这种方法的苦头之后,我开始搜索新的方法。于是就找到了网上大家最常提到的语句

这句没错。但是需要注意做些配置,才能导入得快。我首先加入得配置是这些

具体得解释请参考这个Gist。基本的思路就是让缓存池大一些,I/O线程多一些之类的。总之,都有一些作用。改完这个之后,我就面临一个问题。因为我已经导入了一晚上数据了。我改配置的话势必要停掉MySQL,这样导入就中止了。停掉是肯定要停掉的。可是我又不想完全重来,于是我就整整命令呗。来看看我用了啥命令。

第一步,找到已经入库的最大主键ID

假设这个最大主键就是max_id了。第二步,在SQL备份中搜索,这个max_id在第几行

我们当然不可能用Vim那么“重”的工具了。sed刚刚好,适合进行简单的搜索。

拿到行数之后,就是把备份从这一行的下一行开始截开,这边我用的是tail命令。假设行号是line_num

这样我们就能拿到我们还没插入的所有记录了。另外其实还可以再加一个命令行参数

这会把最大允许的数据包大小提高,从而提升导入的速度。


不过,前面我说的对于提升导入效率来说,有作用,但不算特别明显。但接下来要介绍的这个思路。这可能是一个常识,但可能很多人(包括我)以前都没意识到,这个才是最重要的优化方案。那就是把你要导入的表的索引能去的都去掉。这个很重要!

学过数据结构的同学们,大家可以想象一下这是为什么。你可以想象每一个索引都要维护一棵

二叉树。你每插入一条数据,都要维护这么多棵二叉树,它们的平衡,那消耗可想而知。如果摆脱了它们,但就是数据插入硬盘的话,当然会快很多。事实也确实如此。当我处理掉那些索引以后,恢复数据表变得轻松愉快起来了。原本的方法花了一天的时间才做完一点点,这个只要几个小时。

搞完之后,即便还需要加回来索引,也会比每次插入数据都维护结构要快很多。

FastDFS文件服务器的坑

不知道公司为什么用FastDFS这种软件。因为简单好用吗?还是因为比HDFS或者其他什么在性能上表现出来的优势呢?还是因为它是一个国产软件呢?不管怎样,我要开始说这次遇到的问题了,也许不能算是坑,但我觉得算啦。也许是我不了解它。

我们的FastDFS一直部署在某个生产服务器上面。一个以我以前的想象怎么也填不满的大小,8TB。但是,它就是满了。满了之后用到文件服务器的我们的各种服务开始变慢,然后我们开始找寻解决的办法。

我的第一个反应就是删除没用的文件。但这是文件服务器。删除没用的文件,可以延迟服务器满的时间。但我期待的事却没有发生。文件还是存不进去。解决不了,只能找万能的搜索引擎了。

终于让我找到了一个能够成功挺过去的方法。你们知道嘛,FastDFS的默认配置会给分区预留10%的空间。对于8T来说,就是预留了800G的空间。这种策略对于本身TB级的存储有点白痴啊。虽然可以改吧,但如果能够自动判断,那就会更方便了。800G的空间,让我们成功撑过了关键的时期。

但是过了十数日,问题终于还是又冒出来了。于是我们有了两种方案:新增服务器,或者加硬盘。根据大师的说法,加块硬盘需要做RAID。咱也不懂RAID是啥,上维基查说是通过组合多个硬盘,提升性能或数据冗余。好像懂Linux的大神都懂这个。总而言之,最终我们采用的是搞一台新服务器。于是整来了一个华为鲲鹏服务器。关于鲲鹏的吐槽我不在这里说,就说安上FastDFS之后遇到的问题。

或许是我没有按照常理出牌的缘故,在第一天晚上按照教程配置好FastDFS之后,能够顺利使用。但是出现了一个问题,加载图片有时候快有时候慢。好了,不卖关子了,我直接说我认为问题在哪。就是ngx_fastdfs_module这个模块有坑。当然这个模块设计初衷是没问题的,但是缺乏文档,所以我们公司默认配置的就不完全对。我们一直用着不完全对,而能用的配置,在我们的生产环境中。

当我们按照默认配置安装,并且按照网上教程书写Nginx配置文件的时候,是不会有问题的。但为什么我还说这个模块有坑呢?坑就在于我们想让这个Nginx发挥正常Nginx功能的时候。我大概是这么配置Nginx的。

上面83是我们原来磁盘满的文件服务器地址,那边只存储group1的文件。而新服务器只存储group2的文件。我做的操作就是把新服务器的作为一个跳板,当路径是group1的时候,我就代理到老服务器上面。请大家注意,我就用上面的配置运行了好几天,也就是这样卡卡地运行了好几天。心里安慰一下,总好过完全不能用的时候。

终于有一天,我打算研究一下原因。下面是我想要给各位看的,我的分析和解决。

现象

首先我把现象都描述一下。

分析和解决

我一开始怎么也没想到会是ngx_fastdfs_module的问题。我反复怀疑自己写Nginx配置的能力。总是在想,以前这样配置代理就可以访问了啊,为什么这次不行了。我甚至在下面又写了一个代理别的网站的配置,结果别的网站正常,文件服务器的代理就是不行。同样,我不知道为什么会有redirect=1,因为我十分怀疑增加redirect=1会导致缓存功能无效。另外,为什么是8888端口?83上明明绑定的19999端口,而且我用

在83上试过了,但发现这个端口没有程序在listen。当初由于需要顶过紧要关头,我把83的Nginx也改到绑定8888端口,才可以将就使用。我尝试用Nginx重新设置header中的Host,也没有卵用。

直到我在网上搜到redirect=1是FastDFS加上的,我才去分析ngx_fastdfs_module的问题。另外从正常逻辑来看,ngx_fastdfs_module是加到/group2上面的,所以我理所当然地认为它不会影响/group1的代理行为,但事实不是这样。只要你在nginx.conf里加了这句话,ngx_fastdfs_module就会对/group[0-9]之类的location都产生影响,即便你没有配置。而我在/group1配置了代理,虽然走了代理,但端口被它篡改了,不受我控制,而且我想proxy_cache的设置也有可能与它有关。

我们公司默认的FastDFS的nginx配置是这样的

这让当初的我对ngx_fastdfs_module产生了一定误会。在这次人工在华为鲲鹏机器上安装FastDFS的时候,我发现它教程配置了root目录。我原来以为只要有ngx_fastdfs_module,就可以不必配置root目录了。

那么ngx_fastdfs_module到底是干啥用的呢?网上的解释是“在storage之间同步数据时候,还没同步完全时候就发生下载时,直接从源数据storage下载”。原来还有这操作?我本以为这些storage之间的交换在FastDFS层做好就行了,Nginx只要从storage里取文件就行了。其实细想想,这样的设计还是合理的。配置root会让Nginx默认查找这个文件,没有的话,应该才会走ngx_fastdfs_module的逻辑吧。而且,有了ngx_fastdfs_module,即便root路径配错,也会找到文件,这可能就是所有文件都redirect的原因。

了解了前因后果之后,我意识到,我并不需要ngx_fastdfs_module这个模块,直接用Nginx自带的目录访问就行了。因为我不需要去别的storage去下载没有的文件。因为目前group1和group2都只有自己服务器上的storage而已,并没有互通。于是我在两个服务器上的Nginx配置中,都注释掉了ngx_fastdfs_module这一行,并且纠正了root的路径。重启之后,我意外发现,/group1的请求开始往83的19999发了。于是,我终于可以把83的Nginx重新绑定回19999端口,避免影响我们自己其他不知道什么服务,或者其他厂家访问这台服务器上的文件。