部署 Nginx+Mongrel+MySQL 多进程部署时的数据库安全问题,求指教

lionzixuanyuan · November 20, 2012 · Last by Magic replied at June 19, 2013 · 3538 hits

最近在尝试 Nginx+Mongrel 的部署方式。 通过 Nginx 的负载均衡以及 Mongrel 集群服务的部署方式,试图提高所开发的系统在高并发时的性能。 但是,现在有一个疑惑:由于所有的 Mongrel 集群服务都作用于同一个数据库,那么,当多个进程服务同时对同一条记录进行编辑操作时,在数据库中,这种并发操作时如何处理的呢? 举个例子: 假如现在有一条记录为:姓名:lionzixuanyuan 性别:男 年龄:24。 然后,现在又两个用户分别通过两个进程同时对此记录进行编辑操作: 用户 1:姓名:lion 性别:男 年龄:24; 用户 2:姓名:lionzixuanyuan 性别:男 年龄:30。 假设这两个用户同时提交了信息,对这条记录进行保存,那么保存的结果是什么呢?如何对这个极端的情况进行测试呢? PS:有没有人知道为什么社区的搜索没办法用啊?难道要翻墙?

同时提交信息,保存信息以最后一个保存为准。如果要严格避免数据保存冲突,有两种方法,需要程序自己做处理,具体见 API http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.htmlhttp://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html

另外,不推荐使用 Nginx + Mongrel 这种组合部署,因为 Mongrel 已经不再更新。建议使用 Nginx + Unicorn, Nginx + thin 或 Nginx + Passenger。

#1 楼 @vincent 先谢过,我去研究一下你给我提供的文档

#1 楼 @vincent 之前针对这个问题加过乐观锁定和事物处理,但是在领导人的要求下又被否决了,表示一个礼拜白干了。 另外,关于部署组合的问题,之前想过运用 Nginx+Passenger,但是 Passenger 不支持 Windows,只好作罢,另外两种没有之前也没有接触过,留着有空去学习下。 最后,根据你提供的答案就是说不会出现“姓名:lion 性别:男 年龄:30”这种状况,那有没有办法可以证明呢? 请前辈指教

#3 楼 @lionzixuanyuan 你用 Windows 部署就比较蛋疼了,Unicorn 和 Passenger 明显被排除了,Thin 还可以考虑考虑,不过强烈建议你换到 Unix 系系统。

如果不加任何锁处理,通常以最后一次保存为准,但是某些并发情况下会出现“姓名:lion 性别:男 年龄:30”这种状况。

请求处理的顺序是

  1. 从数据库加载用户对象到 user
  2. user.update_attributes( params[:user] ) params[:user] 是修改的内容,update_attributes 根据 user 数据和 params[:user] 数据生成 update 语句,如果数据未变化,不会出现在 update sql 的 set 里面。

如果请求同时被两个进程接收处理,他们可能同时进入第 1 步,这时候用户 1 更新的 update sql 只带 set 姓名,用户 2 的更新 update sql 只带 set 年龄,就导致了两个数据部分更新的情况。

#4 楼 @vincent 嗯,确实蛋疼,但是公司现状不是我们决定的。。。 非常感谢你的解释,我现在正在设计一个测试方案,想要通过系统的定时调度模拟这种极端情况,不知道是否可行。

#5 楼 @lionzixuanyuan 不客气,这种涉及并发很难在测试模拟的,但是你可以打开 2 个控制台进程,按上面说的操作顺序模拟数据操作,就可以看到实际结果了。

假设 id 为 1 的 user 初始值是 name: 'lionzixuanyuan', age: 24,根据 代码前的序号执行代码。 控制台 1

1 user = User.find(1)
3 user.update_attributes( name: 'lion', age: 24)
5 user.reload 
7 pp user

控制台 2

2 user = User.find(1)
4 user.update_attributes( name: 'lionzixuanyuan', age: 30)
6 user.reload 
8 pp user

结果是

name: 'lion', age: 30

如果高并发的话,用悲观锁就怕你到时其它的查询等待锁时间过长

看情况可以加入队列处理

#8 楼 @cxh116 嗯,之前只加了乐观锁,没有使用悲观锁,目前系统还在测试阶段。多谢你的提醒

#3 楼 @lionzixuanyuan 不可能出现脏数据情况,关系型数据库 ACID 特性保证,每次修改都是原子性。

You need to Sign in before reply, if you don't have an account, please Sign up first.