眼界和梦想

二月 22, 2014
Life

早上一起床,和大叔(大学舍友)聊天,惊闻(only me, maybe...)大飞到CMU大学(卡内基梅隆)读计算机了,很是震撼,包括上一年小明考上研究生了,等等,这些事情对我来说都是没怎么想到的。

到底是什么因素,导致我们走在了不同的路上,是因为眼界和梦想吗?

2013总结

十二月 22, 2013
Life

时间过的真快,转眼就已经毕业一年半了,回忆一下2013年,主要是工作,顺带对一些家庭和生活的感悟,算是对自己的一个总结吧。

一、关于工作

2013年的工作主题:

  1. 理解基础系统

2013年所做的过的事情:

  1. 开发分布式存储系统
  2. 研究git核心代码
  3. 研究c语言编译器lcc源码,go语言编译器runtime的实现,lua虚拟机的实现
  4. 研究xv6操作系统源码
  5. 研究linux内核文件系统源码,tcp/ip协议栈的实现,参与社区开发
  6. 研究openstack/分布式存储系统ceph,理解云计算的基础架构
  7. 开发pio

2013年花了大部分时间在基础系统的学习和理解上,目标是初步实现基础完备,为后面的深入研究打下基础。2013年最大的收获就是找准了自己对方法论的定义:是一套指导编码和实施的原则和方法的集合。以及找到了积累方法论的途径:在工作中不断的理解,反思,和总结。

2013年的不足和自我总结:

  1. 悟性不够,思维不够敏捷,需要提高大脑的活跃度,善于思考
  2. 代码产出低
  3. 学习的过程没有记录,所谓好记性不如烂笔头

2014年的工作主题:

  1. 基础架构
  2. 软件质量保障

2014年需要TODO的:

  1. 坚持每周写博文
  2. 15w的代码产出
  3. 关注基础架构,并思考实际编码中的软件质量保障,希望可以积累出一些相关的方法论。
  4. 多看书,上豆瓣积累一个书单

二、关于家庭和生活

9月份后给家里打电话的次数就越来越少了,一个月偶尔一两次,这一点做的很不好。应该多关心家里,父母身体不好,做孩子的应该上心。另外,和老婆沟通的也不够,导致她对毕业季的找工作安排不妥当,需要检讨。

其次,没能够坚持运动,注意身体,避免职业病。

htc touch hd升级安卓2.3.7

十一月 23, 2013
Life

最近为了响应公司的号召,体验一把微米,于是决心研究下怎么把老爷机htc touch hd从屌丝wm6.1逆袭成安卓2.3.6。牛人早就把材料准备好了,移步请看:

  1. [ROM] {NAND} AOSP-GBX | < Kernel: 2.6.27 > | 2013.01.20
  2. Installation guide from Windows Mobile to the Android

研究了一下,安卓过程大概如下:

  1. 首先升级机器的HardSPL,我的是SPL1.56,对于经常刷机的机油来说,1.56不陌生了,我的默认就是。
  2. win xp请安装ActiveSync 4.5,vista/win7/win8会自动安装驱动,一般在你手机USB连接电脑时,自动搜索和更新驱动程序。然后HTC与电脑连接
  3. 从googlecode上下载rom文件,http://code.google.com/p/nandroid-for-htc-blackstone/downloads/list,我下载的是  FagyiDROID-V1-ODEXED.zip
  4. 从mediafile上下载其他刷机需要的文件,http://www.mediafire.com/?85m45naii6dpk,只需要三个即可:Adb-fastboot.zip,BLACIMG.NBH,BlackstoneAdvancedRUU和recovery.img

其他过程按照xda指引来做就是了,非常简单。刚装完是英文的,重启后变成中文了,真不错。

谈软件质量保障

