2

NoSQL数据库笔谈(转载收藏)

Posted by 超级苍蝇 on Apr 3, 2011 in 技术~
NoSQL数据库笔谈
颜开
v0.2
2010.2
  • 思想篇
    1. CAP
    2. 最终一致性
      1. 变体
    3. BASE
    4. 其他
      1. I/O的五分钟法则
      2. 不要删除数据
      3. RAM是硬盘,硬盘是磁带
      4. Amdahl定律和Gustafson定律
      5. 万兆以太网
  • 手段篇
    1. 一致性哈希
        1. 亚马逊的现状
        2. 算法的选择
    2. Quorum NRW
    3. Vector clock
    4. Virtual node
    5. gossip
      1. Gossip (State Transfer Model)
      2. Gossip (Operation Transfer Model)
    6. Merkle tree
    7. Paxos
      1. 背景
    8. DHT
    9. Map Reduce Execution
    10. Handling Deletes
    11. 存储实现
    12. 节点变化
    13. 列存
      1. 描述
      2. 特点
  • 软件篇
    1. 亚数据库
      1. MemCached
        1. 特点
        2. 内存分配
        3. 缓存策略
        4. 缓存数据库查询
        5. 数据冗余与故障预防
        6. Memcached客户端(mc)
        7. 缓存式的Web应用程序架构
        8. 性能测试
      2. dbcached
        1. Memcached 和 dbcached 在功能上一样吗?
    2. 列存系列
      1. Hadoop之Hbase
      2. 耶鲁大学之HadoopDB
      3. GreenPlum
      4. FaceBook之Cassandra
        1. Cassandra特点
        2. Keyspace
        3. Column family(CF)
        4. Key
        5. Column
        6. Super column
        7. Sorting
        8. 存储
        9. API
      5. Google之BigTable
      6. Yahoo之PNUTS
        1. 特点
        2. PNUTS实现
          1. Record-level mastering 记录级别主节点
          2. PNUTS的结构
          3. Tablets寻址与切分
          4. Write调用示意图
        3. PNUTS感悟
      7. 微软之SQL数据服务
    3. 非云服务竞争者
    4. 文档存储
      1. CouchDB
        1. 特性
      2. Riak
      3. MongoDB
      4. Terrastore
      5. ThruDB
    5. Key Value / Tuple 存储
      1. Amazon之SimpleDB
      2. Chordless
      3. Redis
      4. Scalaris
      5. Tokyo cabinet / Tyrant
      6. CT.M
      7. Scalien
      8. Berkley DB
      9. MemcacheDB
      10. Mnesia
      11. LightCloud
      12. HamsterDB
      13. Flare
    6. 最终一致性Key Value存储
      1. Amazon之Dynamo
        1. 功能特色
        2. 架构特色
      2. BeansDB
        1. 简介
        2. 更新
        3. 特性
        4. 性能
      3. Nuclear
        1. 两个设计上的Tips
      4. Voldemort
      5. Dynomite
      6. Kai
    7. 未分类
      1. Skynet
      2. Drizzle
    8. 比较
      1. 可扩展性
      2. 数据和查询模型
      3. 持久化设计
  • 应用篇
    1. eBay 架构经验
    2. 淘宝架构经验
    3. Flickr架构经验
    4. Twitter运维经验
      1. 运维经验
        1. Metrics
        2. 配置管理
        3. Darkmode
        4. 进程管理
        5. 硬件
      2. 代码协同经验
        1. Review制度
        2. 部署管理
        3. 团队沟通
      3. Cache
    5. 云计算架构
    6. 反模式
      1. 单点失败(Single Point of Failure)
      2. 同步调用
      3. 不具备回滚能力
      4. 不记录日志
      5. 无切分的数据库
      6. 无切分的应用
      7. 将伸缩性依赖于第三方厂商
    7. OLAP
      1. OLAP报表产品最大的难点在哪里?
    8. NOSQL们背后的共有原则
      1. 假设失效是必然发生的
      2. 对数据进行分区
      3. 保存同一数据的多个副本
      4. 动态伸缩
      5. 查询支持
      6. 使用 Map/Reduce 处理汇聚
      7. 基于磁盘的和内存中的实现
      8. 仅仅是炒作?
    1. 感谢
    2. 版本志
    3. 引用
  • 日前国内没有一套比较完整的NoSQL数据库资料,有很多先驱整理发表了很多,但不是很系统。不材尝试着将各家的资料整合一下,并书写了一些自己的见解。
    本书写了一些目前的NoSql的一些主要技术,算法和思想。同时列举了大量的现有的数据库实例。读完全篇,相信读者会对NoSQL数据库了解个大概。
    另外我还准备开发一个开源内存数据库galaxydb.本书也是为这个数据库提供一些架构资料。

    思想篇

    CAP,BASE和最终一致性是NoSQL数据库存在的三大基石。而五分钟法则是内存数据存储了理论依据。这个是一切的源头。

    CAP


    • C: Consistency 一致性
    • A: Availability 可用性(指的是快速获取数据)
    • P: Tolerance of network Partition 分区容忍性(分布式)
    10年前,Eric Brewer教授指出了著名的CAP理论,后来Seth Gilbert 和 Nancy lynch两人证明了CAP理论的正确性。CAP理论告诉我们,一个分布式系统不可能满足一致性,可用性和分区容错性这三个需求,最多只能同时满足两个。
    熊掌与鱼不可兼得也。关注的是一致性,那么您就需要处理因为系统不可用而导致的写操作失败的情况,而如果您关注的是可用性,那么您应该知道系统的read操作可能不能精确的读取到write操作写入的最新值。因此系统的关注点不同,相应的采用的策略也是不一样的,只有真正的理解了系统的需求,才有可能利用好CAP理论。

    作为架构师,一般有两个方向来利用CAP理论
    1. key-value存储,如Amaze Dynamo等,可根据CAP三原则灵活选择不同倾向的数据库产品。
    2. 领域模型 + 分布式缓存 + 存储 (Qi4j和NoSql运动),可根据CAP三原则结合自己项目定制灵活的分布式方案,难度高。

    我准备提供第三种方案:实现可以配置CAP的数据库,动态调配CAP。


    • CA:传统关系数据库
    • AP:key-value数据库
    而对大型网站,可用性与分区容忍性优先级要高于数据一致性,一般会尽量朝着 A、P 的方向设计,然后通过其它手段保证对于一致性的商务需求。架构设计师不要精力浪费在如何设计能满足三者的完美分布式系统,而是应该进行取舍。
    不同数据对于一致性的要求是不同的。举例来讲,用户评论对不一致是不敏感的,可以容忍相对较长时间的不一致,这种不一致并不会影响交易和用户体验。而产品价格数据则是非常敏感的,通常不能容忍超过10秒的价格不一致。

    CAP理论的证明:Brewer’s CAP Theorem


    最终一致性

    一言以蔽之:过程松,结果紧,最终结果必须保持一致性
    为了更好的描述客户端一致性,我们通过以下的场景来进行,这个场景中包括三个组成部分:
    • 存储系统
    存储系统可以理解为一个黑盒子,它为我们提供了可用性和持久性的保证。
    • Process A
    ProcessA主要实现从存储系统write和read操作
    • Process B 和ProcessC
    ProcessB和C是独立于A,并且B和C也相互独立的,它们同时也实现对存储系统的write和read操作。

    下面以上面的场景来描述下不同程度的一致性:

    • 强一致性
    强一致性(即时一致性) 假如A先写入了一个值到存储系统,存储系统保证后续A,B,C的读取操作都将返回最新值
    • 弱一致性
    假如A先写入了一个值到存储系统,存储系统不能保证后续A,B,C的读取操作能读取到最新值。此种情况下有一个“不一致性窗口”的概念,它特指从A写入值,到后续操作A,B,C读取到最新值这一段时间。
    • 最终一致性
    最终一致性是弱一致性的一种特例。假如A首先write了一个值到存储系统,存储系统保证如果在A,B,C后续读取之前没有其它写操作更新同样的值的话,最终所有的读取操作都会读取到最A写入的最新值。此种情况下,如果没有失败发生的话,“不一致性窗口”的大小依赖于以下的几个因素:交互延迟,系统的负载,以及复制技术中replica的个数(这个可以理解为master/salve模式中,salve的个数),最终一致性方面最出名的系统可以说是DNS系统,当更新一个域名的IP以后,根据配置策略以及缓存控制策略的不同,最终所有的客户都会看到最新的值。

    变体

    • Causal consistency(因果一致性)
    如果Process A通知Process B它已经更新了数据,那么Process B的后续读取操作则读取A写入的最新值,而与A没有因果关系的C则可以最终一致性。
    • Read-your-writes consistency
    如果Process A写入了最新的值,那么Process A的后续操作都会读取到最新值。但是其它用户可能要过一会才可以看到。
    • Session consistency
    此种一致性要求客户端和存储系统交互的整个会话阶段保证Read-your-writes consistency.Hibernate的session提供的一致性保证就属于此种一致性。
    • Monotonic read consistency
    此种一致性要求如果Process A已经读取了对象的某个值,那么后续操作将不会读取到更早的值。
    • Monotonic write consistency
    此种一致性保证系统会序列化执行一个Process中的所有写操作。

    BASE

    说起来很有趣,BASE的英文意义是碱,而ACID是酸。真的是水火不容啊。

    • Basically Availble –基本可用
    • Soft-state –软状态/柔性事务

    “Soft state” 可以理解为”无连接”的, 而 “Hard state” 是”面向连接”的

    • Eventual Consistency –最终一致性
    最终一致性, 也是是 ACID 的最终目的。

    BASE模型反ACID模型,完全不同ACID模型,牺牲高一致性,获得可用性或可靠性: Basically Available基本可用。支持分区失败(e.g. sharding碎片划分数据库) Soft state软状态 状态可以有一段时间不同步,异步。 Eventually consistent最终一致,最终数据是一致的就可以了,而不是时时一致。

    BASE思想的主要实现有
    1.按功能划分数据库
    2.sharding碎片

    BASE思想主要强调基本的可用性,如果你需要高可用性,也就是纯粹的高性能,那么就要以一致性或容错性为牺牲,BASE思想的方案在性能上还是有潜力可挖的。

    其他

    I/O的五分钟法则

    在 1987 年,Jim Gray 与 Gianfranco Putzolu 发表了这个”五分钟法则”的观点,简而言之,如果一条记录频繁被访问,就应该放到内存里,否则的话就应该待在硬盘上按需要再访问。这个临界点就是五分钟。 看上去像一条经验性的法则,实际上五分钟的评估标准是根据投入成本判断的,根据当时的硬件发展水准,在内存中保持 1KB 的数据成本相当于硬盘中存据 400 秒的开销(接近五分钟)。这个法则在 1997 年左右的时候进行过一次回顾,证实了五分钟法则依然有效(硬盘、内存实际上没有质的飞跃),而这次的回顾则是针对 SSD 这个”新的旧硬件”可能带来的影响。

    随着闪存时代的来临,五分钟法则一分为二:是把 SSD 当成较慢的内存(extended buffer pool )使用还是当成较快的硬盘(extended disk)使用。小内存页在内存和闪存之间的移动对比大内存页在闪存和磁盘之间的移动。在这个法则首次提出的 20 年之后,在闪存时代,5 分钟法则依然有效,只不过适合更大的内存页(适合 64KB 的页,这个页大小的变化恰恰体现了计算机硬件工艺的发展,以及带宽、延时)。

    不要删除数据


    Oren Eini(又名Ayende Rahien)建议开发者尽量避免数据库的软删除操作,读者可能因此认为硬删除是合理的选择。作为对Ayende文章的回应,Udi Dahan强烈建议完全避免数据删除。

    所谓软删除主张在表中增加一个IsDeleted列以保持数据完整。如果某一行设置了IsDeleted标志列,那么这一行就被认为是已删除的。Ayende觉得这种方法“简单、容易理解、容易实现、容易沟通”,但“往往是错的”。问题在于:

    删除一行或一个实体几乎总不是简单的事件。它不仅影响模型中的数据,还会影响模型的外观。所以我们才要有外键去确保不会出现“订单行”没有对应的父“订单”的情况。而这个例子只能算是最简单的情况。……

    当采用软删除的时候,不管我们是否情愿,都很容易出现数据受损,比如谁都不在意的一个小调整,就可能使“客户”的“最新订单”指向一条已经软删除的订单。

    如果开发者接到的要求就是从数据库中删除数据,要是不建议用软删除,那就只能硬删除了。为了保证数据一致性,开发者除了删除直接有关的数据行,还应该级联地删除相关数据。可Udi Dahan提醒读者注意,真实的世界并不是级联的:

    假设市场部决定从商品目录中删除一样商品,那是不是说所有包含了该商品的旧订单都要一并消失?再级联下去,这些订单对应的所有发票是不是也该删除?这么一步步删下去,我们公司的损益报表是不是应该重做了?

    没天理了。

    问题似乎出在对“删除”这词的解读上。Dahan给出了这样的例子:

    我说的“删除”其实是指这产品“停售”了。我们以后不再卖这种产品,清掉库存以后不再进货。以后顾客搜索商品或者翻阅目录的时候不会再看见这种商品,但管仓库的人暂时还得继续管理它们。“删除”是个贪方便的说法。

    他接着举了一些站在用户角度的正确解读:

    订单不是被删除的,是被“取消”的。订单取消得太晚,还会产生花费。

    员工不是被删除的,是被“解雇”的(也可能是退休了)。还有相应的补偿金要处理。

    职位不是被删除的,是被“填补”的(或者招聘申请被撤回)。

    在上面这些例子中,我们的着眼点应该放在用户希望完成的任务上,而非发生在某个
    实体身上的技术动作。几乎在所有的情况下,需要考虑的实体总不止一个。

    为了代替IsDeleted标志,Dahan建议用一个代表相关数据状态的字段:有效、停用、取消、弃置等等。用户可以借助这样一个状态字段回顾过去的数据,作为决策的依据。

    删除数据除了破坏数据一致性,还有其它负面的后果。Dahan建议把所有数据都留在数据库里:“别删除。就是别
    删除。”

    RAM是硬盘,硬盘是磁带

    Jim Gray在过去40年中对技术发展有过巨大的贡献,“内存是新的硬盘,硬盘是新的磁带”是他的名言。“实时”Web应用不断涌现,达到海量规模的系统越来越多,这种后浪推前浪的发展模式对软硬件又有何影响?

    Tim Bray早在网格计算成为热门话题之前,就讨论过以RAM和网络为中心的硬件结构的优势,可以用这种硬件建立比磁盘集群速度更快的RAM集群。

    对于数据的随机访问,内存的速度比硬盘高几个数量级(即使是最高端的磁盘存储系统也只是勉强达到1,000次寻道/秒)。其次, 随着数据中心的网络速度提高,访问内存的成本更进一步降低。通过网络访问另一台机器的内存比访问磁盘成本更低。就在我写下这段话的时候,Sun的 Infiniband产品线中有一款具备9个全互联非阻塞端口交换机,每个端口的速度可以达到30Gbit/sec!Voltaire产品的端口甚至更多;简直不敢想象。(如果你想了解这类超高性能网络的最新进展,请关注Andreas Bechtolsheim在Standford开设的课程。)

    各种操作的时间,以2001年夏季,典型配置的 1GHz 个人计算机为标准:

    执行单一指令 1 纳秒
    从L1 高速缓存取一个字 2 纳秒
    从内存取一个字 10 纳秒
    从磁盘取连续存放的一个字 200 纳秒
    磁盘寻址并取字 8 毫秒
    以太网 2GB/s

    Tim还指出Jim Gray的
    名言中后半句所阐述的真理:“对于随机访问,硬盘慢得不可忍受;但如果你把硬盘当成磁带来用,它吞吐连续数据的速率令人震惊;它天生适合用来给以RAM为主的应用做日志(logging and journaling)。”

    时间闪到几年之后的今天,我们发现硬件的发展趋势在RAM和网络领域势头不减,而在硬盘领域则止步不前。Bill McColl提到用于并行计算的海量内存系统已经出现

    内存是新的硬盘!硬盘速度提高缓慢,内存芯片容量指数上升,in-memory软件架构有望给各类数据密集的应用带来数量级的性能提升。小型机架服务器(1U、2U)很快就会具备T字节、甚至更大量的内存,这将会改变服务器架构中内存和硬盘之间的平衡。硬盘将成为新的磁带,像磁带一样作为顺序存储介质使用(硬盘的顺序访问相当快速),而不再是随机存储介质(非常慢)。这里面有着大量的机会,新产品的性能有望提高10倍、100倍。

    Dare Obsanjo指出如果不把这句真言当回事,会带来什么样的恶劣后果—— 也就是Twitter正面临的麻烦。论及Twitter的内容管理,Obsanjo说,“如果一个设计只是简单地反映了问题描述,你去实现它就会落入磁盘 I/O的地狱。不管你用Ruby on Rails、Cobol on Cogs、C++还是手写汇编都一样,读写负载照样会害死你。”换言之,应该把随机操作推给RAM,只给硬盘留下顺序操作。

    Tom WhiteHadoop Core项目的提交者,也是Hadoop项目管理委员会的成员。他对Gray的真言中“硬盘是新的磁带”部分作了更深入地探讨。White在讨论MapReduce编程模型的时候指出,为何对于Hadloop这类工具来说,硬盘仍然是可行的应用程序数据存储介质:

    本质上,在MapReduce的工作方式中,数据流式地读出和写入硬盘,MapReduce是以硬盘的传输速率不断地对这些数据进行排序和合并。 与之相比,访问关系数据库中的数据,其速率则是硬盘的寻道速率(寻道指移动磁头到盘面上的指定位置读取或写入数据的过程)。为什么要强调这一点?请看看寻道时间和磁盘传输率的发展曲线。寻道时间每年大约提高5%,而数据传输率每年大约提高20%。寻道时间的进步比数据传输率慢——因此采用由数据传输率决定性能的模型是有利的。MapReduce正是如此。

    虽然固态硬盘(SSD)能否改变寻道时间/传输率的对比还有待观察,White文章的跟贴中,很多人都认为SSD会成为RAM/硬盘之争中的平衡因素

    Nati Shalom对内存和硬盘在数据库部署和使用中的角色作了一番有理有据的评述。 Shalom着重指出用数据库集群和分区来解决性能和可伸缩性的局限。他说,“数据库复制和数据库分区都存在相同的基本问题,它们都依赖于文件系统/硬盘 的性能,建立数据库集群也非常复杂”。他提议的方案是转向In-Memory Data Grid(IMDG),用Hibernate二级缓存或者GigaSpaces Spring DAO之类的技术作支撑,将持久化作为服务(Persistence as a Service)提供给应用程序。Shalom解释说,IMDG

    提供在内存中的基于对象的数据库能力,支持核心的数据库功能,诸如高级索引和查询、事务语义和锁。IMDG还从应用程序的代码中抽象出了数据的拓扑。通过这样的方式,数据库不会完全消失,只是挪到了“正确的”位置。

    IMDG相比直接RDBMS访问的优势列举如下:

    • 位于内存中,速度和并发能力都比文件系统优越得多
    • 数据可通过引用访问
    • 直接对内存中的对象执行数据操作
    • 减少数据的争用
    • 并行的聚合查询
    • 进程内(In-process)的局部缓存
    • 免除了对象-关系映射(ORM)

    你是否需要改变对应用和硬件的思维方式,最终取决于你要用它们完成的工作。但似乎公论认为,开发者解决性能和可伸缩性的思路已经到了该变一变的时候。

    Amdahl定律和Gustafson定律

    这里,我们都以S(n)表示n核系统对具体程序的加速比,K表示串行部分计算时间比例。

    Amdahl 定律的加速比:S(n) = 使用1个处理器的串行计算时间 / 使用n个处理器的并行计算时间

    S(n) = 1/(K+(1-K)/n) = n/(1+(n-1)K)

    Gustafson定律的加速比:S(n) = 使用n个处理器的并行计算量 / 使用1个处理器的串行计算量

    S(n) = K+(1-K)n
    有点冷是不是?

    通俗的讲,Amdahl 定律将工作量看作1,有n核也只能分担1-K的工作量;而Gustafson定律则将单核工作量看作1,有n核,就可以增加n(1-K)的工作量。

    这里没有考虑引进分布式带来的开销,比如网络和加锁。成本还是要仔细核算的,不是越分布越好。

    控制算法的复杂性在常数范围之内。

    万兆以太网

    手段篇

    一致性哈希

    要求分布式架构的发展说起。
    第一阶段
    考虑到单服务器不能承载,因此使用了分布式架构,最初的算法为 hash() mod n, hash()通常取用户ID,n为节点数。此方法容易实现且能够满足运营要求。缺点是当单点发生故障时,系统无法自动恢复。

    第二阶段
    为了解决单点故障,使用 hash() mod (n/2), 这样任意一个用户都有2个服务器备选,可由client随机选取。由于不同服务器之间的用户需要彼此交互,所以所有的服务器需要确切的知道用户所在的位置。因此用户位置被保存到memcached中。

    当一台发生故障,client可以自动切换到对应backup,由于切换前另外1台没有用户的session,因此需要client自行重新登录。

    这个阶段的设计存在以下问题
    负载不均衡,尤其是单台发生故障后剩下一台会压力过大。
    不能动态增删节点
    节点发生故障时需要client重新登录

    第三阶段
    打算去掉硬编码的hash() mod n 算法,改用一致性哈希(consistent hashing)分布
    假如采用Dynamo中的strategy 1
    我们把每台server分成v个虚拟节点,再把所有虚拟节点(n*v)随机分配到一致性哈希的圆环上,这样所有的用户从自己圆环上的位置顺时针往下取到第一个vnode就是自己所属节点。当此节点存在故障时,再顺时针取下一个作为替代节点。



    优点:发生单点故障时负载会均衡分散到其他所有节点,程序实现也比较优雅。

    亚马逊的现状

    aw2.0公司的Alan Williamson撰写了一篇报道,主要是关于他在Amazon EC2上的体验的,他抱怨说,Amazon是公司唯一使用的云提供商,看起来它在开始时能够适应得很好,但是有一个临界点

    在开始的日子里Amazon的表现非常棒。实例在几分钟内启动,几乎没有遇到任何问题,即便是他们的小实例(SMALL INSTANCE)也很健壮,足以支持适当使用的MySQL数据库。在20个月内,Amazon云系统一切运转良好,不需要任何的关心和抱怨。……

    然而,在最后的八个月左右,他们“盔甲”内的漏洞开始呈现出来了。第一个弱点前兆是,新加入的Amazon SMALL实例的性能出现了问题。根据我们的监控,在服务器场中新添加的机器,与原先的那些相比性能有所下降。开始我们认为这是自然出现的怪现象,只是碰 巧发生在“吵闹的邻居”(Noisy Neighbors)旁边。根据随机法则,一次快速的停机和重新启动经常就会让我们回到“安静的邻居”旁边,那样我们可以达到目的。

    ……然而,在最后的一两个月中,我们发现,甚至是这些“使用高级CPU的中等实例”也遭受了与小实例相同的命运,其中,新的实例不管处于什么位置,看起来似乎都表现得一样。经过调查,我们还发现了一个新问题,它已经悄悄渗透到到Amazon的世界中,那就是内部网络延迟。

    算法的选择

    不同的哈希算法可以导致数据分布的不同位置,如果十分均匀,那么一次MapReduce就涉及节点较多,但热点均匀,方便管理。反之,热点不均,会大致机器效率发挥不完全。

    Quorum NRW

    • N: 复制的节点数量
    • R: 成功读操作的最小节点数
    • W: 成功写操作的最小节点数

    只需W + R > N,就可以保证强一致性。

    第一个关键参数是 N,这个 N 指的是数据对象将被复制到 N 台主机上,N 在实例级别配置,协调器将负责把数据复制到 N-1 个节点上。N 的典型值设置为 3.

    复 制中的一致性,采用类似于 Quorum 系统的一致性协议实现。这个协议有两个关键值:R 与 W。R 代表一次成功的读取操作中最小参与节点数量,W 代表一次成功的写操作中最小参与节点数量。R + W>N ,则会产生类似 quorum 的效果。该模型中的读(写)延迟由最慢的 R(W)复制决定,为得到比较小的延迟,R 和 W 有的时候的和又设置比 N 小。

    如果N中的1台发生故障,Dynamo立即写入到preference list中下一台,确保永远可写入

    如 果W+R>N,那么分布式系统就会提供强一致性的保证,因为读取数据的节点和被同步写入的节点是有重叠的。在一个RDBMS的复制模型中 (Master/salve),假如N=2,那么W=2,R=1此时是一种强一致性,但是这样造成的问题就是可用性的减低,因为要想写操作成功,必须要等 2个节点都完成以后才可以。

    在分布式系统中,一般都要有容错性,因此一般N都是大于3的,此时根据CAP理论,一致性,可用性和分区容错 性最多只能满足两个,那么我们就需要在一致性和分区容错性之间做一平衡,如果要高的一致性,那么就配置N=W,R=1,这个时候可用性就会大大降低。如果 想要高的可用性,那么此时就需要放松一致性的要求,此时可以配置W=1,这样使得写操作延迟最低,同时通过异步的机制更新剩余的N-W个节点。

    当存储系统保证最终一致性时,存储系统的配置一般是W+R<=N,此时读取和写入操作是不重叠的,不一致性的窗口就依赖于存储系统的异步实现方式,不一致性的窗口大小也就等于从更新开始到所有的节点都异步更新完成之间的时间。

    (N,R,W) 的值典型设置为 (3, 2 ,2),兼顾性能与可用性。R 和 W 直接影响性能、扩展性、一致性,如果 W 设置 为 1,则一个实例中只要有一个节点可用,也不会影响写操作,如果 R 设置为 1 ,只要有一个节点可用,也不会影响读请求,R 和 W 值过小则影响一致性,过大也不好,这两个值要平衡。对于这套系统的典型的 SLA 要求 99.9% 的读写操作在 300ms 内完成。

    无 论是Read-your-writes-consistency,Session consistency,Monotonic read consistency,它们都通过黏贴(stickiness)客户端到执行分布式请求的服务器端来实现的,这种方式简单是简单,但是它使得负载均衡以 及分区容错变的更加难于管理,有时候也可以通过客户端来实现Read-your-writes-consistency和Monotonic read consistency,此时需要对写的操作的数据加版本号,这样客户端就可以遗弃版本号小于最近看到的版本号的数据。

    在系统开发过程 中,根据CAP理论,可用性和一致性在一个大型分区容错的系统中只能满足一个,因此为了高可用性,我们必须放低一致性的要求,但是不同的系统保证的一致性 还是有差别的,这就要求开发者要清楚自己用的系统提供什么样子的最终一致性的保证,一个非常流行的例子就是web应用系统,在大多数的web应用系统中都 有“用户可感知一致性”的概念,这也就是说最终一致性中的“一致性窗口”大小要小于用户下一次的请求,在下次读取操作来之前,数据可以在存储的各个节点之 间复制。还比如假如存储系统提供了

    read-your-write-consistency一致性,那么当一个用户写操作完成以后可以立马看到自己的更 新,但是其它的用户要过一会才可以看到更新。

    几种特殊情况:
    W = 1, R = N,对写操作要求高性能高可用。
    R = 1, W = N , 对读操作要求高性能高可用,比如类似cache之类业务。
    W = Q, R = Q where Q = N / 2 + 1 一般应用适用,读写性能之间取得平衡。如N=3,W=2,R=2

    Vector clock


    vector clock算法。可以把这个vector clock想象成每个节点都记录自己的版本信息,而一个数据,包含所有这些版本信息。来看一个例子:假设一个写请求,第一次被节点A处理了。节点A会增加一个版本信息(A,1)。我们把这个时候的数据记做D1(A,1)。 然后另外一个对同样key(这一段讨论都是针对同样的key的)的请求还是被A处理了于是有D2(A,2)。

    这个时候,D2是可以覆盖D1的,不会有冲突产生。现在我们假设D2传播到了所有节点(B和C),B和C收到的数据不是从客户产生的,而是别人复制给他们的,所以他们不产生新的版本信息,所以现在B和C都持有数据D2(A,2)。好,继续,又一个请求,被B处理了,生成数据D3(A,2;B,1),因为这是一个新版本的数据,被B处理,所以要增加B的版本信息。

    假设D3没有传播到C的时候又一个请求被C处理记做D4(A,2;C,1)。假设在这些版本没有传播开来以前,有一个读取操作,我们要记得,我们的W=1 那么R=N=3,所以R会从所有三个节点上读,在这个例子中将读到三个版本。A上的D2(A,2);B上的D3(A,2;B,1);C上的D4(A,2;C,1)这个时候可以判断出,D2已经是旧版本,可以舍弃,但是D3和D4都是新版本,需要应用自己去合并。

    如果需要高可写性,就要处理这种合并问题。好假设应用完成了冲入解决,这里就是合并D3和D4版本,然后重新做了写入,假设是B处理这个请求,于是有D5(A,2;B,2;C,1);这个版本将可以覆盖掉D1-D4那四个版本。这个例子只举了一个客户的请求在被不同节点处理时候的情况, 而且每次写更新都是可接受的,大家可以自己更深入的演算一下几个并发客户的情况,以及用一个旧版本做更新的情况。

    上面问题看似好像可以通过在三个节点里选择一个主节点来解决,所有的读取和写入都从主节点来进行。但是这样就违背了W=1这个约定,实际上还是退化到W=N的情况了。所以如果系统不需要很大的弹性,W=N为所有应用都接受,那么系统的设计上可以得到很大的简化。Dynamo 为了给出充分的弹性而被设计成完全的对等集群(peer to peer),网络中的任何一个节点都不是特殊的。

    Virtual node


    虚拟节点,未完成

    gossip

    Gossip协议是一个Gossip思想的P2P实现。现代的分布式系统经常使用这个协议,他往往是唯一的手段。因为底层的结构非常复杂,而且Gossip也很有效。

    Gossip协议也被戏称为病毒式传播,因为他的行为生物界的病毒很相似。

    Gossip (State Transfer Model)

    在状态转移到模式下,每个重复节点都保持的一个Vector clock和一个state version tree。每个节点的状态都是相同的(based on vector clock comparison),换句话说,state version tree包含有全部的冲突updates.

    At query time, the client will attach its vector clock and the replica will send back a subset of the state tree which precedes the client’s vector clock (this will provide monotonic read consistency). The client will then advance its vector clock by merging all the versions. This means the client is responsible to resolve the conflict of all these versions because when the client sends the update later, its vector clock will precede all these versions.


    At update, the client will send its vector clock and the replica will check whether the client state precedes any of its existing version, if so, it will throw away the client’s update.



    Replicas also gossip among each other in the background and try to merge their version tree together.


    Gossip (Operation Transfer Model)


    In an operation transfer approach, the sequence of applying the operations is very important. At the minimum causal order need to be maintained. Because of the ordering issue, each replica has to defer executing the operation until all the preceding operations has been executed. Therefore replicas save the operation request to a log file and exchange the log among each other and consolidate these operation logs to figure out the right sequence to apply the operations to their local store in an appropriate order.

    “Causal order” means every replica will apply changes to the “causes” before apply changes to the “effect”. “Total order” requires that every replica applies the operation in the same sequence.

    In this model, each replica keeps a list of vector clock, Vi is the vector clock the replica itself and Vj is the vector clock when replica i receive replica j’s gossip message. There is also a V-state that represent the vector clock of the last updated state.

    When a query is submitted by the client, it will also send along its vector clock which reflect the client’s view of the world. The replica will check if it has a view of the state that is later than the client’s view.

    When an update operation is received, the replica will buffer the update operation until it can be applied to the local state. Every submitted operation will be tag with 2 timestamp, V-client indicates the client’s view when he is making the update request. V-@receive is the replica’s view when it receives the submission.

    This update operation request will be sitting in the queue until the replica has received all the other updates that this one depends on. This condition is reflected in the vector clock Vi when it is larger than V-client

    On the background, different replicas exchange their log for the queued updates and update each other’s vector clock. After the log exchange, each replica will check whether certain operation can be applied (when all the dependent operation has been received) and apply them accordingly. Notice that it is possible that multiple operations are ready for applying at the same time, the replica will sort these operation in causal order (by using the Vector clock comparison) and apply them in the right order.

    The concurrent update problem at different replica can also happen. Which means there can be multiple valid sequences of operation. In order for different replica to apply concurrent update in the same order, we need a total ordering mechanism.

    One approach is whoever do the update first acquire a monotonic sequence number and late comers follow the sequence. On the other hand, if the operation itself is commutative, then the order to apply the operations doesn’t matter

    After applying the update, the update operation cannot be immediately removed from the queue because the update may not be fully exchange to every replica yet. We continuously check the Vector clock of each replicas after log exchange and after we confirm than everyone has receive this update, then we’ll remove it from the queue.

    Merkle tree

    有数据存储成树状结构,每个节点的Hash是其所有子节点的Hash的Hash,叶子节点的Hash是其内容的Hash。这样一旦某个节点发生变化,其Hash的变化会迅速传播到根节点。需要同步的系统只需要不断查询跟节点的hash,一旦有变化,顺着树状结构就能够在logN级别的时间找到发生变化的内容,马上同步。

    Paxos

    paxos是一种处理一致性的手段,可以理解为事务吧。
    其他的手段不要Google GFS使用的Chubby的Lock service。我不大喜欢那种重型的设计就不费笔墨了。

    背景

    当规模越来越大的时候。

    一、Master/slave

    这个是多机房数据访问最常用的方案,一般的需求用此方案即可。因此大家也经常提到“premature optimization is the root of all evil”。
    优点:利用mysql replication即可实现,成熟稳定。
    缺点:写操作存在单点故障,master坏掉之后slave不能写。另外slave的延迟也是个困扰人的小问题。

    二、Multi-master

    Multi-master指一个系统存在多个master, 每个master都具有read-write能力,需根据时间戳或业务逻辑合并版本。比如分布式版本管理系统git可以理解成multi-master模式。具备最终一致性。多版本数据修改可以借鉴Dynamo的vector clock等方法。

    优点:解决了单点故障。
    缺点:不易实现一致性,合并版本的逻辑复杂。


    三、Two-phase commit(2PC)


    (图片来源:http://en.wikipedia.org/wiki/File:Three-phase_commit_diagram.png)

    从图来看,cohorts(participant)收到preCommit之后,如果没收到commit, 默认也执行commit, 即图上的timeout cause commit。

    如果coodinator发送了一半preCommit crash, watchdog接管之后通过query, 如果有任一节点收到commit, 或者全部节点收到preCommit, 则可继续commit, 否则abort。

    优点:允许发生单点故障后继续达成一致。
    缺点:网络分离问题,比如preCommit消息发送后突然两个机房断开,这时候coodinator所在机房会abort, 另外剩余replicas机房会commit。

    Google Chubby的作者Mike Burrows说过, “there is only one consensus protocol, and that’s Paxos” – all other approaches are just broken versions of Paxos. 意即“世上只有一种一致性算法,那就是Paxos”,所有其他一致性算法都是Paxos算法的不完整版。相比2PC/3PC, Paxos算法的改进
    P1a. 每次Paxos实例执行都分配一个编号,编号需要递增,每个replica不接受比当前最大编号小的提案
    P2. 一旦一个 value v 被replica通过,那么之后任何再批准的 value 必须是 v,即没有拜占庭将军(Byzantine)问题。拿上面请客的比喻来说,就是一个参与者一旦accept周六2pm-5pm的proposal, 就不能改变主意。以后不管谁来问都是accept这个value。
    一个proposal只需要多数派同意即可通过。因此比2PC/3PC更灵活,在一个2f+1个节点的集群中,允许有f个节点不可用。

    另外Paxos还有很多约束的细节,特别是Google的chubby从工程实现的角度将Paxos的细节补充得非常完整。比如如何避免Byzantine问题,由于节点的持久存储可能会发生故障,Byzantine问题会导致Paxos算法P2约束失效。

    以上几种方式原理比较如下

    DHT

    Distributed hash table

    Map Reduce Execution

    Map Reduce已经烂大街了,不过还是要提一下。
    参见:http://zh.wikipedia.org/wiki/MapReduce

    Handling Deletes

    但我们执行删除操作的时候必须非常谨慎,以防丢失掉相应的版本信息。

    通常我们给一个Object标注上”已删除”的标签。在足够的时间之后,我们在确保版本一致的情况下可以将它彻底删除。回收他的空间。

    存储实现

    One strategy is to use make the storage implementation pluggable. e.g. A local MySQL DB, Berkeley DB, Filesystem or even a in memory Hashtable can be used as a storage mechanism.


    Another strategy is to implement the storage in a highly scalable way. Here are some techniques that I learn from CouchDB and Google BigTable.

    CouchDB has a MVCC model that uses a copy-on-modified approach. Any update will cause a private copy being made which in turn cause the index also need to be modified and causing the a private copy of the index as well, all the way up to the root pointer.


    Notice that the update happens in an append-only mode where the modified data is appended to the file and the old data becomes garbage. Periodic garbage collection is done to compact the data. Here is how the model is implemented in memory and disks

    In Google BigTable model, the data is broken down into multiple generations and the memory is use to hold the newest generation. Any query will search the mem data as well as all the data sets on disks and merge all the return results. Fast detection of whether a generation contains a key can be done by checking a bloom filter.

    When update happens, both the mem data and the commit log will be written so that if the

    节点变化

    Notice that virtual nodes can join and leave the network at any time without impacting the operation of the ring.

    When a new node joins the network

    1. 新加入的节点宣告自己的存在(广播或者其他手段)
    2. 他的邻居节点要调整Key的分配和复制关系。这个操作通常是同步的
    3. 这个新加入的节点异步的拷贝数据
    4. 这个节点变化的操作被发布到其他节点

    Notice that other nodes may not have their membership view updated yet so they may still forward the request to the old nodes. But since these old nodes (which is the neighbor of the new joined node) has been updated (in step 2), so they will forward the request to the new joined node.

    On the other hand, the new joined node may still in the process of downloading the data and not ready to serve yet. We use the vector clock (described below) to determine whether the new joined node is ready to serve the request and if not, the client can contact another replica.

    When an existing node leaves the network (e.g. crash)

    1. The crashed node no longer respond to gossip message so its neighbors knows about it.崩溃的节点不再发送Gossip Message的回应,所以他的邻居都知道他是了
    2. The neighbor will update the membership changes and copy data asynchronously,他的邻居处理后事,将他的活分给别人干,同时调整节点关系。

    We haven’t talked about how the virtual nodes is mapped into the physical nodes. Many schemes are possible with the main goal that Virtual Node replicas should not be sitting on the same physical node. One simple scheme is to assigned Virtual node to Physical node in a random manner but check to make sure that a physical node doesn’t contain replicas of the same key ranges.

    Notice that since machine crashes happen at the physical node level, which has many virtual nodes runs on it. So when a single Physical node crashes, the workload (of its multiple virtual node) is scattered across many physical machines. Therefore the increased workload due to physical node crashes is evenly balanced.

    列存

    描述

    数据库以行、列的二维表的形式存储数据,但是却以一维字符串的方式存储,例如以下的一个表:

    EmpId Lastname Firstname Salary
    1 Smith Joe 40000
    2 Jones Mary 50000
    3 Johnson Cathy 44000

    这个简单的表包括员工代码(EmpId), 姓名字段(Lastname and Firstname)及工资(Salary).

    这个表存储在电脑的内存(RAM)和存储(硬盘)中。虽然内存和硬盘在机制上不同,电脑的操作系统是以同样的方式存储的。数据库必须把这个二维表存储在一系列一维的“字节”中,又操作系统写到内存或硬盘中。

    行式数据库把一行中的数据值串在一起存储起来,然后再存储下一行的数据,以此类推。 1,Smith,Joe,40000;2,Jones,Mary,50000;3,Johnson,Cathy,44000;

    列式数据库把一列中的数据值串在一起存储起来,然后再存储下一列的数据,以此类推。 1,2,3;Smith,Jones,Johnson;Joe,Mary,Cathy;40000,50000,44000;

    特点

    • 良好的压缩比。由于大多数数据库设计都有冗余,如此一来,压缩比非常高,把40多M的数据导入infobright,没想到数据文件只有1M多
    • 列上的计算非常的快。
    • 方便MapReduce和Key-value模型的融合
    • 读取整行的数据较慢,但部分数据较快

    简单分析含源码

    软件篇

    亚数据库

    我发明的新概念,就是称不上数据库但有一些数据库的特征。可以指缓存。

    MemCached

    Memcached是danga.com(运营LiveJournal的技术团队)开发的一套分布式内存对象缓存系统,用于在动态系统中减少数据库 负载,提升性能。

    特点

    • 协议简单
    • 基于libevent的事件处理
    • 内置内存存储方式
    • memcached不互相通信的分布式

    Memcached处理的原子是每一个(key,value)对(以下简称kv对),key会通过一个hash算法转化成hash-key,便于查找、对比以及做到尽可能的散列。同时,memcached用的是一个二级散列,通过一张大hash表来维护。

    Memcached有两个核心组件组成:服务端(ms)和客户端(mc),在一个memcached的查询中,mc先通过计算key的hash值来 确定kv对所处在的ms位置。当ms确定后,客户端就会发送一个查询请求给对应的ms,让它来查找确切的数据。因为这之间没有交互以及多播协议,所以 memcached交互带给网络的影响是最小化的。

    内存分配

    默认情况下,ms是用一个内置的叫“块分配器”的组件来分配内存的。舍弃c++标准的malloc/free的内存分配,而采用块分配器的主要目的 是为了避免内存碎片,否则操作系统要花费更多时间来查找这些逻辑上连续的内存块(实际上是断开的)。用了块分配器,ms会轮流的对内存进行大块的分配,并 不断重用。当然由于块的大小各不相同,当数据大小和块大小不太相符的情况下,还是有可能导致内存的浪费。

    同时,ms对key和data都有相应的限制,key的长度不能超过250字节,data也不能超过块大小的限制 — 1MB。
    因为mc所使用的hash算法,并不会考虑到每个ms的内存大小。理论上mc会分配概率上等量的kv对给每个ms,这样如果每个ms的内存都不太一样,那 可能会导致内存使用率的降低。所以一种替代的解决方案是,根据每个ms的内存大小,找出他们的最大公约数,然后在每个ms上开n个容量=最大公约数的 instance,这样就等于拥有了多个容量大小一样的子ms,从而提供整体的内存使用率。

    缓存策略

    当ms的hash表满了之后,新的插入数据会替代老的数据,更新的策略是LRU(最近最少使用),以及每个kv对的有效时限。Kv对存储有效时限是在mc端由app设置并作为参数传给ms的。

    同时ms采用是偷懒替代法,ms不会开额外的进程来实时监测过时的kv对并删除,而是当且仅当,新来一个插入的数据,而此时又没有多余的空间放了,才会进行清除动作。

    缓存数据库查询

    现在memcached最流行的一种使用方式是缓存数据库查询,下面举一个简单例子说明:

    App需要得到userid=xxx的用户信息,对应的查询语句类似:

    “SELECT * FROM users WHERE userid = xxx”

    App先去问cache,有没有“user:userid”(key定义可预先定义约束好)的数据,如果有,返回数据;如果没有,App会从数据库中读取数据,并调用cache的add函数,把数据加入cache中。

    当取的数据需要更新,app会调用cache的update函数,来保持数据库与cache的数据同步。

    从上面的例子我们也可以发现,一旦数据库的数据发现变化,我们一定要及时更新cache中的数据,来保证app读到的是同步的正确数据。当然我们可 以通过定时器方式记录下cache中数据的失效时间,时间一过就会激发事件对cache进行更新,但这之间总会有时间上的延迟,导致app可能从 cache读到脏数据,这也被称为狗洞问题。(以后我会专门描述研究这个问题)

    数据冗余与故障预防

    从设计角度上,memcached是没有数据冗余环节的,它本身就是一个大规模的高性能cache层,加入数据冗余所能带来的只有设计的复杂性和提高系统的开支。

    当一个ms上丢失了数据之后,app还是可以从数据库中取得数据。不过更谨慎的做法是在某些ms不能正常工作时,提供额外的ms来支持cache,这样就不会因为app从cache中取不到数据而一下子给数据库带来过大的负载。

    同时为了减少某台ms故障所带来的影响,可以使用“热备份”方案,就是用一台新的ms来取代有问题的ms,当然新的ms还是要用原来ms的IP地址,大不了数据重新装载一遍。

    另外一种方式,就是提高你ms的节点数,然后mc会实时侦查每个节点的状态,如果发现某个节点长时间没有响应,就会从mc的可用server列表里 删除,并对server节点进行重新hash定位。当然这样也会造成的问题是,原本key存储在B上,变成存储在C上了。所以此方案本身也有其弱点,最好 能和“热备份”方案结合使用,就可以使故障造成的影响最小化。

    Memcached客户端(mc)

    Memcached客户端有各种语言的版本供大家使用,包括java,c,php,.net等等,具体可参见memcached api page [2]。
    大家可以根据自己项目的需要,选择合适的客户端来集成。

    缓存式的Web应用程序架构

    有了缓存的支持,我们可以在传统的app层和db层之间加入cache层,每个app服务器都可以绑定一个mc,每次数据的读取都可以从ms中取得,如果 没有,再从db层读取。而当数据要进行更新时,除了要发送update的sql给db层,同时也要将更新的数据发给mc,让mc去更新ms中的数据。

    性能测试

    Memcached 写速度
    平均速度: 16222 次/秒
    最大速度 18799 次/秒

    Memcached 读速度
    平均速度: 20971 次/秒
    最大速度 22497 次/秒

    Memcachedb 写速度
    平均速度: 8958 次/秒
    最大速度 10480 次/秒

    Memcachedb 读速度
    平均速度: 6871 次/秒
    最大速度 12542 次/秒

    dbcached

    ● dbcached 是一款基于 Memcached 和 NMDB 的分布式 key-value 数据库内存缓存系统。
    ● dbcached = Memcached + 持久化存储管理器 + NMDB 客户端接口
    ● Memcached 是一款高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,提升访问速度。
    ● NMDB 是一款多协议网络数据库(dbm类)管理器,它由内存缓存和磁盘存储两部分构成,使用 QDBM 或 Berkeley DB 作为后端数据库。
    ● QDBM 是一个管理数据库的例程库,它参照 GDBM 为了下述三点而被开发:更高的处理速度,更小的数据库文件大小,和更简单的API。QDBM 读写速度比 Berkeley DB 要快,详细速度比较见《Report of Benchmark Test》。

    Memcached 和 dbcached 在功能上一样吗?

    ● 兼容:Memcached 能做的,dbcached 都能做。除此之外,dbcached 还将“Memcached、持久化存储管理器、NMDB 客户端接口”在一个程序中结合起来,对任何原有 Memcached 客户端来讲,dbcached 仍旧是个 Memcached 内存对象缓存系统,但是,它的数据可以持久存储到本机或其它服务器上的 QDBM 或 Berkeley DB 数据库中。
    ● 性能:前端 dbcached 的并发处理能力跟 Memcached 相同;后端 NMDB 跟 Memcached 一样,采用了libevent 进行网络IO处理,拥有自己的内存缓存机制,性能不相上下。
    ● 写入:当“dbcached 的 Memcached 部分”接收到一个 set(add/replace/…) 请求并储存 key-value 数据到内存中后,“dbcached 持久化存储管理器”能够将 key-value 数据通过“NMDB 客户端接口”保存到 QDBM 或 Berkeley DB 数据库中。
    ● 速度:如果加上“-z”参数,采用 UDP 协议“只发送不接收”模式将 set(add/replace/…) 命令写入的数据传递给 NMDB 服务器端,对 Memcache 客户端写速度的影响几乎可以忽略不计。在千兆网卡、同一交换机下服务器之间的 UDP 传输丢包率微乎其微。在命中的情况下,读取数据的速度跟普通的 Memcached 无差别,速度一样快。
    ● 读取:当“dbcached 的 Memcached 部分”接收到一个 get(incr/decr/…) 请求后,如果“dbcached 的 Memcached 部分”查询自身的内存缓存未命中,则“dbcached 持久化存储管理器”会通过“NMDB 客户端接口”从 QDBM 或 Berkeley DB 数据库中取出数据,返回给用户,然后储存到 Memcached 内存中。如果有用户再次请求这个 key,则会直接从 Memcached 内存中返回 Value 值。
    ● 持久:使用 dbcached,不用担心 Memcached 服务器死机、重启而导致数据丢失。
    ● 变更:使用 dbcached,即使因为故障转移,添加、减少 Memcached 服务器节点而破坏了“key 信息”与对应“Memcached 服务器”的映射关系也不怕。
    ● 分布:dbcached 和 NMDB 既可以安装在同一台服务器上,也可以安装在不同的服务器上,多台 dbcached 服务器可以对应一台 NMDB 服务器。
    ● 特长:dbcached 对于“读”大于“写”的应用尤其适用。
    ● 其他:《dbcached 的故障转移支持、设计方向以及与 Memcachedb 的不同之处

    列存系列

    Hadoop之Hbase

    Hadoop / HBase: API: Java / any writer, Protocol: any write call, Query Method: MapReduce Java / any exec, Replication: HDFS Replication, Written in: Java, Concurrency: ?, Misc: Links: 3 Books [1, 2, 3]

    耶鲁大学之HadoopDB

    GreenPlum


    FaceBook之Cassandra

    Cassandra: API: many Thrift ? languages, Protocol: ?, Query Method: MapReduce, Replicaton: , Written in: Java, Concurrency: eventually consistent , Misc: like “Big-Table on Amazon Dynamo alike”, initiated by Facebook, Slides ? , Clients ?

    Cassandra是facebook开源出来的一个版本,可以认为是BigTable的一个开源版本,目前twitter和digg.com在使用。

    Cassandra特点

    • 灵活的schema,不需要象数据库一样预先设计schema,增加或者删除字段非常方便(on the fly)。
    • 支持range查询:可以对Key进行范围查询。
    • 高可用,可扩展:单点故障不影响集群服务,可线性扩展。

    Cassandra的主要特点就是它不是一个数据库,而是由一堆数据库节点共同构成的一个分布式网络服务,对Cassandra的一个写操作,会 被复制到其他节点上去,对Cassandra的读操作,也会被路由到某个节点上面去读取。对于一个Cassandra群集来说,扩展性能是比较简单的事 情,只管在群集里面添加节点就可以了。我看到有文章说Facebook的Cassandra群集有超过100台服务器构成的数据库群集。

    Cassandra也支持比较丰富的数据结构和功能强大的查询语言,和MongoDB比较类似,查询功能比MongoDB稍弱一些,twitter的平台架构部门领导Evan Weaver写了一篇文章介绍Cassandra:http://blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra/,有非常详细的介绍。

    Cassandra以单个节点来衡量,其节点的并发读写性能不是特别好,有文章说评测下来Cassandra每秒大约不到1万次读写请求,我也看 到一些对这个问题进行质疑的评论,但是评价Cassandra单个节点的性能是没有意义的,真实的分布式数据库访问系统必然是n多个节点构成的系统,其并 发性能取决于整个系统的节点数量,路由效率,而不仅仅是单节点的并发负载能力。

    Keyspace

    Cassandra中的最大组织单元,里面包含了一系列Column family,Keyspace一般是应用程序的名称。你可以把它理解为Oracle里面的一个schema,包含了一系列的对象。

    Column family(CF)

    CF是某个特定Key的数据集合,每个CF物理上被存放在单独的文件中。从概念上看,CF有点象数据库中的Table.

    Key

    数据必须通过Key来访问,Cassandra允许范围查询,例如:start => ‘10050′, :finish => ‘10070′

    Column

    在Cassandra中字段是最小的数据单元,column和value构成一个对,比如:name:“jacky”,column是name,value是jacky,每个column:value后都有一个时间戳:timestamp。

    和数据库不同的是,Cassandra的一行中可以有任意多个column,而且每行的column可以是不同的。从数据库设计的角度,你可以理解 为表上有两个字段,第一个是Key,第二个是长文本类型,用来存放很多的column。这也是为什么说Cassandra具备非常灵活schema的原 因。

    Super column

    Super column是一种特殊的column,里面可以存放任意多个普通的column。而且一个CF中同样可以有任意多个Super column,一个CF只能定义使用Column或者Super column,不能混用。下面是Super column的一个例子,homeAddress这个Super column有三个字段:分别是street,city和zip: homeAddress: {street: “binjiang road”,city: “hangzhou”,zip: “310052″,}

    Sorting

    不同于数据库可以通过Order by定义排序规则,Cassandra取出的数据顺序是总是一定的,数据保存时已经按照定义的规则存放,所以取出来的顺序已经确定了,这是一个巨大的性能优势。有意思的是,Cassandra按照column name而不是column value来进行排序,它 定义了以下几种选项:BytesType, UTF8Type, LexicalUUIDType, TimeUUIDType, AsciiType, 和LongType,用来定义如何按照column name来排序。实际上,就是把column name识别成为不同的类型,以此来达到灵活排序的目的。UTF8Type是把column name转换为UTF8编码来进行排序,LongType转换成为64位long型,TimeUUIDType是按照基于时间的UUID来排序。例如:

    Column name按照LongType排序:
    {name: 3, value: “jacky”},
    {name: 123, value: “hellodba”},
    {name: 976, value: “Cassandra”},
    {name: 832416, value: “bigtable”}

    Column name按照UTF8Type排序:
    {name: 123, value: “hellodba”},
    {name: 3, value: “jacky”},
    {name: 832416, value: “bigtable”}
    {name: 976, value: “Cassandra”}

    下面我们看twitter的Schema:
    <Keyspace Name=”Twitter”>
    < ColumnFamily CompareWith=”UTF8Type” Name=”Statuses” />
    < ColumnFamily CompareWith=”UTF8Type” Name=”StatusAudits” />
    < ColumnFamily CompareWith=”UTF8Type” Name=”StatusRelationships”
    CompareSubcolumnsWith=”TimeUUIDType” ColumnType=”Super” />
    < ColumnFamily CompareWith=”UTF8Type” Name=”Users” />
    < ColumnFamily CompareWith=”UTF8Type” Name=”UserRelationships”
    CompareSubcolumnsWith=”TimeUUIDType” ColumnType=”Super” />
    < /Keyspace>

    我们看到一个叫Twitter的keyspace,包含若干个CF,其中StatusRelationships和 UserRelationships被定义为包含Super column的CF,CompareWith定义了column的排序规则,CompareSubcolumnsWith定义了subcolumn的排序 规则,这里使用了两种:TimeUUIDType和UTF8Type。我们没有看到任何有关column的定义,这意味着column是可以灵活变更的。

    为了方便大家理解,我会尝试着用关系型数据库的建模方法去描述Twitter的Schema,但千万不要误认为这就是Cassandra的数据模型,对于Cassandra来说,每一行的colunn都可以是任意的,而不是象数据库一样需要在建表时就创建好。

    Users CF记录用户的信息,Statuses CF记录tweets的内容,StatusRelationships CF记录用户看到的tweets,UserRelationships CF记录用户看到的followers。我们注意到排序方式是TimeUUIDType,这个类型是按照时间进行排序的UUID字段,column name是用UUID函数产生(这个函数返回了一个UUID,这个UUID反映了当前的时间,可以根据这个UUID来排序,有点类似于timestamp 一样),所以得到结果是按照时间来排序的。使用过twitter的人都知道,你总是可以看到自己最新的tweets或者最新的friends.

    存储

    Cassandra是基于列存储的(Bigtable也是一样),这个和基于列的数据库是一个道理。

    API

    下面是数据库,Bigtable和Cassandra API的对比: Relational SELECT `column` FROM `database`.`table` WHERE `id` = key;
    BigTable table.get(key, “column_family:column”)
    Cassandra: standard model keyspace.get(“column_family”, key, “column”)
    Cassandra: super column model keyspace.get(“column_family”, key, “super_column”, “column”)

    对Cassandra数据模型的理解:

    1.column name存放真正的值,而value是空。因为Cassandra是按照column name排序,而且是按列存储的,所以往往利用column name存放真正的值,而value部分则是空。例如:“jacky”:“null”,“fenng”:”null”

    2.Super column可以看作是一个索引,有点象关系型数据库中的外键,利用super column可以实现快速定位,因为它可以返回一堆column,而且是排好序的。

    3.排序在定义时就确定了,取出的数据肯定是按照确定的顺序排列的,这是一个巨大的性能优势。

    4. 非常灵活的schema,column可以灵活定义。实际上,colume name在很多情况下,就是value(是不是有点绕)。

    5.每个column后面的timestamp,我并没有找到明确的说明,我猜测可能是数据多版本,或者是底层清理数据时需要的信息。

    最后说说架构,我认为架构的核心就是有所取舍,不管是CAP还是BASE,讲的都是这个原则。架构之美在于没有任何一种架构可以完美的解决各种问题,数据库和NoSQL都有其应用场景,我们要做的就是为自己找到合适的架构。

    Hypertable

    Hypertable:

    (can you help?) Open-Source Google BigTable alike.

    它是搜索引擎公司Zvents根据Google的9位研究人员在2006年发表的一篇论文《Bigtable:结构化数据的分布存储系统》 开发的一款开源分布式数据储存系统。Hypertable是按照1000节点比例设计,以 C++撰写,可架在 HDFS 和 KFS 上。尽管还在初期阶段,但已有不错的效能:写入 28M 列的资料,各节点写入速率可达7MB/s,读取速率可达 1M cells/s。Hypertable目前一直没有太多高负载和大存储的应用实例,但是最近,Hypertable项目得到了百度的赞助支持,相信其会有更好的发展。

    Google之BigTable

    研究Google的产品总是感激Google给了自己那么多方便,真心喜欢之。

    Google AppEngine Datastore 是在BigTable之上建造出来的,是Google的内部存储系统,用于处理结构化数据。AppEngine Datastore其自身及其内部都不是直接访问BigTable的实现机制,可被视为BigTable之上的一个简单接口。

    AppEngine Datastore所支持的项目的数据类型要比SimpleDB丰富得多,也包括了包含在一个项目内的数据集合的列表型。

    如果你打算在Google AppEngine之内建造应用的话,几乎可以肯定要用到这个数据存储。然而,不像SimpleDB,使用谷歌网络服务平台之外的应用,你并不能并发地与AppEngine Datastore进行接口 (或通过BigTable)。

    Yahoo之PNUTS

    Yahoo!的PNUTS是一个分布式的数据存储平台,它是Yahoo!云计算平台重要的一部分。它的上层产品通常也称为Sherpa。按照官方的 描述,”PNUTS, a massively parallel and geographically distributed database system for Yahoo!’s web applications.” PNUTS显然就深谙CAP之道,考虑到大部分web应用对一致性并不要求非常严格,在设计上放弃了对强一致性的追求。代替的是追求更高的 availability,容错,更快速的响应调用请求等。

    特点

    • 地理分布式,分布在全球多个数据中心。由于大部分Web应用都对响应时间要求高,因此最好服务器部署在离用户最近的本地机房。
    • 可扩展,记录数可支持从几万条到几亿条。数据容量增加不会影响性能。
    • schema-free,即非固定表结构。实际使用key/value存储的,一条记录的多个字段实际是用json方式合并存在value中。因此delete和update必须指定primary key。但也支持批量查询。
    • 高可用性及容错。从单个存储节点到整个数据中心不可用都不会影响前端Web访问。
    • 适合存相对小型的记录,不适合存储大文件,流媒体等。
    • 弱一致性保证。

    PNUTS实现

    Record-level mastering 记录级别主节点

    每一条记录都有一个主记录。比如一个印度的用户保存的记录master在印度机房,通常修改都会调用印度。其他地方如美国用户看这个用户的资料调用 的是美国数据中心的资料,有可能取到的是旧版的数据。非master机房也可对记录进行修改,但需要master来统一管理。每行数据都有自己的版本控 制,如下图所示。

    PNUTS的结构


    每个数据中心的PNUTS结构由四部分构成
    Storage Units (SU) 存储单元
    物理的存储服务器,每个存储服务器上面含有多个tablets,tablets是PNUTS上的基本存储单元。一 个tablets是一个yahoo内部格式的hash table的文件(hash table)或是一个MySQL innodb表(ordered table)。一个Tablet通常为几百M。一个SU上通常会存在几百个tablets。
    Routers
    每个tablets在哪个SU上是通过查询router获得。一个数据中心内router通常可由两台双机备份的单元提供。

    Tablet Controller
    router的位置只是个内存快照,实际的位置由Tablet Controller单元决定。
    Message Broker

    与远程数据的同步是由YMB提供,它是一个pub/sub的异步消息订阅系统。

    Tablets寻址与切分

    存储分hash和ordered data store。

    以hash为例介绍,先对所有的tablets按hash值分片,比如1-10,000属于tablets 1, 10,000到20,000属于tablets 2,依此类推分配完所有的hash范围。一个大型的IDC通常会存在100万以下的tablets, 1,000台左右的SU。tablets属于哪个SU由routers全部加载到内存里面,因此router访问速度极快,通常不会成为瓶颈。按照官方的 说法,系统的瓶颈只存在磁盘文件hash file访问上。
    当某个SU访问量过大,则可将SU中部分tablets移到相对空闲的SU,并修改tablet controller的偏移记录。router定位tablet失效之后会自动通过tablet controller重新加载到内存。所以切分也相对容易实现。
    Tim也曾经用MySQL实现过类似大规模存储的系统,当时的做法是把每条记录的key属于哪个SU的信息保存到 一个字典里面,好处是切分可以获得更大的灵活性,可以动态增加新的tablets,而不需要切分旧的tablets。但缺点就是字典没法像router这 样,可以高效的全部加载到内存中。所以比较而言,在实际的应用中,按段分片会更简单,且已经足够使用。

    Write调用示意图

    PNUTS感悟

    2006年Greg Linden就说I want a big, virtual database

    What I want is a robust, high performance virtual relational database that runs transparently over a cluster, nodes dropping in an out of service at will, read-write replication and data migration all done automatically.

    I want to be able to install a database on a server cloud and use it like it was all running on one machine.

    详细资料:

    http://timyang.net/architecture/yahoo-pnuts/

    微软之SQL数据服务

    SQL数据服务 是微软 Azure 网 络服务平台的一部分。该SDS服务也是处于测试阶段,因此也是免费的,但对数据库大小有限制。 SQL数据服务其自身实际上是一项处在许多SQL服务器之上的应用,这些SQL服务器组成了SDS平台底层的数据存储。你不需要访问到它们,虽然底层的数 据库可能是关系式的;SDS是一个键/值型仓储,正如我们迄今所讨论过的其它平台一样。

    微软看起来不同于前三个供应商,因为虽然键/值存储对于可扩性???言非常棒,相对于RDBMS,在数据管理上却很困难。微软的方案似乎是入木三分,在实现可扩性和分布机制的同时,随着时间的推移,不断增加特性,在键/值存储和关系数据库平台的鸿沟之间搭起一座桥梁。

    非云服务竞争者

    在云之外,也有一些可以独立安装的键/值数据库软件产品。大部分都还很年轻,不是alpha版就是beta版,但大都是开源的;通过看看它的代码,比起在非开源供应商那里,你也许更能意识到潜在的问题和限制。

    文档存储

    CouchDB

    CouchDB

    : API: JSON, Protocol: REST, Query Method: MapReduceR of JavaScript Funcs, Replication: Master Master, Written in: Erlang, Concurrency: MVCC, Misc:
    Links: 3 CouchDB books ?, Couch Lounge ? (partitioning / clusering), …

    它是Apache社区基于 Erlang/OTP 构建的高性能、分布式容错非关系型数据库系统(NRDBMS)。它充分利用 Erlang 本身所提供的高并发、分布式容错基础平台,并且参考 Lotus Notes 数据库实现,采用简单的文档数据类型(document-oriented)。在其内部,文档数据均以 JSON 格式存储。对外,则通过基于 HTTP 的 REST 协议实现接口,可以用十几种语言进行自由操作。



    CouchDB一种半结构化面向文档的分布式,高容错的数据库系统,其提供RESTFul HTTP/JSON接口。其拥有MVCC特性,用户可以通过自定义Map/Reduce函数生成对应的View。

    在CouchDB中,数据是以JSON字符的方式存储在文件中。

    特性

    • RESTFul API:HTTP GET/PUT/POST/DELETE + JSON
    • 基于文档存储,数据之间没有关系范式要求
    • 每个数据库对应单个个文件(以JSON保存),Hot backup
    • MVCC(Multi-Version-Concurrency-Control),读写均不锁定数据库
    • 用户自定义View
    • 内建备份机制
    • 支持附件
    • 使用Erlang开发(更多的特性)

    应用场景 在我们的生活中,有很多document,比如信件,账单,笔记等,他们只是简单的信息,没有关系的需求,我们可能仅仅需要存储这些数据。 这样的情况下,CouchDB应该是很好的选择。当然其他使用关系型数据库的环境,也可以使用CouchDB来解决。

    根据CouchDB的特性,在某些偶 尔连接网络的应用中,我们可以用CouchDB暂存数据,随后进行同步。也可以在Cloud环境中,作为分布式的数据存储。CouchDB提供给予 HTTP的API,这样所有的常见语言都可以使用CouchDB。

    使用CouchDB,意味着我们不需要在像使用RMDBS一样,在设计应用前首先设计负责数据Table。我们的开发更加快速,灵活。
    详细参见:

    http://www.javaeye.com/topic/319839

    Riak

    Riak: API: JSON, Protocol: REST, Query Method: MapReduce term matching , Scaling: Multiple Masters; Written in: Erlang, Concurrency: eventually consistent (stronger then MVCC via Vector Clocks), Misc:Links: talk ?,

    MongoDB

    MongoDB: API: BSON, Protocol: lots of langs, Query Method: dynamic object-based language, Replication: Master Slave, Written in: C++,Concurrency: Update in Place. Misc: Links: Talk ?,

    MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是 类似json的bjson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语 言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

    Mongo主要解决的是海量数据的访问效率问题,根据官方的文档,当数据量达到50GB以上的时候,Mongo的数据库访问速度是MySQL的 10倍以上。Mongo的并发读写效率不是特别出色,根据官方提供的性能测试表明,大约每秒可以处理0.5万-1.5次读写请求。对于Mongo的并发读 写性能,我(robbin)也打算有空的时候好好测试一下。

    因为Mongo主要是支持海量数据存储的,所以Mongo还自带了一个出色的分布式文件系统GridFS,可以支持海量的数据存储,但我也看到有些评论认为GridFS性能不佳,这一点还是有待亲自做点测试来验证了。

    最后由于Mongo可以支持复杂的数据结构,而且带有强大的数据查询功能,因此非常受到欢迎,很多项目都考虑用MongoDB来替代MySQL来实现不是特别复杂的Web应用,比方说why we migrated from MySQL to MongoDB就是一个真实的从MySQL迁移到MongoDB的案例,由于数据量实在太大,所以迁移到了Mongo上面,数据查询的速度得到了非常显著的提升。

    MongoDB也有一个ruby的项目MongoMapper,是模仿Merb的DataMapper编写的MongoDB的接口,使用起来非常简单,几乎和DataMapper一模一样,功能非常强大易用。

    Terrastore

    Terrastore: API: Java & http, Protocol: http, Language: Java, Querying: Range queries, Predicates, Replication: Partitioned with consistent hashing, Consistency: Per-record strict consistency, Misc: Based on Terracotta

    ThruDB

    ThruDB: (please help provide more facts!) Uses Apache Thrift to integrate multiple backend databases as BerkeleyDB, Disk, MySQL, S3.

    Key Value / Tuple 存储

    Amazon之SimpleDB

    Amazon SimpleDB: Misc: not open source, Book ?
    SimpleDB 是一个亚马逊网络服务平台的一个面向属性的键/值数据库。SimpleDB仍处于公众测试阶段;当前,用户能在线注册其“免费”版 –免费的意思是说直到超出使用限制为止。

    SimpleDB有几方面的限制。首先,一次查询最多只能执行5秒钟。其次,除了字符串类型,别无其它数据类型。一切都以字符串形式被存储、获取和 比较,因此除非你把所有日期都转为ISO8601,否则日期比较将不起作用。第三,任何字符串长度都不能超过1024字节,这限制了你在一个属性中能存储 的文本的大小(比如说产品描述等)。不过,由于该模式动态灵活,你可以通过追加“产品描述1”、“产品描述2”等来绕过这类限制。一个项目最多可以有 256个属性。由于处在测试阶段,SimpleDB的域不能大于10GB,整个库容量则不能超过1TB。

    SimpleDB的一项关键特性是它使用一种最终一致性模型。 这个一致性模型对并发性很有好处,但意味着在你改变了项目属性之后,那些改变有可能不能立即反映到随后的读操作上。尽管这种情况实际发生的几率很低,你也 得有所考虑。比如说,在你的演出订票系统里,你不会想把最后一张音乐会门票卖给5个人,因为在售出时你的数据是不一致的。

    Chordless


    Chordless: API: Java & simple RPC to vals, Protocol: internal, Query Method: M/R inside value objects, Scaling: every node is master for its slice of namespace, Written in: Java, Concurrency: serializable transaction isolation, Links:

    Redis

    Redis :

    (please help provide more facts!) API: Tons of languages, Written in: C, Concurrency: in memory and saves asynchronous disk after a defined time. Append only mode available. Different kinds of fsync policies. Replication: Master / Slave,

    Redis是一个很新的项目,刚刚发布了1.0版本。Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统 统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是我知道的性能最快的Key-Value DB。

    Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存List链表和Set集合的数据结构,而且还支持对List进行各种操作,例 如从List两端push和pop数据,取List区间,排序等等,对Set支持各种集合的并集交集操作,此外单个value的最大限制是1GB,不像 memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能,比方说用他的List来做FIFO双向链表,实现一个轻量级的高性 能消息队列服务,用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一 个功能加强版的memcached来用。

    Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,并且它没有原生的可扩展机制,不具有scale(可扩展) 能力,要依赖客户端来实现分布式读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。目前使用Redis的网站有 github,Engine Yard。

    Scalaris

    Scalaris: (please help provide more facts!) Written in: Erlang, Replication: Strong consistency over replicas, Concurrency: non blocking Paxos.

    Tokyo cabinet / Tyrant

    Tokyo Cabinet / Tyrant: Links: nice talk ?, slides ?, Misc: Kyoto Cabinet ?

    它是日本最大的SNS社交网站mixi.jp开发的 Tokyo Cabinet key-value数据库网络接口。它拥有Memcached兼容协议,也可以通过HTTP协议进行数据交换。对任何原有Memcached客户端来讲, 可以将Tokyo Tyrant看成是一个Memcached,但是,它的数据是可以持久存储的。Tokyo Tyrant 具有故障转移、日志文件体积小、大数据量下表现出色等优势,详见:http://blog.s135.com/post/362.htm

    Tokyo Cabinet 2009年1月18日发布的新版本(Version 1.4.0)已经实现 Table Database,将key-value数据库又扩展了一步,有了MySQL等关系型数据库的表和字段的概念,相信不久的将来,Tokyo Tyrant 也将支持这一功能。值得期待。

    TC除了支持Key-Value存储之外,还支持保存Hashtable数据类型,因此很像一个简单的数据库表,并且还支持基于column的条 件查询,分页查询和排序功能,基本上相当于支持单表的基础查询功能了,所以可以简单的替代关系数据库的很多操作,这也是TC受到大家欢迎的主要原因之一, 有一个Ruby的项目miyazakiresistance将TT的hashtable的操作封装成和ActiveRecord一样的操作,用起来非常爽。

    TC/TT在mixi的实际应用当中,存储了2000万条以上的数据,同时支撑了上万个并发连接,是一个久经考验的项目。TC在保证了极高的并发 读写性能的同时,具有可靠的数据持久化机制,同时还支持类似关系数据库表结构的hashtable以及简单的条件,分页和排序操作,是一个很棒的 NoSQL数据库。

    TC的主要缺点是在数据量达到上亿级别以后,并发写数据性能会大幅度下降,NoSQL: If Only It Was That Easy提到,他们发现在TC里面插入1.6亿条2-20KB数据的时候,写入性能开始急剧下降。看来是当数据量上亿条的时候,TC性能开始大幅度下降,从TC作者自己提供的mixi数据来看,至少上千万条数据量的时候还没有遇到这么明显的写入性能瓶颈。

    这个是Tim Yang做的一个Memcached,Redis和Tokyo Tyrant的简单的性能评测,仅供参考

    CT.M

    GT.M: API: M, C, Python, Perl, Protocol: native, inprocess C, Misc: Wrappers: M/DB for SimpleDB compatible HTTP ?, MDB:X for XML ?, PIP for mapping to tables for SQL ?, Features: Small footprint (17MB), Terabyte Scalability, Unicode support, Database encryption, Secure, ACID transactions (single node), eventual consistency (replication), License: AGPL v3 on x86 GNU/Linux, Links: Slides ?,

    Scalien

    Scalien: API / Protocol: http (text, html, JSON), C, C++, Python, Concurrency: Paxos.

    Berkley DB

    Berkley DB: API: Many languages, Written in: C, Replication: Master / Slave, Concurrency: MVCC, License: Sleepycat, BerkleyDB Java Edition: API: Java, Written in: Java, Replication: Master / Slave, Concurrency: serializable transaction isolation, License: Sleepycat

    MemcacheDB

    MemcacheDB: API: Memcache protocol (get, set, add, replace, etc.), Written in: C, Data Model: Blob, Misc: Is Memcached writing to BerkleyDB.

    它是新浪互动社区事业部为在Memcached基础上,增加Berkeley DB存储层而开发一款支持高并发的分布式持久存储系统,对任何原有Memcached客户端来讲,它仍旧是个Memcached,但是,它的数据是可以持久存储的。

    Mnesia

    Mnesia: (ErlangDB ?)

    LightCloud

    LightCloud: (based on Tokyo Tyrant)

    HamsterDB

    HamsterDB: (embedded solution) ACID Compliance, Lock Free Architecture (transactions fail on conflict rather than block), Transaction logging & fail recovery (redo logs), In Memory support – can be used as a non-persisted cache, B+ Trees – supported [Source: Tony Bain ?]

    Flare

    TC是日本第一大SNS网站mixi开发的,而Flare是日本第二大SNS网站green.jp开发的,有意思吧。Flare简单的说就是给 TC添加了scale功能。他替换掉了TT部分,自己另外给TC写了网络服务器,Flare的主要特点就是支持scale能力,他在网络服务端之前添加了 一个node server,来管理后端的多个服务器节点,因此可以动态添加数据库服务节点,删除服务器节点,也支持failover。如果你的使用场景必须要让TC可 以scale,那么可以考虑flare。

    flare唯一的缺点就是他只支持memcached协议,因此当你使用flare的时候,就不能使用TC的table数据结构了,只能使用TC的key-value数据结构存储。

    最终一致性Key Value存储

    Amazon之Dynamo

    : Misc: not open source (see KAI below)

    功能特色

    • 高可用
    • 可扩展
    • 总是可写
    • 可以根据应用类型优化(可用性,容错性,高效性配置)

    架构特色


    • 完全的分布式
    • 去中心化(人工管理工作很小)
    • Key 唯一代表一个数据对象,对该数据对象的读写操通过 Key 来完成.
    • 通常是一台自带硬盘的主机。每个节点有三个 Java 写的组件:请求协调器(request coordination)、成员与失败检测、本地持久引擎(local persistence engine)
    • 数据分区并用改进的一致性哈希(consistent hashing)方式进行复制,利用数据对象的版本化实现一致性。复制时因为更新产生的一致性问题的维护采取类似 quorum 的机制以及去中心化的复制同步协议。
    • 每个实例由一组节点组成,从应用的角度看,实例提供 IO 能力。一个实例上的节点可能位于不同的数据中心内, 这样一个数据中心出问题也不会导致数据丢失。

    BeansDB

    简介

    BeansDB 是一个主要针对大数据量、高可用性的分布式KeyValue存储系统,采用HashTree和简化的版本号来快速同步保证最终一致性(弱),一个简化版的Dynamo。

    它采用类似memcached的去中心化结构,在客户端实现数据路由。目前只提供了Python版本的客户端,其它语言的客户端可以由memcached的客户端稍加改造得到。

    Google Group: http://groups.google.com/group/beandb/

    更新

    2009.12.29 第一个公开版本 0.3

    特性

    • 高可用:通过多个可读写的用于备份实现高可用
    • 最终一致性:通过哈希树实现快速完整数据同步(短时间内数据可能不一致)
    • 容易扩展:可以在不中断服务的情况下进行容量扩展。
    • 高性能:异步IO和高性能的KeyValue数据TokyoCabinet 可配置的
    • 可用性和一致性:通过N,W,R进行配置 简单协议:Memcache兼容协议,大量可用客户端

    性能

    在小数据集上,它跟memcached一样快:

    # memstorm -s localhost:7900 -n 1000
    Num of Records : 10000
    Non-Blocking IO : 0
    TCP No-Delay : 0

    Successful [SET] : 10000
    Failed [SET] : 0
    Total Time [SET] : 0.45493s
    Average Time [SET] : 0.00005s

    Successful [GET] : 10000
    Failed [GET] : 0
    Total Time [GET] : 0.28609s
    Average Time [GET] : 0.00003s

    实际部署情况下的性能(客户端测量):

    &#x100084; 服务器 请求数 评价时间(ms) 中位数(ms) 99% (ms) 99.9%(ms)
    &#x100084; get A:7900 n=151398, avg=8.89, med=5.94, 99%=115.5, 99.9%=310.2
    &#x100084; get B:7900 n=100054, avg=6.84, med=0.40, 99%=138.5, 99.9%=483.0
    &#x100084; get C:7900 n=151250, avg=7.42, med=5.34, 99%=55.2, 99.9%=156.7
    &#x100084; get D:7900 n=150677, avg=7.63, med=5.09, 99%=97.7, 99.9%=284.7
    &#x100084; get E:7900 n=3822, avg=3.07, med=0.18, 99%=44.3, 99.9%=170.0
    &#x100084; get F:7900 n=249973, avg=8.29, med=6.36, 99%=46.8, 99.9%=241.5
    &#x100084; set A:7900 n=10177, avg=18.53, med=12.78,99%=189.3, 99.9%=513.6
    &#x100084; set B:7900 n=10431, avg=12.85, med=1.19, 99%=206.1, 99.9%=796.8
    &#x100084; set C:7900 n=10556, avg=17.29, med=12.97,99%=132.2, 99.9%=322.9
    &#x100084; set D:7900 n=10164, avg=7.34, med=0.64, 99%=98.8, 99.9%=344.4
    &#x100084; set E:7900 n=10552, avg=7.18, med=2.33, 99%=73.6, 99.9%=204.8
    &#x100084; set F:7900 n=10337, avg=17.79, med=15.31, 99%=109.0, 99.9%=369.5

    BeansDB设计实现(非常难得的中文资料)
    PPT

    Nuclear

    人人网研发中的数据库
    详见:

    http://ugc.renren.com/2010/01/21/ugc-nuclear-guide-use/

    http://ugc.renren.com/2010/01/28/ugc-nuclear-guide-theory/

    两个设计上的Tips

    1. 万事皆异步
    我们在编码的过程中走了一些弯路,同步的操作在高并发的情况下带来的性能下降是非常恐怖的,于是乎,Nuclear系统中任何的高并发操作都消除了Block。no waiting, no delay。

    2. 根据系统负载控制后台线程的资源占用
    Nuclear系统中有不少的后台线程默默无闻的做着各种辛苦的工作,但是它们同样会占用系统资源,我们的解决方案是根据系统负载动态调整线程的运行和停止,并达到平衡。

    Voldemort

    Voldemort:

    (can you help)

    Voldemort是个和Cassandra类似的面向解决scale问题的分布式数据库系统,Cassandra来自于Facebook这个 SNS网站,而Voldemort则来自于Linkedin这个SNS网站。说起来SNS网站为我们贡献了n多的NoSQL数据库,例如 Cassandar,Voldemort,Tokyo Cabinet,Flare等等。Voldemort的资料不是很多,因此我没有特别仔细去钻研,Voldemort官方给出Voldemort的并发读 写性能也很不错,每秒超过了1.5万次读写。


    其实现在很多公司可能都面临着这个抽象架构图中的类似问题。以 Hadoop 作为后端的计算集群,计算得出来的数据如果要反向推到前面去,用什么方式存储更为恰当? 再放到 DB 里面的话,构建索引是麻烦事;放到 Memcached 之类的 Key-Value 分布式系统中,毕竟只是在内存里,数据又容易丢。Voldemort 算是一个不错的改良方案。

    值得借鉴的几点:

    • 键(Key)结构的设计,有点技巧;
    • 架构师熟知硬件结构是有用的。越大的系统越是如此。
    • 用好并行。Amdahl 定律以后出现的场合会更多。

    详细:

    http://www.dbanotes.net/arch/voldemort_key-value.html

    http://project-voldemort.com/blog/2009/06/building-a-1-tb-data-cycle-at-linkedin-with-hadoop-and-project-voldemort/

    Dynomite

    Dynomite:

    (can you help)

    Kai

    KAI: Open Source Amazon Dnamo implementation, Misc: slides ,

    未分类

    Skynet

    全新的Ruby MapReduce实现

    2004年,Google提出用于分布式数据处理的MapReduce设计模式,同时还提供了第一个C++的实现。现在,一个名为Skynet的Ruby实现已经由Adam Pisoni发布。
    Skynet是可适配、可容错的、可自我更新的,而且完全
    是分布式的系统,不存在单一的失败节点。

    Skynet和Google在设计上有两点重要的区别:
    Skynet无法向工作者(Worker)发送原生代码(Raw code),
    Skynet利用结对恢复系统,不同的工作者会互相监控以防失败:
    如果有一个工作者由于某种原因离开或者放弃了,就会有另一个工作者发现并接管它的任务。Skynet 也没有所谓的“主”管理进程,只有工作者,它们在任何时间都可以充当任何任务的主管理进程。

    Skynet的使用和设置都很容易,这也正是MapReduce这个概念的真正优势。Skynet还扩展了ActiveRecord,加入了MapReduce的特性,比如distributed_find。

    你要为Starfish编写一些小程序,它们的代码是你将要构建其中的。如果我没有弄错的话,你无法在同一台机器上运行多种类型的MapReduce作业。Skynet是一个更全面的MR系统,可以运行多种类型的多个作业,比如,各种不同的代码。

    Skynet也允许失败。工作者会互相关照。如果一个工作者失败了,无法及时完成任务,另一个工作者将会接起这个任务并尝试完成它。Skynet也支持map_data流,也就是说,即使某个数据集非常庞大,甚至无法放在一个数据结构中,Skynet也可以处理。

    什 么是map_data流?大多数时候,在你准备启动一个map_reduce作业时,必须提供一个数据的队列,这些数据已经被分离并将被并行处理。如果队 列过大,以至于无法适应于内存怎么办?在这种情况下,你就要不能再用队列,而应该使用枚举(Enumerable)。Skynet知道去对象的调 用:next或者:each方法,然后开始为“每一个(each)”分离出map_task来。通过这样的方式,不会有人再试图同时创建大量的数据结构。

    还 有很多特性值得一提,不过最想提醒大家的是,Skynet能够与你现有的应用非常完美地集成到一起,其中自然包括Rails应用。Skynet甚 至还提供了一个ActiveRecord的扩展,你可以在模型中以分布式的形式执行一些任务。在Geni中,我们使用这项功能来运行特别复杂的移植,它通 常涉及到在数百万的模型上执行Ruby代码。
    > Model.distributed_find(:all, :conditions => “id > 20″).each(:somemethod)在你运行Skynet的时候,它将在每个模型上执行:somemethod,不过是以分布式的方式(这和你 拥有多少个工作者相关)。它在向模型分发任务前不必进行初始化,甚至不必提前获取所有的id。因此它可以操作无限大的数据集。 用户的反馈如何?

    Drizzle

    Drizzle可 被认为是键/值存储要解决的问题的反向方案。Drizzle诞生于MySQL(6.0)关系数据库的拆分。在过去几个月里,它的开发者已经移走了大量非核 心的功能(包括视图、触发器、已编译语句、存储过程、查询缓冲、ACL以及一些数据类型),其目标是要建立一个更精简、更快的数据库系统。Drizzle 仍能存放关系数据;正如MySQL/Sun的Brian Aker所说那样:“没理由泼洗澡水时连孩子也倒掉”。它的目标就是,针对运行于16核(或以上)系统上的以网络和云为基础的应用,建立一个半关系型数据 库平台。

    比较

    可扩展性

    数据和查询模型

    当你需要查询或更新一个值的一部分时,Key/value模型是最简单有效实现。

    面向文本数据库是Key/value的下一步, 允许内嵌和Key关联的值. 支持查询这些值数据,这比简单的每次返回整个blob类型数据要有效得多。

    Neo4J是唯一的存储对象和关系作为数学图论中的节点和边. 对于这些类型数据的查询,他们能够比其他竞争者快1000s

    Scalaris是唯一提供跨越多个key的分布式事务。

    持久化设计

    内存数据库是非常快的,(Redis在单个机器上可以完成每秒100,000以上操作)但是数据集超过内存RAM大小就不行. 而且 Durability (服务器当机恢复数据)也是一个问题

    Memtables和SSTables缓冲 buffer是在内存中写(“memtable”), 写之前先追加一个用于durability的日志中.
    但有足够多写入以后,这个memtable将被排序然后一次性作为“sstable.”写入磁盘中,这就提供了近似内存性能,因为没有磁盘的查询seeks开销, 同时又避免了纯内存操作的durability问题.(个人点评 其实Java中的Terracotta早就实现这两者结合)
    B-Trees提供健壮的索引,但是性能很差,一般和其他缓存结合起来。

    应用篇

    eBay 架构经验

    • 1、 Partition Everything 切分万物
    • 2、 Asynchrony Everywhere 处处异步
    • 3、 Automate Everything 全部自动
    • 4、 Remember Everything Fails 记录失败
    • 5、 Embrace Inconsistency 亲不同是谓大同
    • 6、 Expect (R)evolution 预言演变
    • 7、 Dependencies Matter 重视依赖
    • 8、 Be Authoritative 独断专行
    • 9、 Never Enough Data
    • 10、Custom Infrastructure 自定义基础设施

    淘宝架构经验

    • 1、适当放弃一致性
    • 2、备份和隔离解决稳定性问题
    • 3、分割和异步解决性能问题(类似 eBay 的 Asynchrony Everywhere)
    • 4、自动化降低人力成本(类似 eBay 的 Automate Everything)
    • 5、产品化管理

    Flickr架构经验

    • 使得机器自动构建 (Teach machines to build themselves)
    • 使得机器自监控(Teach machines to watch themselves)
    • 使得机器自修复(Teach machines to fix themselves)
    • 通过流程减少 MTTR (Reduce MTTR by streamlining)

    Twitter运维经验

    最近看到的另外一个介绍Twitter技术的视频[Slides] [Video (GFWed)],这是Twitter的John Adams在Velocity 2009的一个演讲,主要介绍了Twitter在系统运维方面一些经验。 本文大部分整理的观点都在Twitter(@xmpp)上发过,这里全部整理出来并补充完整。

    Twitter没有自己的硬件,都是由NTTA来提供,同时NTTA负责硬件相关的网络、带宽、负载均衡等业务,Twitter operations team只关注核心的业务,包括Performance,Availability,Capacity Planning容量规划,配置管理等,这个可能跟国内一般的互联网公司有所区别。

    运维经验

    Metrics

    Twitter的监控后台几乎都是图表(critical metrics),类似驾驶室的转速表,时速表,让操作者可以迅速的了解系统当前的运作状态。联想到我们做的类似监控后台,数据很多,但往往还需要浏览者 做二次分析判断,像这样满屏都是图表的方法做得还不够,可以学习下这方面经验。 据John介绍可以从图表上看到系统的瓶颈-系统最弱的环节(web, mq, cache, db?)
    根据图表可以科学的制定系统容量规划,而不是事后救火。

    配置管理

    每个系统都需要一个自动配置管理系统,越早越好,这条一整理发到Twitter上去之后引起很多回应。

    Darkmode

    配置界面可以enable/disable 高计算消耗或高I/O的功能,也相当于优雅降级,系统压力过大时取消一些非核心但消耗资源大的功能。

    进程管理

    Twitter做了一个”Seppaku” patch, 就是将Daemon在完成了n个requests之后主动kill掉,以保持健康的low memory状态,这种做法据了解国内也有不少公司是这样做。

    硬件

    Twitter将CPU由AMD换成Xeon之后,获得30%性能提升,将CPU由双核/4核换成8核之后,减少了40%的CPU, 不过John也说,这种升级不适合自己购买硬件的公司。

    代码协同经验

    Review制度

    Twitter有上百个模块,如果没有一个好的制度,容易引起代码修改冲突,并把问题带给最终用户。所以Twitter有一强制的source code review制度, 如果提交的代码的svn comment没有”reviewed by xxx”, 则pre-commit脚本会让提交失败, review过的代码提交后会通过自动配置管理系统应用到上百台服务器上。 有@xiaomics同学在Twitter上马上就问,时间成本能否接受?如果有紧急功能怎么办?个人认为紧急修改时有两人在场,一人修改一人 review也不是什么难事。

    部署管理

    从部署图表可以看到每个发布版本的CPU及latency变化,如果某个新版本latency图表有明显的向上跳跃,则说明该发布版本存在问题。另外在监控首页列出各个模块最后deploy版本的时间,可以清楚的看到代码库的现状。

    团队沟通

    Campfire来协同工作,campfire有点像群,但是更适合协同工作。对于Campfire就不做更多介绍,可参考Campfire官方说明。

    Cache

    • Memcache key hash, 使用FNV hash 代替 MD5 hash,因为FNV更快。
    • 开发了Cache Money plugin(Ruby), 给应用程序提供read-through, write-through cache, 就像一个db访问的钩子,当读写数据库的时候会自动更新cache, 避免了繁琐的cache更新代码。
    • “Evictions make the cache unreliable for important configuration data”,Twitter使用memcache的一条经验是,不同类型的数据需放在不同的mc,避免eviction,跟作者前文Memcached数据被踢(evictions>0)现象分析中的一些经验一致。
    • Memcached SEGVs, Memcached崩溃(cold cache problem)据称会给这种高度依赖Cache的Web 2.0系统带来灾难,不知道Twitter具体怎么解决。
    • 在Web层Twitter使用了Varnish作为反向代理,并对其评价较高。

    云计算架构

    作者认为,金字塔概念最能说明每一层的大小,它也表达了每 个层是依赖前层的消息传递。在概念上,硬件是基础和广泛层。SaaS层是顶峰,也是最轻层。这种观点是来自于将购买SaaS的的最终用户角度。对于一个非 常大的企业内部,PaaS平台层将是顶峰。使用内部开发的软件的内部各部门将实现他们的顶峰SaaS。还要注意:大小和层位置并不一定等同于重要性。硬件 层可能是最重要的,因为它是所有超过一定点的商品。

    硬件层The Hardware Layer
    必须考虑容错和冗余,大部分人认为没有容错硬件廉价商品。冗余和容错处理在软件层内,硬件预计要失败的,当然故障多电源容错服务器,RAID磁盘阵列也是必要的。

    虚拟层The Virtualization Layer
    基于操作系统OS的虚拟化层,虚拟资源能够在线即时增加拓展,允许供应商提供基础设施作为服务(SaaS),VMware,Citrix公司,Sun都提供虚拟化产品。

    The IaaS Layer
    提 供和控制的基于虚拟层的计算方式,终端用户能够精确控制每个虚拟机没分钟每小时耗费多少钱。比如提供一个共同的接口,如门户网站暴露的API,允许最终用 户创建和配置虚拟机模板的需求。最终用户还可以控制何时打开或破坏虚拟机,以及如何在虚拟机互相联网。在这个领域的主要竞争者例子是亚马逊网络服务的 EC2,S3和数据库服务。

    The PaaS Layer
    这一层的目的是尽量减少部署云的复杂性和麻烦,最终用户 利用和开发的这层的API和编程语言。两个很好的例子是谷歌的App Engine 和Force.com平台,在App Engine中,谷歌公开云存储,平台和数据库,以及使用Python和Java编程语言的API。开发人员能够编写应用程序并部署到这一层中,后端可伸缩性架构设计完全交给谷歌负责,最终用户完全不必担心管理基础设施。Force.com平台类似,但采用了自定义的编程语言名为Apex。如果你是一个大型企业寻求内部开发应用的部署,这层是你的顶峰。

    The SaaS Layer
    如 果您是中小型企业(SME)和大企业不希望开发自己的应用程序时,SaaS的层是你的顶峰(是你将直接面对的)。您只是进行有兴趣地采购如电子邮件或客户 关系管理服务,这些功能服务已经被供应商开发成功,并部署到云环境中了,您只需验证的应用是否符合你的使用需要,帐单可以基于包月租费等各种形式,,作为 最终用户的您不会产生开发和维护拓展应用程序软件的任何成本。越来越多的企业订阅Salesforce.com和Sugar CRM的SaaS产品。

    反模式

    单点失败(Single Point of Failure)

    大部分的人都坚持在单一的设备上部署我们的应用,因为这样部署的费用会比较低,但是我们要清楚任何的硬件设备都会有失败的风险的,这种单点失败会严重的影响用户体验甚至是拖垮你的应用,因此除非你的应用能容忍失败带来的损失,否则得话应该尽量的避免单点风险,比如做冗余,热备等。

    同步调用

    同步调用在任何软件系统中都是不可避免的,但是我们软件工程师必须明白同步调用给软件系统带来的问题。如果我们将应用程序串接起来,那么系统的可用性就会低于任何一个单一组件的可用性。比如组件A同步调用了组件B,组件A的可用性为99.9%,组件B的可用性为99.9%,那么组件A同步调用组件B的可用性就是99.9% * 99.9%=99.8%。同步调用使得系统的可用性受到了所有串接组件可用性的影响,因此我们在系统设计的时候应该清楚哪些地方应该同步调用,在不需要同步调用的时候尽量的进行异步的调用(而我这里所说的异步是一种基于应用的异步,是一种设计上的异步,因为J2EE目前的底层系统出了JMS是异步API以外,其它的API都是同步调用的,所以我们也就不能依赖于底层J2EE平台给我们提供异步性,我们必须从应用和设计的角度引入异步性)

    不具备回滚能力

    虽然对应用的每个版本进行回滚能力测试是非常耗时和昂贵的,但是我们应该清楚任何的业务操作都有可能失败,那么我们必须为这种失败作好准备,需要对系统的用户负责,这就要求系统一定要具有回滚的能力,当失败的时候能进行及时的回滚。(说到回滚大家可能第一时间想到的是事务的回滚,其实这里的回滚应该是一种更宽泛意义的回滚,比如我们记录每一次的失败的业务操作,这样在出现错误的时候就不是依靠于事务这种技术的手段,而是通过系统本身的回滚能力来进行回滚失败业务操作)。

    不记录日志

    日志记录对于一个成熟稳定的系统是非常重要的,如果我们不进行日志记录,那么我就很难统计系统的行为。

    无切分的数据库

    随着系统规模的慢慢变大,我们就需要打破单一数据的限制,需要对其进行切分。

    无切分的应用

    系统在规模小的时候,也许感觉不出无切分的应用带来的问题,但是在目前互联网高速发展的时代,谁能保证一个小应用在一夜或者是几夜以后还是小应用呢?说不定哪天,我们就发现应用在突如其来的访问量打击的支离破碎。因此我们就需要让我们的系统和我们一样具有生命力,要想让系统具有应付大负载的能力,这就要求我们的应用具有很好的伸缩性,这也就要求应用需要被良好的切分,只有进行了切分,我们才能对单一的部门进行伸缩,如果应用是一块死板的话,我们是没有办法进行伸缩的。就好比火车一样,如果火车设计之初就把他们设计为一体的,那么我们还怎么对火车的车厢进行裁剪?因此一个没有切分的应用是一个没有伸缩性和没有可用性的应用。

    将伸缩性依赖于第三方厂商

    如果我们的应用系统的伸缩性依赖于第三方的厂商,比如依赖于数据库集群,那么我们就为系统的伸缩性埋下了一个定时炸弹。因为只有我们自己最清楚我们自己的应用,我们应该从应用和设计的角度出发去伸缩我们的应用,而不是依赖于第三方厂商的特性。

    OLAP

    联机分析处理 (OLAP) 的概念最早是由关系数据库之父E.F.Codd于1993年提出的,他同时提出了关于OLAP的12条准则。OLAP的提出引起了很大的反响,OLAP作为一类产品同联机事务处理 (OLTP) 明显区分开来。

    OLAP报表产品最大的难点在哪里?

    目前报表工具最大的难点不在于报表的样式(如斜线等),样式虽较繁琐但并非本质困难。最根本的难点在于业务 部门知道报表代表的真正含义,却不知道报表的数据统计模型模型;而IT部门通过理解业务部门的描述,在数据库端进行设置数据统计模型,却对报表本身所代表 的价值很难理解。

    说起来有点深奥,其实并不复杂,OLAP最基本的概念只有三个:多维观察、数据钻取、CUBE运算。

    关于CUBE运算:OLAP分析所需的原始数据量是非常庞大的。一个分析模型,往往会涉及数百万、数千万条数据,甚至更多;而分析模型中包含多个维数据,这些维又可以由浏览者作任意的提取组合。这样的结果就是大量的实时运算导致时间的延滞。

    我们可以设想,一个1000万条记录的分析模型,如果一次提取4个维度进行组合分析,那么实际的运算次数将 达到4的1000次方的数量。这样的运算量将导致数十分钟乃至更长的等待时间。如果用户对维组合次序进行调整,或增加、或减少某些维度的话,又将是一个重 新的计算过程。

    从上面的分析中,我们可以得出结论,如果不能解决OLAP运算效率问题的话,OLAP将是一个毫无实用价值的概念。那么,一个成熟产品是如何解决这个问题的呢?这涉及到OLAP中一个非常重要的技术——数据CUBE预运算。

    一个OLAP模型中,度量数据和维数据我们应该事先确定,一旦两者确定下来,我们可以对数据进行预先的处理。在正式发布之前,将数据根据维进行最大

    限度的聚类运算,运算中会考虑到各种维组合情况,运算结果将生成一个数据CUBE,并保存在服务器上。

    这样,当最终用户在调阅这个分析模型的时候,就可以直接使用这个CUBE,在此基础上根据用户的维选择和维组合进行复运算,从而达到实时响应的效果。

    NOSQL们背后的共有原则

    几个星期之前,我写了一篇文章描述了常被称作 NOSQL 的一类新型数据库的背后驱动。几个星期之前,我在Qcon上发表了一个演讲,其中,我介绍了一个可伸缩(scalable)的 twitter 应用的构建模式,在我们的讨论中,一个显而易见的问题就是数据库的可扩展性问题。要解答这个问题,我试图寻找隐藏在各种 NOSQL 之后的共有模式,并展示他们是如何解决数据库可扩展性问题的。在本文中,我将尽力勾勒出这些共有的原则。

    假设失效是必然发生的

    与我们先前通过昂贵硬件之类的手段尽力去避免失效的手段不同,NOSQL实现都建立在硬盘、机器和网络都会失效这些假设之上。我们需要认定,我们不 能彻底阻止这些时效,相反,我们需要让我们的系统能够在即使非常极端的条件下也能应付这些失效。Amazon S3 就是这种设计的一个好例子。你可以在我最近的文章 Why Existing Databases (RAC) are So Breakable! 中找到进一步描述。哪里,我介绍了一些来自 Jason McHugh 的讲演的面向失效的架构设计的内容(Jason 是在 Amazon 做 S3 相关工作的高级工程师)。

    对数据进行分区

    通过对数据进行分区,我们最小化了失效带来的影响,也将读写操作的负载分布到了不同的机器上。如果一个节点失效了,只有该节点上存储的数据受到影响,而不是全部数据。

    保存同一数据的多个副本

    大部分 NOSQL 实现都基于数据副本的热备份来保证连续的高可用性。一些实现提供了 API,可以控制副本的复制,也就是说,当你存储一个对象的时候,你可以在对象级指定你希望保存的副本数。在 GigaSpaces,我们还可以立即复制一个新的副本到其他节点,甚至在必要时启动一台新机器。这让我们不比在每个节点上保存太多的数据副本,从而降低 总存储量以节约成本。

    你还可以控制副本复制是同步还是异步的,或者两者兼有。这决定了你的集群的一致性、可用性与性能三者。对于同步复制,可以牺牲性能保障一致性和可用 性(写操作之后的任意读操作都可以保证得到相同版本的数据,即使是发生失效也会如此)。而最为常见的 GigaSpaces 的配置是同步副本到被分界点,异步存储到后端存储。

    动态伸缩

    要掌控不断增长的数据,大部分 NOSQL 实现提供了不停机或完全重新分区的扩展集群的方法。一个已知的处理这个问题的算法称为一致哈希。有很多种不同算法可以实现一致哈希。

    一个算法会在节点加入或失效时通知某一分区的邻居。仅有这些节点受到这一变化的影响,而不是整个集群。有一个协议用于掌控需要在原有集群和新节点之间重新分布的数据的变换区间。

    另一个(简单很多)的算法使用逻辑分区。在逻辑分区中,分区的数量是固定的,但分区在机器上的分布式动态的。于是,例如有两台机器和1000个逻辑 分区,那么每500个逻辑分区会放在一台机器上。当我们加入了第三台机器的时候,就成了每 333 个分区放在一台机器上了。因为逻辑分区是轻量级的(基于内存中的哈希表),分布这些逻辑分区非常容易。

    第二种方法的优势在于它是可预测并且一致的,而使用一致哈希方法,分区之间的重新分布可能并不平稳,当一个新节点加入网络时可能会消耗更长时间。一个用户在这时寻找正在转移的数据会得到一个异常。逻辑分区方法的缺点是可伸缩性受限于逻辑分区的数量。

    更进一步的关于这一问题的讨论,建议阅读 Ricky Ho 的文章 NOSQL Patterns

    查询支持

    在这个方面,不同的实现有相当本质的区别。不同实现的一个共性在于哈希表中的 key/value 匹配。一些市县提供了更高级的查询支持,比如面向文档的方法,其中数据以 blob 的方式存储,关联一个键值对属性列表。这种模型是一种无预定义结构的(schema-less)存储,给一个文档增加或删除属性非常容易,无需考虑文档结 构的演进。而 GigaSpaces 支持很多 SQL 操作。如果 SQL查询没有指出特定的简直,那么这个查询就会被并行地 map 到所有的节点去,由客户端完成结果的汇聚。所有这些都是发生在幕后的,用户代码无需关注这些。

    使用 Map/Reduce 处理汇聚

    Map/Reduce 是一个经常被用来进行复杂分析的模型,经常会和 Hadoop 联系在一起。 map/reduce 常常被看作是并行汇聚查询的一个模式。大部分 NOSQL 实现并不提供 map/reduce 的内建支持,需要一个外部的框架来处理这些查询。对于 GigaSpaces 来说,我们在 SQL 查询中隐含了对 map/reduce 的支持,同时也显式地提供了一个称为 executors 的 API 来支持 map/reduce。在质疑模型中,你可以将代码发送到数据所在地地方,并在该节点上直接运行复杂的查询。

    这方面的更多细节,建议阅读 Ricky Ho 的文章 Query Processing for NOSQL DB

    基于磁盘的和内存中的实现

    NOSQL 实现分为基于文件的方法和内存中的方法。有些实现提供了混合模型,将内存和磁盘结合使用。两类方法的最主要区别在于每 GB 成本和读写性能。

    最近,斯坦福的一项称为“The Case for RAMCloud”的调查,对磁盘和内存两种方法给出了一些性能和成本方面的有趣的比较。总体上说,成本也是性能的一个函数。对于较低性能的实现,磁盘方 案的成本远低于基于内存的方法,而对于高性能需求的场合,内存方案则更加廉价。

    内存云的显而易见的缺点就是单位容量的高成本和高能耗。对于这些指标,内存云会比纯粹的磁盘系统差50到100 倍,比使用闪存的系统差5-10倍(典型配置情况和指标参见参考文献[1])。内存云同时还比基于磁盘和闪存的系统需要更多的机房面积。这样,如果一个应 用需要存储大量的廉价数据,不需要高速访问,那么,内存云将不是最佳选择。
    然而,对于高吞吐量需求的应用,内存云将更有竞争力。当 使用每次操作的成本和能量作为衡量因素的时候,内存云的效率是传统硬盘系统的 100 到 1000 倍,是闪存系统的 5-10 倍。因此,对于高吞吐量需求的系统来说,内存云不仅提供了高性能,也提供了高能源效率。同时,如果使用 DRAM 芯片提供的低功耗模式,也可以降低内存云的功耗,特别是在系统空闲的时候。此外,内存云还有一些缺点,一些内存云无法支持需要将数据在 多个数据中心之间进行数据复制。对于这些环境,更新的时延将主要取决于数据中心间数据传输的时间消耗,这就丧失了内存云的时延方面的优势。此外,跨数据中 心的数据复制会让内存云数据一致性更能难保证。不过,内存云仍然可以在夸数据中心的情况下提供低时延的读访问。

    仅仅是炒作?

    近来我见到的最多的问题就是 “NOSQL 是不是就是炒作?” 或 “NOSQL 会不会取代现在的数据库?”

    我的回答是——NOSQL 并非始于今日。很多 NOSQL 实现都已经存在了十多年了,有很多成功案例。我相信有很多原因让它们在如今比以往更受欢迎了。首先是由于社会化网络和云计算的发展,一些原先只有很高端的 组织才会面临的问题,如今已经成为普遍问题了。其次,已有的方法已经被发现无法跟随需求一起扩展了。并且,成本的压力让很多组织需要去寻找更高性价比的方 案,并且研究证实基于普通廉价硬件的分布式存储解决方案甚至比现在的高端数据库更加可靠。(进一步阅读)所有这些导致了对这类“可伸缩性优先数据库”的需求。这里,我引用 AWS团队的接触工程师、VP, James Hamilton 在他的文章 One Size Does Not Fit All 中的一段话:

    “伸缩性优先应用是那些必须具备无限可伸缩性的应用,能够不受限制的扩展比更丰富的功能更加重要。这些应用包括很多需要高 可伸缩性的网站,如 Facebook, MySpace, Gmail, Yahoo 以及 Amazon.com。有些站点实际上使用了关系型数据库,而大部分实际上并未使用。这些服务的共性在于可扩展性比功能公众要,他们无法泡在一个单一的 RDBMS 上。”

    总结一下——我认为,现有的 SQL 数据库可能不会很快淡出历史舞台,但同时它们也不能解决世上的所有问题。NOSQL 这个名词现在也变成了 Not Only SQL,这个变化表达了我的观点。

    本书不求利,只图学术之便。感谢诸位大牛写了那么多的资料,如果您不愿意被引用,学生会重写相应的章节。
    引用网志多篇,由于涵盖太广难以一一校队,特此致歉。

    感谢

    感谢Jdon,dbanotes,infoq和Timyang.您们分享和撰写了那么多有用的资料。

    版本志

    V0.1版本在2010.2.21发布,提供了本书的主题框架
    v0.2版本在2010.2.24发布,因为一些外界原因,提前发布。完善各个示例,勘误,翻译部分内容。
    v0.3版本将在3月份或之后发布

    引用

    http://www.jdon.com/jivejdon/thread/37999

    http://queue.acm.org/detail.cfm?id=1413264

    http://www.dbanotes.net/arch/five-minute_rule.html

    http://www.infoq.com/cn/news/2009/09/Do-Not-Delete-Data

    http://www.infoq.com/cn/news/2010/02/ec2-oversubscribed

    http://timyang.net/architecture/consistent-hashing-practice

    http://en.wikipedia.org/wiki/Gossip_protocol

    http://horicky.blogspot.com/2009/11/nosql-patterns.html

    http://snarfed.org/space/transactions_across_datacenters_io.html

    http://research.microsoft.com/en-us/um/people/lamport/pubs/lamport-paxos.pdf

    http://en.wikipedia.org/wiki/Distributed_hash_table

    http://hi.baidu.com/knuthocean/blog/item/cca1e711221dcfcca6ef3f1d.html

    http://zh.wikipedia.org/wiki/MapReduce

    http://labs.google.com/papers/mapreduce.html

    http://nosql-database.org/

    http://www.rackspacecloud.com/blog/2009/11/09/nosql-ecosystem/

    http://www.infoq.com/cn/news/2008/02/ruby-mapreduce-skynet

    http://s3.amazonaws.com/AllThingsDistributed/sosp/amazon-dynamo-sosp2007.pdf

    http://labs.google.com/papers/bigtable.html

    http://www.allthingsdistributed.com/2008/12/eventually_consistent.html

    http://www.rackspacecloud.com/blog/2009/11/09/nosql-ecosystem/

    http://timyang.net/tech/twitter-operations/

    http://blog.s135.com/read.php?394

    http://www.programmer.com.cn/1760/

    Two-phase commit是一个比较简单的一致性算法。由于一致性算法通常用神话(如Paxos的The Part-Time Parliament论文)来比喻容易理解,下面也举个类似神话的例子。

    某班要组织一个同学聚会,前提条件是所有参与者同意则活动举行,任意一人拒绝则活动取消。用2PC算法来执行过程如下

    Phase 1

    Prepare: 组织者(coordinator)打电话给所有参与者(participant) ,同时告知参与者列表。
    Proposal: 提出周六2pm-5pm举办活动。
    Vote: participant需vote结果给coordinator:accept or reject。
    Block: 如果accept, participant锁住周六2pm-5pm的时间,不再接受其他请求。
    Phase 2

    Commit: 如果所有参与者都同意,组织者coodinator通知所有参与者commit, 否则通知abort,participant解除锁定。
    Failure 典型失败情况分析

    Participant failure:
    任一参与者无响应,coordinator直接执行abort
    Coordinator failure:
    Takeover: 如果participant一段时间没收到cooridnator确认(commit/abort),则认为coordinator不在了。这时候可自动成为Coordinator备份(watchdog)
    Query: watchdog根据phase 1接收的participant列表发起query
    Vote: 所有participant回复vote结果给watchdog, accept or reject
    Commit: 如果所有都同意,则commit, 否则abort。

    优点:实现简单。
    缺点:所有参与者需要阻塞(block),throughput低;无容错机制,一节点失败则整个事务失败。

    四、Three-phase commit (3PC)

    Three-phase commit是一个2PC的改进版。2PC有一些很明显的缺点,比如在coordinator做出commit决策并开始发送commit之后,某个participant突然crash,这时候没法abort transaction, 这时候集群内实际上就存在不一致的情况,crash恢复后的节点跟其他节点数据是不同的。因此3PC将2PC的commit的过程1分为2,分成preCommit及commit, 如图。

     
    三栏

    哼!小单车横穿小北京

    Posted by 超级苍蝇 on Jul 18, 2008 in 浮尘~

    因为现在住的地方离单位大约3公里,但是却要走1公里去坐公交车,堵车前前后后竟然要30多分钟,俺用脚趾头想了想,发现骑自行车上班比较靠谱。前思后想,决定搞台韩姐姐那样的折叠车,回家就拉进屋里,到单位就搬上楼,连锁都不用买…

    型号是HT060,是大行的超入门变速车型,20寸的小轮胎,传说具备良好的改车条件…

    然后呢,周日中午联系了一家店主,问了问价格,单刀直入又砍了一砍,还可以,只是那家店有点远,在五棵松那边,恩,还没去过那么西的北京。

    我的计划是:五棵松有地铁站,挺方便,远也不怕,地铁过去买完了直接一折叠带上地铁,然后一路到永安里出地铁,骑上新车,正好还能试试从单位回家要多长时间,也熟悉一下路况。按计划一个半小时就能搞定,还能从容的送bo同学回去。

    实际情况是:我在地铁1号线五棵松站那里,把车折叠了,这是才发现车其实很重,折起来后也很大个儿…进站时,安检MM便一脸歉意看着我,温柔的说,你这个可能不能进站哦…
    我晕,说,那怎么办啊?
    地铁MM说,那我帮你问问吧,你等一下…
    …难道不让进? 就在我等待的过程中,一个卖票的大妈,对我吼了句,喂,你这个不让进阿,快走吧。
    倒,就在这时,刚才的安检MM带了一位警察叔叔过来,警察叔叔慈祥的说,折叠车一律不准进站,你还是上去坐公交车吧。

    郁闷了…XXX…生气了…
    哼…哼…大爷我好歹也是有车一族了…我…我…大不了骑回去!

    于是乎,小单车,横穿小北京!

     

    一路上基本上是沿着1号线走的,复兴路-〉复兴门内大街-〉复兴门外大街-〉长安街-〉建国门内大街-〉建国门外大街-〉东三环。从地图上量全程大约18公里。

    17:21 从五棵松地铁口郁闷而出,重新展开设备,之后发现车在6档时,总是嘎嘎的想,正好折回车店,又让师傅给调了调…恩,好不容易来一趟,调好了再走
    18:29 到达复兴门,本来想从2号线走,又一想,还是走1号线压长安街比较爽,哈哈
    18:41 西单,中友百货,原来骑车的风景很不一样呢
    18:51 天安门广场,好多人围着看,貌似是要降旗了,本来想凑个热闹,又想起降旗貌似是和太阳落山一起,俺一瞅太阳还挺高,少说还得20分钟吧,于是放弃,继续
    19:05 北京站前街东(西)口,北京站,恩
    19:15 可爱的永安里呀!秀水街,贵友,终于到了…
    19:35 下了电梯,到达家门口…

     
    2

    关于人与人,漫画图文。(20p)。

    Posted by 超级苍蝇 on Jun 4, 2008 in 社会~






















     
    两栏

    久违的砖头文

    Posted by 超级苍蝇 on Apr 28, 2008 in 浮尘~

     
    两栏

    J2ME程序开发全方位基础讲解汇总

    Posted by 超级苍蝇 on Feb 26, 2008 in 技术~

    J2ME程序开发全方位基础讲解汇总
     
     
     
    一、J2ME中需要的Java基础知识
      
      现在有大部分人,都是从零开始学J2ME的,学习J2ME的时候,总是从Java基础开始学习,而且现在讲Java基础的书籍中都是以J2SE来讲基础,这就给学习造成了一些不必要的麻烦,下面将J2ME中用到的和不需要的Java基础知识做一个简单的说明:
      
      J2ME中使用到的Java基础知识:
      1、Java语法基础:包括基本数据类型、关键字、运算符等等
      2、面向对象的思想:类和对象的概念,继承和多态等等。
      3、异常处理
      4、多线程
      
      J2ME中没有用到的Java基础知识:
      1、JDK中javac和java命令的使用
      2、Java基础中的很多类在J2ME中没有,或者类中的方法做了大量的精简。所以建议在J2ME中熟悉类库。
      3、Applet、AWT、Swing这些知识在J2ME中根本使用不到。
      
      简单说这么多,希望学J2ME的朋友们能少走一些弯路,不足之处希望大家积极指正和补充。

      
    二、J2ME中暂时无法完成的功能
      
      列一些J2ME中暂时无法完成的功能,希望大家能积极补充:
      1、在手机中不更改代码实现移植,主要指游戏。
      2、动态修改按钮文字。
      3、在Canvas上接受中文输入。
      4、操作本地资源、例如地址本、已收短信息等。
      5、制作破坏性的手机病毒。
      6、其他等待大家来补充。

     
    三、J2ME的跨平台性
      
      J2ME技术源于Java,所以也具有JVM的优势,可以在支持Java的平台上进行移植,但是现在的J2ME技术在跨平台上却做的很糟糕,我们来简单看一下原因:
      1、手机的屏幕尺寸不一:
      这个主要在界面制作上。
      
      如果你使用的是高级用户界面,比如你做的是应用开发或者用户登陆、用户注册这样的通用功能时,一般没有什么问题。
      
      如果你使用的是低级用户界面,比如你做的是游戏,那么你就需要考虑这个问题了。
      
      2、厂商的扩展API不统一:
      例如Nokia的扩展API类库UI系列,在别的手机上或者没有实现,或者包名不同等等。
      
      3、手机平台上实现的bug:
      例如Nokia的7650在实现双缓冲上有bug,那么在这种机型上运行的软件就不能使用双缓冲。其他NOKIA上的一些bug,可以参看:http://blog.csdn.net/Mailbomb/archive/2005/03/24/329123.aspx
      
      4、手机性能问题。
      不同手机的可用内存、最大jar文件都有要求,例如Nokia S40的大部分手机支持的最大jar文件为64K,最大可用内容为210K。
      
      所以现在的手机软件,特别是游戏都提供支持的机型列表,也才有了手机游戏移植人员的存在。

      
    四、学习J2ME可以从事的工作种类
      
      现在J2ME技术可以说相当的火暴,这里介绍一些学好了J2ME之后可以从事的工作的种类:
      
      1、J2ME游戏开发人员
      根据游戏策划或者文档要求,在某种特定的机型(以Nokia S40或S60居多)开发游戏程序。
      这是现在大部分J2ME程序员从事的工作。
      
      需要熟练掌握:高级用户界面、低级用户界面、线程,如果是网络游戏,还需要熟练网络编程。
      
      2、J2ME应用开发人员
      现在的移动应用还不是很多,但是还是出现了一些,特别是移动定位以及移动商务相关的内容。
      
      需要熟练掌握:高级用户界面、线程和网络编程。
      
      3、J2ME游戏移植人员
      参照源代码,将可以在一个平台上可以运行的游戏移植到其他平台上去。例如将Nokia S40的游戏移植到S60上,或者索爱的T618等等。
      
      主要是控制屏幕坐标,有些可能需要替换一些API。
      
      需要熟悉各平台之间的差异以及相关的技术参数,比如屏幕大小、最大jar文件尺寸等等。

      
    五、J2ME程序设计的几个原则
      
      1、使用面向对象编程。
      虽然使用面向过程编程可以减小文件的尺寸,但是为了以后维护的方便和利于扩展,还是要使用面向对象编程。
      
      2、使用MVC模式
      将模型、界面和控制分离。现在很多的程序将三者合一,但是如果你做的程序比较大的话,还是建议你进行分离。
      
      3、自动存储用户设定
      使用RMS来存储用户的信息,例如存储用户上次输入的用户名、密码、用户对于系统的设定等,这样不仅可以减少用户的输入,而且对用户友好。很多程序甚至做了自动登陆等。
      
      4、一些系统设置允许用户关闭。如背景音乐、背景灯显示等。
      
      5、将低级用户界面的绘制动作放在一个独立的线程里面去。
      
      6、在需要大量时间才能完成的工作时,给用户一个等待界面。

      
    六、从模拟器到真机测试
      
      对于J2ME开发者来说,模拟器给我们带来了很多方便,比如可以在模拟器中调试程序以及很方便的察看程序的效果,但是模拟器也给我们带来了一些问题,比如模拟器实现的bug等等,所以进行真机测试是必须的。
      
      1、为什么要进行真机测试?
      因为模拟器程序可能存在bug,以及真机的性能有限,所以必须进行真机测试。
      
      2、如何将程序传输到机器中?
      将程序传输到机器中有如下方式:
      a) OTA下载
      
      b) 使用数据线传输
      
      c) 红外传输
      
      d) 蓝牙
      你可以根据条件,选择合适的方式。
      
      3、 真机测试主要测什么?
      真机测试的内容很多,主要测试以下几个方面:
      a) 程序的功能
      
      b) 程序的操作性,是否易操作
      
      c) 程序的大小,比如Nokia S40系列的手机大部分接受的最大文件尺寸为64K
      
      d) 程序运行速度,速度是否可以忍受。

      
    七、从WTK到厂商SDK
      
      对于J2ME爱好者来说,基本上大家都是从SUN的WTK(J2ME Wireless Toolkit)开始的,但是对于实际应用来说,仅仅使用WTK是远远不够的,所以在学习过程中,必须完成从WTK到SDK的跨越。
      
      1、厂商SDK的下载地址?
      http://blog.csdn.net/Mailbomb/archive/2005/01/01/236606.aspx
      
      2、厂商SDK和WTK有什么不同?
      厂商SDK最简单的理解就是在WTK的基础上增加了自己的模拟器和自己的扩展API。
      也就是说,你在使用厂商的SDK时,可以使用厂商的扩展类库,例如Nokia的UI类库,和厂商自己的模拟器而已。
      每个厂商的扩展API都不多,而且不尽相同。
      
      3、如何使用?
      有些厂商SDK的使用都和WTK相同,例如SamSung。
      Nokia提供了独立的界面来开发,但是这个界面在实际开发中使用不多。
      
      4、厂商SDK的问题
      厂商SDK实现过程中,有一些bug,而且和真机实现不一致。例如NOKIA的混音播放问题等等。

      
    八、在J2ME中获得手机IMEI的方法
      
      IMEI是Internation mobile entity identification的简称,在手机中输入*#06#可以显示该数字,长度为15位,全球唯一,永远不会冲突,所以可以作为识别用户的一个标志。
      
      下面是在J2ME中获得IMEI的方法:
      
      1、MOTO系列的手机可以通过读取系统的IMEI属性获得,代码如下:
      String imei = System.getProperty("IMEI");
      
      2、SIEMENS系列的手机可以通过读取系统的com.siemens.IMEI属性获得,代码如下:
      String imei = System.getProperty("com.siemens.IMEI");

      
    九、J2ME网络连接中显示问题的解决办法
      
      在网络编程中,有些时候会出现一些在没有接收到网络数据就显示界面的,造成界面显示不符合要求(例如公告显示,会先显示公告的背景图片再显示公告信息),这里提一个简单的解决办法给大家:
      
      解决这种情况的方法分成三个步骤:
      1、在需要显示的界面中,调用发送网络数据的方法。每次显示时调用该构造方法,不调用Display的setCurrent方法显示。
      
      2、显示等待界面(例如进度条等),给用户提示,在进行网络连接。
      
      3、在处理网络反馈的数据完以后,调用Display的setCurrent方法显示显示当前界面。

      
    十、增强J2ME的String能力——分割字符串
      
      从JDK1.4以后,String类中新增了split方法来实现字符串的分割,但是在J2ME中却没有该方法(MIDP2.0中也没有实现),但是在实际使用过程中,有些时候的确要用到这种操作,这里将我以前实现的一段代码和大家共享:
      /**
      
      * 分割字符串,原理:检测字符串中的分割字符串,然后取子串
      
      * @param original 需要分割的字符串
      
      * @paran regex 分割字符串
      
      * @return 分割后生成的字符串数组
      
      */
      private static String[] split(String original,String regex)
      
      {
      
      //取子串的起始位置
      
      int startIndex = 0;
      
      //将结果数据先放入Vector中
      
      Vector v = new Vector();
      
      //返回的结果字符串数组
      
      String[] str = null;
      
      //存储取子串时起始位置
      
      int index = 0;
      
      //获得匹配子串的位置
      
      startIndex = original.indexOf(regex);
      
      //System.out.println("0" + startIndex);
      
      //如果起始字符串的位置小于字符串的长度,则证明没有取到字符串末尾。
      
      //-1代表取到了末尾
      
      while(startIndex < original.length() && startIndex != -1)
      
      {
      
      String temp = original.substring(index,startIndex);
      
      System.out.println(" " + startIndex);
      
      //取子串
      
      v.addElement(temp);
      
      //设置取子串的起始位置
      
      index = startIndex + regex.length();
      
      //获得匹配子串的位置
      
      startIndex = original.indexOf(regex,startIndex + regex.length());
      
      }
      
      //取结束的子串
      
      v.addElement(original.substring(index + 1 – regex.length()));
      
      //将Vector对象转换成数组
      
      str = new String[v.size()];
      
      for(int i=0;i
      {
      
      str[i] = (String)v.elementAt(i);
      
      }
      
      //返回生成的数组
      
      return str;
      
      }

      
    十一、J2ME在低级用户界面上分行显示文字
      
      在J2ME的低级用户界面开发中,经常会遇到需要在Canvas上显示大量的文字,例如关于界面、游戏说明、游戏公告等信息。如果在设计时,将文字的内容和长度都固定,既不利于修改也不利于维护。下面介绍一个简单的方法,实现一个简单、可维护性强的方式。
      
      实现方法:
      1、将需要显示的所有信息做成一个字符串。
      2、编写一个将该字符串按照要求转换为字符串数组的方法。
      3、将转换后的数组以循环的方式显示在Canvas上。
      
      通过这样三个步骤,则修改显示的信息时,只需要修改包含显示信息的字符串即可,自己书写的方法可以按照以前的标准重新分割新的字符串。如果需要修改每行显示的字符个数,则只需要修改自己书写的方法即可。
      
      通过这样一种实现方式,可以很方便的实现显示一些比较长的文本信息,即使是可变长度的字符串也没有问题。

      
    十二、J2ME中使用记录存储系统(RMS)存储信息
      
      在MIDP中,没有文件的概念,所以永久存储一般只能依靠记录存储系统实现,关于记录存储系统的简介,可以参看教程:http://www-900.ibm.com/developerWorks/cn/java/j-wi-rms/index.shtml
      
      下面是一些记录存储系统的常用编码介绍:
      
      1、打开记录集:
      打开记录集使用RecordStore里面的静态方法openRecordStore,示例代码如下:
      RecordStore rs = RecordStore.openRecordStore(“username”,true);
      
      这样就打开了一个名称为rs的记录集,其中username为记录集的名称,该名称可以根据需要来取,第二个参数代表是否则没有时创建新的记录集,true代表在该记录集不存在时,创建新的记录集,false代表不创建。
      
      如果在打开记录集时,该记录集不存在,则抛出RecordStoreNotFoundException异常,所以检测记录集是否已创建可以使用该异常。
      
      注意:记录集打开以后记得关闭。
      
      2、向记录集中写入数据
      
      2.1增加数据
      向已经打开的记录集中添加数据,需要使用addRecord方法,示例代码:
      byte[] bytes = {1,2,3};
      int id = rs. addRecord(bytes,0,bytes.length);
      
      该代码将字节数组bytes的全部内容写入到记录集中,该方法的返回值为该信息的id,注意:id从1开始,而不是从0开始。
      你可以循环使用该方法向记录集中写入多条数据。
      
      2.2修改数据
      修改已经存在的记录集中指定id的数据,需要使用setRecord方法,示例代码:
      byte[] bytes = {1,2,3};
      rs. setRecord(1,bytes,0,bytes.length);
      
      以上代码的作用是将字节数组bytes的全部内容写入到id为1的记录集rs中。
      
      该操作会覆盖已有的数据。
      
      说明:有些时候,你需要将信息写入到记录集中的第一条记录中,则可以结合以上两个方法,则第一次时向记录集增加数据,以后来进行修改。
      
      3、从记录集中读出数据
      从记录集中读取已有数据,需要使用getRecord方法,示例代码:
      byte[] bytes = rs. getRecord(1);
      
      该代码从记录集rs中读取第一条数据,将读取到的数据放在bytes数组中。
      
      在读取数据时,可以获得记录集中id的个数,可以使用getNumRecords方法获得
      
      综合代码为:
      int number = rs. getNumRecords();
      int id = 1;
      if(id >0 && id < number){
      byte[] bytes = rs. getRecord(1);
      }
      
      4、从记录集中删除记录
      从记录集中删除记录的方法有两种:逻辑删除和物理删除。
      逻辑删除是指给删除的记录打标记。
      物理删除是指从物理上删除该记录,但是该记录的id不能被重用,也就是说该id不会被继续使用。例如一个记录集中有5个记录,假设你删除了id为3的数据,则剩余记录的id依然为1、2、4、5。这给便历带来了一定的麻烦。
      
      5、便历记录集
      便历记录集,即访问记录集中的所有数据,有两个方法,详见:
      http://gceclub.sun.com.cn/NASApp/sme/controller/teclist?tid=0103
      
      6、其他操作
      6.1删除记录集
      删除记录集不同于删除记录,需要使用deleteRecordStore方法,示例代码:
      RecordStore. deleteRecordStore(“username”);
      
      该代码删除名称为username的记录集。

      
    十三、J2ME加密数据的一个第三方开源免费类库介绍
      
      在J2ME编程中,经常遇到一些数据在存储或者传输时需要加密,下面介绍一个第三方的加密类库的一些资料:
      加密类库的官方主页:http://www.bouncycastle.org/
      
      介绍的文章:
      中文:https://18900.motorola.com/ewa_portal/develope/jc_j2messl_5_1.jsp
      英文:http://www.javaworld.com/javaworld/jw-12-2002/jw-1220-wireless.html
      该文章的源代码包含使用的一些方法。
      
      备注:因为该类库提供的功能比较强大,所以类库的尺寸比较大,最后在发布时需要将类库中不需要的类删除。

      
    十四、如何播放声音
      
      在J2ME中,处理声音需要使用到Mobile Media API(MMAPI),该包是MIDP1.0的可选包,在MIDP2.0中已经包含了这个包。所以如果你使用MIDP1.0的话,请确认你的运行环境是否支持。
      
      一般手机支持的声音文件格式为wav、mid和mpg等。具体请查阅你的手机说明文档。
      
      在声音处理中,有很多处理的方式,这里说一下最常用的情况,播放JAR文件中的wav文件。
      
      播放声音文件的流程:
      1、按照一定的格式读取声音文件。
      
      播放JAR文件中的声音文件一般是将声音文件处理成流的形式。示例代码:
      InputStream is = this.getClass().getResourceAsStream("/Autorun.wav");
      
      其中Autorun.wav文件位于JAR文件的根目录下,如果位于别的目录,需要加上目录名称,如/res /Autorun.wav。
      
      2、将读取到的内容传递给播放器。
      将流信息传递给播放器,播放器按照一定的格式来进行解码操作,示例代码:
      Player player = Manager.createPlayer(is,"audio/x-wav");
      
      其中第一个参数为流对象,第二个参数为声音文件的格式。
      
      3、播放声音。
      使用Player对象的start方法,可以将声音播放出来,示例代码:
      player.start();
      
      在播放声音时也可以设定声音播放的次数,可以使用Player类中的setLoopCount方法来实现,具体可查阅API文档。
      
      下面是在NOKIA S60模拟器中测试通过。代码如下:
      package sound;
      
      import javax.microedition.midlet.*;
      
      import javax.microedition.lcdui.*;
      
      import javax.microedition.media.*;
      
      import java.io.*;
      
      public class SoundMIDlet extends MIDlet {
      
      private Player player = null;
      
      /** Constructor */
      
      public SoundMIDlet() {
      
      try{
      
      InputStream is = this.getClass().getResourceAsStream("/Autorun.wav");
      
      player = Manager.createPlayer(is,"audio/x-wav");
      
      }catch(IOException e){
      
      System.out.println("1:" + e);
      
      }catch(MediaException e){
      
      System.out.println("2:" + e);
      
      }catch(Exception e){
      
      System.out.println("3:" + e);
      
      }
      }
      
      /** Main method */
      
      public void startApp() {
      
      if(player != null){
      
      try{
      
      player.start();
      
      }catch(MediaException e){
      
      System.out.println("4:" + e);
      }
      
      }
      }
      
      /** Handle pausing the MIDlet */
      
      public void pauseApp() {
      
      }
      
      /** Handle destroying the MIDlet */
      
      public void destroyApp(boolean unconditional) {
      
      }
      
      }

      
    十五、J2ME 3D编程的一些资料
      
      随着J2ME技术的发展,以及硬件速度的提升,3D游戏程序将慢慢的变成主流,最近想学习这一块的编程,所以收集了一些资料,和大家一起分享:
      1、JSR184
      JSR184是Nokia公司起草的一个关于3D API的规范,下载地址为:
      http://www.forum.nokia.com/main/1,,1_0_10,00.html#jsr184
      
      2、Nokia的3D编程资料
      http://www.forum.nokia.com/main/1,6566,21,00.html
      
      3、3D引擎
      一个简单的开放源代码的3D游戏引擎
      http://www.j2me.com.cn/Soft_Show.asp?SoftID=19
      
      国内一个合作开发3D引擎的项目:
      http://gceclub.sun.com.cn/NASApp/sme/jive/thread.jsp?forum=11&thread=8593
      
      4、一款3D游戏产品
      http://games.sina.com.cn/newgames/2004/04/040217696.shtml
      
      5、支持3D的开发工具
      当前一些高端的手机支持3D开发,支持3D开发的开发工具中,通用的有SUN的J2MEWTK2.2。专用的是厂商提高的支持JSR184的SDK。

      
    十六、3D编程——第一个3D程序
      
      参考WTK2.2提供的demo,完成了第一个3D程序,虽然很简单,而且有些问题还不是很清楚,还是把代码共享出来和愿意学习J2ME 3D编程的朋友一起学习。
      
      关于代码的编译和运行说明如下:
      1、以下代码在J2ME WTK2.2下面编译通过。
      
      2、代码分为两个文件:First3DCanvas.java和First3DMIDlet.java。
      
      3、使用J2ME WTK2.2建立新的工程,主MIDlet类为:first3d. First3DMIDlet
      
      4、将代码保存在你的工程目录下的first3d目录下。
      
      5、将J2ME WTK安装目录下的apps\Demo3D\res\com\superscape\m3g\wtksamples\retainedmode\content目录中的swerve.m3g文件复制到你的工程目录下的res目录下。
      
      6、你的工程建立后,设置工程,通过WTK界面中的“设置”按钮打开设置窗口,在“API选择”中,设置“目标平台”为:自定义;“简档”为“MIDP2.0”;“配置”为“CLDC1.1”;选中“Mobile 3D Graphics for J2ME(JSR184)”。
      
      7、这样你就可以编译和运行以下代码了。
      
      源代码如下:
      // First3DMIDlet.java
      
      package first3d;
      
      import javax.microedition.midlet.*;
      
      import javax.microedition.lcdui.*;
      
      public class First3DMIDlet extends MIDlet {
      
      private First3DCanvas displayable = new First3DCanvas();
      
      public void startApp() {
      
      Display.getDisplay(this).setCurrent(displayable);
      
      }
      
      public void pauseApp() {}
      
      public void destroyApp(boolean unconditional) {}
      
      }
      
      // First3Dcanvas.java
      
      package first3d;
      
      import javax.microedition.lcdui.*;
      
      import javax.microedition.m3g.*;
      
      import java.util.*;
      
      /**
      
      * 第一个3D程序
      
      */
      
      public class First3DCanvas
      
      extends Canvas
      
      implements Runnable {
      
      /**World对象*/
      
      private World myWorld = null;
      
      /**Graphics3D对象*/
      
      private Graphics3D g3d = Graphics3D.getInstance();
      
      /**Camera对象*/
      
      private Camera cam = null;
      
      private int viewport_x;
      
      private int viewport_y;
      
      private int viewport_width;
      
      private int viewport_height;
      
      private long worldStartTime = 0;
      
      //重绘时间
      
      private int validity = 0;
      
      public First3DCanvas() {
      
      //启动重绘界面的线程
      
      Thread thread = new Thread(this);
      
      thread.start();
      
      try {
      
      //导入3D图片
      
      myWorld = (World) Loader.load("/swerve.m3g")[0];
      
      viewport_x = 0;
      
      viewport_y = 0;
      
      viewport_width = getWidth();
      
      viewport_height = getHeight();
      
      cam = myWorld.getActiveCamera();
      
      //设置cam对象
      
      float[] params = new float[4];
      
      int type = cam.getProjection(params);
      
      if (type != Camera.GENERIC) {
      
      //calculate window aspect ratio
      
      float waspect = viewport_width / viewport_height;
      
      if (waspect < params[1]) {
      
      float height = viewport_width / params[1];
      
      viewport_height = (int) height;
      
      viewport_y = (getHeight() – viewport_height) / 2;
      
      }
      
      else {
      
      float width = viewport_height * params[1];
      
      viewport_width = (int) width;
      
      viewport_x = (getWidth() – viewport_width) / 2;
      
      }
      
      }
      
      worldStartTime = System.currentTimeMillis();
      
      }
      
      catch (Exception e) {}
      
      }
      
      protected void paint(Graphics g) {
      
      //清除背景
      
      g.setColor(0×00);
      
      g.fillRect(0, 0, getWidth(), getHeight());
      
      //和3D对象绑定
      
      g3d.bindTarget(g);
      
      g3d.setViewport(viewport_x, viewport_y, viewport_width, viewport_height);
      
      long startTime = System.currentTimeMillis() – worldStartTime;
      
      validity = myWorld.animate((int)startTime);
      
      try {
      
      g3d.render(myWorld);
      
      }
      
      finally {
      
      g3d.releaseTarget();
      
      }
      
      }
      
      public void run() {
      
      try{
      
      while(true){
      
      //重绘图形
      
      repaint(viewport_x, viewport_y, viewport_width, viewport_height);
      
      }
      
      }catch(Exception e){}
      
      }
      
      }

     

     

    十七、在J2ME网络编程中使用CMWAP代理
      
      在中国移动提供的网络连接中,分为CMNET和CMWAP两种,其中CMNET可以无限制的访问互联网络,资费比较贵。CMWAP类似一个HTTP的代码,只能访问支持HTTP的应用,但是资费便宜,稳定性比较差。
      
      在实际的J2ME网络编程中,一般需要提供以CMWAP代理的方式连接网络,在J2ME中,连接的代码和直接连接有所不同,代码如下:
      HttpConnection http = (HttpConnection)Connector.open(("http://10.0.0.172/"+url);
      http.setRequestProperty("X-Online-Host",ServerName);
      
      例如你需要访问的地址为:http://www.test.com/login/loginServlet
      
      则上面的代码就为:
      HttpConnection http = (HttpConnection)Connector.open(("http://10.0.0.172/"+
      ”login/loginServlet”);
      http.setRequestProperty("X-Online-Host",”www.test.com”);
      
      在实际使用过程中,只需要使用实际需要访问的地址的域名或者IP来代替ServerName,例如示例中的“www.test.com”,使用后续的地址类代替代码中的url,例如示例中的“login/loginServlet”,就可以实际的使用CMWAP代理来进行连接了。

      
    十八、J2ME中的时间处理全攻略
      
      时间处理在程序开发中相当常见,下面对于时间处理做一个简单的说明。
      
      一、时间的表达方式
      时间在J2ME中有两种表达方式:
      
      1、以和GMT1970年1月1号午夜12点和现在相差的毫秒数来代表
      这种方式适合比较两个时间之间的差值。
      
      2、以对象的形式来表达
      
      二、时间处理的相关类
      时间处理在J2ME中涉及三个类:
      
      1、System类
      long time = System. currentTimeMillis();
      
      使用该方法可以获得当前时间,时间的表达方式为上面提到的第一种。
      
      2、Date类
      Date date = new Date();
      
      获得当前时间,使用对象的形式来进行表达。
      
      3、Calendar类
      Calendar calendar = Calendar. getInstance();
      
      三、时间处理的具体操作
      
      1、以上三种表达方式的转换:
      a)将System类获得的时间转换为Date对象
      Date date = new Date(System. currentTimeMillis());
      
      b)将Date类型的对象转换为Calendar类型的对象
      Calendar calendar = Calendar. getInstance();
      Date date = new Date();
      calendar.setTime(date);
      
      2、使用Calendar完成一些日期操作:
      Calendar是时间处理中最常用也是功能最强大的类,可以用它来获得某个时间的日期、星期几等信息。
      
      获得日期:
      Calendar calendar = Calendar. getInstance();
      ……
      int day = calendar.get(Calendar. DATE);
      
      获得日期、年份、星期的操作和这个类似。
      
      需要注意的是:Calendar中表示月份的数字和实际相差1,即1月用数字0表示,2月用数字1表示,……12月用数字11表示。
      

     

    十九、J2ME中随机数字处理全攻略
      
      在程序中生成随机数字,用处比较,如人工智能领域等等,这里对于在J2ME中生成随机数的操作进行一个简单的整理,希望对大家能有帮助。
      
      J2ME和J2SE不同,不能使用Math类的random来生成随机数字,只能使用java.util包的Random类来生成随机数字。
      
      1、创建Random类型的对象:
      Random random = new Random();
      
      Random random = new Random(10010010);
      
      以上两种是创建Random对象的方式,第一种使用默认构造方法,和以下的代码作用完全等价:
      Random random = new Random(System. currentTimeMillis());
      相当与使用当前时间作为种子数字来进行创建。
      
      第二种方式通过自己来指定种子数字来进行创建。
      
      大家可以根据需要使用以上两种方式的任一种。
      
      2、生成随机数字:
      创建好了随机对象以后,我们就可以来生成随机数字了:
      
      生成随机整数:
      int k = random.nextInt();
      
      生成随机长整数:
      long l = random.nextLong();
      
      3、生成指定范围的数字:
      例如生成0-10之间的随机数字:
      int k = random.nextInt();
      int j = Math.abs(k % 10);
      
      首先生成一个随机整数k,然后用k和10取余,最后使用Math类的abs方法取绝对值,获得0-10之间的随机数字。
      
      获得0-15之间的随机数,类似:
      int k = random.nextInt();
      int j = Math.abs(k % 15);
      
      获得10-20之间的随机数字:
      int k = random.nextInt();
      int j = Math.abs(k % 10) + 10;

      
    二十、在J2ME手机编程中使用字体
      
      在J2ME手机编程中,可以通过使用字体类——Font在低级用户界面中,获得更好的表现效果,那么如何使用Font类呢?
      
      首先,由于手机设备的限制,手机中支持的字体类型很有限,所以在J2ME中只能使用手机支持的默认字体来构造Font类对象。下面是创建Font类的对象时使用的方法:
      getFont(int face,int style,int size);
      
      例如:
      Font font = Font.getFont(Font.FACE_SYSTEM,Font.STYLE_BOLD,Font. SIZE_MEDIUM);
      
      无论哪一个参数,都只能使用系统设置的数值,这些数值具体的大小在不同的手机上可能不同。下面对于其中的三个参数的取值做详细的介绍:
      
      face参数指字体的外观,其的取值:
      FACE_MONOSPACE——等宽字体
      FACE_PROPORTIONAL——均衡字体
      FACE_SYSTEM——系统字体
      
      style参数指字体的样式,其的取值:
      STYLE_BOLD——粗体
      STYLE_ITALIC——斜体
      STYLE_PLAIN——普通
      STYLE_UNDERLINED——下划线
      STYLE_BOLD | STYLE_ITALIC——粗斜体
      STYLE_UNDERLINED | STYLE_BOLD——带下划线粗体
      STYLE_UNDERLINED | STYLE_ITALIC——带下划线斜体
      STYLE_UNDERLINED | STYLE_ITALIC | STYLE_BOLD——带下划线的粗斜体
      
      size参数指字体的大小,其的取值:
      SIZE_SMALL——小
      SIZE_MEDIUM——中
      SIZE_LARGE——大
      
      通过上面的参数的值,可以组合出你需要的字体对象。
      
      下面是一些常用的字体操作:
      1. 获得系统的默认字体:
      Font font = Font.getDefaultFont();
      
      2. 在panit方法内部,假设Graphics参数的名称为g,则获得当前字体的方法是:
      Font font = g.getFont();
      
      3. 在panit方法内部,假设Graphics参数的名称为g,则设置当前字体的方法是:
      g.setFont(font);
      
      其中font为你构造好的字体对象。
      
      4. 在MIDP2.0中,List可以设置每行的字体格式,方法是:
      list.setFont(0,font);
      
      则上面的代码是将list中的第一行设置为font类型的字体。

      
    二十一、在J2ME手机程序开发中使用颜色
      
      在J2ME手机开发过程中,需要经常用到颜色来进行绘制,增强程序的表现效果,下面就介绍一下如何使用颜色。
      
      由于J2ME技术比较简单,所以没有实现专门的颜色类,而只是使用RGB的概念来代表颜色。这里简单介绍一下RGB的概念,颜色是由红(Red)、绿(Green)、蓝(Blue)三原色组成的,所以可以使用这三个颜色的组合来代表一种具体的颜色,其中R、G、B的每个数值都位于0-255之间。在表达颜色的时候,即可以使用三个数字来表达,也可以使用一个格式如0X00RRGGBB这样格式的十六进制来表达,下面是常见颜色的表达形式:
      
      红色:(255,0,0)或0×00FF0000
      
      绿色:(0,255,0)或0×0000FF00
      
      蓝色:(255,255,255)或0×00FFFFFF
      
      其他颜色也可以通过上面的方式组合出来。
      
      知道了颜色的表达方式以后,下面来介绍一下如何在J2ME程序中使用颜色,涉及的方法均在Graphics类中,有以下几个:
      
      1.getColor():
      获得当前使用的颜色,返回值是0×00RRGGBB格式的数字。例如:
      int color = g.getColor();
      
      其中g为Graphics类型的对象。
      
      2.setColor(int RGB):
      设置使用的颜色。例如:
      g.setColor(0×00ff0000);
      
      3.setColor(int red, int green, int blue)
      和上面的方法作用一样,例如:
      g.setColor(255,0,0);
      
      在设置了Graphics使用的颜色以后,再进行绘制的时候,就可以绘制指定的颜色了。

      
    二十二、在J2ME联网应用中获得客户端的手机号码
      
      在J2ME程序开发过程中,为了一定的需要,经常需要来获得用户的手机号码,但是这个功能却在标准的J2ME类库中没有提供。
      
      在使用中国移动的CMWAP方式连接网络时,中国移动会将用户的手机号码放在一个名称为x-up-calling-line-id的头信息中,可以通过读取该头信息,获得用户的手机号码,具体代码如下:
      String usermphone = http.getHeader("x-up-calling-line-id");
      
      其中http是HttpConnction类型的对象。
      
      

    二十三、使用J2ME发送手机短信息
      
      在程序中,发送短信息的方式一般有三种:
      
      1、 使用程序在网络上发送短信息,例如各大网站的短信业务。这种方式是通过程序将信息发送给运营商的网关服务器,然后通过运营商的网络发送给手机。
      
      2、 在计算机中,通过数据线连接到手机,然后通过手机来发送短信息。这种方式是通过使用AT指令来实现。爱立信手机的AT指令你可以在以下地址找到:http://mobilityworld.ericsson.com.cn/development/download_hit.asp
      
      3、 通过在手机中运行的程序来发送短信息。这个正是本文实现的方式。
      
      在J2ME中,如果想发送短信息,需要使用WMA包,MIDP2.0中已经包含,MIDP1.0中可以通过厂商提供的扩展API实现,和WMA的类库基本一样。
      
      下面是使用WMA向指定手机号码发送短信息的一个方法,很简单。当然WMA也提供了其他的方式来发送更多的内容。
      // SMSUtil.java
      
      package my.util;
      
      import javax.wireless.messaging.*;
      
      import javax.microedition.io.*;
      
      /**
      
      * 发送文本短信息的方法
      
      */
      
      public class SMSUtil{
      
      /**
      
      * 给指定号码发送短信息
      
      * @param content 短信息内容
      
      * @param phoneNumber 手机号码
      
      * @return 发送成功返回true,否则返回false
      
      */
      
      public static boolean send(String content,String phoneNumber){
      
      //返回值
      
      boolean result = true;
      
      try{
      
      //地址
      
      String address = "sms://+" + phoneNumber;
      
      //建立连接
      
      MessageConnection conn = (MessageConnection)Connector.open(address);
      
      //设置短信息类型为文本,短信息有文本和二进制两种类型
      
      TextMessage msg = (TextMessage)conn.newMessage(MessageConnection.TEXT_MESSAGE);
      
      //设置信息内容
      
      msg.setPayloadText(content);
      
      //发送
      
      conn.send(msg);
      
      }catch(Exception e){
      
      result = false;
      
      //未处理
      
      }
      
      return result;
      }
      }
      
      

    二十四、使用简单的J2ME程序测试MIDlet的生命周期
      
      在MIDlet程序学习中,生命周期是一个比较抽象的概念。其实生命周期就是一个简单的规定,规定了MIDlet中的每个方法,什么时候被系统调用。下面是一个示例代码,在每个方法的内部都输出一条语句,可以根据程序的输出结果来验证各方法被调用的顺序,具体代码如下:
      //文件名:LifeCircleMIDlet.java
      
      import javax.microedition.midlet.*;
      
      /**
      
      * 测试MIDlet的生命周期
      
      */
      
      public class LifeCircleMIDlet extends MIDlet{
      
      /**
      
      * 默认构造方法
      
      */
      
      public LifeCircleMIDlet(){
      
      System.out.println("默认构造方法");
      
      }
      
      /**
      
      * 启动方法
      
      */
      
      public void startApp(){
      
      System.out.println("startApp方法");
      
      }
      
      /**
      
      * 暂停方法
      
      */
      
      public void pauseApp(){
      
      System.out.println("pauseApp方法");
      
      }
      
      /**
      
      * 销毁方法
      
      * @param b
      
      */
      
      public void destroyApp(boolean b){
      
      System.out.println("destroyApp方法");
      
      }
      
      }
      
      在J2WTK中运行该程序时,可以使用浏览器中的“MIDlet”菜单中的暂停和恢复菜单,模拟暂停事件。
      
      

    二十五、使用OTA来发布你的程序
      
      众所周知,J2ME程序发布的形式主要有:OTA、数据线传输、红外和蓝牙传输等。这里简单说说如何通过OTA来发布你的程序。
      
      OTA是Over The Air的简写,也就是通过网络下载,这是主要的发布形式之一。现在的百宝箱都是采用这种形式。
      
      使用OTA来发布程序,需要如下几个步骤:
      1、在你的WEB服务器上添加对于jad和jar文件的MIME支持。
      后缀名:jad
      MIME类型:text/vnd.sun.j2me.app-descriptor
      
      后缀名:jar
      MIME类型:application/java-archive
      
      2、发布WML页面:
      例如你的jar文件名test.jad,则最简单的下载页面是:
      <?xml version="1.0"?>
      <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.3//EN"
      "http://www.wapforum.org/DTD/wml13.dtd">
      <wml>
      <card id="card1" title="Download Midlet">
      <a href="test.jad">test</a>
      </card>
      </wml>
      你可以将以上代码保存在WEB服务器上,例如保存为text.wml
      
      3、修改jad文件:
      在jad文件中增加 MIDlet-Jar-URL: http://domain/directory/test.jar
      其中的http://domain/directory/test.jar为你的jar文件的路径。
      
      经过上面的设置,你就可以将你的wml页面路径作为你的WAP下载页面发布了。用户只需要在手机上输入这个路径就可以访问和下载你的程序了。
     
     

     
    三栏

    紧锣密鼓 腾讯QQ三国资料片即将推出

    Posted by 超级苍蝇 on Nov 19, 2007 in 技术~

      2007年11月14日下午,腾讯控股有限公司公布截至2007年9月30日止的第三季度业绩报告。其中作为互联网增值服务之一的网络游戏表现突出,占总收入的21.8%,比上一季度增长52.0%。于第三季度正式推出的大型网络游戏《QQ三国》成为最大功臣之一。

      《QQ三国》作为腾讯的首款横版MMORPG,游戏具有浓郁的历史背景和文化内涵,加上绿色清新的Q版风格以及丰富多样的玩法,使得《QQ三国》在内测阶段便已经积累起超高的人气。6月29日开放正式公测后,人气再次爆发,服务器全线爆满。QQ三国甚至创造了公测后每周开放新服的行业记录,来迎接进入游戏的新玩家们。在2007年被誉为网游奥斯卡的金翎奖评选中,QQ三国荣登国内最佳Q版网游宝座,时尚玩法和文化魅力一展无余。

      从内测的最受期待到公测后最受喜爱,赢得人气和市场的《QQ三国》再接再厉,大型资料片正在紧锣密鼓的筹备和完善当中,即将在2007年岁末隆重登场。《QQ三国》游戏内容强调古典文化和时尚玩法的结合,资料片传承以往优势的同时更是添加了众多新潮的游戏元素,围绕“官爵”、“军团”、“竞技场”和“副将”等主题内容展开,带来的是前所未有的体验和玩法。

      资料片中,古典文化里原汁原味的“官爵”将会在QQ三国游戏中得到完美展现,从“九品芝麻官”到“一品丞相”等不同职级的官职都会与玩家的日常游戏挂钩。玩家通过完成任务、挑战BOSS等不同的途径积累声望便可获得官职和独一无二的称号。当然,官职不仅仅是责任和荣誉的象征,更重要的是根据不同的职位可以领取国家发放的俸禄。电影电视和小说里的加官进爵、升官发财在《QQ三国》游戏里天天上演,而且每个玩家都是主角。

      头戴乌纱帽,身着熊猫装,QQ三国演绎传统文化的同时也不忘恶搞。如果说“官爵”系统带来的是最古典的趣味体验和单人最实惠的经济收入的话,那么即将登场的“军团”和“副将”等特色系统则让千万的QQ三国玩家找到共同的家园,军团让玩家找到组织,副将让每个玩家过足老大瘾。QQ三国里的军团不同于传统网游的家族和公会,只是简单的将玩家聚合在一起。军团具有等级和成长的概念,还会有物资的产出,带来新的多人集体养成体验。加入组织,享受网游大家庭的温暖,同时还能结拜兄弟、在游戏里找个美女做老婆。齐心合力让军团更强大,打造真正的玩家基地,实现“我的地盘听我的”。资料片前传的到来已经有了“升官发财、兄弟老婆我要我们在一起”的影子,有了老婆兄弟的陪伴可能还不够,我们还需要一个“宠物”。“副将”的推出相信会颠覆传统网游养宠玩法,忠义关羽、勇猛张飞、文韬武略的三国人物,个个都能成为玩家的“副将”,听候玩家差遣,这样的“宠物”玩法您一定闻所未闻吧。试想下,带个关羽做“小弟”,自己当“大佬”,那该是何等的拉风。

      官爵系统带来升官发财,天天领俸禄的实惠,可以成长的军团实现拜兄弟、交朋友、找老婆的美丽梦想,资料片还有最热门的副职、最拉风的副将系统、最刺激的竞技场推出;未来更多精彩,QQ三国与你一同分享。

     
    两栏

    南开ACM又一次历史性突破!

    Posted by 超级苍蝇 on Nov 19, 2007 in 技术~

     

    南开大学ACM发展历史回顾

    2001年 第一次组队参加ACM国际大学生程序设计竞赛

    2003年 第一次获取铜奖的成绩

    2005年 第一次校内选拔赛NKPC成功举办

    2006年 第一次正式上线自主开发的OnlineJudge

    2007年11月18日  第一次获取银奖的成绩

    200X年 第一次获取金奖的成绩~~~

    200X年 第一次参加世界总决赛

     

     

     
    2

    了解MySpace的六次重构经历

    Posted by 超级苍蝇 on Nov 12, 2007 in 技术~

     

    在每个里程碑,站点负担都会超过底层系统部分组件的最大载荷,特别是数据库和存储系统。接着,功能出现问题,用户失声尖叫。最后,技术团队必须为此修订系统策略。

    虽然自2005年早期,站点账户数超过7百万后,系统架构到目前为止保持了相对稳定,但MySpace仍然在为SQL Server支持的同时连接数等方面继续攻坚,Benedetto说,"我们已经尽可能把事情做到最好"。

    里程碑一:50万账户

    按Benedetto 的说法,MySpace最初的系统很小,只有两台Web服务器和一个数据库服务器。那时使用的是Dell双CPU、4G内存的系统。

    单个数据库就意味着所有数据都存储在一个地方,再由两台Web服务器分担处理用户请求的工作量。但就像MySpace后来的几次底层系统修订时的情况一样,三服务器架构很快不堪重负。此后一个时期内,MySpace基本是通过添置更多Web服务器来对付用户暴增问题的。

    但到在2004年早期,MySpace用户数增长到50万后,数据库服务器也已开始汗流浃背。

    但和Web服务器不同,增加数据库可没那么简单。如果一个站点由多个数据库支持,设计者必须考虑的是,如何在保证数据一致性的前提下,让多个数据库分担压力。

    在第二代架构中,MySpace运行在3个SQL Server数据库服务器上——一个为主,所有的新数据都向它提交,然后由它复制到其他两个;另两个全力向用户供给数据,用以在博客和个人资料栏显示。这种方式在一段时间内效果很好——只要增加数据库服务器,加大硬盘,就可以应对用户数和访问量的增加。

    里程碑二:1-2百万账户

    MySpace注册数到达1百万至2百万区间后,数据库服务器开始受制于I/O容量——即它们存取数据的速度。而当时才是2004年中,距离上次数据库系统调整不过数月。用户的提交请求被阻塞,就像千人乐迷要挤进只能容纳几百人的夜总会,站点开始遭遇"主要矛盾",Benedetto说,这意味着MySpace永远都会轻度落后于用户需求。

    "有人花5分钟都无法完成留言,因此用户总是抱怨说网站已经完蛋了。"他补充道。

    这一次的数据库架构按照垂直分割模式设计,不同的数据库服务于站点的不同功能,如登录、用户资料和博客。于是,站点的扩展性问题看似又可以告一段落了,可以歇一阵子。

    垂直分割策略利于多个数据库分担访问压力,当用户要求增加新功能时,MySpace将投入新的数据库予以支持它。账户到达2百万后,MySpace还从存储设备与数据库服务器直接交互的方式切换到SAN(Storage Area Network,存储区域网络)——用高带宽、专门设计的网络将大量磁盘存储设备连接在一起,而数据库连接到SAN。这项措施极大提升了系统性能、正常运行时间和可靠性,Benedetto说。

    里程碑三:3百万账户

    当用户继续增加到3百万后,垂直分割策略也开始难以为继。尽管站点的各个应用被设计得高度独立,但有些信息必须共享。在这个架构里,每个数据库必须有各自的用户表副本——MySpace授权用户的电子花名册。这就意味着一个用户注册时,该条账户记录必须在9个不同数据库上分别创建。但在个别情况下,如果其中某台数据库服务器临时不可到达,对应事务就会失败,从而造成账户非完全创建,最终导致此用户的该项服务无效。

    另外一个问题是,个别应用如博客增长太快,那么专门为它服务的数据库就有巨大压力。

    2004年中,MySpace面临Web开发者称之为"向上扩展"对"向外扩展"(译者注:Scale Up和Scale Out,也称硬件扩展和软件扩展)的抉择——要么扩展到更大更强、也更昂贵的服务器上,要么部署大量相对便宜的服务器来分担数据库压力。一般来说,大型站点倾向于向外扩展,因为这将让它们得以保留通过增加服务器以提升系统能力的后路。

    但成功地向外扩展架构必须解决复杂的分布式计算问题,大型站点如Google、Yahoo和Amazon.com,都必须自行研发大量相关技术。以Google为例,它构建了自己的分布式文件系统。

    另外,向外扩展策略还需要大量重写原来软件,以保证系统能在分布式服务器上运行。"搞不好,开发人员的所有工作都将白费",Benedetto说。

    因此,MySpace首先将重点放在了向上扩展上,花费了大约1个半月时间研究升级到32CPU服务器以管理更大数据库的问题。Benedetto说,"那时候,这个方案看似可能解决一切问题。"如稳定性,更棒的是对现有软件几乎没有改动要求。

    糟糕的是,高端服务器极其昂贵,是购置同样处理能力和内存速度的多台服务器总和的很多倍。而且,站点架构师预测,从长期来看,即便是巨型数据库,最后也会不堪重负,Benedetto说,"换句话讲,只要增长趋势存在,我们最后无论如何都要走上向外扩展的道路。"

    因此,MySpace最终将目光移到分布式计算架构——它在物理上分布的众多服务器,整体必须逻辑上等同于单台机器。拿数据库来说,就不能再像过去那样将应用拆分,再以不同数据库分别支持,而必须将整个站点看作一个应用。现在,数据库模型里只有一个用户表,支持博客、个人资料和其他核心功能的数据都存储在相同数据库。

    既然所有的核心数据逻辑上都组织到一个数据库,那么MySpace必须找到新的办法以分担负荷——显然,运行在普通硬件上的单个数据库服务器是无能为力的。这次,不再按站点功能和应用分割数据库,MySpace开始将它的用户按每百万一组分割,然后将各组的全部数据分别存入独立的SQL Server实例。目前,MySpace的每台数据库服务器实际运行两个SQL Server实例,也就是说每台服务器服务大约2百万用户。Benedetto指出,以后还可以按照这种模式以更小粒度划分架构,从而优化负荷分担。

    当然,还是有一个特殊数据库保存了所有账户的名称和密码。用户登录后,保存了他们其他数据的数据库再接管服务。特殊数据库的用户表虽然庞大,但它只负责用户登录,功能单一,所以负荷还是比较容易控制的。

    里程碑四:9百万到1千7百万账户

    2005年早期,账户达到9百万后,MySpace开始用Microsoft的C#编写ASP.NET程序。C#是C语言的最新派生语言,吸收了C++和Java的优点,依托于Microsoft .NET框架(Microsoft为软件组件化和分布式计算而设计的模型架构)。ASP.NET则由编写Web站点脚本的ASP技术演化而来,是Microsoft目前主推的Web站点编程环境。

    可以说是立竿见影, MySpace马上就发现ASP.NET程序运行更有效率,与ColdFusion相比,完成同样任务需消耗的处理器能力更小。据技术总监Whitcomb说,新代码需要150台服务器完成的工作,如果用ColdFusion则需要246台。Benedetto还指出,性能上升的另一个原因可能是在变换软件平台,并用新语言重写代码的过程中,程序员复审并优化了一些功能流程。

    最终,MySpace开始大规模迁移到ASP.NET。即便剩余的少部分ColdFusion代码,也从Cold-Fusion服务器搬到了ASP.NET,因为他们得到了BlueDragon.NET(乔治亚州阿尔法利塔New Atlanta Communications公司的产品,它能将ColdFusion代码自动重新编译到Microsoft平台)的帮助。

    账户达到1千万时,MySpace再次遭遇存储瓶颈问题。SAN的引入解决了早期一些性能问题,但站点目前的要求已经开始周期性超越SAN的I/O容量——即它从磁盘存储系统读写数据的极限速度。

    原因之一是每数据库1百万账户的分割策略,通常情况下的确可以将压力均分到各台服务器,但现实并非一成不变。比如第七台账户数据库上线后,仅仅7天就被塞满了,主要原因是佛罗里达一个乐队的歌迷疯狂注册。

    某个数据库可能因为任何原因,在任何时候遭遇主要负荷,这时,SAN中绑定到该数据库的磁盘存储设备簇就可能过载。"SAN让磁盘I/O能力大幅提升了,但将它们绑定到特定数据库的做法是错误的。"Benedetto说。

    最初,MySpace通过定期重新分配SAN中数据,以让其更为均衡的方法基本解决了这个问题,但这是一个人工过程,"大概需要两个人全职工作。"Benedetto说。

    长期解决方案是迁移到虚拟存储体系上,这样,整个SAN被当作一个巨型存储池,不再要求每个磁盘为特定应用服务。MySpace目前采用了一种新型SAN设备——来自加利福尼亚州弗里蒙特的3PARdata。

    在3PAR的系统里,仍能在逻辑上按容量划分数据存储,但它不再被绑定到特定磁盘或磁盘簇,而是散布于大量磁盘。这就使均分数据访问负荷成为可能。当数据库需要写入一组数据时,任何空闲磁盘都可以马上完成这项工作,而不再像以前那样阻塞在可能已经过载的磁盘阵列处。而且,因为多个磁盘都有数据副本,读取数据时,也不会使SAN的任何组件过载。

    当2005年春天账户数达到1千7百万时,MySpace又启用了新的策略以减轻存储系统压力,即增加数据缓存层——位于Web服务器和数据库服务器之间,其唯一职能是在内存中建立被频繁请求数据对象的副本,如此一来,不访问数据库也可以向Web应用供给数据。换句话说,100个用户请求同一份资料,以前需要查询数据库100次,而现在只需1次,其余都可从缓存数据中获得。当然如果页面变化,缓存的数据必须从内存擦除,然后重新从数据库获取——但在此之前,数据库的压力已经大大减轻,整个站点的性能得到提升。

    缓存区还为那些不需要记入数据库的数据提供了驿站,比如为跟踪用户会话而创建的临时文件——Benedetto坦言他需要在这方面补课,"我是数据库存储狂热分子,因此我总是想着将万事万物都存到数据库。"但将像会话跟踪这类的数据也存到数据库,站点将陷入泥沼。

    增加缓存服务器是"一开始就应该做的事情,但我们成长太快,以致于没有时间坐下来好好研究这件事情。"Benedetto补充道。

    里程碑五:2千6百万账户

    2005年中期,服务账户数达到2千6百万时,MySpace切换到了还处于beta测试的SQL Server 2005。转换何太急?主流看法是2005版支持64位处理器。但Benedetto说,"这不是主要原因,尽管这也很重要;主要还是因为我们对内存的渴求。"支持64位的数据库可以管理更多内存。

    更多内存就意味着更高的性能和更大的容量。原来运行32位版本的SQL Server服务器,能同时使用的内存最多只有4G。切换到64位,就好像加粗了输水管的直径。升级到SQL Server 2005和64位Windows Server 2003后,MySpace每台服务器配备了32G内存,后于2006年再次将配置标准提升到64G。

    意外错误

    如果没有对系统架构的历次修改与升级,MySpace根本不可能走到今天。但是,为什么系统还经常吃撑着了?很多用户抱怨的"意外错误"是怎么引起的呢?

    原因之一是MySpace对Microsoft的Web技术的应用已经进入连Microsoft自己也才刚刚开始探索的领域。比如11月,超出SQL Server最大同时连接数,MySpace系统崩溃。Benedetto说,这类可能引发系统崩溃的情况大概三天才会出现一次,但仍然过于频繁了,以致惹人恼怒。一旦数据库罢工,"无论这种情况什么时候发生,未缓存的数据都不能从SQL Server获得,那么你就必然看到一个’意外错误’提示。"他解释说。

    去年夏天,MySpace的Windows 2003多次自动停止服务。后来发现是操作系统一个内置功能惹的祸——预防分布式拒绝服务攻击(黑客使用很多客户机向服务器发起大量连接请求,以致服务器瘫痪)。MySpace和其他很多顶级大站点一样,肯定会经常遭受攻击,但它应该从网络级而不是依靠Windows本身的功能来解决问题——否则,大量MySpace合法用户连接时也会引起服务器反击。

    "我们花了大约一个月时间寻找Windows 2003服务器自动停止的原因。"Benedetto说。最后,通过Microsoft的帮助,他们才知道该怎么通知服务器:"别开枪,是友军。"

    紧接着是在去年7月某个周日晚上,MySpace总部所在地洛杉矶停电,造成整个系统停运12小时。大型Web站点通常要在地理上分布配置多个数据中心以预防单点故障。本来,MySpace还有其他两个数据中心以应对突发事件,但Web服务器都依赖于部署在洛杉矶的SAN。没有洛杉矶的SAN,Web服务器除了恳求你耐心等待,不能提供任何服务。

    Benedetto说,主数据中心的可靠性通过下列措施保证:可接入两张不同电网,另有后备电源和一台储备有30天燃料的发电机。但在这次事故中,不仅两张电网失效,而且在切换到备份电源的过程中,操作员烧掉了主动力线路。

    2007年中,MySpace在另两个后备站点上也建设了SAN。这对分担负荷大有帮助——正常情况下,每个SAN都能负担三分之一的数据访问量。而在紧急情况下,任何一个站点都可以独立支撑整个服务,Benedetto说。

    MySpace仍然在为提高稳定性奋斗,虽然很多用户表示了足够信任且能原谅偶现的错误页面。

    "作为开发人员,我憎恶Bug,它太气人了。"Dan Tanner这个31岁的德克萨斯软件工程师说,他通过MySpace重新联系到了高中和大学同学。"不过,MySpace对我们的用处很大,因此我们可以原谅偶发的故障和错误。" Tanner说,如果站点某天出现故障甚至崩溃,恢复以后他还是会继续使用。

    这就是为什么Drew在论坛里咆哮时,大部分用户都告诉他应该保持平静,如果等几分钟,问题就会解决的原因。Drew无法平静,他写道,"我已经两次给MySpace发邮件,而它说一小时前还是正常的,现在出了点问题……完全是一堆废话。"另一个用户回复说,"毕竟它是免费的。"Benedetto坦承100%的可靠性不是他的目标。"它不是银行,而是一个免费的服务。"他说。

    换句话说,MySpace的偶发故障可能造成某人最后更新的个人资料丢失,但并不意味着网站弄丢了用户的钱财。"关键是要认识到,与保证站点性能相比,丢失少许数据的故障是可接受的。"Benedetto说。所以,MySpace甘冒丢失2分钟到2小时内任意点数据的危险,在SQL Server配置里延长了"checkpoint"操作——它将待更新数据永久记录到磁盘——的间隔时间,因为这样做可以加快数据库的运行。

    Benedetto说,同样,开发人员还经常在几个小时内就完成构思、编码、测试和发布全过程。这有引入Bug的风险,但这样做可以更快实现新功能。而且,因为进行大规模真实测试不具可行性,他们的测试通常是在仅以部分活跃用户为对象,且用户对软件新功能和改进不知就里的情况下进行的。因为事实上不可能做真实的加载测试,他们做的测试通常都是针对站点。

    "我们犯过大量错误,"Benedetto说,"但到头来,我认为我们做对的还是比做错的多。"

    MySpace Tech Roster

    January 16, 2007

    By David F. Carr

     
    两栏

    《互联网红色记忆》之谢文:反思互联网

    Posted by 超级苍蝇 on Oct 12, 2007 in 浮尘~

    《互联网红色记忆》之谢文:反思互联网

    关键字:互联网红色记忆 谢文 和讯网 中公网 互联网创业

    视频下载地址:mms://vod.tom.com/fangtan/200703/0322kj.wmv

    ·读书阶段

    文革中做过3年电工,中国人民大学本科毕业后,在中国社会科学院做研究2年。1983年赴美读研究生。

    ·回国创立中公网 1996-2000

    96年回国,是中公网的2位创始人之一,曾任中公网董事,常务副总,CEO并兼联众游戏CEO。

    ·做宽带门户网站 2000-2001

    2000年开始探索宽带增值业务的开发与运营。组建北京宽信网际信息技术有限公司。

    ·互联网实验室CEO 2001-2002

    2001年初,谢文加盟互联网实验室。2002年,出任互联网实验室CEO。

    ·加盟和讯出任CEO 2003-2005

    2003年09月加盟和讯网出任CEO,并成功打造了博客财经门户。2005年11月16日其宣布辞职。

    ·加盟阿里巴巴集团出任雅虎中国总经理 2006

    2006年10月17日任雅虎中国总经理,11月27日离职。

    [访谈精彩语录]

    · 他说起当年的互联网: “我们那时候有巨大的讲座,我们成功发了一个600多K的东西到欧洲去,解决了若干难题,大家都鼓掌。”

    · 他说自己是“乌鸦嘴”,但是善于挽救垂死公司: 我们这代人,唱崔健歌,看王朔小说,永远不满足现状,永远要变化。所以特别适合耕耘过的土地再重新耕耘一下。我很善于救一些垂死的,或者遇到重大问题的公司。

    · 他“赖着互联网”不走:我这么大岁数赖着不走,就在于互联网的魅力。我如果现在换在别的行当,马上就老十岁,心态老十岁。

    [编者按] 生在红旗下、高考、转学、分配、留学、归国、出任互联网公司职业经理人、离职……谢文的互联网征途每每和时代相交,所描画的轨迹都彰显出他足够的个性。他回国之后,在一片空白的互联网领域创办了中公网,“悲情”离职以后加盟互联网实验室,2003年09月加盟和讯网出任CEO,并成功打造了博客财经门户,两年后他说“自己已不适合带领和讯团队”而宣布辞职。这种种故事、传说渐渐使他在业界越来越具有标本式的意义。如果要从“网事”中选出一个亲历历史、见证历史的人物,也许没有人比“谢老师”更合适。

    3月底,TOM科技邀请到谢文担任《互联网红色记忆》系列访谈的第一位嘉宾,“共忆网事”。

    [访谈实录]:

    主持人: 各位网友大家好,今天TOM科技新访谈特别节目,互联网红色记忆的第一期。已经开始了,我们今天请到的嘉宾是互联网的资深人士, 谢文 老师。请 谢文 老师跟我们各位网友打一个招呼。

    谢文: 网友朋友们大家好。

    主持人: 谢文 老师大家很熟悉了,我们直接进入正题。我们先 从谢文 老师个人履历说起,谢文在进入互联网行业之前,经历是很丰富的。在人大本科毕业之后,在中国社科院做了两年研究,83年赴美就读哥伦比亚大学研究社会网络,92年开始从事投资咨询工作。 谢文 老师,您从事这么多行业,经历如此丰富,是什么促使您进入互联网这个行业?

    第一阶段:从“触网”到创办中公网

    谢文: 进入互联网之前经历丰富,是因为那个时代动荡,当然上大学是自己选择的,出国肯定是自己选择的,然后做互联网也是自己选择的。我接触互联网比较早,从83年开始接触,到了90年代初的时候“WWW”的出现,看到互联网大规模商用走向大众社会的可能性,就动了心思,觉得经过这么多曲折的人生,现在有一个机会参与到影响人类社会的一次大工业革命这么一个实践当中,想尽自己所能做点什么。

    主持人: 当时您觉得可以做些什么?

    谢文: 应该是从概念上很清楚,就是直接诉求,当时还不是很多,直接诉求最终用户,给网民提供首先是信息服务,然后是其他的应用服务,大致的方向是这样的。具体的因为当时也没有什么很好的榜样去学。

    主持人: 离开华尔街到中公网之间,在美国从事过互联网行业吗?

    谢文: 应用过互联网,主要是从数据应用,建立数据库,包括信息传播,(主要是)网上网民的行为,更多是从观察和应用角度,没有从商业角度。

    主持人: 更多偏向于观察,还是应用?

    谢文: 应用。

    主持人: 中公网哪一点吸引了你加入了这个公司?

    谢文: 是我创立的,和我朋友一起,他出钱我出力。当时没有互联网信息服务公司,没这个行当。我个人回国以后,想得很清楚,希望做互联网增值服务,也就是信息增值服务这块,所以就和同学一起注册这个公司,自己设计战略,自己做。因为自己当时肯定是很神秘,条条框框比较多,所以找的是信息产业部的数据局合作,所以我们名字用了CHINANET的名字。

    主持人: 后来怎么引入海虹控股的?

    谢文: 就是收购的,有现在海虹控股大股东我们一起做的。

    主持人: 这个过程中您觉得您碰到的最大问题是什么?

    谢文: 当时肯定缺钱啊。

    主持人: 钱是最大的问题,有其他方面的问题吗?比如管理方面的问题?

    谢文: 
     
    那些问题还不太大,公司自己创立的,可以按照自己的想法,自己搭班子,组队伍,定方向,那些就是摸索实践,最大的困扰还是资金比较不足,(由于)种种原因,大股东也不去做融资,所以由于资金不足,虽然我们自己做得还马马虎虎,但是错失了一些当时早期迅速膨胀、把公司做大的机会。

    主持人: 您刚才也提到大股东可能对于融资并不是特别热衷,但是您在这方面还是有很深的了解和人脉的。您当时是不是很尽力地做了一些融资的事情?

    谢文: 我不能在大股东不同意的情况下做事情,但到了99年底融资已经蔚然成风了,所以大股东也勉强同意了,2000年初我们又谈了6千万美元的融资,现在来看的话,也是最大的一笔(融资),何况中公网97、98都是盈利的,本来可以做得很有意思的,但是种种原因吧,没完成这个事情。

    主持人: 您觉得没有完成最大的原因是什么?

    谢文: 理念,观念上的差别。如果把互联网作为一种炒作题材,概念去做资本运作,那么这个公司大小无所谓,越小越好,如果题材能卖钱的话投入越少,赚得越多,如果你是喜欢互联网的,一个企业家的思维,想把企业做大,可能挣钱更多,从现在看历史已经证明了。但是当时这么说,不管有多少观念,苦于没有实证来证明,所以只能拿股权决定。

    主持人: TOM网友相对比较年轻,可能很多人不是很了解这段历史。

    谢文: 没关系,这种事情还在大量的发生。

    主持人: 当时谢文离开中公网在互联网业引起了轩然大波,我们注意到,您这几年多次提到做一个大的能长期稳定发展的互联网公司要具备的几个条件:第一要有规范的结构和机制;第二在财务上具备一个基本的条件,就是按您说的千人千万/年的投入;第三个就是三年时间。您觉得在您的做好互联网公司的标准里面,造成不能够落实最大的冲突点在哪?

    谢文: 我想还是最基本的投资者,或者是创始人这个队伍,大家理念要一致,也就是说,比如我推崇的这一套不是我发明的。这个机制大家要么接受,要么干脆就不接受,怕的就是表面接受,实际上不接受。那么随着公司成长,你会发现,你是喜欢互联网,真正想把公司做大,而另外人想题材就够了,拿题材炒楼,拿资本去挣钱,如果这样的东西,一开始表面是一致的,但是走来走去的话,就发现那种不可弥补的分歧,那个时候已经不是你的业绩,你的市场占有率,品牌这些东西可以弥补的。你越做得好,别人可能意见越大。我觉得这是至关重要的。

    主持人: 我们刚刚提到理念要一致的问题,我们今天是通过回望历史看现实,能够有所借鉴,刚才 谢文 老师提到在这种理念分歧之下,股东或者股权发挥“作用”,这样的事情在今天也频繁发生。
    谢文: 还有股权问题,比如我做互联网,你也做互联网,但你想象的就是一年之后上市,而我想的是三年,以三年为周期去做,这种也一样,这种心态是从VC层,投资者角度,这种情况在公司时时刻刻发生,有的时候不说出来,但是他们做事情的思维都在时时刻刻反映,这种急功近利的心态,对互联网不健康应该负最大的责任。

     
    主持人: 以您的观察,当时存在的这种问题,或者普遍存在的这种分析,现在这七年,您觉得这个情况有变化吗?有好转吗?或者是更加恶化了?

    谢文: 应该说没有好转,应该是更恶化了,如果第一批创业人,也就是96年到97年这一批,我们今天看到互联网主力公司,包括这一两年上市的公司,种子都是99年的,甚至更早,也就是说在当时还是有相当的投资者,相当的创业者自觉不自觉地走过了一个相对漫长的周期,到今天相对一个健康的状态,从2003年后的第二批,包括美国互联网复苏了,到今天为止我们还没有看到一家正式的互联网公司上市了,有个别SP上市了,但是他们不是互联网领域。到现在为止我想业内应该承认,没有一家公认的相对成功,相对让大家信服的,让大家领先的2.0公司,大致上像样的,换句话说就是全军覆没,这里面应该说有03年开始的SP那一拨以后,包括咱们现在新从业的人当中,急功近利的心态,不懂装懂,想炒近路,不认真地总结我们第一轮的失败的教训,或者是成功的经验,造成了成功率为零,第二批到现在为止成功率为零,哪怕流量进了前十,前二十,规模化的盈利,创新的模式,让TOM这样的公司看了都很觉得有学习的必要。看到今天这么一种现状,应该说这就是我在不同场合,不断地说,中国互联网处在一个十字路口,或者是中国互联网有可能退化为中国式的传统产业的那套玩法,那么这个产业可能就进入一种亚健康状态,或者不健康状态。

    主持人: 那么非但没有好转,反而越来越恶化,甚至开始出现一种像传统产业那样的趋势,原因是什么?

    谢文: 原因是互联网已经证明了,全世界范围内证明了互联网是一个朝气蓬勃,而且有暴富机会,这个行业对全国影响重大,侵略性,很多传统方式的人开始上来了,现在很多投机的,或者是带有侥幸心理的,或者半懂不懂的,拿做饭馆、做工厂、做商店的那些方法来做互联网。这个已经被证明了的产业冲进来了大量的各色人类,所以噪音比较大,杂音比较大。加上现在已经成为产业主流的很多公司,由于种种原因,商业上的考虑、江湖上的考虑,等等没有很好的起到行业的中流底柱的那个作用。当然不是阴谋说——这样更好,让一个新的都起不来,我们那块地盘不至于丢了——应该不是,开玩笑。我想应该是整个产业相对来说杂音过大,各色人等,变成一个闹市。

    周雪峰: 你给这些人建议是什么?
    谢文: 我建议就是若干人组起来一起做,好好的,他们每个人都有一套说法,其实99年,2000年已经见过无数了,但是这可能也是客观规律,像这样的新兴产业,门槛高一点,成功率大概就是千分之一万分之一之间,确实有99.99%去烘托0.001%,如果大家都有悟性,都有理性挺过来人的参考,那成功率不就提高了吗。成功率提高了就不是新兴产
    业,所以我们需要垫脚石。

    主持人: 这么多人心甘情愿做垫脚石可能是因为他们没有吸取前人经验教训的心态。

    谢文: 我认为他们都没有这种心态,当然很大一个差别就是资本主义造成的,如果资本也鼓励这一套,看好这一套,你说小孩闹吧,他一般没本钱,怎么还有人给钱他们闹呢,那就要问问那些给钱的没有想清楚。

    周雪峰: 就是整个产业导致发展方向或者是急功近利多一些?

    谢文: 一定说谁是百分之多少的责任,这个不好说,到2003年中国互联网和美国互联网相比,中国不输,并在局部是领先的,无论是网络媒体模式,广告模式,IM,我们其实在局部还是有创新的,比如像网络游戏,到今天IM还是一个独立平台商业模式,腾讯就把它做得有色有生,比如SP,利用无线平台做得很大规模,比如TOM,这在美国互联网界也是近一年才悟出来。他们是后来者,比如B2B,像阿里巴巴,这个在美国找不到对应的模式,但是怎么着就变成04年这一拨,原来是一些新起来的社区式的东西,后来被归纳为web2.0这么一个名字,这一批美国前二十个网站,至少十几个都是这一批公司,前十名大概一半大家都能张嘴说出来的,MYSPACE等等,中国就没有相当的这么一个,比如流量跟TOM差不多的——不要作弊,咱们说的真的流量,或者是成长速度明显快于你们的,找不到,连接近的都没有。钱投得不少,甚至靠这个成名的都有若干位了,就是成功的没有。甚至现在还有因这个事被关的。那一定是什么地方错了,但是不能怨这个行当没有钱,我今天看到一篇说是06年中国互联网这批投了6000多万美元,21家公司得到了钱,钱不少啊。比我当年好多了。比我做任何公司都阔多了。肯定不会是百分之百的不成功,总会有一些相对健康的,因为还在成长过程当中,现在不好下结论,但是你看不出来,这个就需要总结。但是不是新的一批,我现在的标准就是在大的创新,大的发展上跟上世界的潮流,甚至是领先,或者是各有千秋。现在我们中国有个别不错的公司,但是总体来说,大的不想做,就吃自己现有那口,中的不敢做,资源不够,小的不会做。既不想做,又不能做,又不会做,所以我们现在是这么一个混沌局面,幸亏外国这些大的互联网公司,认为在中国是本地化步伐太慢,给了我们一定时间,不然有可能,外国公司进来以后就把你的江山给拿走了,这个很现实。

    主持人: 您刚才提了没有创新的现状,这个还是跟在这个行业里面进入者和从业人员的心态有关,其实您刚才也提到,是不是每隔一段时间,比如三四年,四五年,可能这种很新的人,大批进来,他们就觉得进互联网是不需要从业经验的,你刚才提到很多新进者没有从业经验的,可能有一个误区,互联网既然是一个新兴产业,这个新兴产业可能就是给了我这样一个没有经历的一个机会,这样的心态的人可能每隔几年就会反复出现的?

    谢文: 这个是肯定的,美国也是如此,很多大学生没毕业就创业。但是大环境上,美国大的商业环境是成熟的,不需要专门去学。像美国公司,第一轮最晚到第二轮融资的时候差不多都引入经理人,这些行当还是由当年那些人掌控的。我们企业治理机构,公司管理,美国不存在,没有任何互联网公司是因为这方面而失败的,而中国这个失败是相当的原因。

    主持人: 是不是并不是怪这帮孩子不懂事,而是因为他们没有人引导他们。

    谢文: 不,80后还需要人引导吗?你们不引导我就不错了。我觉得应该有,后来者有他的优势,能蔑视常规,有创新,但是不能面对常识,各有各的问题,大企业有大企业的问题,从来没过事的年轻人主要是学习问题,这个世界上没有那种革命就是说不需要花力气,不需要好好建设,随便一比划你就成了英雄,就会发大财,这个社会很残酷,商场竞争很残酷。

    主持人: 刚才您已经讲过大公司的问题,其实投资者也有投资者的问题,我说一个猜测,现在很多像我们从事媒体的,经常看到一些报道,很多分析者,很多观察家他们也这样说,普遍认为风投投资的成功概率很低的,其实就需要一些垫脚石,或者是炮灰,这些是不是投资者起的,我们估计是不好的作用,甚至是坏作用,他们需要一些垫脚石。

    谢文: 没有一个VC说我投的时候就准备9个失败一个成功,你追求的是我投每一个都成功,结果是9个失败,一个成功,这个是事实,如果你什么就准备投,蒙一个是一个,那就一个成功都没有,这个其实在于心态,比如web2.0现在都改叫新媒体了。什么都不着边的事,说我们是新媒体,化个妆又来了,但是还是在ABC的问题(上没想明白),你吃哪个市场,你怎么和现有的演员竞争,你怎么做大,你凭什么,说什么,你原来是web2.0牌子卖砸了,我们改叫新媒体,这还是投机取巧的心态,这个心态是很可怕的,这个问题是没有办法的。

    主持人: 您刚刚提到新媒体这块。其实很多的WEB2.0的公司会在两种状态,或者是两种界定中摇摆,就是媒体和社区。您觉得WEB2.0能做媒体吗,应该是偏向于社区,还是媒体?

    谢文: 像广播、像TOM一样做个频道放文章大家点了读,这叫媒体还是博客,社区式的,现在加上音频,视频各种东西,其实这个并不重要。应该说你叫web2.0就是对以前的一种行业、产业划分结构的一种颠覆,你现在叫新媒体,也是对原有的那种模式划分的一种颠覆,你能说一个社区没有媒体的东西吗?不可能,北京这么大个社区几百家媒体总是有的,也有很多新型的媒体在出现,你说是媒体,现在大家不弄个博客,播客了,这个本身不重要,关键是这个定义之后,随之而来的具体的战略,实施能力,和操作的技巧。没有这个说什么都是瞎说。

    主持人: 刚才我们做了第一段的回望,这个回望是 从谢文 老师接触互联网到2000年的中公网的经历谈起, 谢文 老师能对这段回望,对应到现实的做个经验总结,我的感受就是您刚才谈了两点,就是理论的问题,和心态的问题。

    谢文: 应该说每个人的经历不一样,也许有人应该讲我的技术能力,有人说我要注意市场能力,有人说要注意公关沟通能力,但是我是力图概括的时候把它和我个人的经历分开,是从一个角度看。假定我们今天谈的主要对象是准备进入这个行当,或者是创业的年轻人,我觉得首先要有一个大的抉择。就是你要以做好事,做有意思的事,还是说只要为了发财就可以不择手段。Google有一个信条叫不作恶,我想它不是随随便便的,也是经过认真讨论的,因为互联网把整个社会搬到虚拟空间来了,大家自觉不自觉在某种引诱,或者是压力上都会有一个选择,有的时候自觉不自觉滑向了媚俗,流氓、做假、急功近利,如果这样的话,即使你上市,成了亿万富翁了对我来说我毫不羡慕,我也不认为那是一种成功。相反互联网界公认是做得比较好的,成功的企业家的,比如丁磊,李彦宏,还有若干人,我觉得他们首先是有底线的,做自己喜欢做的事情,按照一个社会能够接受的方式做。对投资者,对员工,对用户都是负责任的。能坚持这一点,我觉得挣一百万也算成功,挣一个亿也算成功,哪怕一百万没有挣到,有这段经历,对你来说人生就不是负值。SP有多少个发财了,你采访过多少过成功的SP到这里来可以侃侃而谈,主流社会给用户带来长期有效的贡献有多少?没有吧,大概也就是这几家,TOM、空中、网易等,就是几家比较大的,因为他们有比较独特的知识产权,娱乐,剩下的不就是坑蒙拐骗,但是有不少人发了一笔财,有做互联网的,还有一个人最基本的价值观的判断。
    第二阶段:北京宽信网络信息有限公司

    主持人: 刚才谈了 谢文 老师就是中公网的经历,我记得你离开中公网的时候,你当时说绝对不会离开互联网,梦想一直专注于门户,而且当时跟几个重量级对象洽谈一个比中公网大得多的事,后来创办了北京宽信网络信息有限公司,当时怎么想到要做一个宽带门户网站?

     
    谢文: 这个比较复杂,我因为当时去了香港,那里有一个网站,我在那里呆了好几个月,只不过后来发现好像跟我想的不一样。所以这才回到北京做了这个网站,觉得找对了一个方向,社区利用宽带,多做一些多媒体的事。想找钱,但是当时是2000年初是资本市场最坏的时候,所以尝试了几个月,发现没有人听得懂也没有人愿意听,也没有人愿意出钱那就算了。

    主持人: 您已经意识到当时互联网渐入低潮的形势,为什么还要下决心尝试一下?

    谢文: 我以为别人看到我的操作能力,或者叫做预见性,像买股票一样,真正发财的都是在买低卖高,低的时候入场,将来收益最大,但是这也是问题,不跟风。所以你看我那个时候想做的事情到今天还是热门,社区化不就是社区这点事吗。所以有我个人的问题,我这个人不愿意求人,不愿意游说,不愿意把自己包装起来,也不愿意附和别人那些半通不通的话,那么就是这样。

    主持人: 当时钱都是您自己投的?

    谢文: 是。

    主持人: 后来没有继续下去是不是也是钱的问题?

    谢文: 你说我再投也投得起,问题那就不是做互联网了,就变成赌气了。现在包括很多有钱的人,融资到一定程度,也不融资了,这是有限责任公司。李嘉诚很有钱,李嘉诚天天在融资,这个是两回事。这个算一个小插曲,等于没启动就收了。

    周雪峰: 现在来看还可以坚持下来吗?

    谢文: 我觉得坚持不下来,要做不要做三五个人,要做就做得有声有色。这种故事很多,坚持下来也未必,因为你资源太少,资源太少的话,包括员工的士气,等等。所以应该是收的是对的。

    周雪峰: 刚才您谈到,如果当时坚持下来,可能愿意讨好别人,如果在这方面做妥协呢?

    谢文: 当时没有人买的,我是希望有一个比较好的基础,因为整天把主要精力放在融资这件事情上,公司就会有问题。

    周雪峰: 公司可以请一个人做这些事。

    谢文: 00年的时候网易、新浪都在叫卖,我这是上市的,都居然没有人买。网易七千多万要卖,新浪要一个亿要卖,手里一亿多,少的钱买多的现金,外加一个公司都没有人买。

    主持人: 当时做互联网的产业背景和面临大环境,近半年也有一种说法,就是WEB2.0在中国也进入寒冬了,前一段时间您也说2006年互联网就是令人失望的一年。

    谢文: 您知道99年的时候中国几百万,没有象样的人投放广告,和今天一亿三,可能一亿四千万网民了,巨大的产业模式,大家公认,现在不承认互联网是个产业还有,他们是出于其他考虑,咱们就说收入规模养活的人,这个时候钱有,很多人在投,VC都在找项目投,不是因为互联网不敢投了,是因为没有找到好项目,是认识的局限性,不是那种泡沫破碎,完全是两回事。现在我觉得如果大家没有做,没有人给钱,从自己身上找原因就好了,比如我,我现在就说我不行,我不太会游说,我这个人有点自负,我就承认,我绝不说资本现在没有这个实力,不投。绝对不是这回事。
    主持人: 七年来您在这点上是没有变化的。您不是始终站在互联网发展的前沿吗?

    谢文: 是啊,我自认为。

    主持人: 
    我们知道很多网民,很多从业人员也这么认为,您的思维总是能跟得上互联网最新的发展。

    谢文: 我的意思就是我定义发展,不叫我跟得上发展。

    主持人: 其实从创业角度,匹配的角度上,您怎么没有创新?

    谢文: 那没有办法,跟王朔一样,人都长成这样了,没有什么办法。我再把的缺点再改改你们还有活路吗,每个人都有自己的弱点,扮演自己能扮演的角色,有机会我就上,有人给我送钱我就干。

    主持人: 其实假如对比当时的2000年到01年这一段,对比现在,比如06年下半年,07年上半年这一段的话,虽说当时的VC是不愿意投,现在的VC是找不到合适的可以投。环境其实大不一样了,现在整体条件已经比当时要好得多了?

    谢文: 现在你不会挣钱不可以赖市场,不可以赖网民,也不可以赖政府,还是赖投资者,现在的环境比00年那一拨要好上十倍不止。

    主持人: 现在很多投资者觉得web2.0整体不好,或者大家做得不好,那么现在想进入创业的人怎么办?

    谢文: 一个是改名字,不叫web2.0叫新媒体,这叫战术,剩下的就是认识到自身的能力,是不是已经具备了在中国这块土地上创业的基本条件,基本素质你有没有,现在中国互联网土地,不管怎么样,你是耕耘过一遍了,不像我们那个时候,一片处女地,只要敢撒这种,种不种庄稼很难说,现在差不多要重新定义市场,你要在现有的存量中夺取一块。包括像TOM这样的庞然大物要想着跟别人竞争。再有一个的话,成功的概率,成功的周期、时间,都会比那个时候长。更何况还有大个的公司,比如TOM之类公司的打压,若干不认同,这样的事情。所以这其中的大部分人,或者不具备创业的基本条件,或者是有一定的想法,有一定的能力,但是资源太小,我老劝他们三五个公司,你们做得事差不多,就合起来,每个人股份少一点,但是至少成功概率可以高几倍,最后一个百分之一的大饼也很大了。但是没有办法,年轻就有这个本钱,年轻就有这个优点或者是缺点,他不死一回两回是不信的。

    周雪峰: 我有一个感觉,您刚才说可能不会做一些妥协,但是你也提到可能在我们发展过程中间,03年开始没有一些创新,不像以前有IM,现在这种现状,像您这样的有经验的人又不出来。

    谢文: 现在我也出来,但是你也得看我年龄大了,精神上是应该受这个苦,但是体力上受不了,再一个我觉得的确启动的规模太小,成功的概率小太多。一个很好的思想,一个很好的创意,由于资源不够,因为好东西,一般都比较复杂,比较复杂需要成长的速度慢一点,所以就需要时间长一点。如果你在黎明之前就倒下了,这个也很遗憾,所以我还是,刚刚提到过,三年一千万左右可以做成一个好公司,并不是开张第一天要放一千万存着我说整个三年投入要达到一千万总规模。年成长率可以保持到百分之百左右,可以做到比较健康,比较有实力,比较有发展潜力的公司,否则的话半大不小。

    周雪峰: 如果现在有这种机会,你会从哪些方面来做。

    谢文: 我做的公司历史上来看,绝不重复,再一个没有机会,我喜欢那种不确定性,概率上新的东西成功率大一点,主要是创新效益,再有一个的话,我不愿意说,因为web2.0大家都有各种各样的了解,但是整体的创新,大的概念上,互动性、个性化、多媒体、跨平台,这个大方向谁也逃不了,现有的公司可以看到,但是他们包袱背得比较重。比如TOM下市了,上市有原有的阵容打乱了来,就会做得鸡飞狗跳,总的方向应该是这样,如果现在有谁做一个TOM,出来做一个eBay,做一个新浪,一般不太可能。

    主持人: 您未来的去向会创业,还是去一个新的大公司?

    谢文: 一切随缘,我完全没有历史负担,按照一个本本,大家都是好人,好好干,不要自相残杀,但是从我另外一方面的经历,我很善于救一些垂死的,或者遇到重大问题的公司,这个我倒没有一定的规矩,但是没有一定要扬名立万,只要好玩,价值的体现,对人家有用,做的事是我喜欢的,就行了,怎么都好。

    张原: 你刚刚说了,你跟王朔一已经长成这样了,但是现在互联网已经耕耘过一遍了。

    谢文: 你知道我长成哪样吗?我那样就是永远不满足现状,永远要变化。所以特别适合耕耘过的土地再重新耕耘一下。

    主持人: 刚才谈了 谢文 老师第二段互联网的经历,2000年到2001年我们回望了一下,给现在想进入这个行业,想创业的人给了他们一些建议和看法,其实刚才还提到了一点,也说了VC(即“风险投资,下同”)的问题,大公司的问题,其实说实话,他们其实也有自己的难度,现在的创业者首先想自己的问题,但是大公司和VC,刚刚您也提到。俗话说天塌下来了,有个高的顶着,大公司也有很多的责任,VC其实也有,创业者需不需要检讨自己的问题,像您这样言论领袖人出来,来教育教育VC。

    谢文: 谁说我是言论领袖,有哪个VC听我这种乌鸦嘴到处乱说。(笑)也有特别是外国的VC找我做咨询,或者做经济调查什么的,也有。我觉得这个事情不是考虑噪音舆论,因为这是一个商业行为,说穿了这里没有价值观念,道德在里面,完全是道德的选择,逐利行为,就像我喜欢现在的透明的、规范的,企业机制,不是我高尚,或者说我是书生,不是。这是在人类发展到今天,大家血的教训,最后寻找了这个机制,是大家付出代价最多的一个机制。家族企业也有很成功的,但是那个成功概率比现在企业支持下成功概率小十倍不止,这个道理还用VC听我说,这个就是优胜劣汰,谁走对了,就成功了。

    主持人: 也就是说VC不缺乏教育,而是缺乏时间的推动,市场的推动。
    谢文: 我们互联网发展这几年整体显得不那么快,大家都应该比较理性,客观地分析一下有哪些问题,是谁的问题谁认帐,自己改正这个问题,为了这个产业的发展,说穿了就是为了大家发财,现在业内不好的风气在于不能讨论,都是自己对。不能总结,包括整个业内很少能够找到那种不心存顾忌可以比较敞开的,认真地讨论问题的环境,平台。

     
    主持人: 是不是只有中国互联网环境是这样的?

    谢文: 其他国家咱们不说,咱们只跟美国比,跟美国差得不是一点半点,美国学术界,美国的行会,专业团体,像就2.0这一拨下来,美国出了多少书,弄出了个十大周刊,年度人物,什么“地球是平”的,“长尾理论”啊什么的,而我们不能说,我要开句TOM的玩笑,我估计TOM主持人脸都绿了。我昨天跟网易说,你别猜想这个那个,你专找一个业内的人猜想网易,这个不是坏事,要能够自己跳出来看。花钱捧自己,自认为中国是互联网之父的好几位,都去争这个,都是认为人家给你提一点建议,提一点批准,就是心怀不轨。这样的话这个产业一定会完蛋,其实中国互联网业在中国各行各业当中相对来讲应该是最健康的。

    主持人: 现在还依然是这样吗?

    谢文: 如果从绝对值上来说我认为是这样的。但是有一个危险,可能向这个平均水平靠拢,中国这十几年,听说过中国有哪一个软件公司在纳斯达克上市了,没有,而中国互联网公司是成批的,我今天看腾讯的年报,腾讯是28亿,今年收入10个亿的利润,好像是整个中国电影业去年票房总值是28亿,腾讯一家等于中国整个电影业,中国电影业有多少个啊。像TOM整个的季度,整个利润率都高于比如联想利润总额,其实还是蛮不错的。什么期权,审计,季报,年报,做市场,做品牌,这些做法都是中国互联网公司给中国带来的,现在正在向外渗透。有那么多年轻人,这么多我们管它叫边缘人士,在互联网这个平台上演出了很多有声有色的喜剧。还是很骄傲的,总体来说,至少我不后悔,我做互联网十几年,但是正是因为投身这么多年,很喜欢互联网也为互联网整个行业骄傲,所以反过来就很愿意遇到有机会的时候,表达一下自己的忧虑。谈谈自己的看法,所以这是相对而言的,你不要抓我的话,完了,沉沦了,没这个意思,凡是敢每天讨论自己公司问题的,自己产业问题,都是最健康的,反正说自己业务好得不得了,这个公司就离死不远了 。 只有整个产业健康了,空间打大了,才有个人的机会,这个事情说到底还是自私的行为,别装出一副大公无私的样子。

    主持人: 是不是中国特有的互联网行业,还是前面提到的受到了某些产业的传统的影响。

    谢文: 中国是一个正在走向市场经济,正在改革过程当中的一个几千年的农业社会,这个历史包袱,我们既然在中国历史土地上,赚中国人的钱,肯定要受他的影响,好的影响有,坏的影响也有,中国市场大,年轻人多,这是好的,不好的家族式,坑蒙拐骗,一人独大,急功近利。还有很多是属于没意识到。因为早期没意识到,其实国外的经验,几十年下来,他们已经知道这条路了。

    主持人: 您说的这些,是不是您刚才提到的中国互联网整体的健康程度,如果受它绝对值在下降的原因。

    谢文: 总原因或者叫大背景,每个公司都有自己的故事,但是大背景是一样的。

    主持人: 但是总的来说,未来呢,还会继续往下滑吗?

    谢文: 如果大家还没意识,互相拆台互相推诿,不创造健康的环境,这种机制,我觉得每个公司只去自保我不觉得一个公司可以推动一个产业,或者一个产业可以推动一个国家,这是不现实的,大家都在自保。SP明摆着的例子,你觉得你怎么样,谁也好不了,弄不好,整个市场在萎缩,或者整个市场的停滞,或者是低速成长,这是最现实的,在整个市场萎缩的时候,你不能想象一个公司可以立马奔腾,扬尘而去。如果产业是发达的,互联网每年以市场份额50%的份额在扩大,从里面分点大家也是比较舒畅。

    主持人: 您刚刚提到是不是互联网产业正在传统产业化的一个后果呢?

    谢文: 我觉得市场是大得很,而且我愿意说,你不可以改变中国,不可以改变环境,那个是巨大的事,我只能说自己在这方面可以做得更好一点,个别公司有个别公司的做法,然后整个产业大家应该也别说团结起来,我估计永远团结不起来,但是至少可以作为媒体,应该呼吁,有一个健康的讨论问题的氛围。有一个相互交流的平台。免得大家死得糊里糊涂不知道怎么着就死了。

    周雪峰: 有没有想过在市场上进行一些推动。

    谢文: 凡是就这个话题找我采访我都拒绝了,但是我从来不主动去找媒体,我要发言,我有话想说,跟找钱是一样的,特没劲。
    要回到创业之初的那种心态

    主持人: 也就是从现在来说,整个中国互联网产业的发展,如果想刹住往下滑的势头,可能就是两个方面,一个方面是每个公司,每个从业者,可能更多是要从自身出发。

     
    谢文: 要总结,要回到比如创业之初的那种心态,我们一无所有,我们老说我们这代人,唱崔健歌,看王朔小说,而不是到后来整天自负得要名,或者是自己封个山头,自己弄个公关部,在外面投稿子,吹自己,像这样的事情,到这个状态就不能创新了。

    主持人: 也就是说第二件事情就是产业整体的事情,不是哪个个体可以影响产业,这个时候就是媒体的责任,也是我们的责任。

    谢文: 对,其实这个业内说大也不大,三五十个人,加上四五十个平台,基本上就主导潮流了。问题是谁来做?

    主持人: 前段时间您也提过,吹吹自己,其实这里面可能有一个现在从互联网现状上,有一个很大的问题,就是PR这种,可能是中国特有的。

    谢文: 国外也有,但是整体上没有像咱们做得这么恶心,这么肉麻,另外有的时候有种黑社会的感觉,没地方可讲,有钱能使鬼推磨。所以一说到PR就头疼。超出一般的常理。

    周雪峰: 看到这样的现象是什么样的心情?

    谢文: 不,反过来说,我认为互联网产业仍在发展,只不过可能有一个苗头,如果大家不认识,不有意识约束自己,也许还是在发展,但是没有意义了。不要玩到一定程度,问你到哪里工作,说我在互联网公司工作,别人会说你怎么还在互联网公司啊。但是现在更多的比如SP这些,现在没有再以干那种事为荣的,对社会影响力不好,最怕的是我们跟互联网工作跟在哪工作差不多,就是混,就是没有一点精神寄托,没有成功的喜悦,非常风险的刺激,我觉得做互联网没有那么多增值。那就没意思了。

    主持人: 刚才您提到,现在PR(即“公关”,下同)很坏的现状,然后刚才您也提到给人一种黑社会的感觉。其实最近有很多人在讨论互联网江湖的问题,您觉得这样的问题是不是已经大到了已经不是战术的负面问题,已经大到影响整个互联网产业,或者说至少影响到现在2.0发展一些企业的状况。

    谢文: 我觉得江湖还不至于致命,真正的在于网络媒体,如果网络媒体讲行帮,讲赚钱说话,那么这个网络媒体本身的公信力、口碑,从长远来讲就是停滞,或者下降。我们互联网网络媒体是有光辉历史的,不是我个人,我说的是新浪、搜狐、网易、TOM,这样的。早些年,很多大事,孙志刚事件,宝马车,很多事情,影响到了,我觉得跟现在“以民为本”,网络媒体有可以非常骄傲的历史,小到我们科技频道,或者是互联网媒体,起到好的推动作用,或者是好的政策,当年这些上市公司上不去。但是这两年,我跟陈彤也讲,可能是受经营的压力,我们网络媒体有一种“枪手”的意思,有一点只说好话,同质性高了一点,各有特点少了一点,比如一个网站整体的成长,PV的增长是广告收入增长的现行指标,所以我觉得要说,说起来最明显的,最常见的还是这种屈于经营的压力,广告的压力,甚至等而下之是请你吃饭,谁请你喝茶,那点小好处,谁送你一个小礼品,去摆平事情,指鹿为马,颠倒黑白,这一点上是比较可怕的。因为互联网最初是以信息的廉价、有效的、大规模传播为杀伤力,比别的东西都太方便了,太有穿透力了,如果我们都变成那种我们管它叫世俗化,或者是商业化,我说的是贬义的商业化,我相信有一天会有别的东西取而代之。

    主持人: 是不是意思就是越来越江湖化了,就是对利益的追求,或者是背后利益追逐利益的状态。

    谢文: 当别人都很江湖,很急功近利的时候,你兜里有钱,你就做一些反其道而行之事,像你这样的大公司,再流氓也还是不敢,比不上那些人没有负担,既然流氓不到哪儿去,毕竟我们还有些钱,毕竟有大的平台,毕竟大的平台上可以吸引很多优秀的人才,因为现在市场上短缺的是正人君子,不缺流氓。

    主持人: 从商业、市场的角度来看,互联网江湖方式还是有望刹车的。

    谢文: 也是,反正现在我遇到场合来了就鼓动。我知道很多人假装点头,但回去拾那十万块钱。结果就一天一天重复。我觉得谁做第一个那时候会有加倍的回报。
    第三阶段:互联网实验室

    主持人: 刚才我们是对着 谢文 老师2000年到2001年这段经历,通过这段回望,借鉴了现在这段相对而言还有一点相似的时期,下面01年到02年这段时期是泡沫破了, 谢文 
    老师做互联网实验室的CEO,是不是泡沫破了以后, 谢文 老师又重新或者是暂时又去做研究了。

    谢文: 那个是偶然的事件,因为方兴东是好朋友,希望我参与一下,我书念得多一点,但是到那个时候,我们01年的夏天的时候,博客网烧钱是有历史的,那个时候等于是给朋友帮忙就去了,倒不是一种战略选择,深思熟虑,战略上我没那个选择我完全做事都是随遇而安,人家需要我,觉得我能做,我在美国也做过咨询,研究反正就是那一套,就去了,就去帮忙了,没想到低潮时期这么长,一帮还帮了两年,还算不辱使命,把公司做活了,而且从第三方的立场,也观察了一下在一线厮杀观察不到的地方,很有意思。

    主持人: 您做了两年,观察到了一些在线不能观察到的事情,能举一个例子,让你觉得收获最大的是什么?

    谢文: 我去的时候,主要提倡的是给各个公司做战略咨询,比如当时263做收费邮箱的时候,从他们动机分析清楚,形成你一个战略建议。比如在盛大游戏,在盛大如日中天的时候,要做游戏公司要有开发能力,光做代理只是产业下游,这话到今天还说对了,你就觉得不错,看来你的感觉还没有大的问题。

    主持人: 就是使他们的模式清晰化。

    谢文: 不光是清晰,你知道做一个公司牵挂很多,有的时候不如局外人,因为你在这个山中。比如02年信息产业报采访我,我当时说短信SP两年寿命结束。言中了,宽带,ADSL不太可能,还是中国人穷只能拨号为主,现在证明都是宽带上网。所以从那些比较复杂的,具体的现象当中,找出规律性的东西,而且在那里了解到不同公司的情况,可以看到很多有意思的事情,另外还有一件事,遗害江湖的,那时候在做研究,找到一个网站看了一下,把alexa整理介绍给中国了,没想到成了行业标准,现在很多人商业模式。

    主持人: 就成了教条主义。

    谢文: 教条主义倒不是,中国人利用这个行业平台系统化的造假。当时就是因为缺少中立第三方,没想到大家都把聪明才智用到那方面了。

    主持人: 其实起到正面的作用,可能以前中国人包括思维方式,传统,就是长线思维模式,对数据并不是很重视,您其实使很多公司很多人开始重视数据。

    谢文: 重视数据和制造数据还是有区别的,重视不能重视到自己去造假,因为你有一面镜子,说漂亮姑娘看着镜子里面得意,我们长的丑的也不要伤心,但是要做一个哈哈镜就失去了原来的本意。但是这个事并不是促使大家造假,见投资商就说我们流量5千万,现在至少说得不能太离谱,不能证明你一个亿的流量,怎么可以排十万多名啊,是不可能的,无非把假的转向了,而且造假是有代价的。但是大致上还是起到一点的作用,总之我觉得没有白费,除了第一线,大家都在公司挣扎的时候,比较惭愧没有跟大家一块挣扎,这点很遗憾。
    第四阶段:和讯网

    主持人: 但是可能恰恰是因为没有在第一线跟着大家挣扎的继续的精力和体力,到了03年的时候 谢文 老师就去了和讯网,在和讯网呆了两年多,做了很多事,比如提出大财经的定位,当时提出这个定位是不是有很多人质疑。 

    谢文: 一个概念说自己觉得我认识,我认同,和你的用户网民感受到是两回事,都说做大财经,我们要做到全世界,全宇宙的财经都在我这儿,没人说不愿意,问题是要它变成实实在在的信息、服务,并且要获得一个大致的名声,比较中立,比较客观。但是把它实实在在变到网站结构上,变到组织结构上,变到频道上。早些年的时候老百姓投资只有一个股票,那个时候那些历史是死的,没有个人渠道,没有贷款,那个时候叫投资,A股市场,叫大炮,但是03年就不一样了,有外汇就期货,有收藏,等等,所以你要叫你是中国第一大财经网站,所以就把所有老百姓可投资的东西弄出来。理财是我04年才提出来的,03年叫大财经,叫综合理财的概念,或者是长期的个人理财。当然后来再延伸一遍我改成叫中产阶级,那个是对现实的一种认可,现在中国这种体制,我们很难做美国同类网站的事,因为牌照你拿不到,那么我们至少可以猜测有投资能力,或者有投资想法的人。应该大致是属于中产阶级这一层,所以我才提出和讯要做中产阶级,做中产阶级的投资特色,这样既照顾历史,又把公司给往前走,大概指条路,做CEO就是干这个活。

    主持人: 其实恰恰是大财经加社区,或者是大财经这个方向下,包含社区,其实也引起了一些争论,包括其实到目前为止和讯公司这个走向,可能都还牵连着你当时在这里面做的很多事情和定位,您当时在和讯做社区,是不是也可以理解为您一直在探索做web2.0的一种尝试。

    谢文: 我当时2003年夏天给和讯做咨询,分析做报告,就是提出社区化的理念,这个道理到今天仍然在坚持,这跟财经没什么关系,整个互联网要以互动为最鲜明的特色,整个五花八门所有的服务,都要以社区基础类展开,这是我今天仍然这么认为的。我不太愿意说离开和讯以后的事,我只能说如果我在那儿我会怎么做。做社区但你这边有一个网络媒体,第一步是先把社区做出来,第二步先把社区和媒体有机地整合在一起。这就是今天当红的新媒体。这二者根本不成矛盾,社区是一种形式,媒体是一种业务方向,是架构在社区上做媒体,还是在广播的架构上,1.0的架构上做媒体。但是呢,2.0做媒体正常,因为整个互联网都要2.0。但2.0是不是今天具体形式,那是可以商量的,也许最后可以更成熟,更好。我在和讯那段时间做到了比以前好一点,比如我当时改了一版财经以后,好像成了行业标准,后来我发现好多网站也都改成那样了。流量也上去了,我去的时候和讯是四千多名,六个月以后是一百多名。然后做做了社区的一些基本模块,我没来得及做的就是各个社区变成一个完整的平台,到今天也没完成,第二个这个媒体怎么合,让用户感受到,你这就是纽约,这就是华尔街,就变成了财经特色一个大都市,大城市,这个事到今天也没做完。所有的网站都会自觉不自觉在未来三五年去完成这个工程。

    主持人: 当时为什么离开了?

    谢文: 具体的我就不说了。我从来不说离开公司的是非。

    主持人: 我们刚刚引用你一直以来坚持,也经常表述的,就是做好一个大的互联网公司的标准,还是我们刚刚说的三个要点,第一个规范,第二个千万人千万美金的投入,第三个是共识,您在和讯这两年多,您觉得这三点都到达了吗?

    谢文: 太具体就不谈了。

    主持人: 从我们外人观察力,也许千万人千万美金这个投入上……

    谢文: 虽然你们觉得我说话比较冲,比较随意,我还是比较谨慎,一定是觉得干不干都那样了,我就得走了,何必呢,让别人试试。

    主持人: 其实当年包括和讯推出社区,博客网推出巨大的首页,在现在看都是当时首创的。

    谢文: 那个形式是不是我当时理想当中的状态,有些可能是刘峻的功劳,我不管具体事,世界上关于该怎么做,都各有各的看法。

    主持人: 我们现在表达作为一个媒体的观点,现在看,当时你在和讯做的事情,从2.0的角度来说,您是做得相对比较早的,也是比较早成规模的。现在也有一些大公司,你刚刚也多次提到大公司,提到大公司做到不容易的地方,其实很多大公司也在关注2.0也有一些门户网站也在关注2.0,我们再一次回望一下再对应到现在,您觉得现在这些大公司,他们要做2.0您觉得从时机来说合适吗,他们现在可以怎么做呢?

    谢文: 我觉得大互联网公司做web2.0的话,笼而统之是晚了点,大的公司,小的公司,互联网公司没有选择,在向前发展,向前变化,不拘泥于现在这个状态,谁都没有改变,改变的大方向,社区化互动,这个大方向谁也逃不掉。如果我们跟美国大公司比,我们所谓晚了看得更清楚,我们看到雅虎人家03年就开始弄,他的问题没做彻底,但是他们意识到了。过去雅虎也有社区,现在我们知道不够,现在我们就说雅虎正是社区,他们正在努力做这个事。MSN,甚至不惜虚弱MSN这个品牌,移植到到这边,甚至Google,自己偷偷摸摸买了blog,对比这些比,甚至eBay,我们中国就落后太多,现在所谓马马虎虎做了一点,弄了一个孤零零的博客,开始不敢放在首页,但是这些无所谓,但是大家真正上从意识上,把自己公司整个经营平台设想成一个大革命,完整革命,并且很大力度在做的,现在我看到的就是腾讯和百度,腾讯做得更彻底。我看腾讯老总最近又说搜索是整个大平台的中枢神经。百度也是原创,我不知道当时他做百度贴吧的时候后面有没有大战略,还是后面的一种即兴之作,按照那种搜索,每个主题都成一个贴吧来的,后来从他们做空间,做收藏等等下来,现在看跟Google有异曲同工之妙,比较起来,新浪、网易、搜狐、TOM在这方面我认为比较慢,比较局部,比较被动,这个全部的看法是站在那个角度,大家早早晚晚主动还是被迫,都要上这条路,因为这本身是一种形式。这个意义上说,一批小web2.0公司没有一个成功的,一批大公司,或者是出于种种原因,有很骄傲觉得已经拿了终结真理,没有,天下没有新鲜事了,没有这种心态,剩下的就是本来对互联网没有什么感觉,误打误撞进了这行。

    主持人: 这里还有一个很重要的点,就是技术问题,无论是大公司,还是小公司,如果真正想做2.0的话,要面临一个很重要的技术的问题,我看了您前段时间麦田洪波的聊天,您在里面阐述如何做一个2.0的社区,如何做一个真正的社会,您提了两点,一个是真实的再现,另外一个无论是体现互动,还是有助于交流,您提到搜索,您当时提到搜索就是技术皇冠的明珠这种级别,也是需要千人/年这种投入,这种量级的难度,对现在中国这种所谓的大公司,还是新进入者,其实都是有相当的难度,甚至可以说在钱和投入上都是很难做到的。那么在这个时候,无论对大公司还是对小公司,他们可能有的人脑子已经革新了,他们想了多少年,怎么办呢?这个技术怎么解决呢,有理念有构想都可以。总是需要通过技术来落实。

    谢文: 你这种问法很有代表性,天天到我家楼下坐着聊天的这批,三六九等差不多都有这种,我就听不懂这种逻辑,说我要赚钱做好东西,但是好东西我做不起,但是我要发财,但是我问您要做什么,他说随便做一东西我就要发财,Google当时起来就一两个人,李彦宏最初也就三五个人,人家坚持慢慢做,做下来不就成了吗,如果你想明天马上见效了。除此以外我就觉得我等不起,我没有资源,我也不会做,那就不要做这行,这个问题对我来说是一个常识,我不懂这个问题是怎么问的,我告诉你怎么做一个好东西才能赢,但是好东西不想做但是我想赢有什么好方法没有,我说没有,这是问题吗?

    主持人: 也就是解决技术的问题。

    谢文: 特别是要投资大公司更做不起,你做不起你的大是什么意思呢?我说千人/年,三百人干三年,千万美元,现在回归头来看,猫扑,51等等,到今天公司都三四年历史了,都说我那个东西太高不可行,但现实当中是花了好几千万美元,或者是若干年,还是没想到,你说今天这个大公司拿出三五十人搞搞创新,搞得起来吗,完全搞得起,为什么不可以搞。搜索这个东西肯定今天都要想清楚了,然后今天投入一千人,马上见效果这是胡说,现在没有三五个人,逐渐逐渐做起来,目的是社会搜索的对象是人,不是主题词,这个本身,而且它搜索主要是依靠log文件,而不是全网搜索,这样的东西谁可能都想不太清楚,但是你弄个小组,弄个部门,最多设个总监去做,有谁投不起,问题是你没有把这个东西放你在的新战略上新框架上去行驶,你永远不开始,整天在那儿坐而论道,说这个东西太悬没有意思,说就靠我眼前这点东西,心理踏实,你不变市场变,你不做,别人做,最后你就被淘汰了,很多大公司,IBM,微软,那就是公司自己的惨痛教训。

    主持人: 也就是说还是认识不到位,导致战略出现问题。

    谢文: 一个公司都在投入,当他们说这个向舍不得投入,或者不愿投入的时候,他们没有停止花钱。无非都去买SP公司了,都去做彩信了,做了一些简单的产品,但是当大风一吹的时候,突然发现这笔投资废了。其他的跟别人不一样的东西没做啊。我们看到Google投了,雅虎投了,MSN投了,腾迅投了,百度投了,怎么了,也不试试,不是没有人投,就我一个人在这里嚷嚷,是很多人投了,并且见效了,为什么腾讯变得让人害怕,成为公敌,就在于人家不择手段地创造新的东西,昨天种的庄稼今天在收获,但是收获的同时,拿出一部分种子又去等待明天的开发,明天的收获,这是一个有侵略性,有扩张性的标准。TOM现在也不错,不是现在开始做C 2C ,那确实是挑战巨大,但是至少比没有强,因为至少给了你努力的方向,就像现在有人批判,说百度跑日本去,人家至少在试,比你什么都不试就是强,你都看清楚了,最后你还是那点东西,只好靠什么,靠管理,深耕细作,卡成本,减员,这还是朝阳企业,朝阳产业的状态吗,那是老行当了。如果只做那个,那个公司就已经进入晚期了。
    第五阶段:雅虎前后

    主持人: 您刚刚说到尝试,在06年您去了雅虎,这是不是也是一种尝试?

    谢文: 反正我觉得我有贡献,别人觉得需要,什么大公司小公司我都愿意试,都愿
    意做。有多大把握,这玩意儿不好说。试试,行就行,不行就拉倒。

    周雪峰: 当时一进去的心态就是这样的的吗?

    谢文: 进去时候的信心应该比现在高嘛,但是具体就不说了。

    主持人: 到了年底的时候,您离开了雅虎,就离开的今年,我们说了这么久的历史终于回到了现在,我们时间也接近尾声,您能不能对我们刚才谈的这些,其实是以您的经历为脉络,不断的回望历史,然后借鉴到现在,主要是从四个角度谈了问题,第一个是关于创业,第二个是关于现在当前的无论说社会网络也好,2.0也好,社区也好,互联网新的发展趋势,以及新的创业,大公司、小公司,第三个互联网的走向,重点谈了江湖的特性,当然我们从中看到了问题,但也看到了可能往良性发展的趋势,最后我们讲到弱视的问题,怎么解决技术的问题,您能做一个简单的总结?

    谢文: 总结有各种各样的角度。我是作为过来人,另外我谈的大家都是行内人,所以我们可能说问题多一点,我们是为了在已经很好的状况下做得更好这个角度谈的。对于要选择职业,或者选择事业的年轻人来说,我仍然是鼓励鼓吹,如果你不怕死,喜欢新鲜事,喜欢那种没有确定结果的,不重复的事业的话,互联网应该是首选。有能力的话,有机会的话,都来试试。互联网还在非常幼年的状态下,满打满算,中国也就12年,也就这个状态,幼稚得很,我最近看到有人说互联网没有蓝海了,这可能就是不懂互联网的,或者是从其他角度谈的,比如今年的投资,明年不回报。互联网现在在深不可测的蓝海当中不知道往哪走,太幼稚,太早。我相信比如今天,我想一下我们八十年代用互联网的时候,那个时候发一个电子邮件是单独编程的,你要比划一大堆的东西,我们那时候有巨大的讲座,我们成功发了一个600多K的东西到欧洲去,解决了若干难题,大家都鼓掌,到后来许多IE这种东西下,互联网都是一个很难看的东西,再后来就是互联网大家自以为得意的东西,也都会说它怎么那么蠢,还要强迫我们花这么大的成本掌握这点东西,再往后来,因为互联网是一个虚拟平台,它扩张性,应该把现实很多问题复制,转化到网上做。我们刚才谈了一部分,我们已经在里面有点经历有点责任的人,我们应该把我们行业的气氛搞得健康一点,让大家财发得舒畅一点。我们其实也蛮骄傲的,中国这么多产业,我们别过几年,又差个几年,十年五年,距离拉开了,甚至又变成人家的殖民地,好吃的又被外国公司拿走了,这个就是我们的悲哀,是从这个意义上说,所以要做很多环节,第一大环节,就是让业内人的思想,能够交锋,各种意见能够阐述,各种实验能够进行,把投机取巧江湖气这种东西消灭是不可能的,把它局限到尽可能小的一个范围内,使主流应该能够发展。这对我们自己,对公司,对产业,对国家都好。

    主持人: 刚才您跟我们年轻网友,和一些青年创业者讲了怎么看互联网,要做什么样的互联网,以及怎么做互联网,能最后再跟大家讲一讲,我们希望越来越多的人,投入到互联网这个这个行业,这个事业中,能够为中国的互联网发展,能够再更增加一些新鲜的血液,能不能给我们年轻网友最后再说一说,或者说讲一下您的观点,当做一个招纳宣言吧,我们为什么要做互联网,我们为什么要做中国互联网,我们为什么要投身进来,它为何吸引我。

    谢文: 年轻人从定义上就是喜欢新鲜事物的,如果你爹,你爷爷,祖爷爷都干这个活一般对自己吸引力不大。对大多数人来说,都是追求新奇,追求未来,因为年轻人刚刚走入社会!他后来还有大半辈子还要过,肯定不能做要贬值的,互联网给了一个机会,互联网等待我们新的一代去完成,我们面临着把传统社会,传统产业格局的很多东西搅乱,转移到互联网平台上来,或者是新生的,这样的机会使命。如果我们这些人把互联网搞坏了,转到传统产业仍然是主力,因为传统产业现在正在以极大的兴趣和极大的速度向互联网靠拢,都想充分利用互联网平台,重组,重塑自己的商业模式。所以,万一最坏,你在互联网行当,摸爬滚打几年,只会增值不会贬值,是能够让你学到很多。当然我们还是希望,如果我仍然现在愿意相信我们互联网业一定会健康地,高速发展,让我们互联网向外侵略,向外扩张,作为一支新生的力量,一支新生的大军中的一员对你未来的职业规划,应该是非常好的落脚点。

    主持人: 各位年轻的网友们,欢迎大家加入互联网行业,这里虽然风险很大,但机会更大。

    谢文: 换句话说,我这么大岁数赖着不走,就在于互联网的魅力。我如果现在换在别的行当,马上就老十岁,心态老十岁。(笑)

    主持人: 大家进来以后还可以拥抱年轻。今天的访谈到此结束,谢谢各位网友, 谢谢谢文 老师。

    谢文: 谢谢各位网友!

     
    三栏

    跨浏览器样式表 CSS hack

    Posted by 超级苍蝇 on May 9, 2007 in 技术~

    转载备忘

    屏蔽IE浏览器(也就是IE下不显示)
    *:lang(zh) select {font:12px  !important;} /*FF,OP可见*/
    select:empty {font:12px  !important;} /*safari可见*/
    这里select是选择符,根据情况更换。第二句是MAC上safari浏览器独有的。

    仅IE7识别
    *+html  {…}
    当面临需要只针对IE7做样式的时候就可以采用这个HACK。

    IE6及IE6以下识别
    * html  {…}
    这个地方要特别注意很多地主都写了是IE6的HACK其实IE5.x同样可以识别这个HACK。其它浏览器不识别。
    仅IE6不识别
    select { display /*IE6不识别*/:none;}
    这里主要是通过CSS注释分开一个属性与值,流释在冒号前。

    仅IE6与IE5不识别
    select/**/ { display /*IE6,IE5不识别*/:none;}
    这里与上面一句不同的是在选择符与花括号之间多了一个CSS注释。

    仅IE5不识别
    select/*IE5不识别*/ { display:none;}
    这一句是在上一句中去掉了属性区的注释。只有IE5不识别

    盒模型解决方法
    selct {width:IE5.x宽度; voice-family :"\"}\""; voice-family:inherit; width:正确宽度;}
    盒模型的清除方法不是通过!important来处理的。这点要明确。

    清除浮动
    select:after {content:"."; display:block; height:0; clear:both; visibility:hidden;}
    在Firefox中,当子级都为浮动时,那么父级的高度就无法完全的包住整个子级,那么这时用这个清除浮动的HACK来对父级做一次定义,那么就可以解决这个问题 。

    节字省略号
    select { -o-text-overflow:ellipsis; text-overflow:ellipsis; white-space:nowrap; overflow:hidden; }
    这个是在越出长度后会自行的截掉多出部分的文字,并以省略号结尾,很好的一个技术。只是目前Firefox并不支持。

    只有Opera识别
    @media all and (min-width: 0px){ select {……}  }
    针对Opera浏览器做单独的设定。

    IE5.x的过滤器,只有IE5.x可见
    @media tty {
    i{content:"\";/*" "*/}} @import ’ie5win.css’; /*";}
    }/* */

    IE5/MAC的过滤器,一般用不着
    /*\*//*/
       @import "ie5mac.css";
    /**/

    Copyright © 2014 SuperFly-超级苍蝇飞飞飞 All rights reserved. Theme by Laptop Geek.