[Behind CS] CS平台设计随笔 – 综述

转眼再过一个月就要离开西邮。2014年5月到2015年5月,一年时间,受阳哥所托,花了很多精力在一个小具规模的项目上——西邮Linux兴趣小组内部协作交流平台(Xiyou Linux Group Collaboration System),简称CS。因为是第一次从头构思设计实现一个平台级项目,也是第一次带领十数人的团队,受制自己水平有限,走了很多弯路,但也终于有了一点成果,积累了很多经验与感悟。一方面希望能够把它们总结下来自我回顾,另一方面也希望能给后来人留下一些资料,所以在这里开一个系列文章[Behind CS]。

为什么要做CS

小组自2006年成立以来,至今已走过8年,走出了一批批活跃在各地各方向上的优秀的学长学姐们。然而,随着时间推移,小组也暴露出了一些问题,比较明显的就是传承与沟通上的缺失——一方面,往届学长学姐们曾经开发的优秀项目鲜有后人维护,毕业后心系小组却缺少了解小组近况的途径,在校学习期间精心收集整理积累下的学习资源材料也难以向下沉淀;另一方面,在校的小组成员想要参与原有项目,却因文档缺失难以入手,想要联系往届同学咨询,却缺乏有效联系方式而求助无门……

同时,作为一个技术型团体,小组内部的信息化程度却并不高;小组官网也多年无人维护;而随着邮件列表的日益冷清,急需一个能够替代邮件列表进行问题讨论与结论沉淀的平台;刚诞生的小组基金,也急需摆脱人工记账的原始方式,而有一个便捷稳定,方便公示与查询的载体……

为了解决这些问题,一年前,王亚刚老师与10级的刘丹阳学长,启动了这个项目。我们组建了一支前后共12人的开发团队。经过一年的不断摸索尝试,无数次讨论、争执、重构,终于有了现在呈现的这个雏形。

CS的业务结构是什么样的

设计之初,我们就清楚的认识到,目前我们考虑到的需求——基金管理、讲座、项目、活动、……绝不会,无法,也不应该限制系统未来的职能与边界;既然如此,平台就应该具备极灵活的架构与极大的可扩展性。

业务角度,作为项目PM,我给这个平台的定位,是使其逐渐发展为小组日常运营的服务型中心。如下图所示:

CS业务架构

我们把整个系统分为两大部分:底层应用服务框架,和上层应用。为了真正让这个系统成为小组内部联结的纽带,适应未来可能出现的新需求,也让每个人都有可能参与平台的开发,我们将项目、问答、招聘、基金、活动等具体业务需求定义为上层应用(App),以类似WordPress插件的形式与应用服务框架结合;应用服务框架为应用提供了封装好的各类API,以及全站搜索、站内信、用户管理、应用管理等各类基础服务。具体架构将在下一节中详述。

从图中可以看出,整个小组的信息化建设分为对内对外两部分;对外主要包含官方网站与微信平台等公开渠道;对内则是完整的CS生态圈;CS平台为其上的应用提供丰富的接口与基础服务支持,而各个应用则成为了官方网站与微信平台等对外渠道的数据与服务源,提供类似“近期讲座”、“纳新报名”等信息与功能的后台支撑。

简单来说,理想情况下,这个平台将成为小组生活、学习、活动与对外交流的中心,成为小组“Free Open Share”精神的体现,以丰富可用的功能与大量宝贵的优质内容吸引大家常常使用。“每天来到小组第一件事,就是打开CS”。(野心不可谓不大……)

CS的技术架构是什么样的

如前所述,CS将平台服务多层封装,平台与应用之间高度解耦来实现高度可扩展性。技术架构如下图所示:

CS技术架构

如图所示,平台技术架构分为四层。

最底层(Server层)基于经典的LNMP(Linux+Nginx+MySQL+PHP)架构。

平台的下层(Model层),首先将基本数据库操作封装为CSDB类,提供数据库服务(DB Service);在DB层之上,平台实现并封装了四大类服务与接口——账户服务(Account Service),提供用户账户控制(增删改查)、用户信息获取(基本资料,在线状态)、用户权限分级管理(管理员权限移交)等服务;消息服务(Message Service),提供站内信一对一、一对多收发,管理,以及已读状态等服务;动态服务(Activity Service),提供用户自发布状态,以及应用产生富文本动态服务;搜索服务(Search Service),提供基于动态的跨应用全站搜索服务。

平台的中层(Control层),利用下层提供的丰富的服务接口,开发了平台基础模块的后台(登陆、找回密码、首页、个人资料页、站内信模块、搜索模块、用户管理模块与应用管理模块等)。同时对接应用的后台。各应用后台通过本层实现业务逻辑并对前端模板进行渲染,同时封装对外提供接口。

平台的上层(View层),基于前端渲染框架Smarty,平台约束了两类基本模板——Frame.tpl与Base.tpl。平台页面与应用页面,利用这两类基本模版,开发并渲染前端展示页面。同时,平台页面通过约定规范,向应用请求并展示各类整合信息,例如首页侧边插件,导航栏应用动态数字等。

小结

在本文中,我们对CS项目的目的与意义,CS的业务结构,以及CS的技术架构有了初步的认识。后面的文章将会关注各个技术细节的实现与心得。

CS平台分为线上正式版与开发版。线上正式版地址:cs.xiyoulinux.org   开发版地址:dev.xiyoulinux.org

CS平台的全部代码,开源于Github。仓库地址:https://github.com/Jensyn/cs-xiyoulinux/   应用开发文档地址:https://github.com/Jensyn/cs-xiyoulinux/wiki

[补充实习笔记] 项目流程与角色分工

项目角色

PDM Product Manager 产品经理(对商业计划负责)
PM Project Manager 项目经理(对开发负责)
VD Visual Designer 视觉设计
ID Interactive Designer 交互设计
DEV Developer 开发
TEST Test 测试(性能测试、安全测试、功能测试)
DBA Database Administrator 数据库管理员
SCM Software Configuration Management 软件配置管理
PE Production Engineer 应用运维工程师(线上环境)

