kevx's Writing

架构 / 云计算 / 技术管理 | kevx@outlook.com 未经授权请勿转载©

Contact Me

技术体系切换与基础框架构建

内容提纲

  • 概述
  • 技术框架
  • 编码风格
  • 分层约定
  • 边界约定
  • 基础服务
  • 调试&测试
  • 部署运维
  • 审计&监控

堆糖之前的系统主要是以python为主,随着业务的增长和开发人员的增多,python无论是在性能上还是可维护性上都反映出相当的不足,因此为了后续公司能够继续前行,我们决定建立基于JAVA的WEB系统,承载堆糖核心web系统逻辑,在性能,维护性,调试,运维层面达到较高的水平,满足堆糖未来一到三年内的需求。

以下几点原则贯穿整个设计过程中

  • 设计:逻辑非潜规则,词汇命名统一,代码风格统一,代码逻辑层次清晰,引入领域模型思想
  • 性能:响应时间,吞吐量,数据量,使用频率
  • 安全:外网可访问,访问审计,防攻击,访问控制
  • 稳定:告警通知机制,可用性要求,维护状态
  • 扩展:配置动态化
  • 测试:易于测试,测试数据容易获取/造出,易于调试
  • 观测:系统运行状态和关键参数可以被观测到

技术框架选型

Web:Spring MVC,成熟稳定,文档/社区丰富。 Template: Freemarker,与现有保持兼容,易于使用 Test: JUnit & EasyMock

编码风格

使用标准Eclipse或IDEA的编码格式。 目录组织结构如下:

src/main/java:应用代码
src/test/java:应用单元测试代码
src/main/resources:应用非代码资源,将被装配到classpath:/
src/main/webapp/WEB-INF/spring:spring相关配置文件
src/main/webapp/WEB-INF/props:各种properties文件
src/main/webapp/WEB-INF/templates:模板文件
conf/:编译时配置项(运行时静态值)

其中src/main/java包结构约定如下:

  1. 所有包均以com.duitang.开头;
  2. 以下内容中[BIZ]是业务域的名称或者代号

分层约定

展示层:

面向终端用户的展现逻辑,分成模版渲染和Json数据直接输出两种。 com.duitang.views.[BIZ]

远程服务层:

定义对其他应用暴露的rpc接口。一般来说不允许直接暴露对外接口, 只能通过gateway类的系统来中转。

com.duitang.facade.[BIZ]:对外接口定义
com.duitang.facade..[BIZ].impl:对外接口实现

领域服务层:

跨领域模型的服务,以动词开头 com.duitang.domain.services.[BIZ]:领域模型的具体代码实现 特征: 1,与领域相关操作不是实体的一个自然部分 2,接口是根据领域模型的其他元素定义 3,操作是无状态(即客户端可以使用service的任何一个实例,而不关心 这个实例的历史状态

领域实体层:

高内聚的业务逻辑模型,领域模型=业务数据+业务逻辑 com.duitang.domain.models.[BIZ]

仓库层:

领域模型的数据来源 com.duitang.domain.repo.[BIZ],仓库与传统的DAO本质区别在哪? 仓库本身是有业务含义的,并且有可能是跨表跨库,而DAO是业务无感知的, 一般不能跨表。

基础设施

com.duitang.infrastructure,如基础消息服务,邮件服务等

基础工具类

com.duitang.infrastructure.utils,如常用字符串处理函数

以上各层与经典领域模型的对应关系

展示层,远程服务层 边界对象 领域服务层 控制对象 领域实体层,仓库层 实体对象

有四个规则对应上面的三种分析类对象间的交互

  1. 用例的参与者只能与边界对象交互
  2. 边界对象只能与控制对象和动作者交互(即不能直接访问实体对象)
  3. 实体对象只能与控制对象交互
  4. 控制对象可以和边界对象交互,也可以和实体交互,但是不能和动作者交互

边界约定

系统自身定位是面向终端用户的前台系统,原则上不应该处理复杂的业务逻辑,不允许直接操作数据库。 但是什么才算复杂的业务逻辑?一般来说,凡是要改动3个以上的数据实体(如table,Mongo,cache等),并且该逻辑在其它系统如doctor中也会用到,就归为复杂的业务逻辑,例如[屏蔽Blog]。这类逻辑需要下沉到mandala或类似系统中。

对于查询类逻辑这里暂时不做限制。

基础服务

在框架层面提供下面这些基础服务: 1,session。通过filter实现,默认都不需要登录,通过配置文件显示指定需要登录的页面。 2,security-utils,通过FreeMarker-Extension提供安全工具,在模版中可直接引用,来对输出到模版的变量进行安全控制。 3,rpc: avro和dboss

调试&测试

Java项目具有高强度和完备的调试机制,在启动脚本中加上相关参数即可开启此功能,开发者可以通过eclipse等工具在线接入,实时调试代码,还具备动态执行代码,动态更改变量值的特性。为了方便排查问题,该系统启动脚本将统一默认开启此功能。

对于测试,通过easymock将repo层的代码给mock掉,然后junit来跑src/test/java下的代码,具体可以参考工程中的demo。

部署运维

当前堆糖老系统的部署是通过其内嵌的jetty来完成的。这里存在比较大的问题在于发布时分发的是一个目录,存在漏文件或者传输不完全的现象。另外内嵌jetty本身并不是一个符合长远计划的做法,因为这样将导致开发与运维职责无法切分清晰。 因此本系统将以纯粹的war包进行打包和分发,在目标机器上事先由运维完成容器的预部署。

环境配置项

对于不同的环境,编译打包时使用的配置是不同的。在运行时,某些配置也可能会动态变化,动态变化的配置我们统一存储在zookeeper,通过zk来进行配置分发。

监控

监控分成应用内部监控和运维层面监控,这里并不涉及后者,后者可以通过广为人知的jvm自带工具来达成。 所谓应用内部监控是指应用自身实时读取分析运行状态,并在达到阀值的情况下对外预警。另外一个方面就是这些运行状态需要通过一定方式对外暴露,以便我们可以随时获取情况。

审计

很多情况下需要知道某个模块执行耗时情况,因此开发出链路跟踪。

链路跟踪

在每个前端请求进入的地方生成唯一的token并放入ThreadLocal,在领域服务层和repo层均进行aop拦截,将执行开始、结束时间以及token写入链路日志。这些数据将进入到hadoop供后面详细分析使用。详情见CCT的介绍(在前面文章中)。

返回主页