作家
登录

数据库写操作弃用“SELECT … FOR UPDATE”解决方案

作者: 来源: 2017-09-08 17:03:46 阅读 我要评论

膳绫擎的解决办法只是一些workaround,今朝情况下最最终的解决办法是应用lock-free的办法来对数据库进行操作,也就是无锁的方法,这就 须要对代码进行修改,如今Nova,Neutron,Gnocchi等项目已经对其进行了修改。

数据库写操作弃用“SELECT … FOR UPDATE”解决筹划

问题阐述

Mysql Galera集群是迄今OpenStack办事最风行的Mysql安排筹划,它基于Mysql/InnoDB,我的OpenStack安排方法大年夜本来的主大年夜复制转换到Galera的多主模式。

Galera固然有很多好处,如任何时刻任何节点都可读可写,无复制延迟,同步复制,行级复制,然则Galera存在一个问题,也可以说是在实现 真正的多主可写上的┞粉衷衡量,也就是这个问题导致在代码的数据库层的操作须要弃用写锁,下面我说一下这个问题。

这个问题是Mysql Galera集群不支撑跨节点对表加锁,也就是当OpenStack一个组件有两个会话分布在两个Mysql节点上同时写入一条数据,个一一个会话会碰到 逝世锁的情况,也就是获得deadlock的缺点,并且该情况在高并发的时刻产生概率很高,在社区Nova,Neutron该情况的申报有很多。

这个行动其实是Galera预期的结不雅,它是由乐不雅锁并发控制机制引起的,当产生多个事务进行写操作的时刻,乐不雅锁机制假设所有的修改都能 没有冲突地完成。如不雅两个事务同时修改同一个数据,先commit的事务会成功,另一个会被拒绝,并从新开端运行全部事务。 在事务产生的肇端节点,它可以获取到所有它须要的锁,然则它不知道其他节点的情况,所以它采取乐不雅锁机制把事务(在Galera中叫writes et)广播到所有其他节点上,看在其他节点上是否能提交成功。这个writeset会在每个节点长进行验证测试,来决定该writeset是否被接收, 如不雅考验掉败,这个writeset就会被摈弃,然后最开端的事务也会被回滚;如不雅考验成功,事务就被提交,writeset也被应用到其他节点上。 这个过程如下图所示:

在Python的SQLAlchemy库中,有一个“with_lockmode(‘update’)”语句,这个代表SQL语句中的“SELECT … FOR UPDATE”,在我介入过的计费项目和社区的一些项目标代码中有大年夜量的该构造,因为写锁不克不及在集群中同步,所以这个语句在Mysql集群中就没有获得它应有的效不雅,也就是在语义上有问题,然则最后Galera会经由过程报deadlock缺点,只让一个commit成功,来包管Mysql集群的ACID性。

  1. server xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx:3306 check 
  2.  
  3. server xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx:3306 check backup 
  4.  
  5. server xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx:3306 check backup  
  • 对OpenStack的所有Mysql操作做读写分别,写操作只在master节点上,读操作在所有节点上做负载均衡。OpenStack没有原生支撑,但 是有一个开源软件可以应用,maxscale。

最终解决办法

起首得有一个retry机制,也就是让操作履行在一个轮回中,一旦捕获到deadlock的error就将操作从新进行,这个在OpenStack的oslo.db中已 经供给了响应的办法叫wrap_db_retry,是一个Python装潢器,应用办法如下:

  1. from oslo_db import api as oslo_db_api 
  2.  
  3. @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True
  4.  
  5. retry_on_request=True
  6.  
  7. def db_operations(): 
  8.  
  9. ...  

然后在这个轮回之中我们应用叫做”Compare And Swap(CAS)”的无锁办法来完成update操作,CAS是最先在CPU中应用的,CAS说白了就是先比较,再修改,在进行UPDATE操作之前,我们先SELEC T出来一些数据,我们叫做期望数据,在UPDATE的时刻要去比对这些期望数据,如不雅期望数据有变更,解释有另一个会话对该行进行了修改, 那么我们就不克不及持续进行修改操作了,只能报错,然后retry;如不雅没变更,我们就可以将修改操作履行下去。该行动表如今SQL语句中就是在 UPDATE的时刻加上WHERE语句,如”UPDATE … WHERE …”。

给出一个计费项目中修改用户等级的DB操作源码:

  1. @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True
  2.                        retry_on_request=

      推荐阅读

      智能手表输在了哪儿?

    【51CTO.com快译】智妙手表类产品的掉败重要在于这个行业犯下一?巨大年夜缺点。它的推广始于面向小我花费者而>>>详细阅读


    本文标题:数据库写操作弃用“SELECT … FOR UPDATE”解决方案

    地址:http://www.17bianji.com/lsqh/37269.html

关键词: 探索发现

乐购科技部分新闻及文章转载自互联网,供读者交流和学习,若有涉及作者版权等问题请及时与我们联系,以便更正、删除或按规定办理。感谢所有提供资讯的网站,欢迎各类媒体与乐购科技进行文章共享合作。

网友点评
自媒体专栏

评论

热度

精彩导读
栏目ID=71的表不存在(操作类型=0)