项目流程

1、MRD  运营

2、用户调研

===========分割线========= 开发介入

3、PRD产品需求文档

4、PRD评审

5、交互

6、视觉

7、技术方案

8、TC评审     TestCase 开发写给测试看的,也是写给开发看的

9、测试用例评审 测试写的

10、开发

11、冒烟测试

12、详细用例测试

13、项目发布计划制定

14、项目效果数据整理

[补充实习笔记] JAVA服务端开发设计的一些指导原则

一,性能相关:
1,避免在循环内部new一个对象。
2,所有与IO相关的操作,都需要考虑性能问题,一般采取的措施是连接池,缓存,减少调用次数,合并请求。
3,每个业务都要分析整个请求链路,找到瓶颈,通过压测的方式确认问题及验证解决方案。
4,根据业务情况,使用异步化和最终一致性。
5,CPU,内存,网络IO,磁盘IO这些瓶颈,需要知道在合适的场景牺牲什么换取什么。通俗的讲是空间换时间,还是时间换空间。
不同业务场景下,要做合理的取舍。例如多线程并发查询后merge。这个就是利用CPU,内存换取速度。
6,善于借助集团内成熟通用的平台来解决性能问题。如TAIR分布式缓存,METAQ,NOTIFY消息队列,HSF,OPENSEARCH等等。
要知道什么场景适合用什么,每个产品的最佳实践是什么要清楚。
7,学会通过业务视角解决技术问题。例如:如果没有分库分表,支付宝的大量交易数据的并发性,可能永远无法解决。
适当的时候,需要根据用户ID去分库分表,分散数据库IO瓶颈。避免只从技术角度考虑问题,陷入死胡同。
8,使用新技术新协议时,一定要分析出最佳使用场景,不能盲目相信。搞懂原理,才能通过最佳实践发挥性能优势。
二,监控相关:
1,监控分为系统监控,应用监控,业务监控。
系统监控一般监控网络IO情况,磁盘IO,空间,CPU,内存等等。
应用监控一般监控JVM的内存,GC情况,日志中的异常情况,SQL,SPRING方法等的耗时情况。
业务监控一般监控一些业务指标,如PV,UV,交易的变化趋势等等具有业务含义的数据。
2,系统监控,应用监控统一接入alimonitor。业务监控暂时接入XFLUSH,这块还在研究。
3,做好容量规划,避免无法支持业务增长。监控好容量。
4,对于调用链路非常深的系统,做好链路监控,及时发现瓶颈。
三,安全相关:
1,不要为了维护方便,在代码里留后门。之前review代码发现有这些问题,上次阿里内外上有一个帖子也反馈了这个问题。
2,涉及到用户密码等,一定要散列哈希算法加密存储。
3,关键用户敏感数据(如:信用卡数据)不能存日志文件中,避免主机漏洞被拖拽。很多互联网公司就发生了这样的事情。
4,要考虑完整业务链路的安全,不仅仅是某一端的安全问题。
5,充分利用集团安全团队的产品及规范,避免产品出现安全漏洞,代码安全这块加强和安全同学一起REVIEW。
6,要注意开发环境和生产环境信息做隔离,避免因在开发环境中泄露导致生产环境安全问题。
7,不在外网分享带有业务规则及需要保密信息的内部文档。
四,规范相关:
1,幂等性:所有对外暴露的接口,需要做到幂等性。
2,隔离性:对同一个数据源的操作,建议由一个服务向外暴露,避免多个不同系统操作同一个数据源,特别是避免修改操作。
3,开源使用:使用第三方开源jar包时,一定要谨慎。搞懂原理,避免不成熟导致缺陷。
对开源的第三方包,一定要有源码。
4,线程安全:要时刻关注线程安全问题。每个业务都要考虑代码是否是线程安全的。
5,关于编程模型,不做强制要求,但是有一个原则就是,这块技术是主流的,外部容易招聘到相关人才,
技术体系是完善的,容易学习和发展定制。
6,关键代码及业务逻辑,一定要有注释。
7,每个系统的设计及需求,接口等,一定要有文档。方便沟通交流以及团队的传承交接。
8,不用存储过程去实现复杂的业务逻辑,原则见第2点。
9,JAVA的日志记录,格式要统一,存储路径和位置,以及磁盘满了之后日志转移的机制要完善。
10,设计REVIEW:系统设计一定要组织REVIEW,避免设计的不合理导致后续扩展性不好。
review的角度,考虑业务的扩展性及发展方向是一个重点。
11,重点业务的单元测试和接口测试用例一定要有且全面。
12,统一使用PE提供的运行环境和容器,特殊定制化容器场景一定要充分测试。
五,异常处理相关:
1,要区分好业务异常还是系统异常。为每种异常定义好处理方式。
2,避免抛出大量异常不处理。
3,异常为了方便系统间传输,一般需要约定errorCode。例如场景:可以根据错误编码,将异常翻译成多国语言。
4,跨进程调用,不要将整个异常堆栈传递过去。
六,设计模式相关:
1,模块之间避免循环依赖。
2,尽量使用接口解耦应用。
3,代码中使用分层设计的思想。
4,高内聚低耦合。

[补充实习笔记] TDDL入门

TDDL(Taobao Distributed Data Layer) 是平台架构&开放平台-分布式产品组提供的一套分布式数据访问引擎。

为什么需要TDDL?

 
核心的目标是为了解决以下三个问题:
一、数据访问路由
    将针对数据的读写请求发送到最合适的地方。
二、数据的多向非对称复制
    一次写入,多点读取
三、数据存储的自由扩展
    不再受限制于单台机器的容量瓶颈与速度瓶颈,平滑迁移。

TDDL流程图

d1031a5d-c5d7-47a1-9189-bbe631f54984
所有蓝色的部分(TDDL三层架构),都是实现了jdbc接口的具体实现,因此可以按照需要随意选用。之所以为此,原因很简单,因为每层都有损耗,不管是易用性还是性能,都会有,所以要看用户的选择,需要用什么就上什么,我们不干涉。具体的三层架构见下:

