node.js单线程,是不是就不用消息队列了啊
发布于 6 年前 作者 iori2882 6505 次浏览 来自 问答

刚刚入门node.js,还在被回调函数弄得死去活来…现在我疑惑一个问题,既然node是单线程,那么是不是永远不会出现2个用户在同一时间读取同一条数据库记录,比如预定系统,A房间是空闲状态,在高并发的状态下,用户甲和用户乙同一时间查询到了这个空闲方法,同时预定成功,这种情况在node.js里是不是就不会发生? 这边现在想做一个酒店预定的系统,初步我想的是,系统初始化的时候一次性的把所有房间的状态都读到内存中,好像线程池那样维护一个状态池,当用户请求的时候,如果有空闲房间就分配给用户,然后更新数据库,如果数据库更新成功,通知用户预定成功,在这个条件下还得做消息队列才能保证房间状态不会乱掉,如果乱掉那么整个系统就崩溃了啊 node.js有我上面所说的问题么???如果没有,我就不用做消息队列了啊?

14 回复

如果你的系统是一台服务器,一个进程,自然不会有并发冲突的问题。消息队列在这种情况下确实没有必要。但如果你是多个进程,甚至多台机器分布式系统呢?消息队列的威力就发挥出来了。

你这理解的有问题吧

注:楼上回答也有问题,就算是单机,单线程也会出现。而且多机要实现负载消费,光消息队列也是无法保证一致性。 举个例子,你要在数据表查是否有同名的,没同名则插入。 因为node无法按整个请求的sql块作为执行单元,而是按sql条作为了执行单元,那么按上面的来说两个select会先后到达,而第一条insert并没有插入,导致第二个select查询为空,还会继续插入用户。(如果表小可能不会出现,表大必现) 而消息队列则相当于是已将请求的整个sql块作为执行单元,即完成了整个请求的select和insert,才会执行下一个请求的select和insert。

来自酷炫的 CNodeMD

我觉得3楼说的有道理,本来以为单线程再也不用消息队列了,现在node.js有没有好的消息队列模块啊?

@iori2882 常用就RabbitMQ这种了

@scarletmu RabbitMQ是不是解决效率的事情,我现在的问题是并发大,导致数据污染的问题,好烦啊

回调只能保证某个请求按照顺序执行,不能保证多个请求访问一个资源的先后顺序,多个请求访问一个资源是要加锁的,用事务加锁就行。

并发更新DB和node没半毛钱关系,node单线程只是保证它自己的线程内没有资源竞争,管不到外面。数据库本身就支持并发,你要是怕资源竞争就加锁,事务隔离级别你需要了解一下。

另外说下MQ的使用场景,MQ比较适合那些异步的情况,比如用户注册后需要给用户发送欢迎邮件,或者执行一个耗时任务,需要产生报告,这类事情就可以丢到MQ去,消费端去取就好了。

具体到你的场景,用户预定房间,如果并发量很大,势必需要削峰,具体来说就是利用MQ缓冲请求,后端消费者慢慢去消费这些请求(pull模式),这样做的好处是在前端流量激增的情况下,不会引起后端服务雪崩。

@coordcn 其实这个也可以实现,要打自己脸了,刚刚实现了一个包,让代码块根据通道按顺序执行的包(即实现同种类型的请求,按顺序执行执行) https://www.npmjs.com/package/block-run 但适用场景有限,大并发不行,否则容易过载 适合小并发,比如用户注册时不小心快速点了两下,用这个包可以实现把请求放到相同通道里,按顺序执行,使数据库不会有两条重复数据(如果是多机,请适用回话保持,确保同一个用户只访问相同的机器,可保证此场景的数据一直性,其他场景不能保证) 不过还未经过严格测试,等周末有时间,我测试一下,然后把结果公布出来

@zy445566 的确被打脸了,以后不能把话说死,单机,单进程,低负载,低响应时间的情况下的确可以,但估计很难用于实际工程,单机队列高并发下很容易被堵死,非常容易被针对。

多进程可以加个跨进程资源锁,让抢到锁的请求访问数据库,openresty和fibjs都有提供资源锁,不清楚nodejs怎么处理跨进程锁的。

多机的情况下要么用消息队列。

如果并发压力不是太大,直接用数据库的锁也行。

谢谢大家~受益匪浅

@coordcn 效果还不错,有点超出预期,库比之前改进了一些 https://cnodejs.org/topic/5ad2c18dba60fcc66b7b80fd

@zy445566 大神有心了 十分感谢 十分感谢

感觉是数据库的事而主要不在node =_=

回到顶部