node.js高并发高可用架构设计实战
发布于 5 年前 作者 huangyi1214 6924 次浏览 来自 分享

项目目的: 在平时开发中,我们也许会经常碰到这些问题: 1,新人加入时会需要花大量的时间去熟悉代码,因没有完全掌握代码,随便改动了一个功能模块就会影响其他功能的使用 2,代码分层不清晰,耦合在一起,改动非常被动 3,代码测试不到位,导致上线后因漏洞造成损失,不停的修改=>测试=>发布=>线上出现问题打回=>修改=>测试=>发布,形成了一个死循环, 4,版本更新需要发邮件,停服更新,更新繁琐, 5,因无法模拟大并发的用户测试,很多隐藏的问题得不到及时发现

基于以上几点,给大家分享一个结合自己工作中遇见的种种问题的解决方案,秒杀系统解决方案,有三套代码,分别是: 1,后台程序代码:https://github.com/huangyi1214/egg-shop.git 2,压测框架:https://gitee.com/huangyi1214/client.git 3,后台管理系统:https://github.com/huangyi1214/eggShop-admin.git

使用到的技术栈:node.js+mysql+redis+redis分布式事物锁+rpc+消息队列

秒杀在现代互联网开发当中非常常见,我的这个例子就是简单的几个模块用于演示,当然后期我会继续完善, 1,登录功能 2,创建一个秒杀订单 3,创建完成后,立即通知所有的在线用户进行抢购 4,有一个后台管理系统,可以生成订单,查询该订单被抢购的详情

项目架构图 1.jpg

一,框架选型,我用express框架用了好几年了,但是给我最深的感觉就是框架太基础了,还记得我要开发一个socket.io的服务,我需要手动去创建,维护,代码规范用ESlint,文件夹每个项目定义都是五花八门, 后来我选择了egg,给我的体验实在是太棒了,地址:https://eggjs.org/zh-cn/

1,egg奉行约束优先,没个文件夹的功能定义都非常清晰, 2,内置多进程管理,我们可以不用pm2这样的框架进行线上部署了,关于node,js的多进程使用,我后面还会有一篇文章进行讲解,我自己写了一套压力测试框架,在github上开源 3,高度可扩展的插件机制,可插拔,社区比较大,有很多现成开源的插件,一个新的项目只需加载一下自己需要的插件就可以开始写业务逻辑了

二,egg优势 1,整个程序对外只提供一个接口(http,socket.io共用),也许到这里大家可能会问这怎么可能,http和socket.io绑定不是一个端口号啊,这就是他的优势,其实底层的实现逻辑是利用了node.js的Cluster模块来启动多线程,关于底层实现,推荐大家参考这篇文章,地址:https://cnodejs.org/topic/56e84480833b7c8a0492e20c,另外知乎上一篇文章详细说明了egg多进程实现原理:https://zhuanlan.zhihu.com/p/62892856

2,原生支持alinode性能监控,阿里云的一个服务套件,性能监控可以查询到当前CPU,内存使用情况,异常日志服务,http慢查询,可精确到某个函数具体的错误,再也不用担心去怎么还原线上场景了,就可以针对性的定位问题

三:功能模块分层 1,controll 提供实现http接口访问的方法, 2,io 实现socket.io实现, 3,model,数据库模型文件夹 4,proxy,RPC代理模块文件,这个文件是自动生成的, 5,rpc/service 具体实现的业务逻辑

四,系统各模块详细讲解 1,登录模块 登录流程是:使用phone在redis查询是否存在,如果不存在–>在mysql数据库中创建user记录及account记录–>更新redis缓存,创建token 在这里遇见一个问题,大批量查询时会很慢,需要mysql设置读写分离,一主多从模式,提升mysql性能,

2,订单生成,需要同时在redis和mysql中生成新的记录, 3,抢购,先查redis,如果数量足够,使用redlock分布式事务锁,然后再更新数据库,如果不用redlock,直接使用mysql事务,会出现多个事务同时锁定,造成死锁,在订单已经被全部抢购完以后,其他的连接请求全部都是读取redis缓存的记录,不会对数据库造成压力

五,微服务的好处及实现 微服务可以将我们庞大的service服务进行切割,分成多个功能完全独立的子系统,易于维护,再也不用担心,只修改一个功能代码就需要把整个系统更新一遍,而且更新的时候,别人有可能在开发新的业务功能,如果更新上去,很容易出错,另外一个好处就可以进行版本管理,当需要更新时,先把服务部署好,创建一个新的版本,然后RPC调用时自动切换到新的版本,无需把用户提出下线 实现流程是,先实现功能service,然后向zookeeper进行注册服务发现,提供客户端调用,egg的RPC实现流程可参考https://www.yuque.com/egg/nodejs/vlmums

五,压测工具的使用,我的压力测试工具已经使用node.js的cluster模块实现高并发压测 使用方式:node index.js “http://ip:port" -c5000 -n5 -u13800000000 -c 单个线程跑的用户数量 -n 需要跑的线程数量

5 回复

欢迎加我微信大家一起交流 2.jpeg

加入购物车了,有时间看看

3,抢购,先查redis,如果数量足够,使用redlock分布式事务锁,然后再更新数据库,如果不用redlock,直接使用mysql事务,会出现多个事务同时锁定,造成死锁,在订单已经被全部抢购完以后,其他的连接请求全部都是读取redis缓存的记录,不会对数据库造成压力 -----使用 redis -> mq -> db 是不是更好

回到顶部