一个业务系统的架构设计

[本文(一个业务系统的架构设计)原始地址]http://xcoder.me/2017-05/architecture/系统架构演进/

之前开发了一个包括多端(PC端,移动端,微信端,API)的B2B系统,分享一下系统的架构设计演进。

技术选型

Web端选型

  • playframework
    无状态
    全栈(Hibernate,Netty,Groovy,Cache)
    Python运维支持,开发热加载
  • AngularJS
    对象操作
    双向绑定
    模版

这样的技术选型是基于低成本/小规模团队快速上线应用的需要。

选择playframework是它让我们从开发到运维都能省去很多成本,对于开发人员只要掌握一定的语法就可以直接关注业务逻辑,不用所有的人都特别深入的学习框架。

  • 自动编译和重载:当编辑Java文件并保存后,刷新浏览器就能立即查看结果。使用playframework开发(生产还是需要重启的)不需要手动编译、部署以及重新启动Web服务器等操作。
  • 无状态模型:playframework是真正的无共享框架,为REST而准备。它可以将同一个应用的多个实例分别部署在多台服务器上,因而扩展性非常强。
  • 高效的模板引擎:基于表达式语言Groovy的清晰模板引擎,提供了模板的继承、导入以及标签自定义等功能。
  • 快速解决错误:当错误发生时,playframework(play1)会在浏览器中显示出错代码块并提示问题发生的确切位置。
  • Full Stack:提供创建Web应用所需的全部功能,集成了Hibernate、OpenID、Memcached等第三方类库。
  • 纯Java:playframework(play1)采用Java编写代码,可以方便地使用任何Java类库,并且能够非常好地和Eclipse、Netbeans等IDE集成,只需通过命令生成匹配的项目文件即可。
  • 基于非阻塞的IO模型:允许创建基于长轮询和WebSocket的主流Web应用。
  • 有趣并且高效:省去了Java应用重启的时间,提高了应用的开发效率。

选择AngularJS是我们的应用更多的是后台应用,在2014年轻量级可选择的还只有knockout和angular,考虑到谷歌以及丰富的控件组件,mvvm的便捷实用我们选择了它,现在它仍然在很好的发挥着作用,在前端开发人手不足时能让后台开发也能以面向对象的方式介入前台开发,以便应用快速上线。

移动端选型

  • Node.js
    事件驱动、非阻塞式 I/O
    让前端有更大自由度
    运维工具丰富

  • Framework7
    集成Dom7(选择器)和Template7(模版引擎)
    类IOS7基本和原生无差别的用户体验
    阿里进一步优化了兼容性问题

这样的技术选型让前端有更大的自由度,同时Framework7的选择让前端可以一套代码同时运行在Android,iOS,微信,移动网站多个终端上。能够降低前端开发的成本,同时还能有很好的用户体验。

架构演进

没有最好的架构,只有最适合的架构

1
2
3
4
5
6
7
8
9
10
11
12
13
* 安全性
权限体系(数据权限/功能权限)
全站HTTPS(HSTS)
BizContext-全局中间层接入租户信息,用户信息
* 稳定性
负载均衡(运行高可用,发布高可用)—SLB!Nginx
云存储– Qiniu/OSS!GFS,HDFS,TFS,QFS,Haystack
* 性能/效率
实体缓存,业务缓存,异步任务,CDN,前端资源压缩/合并
* 扩展性
回调解耦,插件机制,开放接口,事件机制,业务选项,自定义菜单
* DevOps
监控(硬件/数据库/应用),日志,自动上线, 7*24运维保障

SAAS和单机应用对比

SAAS和单机应用对比

架构设计

架构演进

架构设计

我们并不是只用playframework提供的功能而已,在playframework的基础上考虑整体的性能和扩展自定义开发等方面我们在playfamework上做了一些改造

应用设计

整体架构图

  • 强制使用上下文(控制边界/业务隔离)
    这个应用是个多租户的应用,成本考虑不可能每个租户一个库,多个租户在同一个库中就存在租户信息不隔离不安全的问题,我们在数据访问层强制控制,不让业务通过租户字段访问,而是公共部分统一插入租户信息,这样既让业务无须关心租户,当前用户等业务周边信息,也能让类似租户信息更安全。
  • 实体缓存(提高效率)
    为了提高系统操作效率,我们为每个实体访问都设置了缓存,且无需业务干预和操作。能够极大的提高数据库的IO吞吐量。
  • 引入元数据(规范操作,公共问题公共处理)
    引入元数据可以让业务有更多可复用,更多可配置及更聚焦业务本身。比如有些业务表需要有审计功能(需要知道某条记录是谁修改,谁添加的),这个业务实体就可以实现审计接口,然后公共统一异步多线程处理审计问题,既能保证高效也能减少耦合。
  • 回调机制(解耦/二开)
    让业务之间不再通过代码相互调用,减少业务耦合。同时还可以更方便的让二次开发通过这个机制参与进来。
  • playframework服务化(前后端分离/代码复用/更丰富的API)
    我们现在并没有让playframework来直接渲染界面,而是将playframework服务化,即它只提供后台多终端服务,前端通过Node.js或PHP来展现,前后端分离,更易维护,也让后端能发挥更大的作用。同时后端还可以随时被更高效的框架或者语言替代(比如scala,go)。
  • Swagger:API量化(测试深入参与后端服务接口测试)
    前后台通过标准API文档交互,同时第三方开发者也能有标准规范的开发文档。而且业务接口变更或者新增,文档能够即时的更新,而不用手工操作!
  • 大量使用多线程编程来提升系统运行效率
    大量的异步多线程操作来保证系统运行效率。

同时我们使用阿里云的OSS来做静态资源(JS/CSS的存储),使用七牛云存储来存储站点的大量图片和附件信息。

  • 解决前端页面加载效率因地区而异
  • 节省带宽资源
  • 专注业务处理
  • 为集群服务铺路

在运维上我们做了一些优化提升

  • 全站HTTPS
    提高处理效率(相对部分HTTPS)
    提升系统安全性
  • 负载均衡
    避免单点积压
    提升系统稳定性
    提升访问性能
  • 分布式memcached服务
    避免单点雪崩效应
    单实体强制缓存化(有效利用缓存分担数据库压力)
  • ELK
    提供集群部署下快速分析解决问题的入口和渠道
  • Swagger-API文档
    方便前后台分离协同开发及第三方开发者社区规范开发
小英雄雨来 wechat
扫码二维码或搜索"架构演进之旅"订阅微信公众号
enjoy?donate!