您的位置:知识库 » 软件设计

软件架构乱弹——问题域及其解决方法

作者: Anders小明  发布时间: 2008-08-16 22:26  阅读: 1891 次  推荐: 0   原文链接   [收藏]  
[1] 软件架构乱弹——问题域及其解决方法
[2] 软件架构乱弹——问题域及其解决方法

一、什么是架构

1. 和架构相关的几个问题域

架构需要解决的非业务问题域包括如下:

A 系统目标:系统性能,稳定性.

B.项目目标:开发成本,质量

C.项目过程:需求的不确定性和开发过程的团队协作性

不同的问题域,解决之道也不相同!而同一问题域的不同层次的要求,解决之道也不尽相同。

2. 什么是架构

   架构到底是啥,愚以为下面的这段英文描述的很清楚。

That's like asking, what is culture? Culture is the way you do things in a group of people. Architecture is the way you do things in a software product. You could argue by analogy, then, that architecture is to a software product as culture is to a team. It is how that team has established and chosen its conventions,

Which leads us inevitably to the question of “goodness”? How do you know if an architecture is good? Consider an architecture that isn't built using a strong domain model, and instead relies heavily on stored procedures. That might be OK, or it might not be OK. You could have decided that part of your architecture is to use a really strong domain model and not use stored procedures, right? So an architecture is some reasonable regularity about the structure of the system, the way the team goes about building its software, and how the software responds and adapts to its own environment. How well the architecture responds and adapts, and how well it goes through that construction process, is a measure of whether that architecture is any good.

The system architecture determines how hard or easy it is to implement a given feature. Good architectures are those in which it is considered easy to create the features desired. In that the way to judge whether an architecture is good is whether the architecture is good for the purposes to which it is applied.

The definition of goodness has to be related to fitness for purpose. Is this glove good? I don't know. What are you doing with the glove? Are you throwing snowballs, cooking barbeques, or playing golf? There's a set of changes that are going to occur to a software system over time. Probably the utilitarian or most useful definition of goodness is the answer to this question: are the changes that will keep this system successful in this domain in this product line relatively easy? If they are, then it's probably a good architecture.

3. 架构的背后

为了实现架构的目标涉及到以下三个方面:技术,组织和过程。这里举例说明。

1)       技术对开发效率和运行性能,以及组织和过程的影响。

案例A.映射的问题。公司产品的一个重 要需求是根据客户输入,映射到PDF文件上。技术上整体实现需要四个步骤:在PDF文件上画好所有的数据域,通过读入一个XML映射文件,获得运行数据并 生成FDF,合并FDF和PDF生成目标文件。后两步工作都由代码自动化了,因而实现的主要工作在于前两步。

在第一个实现版本里,XML映射文件的 DTD太简单,致使一个xml文件至少在4000行左右,同时xml文件太verbose了。这样的结果直接导致运行系统在峰值时,由于XML消耗了大量 内存,1G的内存根本吃不消;同时对XML解析执行使用了CPU的大量时间;导致开发人员需要做大量的工作,开发效率降低了,通常需要尽一周才能完成一个 xml文件,员工都不愿意做;也导致开发过程的漫长, 开发部门对于BA部门和ST部门的要求反应变的缓慢。

在第二个版本的实现中,重新实现了 DTD,加入了大量的关键字同时也消除了verbose,大量的缩小了XML大小,从4000多行减低到900多行。不仅减低了内存使用,提高执行效率; 也提高了开发效率,基本只要一天就可以完成一个映射文件。同时对BA部门和ST部门的反应也快了。

案例B:脚本的问题。产品在web层提供了脚本支持,出于方便开发的目的。但是没有对脚本的环境限制,脚本可以做系统程序的大部分工作。导致开发人员偷懒,在web层混入了大量业务逻辑代码。最终造成业务逻辑分散而不可控制。

2)       组织结构对技术,开发效率和应变能力的影响。

案例A.部门的分工问题。开发部门根据 不同的职责,分成A,B和C等数个小组。大部分开发中互不相干。但也有时候,需要跨组的支持,比如B要实现某个需求,需要A在一定条件在记录一个或多个信 息。因为每个开发人员各自负责一部分工作,导致跨组沟通的困难。同时由于整个开发部采取任务绩效,有时间压力,加上只是一个小的要求。于是在A人员的同意 下,B人员直接在A代码中写入业务逻辑。每次都是这样的小改动,不断的发展后,代码开发变凌乱。