这真是一个非常广阔的,难以囊括清楚的话题。我所理解的软件质量保证主要包括研发流程管理,质量控制和软件维护。稍微列一下提纲:

  • 研发流程
    • 为什么选择git而不是svn
    • 如何构建企业级的基础系统
  • 质量控制
    • 对象设计:SOLID原则和GOF模式实践
    • 模块化编程:解耦、解耦、还是解耦
    • 模块的可测试性和单元测试
    • 系统量化,让trace bug变得简明
  • 软件维护
    • 文档:wiki/PPT/man pages/docs
    • 自动化部署
    • 监控系统

一、研发流程

1)为什么选择git而不是svn

对于研发流程的选择,我比较偏向于开源社区的风格,例如linux内核。而在分布式协作的工具支持方面,git比svn更易用。

  • 每个人都应该熟悉整个系统(全栈工程师?):不用了解每一个细节,但应该知道它
  • 每个人都是code reviewer
  • 严格的代码提交和合并流程:git做了这一切事情

2)如何构建企业级的基础系统

这里有一个很重要的原则就是:动静分离。所谓动,就是代码中易变的部分,静,就是不易变的部分。将不易变化的代码剖离出来,简化系统架构。ok,举个例子,假如我们要实现一个web service,代码架构通常是这样的:

  • common/
  • core/
  • service/

当然,这是我常用的做法,首先是要完备基础库,接着实现核心模块,而service负责将这些模块组织架构起来,最终编译成一个可执行文件。也许service里就一个main.cc源文件
如果能理解这种模式的好处,我们就可以推广到整个企业系统里面去。例如,这个基础系统看起来可能是这个样子的:

  • base/
    • net/
    • data struct/
    • stat/
    • file/
    • encoding/
    • hash/
    • crypto/
    • ...
  • biz/
    • product1
    • product2
    • product3
    • ...

二、质量控制

对代码进行良好的抽象和模块化编程,是错误隔离的最佳实践。在设计模式里这其实是一个对象职责的问题。

1)对象设计:SOLID原则和GOF模式实践

推荐阅读 Object Design: Roles, Responsibilities, and Collaborations 一书

2)模块化编程:解耦、解耦、还是解耦

3)模块的可测试性和单元测试

模块的可测试性是模块设计的首要目标,如果一个模块是不可测试的或者难以测试的,那么它就不具有良好的设计。因为单元测试是软件质量保证体系里非常重要的一个环节。
单元测试应该尽可能的充分,例如达到80+%以上的覆盖率。单元测试在模块完成的时候就可以编写,基础系统的构建过程类似于积木,打地基,每一步都需要扎实。试想一下,如果某天你接手某部分代码,但是却发现无从下手,为什么?因为你甚至不确信某个API被证明过是语义清晰和完备的。

4)系统量化,让trace bug变得简明

系统能够监控得到的指标应该尽可能的多,这些信息在对问题追中时会变得非常有用。

5)编程范式

推荐如下书籍:

  • Unix编程哲学
  • Effective c++
  • C++ primer

三、软件维护

1)文档:wiki/PPT/man pages/docs

2)自动化部署

简化系统的上线流程。假想一下,假如没有运维团队,你会怎么去做这个事情?ok,这就是我们的目的。

3)监控系统

无非就是将各个系统的监控指标汇总起来,形成图状,网络拓扑状等,对整体系统的运行状态了如指掌。

向beyond致敬--被影响的一代人

十一月 22, 2013
Life

一直以来可以坚持的事情有三:

  1. 看星爷的电影
  2. 听beyond的歌
  3. 陈扬的心灵地图电台

陈老师的电台在高二那年断了,非常可惜,虽然这几年还时不时拨弄一下收音机,但是再也听不到能匹美陈老师那么富有磁性的声音了,^_^。在那个连mp3和md都还不知道是什么东东的年代,大部分学生对心灵地图这个节目应该很熟悉的

