就在最近,我有机会在一个工具上工作,负责通过电线处理数千兆字节的数据,最终的目标是下载这些数据,处理这些数值,最后分批将它们插入持久性存储中。
大图片
简而言之,这个解决方案将由3个进程组成。
- 数据生产者过程:读取输入数据,并将其发送到一个目的地进行进一步处理。
- 数据消费者过程:接收原始数据,使用预期的格式解析这些值,并将其发送到不同的过程。
- 持久性存储过程:接收解析后的数据并分批存储。
这是用管道解决的经典问题。那个经典的帖子和这个新的系列最大的区别是,当与多个goroutines一起工作时,如何取消到位。这意味着定义有关任何失败时的预期行为的规则,所有这些都是使用两个伟大的Go包处理的。 context和 errgroup.
对于我们的例子,我们将使用IMDB的数据集的一部分文件。这些文件是以UTF-8字符集格式的gzipped、tab分隔的数值(TSV)。要使用的具体文件将是 name.basics.tsv.gz它定义了以下字段。
|-------------------|-----------|---------------------------------------------------|
| Field | Data Type | Description |
|-------------------|-----------|---------------------------------------------------|
| nconst | string | alphanumeric unique identifier of the name/person |
| primaryName | string | name by which the person is most often credited |
| birthYear | string | in YYYY format |
| deathYear | string | in YYYY format if applicable, else '\N' |
| primaryProfession | []string | the top-3 professions of the person |
| knownForTitles | []string | titles the person is known for |
|-------------------|-----------|---------------------------------------------------|
数据生产者过程。输入数据格式
由于这个输入文件的位置(http资源)和文件数据格式(gzip),我们的数据生产者进程将使用以下方式请求该文件 net/http请求文件,用 compress/gzip并将它们作为原始[]byte 发送给数据消费者进程。
数据消费者过程。输入数据格式
这些原始[]byte 值将被读成TSV记录,使用 encoding/csv并从那里将它们转换为新的结构类型Name ,以便我们管道的下一步能够理解。
持久性存储过程。输入数据格式
以下将被用作包含最终被持久化在数据库中的值的类型。
type Name struct {
NConst string
PrimaryName string
BirthYear string
DeathYear string
PrimaryProfessions []string
KnownForTitles []string
}
我们将使用PostgreSQL作为关系型数据库,特别是 github.com/jackc/pgx将被导入用于分批存储这些值。
下一步是什么?
下一篇博文将介绍PostgreSQL Batcher的实现,随着我们在这个系列中的进展,我们将不断地把所有的部分连接在一起,最终完成我们的最终工具。