TDDL整体三层架构

28e919fd-871c-4c09-b307-76f1d8c580f3
TDDL主要部署在ibatis或者其他ORM框架之下,JDBC Driver之上,三层数据源每层都按JDBC规范实现, 所以可以将其当作与普通数据源实例化并且注入到各种ORM框架中使用。
TDDL架构分为了3层,最上层的TDataSource负责分库分表路由结果合并,持有多个GroupDS实例中间层TGroupDataSource 负责主备切换读写分离,即根据读写特性与权重,选择一个具体的DB Server进行操作,持有多个AtomDB实例;最下层AtomDataSource持有原子的数据源(剥离的JBOSS数据源)并且可以动态改IP ,连接信息等,能够动态响应数据源创建与销毁。包括IP、用户名、密码、最大最小连接池、连接参数,从Diamond上拉取并交给JBOSS DB。JBOSS DB完成数据库连接管理与池化操作。3层数据源都可以单独使用,应对不同的应用场景。
先来看一条SQL的具体执行流程。而后分别分析三层。

TDDL执行SQL过程

 62aa2073-84d0-415d-8b6d-e90a95806bc8
其中sql解析/ 规则计算/表名替换/选择GroupDs执行sql/合并处理多个结果集 5个步骤在Matrix层执行, 根据权重选AtomDs/具有重试策略地在AtomDs上执行SQL 2个步骤在Group层执行, 读写数控制、线程并发数控制/执行sql返回结果集 2个步骤在Atom层执行。
        为何要做SQL解析?
 
        在这一步,TDDL将SQL中分库分表的条件进行解析提取,包括order by, group by, limit m,n, join等信息、sum, max, min等聚合函数信息、distinct信息。(此外,TDDL行复制需要重新拼写SQL,带上sync_version字段。次要理由。)

TDDL初始化

913f828a-a1c9-4dc7-bb36-05dbafd67907
TDDL初始化主要包括规则信息的初始化和各层数据源拓扑结构的初始化,其中前者包括 规则中的分库分表字段、规则字符串的处理和库表对应关系初始化,后者包括Matrix层 的dsMap初始化,Group层每个GroupDs实例中多个(或单个)AtomDs的可用不用,权重关系 等初始化,Atom层根据本地配置或者持久配置中心的数据源信息初始化剥离的JBOSS数据源, 并且将自身实例和这些数据源一一对应映射起来。这一初始化的过程是从上到下的,也就是 说只有Matrix层配置的GroupDs才会初始化,只有这类GroupDs中配置的AtomDs才会初始化。

TDDL Matrix Data Source

Matrix DS 用于管理数据片sharding,核心功能是根据给定的参数从规则引擎中计算出目标库的路由信息,然后进行路由。
基本功能:
1) 数据的水平切分
 数据库的水平切分,从本质来说就是根据关键的key,将数据切分为多个小片。主要的切片方法是取模和按日期,还有些会将这两种方式综合起来使用。而TDDL的目标也就在于对这些情况进行更好的支持。因为mysql的表有数据量的限制,因此在切库的基础上,还要进行适度的切表,以保证数据库的硬盘的使用率。
2) 事务管理
 TDDL提供了最基本的事务管理功能,首要的目标是让业务现有的事务模型更加简化。
3) 数据库选择
 与事务管理结合,允许业务指定查询的具体目标,用于彻底的替换dbRoute.提供更简单的配置方式和配置模型。与事务管理结合后,可以提供更为清晰的事务判断和事务管理。
4) 规则的集中管理
 规则的集中管理有利于进行数据库的平滑扩展时的状态切换和统一管控。在进行平滑扩展时,分库分表信息必须持有两套不同的规则,在准备完成的时候一并进行切换。
5) 不同数据散列结构读写分离
主要针对以下场景的支持,假设有一张表,是auction_auctions ,在主库内是分布在两个oracle中的, 丛库则分布在16个mysql中,每个mysql有4个表。
那么在这种情况下的读写分离就是不同数据散列结构的读写分离了。TDDL对这种场景也可以予以支持。
TDDL Group Data Source
Group datasource 是构建于atom datasource之上的数据源,他的目标是管理多组数据完全相同的数据库。比如通过mysql或通过oracle进行数据复制后的主备数据库。目标是在rjdbc的基础上,对主备,备库可读的场景进行更好的支持。
基本功能:
1) 主备数据库动态相互容灾切换
支持进行主备的对调切换,状态对调后备库变为主库,主库变为备库,类似rjdbc的作用。
2) 相同数据片内读写分离
针对mysql replication机制进行的数据主备复制,可以直接使用group datasource来支持读写分离。读写分离支持权重设置,允许对不同库使用不同的权重。
3) 读重试
一台数据库挂掉后,如果是个fatal exception ,那么会进入读重试,以确保尽可能多的数据访问可以在正常数据库中访问。
4) 数据库挂掉后的线程保护,不会因为一个数据库挂掉导致所有线程卡死。
使用try – lock机制来进行线程保护,在第一次捕捉到fatal exception以后,只允许一个线程进入数据库进行数据访问,直到数据库可以正常的工作为止。
5) 流量控制,数据库保护

TDDL Atom Data Source