另外就是beyond乐队,受beyond影响最深的一代应该80后,但是到我们读初中那会,很多人仍然是beyond的fans,主要是因为beyond的歌确实很励志。我记得我初中的第一个晚上时,因为是农村,条件没城里那么好,宿舍就是食堂二层临时搭建的工床,宿舍里热闹的炸开了窝,这个时候就两个人在玩弄磁带机,一个是我,在听心灵地图,另一个是我旁边的哥们,在听别安的歌,后来我们成了兄弟。

每个人都有一段很长的故事,偶尔回忆一下。。。

c语言可变参数类型

十一月 21, 2013
Programming practices

使用可变参数时,va_arg宏的第2个参数不能被指定为char、short或者float类型。因为在可变参数函数传递时,char和short会被提升为int类型,而float会被提升到double类型 。

例如,以下的代码是错误的

a = va_arg(ap, char);

因为我们无法传递一个char类型参数,如果传递了,它将会被自动转化为int类型。上面的式子应该写成:

a = va_arg(ap, int);

coredump记

十一月 17, 2013
Programming practices

造成程序coredump的成因很多:

  1. index类的索引造成的数组越界
  2. 多线程环境下使用了非线程安全的函数
  3. 多线程与释构
  4. 多线程环境下的数据互斥
  5. 空指针
  6. 对象delete后仍然被访问

为了避免这些情况,需要谨慎处理所有相关的资源:

  1. 对象必须全部初始化后才能使用
  2. 尽可能的不要缓存对象,使用统一的内存管理来避免内存碎片化的问题。除非你确定对象被重用时,相关的资源被正确的初始化。
  3. 对象该由谁创建,由谁来释放,delete需要全局感知,避免游离的对象指针
  4. 对于共享的资源,注意互斥和死锁
  5. 全局对象使用指针,统一new和delete
  6. 特别注意资源进入临界区的时机,例如初始化工作确认完毕。

数据+结构

十月 21, 2013
Programming practices

数据是业务流密切相关的东西,容易发生变化,而结构通常都是大同小异。很多时候我们不得不为了各种各样的需求而设计复杂的数据结构。而且一旦它们之间呈现出复杂的依赖关系时,你会发现这就是一个噩梦:

  • 结构的逻辑变的相当复杂,而且难以分离
  • code review变得困难,让质量无法保证,代码难以维护

能不能让这个事情变的更简单一些呢?看看内核的红黑树和链表:

  • 链表
    • http://lxr.free-electrons.com/source/include/linux/list.h
  • 红黑数
    • http://lxr.free-electrons.com/source/include/linux/rbtree.h
    • http://lxr.free-electrons.com/source/lib/rbtree_test.c

一旦你习惯了这种设计模式,会发现它很有好处,而且可以轻松巧妙的解决很多问题。例如,在网络编程中,定时器是频繁被用到的一个组件,你会怎么设计它?

nginx slab管理

十月 6, 2013
Programming practices

今天在看一个开源的内存管理,https://github.com/flygoast/flib/blob/master/src/slab.c#L296