案例B.开发的历史问题,当某个开发人员写下的代码,有是问题的,接手开发人员由于文档不全以及没有测试用例,不愿意承担变化的代价,选择小修小补,这个小修小补有可能和有问题的代码混杂,导致更大的代码。

3)       过程对开发效率和应变能力,以及组织的影响

案例A.过程的问题。开发部门的上下游 部门BA部门和ST部门的合作关系。ST部门的绩效考核,考核基于发现错误的数量,导致ST为了完成任务,提出一些非正常性要求。PM部门出于部门的方便 通常提出一些实现难度比较大要求。开发部门本身又存在时间压力,导致一些需求的实现本应在低一层的代码中实现的,却在高层用蹩足的方式实现。

案例B.帮助系统的问题。帮助系统一开始采用一个个单独分散的静态页面。出于性能的考虑和部门负责考虑。帮助系统不断改进中,过程缺乏组织性,文件的命名规则随意,存储位置随意,造成了管理的混乱。直接的后果是页面的入口混乱和各自引用关系混乱。

在帮助系统的第二版,从静态页面转成动态页面。采取统一分类和命名规则,并统一了入口。同时采取分级管理引用关系,适度冗余。虽然减低了运行性能。但提高了开发效率和可维护性。

 

二、架构的性能问题解决讨论

性能问题——嗯,一个非常神圣而高深的问题的。从我刚刚开始工作的时候,至今依然是。然而我相信,一定存在一个基本的思路和方法,我以为解决性能问题的工作还是在于分解,通过分解来确定问题域。 

1. 性能调优的关键

性能调优的关键是:发现性能瓶颈所在,慢是相对概念,评价标准是符合不符合系统要求。调整同时需要考虑维护成本,因为维护成本通常是开发成本的3倍。 

2. 性能调优的公式

先介绍三个公式性能问题的公式:

总处理单量 = 总处理时间/ 单笔请求处理时间 * 总并发数

这个公式另一个写法为:

总处理时间 = 单笔请求处理时间 * 总处理单量 / 总并发数

不同的写法代表不同的关注点,适合不同类型的业务类型, 一般说前一种写法代表在线请求的,后一种写法代表后台batch;即高并发或大数据量问题.

也有客户给明确要求系统要支持xxx并发,这个就需要了解客户的这个并发数是如何计算得来,需要通过分析客户的业务,而通常是根据总处理单量来确定客户实际的并发数。

但无论如如何,四个变量中,总处理单量和总处理时间是先被确定的,换句话说需要关注是单笔请求处理时间和并发数,也就是降低单笔请求处理时间或者增加并发数。 

对于单笔请求处理时间,其公式为:

单笔请求处理时间 = 数据计算时间 + 数据读写时间+其它技术导致时间消耗

很显然降低单笔请求处理时间就需要降低三个因素消耗的时间。

1.降低单笔请求处理时间

第一原则是, 只计算一次.缓存计算结果;

第二是,延迟部分计算(在不影响结果的情况下,将部分后续计算延后处理)

第三是,提前部分计算(例如对于年度的batch计算,可以在每个月都计算各自数据,年底汇总即可)

2.降低数据读取时间,分三种

2.1. Global,系统启动时加载

2.2. Long Time, 可采用LRU方式cache

3.2. Per operation. 第一次访问加载,operation结束后丢弃.

3.降低数据写入时间

例如文件写入通过buffer一次flush;对于SQL采用batch提交(hibernate的做法);对于同一张表数据只做一次更新;

4 .改进计算时间,针对不同技术结构采用不同手段。

4.1.让计算支持并发,提高性能,例如采用MapReduce的方式

4.2.改进算法.例如数据库中的SQL改进.

4.3.减少不必要计算时间. 

5.减少其它技术原因导致的消耗

JVMGC导致性能消耗等 

对于总并发数,其公式为:

总并发数 = 单机服务器并发能力 * 总并发服务器数 

3. 确定改进方案

那么如何确定那些因素需要调整呢,在于两个方面的分解:

A. 业务层面

业务层面只是指通过业务行为分析, 把性能问题分解为不同的部分,每个部分面临性能压力现状和目标,最终确定需要优化的问题域.

