当前位置: 首页 > news >正文

从PHP迁移至Golang - 基础篇

1、Why Not PHP

使用PHP构建的WEB程序,随着业务发展到一定体量之后,都不得不面临以下一些问题:

  • 业务功能不断扩张,如何避免某单一业务功能故障影响整体,维持系统健壮性
  • 业务逻辑复杂度不断上升,如何解耦与模块化,降低系统复杂性
  • 网站访问量不断攀升,如何实现高并发,实现系统高可用性
  • 计算密集型业务的出现,如何快速适应需求,提升网站性能
  • ...

对于PHP而言,在业务发展初期,可以快速实现业务原型,满足需求,但是在发展的中后期就显得略有点后劲不足。
因为PHP在高并发、多进程/线程以及密集计算领域并不擅长。这种情况在swoole出现之后得到了很大的缓和。
但是,随着微服务架构的兴起以及容器时代的到来,这种情况又再次加剧。因为PHP大都需要借助Nginx和PHP-FPM或类似软件来进行进程管理,这对于部署的微服务意味着部署PHP项目代码的同时必须同时包括PHP-FPM和Nginx,这除了增加资源成本也降低了效率。

2、Why Golang

那么,为什么是Golang呢?

  • 首先,Golang与PHP很像,都是类C语言,可以很好的进行『知识迁移』
  • 其次,Golang在性能和开发效率上有很好的平衡,语法简单,语言层面上支持并发编程,且基础库健全,部署容易。
  • 最重要的是,Golang在微服务与容器领域有很好的基础,后期系统可完美实现微服务化与容器化。

当然了,即便如此,PHP还是世界上最好的语言。

3、How To

做好了思想上的准备之后,就可以开始确立技术方案了。
任何大型系统的重构都不可能是一蹴而就,顷刻之间发生的,需要一个循序渐进的过程。并且,在此重构过程中,大前提必须保持现有系统的所有业务照常运行,所以需要确立的是一个对系统基本无损的分模块逐步替换的方案。
回归到我们当前的系统架构:每台服务器上均部署相同的PHP项目代码,统一由PHP-FPM解释执行,并通过Nginx进行反向代理。
在梳理了系统各功能模块业务职责之后,我们决定先将数据模块试水:使用Golang进行改造,理由是数据模块功能较为简单,Golang只需计算逻辑然后向前端页面提供数据接口即可。同时借助Nginx的反向代理功能,将数据接口前缀的转发至Golang程序,其他所有请求还是依旧转发至原来的PHP-FPM程序。其抽象模型大致如下:
图片描述

4、About Hot-Update

所谓热更新,是指在系统升级或修复bug过程中对用户来说是无感知的。
使用PHP开发时,开发者无需关心热更新,因为PHP是解释型的编程语言,PHP-FPM会根据最新的请求实时去调用执行具体某个PHP文件;而Golang则不同,它是编译型语言,在运行时会把Golang文件加载到内存,这时,所有对代码的改动想要更新必须要重启服务才能生效。那么如何在重启服务过程中,不影响当前用户请求,便是热更新需要解决的问题。
目前Golang热更新大致有两个思路:Plugin包(Golang1.8+,原理类似C++动态链接库方式)和第三方热更新库(如)Facebook开源的grace库以及endless库等。
关于第三方热更新库逻辑大致为:

  • 发布变更的项目代码文件
  • 发送变更通知给服务进程(信号方式,通常是USR2信号)
  • 服务进程收到通知后,调用 fork/exec 启动最新项目代码(新进程)
  • 子进程调用会从父进程继承 socket 文件描述符来重新监听 socket(此时父子进程同时Accept连接)
  • 原有父进程不再接收新请求,待正在处理中的请求处理完后,进程自动退出(gracefully shutdown)
  • 子进程托管给init进程

总结

以上大致接介绍了从PHP项目迁移到Golang所需的一些思想与技术上的准备,后续篇章将介绍具体技术方案与实现细节。

References

http://mikespook.com/2012/08/...
https://github.com/facebookgo...
https://github.com/fvbock/end...
https://fitstar.github.io/fal...

相关文章:

  • Spark ML流式在线学习模型初步构建分析-Spark商业ML实战
  • Java接口全链路优化:如何降低接口RT时长
  • redis个人源码分析2---dict的实现原理
  • DB主从一致性架构优化4种方法
  • mysql的TABLE_SCHEMA的sql和information_schema表, MySQL管理一些基础SQL语句, Changes in MySQL 5.7.2...
  • kafka集群消息格式之V0版本到V2版本的平滑过渡详解-kafka 商业环境实战
  • docker镜像的分层结构三
  • form表单中某个input传入数据库数据默认为on
  • Oracle 未能加载文件或程序集Oracle.DataAccess
  • Java进阶篇设计模式之十二 ---- 备忘录模式和状态模式
  • cx_Oracle.DatabaseError: DPI-1047: 64-bit Oracle Client library cannot be loaded: 解决方案
  • 阿里AI设计师一秒出图,小撒连连惊呼,真相是……
  • 前端进阶课程之模块化(一)CommonJS规范
  • PAT(Basic Level) 乙级练习题 ------ 1031 查验身份证 java
  • bzoj 5210 最大连通子块和——动态DP
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • “大数据应用场景”之隔壁老王(连载四)
  • 【笔记】你不知道的JS读书笔记——Promise
  • CentOS 7 修改主机名
  • MySQL用户中的%到底包不包括localhost?
  • Python语法速览与机器学习开发环境搭建
  • Spring Boot MyBatis配置多种数据库
  • Swoft 源码剖析 - 代码自动更新机制
  • 百度小程序遇到的问题
  • 从地狱到天堂,Node 回调向 async/await 转变
  • 从零到一:用Phaser.js写意地开发小游戏(Chapter 3 - 加载游戏资源)
  • 工作踩坑系列——https访问遇到“已阻止载入混合活动内容”
  • 计算机常识 - 收藏集 - 掘金
  • 近期前端发展计划
  • 如何优雅地使用 Sublime Text
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 试着探索高并发下的系统架构面貌
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • postgresql行列转换函数
  • 仓管云——企业云erp功能有哪些?
  • ​Linux Ubuntu环境下使用docker构建spark运行环境(超级详细)
  • #ifdef 的技巧用法
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (附源码)spring boot网络空间安全实验教学示范中心网站 毕业设计 111454
  • (一)appium-desktop定位元素原理
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Core 中的路径问题
  • .NET delegate 委托 、 Event 事件,接口回调
  • .net mvc 获取url中controller和action
  • .NET 的静态构造函数是否线程安全?答案是肯定的!
  • .NET 中 GetProcess 相关方法的性能
  • .NET分布式缓存Memcached从入门到实战
  • /ThinkPHP/Library/Think/Storage/Driver/File.class.php  LINE: 48
  • @vue/cli 3.x+引入jQuery
  • [ IO.File ] FileSystemWatcher
  • [ SNOI 2013 ] Quare
  • []使用 Tortoise SVN 创建 Externals 外部引用目录
  • [AR]Vumark(下一代条形码)
  • [asp.net core]project.json(2)