作者:哇哒嘻哇
https://www.zhihu.com/question/278798145/answer/3416549119
最近几年里,经常看到某些曾重度使用 Python 的大公司迁移成其它语言技术栈,但是,那些小公司/小团队的情况如何呢?
一直很想了解那些仍在坚持使用 Python,且支撑业务量有一定规模的公司是如何使用 Python 技术栈做开发的、会遇到哪些困难/教训、有什么样的优秀经验?
偶然在某乎上看到“为什么软件公司很少用python开发web?”问题下的回答,这里分享给大家。
作者:哇哒嘻哇
(https://www.zhihu.com/question/278798145/answer/3416549119)
回复:
我用 Python 有 10 多年了,现在维护最久的一个项目每年有几个亿的交易额,是个电商平台,并发数不算大,平时有几十的并发,过节会 100 出头这样,极限的时候我看也没到 200 过,数据库上最多的订单表量总数在 5000 万左右,每天增加几万。项目有七八年了,还是用的 Python 2.7 + Django 1.8,没打算升级了。
目前配备的 1 台 4 核 8G、3 台 8 核 16G 阿里云,数据库和 Redis 也是用的阿里云,一年的费用大概 5 万不到,CDN 用的七牛,每年大概也得几万。有包括我在内三个程序员在维护,基本每周都有新功能在增加,经过几年的调整有效代码估计 70% 不到了,部分代码因为业务等原因没在用了。
2021 年开发的另一套系统用的 Python 3.8 + Django 3,平时没啥量,节日会飙上去,目前为止的最高记录是一分钟 350 单,一天 15 万单,那天差不多交易额 1500 万。平时配置的两台 8 核 16G,节日会扩容单 6 台,数据库等也会做临时升级。有包括我在内四个程序员在维护。
另外小的项目有几个,没怎么做起来,也没多少量,差不多是两个人负责一个项目,一个人同时负责两个项目这样交叉着进行的。
目前整个公司后端的技术栈都是 Python + Django + Gunicorn 这样(有个小项目用的 tornado),公司基于 Django 做了一些基础框架的积累,整个公司人也不多,大概十四五个程序员基本都对这套框架熟悉。新人来了也先一般是通过加强 Python 基础 -> 学习 Django -> 学习公司框架 -> 进入项目开发这样的一个流程。
公司对命名、风格等方面要求多些,CR 的时候也关注的多些,熟悉之后大家基本都很默契了,因此 Python 动态语言的弊端没怎么体现出来。
早期没经验也出现过并发稍微上来点就崩的情况,后面对数据库进行了升级(早期是自建的)又做了些 Redis 的缓存,现在发生的情况就少了很多了。
Django 构造的一些查询语言过于复杂或者没考虑优化,或导致出现一些慢查询,现在解决的办法是定期的关注慢日志,寻找出现的代码去做优化,数据库本身也需要做根据业务进行升级。这点其实换任何语言都一样。
大部分编程语言我都有接触过,但唯独觉得 Python 能够让我像母语一样能够很方便的表达我的意思给计算机。
对于 Python,从我自身的感觉来讲是熟悉之后程序员就只需要理解业务把需求转换成代码,不需要在一些技术上花费过多的时间。Python 的库也比较多,基本上遇到的大部分问题都有现成的东西可以使用。Django 的 ORM 也很赞,基本上让程序员可以比较方便的操作到数据库,不需要去管表结构变更、复杂查询等。
要说缺点也有,比如 Python 比较累赘,尤其随着项目变大变复杂之后,启动加载需要的时间越来越长,跑起来之后占用的内存也越来越大。
Django 的 ORM 带来便利性的同时也带来了一些低效的代码,比如经常看到的就是有些人构造了比较复杂的查询,导致 join 的表太多了查询时间太长,或者很多时候不管要不要的的字段都一次性查出来了,以及 for 循环里面大量的数据查询等。
但我觉得这些缺点不算致命,因为相比人工开支和开发效率,增加云服务器的成本是极低的,况且对于性能而言大部分的项目都到不了需要去优化的阶段就黄了。有些规范或者使用方式可以通过培训来进行提升,大部分人写的代码质量都会逐步上来。
除了 Web 本身,我们有些硬件设备(大部分是带 Linux 的单板机,比如树莓派、7688 等)上也会用 Python,好处就是可以在电脑上开发然后直接放到设备上运行,也不需要专门招嵌入式工程师,基本上对硬件调用部分封装之后就可以让公司任何一个后端去开发了。
在一些图片处理识别、爬虫、自动化测试、CICD 等方面我们也在用 Python。
对于小团队来讲,Python 的低门槛高效率比起所谓的性能损失类型难以捉摸有价值,当然,前提是需要建立规范、强调质量以及持续性的关注和优化。
想不到这个回答有这么多人关注,我就再补充几点吧。
上面提到的每分钟 350 单的那套系统,主要做的事情是把几个外卖平台的订单聚合接入到系统,然后让商家使用也是聚合接入的配送平台呼叫骑手配送出去,整个过程涉及外卖订单的同步和配送单的同步以及一些管理功能。
外卖平台的订单通知(新订单、订单状态变动等)会通过请求 HTTP 接口通知我们的系统,早期我们做的是同步的方式,即收到请求之后去调用外卖平台的订单查询接口(及另外几个配套的接口)来获取订单详情数据之后创建订单存到数据,然后再响应,因为大量的网络请求需要不少时间,并发量稍微上来一点就扛不住了,试过多开几台机器和多开几个进程,但作用都不太大。
记得早期每分钟能处理 30 单基本是极限了,再多了就出现明显的响应慢了,而外卖平台的通知又要求我们在规定的时间内响应,因此同步处理的这个套路没能坚持多久就遇到极大的瓶颈了,尝试过做多线程任务队列等但效果不行也有任务丢失的风险。
后面我们用了 Celery,收到通知之后把消息放到 Celery 队列就返回,让 Celery 的工作者进程来慢慢处理,避免高峰期扛不住。因为把消息放到 Celery 队列的极快的操作,系统也就能即时的响应外卖平台的通知消息了。
根据消息积压情况,我们会适当的调整 Celery 工作者进程数量,并且可以根据消息的优先级分配不同的队列,这样能保证新订单的通知消息能够及时的处理,让商家尽早知道有新订单需要处理。
最早 Celery 的消息分发我们用的 Redis,后面为了更方便监控换成了 RabbitMQ。也可能是经过了几年的迭代,目前应对节日我们心里相对有点底,该增加的云资源就临时增加一下,Celery 的工作者进程也做成了自动扩容,原则上来讲不遇到十分极端的情况的话我们还是有信心能够应扛得住的。
除了上面提到的这些,大概七八年前我们用 Python 2 + Django 1.8 给政府做过一个让企业填报数据系统,每年会放开一周让企业来填,大概有四五千家企业来填,每个企业填七八个表,并发数当时没注意,保守估计也会有几十。
一开始用的 Django 自带的 runserver 模式跑的(其实也是没经验),很容易就出现卡顿的情况,后面通过 Gunicorn 跑了几个进程之后就没出现在语言层面卡的问题来了,慢的时候大概率也是数据库负载占用太高了或者 mongodb 做数据汇总。
服务器配置不高只是 2C8G 的,跑 Python Web、MySQL 和 MongoDB,还有其他的一堆应用进程。这个系统跑了三年,第四年因为政府层面的关系变动由另外一家公司重新做来开发了,功能没我们做的多而且难用,比我们的还卡,不知道他们用的什么语言。
这个项目上,Python + MonogoDB 的方式给予我们极大的灵活性,因为每年填报的数据不一样,统计指标也不一样,整个系统支持填报表单的自定义、数据校验、数据导入导出、自定义统计等,换其他语言我感觉是很难做出这样的效果,或者说相同的效果需要付出的代价会更高。
当然这套系统没多少维护方面的事情,基本上是一次开发成型,后面保证能访问就行,当时是我带着一个初级程序员开发的,我负责核心的架构和大部分代码的实现,他做简单点的逻辑、UI、表定义等,可能他也不一定容易理解我写的那堆代码。这类复杂系统的代码可维护性我觉得很大程度取决于规范、文档和培训,而不是语言层面的类型约束。
另外还做过一套给旅行社内部用的办公系统,主要是针对东南亚的旅行社,支持多语言多币种,涵盖了几乎旅行社日常的所有业务,包括计划、成团、拼团、酒店车船、购物、导游、客人、报账、收益、财务、报表、图表等。
也是 Python 2 + Django 1.8 做的,我们给每家旅行社独立部署一个 Web 进程 + 一个数据库(数据库名称是独立的,但一台机器上跑一个 mysql)。每个 Web 进程跑起来之后大概 170MB 的内存占用,我们用的 2C8G 的机器,每台机器可以给 40 家左右的客户提供服务,一般客户每天的用户使用数据也就是 10 来个,大点的旅行社会有个二三十个员工同时操作,大部分是查数据录数据,每家的并发估计不会超过 10。
每月初各家都在做账导数据的时候偶尔会反馈卡顿的问题,据我观察大部分是数据库层面的性能问题,我们的解决方案是客户告诉客户过一会儿再导(或者要导的数据多的话就让他们在晚上导),只要几家之间稍微错开导数据了也就没问题。
为了省成本,数据库我们也是在云服务器上自建的,几乎是把云服务器榨到极限了,白天服务器基本都是跑在 80% 以上的 CPU 占用以及 90% 以上的内存占用,导数据的时候 CPU 会跑满。
2020 年前我们手上有 100 多家客户,疫情三年基本都没在做旅游了,这几年可能是那几台服务器最清闲的时候了,去年今年恢复了一些客户,但和之前完全没法比,因为收入锐减,客户的付费意愿也降低了不少。
我是 2012 年前后接触的 Python,在这之前用 Java 和 C# 的多,Java 用来做 Android 和 Web 的开发,C# 是做 Windows 桌面程序和 Windows Phone 的开发。
之前用的 Java SSH 框架 xml 配置我很头大,感觉基本都是在写废话,不知道现在的 Spring 会不会方便一些,除了框架的麻烦外,Java 语言本身我感觉也是相对繁琐些。
C# 的感觉比 Java 好,但跨平台方面又拉胯一些,所以现在除了做桌面程序会选 C#,其他情况也不会选了,况且现在大部分情况下写桌面程序也用网页了。
而 Python 的感觉就是足够简单,可以让人专注于业务,所以公司在选择主要的语言的时候就定了 Python 了(虽然那时候我其实对 Python 的熟悉程度还不如 Java 和 C#),整个团队建设也往 Python 方向,但是也完全想表达随着 AI 的发展,Python 也会跟着火起来。
前些年招 Python 的人相对困难些,基本都是其他语言的来团队里面了才逐渐的适应和熟悉的,这几年有 Python 基础的人稍晚多点了(感谢公众号广告?),但大部分层次也不高还需要一个熟悉和加强的过程。
一般好点的跟项目半年以上就可以比较熟练了,慢热点的可能需要个一年多,更关键还是看兴趣,有的人就是骨子里喜欢写程序了,下班了也会弄些自己感兴趣的进步就会很块。
不同的团队经验估计也不能完全复制,我是公司的创始人之一,技术上事基本是我确定,也不存在离职之类的问题。
我对于用 Python 去解决我们遇到的大部分的技术问题还是很有兴趣的,包括如何规范如何带人才能让代码可控人员也能得到提高等也是有信心。
总的讲这些年跌跌撞撞多少也积累了点技术和管理上的经验,换个别的语言说实在的我反而不那么自信了。