业务层面分解包括4个内容: 功能, 内容,时间和区域.最重要的是前三个.

eBay为例, ebay对于前端功能划分划分为70多个功能,不同的服务器处理不同的功能.

内容是指内容热点,比如对于search来说,就按体育,数码,音乐等划分,不同内容有不同热点数据,以及不同搜索关键匹配.

时间, 时间是一个非常重要的因素,在一些特定时间段,性能的要求会非常高.比如下半夜的访问点击量和白天的就有不同.对于一些batch来说, 月末或者年末处理的单量就有明显的提高,比如分红险的记息,平时每天只有7000,而年末会有12w.

地点划分,不太常见,不过也有助于分配计算资源. 

业务层面的分析不仅是确定问题所在,还是确定优化的策略.比如有一个batch计算,执行时间比较长,而通过业务分析,发现该计算只针对特定的业务, 系统全部有效单量是12w,而符合计算要求的只有3000,只要加上一个前置判断就可以免除无谓的计算,运行时间减少数个小时(大约0.21). 

B. 技术层面

系统建立时技术结构,通常一个系统结构如下:接入网络,Web服务器,应用服务器,以及数据库服务器. 

在这样结构下,要小心的分析和验证系统性能的瓶颈,需要优化Web服务器,或者提高数据库并发能力等等。这部分网上的资料非常多。 

采用并发立刻面临一个问题,即负载均衡.负载均衡如果无法正常的工作,那么并发也就无法正确的工作.负载均衡可以静态分布,也要动态分布.这里面涉及的问题比较多.服务器自带的负载均衡有时不能满足业务上的需要,要自行开发.

 4. Web网站性能特点

互联网网站的特点是交易少,事务短和并发高.对于网站这一特点需要做一番分解.网站的计算可以分解为:静态内容和动态内容,动态内容又可以分为状态无关(stateless)和状态有关(stateful).

静态内容通过负载均衡或者CDN就可以简单做到.

动态内容特别是状态有关的就复杂一点.动态内容中涉及到两大技术:sessioncache.

Session技术导致很多问题.负载均衡中导致session复制的难题.解决的方式是:1. 把所有的session数据存储到数据库中,这样通过增加数据库的IO读取,换取应用服务器没有任何session数据问题(另一种做法是把session数据放到cookie或者页面hidden值中);2. 负载均衡采用Hash,固定的把同一个请求绑定到同一台服务器上,这样通过牺牲一定的负载,换取应用服务器的session数据.

应用session sticky,虽然避免了session的复制,但是依然面临failover的问题.如果应用程序在session中放入了domain object,failover就容易出问题.一个解决方法是对sessionsetget进行拦截,发现是domain object就只在session中记录ID+ClassName结构,而把对象放入cache,failoversession中内容简单,就通过cache从数据库加载.(SpringSide对于jBPM的扩展采用相同策略)

Cache技术本事没有特别的要说的,但它处在负载均衡环境中就会带来问题:缓存数据失效(版本低).解决的问题有两种:1. 独立缓存+广播通知.一旦数据更新后立刻广播通知,这样引发的问题是通知的管理.2. 采用中央缓存,memcached技术,代价是网络读写.

Center CacheCluster Cache的特性比较如下:

Center Cache没有同步问题,所以,remove/clear的时候,比较有优势,不需要把通知发送到好几个计算机上。但是,Center Cache的所有操作,get/put/remove/clear都是Remote操作。而Cluster Cacheget/put都是Local操作,所以,Cluster Cacheget/put操作上具有优势。

Local get/put在关联对象的组装和分拆方面,优势比较明显。 关联对象的分拆是这个意思, 比如,有一个Topic对象,下面有几个Post对象,每个Post对象都有一个User对象。 Topic对象存放到Cache中的时候,下面的关联对象都要拆开来,分成各自的Entity Region来存放。

Topic Region -> Topic ID -> Topic Object

Post Region  -> Post ID  -> Post Object

User Region  -> User ID  -> User Object

这个时候,put的动作可能发生多次。Remote Put的开销就比较大。 Get的过程类似,也需要get多次,才能拼装成一个完整的Topic对象。

[第1页][第2页]
0
0
标签:架构设计

软件设计热门文章

    软件设计最新文章

      最新新闻

        热门新闻