概念
术语
- MVC
MVC允许在不改变视图的情况下改变视图对用户输入的响应方式,用户对View的操作交给了Controller处理,在Controller中响应View的事件调用Model的接口对数据进行操作,一旦Model发生变化便通知相关视图进行更新。
- MVP
虽然在MVC里,View是可以直接访问Model的,但MVP中的View并不能直接使用Model,而是通过为Presenter提供接口,让Presenter去更新Model,再通过观察者模式更新View。
- MVVM
MVVM把View和Model的同步逻辑自动化了。以前Presenter负责的View和Model同步不再手动地进行操作,而是交给框架所提供的数据绑定功能进行负责,只需要告诉它View显示的数据对应的是Model哪一部分即可。
例如:Vue
指标
- 性能
指标:
- 吞吐量
- 响应速度
- 高并发(无状态设计,有状态可能涉及锁操作;保持合理的粒度;缓存、异步、队列、并发、扩容等技巧)
优点:
- 节省硬件资源
- 高可用性(就是抵御不确定性,保证系统7*24小时健康服务)
https://www.toutiao.com/i6501434365174612494/
指标:
- 避免单点故障
- 任何发布必须具有可回滚能力
- 外部依赖风险,是否可降级,是否可无损降级,并提供降级开关
方法:
- 系统人员负责制、人员备份制、值班制
- 副本、隔离、配额、提前预案、探知
- 应急预案
- 复盘、思考、技改
- 容错性
指标:
*
- 健壮性
指标:
- 海量流量进来,不能冲击到后端应用系统
方法:
- 接口必须配置好限流,限流值必须尽量准确可靠
- 故障自愈
- 易用性
指标:
- 用户体验
- 易部署
- 易扩容
方法:
- 使用简单
- 自动化接入
- 自动化配置
- 自助扩容
- 基于 Docker 部署
- 安全性
指标:
- 防抓取
- 防刷单
- 防表单重复提交
方法:
- 权限管理
- 监控报警
- 指标查看
- 故障发生时自动现场保留
- 后台操作可追溯
- 可维护性
指标:
- 排错手段
*
方法:
- 代码注释
- 代码标注
- 自动化API文档
- 高质量
指标:
- 测试
方法:
- 自动化回归测试
- 开发的 Alpha 测试环境;Beta 环境验证是否可以上线;Prod 环境用于线上生产;
什么是架构
http://www.infoq.com/cn/articles/an-informal-discussion-on-architecture-part01
==架构实际上解决的是人的问题==
- 根据要解决的问题,对目标系统的边界进行界定。
- 并对目标系统按某个原则的进行切分。切分的原则,要便于不同的角色,对切分出来的部分,并行或串行开展工作,一般并行才能减少时间。
- 并对这些切分出来的部分,设立沟通机制。
- 根据3,使得这些部分之间能够进行有机的联系,合并组装成为一个整体,完成目标系统的所有工作。
识别问题
要做好架构所首先必须具备的能力,就是能够正确的认识概念,能够发现概念背后所代表的问题,进而才能够认识目标领域所需要解决的问题,这样才能够为做好架构打好基础。
一般来说,如果把真正的问题找到,那么问题就已经解决80%了。这个能力基本上就决定了架构师的水平。
当我们去解决一个问题的时候,一定要先把问题搞清楚。
要正确的认识问题,需要问两个问题:
- 这是谁的问题?(找出问题的主体)
- 有什么问题?
架构设计
- 架构设计的优势
- 更好的梳理业务的结构体系;
- 更好的拓展、维护及性能优化;
- 更好的适应企业业务灵活的推进;
更好的适应大数据的冲洗和应对;
清洗主要步骤:
* 获取: 主要来源包括——自有(关系数据库同步)、自采(探针/爬虫等手段)、外购 涉及的关键点——数据的维度定义;探针节点的选择及采集方式(依据具体业务而定);外购数据源的选择及价值识别(可信度等)。 * 清洗入库:对数据源进行清洗及其他所需的预处理入库。 * 分析、给数据打标签以用于后续的挖掘:基于业务需求选择所需的字段并分析 * 挖掘:这就看开脑洞的程度了
更好的稳定性、低成本及快速迭代;
- 架构设计时需要注意的地方
不是怎么把架构搭建起来,而是必须根据业务需求,严格分析,实现该需求需要什么技术会更好,及考虑更长远的发展;
性能需要跟起来
- 架构设计的策略
平台的需求
客户的需求为最高,也代表了企业的核心需求
还包括其它很多非功能性需求
平台的业务架构
根据业务的需求进行子系统模块划分
根据各个子系统的核心等级,可拆分出核心子系统和非核心子系统
业务拆分目的:
为了解决各个模块子系统间的耦合、维护及拓展性; 方便单独部署子系统,避免集中部署导致一个出问题,全部不能用; 分配专门的团队,负责具体的子系统,最大化工作效率安排; 应对大数据,高压力时,保护核心子系统正常使用;
平台的技术架构
需要一个技术架构的演变过程,技术架构的搭建不是一蹴而就的,而是随着业务的不断衍变,系统的架构会逐渐完善更新,以实现应对业务数据量的冲击
一切只为满足用户的体验和支撑为前提
基本的架构设计:
a. 单机服务器架构,50万用户数据以内 b. 将图片单独存放在独立服务器中,并且在架构中引入了Cache中间件,100万用户数据以内
初级的架构设计:
a. 三台服务器,一台部署应用,一台部署数据库,一台部署NFS文件系统 将各个规模庞大并耗用性能的部分剥离到不同服务器设备,再配备必要的缓存中间件,基本可以满足近1000万的数据量 b. 采用集群的方式来实现负载均衡和高可用性,使用Cache中间件来存储和管理Session信息
优化的架构设计:
为解决高并发,高可用的架构设计方案,主要采用了分布式、集群、负载均衡、反向代理、消息队列及多级缓存技术。
平台架构的总结
架构按层次结构罗列组织,共分为四层,层次分工明确,高拓展,低耦合,负载均衡、集群、分布式及缓存等技术的使用,架构如下:
架构切分
- 切分就是利益的调整
- 为什么需要切分
- 某个或者某些利益相关人负载太重。
- 时间上的负载太重。
- 空间上的负载太重,本质上还是时间上的负载太重。
- 某个或者某些利益相关人的权利和义务不对等。
- 切分的原则
- 必须在连续时间内发生的一个活动,不能切分。比如孕妇怀孕,必须要10月怀胎,不能够切成10个人一个月完成。
- 切分出来的部分的负责人,对这个部分的权利和义务必须是对等的。比方说妈妈10月怀胎,妈妈有权利处置小孩的出生和抚养,同样也对小孩的出生和抚养负责。为什么必须是这样呢? 因为如果权利和义务是不对等的话,会伤害每个个体的利益,分出来执行的效率会比没有分出来还要低,实际上也损害了整体的利益,这违背了提升整体利益的初衷。
- 切分出来的部分,不应该超出一个自然人的负载。当然对于每个人的能力不同,负载能力也不一样,需要不断的根据实际情况调整,这实际上就是运营。
- 切分是内部活动,内部无论怎么切,对整个系统的外部应该是透明的。如果因为切分导致整个系统解决的问题发生了变化,那么这个变化不属于架构的活动。当然很多时候当我们把问题分析的比较清楚的时候,整个系统的边界会进一步的完善,这就会形成螺旋式的进化。但这不属于架构所应该解决的问题。进化的发生,也会导致新的架构的切分。
切分与建模
实际上切分的过程就是建模的过程,每次对大问题的切分都会生成很多小问题,每个小问题就形成了不同的概念。
对于一个企业也是一样的,一开始一个人干所有的事情。当业务量逐渐变大,就超过了一个人能够处理的容量,这些内容就会被分解出来,开始招聘人进来,把他们组合在一起,帮助处理企业的事务。整个企业的事务,就按照原则2,分出来了很多新的概念:营销,售前,售中,售后,财务,HR等等。企业的创始人的工作就变成了如何组合这些不同的概念完成企业的工作。如果业务再继续增大,这些分出来的部分还要继续分拆,仍然要按照原则2才能够让各方达到利益最大化。如果某个技术的提升,提高了某个角色的生产力,使得某个角色可以同时在承担更多的工作,就会导致职责的合并,降低树的层数。
切分的输出和组织架构
架构切分的输出实际上就是一个系统的模型,对于一个整体问题,有多少的相关方,每个相关方需要承担哪些权利和义务,不同的相关方是如何结合起来完成系统的整体任务的。有的时候是从上往下切(企业),有的时候是从下往上合并,有的时候两者皆有之(人类社会的发展)。而切分的结果最终都会体现在组织架构上,因为我们切分的实际上就是人的利益。
从这方面也可以看出,任何架构调整都会涉及到组织架构,千万不可轻视。同样,如果对于stakeholder的利益分析不够透彻,也会导致架构无法落地,因为没有人愿意去损坏自己的利益。一旦强制去执行,人心就开始溃散。这个也不一定是坏事,只要满足原则2就能够很好的建立一个新的次序和新的利益关系,保持组织的良性发展,长久来看是对所有人的利益都有益的,虽然短期内有对某些既得利益者会有损害。
总结
- 架构的切分的导火索是人的负载太重。
- 架构的切分实际就是对stakeholder的利益进行切分或合并,使得每个stakeholder的权责是对等的,每个stakeholder可以为自己的利益负责。
- 架构切分的最终结果都会体现在组织架构上,只有这样才能够让架构落地并推进。
- 架构切分的结果一定是一个树状,这也是为什么会产生分层。层数越多沟通越多,效率越低,分层要越少越好。尽可能变成一颗平衡树,才能让整个系统的效率最大化。
软件架构
软件架构实际上包括了:代码架构,以及承载代码运行的硬件部署架构。
实际上,硬件部署架构最终还是由代码的架构来决定。因为代码架构不合理,是无法把一个运行单元分拆出多个来的,那么硬件架构能分拆的就非常的有限,整个系统最终很难长的更大。
部署架构:软件因为流量增大而分拆成不同的运行单元,在不同的机器上部署所形成的架构,属于软件架构。
代码架构:每个运行单元为了让不同角色的人,比如前端,业务,数据存储等能够并行工作,所分成的代码架构,也属于软件架构。
技能
6大核心技能要领
数据结构和算法
算法分析与计算
算法时间复杂度和空间复杂度的分析计算
算法思想
递推、递归、穷举、贪心、分治、动态规划、迭代、分枝界限
常用数据结构
数组、链表、堆、栈、队列、Hash表、二叉树等
经典算法
排序 经典排序:插入排序、冒泡排序、快排(分划交换排序)、直接选择排序、堆排序、合并排序等 查找 经典查找:顺序查找、二分查找、二叉排序树查找
Java高级特性
深入理解面向对象
面向对象的基本思想是使用类、对象、继承、封装、消息等基本概念来进行程序设计。面向对象的方式实际上由OOA(面向对象分析)、OOD(面向对象设计)和OOP(面向对象编程)三个部分有机组成。 对象的三大特性:封装、继承和多态,优缺点 如何设计类,类的设计原则以及构造函数,内部类,抽象类,接口,对象的多态性,接口和抽象类的区别。
理解异常处理
Java 常见异常种类 Java Exception Error Runtime Exception 运行时异常 Exception throw 用户自定义异常 java标准里也提到过,希望能用异常来处理错误信息以及后续流程,所以异常不仅仅只是异常,而是一个标准错误处理机制,并且也鼓励这样使用错误信息。
多线程
java多线程5大状态: 新建状态(New) 就绪状态(Runnable) 运行状态(Running) 阻塞状态(Blocked) 死亡状态(Dead) Java多线程掌握 创建与启动 线程和进程的概念 线程安全 线程之间的通讯 线程的同步与锁 死锁问题的剖析 线程生命周期 线程池 输入与输出
标准输入输出,文件的操作,网络上的数据流,字符串流,对象流,zip文件流等等,java中将输入输出抽象称为流,就好像水管,将两个容器连接起来。
Java I/O主要包括如下几个层次,包含三个部分: 流式部分――IO的主体部分 非流式部分――主要包含一些辅助流式部分的类,如:File类、RandomAccessFile类和FileDescriptor等类 其他类--文件读取部分的与安全相关的类
反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。 涉及到类加载机制原理、反射构造方法、字段、方法、Properties配置文件等相关学习要领。
网络编程
七层模型与协议的对应关系、Socket原理机制、UDP、TCP传输等知识点。
JVM
涉及到程序进阶,除了工作中平常使用以外,一定要深入去理解使用之外的核心原理,JVM特别是重中之重,JVM内存划分、class加载机制以及GC策略内存划分,Young Generation(年轻代)、Old G/eneration(年老代)以及Perm Generation(永久代)等。
Java web核心
前段技术
部分H5相关的重点掌握:html5、css3、js、以及对应的框架jquery、node等。
平时多掌握点web开发相关的,前段知识还是要跟上。
Java Web核心
这里还是需要掌握整个java web从容器启动到request、filter、listener的过程,最好自己设置断点调试,把完整的生命周期都走一次。
模板引擎
常见的模板引擎,比如淘宝一直使用velocity,现在最新又出来了个新模板引擎:beetl,有兴趣的同学也可以自己发掘。
高级特性
SSI技术 安全JCCA/JAAS 通信JNDI/JMS/JavaMain/JAF 集成JCA 事务JTA
数据库
数据库设计原则和范式
第一范式,确保每列保持原子性。 第二范式,确保表中的每列都和主键相关。 第二范式,在第一范式的基础之上更进一层。 第三范式,确保每列都和主键列直接相关,而不是间接相关。
Sql与NoSql的优缺点以及使用场景分析
SQL 关系型数据库:SQL Server,Oracle,MySQL(开源),PostgreSQL(开源) NoSQL泛指非关系型数据库 :MongoDB,Redis,Memcached,Hbase,CouchDB。
大型互联网项目常用的数据库选型方案:
采用MySQL + NoSQL的组合方案,根据业务场景和数据访问量来分别采用。
关系式数据库必备
事务(ACID、工作原理、事务的隔离级别、锁、事务的传播机制) 数据库创建,权限分配,表的创建,增删改查,连接,子查询 索引、触发器、存储过程、事务控制等
数据库性能优化
索引原理及适用,大表查询优化,多表连接查询优化,子查询优化 分库、分表、备份、迁移、导入,冷备热备,主从备份、双机热备、纵向扩展、横向扩展等这些都是属于比较常见的数据库方案,我在淘宝具体挑战性的一次架构演变中一文中谈到了数据库纵向和横向的发展策略,有兴趣的同学可以翻看历史查看
Java框架与必备工具
web开发框架
Struts2、SpringMVC、spring、hibernate、myBatis 在搭建日志:Log4j 单元测试:JUnit
构建工具
推荐nexus搭建一套自己的代码仓库中心,采用maven管理,这些都是比较常见而且有效的构建方案。
Web服务器
Tomcat JBoss Jetty Resin WebLogic WebSphere等
通信协议
RMI Hessia Burlap Httpinvoker Soap WebService等
工作流
Activity、JBPM
搜索引擎
lucene,基于lucene封装的solr
系统架构设计
搭建分布系统的基础设施
缓存搭建 分布式缓存搭建 memcached ,redis(推荐),动态、静态数据的缓存,以及配合单点登录的使用等。 负载均衡 Nginx/HaProxy CDN搭建 为了应付复杂的网络环境和不同地区用户的访问,通过CDN和反向代理加快用户访问的速度,同时减轻后端服务器的负载压力。CDN与反向代理的基本原理都是缓存。
分布式储存搭建
常见的分布式文件系统有,GFS、HDFS、Lustre 、Ceph 、GridFS 、mogileFS、TFS、FastDFS等,比如GFS(Google File System),TFS(Taobao File System),tfs参考tfs而来,所以名字也直接参考了。
消息系统搭建
目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ,优先推荐ActiveMQ。
消息系统使用四大场景
异步处理 应用解耦 流量削锋 消息通讯
常用的大数据方案
一般先分库,如果分库后查询仍然慢,于是按照分库的思想开始做分表。 比如淘宝中期数据库压力非常大了,于是数据库端按照业务做垂直拆分:交易数据库、用户数据库、商品数据库、店铺数据库等进行拆分。
采用sql和nosql混搭搭建再配合搜索引擎
随着业务越来越复杂,对数据存储和检索的需求也越来越复杂,系统需要采用一些非关系型数据库如NoSQL和分数据库查询技术如搜索引擎。应用服务器通过统一数据访问模块访问各种数据,减轻应用程序管理诸多数据源的麻烦。
除此之外,还要考虑安全以及机房容灾以及系统运维监控等。
https://www.toutiao.com/i6491139918394294798/
面向对象设计七大原则
- 单一职责原则(Single Responsibility Principle)
每一个类应该专注于做一件事情。
- 里氏替换原则(Liskov Substitution Principle)
超类存在的地方,子类是可以替换的。
- 依赖倒置原则(Dependence Inversion Principle)
实现尽量依赖抽象,不依赖具体实现。
具体依赖抽象,上层依赖下层。假设B是较A低的模块,但B需要使用到A的功能,这个时候,B不应当直接使用A中的具体类;而应当由B定义一抽象接口,并由A来实现这个抽象接口,B只使用这个抽象接口;这样就达到了依赖倒置的目的,B也解除了对A的依赖,反过来是A依赖于B定义的抽象接口。通过上层模块难以避免依赖下层模块,假如B也直接依赖A的实现,那么就可能造成循环依赖。
- 接口隔离原则(Interface Segregation Principle)
应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。
- 迪米特法则(Law Of Demeter)
又叫最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用。
- 开闭原则(Open Close Principle)
面向扩展开放,面向修改关闭。
意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。软件需求总是变化的,世界上没有一个软件的是不变的,因此对软件设计人员来说,必须在不需要对原有系统进行修改的情况下,实现灵活的系统扩展。
可以通过Template Method模式和Strategy模式进行重构,实现对修改封闭,对扩展开放的设计思路。
封装变化,是实现开放封闭原则的重要手段,对于经常发生变化的状态,一般将其封装为一个抽象,拒绝滥用抽象,只将经常变化的部分进行抽象。
- 组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)
尽量使用合成/聚合达到复用,尽量少用继承。原则: 一个类中有另一个类的对象。
如果为了复用,便使用继承的方式将两个不相干的类联系在一起,违反里氏代换原则,哪是生搬硬套,忽略了继承了缺点。继承复用破坏数据封装性,将基类的实现细节全部暴露给了派生类,基类的内部细节常常对派生类是透明的,白箱复用;虽然简单,但不安全,不能在程序的运行过程中随便改变;基类的实现发生了改变,派生类的实现也不得不改变;从基类继承而来的派生类是静态的,不可能在运行时间内发生改变,因此没有足够的灵活性。
架构师
概念
- 架构师的前提条件
- 如果我们把完成别人工作当成自己的最大利益,只有做到这一点,才能在自己所服务的领域建立起自信,成为一个合格的架构师。
找到了问题的主体
能够问出正确的问题:
如果问题不解决,究竟谁会有利益的损失? 如果问题解决了,究竟谁会有收益,谁的收益最大?
明白了这两个问题,我们只要让事情权责对等起来,让每个人为自己的权利产生的结果负有义务,大部分时候我们自己根本就不需要做什么,问题就都解决了。这就是最高明的架构师。
架构师的权利和义务
权利
- 架构师必须是一个组织的领导人,有权利调动这个组织的架构,才能够更好的发挥架构师的作用,更好的把利益的调整落到实处。
领导对于组织成员权利和义务的对等状况会非常的敏感,会及时的调整组织架构,在问题发生之前就解决了。
义务
发现问题并且解决问题
- 必须能够超越对时间的恐惧(必须具备了一定程度的自信)
- 真正的发现问题的主体,识别真正的问题
- 架构的分拆、合并方案,让问题的主体的权责对等
- 架构师和技术
语言和技术应该是随手拈来才对,对于架构师这些都是工具。
学习技术和语言,如果明白了这些技术和语言要解决的是谁的问题,什么问题,学起来是非常快,非常容易的。
采用哪个技术或者语言
只要某个技术或语言所解决的问题的主体,以及所解决的问题,和自己所面对的问题的主体和这个主体要解决的问题,这两者是匹配的,那么这个方案的成本是最低的,所采用的技术或者语言就是靠谱的。
架构毕竟解决的还是人的利益问题,成本越低越好,这个成本当然是长期总体成本,不是眼前的短期成本。
从架构的角度看如何写好代码
https://kb.cnblogs.com/page/542725/
尽量不要让代码成为系统长大的瓶颈,降低架构分拆的成本。
软件实际上是对现实生活的模拟,虚拟化。
- 代码两个不同的部分
表达业务逻辑的代码。很多人把这部分叫做Domain Logic,或者叫Domain Model。这部分实际是来源于生活的,必须保持和现实生活中的切分一致,并非人为的抽象而成。
* Service就专注于user的需求,并组合Glue Code提供的服务完成需求。 * Glue Code专注于组合business的调用,管理Business里面对象的生命周期,并且通过Repository保存或加载Business的状态 * Business专注于实现业务的核心模型。 * Repository专注于数据的保存,并和存储设备一一对应。
逻辑只允许存在于Business中
Service、Glue Code、Repository都不允许存在业务逻辑
对用户提供访问并保存业务逻辑运行结果的代码。计算机的状态保存有一个缺陷,本机保留业务运行结果有很大的问题,一般都在外存储设备上保存,也便于扩展。
什么叫业务逻辑
在软件代码中,不需缩进和计算的顺序调用,包括缩进的代码目的是catch exception的,都不算逻辑,除此以外都是逻辑。
为什么说除了Business代码中有逻辑以外,其他地方不能有逻辑
* 如果service里面不是严格的顺序调用,有很多分支,那么说明这个service做了两件或者两件以上的事情。必须把这个service分拆,确保每个service只做一件事情。因为如果不这么分拆的话,一旦这个service中的某各部分发生变动,其他的部分的执行必定会受影响。而确定到底有哪些影响的沟通成本非常高,其他相关利益方没有动力去配合,我们往往不会投入精力仔细评估。最后上线会出很多不可预料的问题,最终会导致损失用户的利益,并且肯定会导致返工,损坏自己的利益。如果是有计算的逻辑的话,比如受益计算,订单金额计算等,那么这部分应该是Business代码需要完成的,不能交给service代码来实现。 * Glue Code里面如果不是严格的顺序调用,同理会和service一样遇到同样的问题。 * Repository里面如果不是严格的顺序调用,包括存储访问的代码里面(比如SQL),会导致逻辑进入到存储设备中。存储设备的主要目的是拿来存储的,一旦变成了逻辑计算的主体,就会导致存储设备无法通过增加机器的方式横向扩展长大。这个时候就没有架构了,只能换性能更好的机器,这个叫scale up。只有scale out才能算架构。
以上都会导致架构无法快速的横向扩展和分拆,并且增加了修改的成本,这些是不符合开发人员以及业务的利益的。
优点
* Service、Glue Code、Repository里面的代码是严格的顺序调用,那么这些代码只要做连通性测试即可,不需要单元测试。因为这些代码都需要和很多上下文打交道,很难做单元测试。这样才算是真正的组合。 * Business不访问任何上下文,不访问任何具体的设备,所以这部分代码是非常容易写单元测试的,并且单元测试必须100%覆盖。因为其他地方没有业务逻辑,所以一旦有问题,就可以断定是Model的问题,单元测试肯定可以发现。如果单元测试没有发现问题,那么单元测试一定有问题。线上问题的模拟也就变得非常的简单,单元测试也能够得到进一步的补充。 * Repository很容易按照存储设备本身的最小访问粒度来完成工作,比如DB,完全可以做到单表访问。因为这个时候存储设备只关心存取数据,完全和业务没有关系。做表的分拆也是非常容易的事情,存储设备通过增加机器就可以横向扩展长大。很多人会担心说,没有了join,访问DB的次数是不是更多了,会导致性能下降? 按照现在网络的条件,网络访问和Disk IO访问的差距已经不大了,合理的设计下,多访问几次DB并不会导致这个问题。另外如果多台DB的话,还能通过并行加速访问。 * 由于Service、Glue Code、Repository代码简单了,才可以让我们的开发人员投入更多的时间研究业务,毕竟这部分才是软件所真正服务的对象。
实例
Manager类实际就是Glue Code
* 不能把Business Model当做数据对象来处理,Model关心的实际上是业务行为,数据只是是这些行为的结果。所以Glue Code需要把Model转换为Entity,Entity和存储设备里面的存储粒度一一对应。比如在DB中,每个Entity对应一张表,并且跟着表的变化而变化,这样就保证存储的变更不会影响Model。同样Service和用户之间的数据交互,也是不会和Model之间相关的,确保用户的需求变化,不会影响到Model。因为用户的需求变化是最频繁的,没有逻辑,可以让我快速的满足业务的需求。
* 在Service这里,最好不要考虑代码重用。因为当多个不同的角色访问同一个接口,一旦某个角色的需求发生了变化,就会要求开发人员去修改。而这个修改往往会影响到其他的角色,需要这些角色一起配合来确定是否受影响,但是这些角色因为没有需求,往往不会配合。这样就给开发人员造成了很多不必要的沟通,成本是非常高的。最终都会导致线上Bug,影响最终的用户。所以尽量给不同的角色不同的Service,避免重用,降低沟通成本。很多人会说这样Service不就太多了吗? 这样Service注册,查找等管理需求就出现了,Service治理中心就是来解决这个问题的。因为Service里面没有逻辑,所以开发和管理非常的简单,可以快速应对业务的变化。我们只有更快地变,更容易的变,才能更好地应对变。
* Business Model是必须要重用的,一旦发现重用出现问题,那么说明Business Model的识别出现了问题,这是一个我们要重新思考Model的信号。Business Model必须是一个完美的树状,如果不是,也说明Model的识别出了问题。
在实际操作中,Service、Glue Code、Repository不能有逻辑,实际上和很多人的观念是冲突的,认为这个根本做不到。做到这一点需要很多的学习成本,但是一定可以做得到。当发现做不到的时候,可以断定是业务的分析出了问题。比如不该合并的合并了,不该计算的计算了。这个问题一定有办法解决的,做不到都是理由,无非是想早点把自己的工作结束罢了。虽然刚开始会比较困难,一旦把这个观念变成自觉,开发的质量和效率马上就能高好几个级别。
业余选手,越想从水里浮起来,就越想把头抬起来,身体反而沉下去。只有克服恐惧,把头往水里压下去,身体才能够从水里浮起来。真正专业的习惯往往是和我们日常的行为相反的
我们真正想快速的完成代码工作,就要克服自己对时间的恐惧,真正的去研究业务的问题,相关stakeholder的利益,把这个变成我们的习惯。写代码的时候让该出现逻辑的地方出现逻辑,让不该出现的地方不能出现。一旦不该出现的地方出现了逻辑,那么要马上意识到,这个地方是一个坑,这个问题一定和业务的分析不透彻有关系。
以上只是针对单一的Service部署单元的分析,扩展开去,对于其他的部署单元也是类似的。每个单元的下一级都可以认为是Repository,每个单元的上一级都可以认为是User。这些实践在我自己的项目中都有用到,非常的有效,迭代的速度非常的快。很多人担心Business Model建不好,其实没关系,刚开始可以粗糙一点,后续可以慢慢的完善。这个架构已经隔离好了每个部分的变化对其他部分的影响,变化成本都在可控的范围之内。
理清技术、业务和架构的关系
什么是技术
通过人为创造条件,让指定的规律按照人类的意愿发生,这就是技术。
技术与业务
技术是为了解决业务的问题而产生的,没有了业务,技术就没有了存在的前提。
有了更好的技术,效率更差的技术,就会慢慢的被淘汰,消失,一切都遵从人类的利益诉求——也就是业务。有人会问,不用钻木取火了,但是弓弦加速转动木棍还可以用啊? 没错,因为弓弦转动木棍这个技术,不是来生火的,是用来加速木棍转动的,所解决的问题不一样。但是两种不同的技术,合理结合起来,会更好更有效率的解决业务问题。
- 技术与架构
- 在解决同一个业务问题的前提下,更高效,更低成本的技术,会淘汰低效,高成本的技术。这是人类利益诉求所决定的。
一般刚开始解决根本问题的技术(钻木取火)的效率是比较低的,只是把不可能变成了可能(从这一点上来说,技术才是业务的enabler)。然后就会有提高效率的需求出现,要求改进这个技术。这个技术的低效率部分就会被其他人(或者技术发明人自己)加以改进,这部分就会形成新的技术。
一般是先有技术,才会有架构
==架构师应该承担起解决业务问题的这个角色来,专注于Business Domain和软件本身的架构,让技术人员致力于为业务在计算机中跑起来而努力。==
- 重新发明轮子
- 当技术所解决的问题和分拆出来要解决的问题,完全匹配的时候,这是最完美的。比如需要提供web要访问的service,很多MVC的framework就可以很好的满足这一点。而这个时候如果非要自己实现一个,很有可能就是重新发明轮子。
- 当技术所提供的能力远远超过需要解决的问题时,往往掌握技术和维护技术会成为瓶颈。因为越复杂的技术,成本越高。如果自己实现一个仅仅是解决当前问题的方案,可能成本反而更低。这也是为什么很多大型的互联网公司不断地开源出来自己的技术的原因。而这些技术对于我们来说是否适用?他们原本是用来解决谁的问题的?什么问题?如果不清楚这些,就冒然采用,可能会导致更高的成本。
当技术所提供的能力和我们所要解决的问题部分匹配时,还是要看成本。比如当我们需要一个锤子的时候,手边正好没有,但是却有一只高跟鞋,勉强也可以替代锤子。但是长期来看,这么用不划算,因为高跟鞋的价格比锤子高很多,耐用性差很多,维护成本也高很多。
准确识别采用什么技术的能力,也是架构师所要具备的能力之一。考虑的主要因素也是长期的成本和收益。
实战
容量预估
http://www.cnblogs.com/itfly8/p/5006197.html
预估步骤:
(1) 注册用户数-日均UV量-每日的PV量-每天的并发量;
(2) 峰值预估:平常量的2~3倍;
(3) 根据并发量(并发,事务数),存储容量计算系统容量。客户需求:
- 建立一个全品类的电子商务网站(B2C),用户可以在线购买商品,可以在线支付,也可以货到付款;
- 用户购买时可以在线与客服沟通;
- 用户收到商品后,可以给商品打分,评价;
- 目前有成熟的进销存系统;需要与网站对接;
- 希望能够支持3~5年,业务的发展;
==预计3~5年用户数达到1000万;==
==定期举办双11,双12,三八男人节等活动;==
- 其他的功能参考京东或国美在线等网站。
每秒并发数预估:
(1) 每天的UV为200万(二八原则);
(2) 每人每天点击浏览30次;
(3) PV量:20030=6000万;
(4) 集中访问量:240.2=4.8小时会有6000万0.8=4800万(二八原则);
(5) 每分并发量:4.860=288分钟,每分钟访问4800/288=16.7万(约等于);
(6) 每秒并发量:16.7万/60=2780(约等于);
(7) 假设:高峰期为平常值的三倍,则每秒的并发数可以达到8340次。
(8) 1毫秒=1.3次访问;服务器预估:(以tomcat服务器举例)
(1) 按一台web服务器,支持每秒300个并发计算。平常需要10台服务器(约等于);[tomcat默认配置是150]
(2) 高峰期:需要30台服务器;容量预估:70/90原则
系统CPU一般维持在70%左右的水平,高峰期达到90%的水平,是不浪费资源,并比较稳定的。内存,IO类似。
架构演进过程
一个大型服务系统都是从小一步一步走过来的,在每个阶段,找到对应该阶段网站架构所面临的问题,然后在不断解决这些问题,在这个过程中整个架构会一直演进。
单服务器-俗称all in one
随着我们用户越来越多,访问越来越大,硬盘,CPU,内存等都开始吃紧,一台服务器已经满足不了
数据服务与应用服务分离
随着访问qps越来越高,降低接口访问时间,提高服务性能和并发,成为了我们下一个目标,发现有很多业务数据不需要每次都从数据库获取
使用缓存,包括本地缓存,远程缓存,远程分布式缓存
思考的点
具有哪种业务特点数据使用缓存? 具有哪种业务特点的数据使用本地缓存? 具有哪种务特点的数据使用远程缓存? 分布式缓存在扩容时候会碰到什么问题?如何解决?分布式缓存的算法都有哪几种?各有什么优缺点?
随着访问qps的提高,服务器的处理能力会成为瓶颈。这时,我们就需要服务器的集群。需要使我们的服务器可以横向扩展,这时,就必须加个新东西:负载均衡调度服务器。
使用负载均衡,进行服务器集群
思考的点
负载均衡的调度策略都有哪些? 各有什么优缺点? 各适合什么场景?
典型负载均衡策略分析
轮询:优点:实现简单,缺点:不考虑每台服务器处理能力 权重:优点:考虑了服务器处理能力的不同 地址散列:优点:能实现同一个用户访问同一个服务器 最少连接:优点:使集群中各个服务器负载更加均匀 加权最少连接:在最少连接的基础上,为每台服务器加上权值。算法为(活动连接数*256+非活动连接数)/权重,计算出来的值小的服务器优先被选择。
使用轮询或者最小连接负载均衡策略,就导致了,第一次访问A服务器,第二次可能访问到B服务器,这个时候存储在A服务器上的session信息在B服务器上读取不到。
Session管理-Session Sticky粘滞会话:对于同一个连接中的数据包,负载均衡会将其转发至后端固定的服务器进行处理。 缺点: 一台服务器运行的服务挂掉,或者重启,上面的 session 都没了 负载均衡器成了有状态的机器,为以后实现容灾造成了羁绊 Session管理-Session 复制 缺点: 应用服务器间带宽问题,因为需要不断同步session数据 大量用户在线时,服务器占用内存过多 Session管理-基于Cookie 缺点: cookie 的长度限制 cookie存于浏览器,安全性是一个问题 Session管理-Session 服务器
数据库的读及写操作都还需要经过数据库。当用户量达到一定量,数据库将会成为瓶颈。
数据库读写分离
思考的点
如何支持多数据源? 如何封装对业务没有侵入? 如何使用目前业务的ORM框架完成主从读写分离?是否需要更换ORM模型?ORM模型之间各有什么优缺点? 如何取舍?
数据库读写分离会遇到如下问题:
在master和slave复制的时候,考虑延时问题、数据库的支持、复制条件的支持。 当为了提高可用性,将数据库分机房后,跨机房传输同步数据,这个更是问题。 应用对于数据源的路由问题
使用反向代理和 CDN 加速网站响应
使用 CDN 可以很好的解决不同的地区的访问速度问题,反向代理则在服务器机房中缓存用户资源。
访问量越来越大,我们文件服务器也出现了瓶颈。
分布式文件系统
思考的点
分布式文件系统如何不影响已部署在线上的业务访问?不能让某个图片突然访问不到呀 是否需要业务部门清洗数据? 是否需要重新做域名解析?
这个时候数据库又出现了瓶颈
数据垂直拆分
数据库专库专用,如图Products、Users、Deal库。
解决写数据时,并发,量大的问题。
思考的点
跨业务的事务?如何解决?使用分布式事务、去掉事务或不追求强事务 应用的配置项多了 如何跨库进行数据的join操作
这个时候,某个业务的数据表的数据量或者更新量达到了单个数据库的瓶颈
数据水平拆分
我们把User拆成了User1和User2,将同一个表的数据拆分到两个数据库中,解决了单数据库的瓶颈。
思考的点
水平拆分的策略都有哪些?各有什么优缺点? 水平拆分的时候如何清洗数据? SQL 的路由问题,需要知道某个 User 在哪个数据库上。 主键的策略会有不同。 假设我们系统中需要查询2017年4月份已经下单过的用户名的明细,而这些用户分布在user1和user2上,我们后台运营系统在展示时如何分页?
这个时候,公司对外部做了流量导入,应用中的搜索量飙升,继续演进
拆分搜索引擎
使用搜索引擎,解决数据查询问题。部分场景可使用 NoSQL 提高性能,开发数据统一访问模块,解决上层应用开发的数据源问题。如图data access module 可以访问数据库,搜索引擎,NoSQL
在架构演进的过程中,还要考虑系统的安全性、数据分析、监控、反作弊等等……,同时继续发展呢,SOA架构、服务化、消息队列、任务调度、多机房等等