Atom Datasource 如其名,就是一个原子的datasource。从本质来说,就是一个对jboss的浅包装。允许业务通过非jndi的方式获取jboss的数据源,同时也可以协助dba进行统一的数据库管理。依托于diamond server进行数据配置的统一管理。从而实现一个数据库,唯一的对应一套ip+port+username+password+schema的目的。减少配置中的环节。让数据库使用更简便。
基本功能:
1) Dba管控
2) 定期密码变更
3) Jboss数据源管理的相关功能
功能介绍:
a) 线程数统计
线程统计的作用是,在线程进入数据库访问的getConnection()阶段,线程数自增1,在退出数据库访问的close()阶段,线程数自减1。使用这种方式统计真正与数据库交互的线程数。
这样如果数据库挂掉,那么会有更多线程等待已经挂掉数据库的连接,如果到达伐值(可在app规则中设置,默认关闭),那么会拒绝超出伐值后的线程访问数据库的请求。
b) Try-lock机制
如果数据库发生了fatal exception(也就是断连接,数据库硬盘满)等异常的时候,TDDL会抓取到这种异常。一旦发现这种异常,立刻对数据库访问进行保护,只允许单个线程访问数据库,其他线程访问则全部抛出错误。
使用这种方式可以比较有效的保护业务机器的处理能力。
c) 状态切换
DBA发现问题时,可以迅速反应,将数据库状态置为NA,那么所有访问都会直接抛出异常,从而保护业务服务器。
d) 执行次数统计
允许通过设置指定单位时间片内执行的修改类型的sql和查询类型的sql的个数。
Atom使用的参数全部在Diamond上,包括三部分:
1、global:数据库ip, port, dbname信息
2、app:appName和数据源连接池、连接参数、用户的映射
3、passwd:数据库用户名和密码的映射
(2、3可以有多个)

Diamond取数据过程

以IC最新的Mysql动态数据源为例:
因为做了分库分表,所以最上层是Matrix数据源(TDataSource),appName是IC_MYSQL
那么拼成Matrix的dataId:com.taobao.tddl.v1_IC_MYSQL_dbgroups
组名是DEFAULT_GROUP(后续所有dataId的组名都是DEFAULT_GROUP)
以dataId和组名通过http GET访问diamond:(以日常10.232.10.23为例)
http://10.232.10.23:8080/diamond-server/config.co?group=DEFAULT_GROUP&dataId=com.taobao.tddl.v1_IC_MYSQL_dbgroups
得到:
MYSQL_ICDB_00,MYSQL_ICDB_01,MYSQL_ICDB_02,MYSQL_ICDB_03,MYSQL_ICDB_04,MYSQL_ICDB_05,MYSQL_ICDB_06,MYSQL_ICDB_07,MYSQL_ICDB_08,MYSQL_ICDB_09,MYSQL_ICDB_10,MYSQL_ICDB_11,MYSQL_ICDB_12,MYSQL_ICDB_13,MYSQL_ICDB_14,MYSQL_ICDB_15
这个内容是appName为IC_MYSQL的Matrix的group列表(对应TGroupDataSource)
对group列表中的每个group,例如MYSQL_ICDB_00
拼成Group的dataId:com.taobao.tddl.jdbc.group_V2.4.1_MYSQL_ICDB_00 这个dataId 用来获取一个group内部的主备结构,读写权重配置
组名是DEFAULT_GROUP
以dataId和组名通过http GET访问diamond:(以日常10.232.10.23为例)
http://10.232.10.23:8080/diamond-server/config.co?group=DEFAULT_GROUP&dataId=com.taobao.tddl.jdbc.group_V2.4.1_MYSQL_ICDB_00
得到
MYSQL_67_ICDB0:r10w10p0,MYSQL_69_ICDB0:r0w0p0
这个内容是MYSQL_ICDB_00的具体主备结构配置;逗号分隔开每个库;每个库的冒号前面是Atom数据源(对应TAtomDataSource))的key,冒号后面是这个库对应的读写权重。
对每个Atom数据源的key,例如MYSQL_67_ICDB0
拼成Atom相关的2个dataId:
com.taobao.tddl.atom.global.MYSQL_67_ICDB0 这个用来获取数据库本身的信息
com.taobao.tddl.atom.app.IC_MYSQL.MYSQL_67_ICDB0 这个用来获取appName对物理库如何使用的信息(其中IC_MYSQL就是最开始Matrix数据源的appName)
http://10.232.10.23:8080/diamond-server/config.co?group=DEFAULT_GROUP&dataId=com.taobao.tddl.atom.global.MYSQL_67_ICDB0
得到:ip=10.232.31.67 port=3306 dbName=icdb0 dbType=mysql dbStatus=RW
http://10.232.10.23:8080/diamond-server/config.co?group=DEFAULT_GROUP&dataId=com.taobao.tddl.atom.app.IC_MYSQL.MYSQL_67_ICDB0
得到:userName=ic minPoolSize=10 maxPoolSize=20 idleTimeout=60 blockingTimeout=500 connectionProperties=connectTimeout=1000;characterEncoding=gbk;socketTimeout=1000
根据上面两个结果中的dbName和userName拼成数据库密码的dataId:
com.taobao.tddl.atom.passwd.icdb0.mysql.ic
http://10.232.10.23:8080/diamond-server/config.co?group=DEFAULT_GROUP&dataId=com.taobao.tddl.atom.passwd.icdb0.mysql.ic
encPasswd=6eaf1b*********a8
这个是加密后的密码
至此,数据库所有的配置信息获取完毕。
在异常流程下,目前主要通过两种方式来保证业务可以正常启动
1. 如果这个机器曾经启动过,那么如果diamond死掉,他会使用本地cache启动机器
2. 如果这个机器从来没有启动过,diamond死掉,那么可以让sa scp数据文件到本地机器中,启动服务

[补充实习笔记] HSF入门

HSF全称为High-Speed Service Framework,旨在为淘宝的应用提供一个分布式的服务框架,HSF从分布式应用层面以及统一的发布/调用方式层面为大家提供支持,从而可以很容易的开发分布式的应用以及提供或使用公用功能模块,而不用考虑分布式领域中的各种细节技术,例如远程通讯、性能损耗、调用的透明化、同步/异步调用方式的实现等等问题。

适用场景:
  • 将集中部署的应用转换为分布式应用
对于这种需求场景,HSF将提供帮助,基于HSF可以非常容易的将集中部署的应用转换为分布式应用,而不用去过多的考虑分布式应用需要掌握的技术,也不需要对现有应用进行过多的改动,这一切HSF都会提供支持。
  •  以统一的方式对外提供或使用外部的公用功能模块