有几个地方比较难理解,记录一下,代码在 void *slab_alloc_locked(slab_pool_t *pool, size_t size) 函数里

    if (page) {
        if (shift < slab_exact_shift) {
            p = (page - pool->pages) << pagesize_shift;
            bitmap = (uintptr_t*)(pool->start + p);

            s = 1 << shift;
            n = (1 << (pagesize_shift - shift)) / 8 / s;
            if (n == 0) {
                n = 1;
            }

            bitmap[0] = (2 << n) - 1;

            map = (1 << (pagesize_shift - shift))
                / (sizeof(uintptr_t) * 8);

            for (i = 1; i < map; ++i) {
                bitmap[i] = 0;
            }
            page->slab = shift;
            page->next = &slots[slot];
            page->prev = (uintptr_t) &slots[slot] | SLAB_SMALL;

            slots[slot].next = page;

            p = ((page - pool->pages) << pagesize_shift) + s * n;
            p += (uintptr_t)pool->start;
            goto done;

起初一直看不明白第296行代码的 n = (1 << (pagesize_shift - shift)) / 8 / s; 是做什么的,你想一下,1<<pagesize_shift - shift)是一个page内能容纳对象的个数,对象的大小是1<<shift,拿个数除以大小本身有什么作用?越想就越懵了,回头看前面内存分配时的代码,也没什么可参考的地方,内存分配时的实现写的比较简洁和易懂

这里最主要的作用其实是计算bitmap要占用多少个对象的空间,为什么要这么做?是因为它管理内存的数据结构是放在被管理的内存区域上的,这种方法很原始确是真正意义上的内存管理,和内核管理内存的思想很类似。

BTW:这居然是nginx的代码

cpeh: a scalable, high-perormance distributed file system

九月 10, 2013
storage
  1. system architecture
  2. system overview
    1. the ceph file system has three main components:
      • client: each instance of which exposes a near-POSIX file system interface to a host or process
      • osd cluster: sotres all data and metadata
      • mds cluster: manages the namespace(file names and directories) while coordinating security, consistency and coherence.
    2. primary goals
      • scalability: to hundreds of petabytes and beyond, considered in a variety of dimensions, including the overall storage capacity and throughput of the system.
      • performance: out target workload may include such extreme cases as tens or hundreds of thousands of hosts concurrently reading from or writing to the same file or creating files in the same directory.
      • reliablity
    3. three fundamental design fetures
      • decoupled data and metadata: metadata operations(open, rename, etc.) are collectively managed by a metadata server cluster, while clients interact directly with osds to perform file i/o(reads and writes). ceph replace long per-file block lists with shorter object lists, delegate low-level block allocation decisions to individual devices, while a special-purpose data distribution function called CRUSH assigns objects to storage devices. this allow any party to calculate(rather than look up) the name and location of objects comprising a file's contents, eliminting the need to maintain and distribute object lists, simplifying the design of the system, and reducing the metadata cluster workload.
      • dynamic distributed metadata management: ceph utilizes a novel metadata cluster architecture based on Dynamic Subtree Partitioning that adaptively and intelligently distributes responsibility for managing the file system directory hierachy amon tens or even hundreds of MDSs. a hierachical partition preserves locality in each MDS's workload, facilitating efficient updates and aggressive prefecthing to improve performance for common workloads.
      • reliable autonomic distributed object storage: large systems are inherently dynamic, they are built incrementally, grow and contract as new storage is deployed and old devices are decommissioned, device failures are frequent and expected, and large volumes of data are created, moved, and deleted. ceph delegates responsibility for data migration, replication, failure detection, and failure recovery to the cluster of OSDs that store data, while at a high level, OSDs collectively provide a single logical object store to clients and metadata servers.
  3. client operation
    1. file i/o and capabilities open file: oid = (fid, stripe number). if file exists, returns the inode number, file size, and information about the striping strategy used to map file data into objects.
    2. client sync: Dynamic metadata management for petabyte-scale file systems. a subset of which are implemented by ceph.
      • lazyio_propagate: flush a given byte range to the object store.
      • lazyio_synchronize: ensure that the effects of previous propagations are reflected in any subsequent reads.
    3. namespace operations. managed by metadata server cluster. both read operations(e.g., readdir, stat) and updates(e.g., unlink, chmod) are synchronously applied by the MDS to ensure serialization, consistency, correct security, and safety.
      • ceph returns lstat results withdirectory entries.
      • caching metadata longer, if a file opened by multiple writers, in order to return a correct file infomations, MDS revokes any write capabilities to momentarily stop updates and collect infomations from all writes, and then return the highest values.
  4. dynamically distributed metadata.  because object names are constructed using the inode number, and distributed to OSDs using CRUSH, so file and directory metadata in ceph is very small, consisting almost entirely of directory entries(file names) and inodes(80 bytes).
    1. metadata storage