为什么选择 Go ?

为什么选择 Go ?
耳朵Strive为什么选择 Go ?
起因
事情的起因其实很简单,我写了一个访客统计服务。真的非常简单的那种,只有两个接口:
- 一个
POST,用户进入页面时打点 - 一个
GET,返回统计数据(PV、UV、地区、设备等)
没什么高并发、没什么复杂业务,就是一个“小透明服务”。这个服务最初是用 Node 写的,Express + SQLite,一切都很熟,开发速度也很快。但我把服务用 pm2 跑起来之后,看了一眼服务器监控:内存接近 200MB。
说实话,那一刻我有点懵。这坑定不行呀,我的服务器才2G的内存,这一个小小的服务就占用十分之一。不是说 Node 不该用这么多,而是这个体量的服务,真的不该用这么多。按经验,一个普通的 Node API 服务,50MB 左右是比较正常的数字。于是我开始怀疑是不是我代码写得太离谱了。
我把整个服务从头到尾过了一遍:
- 没有大对象常驻内存
- SQLite 查询都很简单
- IP 缓存是一个 Map,也没无限增长
- 没有 websocket、没有定时大任务
- axios 请求有超时
- UA 解析、Geo 解析也都是常规用法
说白了:这就是一个很“干净”的 Node 服务。
但现实就是:
Node + V8 + 一堆依赖,本身就是一个重量级运行时
哪怕你业务再简单,它的“起步成本”就在那里。
那我还能选什么?
我当时会、且能比较熟练使用的后端语言:
- Node.js
- Python
- Java
但这三个放在“小服务 + 小服务器 + 内存敏感”这个前提下,说实话都不太合适:
- Python:开发快,但性能和内存基本不在考虑范围
- Java:性能不错,但 JVM 本身就是内存大户
- Node:开发体验好,但 V8 常驻内存对我不友好
于是我把目光投向了两个“更底层一点”的选择:Go 和 Rust
Rust?我真的试过,但……不行
先说 Rust。我对 Rust 的评价其实一直很高:
- 性能顶级
- 内存占用极低
- 接近 C++,但更安全
但问题在于:我入门好几次,到头来还是在门外徘徊。不是那种“看不懂”,而是那种:
每写一段代码,都要跟编译器进行一次心理博弈。
对一个需要尽快把服务跑起来的场景来说,Rust 的心智成本太高了。这不是语言不好,是现在的我不适合它。
Go:我需要的,刚好它都有
再看 Go。我越看越觉得:它几乎是为我这个场景量身定做的。
1.开发效率:真的很高
Go 的关键词少得离谱,语法也非常直白:
- 没有复杂泛型(至少日常用不到)
- 没有继承地狱
- 错误处理虽然啰嗦,但非常清晰(虽然说我还是不喜欢,习惯了
try...catch之后,写if err != nil太别扭了)
几乎可以用“写脚本”的心态,在写一个性能级别的服务。
2.内存占用:这是关键
这一点是我下定决心的核心原因。
Go 编译后是一个静态二进制文件:
- 没有 JVM
- 没有 V8
- 没有庞大的运行时依赖
实际跑起来,一个类似的 HTTP 服务,十几 MB 内存就能活得很好。对我这种小服务器来说,简直是救命稻草。
3.性能:完全够用,甚至富余
Go 的性能可能比不过 Rust、C++,但对一个访客统计服务来说:Go 的性能,已经是严重过剩的级别了。
IO、多协程、并发请求,Go 天生就擅长这些。
4.一些额外但很香的点
- goroutine:写并发几乎不用思考
- 跨平台编译:Linux / Windows / Mac 一条命令
- 部署简单:一个文件,scp 上去就完事
理论成立,那就开始实干
1.安装 Go 环境
下载 Go SDK:https://go.dev/dl/
选择 Windows 版本(msi 安装包,如
go1.22.x.windows-amd64.msi)。安装 Go SDK
双击下载的 msi 安装包,看不懂就一路点击 Next,如果能看懂就可以修改想要修改的配置,建议默认安装路径(C:\Program Files\Go\),避免中文/空格路径。
安装完成后,Go 会自动配置环境变量:
GOROOT:Go 的安装目录(如C:\Program Files\Go\);PATH:添加%GOROOT%\bin(可直接在终端执行go命令)。
验证安装
按下
Win + R输入cmd打开命令提示符,执行以下命令,输出版本号即安装成功:1
2go version
# 示例输出:go version go1.25.5 windows/amd64配置 Go 环境
Go 的核心环境变量需要手动配置(推荐用
go env命令设置,永久生效):1
2
3
4
5# 1. 设置模块代理(解决国内下载依赖慢的问题,必配)
go env -w GOPROXY=https://goproxy.cn,direct
# 2. 设置 Go 模块启用(Go 1.16+ 默认开启,可选确认)
go env -w GO111MODULE=on把 Go 的全局缓存挪到 D 盘(C 盘真的顶不住)
先在 D 盘新建文件夹,比如:
D:\GoCache\mod(路径自定义,建议简单易记,不要有中文/空格)把 C 盘默认缓存目录的文件复制到新目录,避免重新下载所有依赖:进入原有缓存路径:
C:\Users\你的用户名\go\pkg\mod(比如C:\Users\张三\go\pkg\mod),全选所有文件,复制后粘贴到D:\GoCache\mod目录下。修改环境变量(永久生效)
进入环境变量
在弹出的系统属性窗口中,点击环境变量
新建:变量名:
GOMODCACHE变量值:D:\GoCache\mod点击「确定」保存,关闭所有窗口
验证是否生效
1
2go env GOMODCACHE
# 输出 D:\GoCache\mod(你设置的路径)
2.重写服务
把整个 Node 服务,用 Go 完整重写了一遍,这里就不一一展示了,就是一个简单的服务。
大致包括:
- SQLite 存储
- IP 缓存
- 地理位置解析
- UV / PV 统计逻辑
最后的结果
结果其实很简单:
内存占用显著下降(内存从200m 下降到 20m,可以说是非常优秀了)
服务稳定性更好
非常舒服的部署体验(不依赖环境,打包的时候对应好就行)
上线正常运行
而且最重要的是,我并没有牺牲多少开发效率。我的云服务器2核2G,内存非常宝贵,小服务的内存占用我必须控制在50m以内,不是说 Go 是最好的,但它是现在最适合我的。
2026.01.03 更新
元旦最后一天,在家闲着没啥事,心想我的图床后端服务是不是也能够使用 Go 重写一下,理论存在,实践开始。
我的图床服务之前是使用 Node 写的,没错,又是它,我一般小服务和 Demo 项目我都会使用 Node 先搭建一个可行性的版本验证。
这个简单的服务框架大致如下:
- 整体架构:
- 使用Express框架搭建Web服务器。
- 使用MinIO作为对象存储服务,用于存储上传的图片。
- 使用SQLite数据库记录上传的图片信息(文件名、URL、大小、修改时间)。
- 使用JWT进行身份验证,保护上传、列出和删除图片的接口。
- 主要功能模块:
- 身份验证:通过登录接口获取JWT令牌,后续请求需要在Header中携带该令牌。
- 图片上传:将图片上传到MinIO,并将信息存入SQLite。
- 图片列表:分页获取图片列表。
- 图片删除:从MinIO和SQLite中删除指定的图片。
- 同步功能:启动时同步MinIO中的文件到SQLite数据库。
内存占用情况还行,是一个中规中矩的 Node 服务,大概 60m 左右。
然后就是使用 Go 来进行重写
重构之后,再来看一下内存的占用情况,发现内存占用下降到了 20m 左右,和访客统计服务的内存占用差不多,这个内存占用我还是非常满意的。




















