為什么我們公司還在用 Python 開(kāi)發(fā)項(xiàng)目?
共 5370字,需瀏覽 11分鐘
·
2024-04-27 10:40
作者:哇噠嘻哇 https://www.zhihu.com/question/278798145/answer/3416549119
最近幾年里,經(jīng)常看到某些曾重度使用 Python 的大公司遷移成其它語(yǔ)言技術(shù)棧,但是,那些小公司/小團(tuán)隊(duì)的情況如何呢?
一直很想了解那些仍在堅(jiān)持使用 Python,且支撐業(yè)務(wù)量有一定規(guī)模的公司是如何使用 Python 技術(shù)棧做開(kāi)發(fā)的、會(huì)遇到哪些困難/教訓(xùn)、有什么樣的優(yōu)秀經(jīng)驗(yàn)?
偶然在某乎上看到“為什么軟件公司很少用python開(kāi)發(fā)web?”問(wèn)題下的回答,這里分享給大家。
作者:哇噠嘻哇
(https://www.zhihu.com/question/278798145/answer/3416549119)
回復(fù):
我用 Python 有 10 多年了,現(xiàn)在維護(hù)最久的一個(gè)項(xiàng)目每年有幾個(gè)億的交易額,是個(gè)電商平臺(tái),并發(fā)數(shù)不算大,平時(shí)有幾十的并發(fā),過(guò)節(jié)會(huì) 100 出頭這樣,極限的時(shí)候我看也沒(méi)到 200 過(guò),數(shù)據(jù)庫(kù)上最多的訂單表量總數(shù)在 5000 萬(wàn)左右,每天增加幾萬(wàn)。項(xiàng)目有七八年了,還是用的 Python 2.7 + Django 1.8,沒(méi)打算升級(jí)了。
目前配備的 1 臺(tái) 4 核 8G、3 臺(tái) 8 核 16G 阿里云,數(shù)據(jù)庫(kù)和 Redis 也是用的阿里云,一年的費(fèi)用大概 5 萬(wàn)不到,CDN 用的七牛,每年大概也得幾萬(wàn)。有包括我在內(nèi)三個(gè)程序員在維護(hù),基本每周都有新功能在增加,經(jīng)過(guò)幾年的調(diào)整有效代碼估計(jì) 70% 不到了,部分代碼因?yàn)闃I(yè)務(wù)等原因沒(méi)在用了。
2021 年開(kāi)發(fā)的另一套系統(tǒng)用的 Python 3.8 + Django 3,平時(shí)沒(méi)啥量,節(jié)日會(huì)飆上去,目前為止的最高記錄是一分鐘 350 單,一天 15 萬(wàn)單,那天差不多交易額 1500 萬(wàn)。平時(shí)配置的兩臺(tái) 8 核 16G,節(jié)日會(huì)擴(kuò)容單 6 臺(tái),數(shù)據(jù)庫(kù)等也會(huì)做臨時(shí)升級(jí)。有包括我在內(nèi)四個(gè)程序員在維護(hù)。
另外小的項(xiàng)目有幾個(gè),沒(méi)怎么做起來(lái),也沒(méi)多少量,差不多是兩個(gè)人負(fù)責(zé)一個(gè)項(xiàng)目,一個(gè)人同時(shí)負(fù)責(zé)兩個(gè)項(xiàng)目這樣交叉著進(jìn)行的。
目前整個(gè)公司后端的技術(shù)棧都是 Python + Django + Gunicorn 這樣(有個(gè)小項(xiàng)目用的 tornado),公司基于 Django 做了一些基礎(chǔ)框架的積累,整個(gè)公司人也不多,大概十四五個(gè)程序員基本都對(duì)這套框架熟悉。新人來(lái)了也先一般是通過(guò)加強(qiáng) Python 基礎(chǔ) -> 學(xué)習(xí) Django -> 學(xué)習(xí)公司框架 -> 進(jìn)入項(xiàng)目開(kāi)發(fā)這樣的一個(gè)流程。
公司對(duì)命名、風(fēng)格等方面要求多些,CR 的時(shí)候也關(guān)注的多些,熟悉之后大家基本都很默契了,因此 Python 動(dòng)態(tài)語(yǔ)言的弊端沒(méi)怎么體現(xiàn)出來(lái)。
早期沒(méi)經(jīng)驗(yàn)也出現(xiàn)過(guò)并發(fā)稍微上來(lái)點(diǎn)就崩的情況,后面對(duì)數(shù)據(jù)庫(kù)進(jìn)行了升級(jí)(早期是自建的)又做了些 Redis 的緩存,現(xiàn)在發(fā)生的情況就少了很多了。
Django 構(gòu)造的一些查詢(xún)語(yǔ)言過(guò)于復(fù)雜或者沒(méi)考慮優(yōu)化,或?qū)е鲁霈F(xiàn)一些慢查詢(xún),現(xiàn)在解決的辦法是定期的關(guān)注慢日志,尋找出現(xiàn)的代碼去做優(yōu)化,數(shù)據(jù)庫(kù)本身也需要做根據(jù)業(yè)務(wù)進(jìn)行升級(jí)。這點(diǎn)其實(shí)換任何語(yǔ)言都一樣。
大部分編程語(yǔ)言我都有接觸過(guò),但唯獨(dú)覺(jué)得 Python 能夠讓我像母語(yǔ)一樣能夠很方便的表達(dá)我的意思給計(jì)算機(jī)。
對(duì)于 Python,從我自身的感覺(jué)來(lái)講是熟悉之后程序員就只需要理解業(yè)務(wù)把需求轉(zhuǎn)換成代碼,不需要在一些技術(shù)上花費(fèi)過(guò)多的時(shí)間。Python 的庫(kù)也比較多,基本上遇到的大部分問(wèn)題都有現(xiàn)成的東西可以使用。Django 的 ORM 也很贊,基本上讓程序員可以比較方便的操作到數(shù)據(jù)庫(kù),不需要去管表結(jié)構(gòu)變更、復(fù)雜查詢(xún)等。
要說(shuō)缺點(diǎn)也有,比如 Python 比較累贅,尤其隨著項(xiàng)目變大變復(fù)雜之后,啟動(dòng)加載需要的時(shí)間越來(lái)越長(zhǎng),跑起來(lái)之后占用的內(nèi)存也越來(lái)越大。
Django 的 ORM 帶來(lái)便利性的同時(shí)也帶來(lái)了一些低效的代碼,比如經(jīng)??吹降木褪怯行┤藰?gòu)造了比較復(fù)雜的查詢(xún),導(dǎo)致 join 的表太多了查詢(xún)時(shí)間太長(zhǎng),或者很多時(shí)候不管要不要的的字段都一次性查出來(lái)了,以及 for 循環(huán)里面大量的數(shù)據(jù)查詢(xún)等。
但我覺(jué)得這些缺點(diǎn)不算致命,因?yàn)橄啾热斯ら_(kāi)支和開(kāi)發(fā)效率,增加云服務(wù)器的成本是極低的,況且對(duì)于性能而言大部分的項(xiàng)目都到不了需要去優(yōu)化的階段就黃了。有些規(guī)范或者使用方式可以通過(guò)培訓(xùn)來(lái)進(jìn)行提升,大部分人寫(xiě)的代碼質(zhì)量都會(huì)逐步上來(lái)。
除了 Web 本身,我們有些硬件設(shè)備(大部分是帶 Linux 的單板機(jī),比如樹(shù)莓派、7688 等)上也會(huì)用 Python,好處就是可以在電腦上開(kāi)發(fā)然后直接放到設(shè)備上運(yùn)行,也不需要專(zhuān)門(mén)招嵌入式工程師,基本上對(duì)硬件調(diào)用部分封裝之后就可以讓公司任何一個(gè)后端去開(kāi)發(fā)了。
在一些圖片處理識(shí)別、爬蟲(chóng)、自動(dòng)化測(cè)試、CICD 等方面我們也在用 Python。
對(duì)于小團(tuán)隊(duì)來(lái)講,Python 的低門(mén)檻高效率比起所謂的性能損失類(lèi)型難以捉摸有價(jià)值,當(dāng)然,前提是需要建立規(guī)范、強(qiáng)調(diào)質(zhì)量以及持續(xù)性的關(guān)注和優(yōu)化。
想不到這個(gè)回答有這么多人關(guān)注,我就再補(bǔ)充幾點(diǎn)吧。
上面提到的每分鐘 350 單的那套系統(tǒng),主要做的事情是把幾個(gè)外賣(mài)平臺(tái)的訂單聚合接入到系統(tǒng),然后讓商家使用也是聚合接入的配送平臺(tái)呼叫騎手配送出去,整個(gè)過(guò)程涉及外賣(mài)訂單的同步和配送單的同步以及一些管理功能。
外賣(mài)平臺(tái)的訂單通知(新訂單、訂單狀態(tài)變動(dòng)等)會(huì)通過(guò)請(qǐng)求 HTTP 接口通知我們的系統(tǒng),早期我們做的是同步的方式,即收到請(qǐng)求之后去調(diào)用外賣(mài)平臺(tái)的訂單查詢(xún)接口(及另外幾個(gè)配套的接口)來(lái)獲取訂單詳情數(shù)據(jù)之后創(chuàng)建訂單存到數(shù)據(jù),然后再響應(yīng),因?yàn)榇罅康木W(wǎng)絡(luò)請(qǐng)求需要不少時(shí)間,并發(fā)量稍微上來(lái)一點(diǎn)就扛不住了,試過(guò)多開(kāi)幾臺(tái)機(jī)器和多開(kāi)幾個(gè)進(jìn)程,但作用都不太大。
記得早期每分鐘能處理 30 單基本是極限了,再多了就出現(xiàn)明顯的響應(yīng)慢了,而外賣(mài)平臺(tái)的通知又要求我們?cè)谝?guī)定的時(shí)間內(nèi)響應(yīng),因此同步處理的這個(gè)套路沒(méi)能堅(jiān)持多久就遇到極大的瓶頸了,嘗試過(guò)做多線(xiàn)程任務(wù)隊(duì)列等但效果不行也有任務(wù)丟失的風(fēng)險(xiǎn)。
后面我們用了 Celery,收到通知之后把消息放到 Celery 隊(duì)列就返回,讓 Celery 的工作者進(jìn)程來(lái)慢慢處理,避免高峰期扛不住。因?yàn)榘严⒎诺?Celery 隊(duì)列的極快的操作,系統(tǒng)也就能即時(shí)的響應(yīng)外賣(mài)平臺(tái)的通知消息了。
根據(jù)消息積壓情況,我們會(huì)適當(dāng)?shù)恼{(diào)整 Celery 工作者進(jìn)程數(shù)量,并且可以根據(jù)消息的優(yōu)先級(jí)分配不同的隊(duì)列,這樣能保證新訂單的通知消息能夠及時(shí)的處理,讓商家盡早知道有新訂單需要處理。
最早 Celery 的消息分發(fā)我們用的 Redis,后面為了更方便監(jiān)控?fù)Q成了 RabbitMQ。也可能是經(jīng)過(guò)了幾年的迭代,目前應(yīng)對(duì)節(jié)日我們心里相對(duì)有點(diǎn)底,該增加的云資源就臨時(shí)增加一下,Celery 的工作者進(jìn)程也做成了自動(dòng)擴(kuò)容,原則上來(lái)講不遇到十分極端的情況的話(huà)我們還是有信心能夠應(yīng)扛得住的。
除了上面提到的這些,大概七八年前我們用 Python 2 + Django 1.8 給政府做過(guò)一個(gè)讓企業(yè)填報(bào)數(shù)據(jù)系統(tǒng),每年會(huì)放開(kāi)一周讓企業(yè)來(lái)填,大概有四五千家企業(yè)來(lái)填,每個(gè)企業(yè)填七八個(gè)表,并發(fā)數(shù)當(dāng)時(shí)沒(méi)注意,保守估計(jì)也會(huì)有幾十。
一開(kāi)始用的 Django 自帶的 runserver 模式跑的(其實(shí)也是沒(méi)經(jīng)驗(yàn)),很容易就出現(xiàn)卡頓的情況,后面通過(guò) Gunicorn 跑了幾個(gè)進(jìn)程之后就沒(méi)出現(xiàn)在語(yǔ)言層面卡的問(wèn)題來(lái)了,慢的時(shí)候大概率也是數(shù)據(jù)庫(kù)負(fù)載占用太高了或者 mongodb 做數(shù)據(jù)匯總。
服務(wù)器配置不高只是 2C8G 的,跑 Python Web、MySQL 和 MongoDB,還有其他的一堆應(yīng)用進(jìn)程。這個(gè)系統(tǒng)跑了三年,第四年因?yàn)檎畬用娴年P(guān)系變動(dòng)由另外一家公司重新做來(lái)開(kāi)發(fā)了,功能沒(méi)我們做的多而且難用,比我們的還卡,不知道他們用的什么語(yǔ)言。
這個(gè)項(xiàng)目上,Python + MonogoDB 的方式給予我們極大的靈活性,因?yàn)槊磕晏顖?bào)的數(shù)據(jù)不一樣,統(tǒng)計(jì)指標(biāo)也不一樣,整個(gè)系統(tǒng)支持填報(bào)表單的自定義、數(shù)據(jù)校驗(yàn)、數(shù)據(jù)導(dǎo)入導(dǎo)出、自定義統(tǒng)計(jì)等,換其他語(yǔ)言我感覺(jué)是很難做出這樣的效果,或者說(shuō)相同的效果需要付出的代價(jià)會(huì)更高。
當(dāng)然這套系統(tǒng)沒(méi)多少維護(hù)方面的事情,基本上是一次開(kāi)發(fā)成型,后面保證能訪(fǎng)問(wèn)就行,當(dāng)時(shí)是我?guī)е粋€(gè)初級(jí)程序員開(kāi)發(fā)的,我負(fù)責(zé)核心的架構(gòu)和大部分代碼的實(shí)現(xiàn),他做簡(jiǎn)單點(diǎn)的邏輯、UI、表定義等,可能他也不一定容易理解我寫(xiě)的那堆代碼。這類(lèi)復(fù)雜系統(tǒng)的代碼可維護(hù)性我覺(jué)得很大程度取決于規(guī)范、文檔和培訓(xùn),而不是語(yǔ)言層面的類(lèi)型約束。
另外還做過(guò)一套給旅行社內(nèi)部用的辦公系統(tǒng),主要是針對(duì)東南亞的旅行社,支持多語(yǔ)言多幣種,涵蓋了幾乎旅行社日常的所有業(yè)務(wù),包括計(jì)劃、成團(tuán)、拼團(tuán)、酒店車(chē)船、購(gòu)物、導(dǎo)游、客人、報(bào)賬、收益、財(cái)務(wù)、報(bào)表、圖表等。
也是 Python 2 + Django 1.8 做的,我們給每家旅行社獨(dú)立部署一個(gè) Web 進(jìn)程 + 一個(gè)數(shù)據(jù)庫(kù)(數(shù)據(jù)庫(kù)名稱(chēng)是獨(dú)立的,但一臺(tái)機(jī)器上跑一個(gè) mysql)。每個(gè) Web 進(jìn)程跑起來(lái)之后大概 170MB 的內(nèi)存占用,我們用的 2C8G 的機(jī)器,每臺(tái)機(jī)器可以給 40 家左右的客戶(hù)提供服務(wù),一般客戶(hù)每天的用戶(hù)使用數(shù)據(jù)也就是 10 來(lái)個(gè),大點(diǎn)的旅行社會(huì)有個(gè)二三十個(gè)員工同時(shí)操作,大部分是查數(shù)據(jù)錄數(shù)據(jù),每家的并發(fā)估計(jì)不會(huì)超過(guò) 10。
每月初各家都在做賬導(dǎo)數(shù)據(jù)的時(shí)候偶爾會(huì)反饋卡頓的問(wèn)題,據(jù)我觀察大部分是數(shù)據(jù)庫(kù)層面的性能問(wèn)題,我們的解決方案是客戶(hù)告訴客戶(hù)過(guò)一會(huì)兒再導(dǎo)(或者要導(dǎo)的數(shù)據(jù)多的話(huà)就讓他們?cè)谕砩蠈?dǎo)),只要幾家之間稍微錯(cuò)開(kāi)導(dǎo)數(shù)據(jù)了也就沒(méi)問(wèn)題。
為了省成本,數(shù)據(jù)庫(kù)我們也是在云服務(wù)器上自建的,幾乎是把云服務(wù)器榨到極限了,白天服務(wù)器基本都是跑在 80% 以上的 CPU 占用以及 90% 以上的內(nèi)存占用,導(dǎo)數(shù)據(jù)的時(shí)候 CPU 會(huì)跑滿(mǎn)。
2020 年前我們手上有 100 多家客戶(hù),疫情三年基本都沒(méi)在做旅游了,這幾年可能是那幾臺(tái)服務(wù)器最清閑的時(shí)候了,去年今年恢復(fù)了一些客戶(hù),但和之前完全沒(méi)法比,因?yàn)槭杖脘J減,客戶(hù)的付費(fèi)意愿也降低了不少。
我是 2012 年前后接觸的 Python,在這之前用 Java 和 C# 的多,Java 用來(lái)做 Android 和 Web 的開(kāi)發(fā),C# 是做 Windows 桌面程序和 Windows Phone 的開(kāi)發(fā)。
之前用的 Java SSH 框架 xml 配置我很頭大,感覺(jué)基本都是在寫(xiě)廢話(huà),不知道現(xiàn)在的 Spring 會(huì)不會(huì)方便一些,除了框架的麻煩外,Java 語(yǔ)言本身我感覺(jué)也是相對(duì)繁瑣些。
C# 的感覺(jué)比 Java 好,但跨平臺(tái)方面又拉胯一些,所以現(xiàn)在除了做桌面程序會(huì)選 C#,其他情況也不會(huì)選了,況且現(xiàn)在大部分情況下寫(xiě)桌面程序也用網(wǎng)頁(yè)了。
而 Python 的感覺(jué)就是足夠簡(jiǎn)單,可以讓人專(zhuān)注于業(yè)務(wù),所以公司在選擇主要的語(yǔ)言的時(shí)候就定了 Python 了(雖然那時(shí)候我其實(shí)對(duì) Python 的熟悉程度還不如 Java 和 C#),整個(gè)團(tuán)隊(duì)建設(shè)也往 Python 方向,但是也完全想表達(dá)隨著 AI 的發(fā)展,Python 也會(huì)跟著火起來(lái)。
前些年招 Python 的人相對(duì)困難些,基本都是其他語(yǔ)言的來(lái)團(tuán)隊(duì)里面了才逐漸的適應(yīng)和熟悉的,這幾年有 Python 基礎(chǔ)的人稍晚多點(diǎn)了(感謝公眾號(hào)廣告?),但大部分層次也不高還需要一個(gè)熟悉和加強(qiáng)的過(guò)程。
一般好點(diǎn)的跟項(xiàng)目半年以上就可以比較熟練了,慢熱點(diǎn)的可能需要個(gè)一年多,更關(guān)鍵還是看興趣,有的人就是骨子里喜歡寫(xiě)程序了,下班了也會(huì)弄些自己感興趣的進(jìn)步就會(huì)很塊。
不同的團(tuán)隊(duì)經(jīng)驗(yàn)估計(jì)也不能完全復(fù)制,我是公司的創(chuàng)始人之一,技術(shù)上事基本是我確定,也不存在離職之類(lèi)的問(wèn)題。
我對(duì)于用 Python 去解決我們遇到的大部分的技術(shù)問(wèn)題還是很有興趣的,包括如何規(guī)范如何帶人才能讓代碼可控人員也能得到提高等也是有信心。
總的講這些年跌跌撞撞多少也積累了點(diǎn)技術(shù)和管理上的經(jīng)驗(yàn),換個(gè)別的語(yǔ)言說(shuō)實(shí)在的我反而不那么自信了。
