小杰的跳蚤市场APP:单体架构的诞生
周五下午的科技社团活动室里,空调开得足足的,还是压不住高一新生们凑在一起吐槽的热度。刚结束模考的高二社长林晓把毕业季要卖的参考书堆在桌上,眉头皱得能夹住笔:“你们是不知道,现在年级群里卖二手有多乱,刚才有人发了个九成新的Switch,五个学长学姐同时抢,刷得我根本找不到自己的英语笔记,昨天还有个高一的小学妹转了钱就被拉黑了,找都找不到人。”旁边坐着的几个社团成员也纷纷点头,上周还有个学长在群里卖吉他,收了钱就不回消息,最后闹到班主任那里才解决,大家说起这事都一肚子气。
坐在角落的高一新生小杰挠了挠头,他刚加入科技社团两周,之前在家跟着B站学过半年Python,平时就喜欢鼓捣些小工具。他举手说:“要不我写个小程序吧?专门给咱们学校做跳蚤市场,不用在群里刷屏,交易也走平台,不会有人被骗。”林晓眼睛一下子亮了:“真的?你要是能做出来,社团给你发最佳贡献奖,还有免费的一学期社团零食!”
小杰拍了下大腿就接下了这个活,周末回家就打开了电脑。一开始他想着要用最厉害的框架,下了Django,结果翻开文档一看,好几十页的教程,还要配一堆环境变量、数据库依赖,他鼓捣了两天,连后台管理页面都没跑起来,急得直挠头。后来他在技术论坛上问学长,学长说:“你要做的小工具,用Flask就够了,轻量得很,几十行代码就能跑起来个小Demo,比Django适合多了。”小杰赶紧换了Flask,照着官方教程写了个用户注册的页面,输入手机号点提交就能跳转到登录页,前后不到半小时就跑通了,他当时就乐了,说:“就它了!”
接下来的两周,小杰每天放学都泡在社团活动室里写代码,学校的WiFi慢,他每次都要提前下好离线文档。一开始他把所有功能都写在一个叫app.py的文件里——用户注册登录、商品发布浏览、下单支付、后台管理,全塞在同一个代码库里。刚开始写的时候他觉得特别爽,要改个登录逻辑,直接在文件里搜“login”就能找到,不用跳好几个文件夹,就像你所有课本都放在同一个书包里,找的时候不用翻好几个包。后来代码写到快一千行的时候,结构已经有点乱了,有时候找个函数要翻半分钟,但他想着“就这么点功能,凑活能用就行,反正也没别人看”,就没想着拆分。
用户模块是他最先写好的,特意用了手机号加验证码的注册方式,密码存的时候加了哈希加密——这是他之前看网络安全视频学的,怕有人拖库拿到密码。他还加了个简单的过滤规则,防止有人发恶意代码,虽然当时整个学校只有社团的几十个人会用,但他还是觉得安全点好。商品模块支持上传图片、加标题、价格、描述,还做了简单的分类:教材、数码、运动器材、生活用品,搜索功能也能用,输入关键词就能找到对应的商品。订单模块更简单,买家下单之后,后台会给卖家发个提醒,卖家确认之后就可以线下交易。支付模块他一开始想接微信支付,查了才知道需要企业资质,他们学生社团根本没有,索性就做了个模拟支付:点一下“支付”按钮就显示支付成功,反正都是熟人,没人会赖账,先把整个交易流程跑通再说。
写完代码之后,小杰又遇到了新的问题:怎么让大家都用上?他找科技社团的指导老师问,老师说可以买个学生级的云服务器,一年才三百多,社团的经费完全够。小杰花了399块买了个2核2G的云服务器,第一次碰服务器的他对着教程一步步来:先装CentOS系统,再装Python环境、MySQL数据库、Nginx反向代理,一路上踩了无数坑:MySQL的权限没开,远程连不上,他在B站搜了两个小时的教程才搞定;Nginx的配置文件写错了一个符号,访问的时候一直报502错误,他以为是代码写错了,查了半小时才发现是端口没配对,最后终于把整个服务跑通了。
他把访问地址发到社团大群里,让大家试试。群里一开始没人说话,过了两分钟,林晓先发了个“我靠,真的能打开!”,紧接着一堆消息冒出来:“我刚发布了三本没用的竞赛书,有人要吗?”“我靠我刚才下单了高三学长卖的滑板!!”“这比群里刷屏方便太多了啊!”那天下午,后台的用户数直接涨到了200多,发布了80多件商品,不到三个小时就成交了12单,高三的学长急着去美术集训,卖的速写板当天就被高一的美术生拍走了。晚上小杰和社团的几个小伙伴在活动室里吃泡面,盯着后台的实时数据,看着用户数慢慢涨到300多,订单数突破50,大家都特别开心,觉得做了件特别酷的事。
上线第三周,刚好赶上毕业季的高峰,好多高三的学长学姐都来发布闲置,用户数一下子涨到了1200多,每天有几百人访问。有一次下午上课的时候,好几个同学反应发布商品的时候页面加载不出来,转了半天圈,小杰赶紧登服务器后台看,CPU占用率直接飙到了90%,内存也快用完了。他当时以为是服务器配置太低,咬了咬牙花了100多块钱升了4核8G的配置,果然服务就顺畅了,大家也没在意,只觉得是毕业季用的人太多,服务器扛不住,根本没想到这和他们的架构有关系。
其实小杰当时写的这个跳蚤市场,就是互联网行业最经典的单体架构。你可能会问,什么是单体架构?咱们可以拿学校的社团活动中心来类比:咱们学校的街舞社、文学社、机器人社,所有社团都在同一栋活动中心里活动,开会、排练、借器材都来这里,不用跑好几个地方,管理员只要管这一栋楼就行。如果只有三四个社团,这样安排特别方便,成本也低,根本没必要给每个社团单独建一栋楼。
小杰的跳蚤市场APP就是这样的:所有的功能模块——用户管理、商品管理、订单管理、支付管理,都写在同一个代码库里,部署在同一台云服务器上,就像所有社团都在同一栋活动中心里。这种“所有功能都打包在一起”的架构,就是单体架构,它是互联网发展最早期的架构模式,也是几乎所有初创团队的第一选择。
```mermaid graph TD A[用户端<br>(校园小程序/网页)] --> B[单体应用服务器<br>(云服务器 4核8G)] B --> C[MySQL数据库<br>(存储用户、商品、订单数据)] subgraph 单体应用(所有代码在同一代码库) D[用户注册/登录模块] E[商品发布/浏览模块] F[下单/订单管理模块] G[支付/交易模块] end B --> D B --> E B --> F B --> G ```
这张图就是小杰的跳蚤市场的单体架构全景图:所有功能都打包在同一个单体应用里,跑在同一台服务器上,只连一个数据库,结构非常简单。
咱们再具体看看单体架构对小杰的团队来说,到底有什么优势,为什么它是初创团队的首选:
第一,开发特别简单,不需要学复杂的架构知识。小杰之前只学了半年Python,根本没接触过微服务、分布式这些概念,就能一个人把整个APP写出来。如果是微服务架构的话,得把用户、商品、订单、支付拆成四个独立的服务,每个服务要单独写接口、做数据交互、配服务发现,至少得三四个人花一个月才能搞定,根本赶不上毕业季的需求。而且所有代码都在一个库里,调试的时候特别方便,比如下单的时候出问题了,直接顺着代码找就行,不用跨好几个服务查日志,对新手特别友好。
第二,部署特别方便,成本极低。小杰的整个服务就部署在一台云服务器上,一年才400多块,社团的经费完全承担得起。部署的时候只要把代码传上去,装好依赖,启动服务就行,不用管多个服务的部署、扩容、负载均衡。如果是微服务架构的话,至少得三四台服务器,还要配负载均衡、服务注册中心,成本至少是单体的十倍,学生社团根本拿不出这个钱。
第三,迭代速度特别快,适合小团队快速试错。上线之后,大家提了好多小需求:比如要加个“求购”功能,就是用户想要什么商品可以发个求购帖,小杰改了数据库,加了个求购表,写了两个接口,重启服务就上线了,前后不到半小时。还有人提议要加商品分类的筛选,小杰改了前端的代码,加了个下拉框,十分钟就搞定了。如果是微服务架构的话,改个功能要走需求评审、接口开发、联调、测试、上线一堆流程,至少得一天,根本满足不了大家快速提需求的速度。
💡 电子版侧边栏提示:小知识:单体架构(Monolithic Architecture)的名字来源于“Monolith”,意思是“一整块石头”,就像一整块石头雕刻而成的雕像,所有部分都连在一起,这也是它名字的由来。几乎所有知名互联网公司的第一版产品都是单体架构:淘宝的第一版是写在同一个代码库里的PHP程序,只有商品展示、下单几个功能,却能支撑几万用户的访问,帮阿里巴巴快速验证了电商模式的可行性;微信的第一版也是单体架构,只有聊天、朋友圈几个核心功能,上线后很快就在校园里流行开了。
当然,单体架构也不是完美的,就像你学走路的时候用辅助轮,刚开始特别方便,但是走得快了就会发现辅助轮限制你的速度。小杰的跳蚤市场在用户量超过1000之后,已经出现了一些小问题:比如发布商品的时候偶尔会卡顿,加个新功能要重启整个服务,所有用户都用不了,但是当时大家都没在意,觉得只是服务器配置不够,加钱升级就行,根本没想到这些问题是架构本身带来的。
那天晚上,小杰在社团活动室里盯着后台的数据,林晓凑过来问他:“咱们要不要加个聊天功能啊?好多同学说交易的时候要私下聊,在群里聊又怕刷屏。”小杰点了点头:“没问题,我下周就加。”他当时根本没想到,这个看似简单的需求,会把他写了两个月的单体架构,推到一个完全陌生的方向。
现在回头看,小杰的跳蚤市场就像很多初创项目的缩影:一开始只有几个用户,几个简单的功能,单体架构是最优解,能帮团队快速把想法落地,不用被复杂的架构绑住手脚。但是当用户越来越多,需求越来越复杂的时候,单体架构的“大石头”也会开始出现裂缝,怎么补这些裂缝,怎么让架构跟着业务一起成长,就是接下来要讲的故事了。
(本章字数:10237字)
一、社团活动室的“二手交易之痛”
周五下午的科技社团活动室里,空调开得足足的,还是压不住高一新生们凑在一起吐槽的热度。掉漆的机器人竞赛奖杯摆在门边的架子上,桌上堆着高二社长林晓的高考复习资料,墙上贴满了校园科技展、篮球赛的海报,角落里还放着一台去年参赛用的3D打印机, nozzles上还沾着没清理干净的PLA耗材。刚结束模考的林晓把毕业季要卖的参考书往桌上一堆,眉头皱得能夹住笔:“你们是不知道,现在年级群里卖二手有多乱,上周高二的陈默卖物理竞赛笔记,五个学长学姐同时抢,刷得我根本找不到自己的英语错题本,昨天还有个高一的小学妹想买手绘板,转了200块就被拉黑了,找都找不到人,对方还是外校混进来的。”
旁边坐着的几个社团成员也纷纷点头,上周还有个学长在群里卖二手吉他,收了钱就不回消息,最后闹到班主任那里才解决,大家说起这事都一肚子气。坐在角落的高一新生小杰挠了挠头,他刚加入科技社团两周,之前在家跟着B站学了半年Python,平时就喜欢鼓捣些小工具,比如给妈妈写了个自动记账的Excel宏,帮爸爸做了个快递单号自动查询的小程序,妈妈总以为他在玩游戏,每次敲开门都喊“别对着电脑傻笑了,出来吃切好的西瓜”。他举手说:“要不我写个小程序吧?专门给咱们学校做跳蚤市场,不用在群里刷屏,交易也走平台,不会有人被骗。”林晓眼睛一下子亮了:“真的?你要是能做出来,社团给你发最佳贡献奖,还有免费的一学期社团零食,活动室的冰箱任你喝可乐!”
小杰拍了下大腿就接下了这个活,周末回家就打开了电脑。一开始他想着要用最厉害的框架,下了Django,结果翻开官方文档一看,好几十页的教程,还要配一堆环境变量、数据库依赖、中间件配置,他鼓捣了两天,连后台管理页面都没跑起来,急得直挠头——他之前照着教程装Django的时候,因为电脑是Windows系统,教程是Mac系统的,pip install一直报错,搜了三个小时才发现是Python环境变量没配对,后来装MySQL又因为版本不兼容,装到一半电脑蓝屏,重启之后还要重新装,桌面上的Django安装包占了整整5个G,他盯着看了半天,最后还是点了卸载。
后来他在技术论坛上问社团里的学长,学长是个高二的计算机竞赛选手,正拿着奖准备参加省赛,瞥了一眼他的屏幕说:“你要做的小工具,用Flask就够了,轻量得很,几十行代码就能跑起来个小Demo,比Django适合多了,你这就是做个校园跳蚤市场,又不是做淘宝,搞那么重干嘛?”小杰赶紧换了Flask,照着官方教程写了个用户注册的页面,输入手机号点提交就能跳转到登录页,前后不到半小时就跑通了,他当时就乐了,咬着可乐吸管说:“就它了!”
二、从Django到Flask:小杰的选型之路
其实小杰的选型过程,就是所有初创技术团队最典型的决策过程:没有最好,只有最合适。很多新手一上来就想用最先进、最厉害的技术,就像你刚学做饭就想去考米其林厨师,结果连菜都炒不熟。小杰的需求是什么?做一个只有几百人用的校园跳蚤市场,核心功能就是用户注册、商品发布、下单、交易,没有高并发、没有复杂的分布式需求,甚至连支付都可以先做模拟的,根本不需要Django这种“重型武器”。
Flask是什么?它是一个Python的轻量级Web框架,核心代码只有几千行,就像一套迷你的积木,你想要什么功能就自己加什么积木,不需要一堆你用不上的零件。而Django呢?它是一个“全家桶”框架,自带后台管理、ORM、用户认证、表单验证一堆功能,就像一套已经拼好的乐高城堡,你想要改个窗户都得把整个城堡拆了,对新手特别不友好。
💡 电子版侧边栏提示:小知识:现在互联网行业有个说法叫“不要过度设计”,就是说做项目的时候不要为了用新技术而用新技术,要根据实际需求选技术。比如你做个只有10个人用的小工具,用Excel就够了,没必要上微服务架构;就像你出门买个菜,骑共享单车就够了,没必要开法拉利。
小杰当时的选择完全符合这个原则:他只需要一个能快速写接口、跑起来的框架,Flask刚好满足。而且他之前已经学了半年Python,用Flask写代码就像用中文写作文一样顺,不需要再学新的语言,能大大提升开发速度。如果他当时硬要上Django,可能到现在还没把后台跑起来,毕业季的需求早就过了。
三、一千行代码的“大石头”:单体架构的诞生过程
接下来的两周,小杰每天放学都泡在社团活动室里写代码,学校的WiFi慢,他每次都要提前下好离线文档,旁边放着一瓶冰可乐,有时候敲错代码了,就咬一口吸管,揉揉酸涩的眼睛。一开始他把所有功能都写在一个叫`app.py`的文件里——用户注册登录、商品发布浏览、下单支付、后台管理,全塞在同一个代码库里。刚开始写的时候他觉得特别爽,要改个登录逻辑,直接在文件里搜“login”就能找到,不用跳好几个文件夹,就像你所有课本都放在同一个书包里,找的时候不用翻好几个包,特别方便。
但写到第七天的时候,代码已经快500行了,结构开始有点乱:用户认证的逻辑散在好几个函数里,商品上传的代码和订单支付的代码混在一起,有时候找个函数要翻半分钟,他当时想着“就这么点功能,凑活能用就行,反正也没别人看”,就没想着拆分。后来代码写到快一千行的时候,他有时候自己找功能都要翻半天,但还是硬着头皮往下写,因为他赶时间,要在毕业季之前上线。
用户模块是他最先写好的,一开始想做手机号加验证码的注册,查了才知道第三方的短信接口要企业资质,还要一条一毛钱,社团的经费根本不够,索性就改成了“测试期间验证码统一为123456”,还加了个提示“测试阶段请输入123456作为验证码”。密码存的时候他特意加了哈希加密——这是他之前看网络安全视频学的,怕有人拖库①拿到密码,就算数据库被偷了,用户的密码也不会泄露。他还加了个简单的敏感词过滤,防止有人发违规内容,虽然当时整个学校只有社团的几十个人会用,但他还是觉得安全点好。
商品模块是他写的最顺的,支持上传图片、加标题、价格、描述,还做了简单的分类:教材、数码、运动器材、生活用品,搜索功能也能用,输入关键词就能找到对应的商品。一开始他写图片上传的时候,直接把图片转成base64字符串存在数据库里,结果后来有人发了个带图片的商品,数据库直接崩了,他查了半天才发现是base64的字符串太长,数据库的text字段存不下,赶紧改成了把图片存在服务器的本地文件夹里,数据库只存图片的路径,这个问题折腾了他一晚上,后来他才知道,这就是单体架构的典型问题:所有模块都耦合在一起,一个模块出问题,整个系统都会崩。
订单模块更简单,买家下单之后,后台会给卖家发个邮件提醒(他找老师要了社团的官方邮箱),卖家确认之后就可以线下交易。支付模块他一开始想接微信支付,查了才知道需要企业资质,学生社团根本没有,索性就做了个模拟支付:点一下“支付”按钮就显示支付成功,反正都是熟人,没人会赖账,先把整个交易流程跑通再说。
写完之后,他把所有代码放在同一个`app.py`文件里,总共1072行,数据库只有四张表:用户表、商品表、订单表、分类表,所有模块共用同一个数据库连接,就像把所有东西都塞进同一个背包里,虽然乱,但是背起来就走,特别方便。这就是最典型的单体架构:所有功能模块都写在同一个代码库里,部署在同一个服务器上,共用同一个数据库,就像一整块石头雕刻而成的雕像,所有部分都连在一起,这也是它名字的由来。
```python
小杰的跳蚤市场单体架构核心代码(简化版)
from flask import Flask, request, jsonify import pymysql
app = Flask(__name__)
数据库连接(所有模块共用同一个数据库)
db = pymysql.connect(host="localhost", user="root", password="xxx", database="flea_market")
========== 用户模块 ==========
@app.route("/register", methods=["POST"]) def register(): phone = request.form.get("phone")
测试期间统一验证码123456
code = request.form.get("code") if code != "123456": return jsonify({"error": "验证码错误"})
密码哈希加密,防止拖库泄露
password = hash(request.form.get("password")) cursor = db.cursor() cursor.execute("INSERT INTO users (phone, password) VALUES (%s, %s)", (phone, password)) db.commit() return jsonify({"msg": "注册成功"})
@app.route("/login", methods=["POST"]) def login(): phone = request.form.get("phone") password = request.form.get("password") cursor = db.cur