嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

周梦康 发表于 2014-12-21 2413 次浏览 标签 : Mysqldba

免费领取阿里云优惠券 我的直播 - 《PHP 进阶之路》

业务场景还是关于推送的,推送是针对我们自己的系统用户,所以需要一张表user_bind_push来绑定用户id和SDK里的唯一标识token。在用户登录的时候会访问一个push.bind的api接口,在该接口中会先删除和该手机设备里的token绑定的数据,然后绑定目前登录的用户id和推送SDK里面的token

$sql = "DELETE FROM `user_bind_push` WHERE `push_id` = '{$token}'";
M()->execute($sql);

$sql = "INSERT INTO `user_bind_push` SET `uid`={$uid}, `push_type`={$push_type}, `push_id`={$push_id}, `device`='{$device}', `app_version`={$appVersion}, `build`='{$build}',`channel`='{$channel}'";
M()->execute($sql);

之前三个月一直运行的好好的,但是前几天由于做了一次广播推送,这样一时间同时登录的用户就多了。导致访问该接口却无法获取返回值。

打开数据库通过show processlist发现对该表的操作就出现堵塞了,已经有900多条。

是什么导致了这个问题呢?原来是push_id没有加入到索引(低级错误)。

这个时候为了防止出现数据库出现异常情况,就立即将该api里的两次SQL的执行给注释掉了,而是写入文件,等之前的请求都执行完了(也把索引给加上了),再把把代码恢复,并且将写入文件的SQL执行,既保证了服务的正常,也不会丢失数据。

$sql = "DELETE FROM `user_bind_push` WHERE `push_id` = '{$token}'";
//M()->execute($sql);
file_put_contents('todo.sql',$sql.";\n",FILE_APPEND);

$sql = "INSERT INTO `user_bind_push` SET `uid`={$uid}, `push_type`={$push_type}, `push_id`={$push_id}, `device`='{$device}', `app_version`={$appVersion}, `build`='{$build}',`channel`='{$channel}'";
//M()->execute($sql);
file_put_contents('todo.sql',$sql.";\n",FILE_APPEND);

其实我们应该在框架就应该把这种把SQL堵塞写入文件的紧急任务封装起来,发现问题了,方便立即切换。

我们的库一直还是一主多从,写入的压力都放在了主库上,但是发现在该表发生堵塞的时候,其他的有写操作的api对客户端提供的服务正常,比如留言等,在show processlist看到有堵塞只是user_bind_push一张表的,并没有影响到其他表。

嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

评论列表