招聘会在一所大学的体育馆,二月,馆里没开暖气,我们两个人带了笔记本和一件外套,早上七点到现场。官网提前一周上线,功能是展位查询、简历投递、现场扫码签到。真正让人紧张的是开场那两小时。
扫码入口贴在哪个位置
客户原本想把二维码印在海报正中,扫码进首页再点「签到」。我们拦了一下,改成每张桌牌一个独立二维码,URL 带展位号,扫完直接落到签到页,少两步。二维码是提前用脚本批量生成的,87 个展位,87 张,文件名用展位号,打印出来核对了三遍。
签到页只做一件事:填手机号后四位,提交。不填姓名,不填学校,不注册。现场网络是体育馆的公共 Wi-Fi,多一个字段就多一批人卡在输入上。
九点十分,日志开始涨
开场九点。九点零八分开始有请求,九点十分到十点四十是高峰。我们两个人在后台看 Nginx 的 access log,用 tail -f 加 awk 数每分钟的 POST 数。峰值大概一分钟 140 多次提交,不算大,但全挤在一个 PHP 接口上。
十点出头,有几个人说「点了没反应」。查日志,200 和 500 混着,500 的是数据库连接超时。那台 MySQL 的 max_connections 设的是 100,PHP-FPM 起了 32 个进程,加上简历投递页也在查库,连接数顶满了。现场没法改配置重启,我们先把简历投递页的「实时查重」临时关掉,它每次输入手机号就查一次库,纯属浪费,连接数立刻降下来。
后来复盘,那个实时查重是开发时顺手加的,没人觉得有问题。
那 87 张二维码后来重印过一次
第一批桌牌印出来,有 3 张的展位号对不上,是排版时表格串了行。开幕前一天核对才发现,连夜找印厂重印,贴到桌牌上时胶还没干。从那以后生成二维码的脚本里加了一步:导出一张对照表,二维码文件名、展位号、URL 三列,打印出来人工勾一遍,再发给印厂。
还有个没料到的用法。招聘会第二天,客户问能不能看「哪个时段人最多」。签到表里本来只有时间戳,我们按 10 分钟一段 GROUP BY 了一下,导出一张 12 行的表,峰值落在 9 点 40 到 9 点 50。他们拿去排下一届的展位布置,把热门企业挪到了靠近入口的位置。这个需求不在原始清单里,是数据摆在那儿之后自己冒出来的。
公共 Wi-Fi 那件事
现场网络是体育馆的,我们没有控制权。头一年吃过亏之后,后来这类活动会自带一台 4G 路由做备用,签到页做成断网也能把记录存在 localStorage,有网再补传。2017 年那次没这套,全靠关掉实时查重扛过去,现在看有点悬。
那天回程地铁上收到「没崩」俩字,我们几个都没回。过了半小时有人发了个红包,备注写「87 张都贴对了」。后来那份「现场开关」清单也用过几次,每次活动前打印一张,压在签到台玻璃板底下。第三年清单上多了一条:先把备用路由插上电。那份对照表现在还留着,87 行,最后一行是手写的「补印 3 张」,后来每届都从这张表改,改完另存一份带年份的,原件没动过。
数据怎么收
签到记录写进一张表,字段就四个:id、手机号后四位、展位号、时间戳。当天下午导出 CSV,2000 多行,交给客户跟简历库比对。客户拿 Excel 做了个数据透视,按展位号看每个摊位收了多少人,哪几个摊位冷清一目了然。
散场的时候体育馆开始清人,我们把笔记本合上,外套没怎么穿。回程地铁上收到客户消息:没崩。就俩字,看着挺踏实。
后来这类活动我们固定带一份「现场开关」清单:实时查重、短信通知、复杂报表,高峰时段一律先关。

