mysql并发冲突解决办法?
mysql并发冲突五种解决办法:
1. 最常见的还是分表,但是分表有一个弊端 就是有些查询受限制,对于每一个查询条件都需要把分表 依赖列 传进来。
2.写事务的并发度 依赖于索引设计和文件的io的刷盘速度,如果依赖于索引的锁设计没有问题的话,锁的占用就是行级锁,可以大大提高性能。
3. 由于mysql事务是基于 redo和undo日志来实现的,那么如果数据不是强一致性 并且允许丢失的情况下,可以考虑设置redo和undo 日志的刷新级别,交给操作系统来定时刷盘,这样就没有了io的性能瓶颈。
4.可以考虑在7层或者四层接入的时候 将写流量导入到 主mysql节点所在的机房,将锁占用时间卡在局域网访问,减少锁的占用时间
5.如果真的 并发瓶颈 依赖于网络io,那么可以考虑分库的设计,使用多主多从 来解决单台主mysql节点的性能问题
高并发场景下,如何实现数据库主从同步?
常用方案是数据库读写分离技术。不过既然题主提到了高并发场景,我就来告诉你,event sourcing——事件溯源,eventuate架构就提供,和CQRS——应用层写读分离。再结合kafka这类的消息中间件,或是阿里的canal数据库日志同步解决方案,可以搭建一个完美的高并发事务与实时在线响应系统,当然这种读写分离系统的事务是最终一致性的,题主可自行百度我说的各项技术。如果题主和各位看官觉得有价值,就请点个赞吧
数据主从同步的由来
互联网的很多业务,特别是在高并发的场景下,基本都是读远远大于写,如果数据库读和写的压力都同在一台主机上,这显然不太合理。
于是,把一台数据库主机分为单独的一台写主库(主要负责写操作),而把读的数据库压力分配给读的从库,而且读从库可以变为多台,这就是读写分离的典型场景如下:
为了进一步的降低数据库端的压力(高并发的瓶颈),这个时候也会在业务层部署分布式缓存集群(redis、memcached)等,把读的压力转移给应用服务器端,其实与数据主从的设计是遵循同一个原则,降低后端数据库的压力。
问题:
读写分离提高了资源的利用效率的同时也引出了一个问题,就是由于延时(网络传输,操作)而引起的数据库主从不一致的问题,以下会详细谈相关的数据一致性解决方案。
数据同步一致性解决方案
1.半同步复制
办法就是等主从同步完成之后,等主库上的写请求再返回,这就是常说的“半同步复制"。
实现方案
mysql的半同步复制方案,下面我以mysql为例介绍。
MySQL半同步复制
MySQL的Replication默认是一个异步复制的过程,从MySQL5.5开始,MySQL以插件的形式支持半同步复制,我先谈下异步复制,这样可以更好的理解半同步复制。
1)异步复制
MySQL默认的复制是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主如果crash掉了,此时主上已经提交的事务可能并没有传到从库上。
2)半同步复制
对于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟,这个延迟最少是一个TCP/IP往返的时间。所以,半同步复制最好在低延时的网络中使用。
半同步复制原理:
事务在主库写完binlog后需要从库返回一个已接受,才放回给客户端
mysql5.5版本以后,以插件的形式存在,需要单独安装
确保事务提交后binlog至少传输到一个从库
不保证从库应用完成这个事务的binlog
性能有一定的降低
网络异常或从库宕机,卡主库,直到超时或从库恢复
该方案优点:
利用数据库原生功能,比较简单
该方案缺点:
主库的写请求时延会增长,吞吐量会降低
2.数据库中间件
流程:
1)所有的读写都走数据库中间件,通常情况下,写请求路由到主库,读请求路由到从库
2)记录所有路由到写库的key,在主从同步时间窗口内(假设是500ms),如果有读请求访问中间件,此时有可能从库还是旧数据,就把这个key上的读请求路由到主库。
3)在主从同步时间过完后,对应key的读请求继续路由到从库。
相关的中间件有:
1)canal:是阿里巴巴旗下的一款开源项目,纯Java开发,基于数据库增量日志解析,提供增量数据订阅&消费,目前主要支持了MySQL。
2)otter:也是阿里开源的一个分布式数据库同步系统,尤其是在跨机房数据库同步方面,有很强大的功能。它是基于数据库增量日志解析,实时将数据同步到本机房或跨机房的mysql/oracle数据库。
两者的区别在于:
otter目前嵌入式依赖canal,部署为同一个jvm,目前设计为不产生Relay Log。
otter目前允许自定义同步逻辑,解决各类需求。
该方案优点
能保证绝对一致
该方案缺点:
数据库中间件的成本较高
3.缓存记录写key法
写流程:
1)如果key要发生写操作,记录在cache里,并设置“经验主从同步时间”的cache超时时间,例如500ms
2)然后修改主数据库
读流程:
1)先到缓存里查看,对应key有没有相关数据
2)有相关数据,说明缓存命中,这个key刚发生过写操作,此时需要将请求路由到主库读最新的数据。
3)如果缓存没有命中,说明这个key上近期没有发生过写操作,此时将请求路由到从库,继续读写分离。
该方案优点:
相对数据库中间件,成本较低
该方案缺点:
为了保证“一致性”,引入了一个cache组件,并且读写数据库时都多了缓存操作。
支撑日活百万用户的高并发系统,应该如何设计其数据库架构? ?
之前做过一个每天访问量达到800w的系统,简单说下自己的见解!
从整个应用系统来看,想要支持超高并发量,负载均衡,缓存,消息中间件,数据库读写分离,分库分表等必不可少,既然文章只问了数据库系统,那就只谈数据库!
数据库层面,一般无外乎是主从复制,读写分离,分库分表这些东西!
1,从单台数据库性能来看,单个mysql实例最大连接数为16384,就是说在同一时间最多能容纳那么多的访问量,同时受服务器CPU,内存,硬盘等的影响,但是在实际应用中能达到2000就不错了!
需要使用druid等数据库监控中间件,实时的监控数据库连接,sql效率等各种指标,在达到瓶颈之前找到办法,show status;这个指令也可以方便的查看数据库实例的各项指标
单台数据库实例配置最优化是保证整个数据库集群最优化的基本保证!
2,数据库集群:以分库分表为例,分库分表的方式有很多,比如mycat,Sharding-jdbc等。
分库分表的思想很简单,比如单表1亿的数据量,查询效率很低,如果使用8库1024表拆分,每张表中的数据不会超过10万,对数据库来说不存在任何瓶颈,就算总数据量达到100亿,单表的查询也不会慢!
拆分的策略通常以某个全局唯一的业务主键使用某种方式(比如hash取模,按月份等等)进行分库分表的计算!
那么问题来了,全局唯一的字段怎么获取?普通的数据库主键自增,uuid等不再合适,可以使用redis,zookeeper等获取全局唯一的id,具体可参见之前的其他回答!
问题:分库分表之后存在跨库join的问题,通常的解决方式为1,尽量使用分库分表主键能保证在同一库,同一类型的表中进行连接查询,2,增加专门的查询库:将常用的数据字段冗余到查询库中,方便连接查询和常用字段的快速查询;
4,sql优化:最基本的条件查询,count,分组等使用索引字段等避免全局查询,避免null值判断,避免使用not in,避免无效的like语句,避免查询的时候使用函数操作等等!
5,像秒杀系统等这种瞬时高并发,最好借助缓存系统来完成!
总而言之,数据库是整个应用系统当中最核心,也是最容易出问题的地方,做好监控,提前预防才能保证系统访问量的增长!