PHP+MySQL 千万级数据处理案例(一)(分表)

废话少说 直接进入场景
一个金融公司有500w投资用户,每天充值投资50w笔,那么该公司每年将近有1亿条充值记录,那么我们改如何处理这个充值订单表的数据呢?难不成都放一张表里面,那万一哪天我让你去统计满足某个需求的记录,1亿条数据里面检索你会累死mysql的!今天我们就来讲述一下如何去处理这种情况。

mysql分布式之分表思路
分表不是随随便便就分表,必须要结合项目的实际情况,比如我们的项目的瓶颈在哪里,区区几千几万几十万或者几百万的数据用分表那就是高射炮打蚊子了,不要盲目的分表!必须要达到一定的数量级,并且影响了我们的用户的访问速度,性能下降的情况下才能考虑去做分表处理!
我们来画个简单的不能再简单的图吧,我喜欢画图

分表的思路就是如此简单,借助中间件可以根据不同省份的订单插入到不同省份对应的表当中去,当然实际当中还得要结合自身的业务来寻找制作这个中间件,不要照搬人家的逻辑思路!
就比如12306当年总是奔溃一样,全国这么多条铁路线路,在早上八点同时放出抢票,几亿人去抢,再牛逼的技术也很难抵挡,当然阿里很牛逼哈,当时就很多人为他们出谋划策,提供各种方案,说什么人家淘宝天猫京东都这么搞的,他妈的又不了解人家12306的实际业务很多人瞎逼逼,后来12306不也是采用分发的这种形式,错峰发布各个铁路班线的抢票,缓解了大流量带来的巨大冲击,所以一定要结合自身实际的业务去做各种方案,就跟这里的中间件一样!不废话了!

mysql分布式之分表实战(插入总表分然后取模分发到分表)

//伪代码
//假设用户数据入库 定为每天50w的数据量入库
//我们创建一张用户主表+两张用户分表  用户分表user0 用户分表user1
//首先所有用户数据入用户主表
$sql = insert into users(a,b,c) values($a,$b,$c);
$res = $model->query($sql);
if($res){
    //获取user主表插入的最后一条sql的id
    $insert_id = $model->getLastInsId();
    //对刚才入库成功的记录的id取模 如果你是两种用户分表那么就%2如果是200张那么就%200
    $d = $insert_id%2;
    //取模之后 获取到最后的模 任何数对2取模那么不是0就是1 任何数对200取模那么模就是0到200之间
    //插入到不同的用户分表当中去
    $_sql = insert into user{$d} (a,b,c) values($a,$b,$c);
    $ru = $model->query($_sql);
}

其实我们是利用了取模的形式做了一个中间件的功能,根据模的数值去往不同的user0还有user1当中插入数据,达到了分发的效果
整个过程user主表一定是先插入数据的,然后根据模再去往不同的分表里面插数据;
需要强调的是user分表里面的user_id主键一定不是自增的,一定是根据user主表里面的id来插入的,必须保证和主表里面的主键id保持一致!
需要强调的是user主表和user0 user1分表一定是字段属性相同的直接复制即可,只是把数据分发到不同的表里面去了,这也叫水平分表!

在做mysql的水平分表的时候要记住,潜规则,默认的新增的时候我们插入到user主表然后根据取模插入到不同的分表里面去,但是删除,修改,查看,都和主表没关系了,主表只有在新增的时候往里面写入数据根据id取模再分发到不同的分表里面去!当然主表也可以做一些其他方面的统计。

mysql分布式之分表实战(修改查看删除分表数据)
上边我们讲过,修改删除查询的时候直接操作的是分表,不再去动主表

//伪代码
$id = $_POST['id'];
//对主键id取模从而来判断操作哪张分表
$d = $id%2;
$sql = update user{$d} set username='{$username}',age='{$age}' where id = $id;
$model->query($sql);

修改删除也是根据主键id对其取模确定下来针对哪张分表进行修改或者删除

但是我们删除或者修改了那么主表里面的数据也就和分表里面的不一致了啊,如何保证主表和从表数据一致呢?

很多人会想在操作完分表之后立马去操作主表做修改操作不得了,也行啊!但是不感觉浪费吗?如果你学会了协程那么可以起一个协程去操作主表即可,或者起一个异步task任务去操作主表也可以,都是异步执行不影响程序的执行,这是非常好的做法,前提是你得懂什么是协程以及swoole里面的task异步任务,之前博客里面有讲,可以去翻翻我的博客。
另外还有一种老套的方式就是利用队列的形式,不,不,不,不,不叫队列,redis里面的list,充其量叫列表,redis5才新增了一种新的类型stream类型那才是真正的队列,是相当于乞丐版的kafka,利用redis里面的list类型,将修改分表的sql语句改成修改主表的sql,条件一直 id一直 只是操作的表为主表即可,然后塞到list列表里面去 lpush 然后弄个定时任务rpop去更新主表即可!这种方法很笨哦,但是也管用!

刚开始就说了一定要结合实际的业务需求,我们上边讲到的是按照主键id进行的数据的分发到不同的分表当中,所以不管是查询修改还是删除都要结合主键id去确定要操作的分表才行,有一定的局限性,但是我们的实际业务就是这么设计的,所以还是那句唠唠叨叨的话,一定要结合自己的实际业务需求;

分表并不是最优的解决方案,并且在实际的应用当中使用不不是很广泛,存在就有道理,主要还是看你的业务需求啦哦!

本作品采用《CC 协议》,转载必须注明作者和本文链接
胡军
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!