MySQL 主从同步及全文索引

这两个都是自己在实际操作上遇到的具体问题,很常见也很实用。MySQL主从复制的需求是因为在将GitHub上一个BitTorrent DHT搜索引擎架设到服务器时,想通过复制实现异步数据同步。而全文索引也是想提高千万数据前提下模糊查询速度,将在之后写出。

主从同步

其中很多都是官方文档中意译过来的,英文文档可能更详细 https://dev.mysql.com/doc/refman/5.7/en/replication-howto.html

一、实现机制

主从同步是在主从复制的基础上个实现的。

MySQL支持两种复制方式:基于行复制和基于语句复制。但本质上都是通过在主库上记录二进制日志(binlog),然后从库上通过一个I/O线程从主库上读取binlog,然后传输到从库的中继日志中,然后从库的SQL线程从中继日志中读取中继日志,然后应用到从库的数据库中。这样就实现了主从同步。

当然实现A->B->C也是这个道理,只不过C读取的是B的 binlog。

二、配置步骤

1、创建复制帐号

创建单独的复制帐号,主从推荐都加,而权限只需要REPLICATION SLAVE 即可。另外开启MySQL远程连接自然也是必须的。

限制帐号登录IP为slaveip
mysql> CREATE USER 'repl'@'slaveip' IDENTIFIED BY 'slavepass';
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'slaveip';

2、主库配置

主库必须开启二进制日志选项,并指定唯一的 serve-id,在配置文件my.cn或my.ini的[mysqld]部分修改,修改后重启。

[mysqld]
log-bin=mysql-bin
server-id=1
#binlog-ignore-db=库名 #可选,设置不同步的库,可设置多个
#binlog-do-db=库名     #可选,开启后只同步这些数据库
#expire_logs_days=10  #可选,设置保留时间
#sync_binlog=5        #可选,设置写入频率,以降低性能减少库崩溃损失

server-id 必填,并且取值在1 ~ (2^32)-1,不为0

在复制设置中尽可能使InnoDB事务的持久性和一致性,您可在master my.cnf文件中使用innodb_flush_log_at_trx_commit = 1和sync_binlog = 1。

3、确定主库当前binlog位置

通过命令行在主库开启一个会话,阻止所有表写入操作(确保位置准确)

mysql> FLUSH TABLES WITH READ LOCK;

#离开当前会话需再输入,保存效果
mysql> FLUSH TABLES

然后查看当前binlog 文件名(File)和位置(Position),需记住并在之后用到

mysql > SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 | 73       | test         | manual,mysql     |
+------------------+----------+--------------+------------------+

在结束第四步后则释放锁

mysql> UNLOCK TABLES;

4、创建数据快照

这是后就有三种情况了:

  • 主从库都没有数据,也没有要导入的数据;
  • 主从库都没有数据,但有需要导入的数据;
  • 主库有存在的数据,但从库是新的空库;
    第一种情况可直接跳到下一步,配置从库。

第二种情况也可直接跳到下一步,配置好从库后,将数据导入主库即自动同步到从库。当然也可分别导入主、从库,然后再从头进行主从同步配置。

第三种情况先将主库中数据导出,再导入到从库。

# --master-data 选项可自动追加从库复制过程需要的 CHANGE MASTER TO
# 如果不加,则需要主库锁住所有的表
# --ignore-table 排除哪些库
# --databases    指定哪些库
shell> mysqldump --all-databases --master-data > dbdump.db

5、从库配置

从库修改配置,并重启数据库。

[mysqld]
server-id=2
#以下为 A->B->C 额外配置
#log-bin=bin     #可选,从库开启二进制日志
#relay-log=relay-bin #可选
#log-slave-updates=1 #可选,允许从库将重放的事件也记录到自身的二进制日志中
#read_only=1     # 防止从库被修改

从库启动复制配置

mysql> CHANGE MASTER TO
    ->     MASTER_HOST='master_host_name',#主库IP
    ->     MASTER_USER='replication_user_name',#复制帐号
    ->     MASTER_PASSWORD='replication_password',#密码
    ->     MASTER_LOG_FILE='recorded_log_file_name',#步骤三的File
    ->     MASTER_LOG_POS=recorded_log_position;#步骤三的Position
    ->     MASTER_CONNECT_RETRY=10; #断开重连时间

启动复制,并查看状态

mysql> START SLAVE; #开启同步,结束则为STOP
mysql> SHOW SLAVE STATUS\G
*************************** 1\. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.0.10
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 73
               Relay_Log_File: relay-bin.000001
                Relay_Log_Pos: 400
        Relay_Master_Log_File: mysql-bin.000003
             Slave_IO_Running: Yes #
            Slave_SQL_Running: Yes #都为yes则正常
            ...
            Seconds_Behind_Master: 0

全文索引

一、前言

个人在实践中遇到的情况是这样的:在InnoDB引擎的一个70万+记录的表中,要模糊查询一个text 类型的字段。常见的like 模糊查询需要消耗1.7 + sec ,已经不让人满意了,更不用说更大量的数据。

二、过程

发现全文索引(FULLTEXT)可能是个不错的办法(当然也可使用一些搜索引擎软件,不过对于几十万量级好像没必要),不过在文档中发现:

1、MySQL是从5.6版本才开始支持InnoDB引擎的全文索引,语法层面上大多数兼容之前MyISAM的全文索引模式。但是不支持中、韩、日文

2、从MySQL 5.7.3开始InnoDB支持全文索引插件,用户可以以Plugin的模式来定义自己的分词规则,或是引入社区开发的全文索引解析器。于是可以使用支持中文的全文索引插件。

3、从MySQL5.7.6版本开始提供了一种内建的全文索引 ngram parser,可以很好的支持CJK字符集(中文、日文、韩文)。内建在代码中,该解析器默认安装,你可以通过指定索引属性(WITH PARSER ngram)来利用该parser。

#创建
mysql> create table ft_test(id int, content text, fulltext (content) with parser ngram);
#修改
mysql> alter table ft_test add fulltext content(content) with parser ngram;

当然如果数据量大的话,这可能需要花不少时间(对我可怜的ECS、VPS够呛的)当然这是值得的,通过全文索引能将查询时间降低到0.06 sec 左右。

而N-Gram是使用一种特殊的方式来进行分词,举个简单的例子,假设要对单词’abcd’进行分词,那么其分词结果为:

N=1 : 'a', 'b', 'c', 'd';
N=2 : 'ab', 'bc', 'cd';
N=3 : 'abc','bcd';
N=4: 'abcd';

N取决于ngram_token_size的设置,默认值为2。

在执行查询时,用户传递的搜索词也会基于N-Gram进行分解后进行检索。而关于停词和分词处理 可参考官方博文 [http://mysqlserverteam.com/innodb全文索引:n-gram-parser/](http://mysqlserverteam.com/innodb全文索引:n-gram-parser/)

阿里的这篇特性讲解也很详细 http://mysql.taobao.org/monthly/2015/10/01/

觉得不错不妨打赏一笔