规模化Rails开发实战:用Ruby编写业务逻辑,Go/C/Rust构建高性能组件
Ruby on Rails擅长业务逻辑、开发者体验和快速迭代。但当性能瓶颈出现时,常见的建议是"用Go重写"、“拆分为微服务"或"解构单体应用”。但有一个更好的方法:通过优化工具链来扩展Rails应用,而不是改变核心架构。
TL;DR:保持你的蛋糕配方(业务逻辑)使用Ruby,但升级厨房工具为Go、C、Rust等高性能语言来实现快速混合和烘焙。永远不要为了速度而牺牲风味!
精准提取的艺术
Rails应用就像一个拥有活配方的面包店,你的业务逻辑通过反馈和创新不断优化。然而当订单涌入时,厨房开始不堪重负。解决方案不是用"更快"的语言重写配方,而是升级你的搅拌机和烤箱:识别重复的、CPU密集型的任务,并将它们委托给用Go、C、Rust等构建的专业工具。
实例一:imgproxy - 当厨房需要更快的图像变体处理
想象你的面包店突然被图片订单淹没:图库显示缓慢,图片上传超时,后台任务堆积。手动搅拌机(如Active Storage的.variant调用)无法跟上,消耗大量资源并阻塞其他厨房工作。
这时,你发现了imgproxy - 用Go构建的最快图像变体处理工具。但如何在不重新培训面包师或重写配方的情况下集成它?
架构洞察:在这种情况下,Rails已经有一个将工作委托给"更好搅拌机"的系统。当你调用image.variant(resize_to_limit: [300, 300])时,Rails创建一个变体对象,生成指向ActiveStorage::Representations::*Controller的签名URL。该控制器充当调度器:检查变体是否存在,根据需要处理它(使用配置的处理器),并提供或重定向到结果。
Rails使用libvips作为默认变体处理器,也可以使用ImageMagick。但整个流程(URL生成、处理委托和结果服务)都设计为适配器模式。我们只需要将这些转换指令路由到imgproxy,而不是进程内处理器。
关键点:配方保持纯净(检查权限、验证尺寸、做出业务决策),搅拌机从不查看用户上下文或业务规则 - 它只是遵循转换指令。
实际方案:我们已经构建了这个厨房升级!imgproxy-rails gem可以轻松替换你的搅拌机;安装它,通过配置连接,每个配方都会自动使用新设备。
|
|
你的面包师永远不会知道区别:相同的成分,相同的技术,只是结果更快。相同的视图代码现在将繁重的图像处理从Ruby委托给Go。
三个有效的增强原则
规则一:原生扩展Rails
优秀的性能助手应该插入Rails现有的抽象,而不是与之对抗。Rails提供了数十个扩展点,Active Record数据库适配器自然是最常用的,但还有更多。Active Storage、Cache Store、Session Store、Action Cable、Action Mailer、Active Job都是很好的例子。
规则二:工具不需要了解配方
性能助手应该是纯执行引擎,完全不了解你的业务配方。当它们开始对用户、权限、UX或领域逻辑做出决策时,你就从性能助手跨入了微服务领域。我们的高性能助手遵循指令;它们从不编写菜单。
规则三:规划维护
用外语构建和维护性能助手需要你可能不具备的团队专业知识。因此,尽可能依赖经过实战检验的开源解决方案来处理操作复杂性。自定义解决方案应该是你的最后手段,而不是第一本能。
TL;DR:最好的性能升级对你的团队来说是隐形的,对Rails来说是原生的。它们扩展机械工作而不触及使产品独特的创意过程。
实例二:Playbook的云端处理
自2021年以来,Evil Martians与Playbook合作,为全球70万+用户构建新一代创意云平台。在处理Playbook.com的项目时,我们没有在Rails内部处理文件(占用Web工作进程/内存),而是将计算密集型任务委托给Google Cloud服务:元数据解析、生成缩略图、AI识别,可靠性和可扩展性由GCP基础设施处理。
处理流程:
- 文件上传到Google Cloud Storage后,无服务器函数启动异步处理管道
- 云函数启动Cloud Tasks作业,包含重试机制
- 每个步骤独立处理:图像识别、调整大小、NSFW检查等
- 结果写入Cloud Firestore
- Rails通过计划的Sidekiq工作进程获取处理后的数据
模式:保持Rails用于面向用户的业务逻辑服务。所有繁重的工作都在进程外进行,由Google的无服务器骨干提供支持。
结果:可扩展、快速、有弹性的文件管道,不会拖累你的Ruby Web工作进程。
厨房升级示例
以下是一些遵循此模式的厨房升级示例:
Web服务器:Puma实现Rack::Handler,Falcon是基于Fiber的异步服务器,支持HTTP/2
存储适配器:ActiveStorage提供一系列适配器,包括ActiveStorage::Service,允许我们扩展经典的S3、GCP和Azure,以及Hetzner、Cloudflare R2、DigitalOcean Spaces等替代方案
文件处理:ActiveStorage::Variant可用于按需文件转换工具,如前述的imgproxy。ActiveStorage::Analyzer用于元数据提取(Poppler)。ActiveStorage::Previewer用于生成自定义预览(MuPDF)
后台作业:ActiveJob::QueueAdapters::*Adapter允许我们与替代作业队列集成,包括Sidekiq、GoodJob、Karafka、Temporal、Faktory等
邮件传递:ActionMailer::Base.delivery_method允许我们扩展经典的SMTP、sendmail、文件,以及Postmark、SendGrid、Amazon SES、Mailgun等替代方案
WebSocket适配器:我们正在领导Action Cable服务器适配器化的工作,以支持更多平台和技术
Rails面包店的优势
经过精心设计的现代Rails面包店可以为大量人群提供服务而不失其灵魂。Ruby引擎通过YJIT改进变得更快,而异步功能和Ruby Fiber Scheduler保持烤箱并行运行而不会使员工精疲力尽。性能优先的厨房助手解决瓶颈,智能缓存防止浪费,你的配方在Ruby中继续发展 - 敏捷、活跃、响应客户反馈。
配方驱动创新,同时,专业工具(用C、Go、Rust等编写)扩展机械工作。它们共同创造了快速、可维护且无限创意的面包店!
通过升级设备来扩展你的Rails面包店,永远不要通过重写配方。保持业务逻辑在Ruby中新鲜,用工业级工具升级你的厨房来完成繁重的工作。将它们结合起来,祝你好胃口!