`

mysql set global read_only操作

 
阅读更多

       最近了解mysql MDL的设计。发现mysql "set global read_only=on/off"操作也依赖metadata lock(5.6.16, 推测是从5.5引入metadata lock后就这样了,没有查看更早版本的代码确认)。下面是set global read_only=on/off的实现。

      调用路径如下: 

#0  fix_read_only (self=0x134f5a0, thd=0x2470e0a0, type=OPT_GLOBAL)
    at /home/mysql-5.6.16/sql/sys_vars.cc:2219
#1  0x000000000064ab91 in sys_var::update (this=0x134f5a0, thd=0x2470e0a0, var=0x24691df0)
    at /home/mysql-5.6.16/sql/set_var.cc:194
#2  0x000000000064afad in set_var::update (this=0x24691df0, thd=0x2470e0a0)
    at /home/mysql-5.6.16/sql/set_var.cc:670
#3  0x000000000064a6c9 in sql_set_variables (thd=0x2470e0a0, var_list=<value optimized out>)
    at /home/mysql-5.6.16/sql/set_var.cc:573
#4  0x00000000006d779b in mysql_execute_command (thd=0x2470e0a0)
    at /home/mysql-5.6.16/sql/sql_parse.cc:3704
#5  0x00000000006dcb9b in mysql_parse (thd=0x2470e0a0, rawbuf=0x24691c90 "set global read_only=on", 
    length=0, parser_state=<value optimized out>) at /home/mysql-5.6.16/sql/sql_parse.cc:6235
#6  0x00000000006de6b0 in dispatch_command (command=COM_QUERY, thd=0x2470e0a0, 
    packet=0x246c7f61 "set global read_only=on", packet_length=23)
    at /home/mysql-5.6.16/sql/sql_parse.cc:1334
#7  0x00000000006df977 in do_command (thd=0x2470e0a0)
    at /home/mysql-5.6.16/sql/sql_parse.cc:1036
#8  0x00000000006a1f95 in do_handle_one_connection (thd_arg=0x2470e0a0)
    at /home/mysql-5.6.16/sql/sql_connect.cc:982

       主要的实现都在fix_read_only函数内。主要分为2步:第一步初始化GRL 锁需要的第一个metadata lock -- 一个GLOBAL级别的显式的MDL_SHARED类型的metadata lock,第一步完成之后GRL的状态是GRL_ACQUIRED,并且这一步之后其他连接是无法拿到写锁的(新进来的写请求会被拒绝);第二步获取一个COMMIT级别的显式的MDL_SHARED类型的metadata lock,并将GRL的状态修改为GRL_ACQUIRED_AND_BLOCKS_COMMIT,这一步之后所有的事务都不再允许在提交了(所以执行set global read_only操作时如果有大事务正在执行,set global read_only操作是会被卡住的)。 

fix_read_only(),sys_vars.cc:2219
  --my_bool new_read_only= read_only;
  --read_only= opt_readonly;
...
  --lock_global_read_lock(),lock.cc:966 (enum_grl_state m_state = Global_read_lock::GRL_ACQUIRED_AND_BLOCKS_COMMIT -> m_state = GRL_ACQUIRED)
    --mdl_request.init(MDL_key::GLOBAL, "", "", MDL_SHARED, MDL_EXPLICIT);# 初始化一个namespace=GLOBAL的显式的MDL_SHARED的metadata lock, dbname 和 name为“”
    --thd->mdl_context.acquire_lock(&mdl_request,thd->variables.lock_wait_timeout)         # 获取刚刚初始化过的metadata lock
  --make_global_read_lock_block_commit(),lock.cc:1041 (m_state = GRL_ACQUIRED -> m_state = GRL_ACQUIRED_AND_BLOCKS_COMMIT)
    --mdl_request.init(MDL_key::COMMIT, "", "", MDL_SHARED, MDL_EXPLICIT);
    --thd->mdl_context.acquire_lock(&mdl_request,thd->variables.lock_wait_timeout))
...
  --opt_readonly= new_read_only;
  --read_only= opt_readonly;

      细看这段逻辑,其实 set global read_only=on/off最主要的操作还是要把全局变量opt_readonly设置为on/off。之所以有上面这段fix_read_only的逻辑,我觉得是要考虑如何处理处于提交阶段的事务:第一步可以阻止新的写请求,第二步阻止事务提交。

      Global_read_lock也很容易理解:

Global_read_lock主要有下面几个函数:
lock_global_read_lock()
unlock_global_read_lock()
make_global_read_lock_block_commit()

Global_read_lock主要有下面几个变量:
  /**
    In order to acquire the global read lock, the connection must
    acquire shared metadata lock in GLOBAL namespace, to prohibit
    all DDL.
  */
  MDL_ticket *m_mdl_global_shared_lock;
  /**
    Also in order to acquire the global read lock, the connection
    must acquire a shared metadata lock in COMMIT namespace, to
    prohibit commits.
  */
  MDL_ticket *m_mdl_blocks_commits_lock;
  enum_grl_state m_state;

       前面说了set global read_only=on/off最重要的还是设置全局变量opt_readonly。那么只读是如何生效的呢?mysql在执行写操作前/commit的时候会去判断read_only状态(变量opt_readponly),如果read_only=on && 当前用户没有超级权限,就会报1290错误(ER_OPTION_PREVENTS_STATEMENT)--“ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement”

bool trans_begin(THD *thd, uint flags) //transaction.cc,事务开始start transaction/begin
{
...
    if (opt_readonly && !user_is_super)
    {
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
      DBUG_RETURN(true);
    }
...
int ha_commit_trans(THD *thd, bool all, bool ignore_global_read_lock) //事务commit的时候
...
    if (rw_trans &&
        opt_readonly &&
        !(thd->security_ctx->master_access & SUPER_ACL) &&
        !thd->slave_thread)
    {
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
      ha_rollback_trans(thd, all);
...

 

 

 

 PS:

set global read_only=on/off是DBA经常用的一个操作:进行主备切换的时候,一般都会先对主库进行只读操作(on),然后主备同步完成后,再把备库置为可读写(off)。这样可以避免切换的过程中双写引起脏数据。

 mysqld.cc中同时定义了2个变量:my_bool read_only= 0, opt_readonly= 0; opt_readonly是当前系统的read_only状态,read_only是要把read_only设置成的值。

0
0
分享到:
评论

相关推荐

    The MySQL server is running with the --read-only option so it cannot execute this statement

    - 修改`read_only`状态:若需要恢复写入功能,可以使用`SET GLOBAL read_only=0;`命令临时关闭只读模式。 - 查看错误日志:通过阅读MySQL的错误日志(通常在`/var/log/mysql/error.log`)来确定服务器重启的原因。...

    The MySQL server is running with the –read-only option so it cannot execute this statement

    如果其值为1,可以通过`SET GLOBAL read_only=0;`命令临时关闭只读模式,以解决紧急问题。 然而,服务器为何会自动将`read_only`设置为1,这通常与服务器的异常行为有关。在本例中,MySQL因内存溢出被系统强制重启...

    mysql server is running with the --skip-grant-tables option

    mysql&gt; SET GLOBAL read_only=0; ``` 然后刷新权限以应用更改: ``` mysql&gt; FLUSH PRIVILEGES; ``` 接着,如果你遇到了因为binlog_format限制不能执行某些语句的问题,如存储引擎只支持行记录格式,你需要将...

    mysql server is running with the –skip-grant-tables option

    - 首先,你可能需要取消新主库的只读属性,通过执行`mysql&gt; SET GLOBAL read_only=0;`。 - 然后,刷新权限以应用更改:`mysql&gt; FLUSH PRIVILEGES;`。 - 如果你遇到错误,提示“不可能写入二进制日志,因为BINLOG_...

    Mysql主从同步Last_IO_Errno:1236错误解决方法

    mysql&gt; SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; mysql&gt; START SLAVE; ``` ### 永久跳过错误 如果经常遇到特定类型的错误,可以在`my.cnf`配置文件中添加`slave-skip-errors`选项,指定要忽略的错误编号。例如,要...

    mysql5.1升级mysql5.5操作步骤

    特别注意的是,必须将 `innodb_fast_shutdown` 参数设置为 0,以确保在关闭过程中不会跳过任何重要的清理工作,这可以通过执行 `mysql&gt; set global innodb_fast_shutdown=0;` 来实现。 - **停止当前服务**:通过...

    mysql -参数thread_cache_size优化方法 小结

    1. 动态调整:在MySQL命令行中输入`set global thread_cache_size=16`,即可临时修改此参数。 2. 配置文件修改:在`/etc/my.cnf`(或其他MySQL配置文件)中添加或修改`thread_cache_size`的值,如`thread_cache_size...

    mysql主从搭建.docx

    set global read_only=1; 这样,从数据库就只能读取数据,不能写入数据。 注意 在从数据库中,root 用户需要同步主数据库中的数据,所以不能将 root 用户设置为只读模式,否则同步不会成功。可以新建一个普通用户...

    mysql提示got timeout reading communication packets的解决方法

    错误提示: user: ‘root’ host: `localhost’ (Got timeout reading communication packets) MYSQL server has gone away 引起这个原因是不可怕的.原因是更改了系统的断开时间. ...mysql&gt; set global interactiv

    mysql-mha笔记1

    - `set global read_only=1;`:设置从服务器为只读模式,防止在故障切换期间写入数据。 综上,MHA是一个强大的工具,它通过自动化故障检测和处理,降低了MySQL集群的停机时间,提升了系统的整体可用性。结合半同步...

    8.0.22mysql主从配置详细讲解.docx

    SET GLOBAL server_id = 2; ``` 2. **开始复制**:使用在主服务器上获取的信息设置复制: ``` CHANGE MASTER TO MASTER_HOST='主服务器IP', MASTER_USER='replication', MASTER_PASSWORD='your_password', ...

    mysql-5.5配置文件模板-详解1

    - `SET GLOBAL sort_buffer_size = &lt;value&gt;` - 修改全局排序缓冲区大小,影响所有新创建的会话。 - `SET @@sort_buffer_size := &lt;value&gt;` - 更改当前会话的变量值。 - `SET @@session.sort_buffer_size := &lt;value&gt;` ...

    mysql不重启的情况下修改参数变量

    首先,当我们尝试通过`SET GLOBAL`命令来更改一个参数,如`log_slave_updates`,可能会遇到“read only variable”的错误。例如: ```sql mysql&gt; show variables like 'log_slave_updates'; +--------------------+...

    MySQL学习笔记5-数据库性能优化与扩展.md

    $MYSQL_CMD -e "SET GLOBAL read_only = 0;" echo "Slave promoted to master." fi ``` #### 负载均衡 ##### 代理层 代理层可以实现负载均衡功能,将请求分发给多个数据库节点,以达到均衡负载的目的。 - **...

    解决C#操作Mysql时中文乱码问题

    SET GLOBAL character_set_server = 'utf8'; ``` 综上所述,解决C#操作MySQL时的中文乱码问题需要从数据库连接、数据表创建、代码处理、文件编码等多个方面综合考虑。仔细检查并调整上述环节,通常能有效避免乱码...

    52 MySQL是如何支持4种事务隔离级别的?Spring事务注解是如何设置的?l.pdf

    - `Isolation.READ_COMMITTED`:防止脏读,但允许不可重复读和幻读。 - `Isolation.REPEATABLE_READ`:防止脏读和不可重复读,但允许幻读。 - `Isolation.SERIALIZABLE`:最严格的隔离级别,防止脏读、不可重复读和...

    mysql配置[归类].pdf

    - 使用SQL命令设置新的最大连接数:`set GLOBAL max_connections=200` - 检查当前状态:`show processlist` 和 `show status` - 退出客户端:`exit` 3. **方法三**:修改源代码重新编译 - 解压MySQL源代码,...

    mysql 优化教程

    `,其中`handler_read_key`值高表示使用索引查询较多,而`handler_read_rnd_next`值高则表明查询效率低。 #### 九、其他SQL优化技巧 - **ORDER BY NULL**:使用`ORDER BY NULL`禁用不必要的排序。 - **使用JOIN...

    mysql数据库 slave复制异常问题解决办法.docx

    mysqlbinlog --start-position=&lt;前一个有效位置&gt; --stop-position=&lt;Read_Master_Log_Pos&gt; ./mysql-bin.000342 ``` 3. **确定新的同步位置**:根据分析结果,确定一个新的位置,确保数据的一致性。 4. **配置并启动...

    mysql数据库复制维护说明.pdf

    - **Read_Master_Log_Pos**:已经读取的日志文件位置。 - **Relay_Master_Log_File**:从服务器上的中继日志文件名称。 - **Slave_IO_Running**:I/O线程是否正在运行。 - **Slave_SQL_Running**:SQL线程是否...

Global site tag (gtag.js) - Google Analytics