对于这种需求场景,HSF将提供帮助,基于HSF所有分布式部署的功能模块都可以以一种简单而标准的方式进行通讯,而无需关注所使用的公用功能模块部署在什么地方以及怎么远程调用它等问题,可做到的效果就像是本地调用library的API一样。
  • 开发分布式应用
对于这种需求场景,HSF提供了分布式领域问题解决的支持,HSF屏蔽了分布式应用带来的一些问题,例如:如何与远程的功能通讯、异步/同步调用等问题,使用HSF,只需要简单配置就可以做到就像本地调用一样的效果。
总结来说就是,只要应用涉及到分布式,那么HSF就可以提供支持和帮助。
为何使用HSF?

07年时,淘宝是一个单一的应用Denali。随着业务的发展,暴露了两个问题:

1、业务功能累积,单一应用不堪重负
2、牵一发而动全身,代码难以维护
因此在07年下半年,将Denali进行了拆分。面临问题:拆分后系统跑在不同的虚拟机中,如何互相调用?因此开发了HSF。

HSF远程调用流程

bd9b2f21-4f27-439c-9cc8-1ae5a2b63343
基本调用流程:
1、连接服务器
2、把接口名,方法名,参数传给服务器
3、等待服务器返回结果即可

HSF框架结构

22ee41db-90ac-4304-8956-9f69319a5594

应用层:HSFSpringProviderBean/ HSFSpringConsumerBean
协议层:RPC协议(TCP/IP协议,Webservice协议,Google protocol buffers协议)/序列化协议(java,Hessian)
核心服务层:RPC服务/路由规则服务/地址服务/配置服务/notify消息服务/OSGI容器及jar依赖管理。
QOS(Quality of Service,服务质量):监控 日志(哈勃,logstat)
容器接入层:Tomcat,Jboss
b087af20-8f20-4dd3-99f7-536e40bb1042

托福心得

这篇是写给福州新东方骗点高分奖金的……不过也算记录了一下自己的托福之旅吧。贴在这留个纪念,也为后人留点不敢说经验,权当教训吧。

我在2014年寒假,趁着春节放假回家的时间,报名了福州新东方的托福强化。之所以当时直接报的强化段,主要是因为自己的时间安排太紧,假期也比较短没有充足的时间上全程;此外针对自己的情况,认为自己亟需加强的是针对托福的解题思路与技巧,于是在做了一套测试题后就直接报了强化。事实证明新东方不愧是外语教学领域的领军者,即便只参加了强化段,仍然让我感觉收获颇丰。下面说说我一战托福的经验。

先介绍一下我的情况。我是2月8日开班后真正开始托福准备,此前只草草看过题型介绍,单词都没开始背(只有六级水平)。2月16结课后报了5月11的场;结果4月份因为一些个人原因将考试延期到6月28日。前前后后隔了4个多月。这里告诫大家如果可以,还是在上完班后尽早报考,效果会比较好。我属于反例,拖到临考前其实很多老师告诫的要点已经有些记不清了。

成绩方面,我的总分是104,听力和写作分别拿了28和27,阅读稍差一些26,口语比较拖后腿只有23,算是一个遗憾吧。先说说听力,我觉得新东方有一个观点特别对,就是唯听写是提升听力的唯一途径。我之前练听力的方式比较低效,就是在闲暇的时候反复听相同的材料,比如一些经典的外语演讲。刚开始可能能听懂50%~60%,但到后期就能感觉大部分都能听懂甚至能复述。个人认为这种方法对于长期培养语感可能有帮助,但对于中短期提升听力水平进展太慢。而换用老师提倡的直接听写TPO的conversation和lecture,而后和原文进行比对找出自己错误的点,分析为什么听不出来,是连读的问题,还是其他原因;然后针对性的加强,能够在短期内起到不错的效果。此外,好的笔记习惯也对考场上作答有很大帮助。平时就要针对性的训练自己快速而有条理的整理lecture笔记,并根据笔记尽可能复述原文。这样考场上不会慌乱,也能迅速定位题目对应的笔记位置并回想起细节。

写作的话,个人认为不要片面追求过于华丽的词汇和太复杂的句式。重要的是清晰明确且有理有据地表明自己的观点。但平时也不要只看题想观点而不练手。若很少练习,容易在考场上因为慌乱而脑子短路想不出句式回忆不起单词,最后只能拼凑简单句草草了事。独立写作不妨在开始动手前,花5分钟左右梳理出文章的脉络和论据,想想自己文章的亮点。从而使写作过程一气呵成。

阅读只能算不功不过。只能建议大家平时多做练习加快阅读速度,考场上只会比平时慢而不会快,即便快准确率也会没有保障。阅读的提升,技巧只能是锦上添花而不能雪中送炭。纯靠技巧,风险太高。

口语是短板,也是比较遗憾的点。只能说,口语套路相对固定,平时不能只在脑子里想或者在纸上写,一定要多张口说,这样考场上才不会磕磕绊绊,影响发挥也浪费答题时间。我就吃亏在平时张口练习太少,考场被周围的人影响而回答的并不流利。

最后想跟大家说的是,不要过度依赖机经。我在考前和同学交流得知5月份机经命中率极高,以为6月也能重现全中奇迹;没想到最后口语机经一道没中差点慌神。因此告诫大家,靠实力才是王道,机经不妨当做高保真模拟题。切勿依赖机经。

这就是我的托福一战经验。希望对大家有所帮助。

[7.22实习笔记] 校招实习生百阿百技培训笔记

前几天报名了今天的校招实习生百阿百技培训。今早9点半在1号楼的白马山庄准时开始。主持人先闲扯了下,介绍一天的计划,上午是华黎带来的关于阿里技术发展历程以及个人经验的分享,下午还有两场讲座但与技术关联不大。由于师兄还给我布置了任务,我就参与了上午的讲座就回来了。在这里整理一下上午听到的笔记,可能比较零散,凑合着看。

从集中式应用到分布式应用

淘宝07年的负载是每天100万笔订单,当时采用的还是集中式的系统。集中式系统并不落后,不要陷入唯分布式至上的误区。

