第 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 构建高效的数据服务,包括存储库设计、测试驱动开发、自动化集成测试和云端部署。通过实践这些模式,能够实现高可靠性和可扩展性的云原生应用。建议读者结合实际项目,深入理解数据服务的设计与测试方法,为后续复杂系统开发打下坚实基础。

参考文献

文章导航

独立页面

这是书籍中的独立页面。

书籍首页

评论区