精华内容
下载资源
问答
  • MySQL 8 复制)——异步复制

    千次阅读 多人点赞 2019-05-10 18:25:10
    目录 、MySQL异步复制介绍 1. 复制的用途 2. 复制如何工作 ... 简单说,复制就是将来自个MySQL数据库服务器(主库)的数据复制个或多个MySQL数据库服务器(从库)。传统的MySQL复制提供了...

    目录

    一、MySQL异步复制介绍

    1. 复制的用途

    2. 复制如何工作

    3. 两阶段提交

    二、复制实验环境

    三、安装mysql-8.0.16

    四、配置异步复制

    1. 空库

    2. 脱机

    3. 联机


    一、MySQL异步复制介绍

            简单说,复制就是将来自一个MySQL数据库服务器(主库)的数据复制到一个或多个MySQL数据库服务器(从库)。传统的MySQL复制提供了一种简单的Primary-Secondary复制方法,默认情况下,复制是单向异步的。MySQL支持两种复制方式:基于行的复制和基于语句的复制。这两种方式都是通过在主库上记录二进制日志(binlog)、在从库重放中继日志(relylog)的方式来实现异步的数据复制。二进制日志或中继日志中的记录被称为事件。所谓异步包含两层含义,一是主库的二进制日志写入与将其发送到从库是异步进行的,二是从库获取与重放日志事件是异步进行的。这意味着,在同一时间点从库上的数据更新可能落后于主库,并且无法保证主从之间的延迟间隔。

            复制给主库增加的开销主要体现在启用二进制日志带来的I/O,但是开销并不大,MySQL官方文档中称开启二进制日志会产生1%的性能损耗。出于对历史事务备份以及从介质失败中恢复的目的,这点开销是非常必要的。除此之外,每个从库也会对主库产生一些负载,例如网络和I/O开销。当从库读取主库的二进制日志时,可能会造成一定的I/O开销。如果从一个主库上复制到多个从库,唤醒多个复制线程发送二进制日志内容的开销将会累加。但所有这些复制带来的额外开销相对于应用对MySQL服务器造成的高负载来说是很小的。

    1. 复制的用途

    (1)横向扩展
            通过复制可以将读操作指向从库来获得更好的读扩展。所有写入和更新都在主库上进行,但读取可能发生在一个或多个从库上。在这种读写分离模型中,主库专用于更新,显然比同时进行读写操作会有更好的写性能。需要注意的是,对于写操作并不适合通过复制来扩展。在一主多从架构中,写操作会被执行多次,这时整个系统的写性能取决于写入最慢的那部分。

    (2)负载均衡
            通过MySQL复制可以将读操作分不到多个服务器上,实现对读密集型应用的优化。对于小规模的应用,可以简单地对机器名做硬编码或者使用DNS轮询(将一个机器名指向多个IP地址)。当然也可以使用复杂的方法,例如使用LVS网络负载均衡器等,能够很好地将负载分配到不同的MySQL服务器上。

    (3)提高数据安全性
            提高数据安全性可以从两方面来理解。其一,因为数据被复制到从库,并且从库可以暂停复制过程,所以可以在从库上运行备份服务而不会影响相应的主库。其二,当主库出现问题,还有从库的数据可以被访问。但是,对备份来说,复制仅是一项有意义的技术补充,它既不是备份也不能够取代备份。例如,当用户误删除一个表,而且此操作已经在从库上被复制执行,这种情况下只能用备份来恢复。

    (4)提高高可用性
            复制能够帮助应用程序避免MySQL单点失败,一个包含复制的设计良好的故障切换系统能够显著缩短宕机时间。

    (5)滚动升级
            比较普遍的做法是,使用一个高版本MySQL作为从库,保证在升级全部实例前,查询能够在从库上按照预期执行。测试没有问题后,将高版本的MySQL切换为主库,并将应用连接至该主库,然后重新搭建高版本的从库。

    2. 复制如何工作

            如前所述,MySQL复制依赖二进制日志,所以要理解复制如何工作,先要了解MySQL的二进制日志。
    (1)二进制日志
            二进制日志包含描述数据库更改的事件,如建表操作或对表数据的更改等。开启二进制日志有两个重要目的:

    • 用于复制。主库上的二进制日志提供要发送到从库的数据更改记录。主库将其二进制日志中包含的事件发送到从库,从库执行这些事件以对主服务器上的数据进行相同的更改。
    • 用于恢复。当出现介质错误(如磁盘故障)时,数据恢复操作需要使用二进制日志。还原备份后,将重新执行备份后记录的二进制日志中的事件。

            不难看出,MySQL二进制日志所起的作用与Oracle的归档日志类似。二进制日志只记录更新数据的事件,不用于SELECT或SHOW等语句。通过设置log-bin系统变量开启二进制日志,MySQL 8中缺省是开启的。

            二进制日志有STATEMENT、ROW、MIXED三种格式,通过binlog-format系统变量设置:

    • STATMENT格式,基于SQL语句的复制(statement-based replication,SBR)。每一条会修改数据的SQL语句会记录到binlog中。这种格式的优点是不需要记录每行的数据变化,这样二进制日志会比较少,减少磁盘I/O,提高性能。缺点是在某些情况下会导致主库与从库中的数据不一致,例如last_insert_id()、now()等非确定性函数,以及用户自定义函数(user-defined functions,udf)等易出现问题。
    • ROW格式,基于行的复制(row-based replication,RBR)。不记录每一条SQL语句的上下文信息,仅需记录哪条数据被修改了,修改成了什么样子,能清楚记录每一行数据的修改细节。其优点是不会出现某些特定情况下的存储过程、函数或触发器的调用和触发无法被正确复制的问题。缺点是通常会产生大量的日志,尤其像大表上执行alter table操作时候会让日志暴涨。
    • MIXED格式,混合复制(mixed-based replication,MBR)。是语句和行两种格式的混合使用,默认使用STATEMENT模式保存二进制日志,对于STATEMENT模式无法正确复制的操作,会自动切换到基于行的格式,MySQL会根据执行的SQL语句选择日志保存方式。

            MySQL 8缺省使用ROW格式。二进制日志的存放位置最好设置到与MySQL数据目录不同的磁盘分区,以降低磁盘I/O的竞争,提升性能,并且在数据磁盘故障的时候还可以利用备份和二进制日志恢复数据。

    (2)复制步骤
            总的来说,MySQL复制有五个步骤:

    1. 在主库上把数据更改事件记录到二进制日志中。
    2. 从库上的I/O线程向主库询问二进制日志中的事件。
    3. 主库上的binlog dump线程向I/O线程发送二进制事件。
    4. 从库上的I/O线程将二进制日志事件复制到自己的中继日志中。
    5. 从库上的SQL线程读取中继日志中的事件,并将其重放到从库上。

            图1更详细地描述了复制的细节。

    图1 复制如何工作

     

            第一步是在主库上记录二进制日志。在每次准备提交事务完成数据更新前,主库将数据更新的事件记录到二进制日志中。MySQL会按事务提交的顺序而非每条语句的执行顺序来记录二进制日志。在记录二进制日志后,主库会告诉存储引擎可以提交事务了。

            下一步,从库将主库的二进制日志复制到其本地的中继日志中。首先,从库会启动一个工作线程,称为I/O线程,I/O线程跟主库建立一个普通的客户端连接,然后在主库上启动一个特殊的二进制日志转储(binlog dump)线程,它会读取主库上二进制日志中的事件,但不会对事件进行轮询。如果该线程追赶上了主库,它将进入睡眠状态,直到主库发送信号通知其有新的事件时才会被唤醒,从库I/O线程会将接收到的事件记录到中继日志中。

            从库的SQL线程执行最后一步,该线程从中继日志中读取事件并在从库上执行,从而实现从库数据的更新。当SQL线程追赶I/O线程时,中继日志通常已经在系统缓存中,所以重放中继日志的开销很低。SQL线程执行的事件也可以通过log_slave_updates系统变量来决定是否写入其自己的二进制日志中,这可以用于级联复制的场景。

            这种复制架构实现了获取事件和重放事件的解耦,允许这两个过程异步进行。也就是说I/O线程能够独立于SQL线程之外工作。但这种架构也限制了复制的过程,其中最重要的一点是在主库上并发更新的查询在从库上通常只能串行化执行,因为缺省只有一个SQL线程来重放中继日志中的事件。在MySQL 5.6以后已经可以通过配置slave_parallel_workers等系统变量进行并行复制,在后面讨论与复制相关的性能问题时会介绍并行复制的相关细节。

            现在我们已经了解了MySQL复制是以二进制日志为基础的,但是像Innodb这样的事务引擎有自己的事务日志,如ib_logfile,这些事务日志通常被称为重做日志(redo log)。作为背景知识,简单介绍下Innodb重做日志的作用。

            对Innodb的任何修改操作都会首先在称为缓冲池(innodb buffer pool)的内存页面上进行,然后这样的页面将被标记为脏页,并被放到专门的刷新列表上,后续将由master thread或专门的刷脏线程阶段性的将这些页面写入磁盘。这样的好处是避免每次写操作都操作磁盘导致大量的随机I/O,阶段性的刷脏可以将多次对页面的修改合并成一次I/O操作,同时异步写入也降低了访问时延。然而,如果在脏页还未刷入磁盘时,服务器非正常关闭,这些修改操作将会丢失,如果写入操作正在进行,甚至会由于损坏数据文件导致数据库不可用。为了避免上述问题的发生,Innodb将所有对页面的修改操作写入一个专门的文件,并在数据库启动时从此文件进行实例恢复操作,这个文件就是重做日志文件。每当有更新操作时,在数据页变更之前将操作写入重做日志,这样当发生掉电之类的情况时系统可以在重启后继续操作。这就是所谓的预写日志(Write-ahead logging,WAL)。这样的技术推迟了缓冲区页面的刷新,从而提升了数据库的吞吐量。同时由于重做日志的写操作是顺序I/O,相对于写数据文件的随机I/O要快得多。大多数数据库系统都采用类似的技术实现。

            聪明如你可能已经有了这样的疑问,在复制中二进制日志和重做日志如何协同工作?假设Innodb写完重做日志后,服务异常关闭。主库能够根据重做日志恢复数据,但由于二进制日志没写入,会导致从库同步时少了这个事务么?或者反之,二进制日志写成功,而重做日志没有写完,是否导致从库执行事务,而主库不执行?这些情况会不会产生主从数据不一致的问题呢?解决这些问题是MySQL的核心需求,让我们从MySQL基本架构说起。图2是MySQL的逻辑结构图。

    图2 MySQL服务器逻辑架构图

     

            最上层用于处理客户端连接、授权认证、安全等等。第二层架构是MySQL服务器层。大多数MySQL的核心服务功能都在这一层,包括查询解析、分析、优化、缓存以及所有内置函数,所有跨存储引擎的功能(存储过程、触发器、视图等)都在这一层实现。如你所料,二进制日志也在这一层实现。第三层包含了存储引擎,负责MySQL中数据的存储和提取。服务器通过API与存储引擎进行通信,存储引擎只是简单地响应上层服务器的请求。显然Innodb的重做日志在这一层实现。

            由于MySQL的事务日志包含二进制日志和重做日志,当发生崩溃恢复时,MySQL主库通过重做日志进行恢复,而在主从复制的环境下,从库是依据于主节点的二进制日志进行同步数据的。这样的架构对两种日志有两个基本要求:第一,保证二进制日志里面存在的事务一定在重做日志里面存在,也就是二进制日志里不会比重做日志多事务(可以少,因为重做日志里面记录的事务可能有部分没有提交,这些事务最终可能会被回滚)。第二,两种日志中事务的顺序一致,这也是很重要的一点,假设两者记录的事务顺序不一致,那么会出现类似于主库事务执行的顺序是ta、tb、tc、td,但是二进制日志中记录的是ta、tc、tb、td,被复制到从库后导致主从数据不一致。为了达到这两点要求,MySQL使用内部XA来实现(XA是eXtended Architecture的缩写,是X/Open分布式事务定义的事务中间件与数据库之间的接口规范),其核心是两阶段提交(two phase commit,2PC)。

    3. 两阶段提交

            在两阶段提交协议中一般分为事务管理器(协调者)和若干事务执行者(参与者)两种角色。在MySQL内部实现的两阶段提交中,二进制日志充当了协调者角色,由它来通知Innodb执行准备、提交或回滚步骤。从实现角度分析,提交流程和代码框架分别如图3、图4所示。

    图3 MySQL两阶段提交流程

     

    图4 commit命令的MySQL代码框架

     

    (1)先调用binglog_hton和innobase_hton的prepare方法完成第一阶段,binlog_hton的papare方法实际上什么也没做,innodb的prepare持有prepare_commit_mutex,将重做日志刷磁盘,并将事务状态设为TRX_PREPARED。
    (2)如果事务涉及的所有存储引擎的prepare都执行成功,则调用TC_LOG_BINLOG::log_xid将事务(STATEMENT格式或ROW格式)写到二进制日志,此时,事务已经铁定要提交了。否则,调用ha_rollback_trans回滚事务,而事务实际上也不会写到二进制日志。
    (3)最后,调用引擎的commit完成事务的提交。实际上binlog_hton->commit什么也不会做(上一步已经将二进制日志写入磁盘),innobase_hton->commit则清除回滚信息,向重做日志中写入COMMIT标记,释放prepare_commit_mutex,并将事务设为TRX_NOT_STARTED状态。

            如果数据库系统发生崩溃,当重启数据库时会进行崩溃恢复操作。具体到代码层面,Innodb在恢复的时候,不同状态的事务,会进行不同的处理:

    • 对于TRX_COMMITTED_IN_MEMORY的事务,清除回滚段,然后将事务设为TRX_NOT_STARTED;
    • 对于TRX_NOT_STARTED的事务,表示事务已经提交,跳过;
    • 对于TRX_PREPARED的事务,要根据二进制日志来决定事务是否提交,暂时跳过;
    • 对于TRX_ACTIVE的事务,回滚。

            简单来讲,当发生崩溃恢复时,数据库根据重做日志进行数据恢复,逐个查看每条重做条目的事务状态,根据图3的流程,如果已进行到TRX_NOT_STARTED阶段,也就是存储引擎commit阶段,那么说明重做日志和二进制日志是一致的,正常根据重做条目进行恢复即可;事务状态为TRX_ACTIVE,没写到二进制日志中,直接回滚;如果事务状态为TRX_PREPARED,要分两种情况,先检查二进制日志是否已写入成功,如果没写入成功,那么就算是TRX_PREPARED状态,也要回滚。如果写入成功了,那么就进行最后一步,调用存储引擎commit,更改事务状态为TRX_NOT_STARTED,也就是真正提交状态,可以用作数据恢复。

            可见,MySQL是以二进制日志的写入与否作为事务提交成功与否的标志,通过这种方式让Innodb重做日志和MySQL服务器的二进制日志中的事务状态保持一致。两阶段提交很好的保持了数据一致性和事务顺序性。

            了解了所有这些技术细节后,当初的疑问自然也就有了答案。假设在阶段(1)结束之后程序异常,此时没有写入二进制日志,则从库不会同步这个事务。主库上,崩溃恢复时重做日志中这个事务没有trx_commit,因此会被回滚。逻辑上主从库都不会执行这个事务。假设在阶段(2)结束后程序异常,此时二进制日志已经写入,则从库会同步这个事务。主库上,根据重做日志能够正常恢复此事务。也就是说,若二进制日志写入完成,则主从库都会正常完成事务,反之则主从库都回滚事务,都不会出现主从不一致的问题。

            MySQL通过innodb_support_xa系统变量控制Innodb是否支持XA事务的2PC,默认是TRUE。如果关闭,则Innodb在prepare阶段就什么也不做,这可能会导致二进制日志的顺序与Innodb提交的顺序不一致,继而导致在恢复时或者从库上产生不同的数据。在MySQL 8中,innodb_support_xa系统变量已被移除,因为始终启用Innodb对XA事务中两阶段提交的支持,不再让用户来选择。

            上述的MySQL两阶段提交流程并不是天衣无缝的,主从数据是否一致还与重做日志和二进制日志的写盘方式有关。innodb_flush_log_at_trx_commit和sync_binlog系统变量分别控制两者的落盘策略。

    • innodb_flush_log_at_trx_commit:有0、1、2三个可选值。0表示每秒进行一次刷新,但是每次事务提交不进行任何操作(每秒调用fsync使数据落地到磁盘,不过这里需要注意如果底层存储有cache,比如raid cache,那么这时也不会真正落盘,但是由于一般raid卡都带有备用电源,所以一般都认为此时数据是安全的)。1代表每次事务提交都会进行刷新,这是最安全的模式。2表示每秒刷新,每次事务提交时不刷新,而是调用write将重做日志缓冲区里面的内容刷到操作系统页面缓存。从数据安全性和性能比较三种策略的优劣为:1由于每次事务提交都会是重做日志落盘,所以是最安全的,但是由于fsync的次数增多导致性能下降比较严重。0表示每秒刷新,每次事务提交不进行任何操作,所以MySQL或操作系统崩溃时最多丢失一秒的事务。2相对于0来说了多了每次事务提交时的一个write操作,此时数据虽然没有落磁,但是只要没有操作系统崩溃,即使MySQL崩溃,那么事务也是不会丢失的。
    • sync_binlog:MySQL在提交事务时调用MYSQL_LOG::write完成写二进制日志,并根据sync_binlog决定是否进行刷新。默认值是0,即不刷新,从而把控制权交给操作系统。如果设为1,则每次提交事务,就会进行一次磁盘刷新。

            这两个参数不同的值会带来不同的效果。两者都设置为1,数据最安全,能保证主从一致,这也是MySQL 8的默认设置。innodb_flush_log_at_trx_commit非1,假设在二进制日志写入完成后系统崩溃,则可能出现这样的情况:从库能够执行事务,但主库中trx_prepare的日志没有被写入到重做日志中,导致主库不执行事务,出现主从不一致的情况。同理若sync_binlog非1,可能导致二进制日志丢失(操作系统异常宕机),从而与Innodb层面的数据不一致,体现在复制上,从库可能丢失事务。在数据一致性要求很高的场景下,建议就使用缺省的全1配置。

    二、复制实验环境

    1. 主机IP
    172.16.1.125(主)
    172.16.1.126(从)
    172.16.1.127(从)

    2. 软件环境
    OS:CentOS Linux release 7.2.1511 (Core)
    MySQL:MySQL Community Server 8.0.16
    glibc:glibc-2.17-105.el7.x86_64

    3. 硬件环境
    三台虚拟机,每台基本配置为:
    . 双核双CPU,Intel(R) Xeon(R) CPU E5-2420 0 @ 1.90GHz
    . 8G物理内存,8G Swap
    . 100G物理硬盘

    三、安装mysql-8.0.16

            从https://dev.mysql.com/downloads/mysql/下载二进制安装文件mysql-8.0.16-linux-glibc2.12-x86_64.tar.xz,相关选项如图5所示。

    图5 下载mysql-8.0.16安装包

     

    然后用root用户按顺序执行下面的命令,在三台主机上安装MySQL。

    # 进入安装目录
    cd /usr/local
    # 从tar包中把提取文件
    tar xvf /home/mysql/mysql-8.0.16-linux-glibc2.12-x86_64.tar.xz 
    # 建立软连接
    ln -s mysql-8.0.16-linux-glibc2.12-x86_64 mysql
    # 进入mysql目录
    cd mysql
    # 建立secure_file_priv系统变量指向的目录
    mkdir mysql-files
    # 修改属主为mysql
    chown mysql:mysql mysql-files
    # 修改目录权限
    chmod 750 mysql-files
    # mysql系统初始化
    bin/mysqld --initialize --user=mysql
    # 建立SSL/RSA相关文件,如果不启用SSL连接,这步可省略
    bin/mysql_ssl_rsa_setup
    # 启动mysql服务器
    bin/mysqld_safe --user=mysql &
    # 连接mysql服务器
    bin/mysql -u root -p
    -- 修改root密码
    alter user user() identified by "123456";
    -- 创建一个新的mysql管理员账号
    create user 'wxy'@'%' identified with mysql_native_password by '123456';
    grant all on *.* to 'wxy'@'%' with grant option;

            命令说明:
    (1)mysql-files目录用作secure_file_priv系统变量的值。该变量将导入和导出操作限制到特定目录。例如由LOAD DATA和SELECT ... INTO OUTFILE语句和LOAD_FILE()函数所执行的操作。仅允许具有FILE权限的用户执行这些操作。secure_file_priv系统变量设置如下:

    • 空字符串:变量不起作用,是不安全的设置。
    • 目录名:mysql限制导入和导出操作仅用于该目录中的文件。目录必须已经存在,mysql不会创建它。
    • NULL:mysql禁用导入导出操作。

    (2)mysqld --initialize 命令创建默认数据库并退出。在过程中会创建一个超级用户,并为该用户产生一个随机密码。命令执行输出如下所示:

    [root@hdp2/usr/local/mysql]#bin/mysqld --initialize --user=mysql
    2019-05-05T06:31:58.956385Z 0 [System] [MY-013169] [Server] /usr/local/mysql-8.0.16-linux-glibc2.12-x86_64/bin/mysqld (mysqld 8.0.16) initializing of server in progress as process 10256
    2019-05-05T06:32:01.287093Z 5 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: w1SN3pgRPL*D
    2019-05-05T06:32:02.901171Z 0 [System] [MY-013170] [Server] /usr/local/mysql-8.0.16-linux-glibc2.12-x86_64/bin/mysqld (mysqld 8.0.16) initializing of server has completed
    [root@hdp2/usr/local/mysql]#

            mysql文档中说产生的临时密码会写到.err日志文件里,但在本次安装中,这步并不生成.err文件。保险的做法还是记下临时密码,这点很重要。在initialize情况下,临时密码默认标记为已过期,用户必须在第一次进入mysql后首先修改密码。

    (3)mysql_ssl_rsa_setup程序将创建SSL证书和密钥文件,使用SSL进行安全连接所需的RSA密钥对文件。如果现有的SSL文件已过期,mysql_ssl_rsa_setup也可用于创建新的SSL文件。

            mysql_ssl_rsa_setup使用openssl命令,因此主机上必须安装有OpenSSL。mysql_ssl_rsa_setup检查数据目录中的以下SSL文件:

    ca.pem
    server-cert.pem
    server-key.pem

            如果存在任何这些文件,则mysql_ssl_rsa_setup不会创建任何SSL文件。否则,它会调用openssl来创建它们,以及一些其他文件:

    ca.pem               自签名CA证书
    ca-key.pem           CA私钥
    server-cert.pem      服务器证书
    server-key.pem       服务器私钥
    client-cert.pem      客户端证书
    client-key.pem       客户端私钥

            在启用SSL安全客户端连接时需要这些文件。

            之后mysql_ssl_rsa_setup检查数据目录中的以下RSA文件:

    private_key.pem      私钥/公钥对的私有成员
    public_key.pem       私钥/公钥对的公共成员

            如果存在任何这些文件,则mysql_ssl_rsa_setup不会创建任何RSA文件。否则,它会调用openssl来创建它们。对于sha256_password或caching_sha2_password插件验证的帐户不加密连接时,通过这些文件使用RSA进行安全密码交换。

            mysql 8.0.16缺省支持SSL加密连接:

    mysql> show variables like 'have_ssl';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | have_ssl      | YES   |
    +---------------+-------+
    1 row in set (0.00 sec)

    (4)第一次进入mysql后,执行任何命令都会报以下错误:

    ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.

            提示很明显,需要修改初始化时为用户'root'@'localhost'生成的临时密码。mysql 8缺省使用的认证插件是caching_sha2_password:

    mysql> show variables like 'default_authentication_plugin';
    +-------------------------------+-----------------------+
    | Variable_name                 | Value                 |
    +-------------------------------+-----------------------+
    | default_authentication_plugin | caching_sha2_password |
    +-------------------------------+-----------------------+
    1 row in set (0.01 sec)

            当用老版本mysql的客户端连接mysql 8服务器时,可能报以下错误:

    ERROR 2059 (HY000): Authentication plugin 'caching_sha2_password' cannot be loaded: /home/mysql/mysql-5.6.14/lib/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directory

            可以使用两个方法解决此问题。第一种方法是在配置文件中设置default_authentication_plugin='mysql_native_password',然后重启mysql服务器使之生效。default_authentication_plugin是只读系统变量,不能动态修改。第二种方法是在创建用户时,使用兼容新老版本的认证方式,例如:

    create user 'wxy'@'%' identified with mysql_native_password by '123456';

            通过以下查询可以得到用户所对应的认证插件:

    mysql> select host,user,plugin from mysql.user;
    +-----------+------------------+-----------------------+
    | host      | user             | plugin                |
    +-----------+------------------+-----------------------+
    | %         | wxy              | mysql_native_password |
    | localhost | mysql.infoschema | caching_sha2_password |
    | localhost | mysql.session    | caching_sha2_password |
    | localhost | mysql.sys        | caching_sha2_password |
    | localhost | root             | caching_sha2_password |
    +-----------+------------------+-----------------------+
    5 rows in set (0.00 sec)

    四、配置异步复制

            本实验中分别针对空库、脱机、联机三种方式,配置一主两从的mysql标准异步复制。只做整服务器级别的复制,不考虑对个别库表或使用过滤复制的情况。

    1. 空库

            初始安装后,mysql中还没有任何应用数据。此时事先配置好复制,再投入使用,是最理想也是最简单的一种情况,具体配置步骤如下。
    (1)修改server_id系统变量。

    -- 主库
    set global server_id=1125;
    
    -- 从库1
    set global server_id=1126;
    
    -- 从库2
    set global server_id=1127;

            要求复制中所有MySQL实例的server_id都不相同,这里将三个实例的server_id分别配置为1125、1126、1127。server_id系统变量可以动态修改,这样做的好处是不需要重启实例,配置即可在新连接中生效。但是为了避免MySQL重启后配置信息丢失,还需要同时在/etc/my.cnf配置文件中设置server_id参数。

    (2)查看主库二进制日志信息,

    -- 主库
    show master status;

            因为是一个静态的空库,二进制信息此时不会发生变化,可以作为复制的起始点。本例中重启过MySQL实例,输出的信息为:

    +---------------+----------+--------------+------------------+-------------------+
    | File          | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
    +---------------+----------+--------------+------------------+-------------------+
    | binlog.000003 |      155 |              |                  |                   |
    +---------------+----------+--------------+------------------+-------------------+

    (3)在主库上建立复制专属用户

    -- 主库
    create user 'repl'@'%' identified with mysql_native_password by '123456';
    grant replication client,replication slave on *.* to 'repl'@'%';

            前面说过MySQL 8的用户认证机制,这里仍然使用mysql_native_password方式。

    (4)在从库创建主库信息。

    change master to
    master_host='172.16.1.125',
    master_port=3306,
    master_user='repl',
    master_password='123456',
    master_log_file='binlog.000003',
    master_log_pos=155;

            连接主库时,需要使用change master to提供连接到主库的连接选项,包括主机地址、端口、用户名、密码、二进制文件名、复制起始事件位置等。change master to后,在mysql.slave_master_info表中就会生成一条记录,此行为是由master_info_repository系统变量控制的。MySQL 8中,该变量的缺省值为TABLE,即将与复制相关的主库信息记录到mysql.slave_master_info表中。随着复制的进行,表中的数据会随之更新。change master to只是为I/O线程连接主库时提供连接参数,这条语句本身不会连接主库。以后启动I/O线程时,I/O线程都会自动读取这条记录来连接主库,不需要再执行change master to语句。

            类似地,MySQL 8缺省会将中继日志的重放信息存到mysql.slave_relay_log_info表中。该行为由系统变量relay_log_info_repository控制。中继日志信息在首次启动复制时生成,并随复制即时改变。SQL线程再次启动时就能从中获取到从中继日志的的哪个地方继续读取、执行。

    (5)在从库启动复制并查看复制信息

    start slave;
    show slave status\G
    select * from mysql.user where user='repl'\G

            刚才我们并没有在从库上建立repl用户,但由于create user语句是在起始位置点后执行的,因此可以正常复制到从库,查询mysql.user表即可确认。       

            start slave语句会启动I/O线程和SQL线程,并创建一个到主库的客户端连接。该命令执行后,在主库的processlist中会看到类似如下的线程,这些就是从库上I/O线程所建立的,Binlog Dump表示由I/O线程在主库上启动了Binlog Dump线程,每个连接上来的从库对应一个线程,如Id 32和56是两个从库的连接线程:

    mysql> show processlist;
    +----+-----------------+------------+------+-------------+--------+---------------------------------------------------------------+------------------+
    | Id | User            | Host       | db   | Command     | Time   | State                                                         | Info             |
    +----+-----------------+------------+------+-------------+--------+---------------------------------------------------------------+------------------+
      ...
    | 32 | repl            | hdp4:3723  | NULL | Binlog Dump | 328879 | Master has sent all binlog to slave; waiting for more updates | NULL             |
    | 56 | repl            | hdp3:57308 | NULL | Binlog Dump | 319204 | Master has sent all binlog to slave; waiting for more updates | NULL             |
      ...

            从库上的processlist中会看到类似如下的线程,Id 325和326分别对应I/O线程与SQL线程:

    mysql> show processlist;
    +--------+-----------------+-----------+-------+---------+--------+--------------------------------------------------------+------------------+
    | Id     | User            | Host      | db    | Command | Time   | State                                                  | Info             |
    +--------+-----------------+-----------+-------+---------+--------+--------------------------------------------------------+------------------+
      ...
    |    325 | system user     |           | NULL  | Connect | 320408 | Waiting for master to send event                       | NULL             |
    |    326 | system user     |           | NULL  | Query   | 320408 | Slave has read all relay log; waiting for more updates | NULL             |
      ...

            从show slave status输出中可以查看复制状态信息:

    mysql> show slave status\G
    *************************** 1. row ***************************
                   Slave_IO_State: Waiting for master to send event
                      Master_Host: 172.16.1.125
                      Master_User: repl
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: binlog.000011
              Read_Master_Log_Pos: 155
                   Relay_Log_File: hdp3-relay-bin.000002
                    Relay_Log_Pos: 319
            Relay_Master_Log_File: binlog.000011
                 Slave_IO_Running: Yes
                Slave_SQL_Running: Yes
                  Replicate_Do_DB: 
              Replicate_Ignore_DB: 
               Replicate_Do_Table: 
           Replicate_Ignore_Table: 
          Replicate_Wild_Do_Table: 
      Replicate_Wild_Ignore_Table: 
                       Last_Errno: 0
                       Last_Error: 
                     Skip_Counter: 0
              Exec_Master_Log_Pos: 155
                  Relay_Log_Space: 526
                  Until_Condition: None
                   Until_Log_File: 
                    Until_Log_Pos: 0
               Master_SSL_Allowed: No
               Master_SSL_CA_File: 
               Master_SSL_CA_Path: 
                  Master_SSL_Cert: 
                Master_SSL_Cipher: 
                   Master_SSL_Key: 
            Seconds_Behind_Master: 0
    Master_SSL_Verify_Server_Cert: No
                    Last_IO_Errno: 0
                    Last_IO_Error: 
                   Last_SQL_Errno: 0
                   Last_SQL_Error: 
      Replicate_Ignore_Server_Ids: 
                 Master_Server_Id: 1125
                      Master_UUID: 8eed0f5b-6f9b-11e9-94a9-005056a57a4e
                 Master_Info_File: mysql.slave_master_info
                        SQL_Delay: 0
              SQL_Remaining_Delay: NULL
          Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
               Master_Retry_Count: 86400
                      Master_Bind: 
          Last_IO_Error_Timestamp: 
         Last_SQL_Error_Timestamp: 
                   Master_SSL_Crl: 
               Master_SSL_Crlpath: 
               Retrieved_Gtid_Set: 
                Executed_Gtid_Set: 
                    Auto_Position: 0
             Replicate_Rewrite_DB: 
                     Channel_Name: 
               Master_TLS_Version: 
           Master_public_key_path: 
            Get_master_public_key: 0
                Network_Namespace: 
    1 row in set (0.00 sec)
    
    mysql> 

            在从库上执行show slave status可以查看从库状态,输出信息非常多,其中除了那些描述I/O线程、SQL线程状态的行,还有几个log_file和pos相关的行。理解这几行的意义至关重要,所以这里完整地描述它们:

    • Master_Log_File:I/O线程正在读取的master binlog;
    • Read_Master_Log_Pos:I/O线程已经读取到master binlog的哪个位置;
    • Relay_Log_File:SQL线程正在读取和执行的relay log;
    • Relay_Log_Pos:SQL线程已经读取和执行到relay log的哪个位置;
    • Relay_Master_Log_File:SQL线程最近执行的操作对应的是哪个master binlog;
    • Exec_Master_Log_Pos:SQL线程最近执行的操作对应的是master binlog的哪个位置。

            (Relay_Master_Log_File, Exec_Master_log_Pos)构成一个坐标,这个坐标表示从库上已经将主库上的哪些数据重放到自己的实例中,它可以用于下一次change master to时指定的二进制日志坐标。与这个坐标相对应的是从库上SQL线程的中继日志坐标(Relay_Log_File, Relay_Log_Pos)。这两个坐标位置不同,但它们对应的数据是一致的。

            还有一个延迟参数Seconds_Behind_Master需要说明一下,它的本质意义是SQL线程比I/O线程慢多少。如果主从之间的网络状况优良,那么从库的I/O线程读速度和主库写二进制日志的速度基本一致,所以这个参数也用来描述“SQL线程比主库慢多少”,也就是说从库比主库少多少数据,只不过衡量的单位是秒。需要注意的是,该参数的描述并不标准,只是在网速很好的时候做个大概估计,很多种情况下它的值都是0,即使SQL线程比I/O线程慢了很多也是如此。

    2. 脱机

            如果数据库已经存在应用数据,但允许一个可接受的脱机时间窗口做复制,这种场景下常用的做法是先直接将主库的数据目录整体拷贝到从库,再启动复制。具体步骤如下。

    (1)在主库上建立复制专属用户

    -- 主库
    create user 'repl'@'%' identified with mysql_native_password by '123456';
    grant replication client,replication slave on *.* to 'repl'@'%';

    (2)停掉复制涉及的实例

    mysqladmin -uroot -p123456 shutdown

            本例中一主两从三个实例都停止。

    (3)复制将主库的数据目录整体拷贝到从库

    scp -r /usr/local/mysql/data/ 172.16.1.126:/usr/local/mysql

    (4)保证所有参与复制实例的server-uuid和server_id都不同
            这是非常重要的一步,相同的server-uuid或server_id会造成复制错误。从MySQL 5.6开始,用 128 位的 server_uuid 代替了原本的 32 位 server_id 的大部分功能。原因很简单,server_id 依赖于 my.cnf 的手工配置,有可能产生冲突。而自动产生 128 位 uuid 的算法可以保证所有的 MySQL uuid 都不会冲突。首次启动时 MySQL 会调用 generate_server_uuid() 自动生成一个 server_uuid,并且保存到 auto.cnf 文件。这个文件目前存在的唯一目的就是保存 server_uuid。在 MySQL 再次启动时会读取 auto.cnf 文件,继续使用上次生成的 server_uuid。使用 show global variables like 'server_uuid' 命令可以查看 MySQL 实例当前使用的 server_uuid​,它是一个全局只读变量。全局唯一的 server_uuid 的一个好处是,可以解决由 server_id 配置冲突带来的 MySQL 主从复制的异常终止。在从库向主库申请二进制日志时,会首先发送自己的 server_uuid,主库用从库发送的 server_uuid 代替 server_id 作为 kill_zombie_dump_threads 的参数,终止冲突或者僵死的 BINLOG_DUMP 线程。

            删除data_dir/auto.cnf文件,实例启动时会自动生成server_uuid的值。本例中删除从库的/usr/local/mysql/data/auto.cnf文件,并编辑/etc/my.cnf文件修改server_id,保证三个实例的配置互不相同。

    (5)重启实例

    mysqld_safe --user=mysql &

            本例中一主两从三个实例都启动。

    (6)查看主库二进制日志信息,

    -- 主库
    show master status;

    (7)使用上一步的输出在从库创建主库信息。

    change master to
    master_host='172.16.1.125',
    master_port=3306,
    master_user='repl',
    master_password='123456',
    master_log_file='binlog.000004',
    master_log_pos=155;

    (5)在从库启动复制并查看复制信息

    start slave;
    show slave status\G

            此时在从库的err日志文件中可以看到复制正常启动的信息:

    [mysql@hdp3~]$tail /usr/local/mysql/data/hdp3.err 
    2019-05-10T02:54:22.226249Z mysqld_safe Logging to '/usr/local/mysql/data/hdp3.err'.
    2019-05-10T02:54:22.277620Z mysqld_safe Starting mysqld daemon with databases from /usr/local/mysql/data
    2019-05-10T02:54:22.710162Z 0 [System] [MY-010116] [Server] /usr/local/mysql/bin/mysqld (mysqld 8.0.16) starting as process 20571
    2019-05-10T02:54:23.370413Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
    2019-05-10T02:54:23.420160Z 0 [System] [MY-010931] [Server] /usr/local/mysql/bin/mysqld: ready for connections. Version: '8.0.16'  socket: '/tmp/mysql.sock'  port: 3306  MySQL Community Server - GPL.
    2019-05-10T02:54:23.547717Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Socket: '/tmp/mysqlx.sock' bind-address: '::' port: 33060
    2019-05-10T02:56:17.328454Z 144 [Warning] [MY-010604] [Repl] Neither --relay-log nor --relay-log-index were used; so replication may break when this MySQL server acts as a slave and has his hostname changed!! Please use '--relay-log=hdp3-relay-bin' to avoid this problem.
    2019-05-10T02:56:17.333635Z 144 [System] [MY-010597] [Repl] 'CHANGE MASTER TO FOR CHANNEL '' executed'. Previous state master_host='', master_port= 3306, master_log_file='', master_log_pos= 4, master_bind=''. New state master_host='172.16.1.125', master_port= 3306, master_log_file='binlog.000004', master_log_pos= 155, master_bind=''.
    2019-05-10T02:56:25.235523Z 171 [Warning] [MY-010897] [Repl] Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information.
    2019-05-10T02:56:25.237851Z 171 [System] [MY-010562] [Repl] Slave I/O thread for channel '': connected to master 'repl@172.16.1.125:3306',replication started in log 'binlog.000004' at position 155

    3. 联机

            脱机建立复制的需求太过理想化,大多数情况下,复制是被要求在不影响线上业务的情况下,联机创建的,而且还要求对线上库的影响越小越好。例如,复制过程化中对主库加锁会影响对主库的访问,因此通常是不被允许的。这种场景下有两种备选的复制方案:使用mysqldump程序或使用如XtraBackup的第三方工具。这两种方案有各自的适用场合。使用mysqldump联机建立复制的过程如下。

    (1)在主库上建立复制专属用户

    -- 主库
    create user 'repl'@'%' identified with mysql_native_password by '123456';
    grant replication client,replication slave on *.* to 'repl'@'%';

    (2)在从库上创建主库信息

    change master to
    master_host='172.16.1.125',
    master_port=3306,
    master_user='repl',
    master_password='123456';

            注意在上面这条命令中并没有指定主库二进制文件的文件名和位置。

    (3)在从库用mysqldump建立复制

    mysqldump --single-transaction --all-databases --master-data=1 --host=172.16.1.125 --user=wxy --password=123456 --apply-slave-statements | mysql -uroot -p123456 -h127.0.0.1

            说明:

    • --single-transaction参数可以对Innodb表执行非锁定导出。此选项将事务隔离模式设置为REPEATABLE READ,并在转储数据之前向服务器发送START TRANSACTION SQL语句。它仅适用于Innodb等事务表,因为它会在发出START TRANSACTION时转储数据库的一致状态,而不会阻塞任何应用程序。因此这里假定:1. 所有的应用数据表都使用Innodb引擎。2. 所有系统表数据在备份过程中不会发生变化。
    • --master-data参数会导致转储输出包含类似 CHANGE MASTER TO MASTER_LOG_FILE='binlog.000004', MASTER_LOG_POS=1480; 的SQL语句,该语句指示主库的二进制日志坐标(文件名和位置)。如果选项值为2,则CHANGE MASTER TO语句将写为SQL注释,因此仅提供信息,不会执行。如果参数值为1,则该语句不会写为注释,并在重新加载转储文件时执行。如果未指定选项值,则默认值为1。
    • --apply-slave-statements参数会在CHANGE MASTER TO语句之前添加STOP SLAVE语句,并在输出结尾处添加START SLAVE语句,用来自动开启复制。
    • 通过管道操作符,导出导入一步进行,不需要中间落盘生成文件。

    (4)确认复制状态

    -- 从库
    show slave status\G

            mysqldump方式的优点是可以进行部分复制,如在配置文件中定义replicate-do-table=db1.*,则用这种方法可以只复制db1库而忽略其它复制事件。缺点是由于mysqldump会生成主库转储数据的SQL语句,实际是一种逻辑备份方式所以速度较慢,不适用于大库。

            联机建立复制的另一种可选方案是使用XtraBackup。XtraBackup是Percona公司的开源项目,用以实现类似Innodb官方的热备份工具InnoDB Hot Backup的功能,它支持在线热备份,备份时不影响数据读写。到目前为止,最新的版本为Percona XtraBackup 8.0.6,可以从https://www.percona.com/downloads/下载安装包。XtraBackup有很多功能和优点,例如支持全备、增量备份、部分备份;支持压缩备份;备份不影响数据读写、事务等,但是也有缺陷不足:例如不支持脱机备份、不支持直接备份到磁带设备、不支持Cloud Back,MyISAM的备份也会阻塞。不过这些小瑕疵不影响XtraBackup成为一款流行的MySQL备份工具。另外,注意XtraBackup只支持Linux平台,不支持Windows平台。下面演示用XtraBackup联机搭建主从复制的过程,主库已经建立了用于执行复制的用户repl。

    (1)在主、从库安装XtraBackup

    # 安装依赖包
    yum -y install libev
    
    # 安装XtraBackup
    rpm -ivh percona-xtrabackup-80-8.0.6-1.el7.x86_64.rpm

    (2)配置主库到从库的SSH免密码连接

    # 主库执行
    ssh-keygen    
    ... 一路回车 ...    
    ssh-copy-id 172.16.1.126

    (3)停止从库,并清空从库的数据目录

    # 从库执行
    mysqladmin -u root -p123456 shutdown
    
    # 清空数据目录
    rm -rf /usr/local/mysql/data/*

    (3)备份并传输

    # 主库执行
    xtrabackup -uroot -p123456 --socket=/tmp/mysql.sock --no-lock --backup --compress --stream=xbstream --parallel=4 --target-dir=./ | ssh mysql@172.16.1.126 "xbstream -x -C /usr/local/mysql/data/ --decompress"

            这条命令连接主库,进行并行压缩流式备份,同时将备份通过管道操作符传输到从库,并直接解压缩到从库的数据目录。所有操作一条命令完成,不需要中间落盘生成文件。

    (4)在从库恢复备份

    # 应用日志
    xtrabackup --prepare --target-dir=/usr/local/mysql/data/

    (5)查看二进制日志坐标

    cat /usr/local/mysql/data/xtrabackup_binlog_info

    (6)启动从库

    mysqld_safe --user=mysql &

    (7)登录从库启动复制

    -- 创建主库信息,其中的master_log_file和master_log_pos值来自第(5)步
    change master to
    master_host='172.16.1.125',
    master_port=3306,
    master_user='repl',
    master_password='123456',
    master_log_file='binlog.000011',
    master_log_pos=155;
    
    -- 启动复制
    start slave;
    
    -- 确认复制状态
    show slave status\G

            XtraBackup是物理复制,性能比mysqldump高的多,而且对主库的影响极小,非常适用于从头联机创建高负载、大数据量、全实例从库的场景。

    展开全文
  • 粘贴怎样跳过隐藏行,excel技巧

    万次阅读 2019-04-02 20:46:49
    由于筛选后的区域包含隐藏行,因而无法直接进行复制粘贴,否则部分数据会粘贴到隐藏行中。而如果复制后对选择筛选区域用“定位→可见单元格”的方法选择可见单元格,再按“Ctrl+V”进行粘贴,Excel会提示“ ……...

    有时筛选后需将其他区域中的连续行数据复制粘贴到筛选区域,以替换筛选后的数据。由于筛选后的区域包含隐藏行,因而无法直接进行复制粘贴,否则部分数据会粘贴到隐藏行中。而如果复制后对选择筛选区域用“定位→可见单元格”的方法选择可见单元格,再按“Ctrl+V”进行粘贴,Excel会提示“ ……Excel无法粘贴信息,原因是复制区域与粘贴区域形状不同……”。

    一般建议用辅助列处理。
    要把上海和北京的数据筛选出去,然后修改这2个城市的数据再粘贴到原表里对应的城市。其实这个案例用vlookup也很好解决。但如果非要复制粘贴来解决,最简便的还是借助辅助列了。
    在这里插入图片描述
    1,先对原表添加辅助列编号
    在这里插入图片描述
    2,然后再根据城市筛选出上海,北京,再在旁边增加一列筛选辅助列,选中D2:D27,输入数字1,回车
    在这里插入图片描述
    3,然后取消筛选,对D列进行升序或降序排列,这样上海北京的记录都排到原表的最上面

    在这里插入图片描述
    4,复制上海北京的数据记录粘贴到其他空白表里去修改数值,然后再复制修改后的数据记录粘贴到原表上面对应的区域

    在这里插入图片描述

    5,最后对C列进行升序排列即可

    展开全文
  • Redis复制部分同步PSYNC详解

    千次阅读 2019-03-07 11:14:34
    在Redis2.8之前,如果从服务器在主从复制的过程中,出现了断线,重连之后需要全量同步次主服务器上面的数据,即从服务器发送SYNC命令给主服务器,请求进行全量同步,但是断线重连之后,从服务器只是可能落后主...

    概述

    • 在Redis2.8之前,如果从服务器在主从复制的过程中,出现了断线,重连之后需要全量同步一次主服务器上面的数据,即从服务器发送SYNC命令给主服务器,请求进行全量同步,但是断线重连之后,从服务器只是可能落后主服务器断线期间的写入或者如果断线时间非常短,主从之间数据还是一致的,故如果简单地进行全量同步,则会造成主从服务器之间CPU,内存,网络带宽方面的浪费。
    • 故在Redis2.8及其之后版本,对于从服务器断线重连主服务器这种情景,使用的是部分同步PSYNC来实现。即从服务器重连之后,发送PSYNC命令给主服务器,主服务器根据该从服务器的同步情况,决定是只需将断线期间的写入同步给该从服务器,还是需要进行一次全量同步。

    核心设计

    • 在PSYNC中,由于在主从之间只需要同步从服务器落后的部分数据,故在主从服务器中,均需要维护同步状态相关的数据。
    • PSYNC部分主从同步实现的必要组件,即同步状态数据:
      • 主从服务器的复制偏移量;
      • 主服务器的复制积压缓冲区;
      • 主从服务器运行ID。
    复制偏移量
    • 主服务器和从服务器都维护了一个复制偏移量,对应主服务器来说,是记录主服务器同步了多少数据给从服务器,即主服务器每进行一次写操作,如SET key “helloworld”,都会将该写命令同步给从服务器,而在主服务器中会计算这个命令的字节数,假如为N个,则主服务器的复制偏移量将会递增N。
    • 从服务器的复制偏移量则记录了从服务器从主服务器同步了多少字节的数据,如当接收到主服务器的以上写命令时,从服务器也会将自身复制偏移量递增N。
    • 所以如果主从服务器之间的复制偏移量是相等的,表示主从服务器之间数据一致;如果从服务器的小于主服务器的,则表示从服务器落后主服务器,这种情况在从服务器断线重连之后可能会发生。具体过程如以下示意图:(图片均引自黄建宏的《Redis设计与实现》)
      1. 主服务器同步前:
        在这里插入图片描述
      2. 主服务器同步后:
        在这里插入图片描述
    复制积压缓冲区
    • 复制积压缓冲区主要用于缓存主服务器发送给从服务器的数据,在从服务器断线重连后,从该缓冲区查找从服务器断线期间,主服务器的写命令数据,从而主服务器可以从该缓冲区获取从服务器落后的数据,发送给从服务器,实现部分同步。
    • 数据结构:复制积压缓冲区是在主服务器维护的一个大小固定的FIFO的队列,默认大小为1M。即如果超过1M,则主服务器会将队列头部数据出队删除,其中头部数据为最先入队数据,即最早的写入命令数据。具体大小可以通过在配置文件redis.conf中的repl-backlog-size来修改。
    • 合适大小:复制积压缓冲区的合适大小可以根据:seconds * write_size_per_seconds来计算,其中seconds为从服务器断开连接的平均时长,write_size_per_seconds为每秒写(写命令+写的数据)的平均大小。为了安全期间通常为2 * seconds * write_size_per_seconds。
    • 缓冲区的更新:主服务器的复制偏移量和复制积压缓冲区的更新是在主服务器在每次向从服务器传播了N个字节,则将自身的复制偏移量加上N。其中该N个字节的数据是一个写命令(即写命令+写数据)。同时将该次的写命令写入复制积压缓冲区中,写命令的每个字节在复制积压缓冲区都对应一个偏移量,如图:
      在这里插入图片描述
    主从服务器运行ID
    • 在主从同步当中,主从服务器都有自己的运行ID,运行ID是在服务器启动时自动生成的,由40个随机生成的16进制的字符组成。
    • 服务器运行ID的主要作用是:
      1. 从服务器刚开始同步主服务器时,主服务器会将自身的运行ID发送给从服务器,从服务器在内部进行保存。(由于从服务器重启时,没有主服务器的运行ID,故需要进行全量同步)
      2. 之后从服务器断线重新连接主服务器请求同步时,从服务器将之前所连接的主服务器的运行ID传给主服务器,当前这个主服务器检查自己的运行ID和这个从服务器传过来的运行ID是否一致,一致则说明主服务器在断线期间没有更换,故进入根据复制偏移量和复制积压缓冲区来判断是否进行全量还是部分同步的逻辑;否则是主服务器更换过,执行全量同步。

    基于PSYNC的主从同步

    • 主从服务器直接进行PSYNC部分同步通常发送在从服务器断线重连的时候,此时由从服务器发起。除此之外,在心跳检测发现命令丢失时,主服务器也会主动发起一次PSYNC。主从同步示意图如下:
      在这里插入图片描述
    断线重连导致的PSYNC
    • 当从服务器断线重连之后,发送PSYNC命令、自身的复制偏移量和断线前所同步的主服务器运行ID给主服务器,即:

      PSYNC <runid> <offset>
      
    • 主服务器根据该从服务器的复制偏移量offset和主服务器的复制积压缓冲区是否存在该偏移量对应的数据,如果该从服务器偏移量之后(即offset+1)的数据还在该缓冲区中,则执行部分同步,将队列中从offset+1到队列尾的数据发送给从服务器;

    • 否则如果从服务器数据落后太多,如该1M的复制积压缓冲区的头部的偏移量都大于该从服务器复制偏移量(即offset+1),则执行全量同步。

    • 对从服务器而言,发送完PSYNC命令之后,如果主服务器返回+CONTINUE的回复,则说明可以进行部分同步,从服务等待主服务器同步落后的数据过来,主服务器将复制积压缓冲区中该从服务器落后的这部分数据发送过来。如果返回+FULLRESYNCH ,则进行全量同步。如果返回-ERROR,则说明主服务器版本低于2.8,不支持部分同步,此时从服务发送SYNC执行全量同步。

    心跳检测导致的PSYNC
    • 在进入主从同步,主服务器和从服务器建立socket连接之后,从服务器以每秒一次的频率向主服务器发送心跳包,即发送命令:

      REPLCONF ACK <replication_offset>
      
    • 其中replication_offset为从服务器当前的复制偏移量,作用包括:

      1. 检查主从服务器之间的网络状态:如果主服务器超过1秒没有收到从服务器的REPLCONF ACK命令,则说明从服务器网络出问题了;
      2. 辅助实现min-slaves选项:即min-slaves-to-write(主服务器在从服务器数量少于min-slaves-to-write时,拒绝执行写操作),min-slaves-max-lag(多个从服务器的延迟都大于等于min-slaves-max-lag时,拒绝执行写操作);主要保证主从服务器都状态良好时,才执行写操作,保持主从的数据一致性;
      3. 检测命令丢失:主服务器根据从服务器发送过来的复制偏移量replication_offset来判断发送给从服务器的命令是否丢失了,即该复制偏移量不等于主服务器的复制偏移量,则主服务器将复制积压缓冲区对应的落后数据发给从服务器,即主服务器主动发起一次部分同步。
    展开全文
  • 不是会员不让复制粘贴?看我“三板斧”!

    千次阅读 多人点赞 2021-05-09 18:43:25
    前言 不知道你有没有过这样的经历,我们在网上好不容易搜索到自己想要的内容复制粘贴,却被网站要求注册或者购买VIP会员,非常得令人生气和无奈。...个字儿——买(注意:一般人不用考虑该方法,建议跳过,土豪

    目录

     

    前言

    正文

    第一板斧

    第二板斧

    第三板斧

    结尾


    前言

    不知道你有没有过这样的经历,我们在网上好不容易搜索到自己想要的内容,复制粘贴时,却被网站要求注册或者购买VIP会员,非常得令人生气和无奈。今天,我们就来介绍一个非常好用的方法来解决这一系列问题。

    正文

    面对网站注册会员和购买VIP的要求,我们有没有讨价还价的余地呢?是的,看到这篇文章,你今天就是赚到了(如果对你有用,记得点赞呦!)

    接下来,我们以某度文库为例进行说明,怎么不注册会员也能实现复制粘贴文档的内容。

    三板斧走起


    第一板斧

    一个字儿——(注意:一般人不用考虑该方法,建议跳过,土豪随意!)


    第二板斧

    需要一点点开发技巧,在网页中打开“开发者模式”,快捷键一般是F12,本文以chrome浏览器为例进行说明,别的浏览器原理都是一样的。

    好了,开始我的表演!

    比如,我想搜索全国的IP地址库,搜索到的文档内容如下图所示:

    此时,复制的时候会有如下提示:

    这个时候,我们的第二板斧就登场了,打开“开发者模式”,点击左上角的箭头,然后在页面中选择想要复制的内容区域,如下图所示:

    此时,我们就可以在右侧的窗口中双击选中我们想要复制的内容,进行复制粘贴操作了。

    但是这种方式的缺点也是显而易见的,我们每次只能复制一部分内容,比如IP段和位置区域需要分别复制。

    还有没有更加便利的方法呢?

    答案是肯定的。

    请看第三板斧!


    第三板斧

    其实,大家可以不用看前两板斧,直接看第三板斧。调皮一下下,嘿嘿 ^_^

    具体操作也是先打开网页的“开发者模式”,点击右上角的“设置”,在设置页面中,选择“偏好设置”(Preferences),选择“调试器”(Debugger),勾选“禁用JavaScripte”,具体操作如下图所示:

    禁用页面的JS功能后,我们就可以轻松的进行复制粘贴操作了。

    此时,右键出现不一样的“复制”选项,点击“复制”后,就不会出现上面要求购买VIP会员的弹窗了。

    粘贴到自己的文档中,如下图所示:

    深度证明:

    全国IP地址大全1  
    010.179.000.000__010.183.255.255__甘肃____ 
    010.184.000.000__010.188.255.255__青海____ 
    010.189.000.000__010.193.255.255__宁夏____ 
    010.194.000.000__010.198.255.255__新疆____ 
    010.000.000.000__010.001.255.255__北京____ 
    010.003.048.000__010.003.050.255__北京邮电大学____ 
    010.011.017.000__010.013.064.255__天津____ 
    010.017.000.000__010.022.255.255__河北____ 
    010.023.000.000__010.028.255.255__山西____ 
    010.029.000.000__010.033.255.255__内蒙古____ 
    010.034.000.000__010.041.255.255__辽宁____ 
    010.042.000.000__010.049.255.255__吉林____ 
    010.048.000.000__010.051.255.255__黑龙江____ 
    010.052.000.000__010.061.255.255__湖北____ 
    010.062.000.000__010.067.255.255__湖南____ 

    好了,大功告成!

    来吧,赞我!

    结尾

    方法介绍完了, 大家只需要稍微掌握一点前端开发的调试技巧就行了。该方法仅供技术交流学习使用,不要用于商业用途。如果帮到了你,欢迎点赞评论收藏关注

    关注我,分享更多你不知道的开发经验和工作小技巧。

     

     

    展开全文
  • 之前写了篇是在 ubuntu 14.04下装 TensorFlow,装的是cpu版本的,又试着装gpu的但是出现了很多蜜汁问题,担心把之前的caffe环境破坏了,既然现在官方支持Windows系统了,就试试在win10 64位下安装 TensorFlow。...
  • mysql使用GTID跳过事务

    千次阅读 2015-09-17 10:56:34
    GTID跳过有两种方法,一种是普通的跳过一个事务的方法,另外一个是在基于主库搭建新的slave的时候. 一、普通跳过一个事务的方法。 通过show slave status\G找到冲突的GTID号. 然后执行 SET gtid_next = ‘冲突的GTID号...
  • 微信跳一跳自动刷分辅助程序

    千次阅读 2018-01-03 16:23:51
    文章内容转载至以下 链接http://mp.weixin.qq.com/s/cOdW3aDRUAJ2PVbOYiZ5Gg 本文对文章进行了实际...上周微信大更新款名叫【跳一跳】的小程序游戏 关于高分秘籍大家都知道了吧 在以下的方块上停留几秒便会自动加分
  • selenium-跳过登录验证码

    万次阅读 2018-07-28 20:37:24
    3.跳过验证码直接登录成功。 4.验证码识别技术。 第三条写的很模糊,不过下面就介绍一下第三条的实现方法。 先说一下实现思路: 1.打开要测试的网页,获取登录前的cookie(可以抓包获取,可以代码实现,下...
  • 一部分:写给入门者的词袋 什么是 NLP NLP(自然语言处理)是一组用于处理文本问题的技术。这个页面将帮助您从加载和清理IMDB电影评论来起步,然后应用一个简单的词袋模型,来获得令人惊讶的准确预测,评论是点赞...
  • 数据不能增量复制时的解决方案

    千次阅读 2006-04-04 10:41:00
    但很多系统没有时间戳字段或其他字段用来标识数据内容是新增或被修改,因此在复制时无法只提取增量部分,而是全部数据都全部复制一遍,极度费时。而且这种系统通常还不容许在原有数据表中添加新字段来做标记。 ...
  • redis——新版复制

    千次阅读 多人点赞 2019-10-23 08:44:42
    sync虽然解决了数据同步问题,但是在数据量比较大情况下,从库断线从来依然采用全量复制机制,无论是从数据恢复、宽带占用来说,sync所带来的问题还是很多...主库和从库分别各自维护复制偏移量(可以使用info r...
  • MySQL 8 复制(四)——GTID与复制

    千次阅读 多人点赞 2019-06-06 17:52:03
    、GTID简介 1. 什么是GTID 2. GTID的格式与存储 二、GTID生命周期 1. 典型事务的GTID生命周期 2. GTID分配 3. gtid_next系统变量 4. gtid_purged系统变量 三、GTID自动定位 MySQL复制中使用的事务类型有...
  • 相信微信跳一跳这个游戏大家应该都或多或少听或者玩,想必好多朋友看到自己好友们得高分自己却分数老是玩不高! 之前在这个游戏刚出来时候有人用Python写出了个小外挂,随后网上各种各样的外挂包括物理外挂...
  • 本文是Redis主从复制机制的最后篇文章。    主节点在收到从节点发来的PSYNC命令之前,主节点的部分重同步流程,与完全重同步流程是一样的。在收到PSYNC命令后,主节点调用masterTryPartialResynchronization函数...
  • 个方法是个类的不同实例化对象,比如类A,实例化对象a1,a2,:(使用的方法是得到类的属性名) /** * * *@description 转换javabean ,将class2中的属性值赋值给class1,如果class1属性有值,则不覆盖 *...
  • SQL Server复制是我们常用的个提高性能和可用性的功能...也可以选择跳过失败的事务,这样虽然可能会有部分数据不一致但如果能够确保这部分数据不是关键数据则可以使用这个方案。 跳过失败的事务需要用到两个SP,第
  • Mac版git的跳过登录注册方法

    万次阅读 热门讨论 2017-08-22 16:00:35
    3、如果我们对代码进行了更改,在工作副本的未暂存工作区可以看到更改的代码部分,点击暂存-->添加-->推送,便是将修改的代码推送到了远程的仓库上,此时别人拉取后便可以看到你修改的代码了。
  • Redis主从复制主从复制简介主从复制的概念主从复制的作用主从复制工作流程阶段:建立连接阶段主从连接(slave连接master)第种方式第二种方式第三种方式授权访问阶段二:数据同步阶段工作流程数据同步阶段master...
  • 本文演示如何搭建最基本的事务复制。环境准备:虚拟机2台:服务器名分别为RepA和RepB,RepA为发布服务器,RepB为订阅服务器。均安装WindowsServer 2008R2英文版(在外企工作的原因)。并确保两台服务器能互访。SQL ...
  • js实现复制图片到剪切板&下载图片

    千次阅读 2019-08-12 17:44:37
    如果你是页面上已有个图片,可以直接跳过前面的部分。 生成二维码,可以用qrcode。 http://cdn.staticfile.org/jquery.qrcode/1.0/jquery.qrcode.min.js github地址:https://github.com/davidshimjs/qrcodejs $('...
  • 数据库主从复制的原理

    千次阅读 2017-03-02 20:50:06
    从主主复制一主多从---扩展系统读取的性能,因为读是在从库读取的;多主从---5.7开始支持联级复制---     用途及条件   mysql主从复制用途 实时灾备,用于故障切换读写分离,提供查询...
  • wincc项目移植和复制解决办法

    千次阅读 2018-07-06 09:38:00
     wincc项目不支持直接复制部分的后台数据库在活跃状态,直接复制wincc项目,会提示跳过活跃状态的数据库,当跳过活跃数据库复制的项目也是无效的。在wincc项目管理器中打不开复制的wincc项目。  解决办法:...
  • 高性能Mysql主从架构的复制原理及配置详解

    万次阅读 多人点赞 2012-03-06 07:46:32
    将Mysql的数据分布到多个系统上去,这种分布的机制,是通过将Mysql的某台主机的数据复制到其它主机(slaves)上,并重新执行遍来实现的。复制过程中个服务器充当主服务器,而个或多个其它服务器充当从服务器...
  • C++笔记:复制控制

    千次阅读 2014-03-16 08:32:58
    一步了解C++复制控制,复制构造函数,析构函数百科
  • MySQL的GTID复制比传统复制的优势

    千次阅读 2017-08-28 22:41:13
    GTID(Global Transaction ID)是MySQL5.6引入的功能,可以在集群全局范围标识事务,用于取代过去通过binlog文件偏移量定位复制位置的传统方式。借助GTID,在发生主备切换...另外,基于GTID的复制可以忽略已经执行的事
  • ASLR – 第三部分 译者:飞龙 原文:Bypassing ASLR – Part III 预备条件: 经典的基于栈的溢出 ...我们在第一部分中提到,即使可执行文件没有所需的 PLT 桩代码,攻击者也可以使用 GOT 覆盖和解引用技巧
  • mysql 主从复制原理

    千次阅读 2018-01-03 21:52:06
    主从形式 ...从主主复制一主多从---扩展系统读取的性能,因为读是在从库读取的;多主从---5.7开始支持联级复制---     用途及条件   mysql主从复制用途
  • (1)初次复制:从服务器以前没有复制过任何主服务器,或者从服务器当前要复制主服务器和上复制的主服务器不通 (2)断线后重复制:处于命令传播阶段的主从服务器因为网络原因而中断了复制,但从服务器通过自动...
  • 深入 Redis 主从复制的原理详解

    千次阅读 2019-03-28 17:18:37
    4、部分复制 5、心跳 6、异步复制 复制原理 1.复制过程 复制的过程步骤如下: 1、从节点执行 slaveof 命令 2、从节点只是保存了 slaveof 命令中主节点的信息,并没有立即发起复制 3、从节点内部的定时任务...
  • Vim中的多行删除与复制

    千次阅读 2018-05-04 14:29:45
    : 单行删除 :1(待删除行)d 多行删除 :1,10d 法二: 光标所在行 dd 光标所在行以下的N行 Ndd 法三: 光标放到第6行 输入:2yy 光标放到第9行 输入:p 此方法适合复制少量...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 129,999
精华内容 51,999
关键字:

复制时如何跳过一部分内容