08年时,淘宝的数据库力量非常强悍,Oracle认证有60%在淘宝。当时的策略是,性能瓶颈了都从数据库角度入手,优化SQL、建索引等……虽然数据库技术力量非常强,撑起了淘宝的高访问量,但这种做法始终是有瓶颈的,一旦负载超过了天花板,会没有补救的办法(没法加机器水平扩展)。当年JD的618大促挂了,刘强东说要加三倍的机器,但这不能解决问题。集中式应用不可扩展,所以淘宝决定升级架构。

但需要明确,集中式应用的开发和维护代价都比较小。

分布式应用需要解决的核心问题:如何利用多个节点解决计算和存储;应用解耦和异步化;

传统关系型数据库的集群方案不靠谱。淘宝面对非常多类型的存储。

淘宝2.0~3.0的转变。HSF,Notify和数据访问层 三个中间件让集中式走向分布式应用。

※做好接口!你的产品可以有问题,但你应该是第一个发现的,不能让别人跑来告诉你你的产品有问题。(程序员的尊严)

分布式调试非常困难(解耦后找不到消息去向)

如何做线上容量规划和评估(线上真实引流压测)

水平扩展和垂直扩展:工程师不要因为分布式能够水平扩展而过度依赖水平扩展;目前过度依赖加机器,而没有充分发挥单机性能。

同城多机房;异地多机房。

趋势

算法的价值:先发优势

云计算时代:开发让应用做到可伸缩

无线(天猫的无线优先)

DT:数据≠算法。能不能让存数据的成本低,能不能让数据计算快。业务工程师应该有数据的sense:业务如何为公司产生数据;如何在业务中利用数据;如何利用数据产生价值。

建议

站在风口。

选择对职业发展有帮助的公司和职位。机会和空间很重要。看书和学知识只是基础,实战很重要。

找个感兴趣的方向,很辛苦但不会很痛苦。

目标:定短期目标。随着年龄的增大时间会越来越碎,如果愿意在事业上有发展,刚毕业对自己狠一点。

危机感。推荐书籍《浪潮之巅》。

[7.21实习笔记] Notify入门

待更新……

0

1

2

Notify Metamorphosis
模型 Push Pull
服务端 消息存储

处理请求

保存推送轨迹

保存订阅关系

消费者负载均衡

集中式

消息存储

处理请求

分布式

客户端 处理响应和请求 处理响应和请求

保存pull状态,如拉取位置的偏移量offset

异常情况下的消息暂存和recover

实时性 较好,收到数据后可立即发送给客户端 取决于pull的间隔时间
消费者故障 消费者故障情况下,服务端堆积消息,重复推送耗费资源。

保存推送轨迹压力很大。

消费者故障,对服务端无影响
其他 对消息推送有更多控制,能实现多样化的推送机制。

当消费者数量增多的时候,推送压力大,性能天花板。

消费者处理能力差异,导致堆消息

需要在客户端实现消息过滤,浪费资源。

需要在不同客户端之间协调,做负载均衡。

推荐资料

Notify 淘宝百科:http://baike.corp.taobao.com/index.php/Notify

