在单机系统中 (例如一个 MySQL 实例), unique ID 的生成是非常简单的, 直接利用 MySQL 自带的自增 ID 功能就可以实现.
但在一个存在多个 Shards 的分布式系统 (例如多个 MySQL 实例组成一个集群, 在这个集群中插入数据), 这个问题会变得复杂, 所生成的全局的 unique ID 要满足以下需求:
1、保证生成的 ID 全局唯一
2、今后数据在多个 Shards 之间迁移不会受到 ID 生成方式的限制
3、生成的 ID 中最好能带上时间信息, 例如 ID 的前 k 位是 Timestamp, 这样能够直接通过对 ID 的前 k 位的排序来对数据按时间排序
4、生成的 ID 最好不大于 64 bits
5、生成 ID 的速度有要求. 例如, 在一个高吞吐量的场景中, 需要每秒生成几万个 ID (Twitter 最新的峰值到达了 143,199 Tweets/s, 也就是 10万+/秒)
6、整个服务最好没有单点
如果没有上面这些限制, 问题会相对简单, 例如:
1、直接利用 UUID.randomUUID() 接口来生成 unique ID (http://www.ietf.org/rfc/rfc4122.txt). 但这个方案生成的 ID 有 128 bits, 另外, 生成的 ID 中也没有带 Timestamp
2、利用一个中心服务器来统一生成 unique ID. 但这种方案可能存在单点问题; 另外, 要支持高吞吐率的系统, 这个方案还要做很多改进工作 (例如, 每次从中心服务器批量获取一批 IDs, 提升 ID 产生的吞吐率)
3、Flickr 的做法 (http://code.flickr.net/2010/02/08/ticket-servers-distributed-unique-primary-keys-on-the-cheap/). 但他这个方案 ID 中没有带 Timestamp, 生成的 ID 不能按时间排序
实际上,关于「如何抓取汽车之家的车型库」,我已经在「使用 Mitmproxy 分析接口」一文中给出了方法,不过那篇文章里讲的是利用 API 接口来抓取数据,一般来说,因为接口不会频繁改动,相对 WEB 页面而言更稳定,所以通常这是数据抓取的最佳选择,不过利用 API 接口来抓取数据有一些缺点,比如有的数据没有 API 接口,亦可能虽然有 API 接口,但是数据使用了加密格式,此时只能通过 WEB 页面来抓取数据。
既然要通过 WEB 页面来抓取数据,那么就不得不提到 Scrapy,它可以说是爬虫之王,我曾经听说有人用 Scrapy,以有限的硬件资源在几天的时间里把淘宝商品数据从头到尾撸了一遍,如此看来,本文用 Scrapy 来抓取汽车之家的车型库应该是绰绰有余的了。
在抓取汽车之家的车型库之前,我们应该对其结构有一个大致的了解,按照百科中的描述,其大致分为四个级别,分别是品牌、厂商、车系、车型。本文主要关注车系和车型两个级别的数据。在抓取前我们要确定从哪个页面开始抓取,比较好的选择有两个,分别是产品库和品牌找车,选择哪个都可以,本文选择的是品牌找车,不过因为品牌找车页面使用了 js 来按字母来加载数据,所以直接使用它的话可能会有点不必要的麻烦,好在我们可以直接使用从 A 到 Z 的字母页面。