第 7 章:构建数据服务
数据服务是云原生应用的核心组成部分。通过测试优先的设计、数据库集成和自动化部署,可以实现高效、可靠的数据持久化。本章将系统介绍如何用 Go 和 MongoDB 构建数据服务,并优化测试与部署流程。
引言
在数据操作领域,Go 语言不仅能胜任命令行工具开发,更能高效操作数据库,适用于云原生应用的后端服务。本章将以 Go-playing 微服务为例,介绍如何将内存存储库升级为基于 MongoDB 的持久化存储,并实现测试驱动开发和自动化集成测试。
构建 MongoDB 存储库
本节介绍如何将服务从内存存储升级为 MongoDB 持久化存储,实现真正的无状态服务。
为什么选择 MongoDB
MongoDB 是一种文档型数据库,支持灵活的 JSON 文档存储,适合云原生场景。无需本地安装,可通过 Docker 镜像快速集成。详细文档见 MongoDB 官网 。
在第 5 章中,服务采用内存存储 match 列表,存在数据丢失和扩展性问题。升级为 MongoDB 后,可实现数据持久化和多实例一致性。
更新存储库模型
原有的 matchRepository 接口如下:
type matchRepository interface {
addMatch(match gogo.Match) (err error)
getMatches() []gogo.Match
getMatch(id string) (match gogo.Match, err error)
}
内存存储库实现简单,但缺乏 update 方法,难以支持无状态和持久化。升级为 MongoDB 实现后,需补充接口和测试。
Go 操作 MongoDB
推荐使用官方支持的 mgo 驱动,文档见 mgo godoc 。通过 Dial 创建 session:
session, err := mgo.Dial(url)
查询示例:
result := Person{}
err = c.Find(bson.M{"name":"Buckshank"}).Select(bson.M{"phone": 0}).One(&result)
if err != nil {
panic(err)
}
为简化云环境下的连接管理,可使用 cfmgo 包( cfmgo 源码 ),支持 Cloud Foundry 服务绑定和连接恢复。
测试优先开发 MongoDB 存储库
单元测试应覆盖以下场景:
- 添加 match 后能正确查询
- 能检索指定 match
- 查询不存在的 match 返回错误
测试代码示例:
// ...existing code...
func TestAddMatchShowsUpInMongoRepository(t *testing.T) {
// ...existing code...
err := repo.addMatch(match)
// ...断言添加和查询...
}
func TestGetMatchRetrievesProperMatchFromMongo(t *testing.T) {
// ...existing code...
foundMatch, err := repo.getMatch(targetID)
// ...断言 match 属性...
}
func TestGetNonExistentMatchReturnsError(t *testing.T) {
// ...existing code...
_, err := repo.getMatch("bad_id")
// ...断言错误信息...
}
通过伪造连接器和集合,隔离底层数据库逻辑,专注于接口行为测试。
集成测试 MongoDB 持久化服务
集成测试需在真实数据库环境下验证服务端到端功能。推荐使用 Wercker + Docker 自动化集成测试,避免本地安装数据库。
集成临时 MongoDB 数据库
在 wercker.yml 中声明 MongoDB 服务:
services:
- mongo
Wercker 自动创建环境变量,应用可通过这些变量连接数据库。集成测试脚本示例:
- script:
name: integration tests
code: |
export VCAP_SERVICES=vcapinate -path=./integrations/vcap.yml
export VCAP_APPLICATION={}
godep go test ./integrations/_test -v -race
vcapinate 工具将 Wercker 环境变量转换为 Cloud Foundry 格式,便于服务绑定和配置。vcap.yml 示例:
userprovided:
- name: mongodb
credentials:
url: mongodb://{{.MONGO_PORT27017TCP_ADDR}}:{{.MONGO_PORT27017TCP_PORT}}/some-guid-string
服务启动时自动检测 VCAP_SERVICES 环境变量,优先连接 MongoDB,否则回退为内存存储库。初始化代码示例:
func initRepository() (repo matchRepository) {
appEnv, _ := cfenv.Current()
dbServiceURI, err := cftools.GetVCAPServiceProperty(dbServiceName, "url", appEnv)
if err != nil || dbServiceURI == "" {
repo = newInMemoryRepository()
return
}
matchCollection := cfmgo.Connect(cfmgo.NewCollectionDialer, dbServiceURI, MatchesCollectionName)
repo = newMongoMatchRepository(matchCollection)
return
}
编写集成测试
集成测试覆盖服务的主要 RESTful 方法,包括创建、查询、更新 match 及 move。测试流程示例:
- 启动空数据库,GET /matches 返回空数组
- POST /matches 添加新 match,断言 201 状态码和 JSON 响应
- GET /matches 查询列表,断言 match 数量
- GET /matches/{id} 查询详情,断言属性
- POST /matches/{id}/moves 添加 move,断言更新结果
- 负面测试:错误输入、重复请求等
集成测试代码片段:
func TestIntegration(t *testing.T) {
emptyMatches, err := getMatchList(t)
// ...断言空数组...
matchResponse, err := addMatch(t, firstMatchBody)
// ...断言创建结果...
matches, err := getMatchList(t)
// ...断言 match 数量...
// ...后续流程...
}
Wercker 构建输出示例:
$ ./buildlocal
--> Executing pipeline
...
--> Running step: integration tests
Connecting to MongoDB service: mongodb...
=== RUN TestIntegration
[negroni] Started GET /matches
[negroni] Completed 200 OK in 1.655502ms
Queried Match List OK
...
--- PASS: TestIntegration (0.03s)
PASS
ok github.com/cloudnativego/gogo-service/integrations/_test 1.045s
测试通过后,可高度信任服务的持久化和数据一致性。
云端部署与运行
完成本地和集成测试后,推荐将服务部署到云平台(如 Pivotal Web Services 或 PCF Dev),实现真实环境下的验证。
后端服务配置与部署
在 PWS 中,可通过 marketplace 添加 MongoDB 服务,并在 manifest.yml 中声明依赖:
applications:
- path: .
memory: 512MB
instances: 1
name: gogo-service
disk_quota: 1024M
command: gogo-service
buildpack: https://github.com/cloudfoundry/go-buildpack.git
services:
- mongodb
推送命令:
cf push
如服务名已被占用,需更改应用名称。MongoDB 服务自动绑定,连接信息通过 url 属性传递。
部署后可通过 REST 工具(如 Postman)测试服务功能,数据持久化于 MongoDB 实例。可通过 MongoLab dashboard 或本地管理工具查看数据库详情。
总结
本章系统介绍了如何用 Go 语言和 MongoDB 构建高效的数据服务,包括存储库设计、测试驱动开发、自动化集成测试和云端部署。通过实践这些模式,能够实现高可靠性和可扩展性的云原生应用。建议读者结合实际项目,深入理解数据服务的设计与测试方法,为后续复杂系统开发打下坚实基础。
参考文献
- MongoDB 官网 - mongodb.org
- mgo Go 驱动文档 - godoc.org
- cfmgo 包 - github.com
- Cloud Foundry 环境变量文档 - docs.run.pivotal.io
- Wercker 服务文档 - devcenter.wercker.com
- MongoLab dashboard - mongolab.com