(【对比】Metamorphosis淘宝百科:http://baike.corp.taobao.com/index.php/Metamorphosis-User-Guide

Notify Wiki:http://gitlab.alibaba-inc.com/notify/notify1/wikis/user-manual

(【对比】Metamorphosis Wiki:http://gitlab.alibaba-inc.com/middleware//metaq3/wikis/metanotes

Notify 学习视频:http://xue.alibaba-inc.com/trs/mediaDetail.htm?mediaUid=1ac893ae-01e1-4f64-a863-5f5a5f575b34

《Taobao Notify Overview》:http://baike.corp.taobao.com/images/e/eb/Taobao_Notify_Overview.pptx

《Notify Principle》:http://baike.corp.taobao.com/images/2/24/Principle.pptx

[7.14实习笔记] Maven入门

今天主要学习了Maven。整理记录一下。

Maven 是 Java 项目的一个构建工具,阿里内部使用Maven 2.2.1作为项目构建工具。

【Tips】关于Maven和后面WebX的学习,建议参照WebX提供的样例petstore进行对照理解。petstore的Github仓库地址为:https://github.com/webx/citrus-sample/tree/master/petstore

安装配置

安装

安装过程在上一篇博客中已经写过了:

[7.11实习笔记] 环境搭建 JDK+IDEA+MAVEN+JBOSS+HSF+SVN

配置

首先,我们要介绍一下仓库的概念。

在不用Maven的时候,比如说以前我们用Ant构建项目,在项目目录下,往往会看到一个名为/lib的子目录,那里存放着各类第三方依赖jar文件,如log4j.jar,junit.jar等等。每建立一个项目,你都需要建立这样的一个/lib目录,然后复制一对jar文件,这是很明显的重复。重复永远是噩梦的起点,多个项目不共用相同的jar文件,不仅会造成磁盘资源的浪费,也使得版本的一致性管理变得困难。此外,如果你使用版本管理工具,如SVN,你需要将大量的jar文件提交到代码库里,可是版本管理工具在处理二进制文件方面并不出色。

Maven仓库就是放置所有JAR文件(WAR,ZIP,POM等等)的地方,所有Maven项目可以从同一个Maven仓库中获取自己所需要的依赖JAR,这节省了磁盘资源。此外,由于Maven仓库中所有的JAR都有其自己的坐标(坐标的概念将在下面提到),该坐标告诉Maven它的组ID,构件ID,版本,打包方式等等,因此Maven项目可以方便的进行依赖版本管理。你也不再需要提交JAR文件到SCM仓库中,你可以建立一个组织层次的Maven仓库,供所有成员使用。

简言之,Maven仓库能帮助我们管理构件(主要是JAR)。

Maven的仓库分为本地仓库远程仓库。运行Maven的时候,Maven所需要的任何构件都是直接从本地仓库获取的。如果本地仓库没有,它会首先尝试从远程仓库下载构件至本地仓库,然后再使用本地仓库的构件。

关于仓库的 详细介绍,可参见:http://juvenshun.iteye.com/blog/359256

为什么要谈到这个概念呢?因为它是Maven的配置文件settings.xml的很重要的一部分。这个配置文件一般存在在两个地方,分别是用户目录下的.m2目录里,以及maven安装目录的conf目录中。

打开这个配置文件,我们主要关注下面几项内容:

<localrepository>:这一项指定了本地仓库的存储目录。

<mirrors>:这一项指定了远程仓库的镜像地址。如果你的地理位置附近有一个速度更快的central镜像,或者你想覆盖central仓库配置,或者你想为所有POM使用唯一的一个远程仓库(这个远程仓库代理的所有必要的其它仓库),你可以使用这项配置。

<profiles>:profile可以让我们定义一系列的配置信息,然后指定其激活条件。这样我们就可以定义多个profile,然后每个profile对应不同的激活条件和配置信息,从而达到不同环境使用不同配置信息的效果。比如说,我们可以通过profile定义在jdk1.5以上使用一套配置信息,在jdk1.5以下使用另外一套配置信息;或者有时候我们可以通过操作系统的不同来使用不同的配置信息,比如windows下是一套信息,linux下又是另外一套信息,等等。关于profile的具体使用可参见:http://haohaoxuexi.iteye.com/blog/1900568

IntelliJ IDEA中配置Maven

在IntelliJ IDEA中使用Maven,可以在File→Settings→Project Settings→Maven中进行设置。

其中可以在Runner项下设置vm options: -Xmx512m -XX:MaxPermSize=1024m

项目结构

Maven的项目使用一个统一的约定的标准目录结构(Standard Directory Layout)。如下所示:

my-app
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- com
    |           `-- mycompany
    |               `-- app
    |                   `-- App.java
    `-- test
        `-- java
            `-- com
                `-- mycompany
                    `-- app
                        `-- AppTest.java

这是一个典型的项目目录结构。

目录结构最顶层,是一个POM文件pom.xml(关于POM会在下面详细讲)。另外也可以有README.txt,LICENSE.txt等说明性文本。

子目录只有两种,src和target。其中target主要是存储build出来的东西的,src是存储所有的源代码的。它可以有这几种子目录:main(存放主要的构建代码);test(存放单元测试代码和资源),site,等。

在存储源代码的目录下(main,test等),有java(存放java代码),webapp(存放网络应用程序代码)和resource(存放资源)等目录。

src/main/java 应用程序/库的源代码
src/main/resources 应用程序/库的资源
src/main/filters 资源过滤文件
src/main/config 配置文件
src/main/scripts 应用程序/库的脚本
src/main/webapp 网络应用程序源代码
src/test/java 测试源代码
src/test/resources 测试资源
src/test/filters 测试资源过滤文件
src/it 集成测试(主要用于插件)
src/assembly 装配说明
src/site 站点
LICENSE.txt 项目许可协议
NOTICE.txt 项目所依赖的库所要求的说明和权限
README.txt 项目自述文件

POM

现在进入了Maven很重要的一个概念:POM(Project Object Model)。POM是Maven的核心,它以XML格式描述了所有与项目有关的信息。

首先介绍一个概念:坐标

坐标是指项目的唯一标识,以 GAV(groupId,artifactId 和 version)区分,这里我们可以将 groupId 理解为某某公司的 xxx 组或者产品线,开发了某一个项目,对应的版本为 XXX。这里 groupId 包含公司和内部组(或产品线)的信息,如 org.apache.commons,表示 Apache
软件组织下的 Java Commponents 产品线;ArtifactId 则表示项目的名称,如 commons-io,表示项目名称,Version 则表示某一 Artifact 的版本,如 1.3.2,1.3.3-SNAPSHOT 等。

当我们打开一个POM文件,首先看到的是一段描述我们正在建立的artifact信息:

[xml]
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
[/xml]

这是强制性的开端部分。接下来是一组坐标。描述了当前项目的groupId, artifactId, version和name。

下面是<properties>。我们可以把properties理解为一组自定义的变量。我们可以在下面定义的依赖中使用这些变量,这样未来在我们需要升级包版本等场景时,可以通过修改变量的值来方便的实现。大家可以参照petstore的pom.xml文件来理解。

而后是依赖管理的部分。

[xml]
<dependencies>
<dependency>
<groupId>jdbm</groupId>
<artifactId>jdbm</artifactId>
<version>1.0</version>
</dependency>
[/xml]

这是一个获取jdbm的简单依赖。默认情况下,Maven通过访问http://www.ibibio.ort/maven2/来获得依赖,如果你查看jdbm/jdbm/1.0/目录,就会发现jdbm-1.0.jar文件,Maven将恢复它;以及一个简短的jdbm pom.xml文件,它列举artifact本身拥有的任何依赖。你可以手动浏览ibibio贮藏库或使用MVN Registry这样的网站来搜索贮藏库。

下一个要讨论的依赖是dwr,但你在ibibio贮藏库中找不到它。你必须将它安装到我们自己的本地贮藏库中。

[xml]
<dependency>
<groupId>dwr</groupId>
<artifactId>dwr</artifactId>
<version>2.0M3</version>
</dependency>
[/xml]

下一个依赖为Java Servlet API。在ibibio库中可以找到它,但我们只有在建立项目的时候才需要它;因为当我们配置一台网络服务器时,servlet API已经存在。

[xml]
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4-20040521</version>
<scope>provided</scope>
</dependency>
[/xml]

scope说明何时需要这个artifact,因此“provided”说明artifact由运行时间环境提供。另一个scope类型为“test”,它说明只有在测试时需要artifact。例如,我们这样包括Junit:

[xml]
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
[/xml]

那么,我们如果想引入一个依赖,应该怎么写这个dependency呢?其实我们可以通过远程仓库来搜索每个构建对应的XML描述。

常用的搜索页面有:maven.oschina.net,以及search.maven.org。我们在其中搜索一个构建,便可以得到它对应的XML描述。

现在,POM还剩最后一块内容:插件。

[xml]
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
[/xml]

Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成,例如编译源代码是由maven-compiler-plugin完成的。进一步说,每个任务对应了一个插件目标(goal),每个插件会有一个或者多个目标,例如maven-compiler-plugin的compile目标用来编译位于src/main/java/目录下的主源码,testCompile目标用来编译位于src/test/java/目录下的测试源码。

生命周期

Maven强大的一个重要的原因是它有一个十分完善的生命周期模型(lifecycle),这个生命周期可以从两方面来理解,第一,顾名思义,运行Maven的每个步骤都由它来定义的,这种预定义的默认行为使得我们使用Maven变得简单,相比而言,Ant的每个步骤都要你手工去定义。第二,这个模型是一种标准,在不同的项目中,使用Maven的接口是一样的,这样就不用去仔细理解每个项目的构建了,一般情况下,mvn clean install 这样的命令是通用的。

Maven有三套相互独立的生命周期,请注意这里说的是“三套”,而且“相互独立”,初学者容易将Maven的生命周期看成一个整体,其实不然。这三套生命周期分别是:

  • Clean Lifecycle 在进行真正的构建之前进行一些清理工作。
  • Default Lifecycle 构建的核心部分,编译,测试,打包,部署等等。
  • Site Lifecycle 生成项目报告,站点,发布站点。

我再次强调一下它们是相互独立的,你可以仅仅调用clean来清理工作目录,仅仅调用site来生成站点。当然你也可以直接运行 mvn clean install site 运行所有这三套生命周期。

知道了每套生命周期的大概用途和相互关系以后,来逐个详细看一下每套生命周期,Clean和Site相对比较简单,先解释一下。

每套生命周期都由一组阶段(Phase)组成,我们平时在命令行输入的命令总会对应于一个特定的阶段。比如,运行mvn clean ,这个的clean是Clean生命周期的一个阶段。有点绕?要知道有Clean生命周期,也有clean阶段。Clean生命周期一共包含了三个阶段:

  • pre-clean  执行一些需要在clean之前完成的工作
  • clean  移除所有上一次构建生成的文件
  • post-clean  执行一些需要在clean之后立刻完成的工作

mvn clean 中的clean就是上面的clean,在一个生命周期中,运行某个阶段的时候,它之前的所有阶段都会被运行,也就是说,mvn clean 等同于 mvn pre-clean clean ,如果我们运行 mvn post-clean ,那么 pre-clean,clean 都会被运行。这是Maven很重要的一个规则,可以大大简化命令行的输入。

下面看一下Site生命周期的各个阶段:

  • pre-site     执行一些需要在生成站点文档之前完成的工作
  • site    生成项目的站点文档
  • post-site     执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
  • site-deploy     将生成的站点文档部署到特定的服务器上

这里经常用到的是site阶段和site-deploy阶段,用以生成和发布Maven站点,这可是Maven相当强大的功能,Manager比较喜欢,文档及统计数据自动生成,很好看。

最后,来看一下Maven的最重要的Default生命周期,绝大部分工作都发生在这个生命周期中,这里只解释一些比较重要和常用的阶段:

  • validate
  • generate-sources
  • process-sources
  • generate-resources
  • process-resources     复制并处理资源文件,至目标目录,准备打包。
  • compile     编译项目的源代码。
  • process-classes
  • generate-test-sources 
  • process-test-sources 
  • generate-test-resources
  • process-test-resources     复制并处理资源文件,至目标测试目录。
  • test-compile     编译测试源代码。
  • process-test-classes
  • test     使用合适的单元测试框架运行测试。这些测试代码不会被打包或部署。
  • prepare-package
  • package     接受编译好的代码,打包成可发布的格式,如 JAR 。
  • pre-integration-test
  • integration-test
  • post-integration-test
  • verify
  • install     将包安装至本地仓库,以让其它项目依赖。
  • deploy     将最终的包复制到远程的仓库,以让其它开发人员与项目共享。

基本上,根据名称我们就能猜出每个阶段的用途,关于其它阶段的解释,请参考 http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

记住,运行任何一个阶段的时候,它前面的所有阶段都会被运行,这也就是为什么我们运行mvn install 的时候,代码会被编译,测试,打包。

骨架

Maven约定的项目目录结构,如果手动创建,每个工程的重复工作非常多。为此,Maven提供了Archetype以帮助我们快速勾勒出项目骨架。

在IntelliJ IDEA中,使用Maven的骨架创建项目非常简单。我们只需选择File→New Project→Maven,勾选Create from archetype,然后在下方选择所需要使用的骨架(例如maven-archetype-webapp),点击Next按照向导提示操作即可。在选择骨架时,也可以直接输入关键词查找相应的骨架。

资料推荐

一些maven书籍介绍和一些maven视频介绍:
http://pan.baidu.com/s/1hq00qLA

国外非常不错的学习材料网站,集成了介绍、快速引导,书籍推荐等:
http://www.tutorialspoint.com/maven/index.htm

maven官网:
http://maven.apache.org/

官网介绍什么是maven:
http://maven.apache.org/what-is-maven.html

maven2和maven3的区别(目前主流是maven3):
http://tech.it168.com/a2010/1108/1123/000001123274_all.shtml
http://www.infoq.com/cn/news/2011/07/xxb-maven-10-time-to-update

maven下载:
http://maven.apache.org/download.cgi
windows需要下载的文件:apache-maven-版本号-bin.zip

maven官网5分钟速成:
http://maven.apache.org/guides/getting-started/maven-in-five-minutes.html

maven官网入门指南:
http://maven.apache.org/guides/getting-started/index.html

FAQ英文官网:
http://maven.apache.org/general.html

FAQ英文非官网:
http://docs.codehaus.org/display/MAVENUSER/FAQs-1

maven一些插件列表:
http://maven.apache.org/plugins

Maven 的41种骨架功能介绍:
http://www.cnblogs.com/iusmile/archive/2012/11/14/2770118.html
http://docs.codehaus.org/display/MAVENUSER/Archetypes+List