Memcachedb 探讨


MemcachedbMemcachedb 探讨探讨 V1.0 大众点评网平台架构部 (2011/04/10) Danson.Liu 版权声明 版权所有 © 2011 上海市大众点评网(www.dianping.com) Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation. 目录 第 1 章前言 ................................................................................................................................................................... 1 第 1.1 节 Memcachedb 简介 ................................................................................................................................... 1 第 1.2 节分类及同类产品 ...................................................................................................................................... 1 第 2 章海量数据读写方案的历史 ............................................................................................................................... 2 第 2.1 节主从分离 .................................................................................................................................................. 2 第 2.2 节分库分表 .................................................................................................................................................. 2 第 2.3 节 Key-Value Store ....................................................................................................................................... 2 第 3 章 NoSQL 的理论基础 ......................................................................................................................................... 3 第 3.1 节概述 ........................................................................................................................................................... 3 第 3.2 节 CAP .......................................................................................................................................................... 3 第 3.3 节最终一致性 .............................................................................................................................................. 4 第 3.4 节 BASE ........................................................................................................................................................ 4 第 4 章 Key-Value Store ................................................................................................................................................ 5 第 4.1 节什么是 Key-Value Store ........................................................................................................................... 5 第 4.2 节特点 ........................................................................................................................................................... 5 第 4.3 节 Distributed KV Store ............................................................................................................................... 5 第 4.4 节如何使用 .................................................................................................................................................. 5 第 5 章 Memcachedb ..................................................................................................................................................... 6 第 5.1 节与 memcached 的比较 .............................................................................................................................. 6 第 5.2 节与 RDBMS 的比较 ................................................................................................................................... 6 第 5.3 节特性 ........................................................................................................................................................... 6 第 5.4 节支持的 Command ..................................................................................................................................... 6 第 5.5 节性能测试 .................................................................................................................................................. 7 第 5.6 节 Install ........................................................................................................................................................ 7 第 5.7 节 Start and Stop ........................................................................................................................................... 8 第 5.8 节 Commands Using Telnet .......................................................................................................................... 8 第 5.9 节总体结构图 .............................................................................................................................................. 9 第 5.10 节关于 BerkeleyDB .................................................................................................................................. 10 第 6 章 How can we use it ........................................................................................................................................... 11 第 6.1 节我们的应用场景 ..................................................................................................................................... 11 第 6.2 节需要实现的目标 ..................................................................................................................................... 11 第 6.3 节设计方案 ................................................................................................................................................. 11 第 6.4 “节容错: Slave crash” “与 Slave ”连接中断 ............................................................................................ 11 第 6.5 节容错: Master crash ................................................................................................................................ 11 第 6.6 节容错:往 Master 的连接中断 ............................................................................................................... 12 第 6.7 节容错: Master 因磁盘满或其他原因无法写入 ................................................................................... 12 第 6.8 节错误告警 ................................................................................................................................................ 12 第 6.9 节方案改进 ................................................................................................................................................ 12 第 6.10 节如何运维 .............................................................................................................................................. 12 第 7 章 What about Cassandra .................................................................................................................................... 14 第 7.1 节简介 ......................................................................................................................................................... 14 第 7.2 节架构 ......................................................................................................................................................... 14 i 第 1 章 前言 第1章 前言 第1.1节 Memcachedb 简介 Memcachedb 是一个由新浪网的开发人员开放出来的开源项目,在分布式缓存 Memcached 基础上添 加了 Berkeley DB 的持久化存储机制和异步主辅复制机制,具备事务恢复能力、持久化和分布式复制能力, 适合需要超高性能读写速度,但不需要严格事务约束,能够被持久化保存的应用场景,其遵循 Memcache 的优秀协议,任何实现了该协议的客户端都能够与之交互。 第1.2节 分类及同类产品 Memcachedb 属于 key value store 产品,同类或相似产品包括 Cassandra, CouchDB, Amazon SimpleDB, Amazon Dynamo, beansdb(豆瓣), Tokyo Cabinet, MongoDB, Nuclear, dbcached, PNUTS(Yahoo), Voldemort 等 Memcachedb 相比较所具有的优点:高效的并发读能力,支持事务,数据可用性高,支持备份,兼容 Memcached 协议。 相关网址: http://memcachedb.org/ http://code.google.com/p/memcachedb/ Manual: http://memcachedb.org/memcachedb-guide-1.0.pdf 作者: Steve Chu 1 第 2 章 海量数据读写方案的历史 第2章 海量数据读写方案的历史 第2.1节 主从分离 这是最初也是最常见的方案,随着用户访问量的增加,单库已经无法满足访问性能的要求,数据库 查询压力过大,对于大型互联网来说,读写的比例一般在 10:1,于是便产生了数据库主从读写分离的方 案,在主库中进行写操作,由主库将更新的数据同步到从库中,一般性的读操作被负载均衡地分配到多 个从库中,对于写操作即时反映性较高的读操作也被分配到主库中。这样就将数据库访问压力分摊到了 多个库中。 问题:当用户数、业务数据激增,必然会出现单表海量记录,此时导致此类库表查询效率急剧下降, 从而影响正常的客户体验,于是便进入了分库分表时代。 第2.2节 分库分表 一旦系统中出现某些海量数据的表时,对这些表的查询效率便会成为系统的瓶颈,于是就有人提出 了分库分表的方案。利用选定的业务字段将表划分了几个切片,每个切片单独成表,如果这些表够多, 也可以将其放置于不同的库中,通常是将这些选定的字段值联合起来哈希取模后分派到不同的数据库。 这样就解决了单表海量数据的问题。 问题:分库分表单纯从架构上来实现难度太大,目前也没有一个成熟完善的 DAL 解决方案出现,基 本都需要一定程度上的侵入业务系统,而且会给架构及业务系统工程师带来相当大的负担,消耗相当多 的精力在数据切分工作上,每个需要切分的项目皆是如此,甚至包括对切分不理想的数据进行从新切分 的风险和负担。 备注:有相关 Sharding 框架方面的一些尝试,如 HiveDB, Amoeba, 以及一些数据库厂商自行提供的 产品,如 Mysql Proxy,但实际运用中都不近如人意。 第2.3节 Key-Value Store 那么究竟该往何处去呢,伟大的 IT 精英们,在无数个废寝忘食的通宵奋战后,终于为我们提出了新 的解决方案---Nosql(向这些宅男宅女们致敬)。 我们需要什么:海量数据的分布式存储,读写高性能,高可靠,可维护性等等 如此种种,那么究竟什么是 Key-Value Store 呢,别着急,让我们先从纯理论出发。 2 第 3 章 NoSQL 的理论基础 第3章 NoSQL 的理论基础 第3.1节 概述 “CAP, BASE 和最终一致性是 NoSQL 数据库存在的理论基础。 第3.2节 CAP 分布式领域 CAP 理论: Consistency(一致性),Availability(可用性),Partition tolerance(分区容忍性---分布式) Consistency:任何一个读操作总能读取到之前完成的写操作结果; Availability ””:每一个操作总能够在 确定的 时间内返回; Partition tolerance:在出现网络分区(如断网)时,分离的系统依然能够独立运行,提供服务; CAP 理论由 Eric Brewer 教授于 2000 年提出,该理论指出:一个分布式系统不可能同时满足一致性, 可用性和分区容错性这三个需求,最多只能同时满足两个。2002 年 MIT 的 Seth Gilbert 和 Nancy lynch 两 人证明了该理论的正确性。应该视该理论为一个经验理论,实际的指导意义为:架构师不要浪费精力追 求设计出同时满足三者的完美分布式解决方案,而应该有所取舍。 鱼和熊掌不可兼得。关注的是一致性,那么分布式系统中的某个点不可用时,写操作便会失败;关 注可用性时,那么您应该能够考虑到系统读操作可能不能精确地读到写操作的最新值,如 master crash 了, 为了可用性,将写操作引向另外的点,但系统中其他点并未与该点同步,就会导致一致性的缺失。 对于分布式存储系统来说,分区容错性(P)是必然要求,所以只剩下 CP 和 AP 两种选择,而对于大型 网站来说,可用性和分区容错性的优先级是要高于数据一致性的,所以一般会尽量朝着 AP 的方向进行设 3 Consistency Availability Partition Tolerance 第 3 章 NoSQL 的理论基础 计,然后通过其他手段保证对于一致性的业务需求。具体的场景对一致性的要求也有所不同,如客户评 论的一致性并非那么重要,而商品价格对一致性的要求则显然苛刻。对于我们来说,大型网站的一致性 “”可以通过 最终一致性 原则来加以弥补。 第3.3节 最终一致性 ””通俗的讲,就是 过程松,结果紧,最终结果必须保证一致性 。 我们来描述一下不同程度的一致性: • 强一致性:最新写入的数据,必须被后续的读取操作精确获取。 • 弱一致性:最新写入的数据,不能保证后续的读取操作能够精确获取,或许中间有一段时间的延 迟。 • 最终一致性:是弱一致性的一种特例,最终保证数据的一致性,造成不一致的可能性包括:交互 延迟,系统负载以及集群中复制点的个数。 具体表现: 因果一致性:如果 A 通知 B 数据已变更,那么 B 的后续读取操作应读取 A 写入的最新值,而与 A 没 有因果关系的 C 则可以最终一致性即可。 自身一致性:如果 A 写入了最新值,那么 A 的后续操作都应该读取到最新值,其他访问者可能要过 一段时间才能读取到最新值。 “”会话一致性:要求客户端与存储系统交互的整个会话阶段保证 自身一致性 ,如 Hibernate 的 session 提供的一致性就属于此类。 单向一致性:如果 A 已经读取了数据的某个阶段值,那么后续的操作将不会读取到更早的值。 第3.4节 BASE BASE 的英文意义是碱,而 ACID 是酸,理念正好相反。 • Basically Available:基本可用 • Soft-state:柔性事务 • Eventual consistency:最终一致性 ACID 强调一致性,BASE 则强调牺牲高一致性,以获取可用性或可靠性。状态可以有一段时间的不 同步,保证数据最终是一致的即可。 BASE 思想主要强调基本的可用性,如果您需要纯粹的高性能,那么就要以一致性或容错性为牺牲, BASE 思想的方案在性能上有潜力可挖。 4 第 4 章 Key-Value Store 第4章 Key-Value Store 第4.1节 什么是 Key-Value Store Key-Value Store 是一个存在很久的数据库模式,它是一种非结构性的数据存储介质,允许应用程序 存储它们的数据,数据通常是以原生的方式进行存储,没有规定的数据模型。 第4.2节 特点 功能简单,高并发读写性能高 第4.3节 Distributed KV Store 将 KV Store 分布到多个 Server 上,提供数据异步复制功能,提高数据服务的可用性和读写性能,并 且拓展了数据存储的容量。 第4.4节 如何使用 那么 Key-Value Store 方案是万能的吗,并非如此,应该充分利用关系型数据库的关系模型和 Key- Value Store 的海量数据高性能读写的优势,找出折中的最佳解决方案。 5 第 5 章 Memcachedb 第5章 Memcachedb 让我们回来从新看看 Memcachedb 能够为我们提供什么。 第5.1节 与 memcached 的比较 • 并非一种缓存解决方案,而 Memcached 则是一种缓存解决方案。 • 数据不会过期,为了遵循 memcached 协议,所以过期参数仍然保留,但无任何效果。 • 是一个完全的数据持久化方案,包含事务,数据复制等。 第5.2节 与 RDBMS 的比较 • 处理海量数据时 RDBMS 太慢,他在存储介质的上层构建了一个复杂的 SQL 引擎,我们的数据存 取操作都相对较慢。 • RDBMS 高并发操作表现不佳,当我们有数以千计的客户端,亿计的请求时,难以应付。 • 当我们需要持久化的数据很小时,使用 RDBMS 成本太高。 很多重要的基础服务需要快速、可靠的数据存储与获取,但对于灵活的 SQL 查询语法又并非必须。 比如:索引,计数,消息,评论等数据 第5.3节 特性 • 对于 key-value 数据的高性能读写 • 基于事务的高可靠性持久化存储 • 基于数据存储复写的的高可用性:实现高可用性,并提高你的数据读取能力。 • 兼容 Memcached 协议 第5.4节 支持的 Command • 'get' Retrieve of one or multiple items • 'set' Store this data • 'add' Store this data, but only if the server doesn't already hold data for this key • 'replace' Store this data, but only if the server does already hold data for this key • 'delete' Delete one item based a key • 'incr/decr' Increment or decrement a numeric value, It's atomic! • 'stats' Shows the status of current deamon. 'stats', 'stats malloc', 'stats maps' Private Command(部分支持了) • 'db_checkpoint’ Does a checkpoint manuanlly. • 'db_archive’ Removes log les that are no longer needed.fi • 'stats_bdb’ Shows the status of BerkeleyDB. • 'rep_ismaster’ Shows whether the site is a master. • 'rep_whoismaster’ Shows which site is a master. • 'rep_set_priority’ Sets the priority of a site for electing in replication. • 'rep_set_ack policy’ Sets ACK policy of the replication. • 'rep_set_ack timeout’ Sets ACK timeout value of the replication. • 'rep_set_bulk’ Enable bulk transfer or not in replication. 6 第 5 章 Memcachedb • 'rep_set_request’ Sets the minimum and maximum number of missing log records that a client waits before requesting retransmission. • 'stats rep' Shows the status of Replication • 'stats repms' Show the master status of Replication 第5.5节 性能测试 摘自官方文档,自行测试的结果相差不多。 第5.6节 Install Download libevent-2.0.4.tar.gz, db-5.1.25.tar.gz, memcachedb-1.2.0.tar.gz 安装 libevent tar zxvf libevent-2.0.4.tar.gz cd libevent-2.0.4 ./configure make && make install 安装 berkeley db tar zxvf db-5.1.25.tar.gz cd db-5.1.25 ./configure --prefix=/usr/local/berkeley make && make install vi /etc/ld.so.conf add a new line “/usr/local/berkeley/lib” ldconfig 安装 memcachedb tar zxvf memcachedb-1.2.0.tar.gz cd memcachedb-1.2.0 ./configure –prefix=/usr/local/memcachedb --enable-threads --with-bdb=/usr/local/berkeley 7 第 5 章 Memcachedb make && make install 第5.7节 Start and Stop Start example: ./memcachedb -p20201 -d -r -u root -f 21201.db -H /data1/demo -N -P /data1/logs/21201.pid Stop example: kill -9 `cat /data1/logs/21201.pid` 第5.8节 Commands Using Telnet root@schm telnet127.0.0.121201 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is ’^]’. set test 0 0 4 1111 STORED get test VALUE test 0 4 1111 END delete test DELETED stats STAT pid 25767 STAT uptime 9732 STAT time 1302516561 STAT version 1.2.0 STAT pointer_size 64 STAT cmd_set 2 STAT get_hits 1189950 ... STAT bytes_written 44141115 STAT threads 4 END stats repms //查看当前 master/slave 的状态 STAT site-00 127.0.0.1:31201/CLIENT/-- STAT site-01 127.0.0.1:31205/MASTER/CONNECTED STAT site-02 127.0.0.1:31204/CLIENT/CONNECTED END 8 第 5 章 Memcachedb 第5.9节 总体结构图 Nonthread Version Thread Version 9 第 5 章 Memcachedb The Backend: BerkeleyDB Memcachedb 后端是以 BerkeleyDB 作为存储介质的。 第5.10节 关于 BerkeleyDB BerkeleyDB 是一个具有悠久历史的工业级别嵌入式数据库系统,存取数据的效率极高,稳定性久经 考验。它的设计思想是简单、小巧、可靠、高性能。它提供加锁、事务日志、共享缓存区管理、内存管 理等底层服务。 它的优点包括: Portable:可以运行于几乎所有的 UNIX 和 Linux 系统、Windows 系统及多种嵌入式操作系统。 Scalable:自身的 library 很精练,仅仅占用几百 k 的空间,但却能管理高达几百 TB 的数据。支持高 并发访问,成千上万的用户可同时操作数据库。它即可以占据足够小的空间运行于嵌入式 系统,也可在大型互联网应用中耗用 GB 的内存和 TB 容量的磁盘空间。 BerkeleyDB 系统由五个主要的子系统构成,包含:存取管理子系统,内存池管理子系统,事务子系 统,锁子系统以及日志子系统。这里让我们来简单的了解一下锁子系统和日志子系统。 锁子系统为 BerkeleyDB 提供锁机制,为系统提供多用户读取和单用户修改同一对象的共享控制。事 务子系统利用锁机制来实现多个事务的并发控制。 日志子系统采用存储数据时先写日志的策略,以便用于支持事务子系统进行数据恢复,保证数据一致 性。 BerkeleyDB 中存储的数据类型:BerkeleyDB“ ”“”数据库 形象的等同于关系数据库中的 表 ,所有数据 等同于表中的记录,所有数据都是以(key, value) “”形式存储,它不提供关系数据库中表的 列 的概念,而是 通过将列封装到 value object 中的 fields 来实现。 一个典型的 BerkeleyDB 存储目录下有如下的文件:data.db, __db.001, __db.002, log.0000000001, log00 00000002...,其中 data.db 为实际的数据存储文件,__db.xxx 为共享的 memory 文件,logxxxx 则为日志文 件。 10 第 6 章 How can we use it 第6章 How can we use it 第6.1节 我们的应用场景 目前点评网的各类评论内容被集中存储在 Memcachedb 中,另外我们可以利用 Memcachedb 的高并发 读写+锁机制+自带的 incr/decr 接口实现高性能的计数器服务。 第6.2节 需要实现的目标 • 高并发时的高性能读写 • 高并发时的高可用性 • 最终一致性 • 高可维护性 第6.3节 设计方案 “”针对 高性能读写 : 部署时采用单 Master 多 Slave 的方式,在 Master 上进行写操作,在 Master 和多 Slave 上进行负载 均衡的读操作,提高数据读取的性能; “”针对 高可用性 ,分为以下几种情形: Master crash, 某 Slave crash, 客户端与 Master 之间连接中断,Master 因磁盘满或其他原因无法写入, 客户端与某 Slave 之间连接中断,由于相对复杂,会在稍后部分独立成节进行讨论。 “”针对 最终一致性 : 我们的使用场景一般都只要求最终一致性,很少需要即时一致性,而且 Memcachedb 正常情况下 也接近于即时一致性。Memcachedb 的主辅复写机制保证了最终一致性。 “”针对 高可维护性 : 受益于底层存储介质 BerkeleyDB 的高可维护性,我们的维护工作也相应简单了许多,这部分会在 后续单独成节进行介绍(“ ”如何运维 章节)。 第6.4节 “容错: Slave crash” “与 Slave ”连接中断 这两类错误对于客户端来说表现是一致的,都是某个 Slave unavailable,幸运的是现有的 Memcached 客户端都已经做了这种容错,一旦某个 Slave 不可用那么其状态会被置为 inactive,并开始尝试重连,为 “”了使 使用端 能够正确获取到数据,需要我们封装一次重试的逻辑,重试时该 inactive slave 便会排除在 外,不再参与集群 hash 算法,直到他重新可用。所以此类问题可以做到容错。 第6.5节 容错:Master crash Memcachedb 的 Master/Slave 架构中,仅 Master 可接受写操作,再由 Master replicate 到 Slaves 上,如 果此时 Master crash,那么默认配置下,剩下的 electable Slaves 会选举其中的一个接替成为新的 Master, 并由该 Master 接受写操作、执行 replication 任务,因为集群中的其他 Slave 点会被通知到该变更,并注册 到新的 Master 点,此时我们的容错策略可以这样设计:写老的 Master 点失败,重试一次(防止瞬间的网络 失败),再次失败,就开始尝试从其他 Slave 点收集当前 Master 节点的信息(扩展客户端实现 Memcachedb “的 stats repms”私有协议),定位到新的 Master 节点后就将其记录在客户端,以后都往该 Node 写数据。如 果从其他 Slaves 点定位到的 Master 依然是老的 Master,那么证明该客户端机器到老 Master 的网路出现问 题,并非 Master crash,那么就到了我们下面需要讨论的情形。 备注:对于 Master 的切换,我们上面是从客户端着手的,也可以从 Memcachedb 服务端着手,指定 11 第 6 章 How can we use it 某一台 electable slave 的优先级最高,使其成为明确的下一个 Master,然后通过 floating-ip 技术进行服务端 的 failover。但对运维有一定要求。 第6.6节 容错:往 Master 的连接中断 客户端到 Master 的连接中断有两种情形,1:Master 自身往外的网络中断,此时就是 Master crash 的 情形,集群中自动有新的 Master 被推举出来,运维在恢复网络后,老的 Master 会自动成为一个 Slave,2 :该客户端到 Master 的网络接口中断,那么基本不用考虑容错了,到其他介质的访问必定也会有问题;3 :该客户端单独到 Master 的网段不通,也不考虑,依据是 CAP 原则,不存在绝对完美的解决方案; 第6.7节 容错: Master 因磁盘满或其他原因无法写入 此时 Memcachedb 集群不会有新的 Master 出现,那么就需要我们自己实现一套备用的 Master 机制, 这类容错是否需要做,有待商榷,但此处给出一个参考方案。 当判断得出并非 Master crash 导致的写 Master 失败,那么需要切换到备用存储介质(初步定为 MySQL ,需要保证后续的可遍历性,因为涉及到数据往 Memcachedb 中的恢复),MySQL 对应有张表 MEMDB_ LOG (ID, CATEGORY, KEY, VALUE, ACTION)(其中 CATEGORY 字段考虑到可以对 Memcachedb 针对不同 应用场景建立多个集群组时使用),在写数据时相应创建一条记录(1, null, key, value, 'set' / 'add' / 'replace'), 删除该 key 时,查找表中是否有该 key 对应记录,有则删除即可,没有则创建一条记录(2, null, key, value, 'delete'), 后台有一个任务系统会在 Master 重新可用时,将数据库中的数据恢复到 Memcachedb 中去。 第6.8节 错误告警 在出现上述错误时,都需要记录警告日志,再由监控系统收集对相关人员进行告警。 第6.9节 方案改进 从长远来看,随着 Memcachedb 中的数据越来越多,对存储介质的容量要求越来越高(Memcachedb 无 法做 Sharding),并且会带来一定程度上的性能损耗和运维难度(一次热备及恢复的时间太长),所以可以考 虑将 Memcachedb 针对不同的应用场景进行一个分类,建立不同的集群组,这样可以做到分流,拆容,单 独维护和变更(单独的集群在无法满足场景需求时可以替换为其他存储方案)。 第6.10节 如何运维 以确定的 Master/Slaves 模式启动多个 Memcachedb 服务,客户端以第一个 node 作为初始的 Master。 若一台 Slave crash 且从新恢复启动的时间间隔较短,则直接从新启动,让其自动与 Master 进行同步。 在从新启动的一段时间内应该禁止外部请求访问,以免读取不到尚未同步过来的数据,等到日志提示 “memp_trickle thread: writing 0 dirty pages”时再对外提供服务。 若 Slave 从新启动的时间间隔较长,则从任意一台 Slave 中制作一个热备份,然后到该 Slave 中进行 热备份 recover,恢复到较近的时间点,然后再重复上一种情形的操作,主要是为了避免长时间的自动同 步操作。 若 master crash,恢复与 Slave 的两种情形类似,但该 master 不可再显示的以-M 启动,否则就会形成 两个独立的 Memcachedb 集群,而应该利用 Memcachedb 的私有协议找出最新的 Master 点,然后以-O “新 master repl address” -S 启动,使其以 Slave 身份加入到原有集群中。至于恢复和上面 Slave 恢复操作相同。 注意部署 Memcachedb 集群时,应尽量多部署几台 Slave,至少 2 台 electable Slave,外加几台非 elec table Slave 效果更佳,如果 electable Slave 太少,那么一旦他们 crash,在没有 electale Slave 的情形下,Ma ster 会启动同步日志写策略,任何一个写操作都会导致 flush txn data to log file,因为在没有 electale Slave 可提供数据恢复的情形下,只有通过本地日志进行保证,此时显然将 txn data 数据保存在内存中异步写文 件是没有保障的,一旦 crash 内存中的 txn data 就丢失了,也就失去了恢复的保障,此时即便你以-N 参数 启动(异步 txn data flush) ”“,也是没有异步效果的,所以切记 至少两个 electable Slave。 12 第 6 章 How can we use it 需要定期对集群中的每台机器的 BerkeleyDB 日志文件进行线下归档,否则日志文件会越来越多,占 据远超过实际 DB 文件的硬盘容量。外加定期进行 BerkeleyDB 的热备份,备份文件异地存储。 13 第 7 章 What about Cassandra 第7章 What about Cassandra 第7.1节 简介 Cassandra 的名称来源于希腊神话,是特洛伊的一位悲剧性的女先知的名字。由就职于 Facebook 的 Avinash Lakshman 和 Pranshant Malik 为 Facebook 的 Inbox 所编写。2008 年项目开源,09 年进入 Apache 基 金会的 Incubator 项目,于 2010 年走出孵化器,成为正式的基金会项目。 第7.2节 架构 TODO 14
还剩17页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 15 金币 [ 分享pdf获得金币 ] 0 人已下载

下载pdf

pdf贡献者

奋~斗~

贡献于2013-03-18

下载需要 15 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf