-
2021-03-10 11:42:34
一个程序是否优秀健壮,很大程度决定于对异常情况的设计和考虑。从这个角度来讲,异常处理的重要性,丝毫不低于正常的业务流程代码开发。本专题将从实践中总结到多种涉及到异常相关的经验,予以分享。
二、异常和程序容错
在实际业务场景中,往往需要批量处理一类对象,如处理多个网络连接等。这个时候,程序的健壮性,除了考虑到捕获到程序的异常,同时也要避免不要让异常干扰到正常的业务流程。如下代码的fun1方法,由于在循环体外捕获异常,从而导致了后面正常的业务不能执行。而fun2,则当发生异常后,进行一定的异常处理,同时,由于是在循环体内进行捕获,不会影响其他正常对象的执行。
import java.util.Arrays; import java.util.List; public class Demo1 { public static void main(String[] args) { fun1(); System.out.println("==================================="); fun2(); } //在循环外捕捉异常,从而导致如果中间发生异常,正常的无法继续。 public static void fun1(){ List<Job> jobs= Arrays.asList(new Job(1),new Job(2),new Job(),new Job(3),new Job(4),new Job(5)); try { for (Job job : jobs) { job.work(); } }catch (Exception e){ System.out.println(e.getMessage()); } } //在循环内捕捉异常,异常的不会影响到正常的 public static void fun2(){ List<Job> jobs = Arrays.asList(new Job(1), new Job(2), new Job(), new Job(3), new Job(4), new Job(5)); for (Job job : jobs) { try { job.work(); } catch (Exception e) { System.out.println(e.getMessage()); } } } }
public class Job{ int a=0; public Job(){}; public Job(int a){ this.a=a; } void work() { if(a==0){ throw new RuntimeException("不允许出现0值"); } System.out.println("第"+a+"个在工作"); } }
更多相关内容 -
代码行为异常容错机制与自我调节
2020-03-29 21:32:22目录 1、吧啦吧啦吧啦 1.1、代码自我意识 1.2、代码功能安全 1.3、代码保密性 1.4、代码执行完整性 ...1.5、代码的容错机制与自我调节 ...2.1 设计观与代码容错机制、自我调节 ...3、代码容错机制与异常 ...目录
“行为”“自我调节”是心理学和日常生活中比较常见的用语,意义还是很明确的,那么,无论从信息加工论的认知观来看,还是从类比人的心理活动和行为、对代码构建一种新的描述方式来看,“代码行为异常”“代码自我调节”意义都是很明确的。
1、吧啦吧啦吧啦
吧啦吧啦吧啦是什么?补习时,学生模仿我讲道理的时候常常会说“吧啦吧啦吧啦”以示略过。在这里,它就算是一些表达我观点概念性词语吧。这些概念就是电影里的快镜、远景或背景旁白,虽然只有廖廖几个,却足以勾画我的道理的基本框架,成为电光石火间的一道思绪掠影。
1.1、代码自我意识
“代码是具有自我意识的。”
“年轻人,别太高大上。”
代码就是一篇由程序设计语言承载的“小说”,或短篇或中篇或长篇,不同于文学小说的是,代码反映的内容只有一项:这个问题怎么解决。说代码具有自我意识,这是基于既把代码当作、又是代码能够成为独立对象的。程序运行过程中对自身、对运行环境的感知与评价就是代码的自我意识。这对于大多数软件来说,是处于正常业务逻辑之外的,也是不必须的。而说到自我意识,就不得不面对终极之问:我是谁?我存在吗?这种终极之问的答案在同一个维度内和同一个形式系统内很难回答:在找到更高级的智慧生命形态之前,我思故我在可以通过感知思考过程证明客观实在的“我”,但是代码却很难从同一代码系统内的指令层面上对为用户服务的自己、虚拟环境下的自己和反编译下的自己做出绝对区分。软件漏洞问题实际上就是涉及方方面面的逻辑检测、异常捕获是否得到充分展开的问题。如果存在充分展开就会在代码层面上形成一个良好的自我意识系统。
1.2、代码功能安全
软件是为解决一定问题、实现某个业务功能而存在的,软件代码中为确保业务功能得以正常实现的、系统或局部机制下的、在常规业务逻辑流程之外的代码行为都属于代码功能安全范畴,包括代码保密机制、代码执行完整性检查、代码容错机制与自我调节,不包括业务逻辑内的身份验证、使用授权、通信加密等。软件处理的业务越重要,代码功能安全问题就越突出。代码功能安全机制很像带有独立功能的单位的秩序保障机制,有了它,软件的功能才得以平稳而有序地展开,这个世界才会有另一个精彩绝伦的故事,给世间创造一笔笔财富。对于大多数软件来说,一般只要求能实现正常的业务逻辑、一定期限内稳定运行即可,对软件功能安全的意识和要求不高。软件一般会有代码容错和自我调节机制,较高层次的软件支持执行完整性,更高一级的系统(更底层生态的系统)才可能会在前两者基础上要求代码保密。
1.3、代码保密性
不记得是谁说过,比陆地更广阔的是海洋,比海洋更广阔的是天空,比天空更广阔的是你我的心胸。可是,我就要告诉你,人的心胸再大,也装不下不应该知道的秘密。保密是一个老得掉牙的话题。底层基础的、原理的、原子的以及核心的代码往往是双重非公开,既是用户非公开,也是普通设计员或技术维护员非公开,还是形式非公开。用户眼里,软件永远只是一个个交互界面。而普通设计员或技术维护员,只能访问和修改公开性的授权代码。形式非公开,是指即便通过一定技术手段,也只能得到一行行的形式代码,即以或二进制指令、或机器指令、或字节码等形式而存在的代码,但却只是一种加密形式,非原来代码本身。这也是一种认知非公开。说到这里,我不得不赞叹一句:是谁发明了加密这种极具智慧的方法?比如说,小三(2)班只有李雷会讲英文,一天转来一位新加坡的新生露西。韩梅梅只想和露西讨论习题的时候,会偷偷地把露西拉到一个没人的地方,而当李雷只想和露西讨论的时候,则可以正大光明地于阳光之下用英文和露西交流,其他同学同样只有蒙圈的资格。
1.4、代码执行完整性
代码执行完整性问题实际上是关于“我是我吗”或“你是谁”的问题,是正常业务逻辑内或代码系统本身在“自我信息感知”这一层面上,确保自己或对方是合乎要求的自己(自然独立实体)或对方(非冒充者)的一种身份确认和保证特性。这对于基于网络传输的软件来说无疑是意义重大的。关于执行完整性,我在网上找到一些资料,一起来感受一下。
基于完整性的执行控制设计与实现,这是在百度学术中看到的一篇论文,摘要:为防止外来漏洞程序(如来自网络或U盘)威胁系统,本文在LSM框架下构建一个基于完整性的执行控制安全模块,控制这些程序的执行。为区分这些程序,本文定义了完整级,将这些程序标记为最低完整级,普通用户不能执行这些程序,而超级用户可以在构建的沙箱中执行这些程序,从而确保系统的安全。
从摘要看出,这种执行完整性控制是环境级别的,不是软件自身自发的,而是来自外在运行环境的监测。类似这种设计的检测与控制模式在杀毒软件或其他安全软件中用的比较多。
一种程序执行完整性保护方法和系统 [发明],这是在专利之星系统中检索到的内容,摘要: 本发明公开一种程序执行完整性保护方法,包括:根据跳转指令,将程序分割成顺序执行的程序块,在每个程序块的起始位置插入校验值标识CK_FLAG和校验值CK_VALUE;在程序运行时,进行实时程序块校验值计算,并和预先计算好的程序块校验值进行比较,在程序块受到破坏或者没有按照预期执行程序块时给出警报信号。
从摘要来看,这是一种比较典型的完整性检查,可以和某些类型的文件在网络传输中的校验检查做类比,主要检查程序当前的执行指令或模块是否是按照设计者最初的设计进行的。如果是,那么这种执行是完整的,否则是不完整的,即代码的当前行为不是代码本身、而是外在因素发起的,当前的代码行为环境是虚拟而非真实操作系统。执行完整性检查既是一种智慧活,需要一定的策略来确定代码的自然独立和真实性,也是一种智力活,检查策略将以系统性的代码形式体现出来,即能够被翻译成合适的计算科学技术和方法。我能通过我正在思考确定我的客观实在性,但我又是怎么知道我在思考的?很明显,自我感知。也就是说,要把策略转化为形式代码。
以上两种方式侧重点有所不同,但可大致归类于执行完整性检查,第一种是来自代码外部的,基于代码的完整性作出安全风险评估,并给予不同的执行环境,以尽可能地减少对真实的系统带给破坏性的影响。第二种是来自代码内部的,通过基于设计流的校验码来确定当前的代码行为是发自原始的自身。
1.5、代码的容错机制与自我调节
我首先来列举一下代码有哪些异常吧。代码异常有两种级别:系统级别和软件级别。软件级别的异常又分执行控制异常和业务逻辑异常。
系统级别异常:软件正常运行所需要的资源,如权限、内存空间、某种设备资源使用通道、所依赖的系统组件等,操作系统因某种原因无法给予正常提供而导致的访问、修改、运行异常,即代码无法正常进行当前阶段的业务处理行为,实现某个功能。
执行控制异常:执行控制异常即行为流向异常。在当前阶段,根据不同的输入,代码的行为会按照业务处理逻辑有条不紊地指向某一个方向。也即,在控制系统的协调下数据和实现业务的功能模块有序地交互作用。当这种有条不紊和有序受到破坏,也可看作是实现业务处理或软件本体处理及相关处理要求的“规律”受到破坏,从而引发执行控制异常。
业务逻辑异常:也可以称为问题求解异常。当实现某个功能所需的条件不成立时,求解过程或业务处理过程脱离预定逻辑,便发生业务逻辑异常。另一种情况是,数据是正确的,条件是提供的,但是解决方法不对。总之,无法实现正常的业务处理,解决问题。
上面只是代码异常的两种级别和分类,在不同的应用情境、语境下,这些异常都可以包含非常丰富的实际内涵。
代码行为就如学生行为,但比学生行为要可爱多一点,因为它们都可以是形式化的,界定起来要简单得多。一看就知道小明同学是学霸,可是像小明一样不迟到不早退、上课听讲认真下课作业倍儿棒地完成的同学多了去,然而考出99分的就只有小明。既然出现问题代码行为,自然要进行处理,以最低的代价使影响发生在最小范围,这就是代码的自我调节。而支撑代码自我行为调节的,就是代码容错机制。在设计代码容错机制与自我调节时,要注意的一个平衡策略是:既要能路径通畅,又不能代价太大。一般来说,要代价适中、适度地解决问题。如果解决问题的代价比问题本身的代价还要大,说明解决方法是错误的。如果两者代价相近,说明解决方法是可以更优的。如果解决问题的代价在问题本身代价一半附近甚至更低,则解决方法是较优的。我这里也只是以一种设计型的视角做的一个大致规划,有兴趣的朋友可以进一步深入研究。
上述内容是我以一种认知的、基于计算机科学的、类比人类自身又以面向对象的设计方法或汇总或建构起来的观点,这样,下面说起来就比较容易。
2、设计观与方法论
2.1 设计观与代码容错机制、自我调节
这里本不该用“设计”,太容易让人误解,因为一说到设计,自然以为是产品设计、程序设计、功能设计等等,实际上我这里的“设计”指的是“解决问题”设计,设计观实际上就是解决问题的策略观。因为这不是出于对许许多多的、大量的实例、事实、实验结果的总结、归纳和概括,而是一种个人观点,一种设计型的表述。也就是说,下面所说的是一种日常概念和直觉经验,是在对一些直觉经验或我自己也想不起来源的常识的归纳后做的假设演绎式推理。
我道理中的解决问题,就是指代码中容错机制和自我调节的具体内涵。也许像我一样,可能会有这么弱弱一问:那不就是软件测试和调试吗?从开发者行为形式和软件工程角度来看,两者之间的确很像但又有本质区别。首先是对象主体不同,前者是代码自身行为,后者是软件测试者行为。其次是内涵不同,前者是体现代码容错机制和自我调节行为的设计的代码表现,是内在系统性的、策略性的,后者是对软件的一种测试与修改,是软件外部行为性的。最后,前者在代码中具体体现在逻辑检查、条件判断、异常捕获与处理的规划、潜在漏洞预测与控制以及更高要求的检查,后者则侧重对不同形态下同类业务问题是否能够正确解决的检查,包括语句、模块、功能、集成等方面的检查与修改。从这个意义上看,两者是有重叠的地方,但是对从具体中抽象出来的“问题”本质的把握,有助于解决问题时打开更广阔的视野从而找到更多通往目标的路径,以寻求更优。
2.2 问题是否能够被解决
终极之问:问题是否能够被解决?
什么是问题?怎样才是解决问题?我们可以从几个方面来吧啦一下。
2.2.1 意识行为是否具有虚拟性
你认为网络具有虚拟性吗?
玩过游戏的人都知道,游戏是具有虚拟性的。什么是虚拟?虚拟与现实相对,是非现实的,在认知上不把游戏中的一切和现实世界中的一切联系到一起,它们之间不具备相似性,游戏中的一切不能做为现实中任何行为的先行条件。那么网络呢?可能你出身于高教家庭,但网络的出生身份却是一种“超级工具”,它的工具性质使得其上的信息变化和现实中的事物变化能够一一对应起来,正如物理理论中的一些公式变化可以和现实中的事物变化能够一一对应起来,都是一种对应和描述关系。但是,当网络承载的非工具性功能越来越多,便充斥着大量不和现实变化对应的信息,和现实世界既非对应关系,也非描述关系,从这个意义来看,网络不也是一个大型游戏吗?网络和游戏,甚至和所有的被称为“信息系统”的东西一起,都有因建构而虚拟的一面。虚拟的程度如何,取决于网络上的信息能和实际生活有多大的联系,以及我们在现实中进行某个行为时有多以它们为决策参考依据。此外,网络本身也可看成是一个大型“信息系统”,作为人与现实世界交互的中介环节,这种中介性质是虚拟的;网络上各种类型的社区生态,以信息处理作为载体模拟现实世界人际交互的、非实质行动性精神交流,更具虚拟性。
你认为人类文明具有虚拟性吗?
前面说了网络的虚拟性,这种虚拟性是建立在网络上呈现的信息与现实生活中行为的联系密切程度、与现实世界变化的一致性程度上的,或者是建立在拟本体性上的。那么人类文明呢?这要从另一个角度来看一致性和本体性。
我插一句,用自然语言来说明想法就是好,如果是在一个形式系统上讲道理,那么,对于“这要从另一个角度来看”,可能会很难进行下去。
什么是人类文明?人类文明与自然世界相对应。放眼世界及历史发展,人类文明大致包含三部分:一是人类与人类自身特点和行为特点,二是人与人之间的关系和交互,三是人类创造出来的、能以一定方式表达和呈现的、实质性或非实质性之物,比如高楼大厦,学校,文化艺术品等。这三者组成人类文明,但是,高贵的我们会机智地从中选择一些作为人类文明象征。至于为什么要象征,往进化上说就是群体的代表必然是优质的,往情操上说就是我们人类必须是高贵的。
什么是自然?如果对于旁观者的我们以人类视角去看动物世界、植物世界和它们所在的生态环境,很容易概括出“自然”:行为表现与意识情感的高度一致就是自然。大多数动物、植物没有意识怎么办?别啊,不能和意识情感保持一致,行为反应、生理反应、自然变化和客体自身构造对应的功能高度一致不也一样的吗?说简单一点,也行:动物、植物的蛮与野就是自然。
自然性行为不是虚拟的,是实在客观的。
动值物具有自然“行为”,那是不是说像动物一样就是自然?
肯定不是的。人类和动物有差别,那么人类的“自然”必然有差别。
人类和动物有本质的差别吗?“人和动物的本质区别是劳动”、“使用物质工具进行劳动生产,这是人和动物最本质的区别”、“由于人有了以语言为主的第二信号系统,其学习与动物有了本质区别”,这些常见的教科书式说法很容易找到出处。流传范围的宽广可大致看成是客观性的衡量指标,因而上述说法是大众认可的。精神生产工具是中介性质的,它的使用产生出作为人类社会发展结果的高级心理机能,于是人便有不同于动物的由感知觉、情感态度、意识需求、智力活动等构成的独有特性。其中,情感态度、意识需求决定着人的行为方向,智力活动是该方向的选择器和助推器。但我想说的是,人类和动物的最本质差别从外在上区分,是在所有物种的最大公因数式的生存条件下,进行以高级心理机能为依托的建构性语义行为,包括维持的和创造的。
人类行为有着客观虚拟性和独特自然性。人类行为的独特自然性,指人类行为是意识反应的外在表现,带有主动意识的行为表现是人类行为自然性的体现。并非只有像动、植物一样反应才是自然,因为人类有着和它们的本质区别。那么客观虚拟性呢?一方面,人具有动物不具备的高级心理机能和思维活动,对于从外界接收的信息做出处理变换后才表现在行为上,这种中介性加工变换使得人类的客观世界仅仅是一种语义映像,是对真实客观世界的一种描述、加工和反映。这和我们用一段程序来解决问题的过程没什么实质性的不同。所以人类和环境交互的行为具有客观虚拟性。另一方面,从一致性来看,人类行为分三种:一是无意识行为,这种行为只是缺少某个强烈的方向做为加工信息的指引,并非没有在头脑中加工处理信息;二是有意识行为且知情意行合一,这二种行为最能代表人类行为的自然,虽然它们是客观虚拟性的;三是有意识行为但知情意行不合一,这是人类行为客观虚拟性的典型代表。之所以不合一,是因为人类意识中建构性动机而非机体功能性动机的增多。
人与人之间的关系和交互是虚拟性的。人类行为产物既包含行为习惯,也包含人与人之间的关系及基于关系的交互作用,也就是你来我往大家一起讨论问题、做作业、交朋友和争第一名。为什么是虚拟的?并不是说人际关系和交互不是客观实在的,而是关系及基于关系的交互中的“关系”,带有浓浓的描述色彩和建构色彩。“色彩好看吗?”“好看,绿绿的太阳比红红的太阳更好看。”“太阳不是红色的吗?”“不,我只能感到绿色,只有绿色对我有意义。”关系是有意义的,所以是虚拟的。说到建构,不得不说到模仿,一种类型的模仿是:一段时间内人较原始的动机行为呈现一定方向性,随着时间推移,当人的自我意识加强或变化后,察觉到这种方向并总结成行事指导原则,指导后续行为,因而上升到意识水平,成为模仿。模仿的结果是,在一个新的层面上再次造就知、情、意、行的合一。另一种类型的模仿是意义建构:说得东式点,就是人法地,地法天,天法道,道法自然,高度建构性的“自然”还有另一层含义:使制度与规则的具体表征物像一个自然物运转。说得西式点,就是以一个客观对象为蓝本,在一代或几代人的理论钻研、技术改进的积累下,最终制造出该对象的人造之物。不管是模仿还是意义建构,都是虚拟的。
人类行为创造物的虚拟性。基于上面提到的虚拟性,大量的人造物都是某个自然物在人类世界中的呈现与映射,因而也是虚拟性的。
人类社会这个庞然又复杂的大物能够像一只鸟、一条鱼或者其他的有机体一样自然的运转,得益于一些制度、规则的遵循与维护行为。而这些行为都来源于人类意识。比如,学校之所以是学校,是因为从外在来说,有学校场地和相应人员、设施,从内在来说我们会把这样的场地、人员、设施“视为”学校的一种成分。即便有学校场所、有教室、有大门牌匾,但是人进去后只做一件事,找个空地栽栽树,那么“xx学校”对人类来说依旧只是一个林场,不具备“学校”的意义。那么社会或代表社会文明之物是怎么来的呢?如前所提的模仿与建构:反省、总结外加建构。而且,建构性意识行为也是有其建构依据或方向的,要么来自自身问题的改进,要么来自模仿外在物。对于人类而言,外在物很大的构成比例是动、植物及相关生态组成的自然界。因而人类社会的规则和自然界规律相比,本身具有效仿性,是一种人造规律。
无论是从信息的加工变换来看,还是从一致性来看;无论是从个体行为来看,还是从群体行为产物及群体的自身联系来看;无论从模仿来看,还是从建构来看,人类文明有一定虚拟性。
虚拟性并不代表人类文明的非自然。
所以,作为人类文明原因的人类意识行为具有虚拟性。
2.2.2 思维是否具有方向性
人类文明基于意识的维系,是带有虚拟性质的,既模仿大自然建构人造物又有自己独有的特点。这种模仿并非说我们一定要像大自然一样运作,或者是像大自然一模一样的运作,而是说通过人与人之间的有意识的维系性行为,使得人类社会能像大自然中的一个客观存在的、独立又统一的客观对象去运转。人类社会的规则如果要成为规律,是建立在人主动遵守的基础上的。
人造规律主要还是通过效法自然实现的。既然有效法,就一定有效法对象,因而我们的思维活动必定具有指向性,这种指向性体现在思维活动沿着思维规律向目标变化。思维规律其实就是大脑的物质性构造呈现的功能性规律在我们意识层面上的映射。这种内在规定性与意志、动机特别是建构性动机无关。无论是思维活动效仿的指向性,还是思维活动受思维规律制约,都说明思维活动是有方向、有序的。这种方向和有序便是人能解决问题的基础。
思维活动是客观或非客观问题的本体,因而,问题不一定能被解决,但是,问题可以被解决。
2.3 问题与问题解决
什么是问题?一说到问题,像我或我们这种计算机科学专业的人第一反应是程序中出现的BUG,一个函数应用错误,程序运行时的异常,操作系统中出现的错误。还有一些人的第一反应是最近一段时间内最熟悉事件中出现的、导致事件无法正常完成的感觉印象或客观事实。在心理学中,关于问题是什么早就有讨论了,一百多年来认知心理学这一分支所重点关注的内容中就有解决问题这一项。用我的观点来概括就是,在一个或多个视角下,在一个可描述的系统中,无论是形式符号描述还是自然语言描述,当一个带有系统性语义对象的变化偏离它“行进”的路径即变化规律时,此时的系统状态就是“问题”。问题有三个要素:系统语义对象,系统语义变化,系统语义下的变化规律。其中,系统语义对象是“偏离”系统语义下变化规律的,而系统本身则是或描述或模仿客观自然的,或是建构的。
自然规律的固有属性是方向、有序,对于人造规律来说也如此。当然还有变换,但这里先不把变换作为强调对象,因为这与具体功能或问题有关。一个对象之所以成为一个有机整体,是因为其各组成部分及之间的联系、交互是客观存在的,这些联系与交互是有方向的、有序进行的。这种解释同样适用人类文明中的某个对象,比如之前说的“学校”,只不过学校的构成和作为一个独立对象的行为规律都是一种人赋予的意义建构和该意义下人、物的组成与行为交互:我认为有这个意义,并始终按这个意义去做,客观世界也能形成相应方向下的变化,这个意义才是客观,我的行为才是规律的。人类的认知、思维活动也是有方向、有序的,这为问题的解决提供现实可能性。也因此,人的思维活动是应遵循也必然遵循思维的基本规范的,如同一律、矛盾律、排中律、充足理由律及其四重根等,这为形式化问题的出现和解决提供现实可能性。总之,问题能够被解决,是可能的。
那么什么是问题解决?
回到前面说的“问题”上来,问题解决有两种含义:系统语义对象从初始状态沿变化规律发展为目标状态的“路径”的形成,中间没有非变化规律上的,或者是变化规律上但不是变化规律预期的状态,是一种问题解决。怎么可能出现变化规律下的非预期状态?之前说过意识行为具有虚拟性,再加上认知影响,人类发现的规律并不必然与对应的自然规律保持全面和整体的一致;而人造规律就更次之,解决思维逻辑问题和保证行为一致性的策略问题后也只是达到一个模拟规律级别。问题解决的第二种含义是,在系统语义对象从初始状态发展为目标状态过程中出现非变化规律上的其他状态或变化规律上的非预期状态,即异常状态,通过系统调节或对象自我调节后,异常状态消失,重新回到变化规律上,最终到达目标状态。
如同最开始说的,我这里的“问题”是一种设计观,因为它带有浓浓的系统性语义,客观世界是不带“意义”的,就只那么存在着,概念和命题都是意识产物,即便最接近它本身的形式系统,也因为各种概念离它渐行渐远。语义是有意识的人类独有的自然现象,但是,它是一种意识产物,对于客观世界而言无所谓问题不问题,问题是一种意识“设计”概念,是唯心(意识产物)和唯物(模仿自然)的。
2.4 软件与问题
什么是软件?从软件工程视角来看,对外在的用户而言,软件是一个带有服务周期可实现需求的“生命对象”;对内在的开发人员而言,和基于公理推演出来的一些物理上的、数学上的形式理论系统类似:软件是一个形式功能系统,只不过这个形式系统既有静态信息和静态性质描述,也有动态信息和动态行为描述。数学等领域的形式系统和这不同,它们是人类在探索客观规律后的一种表达型却可推演的形式系统,是静态的,表达于其上的运动规律通过几个关键性指标及其之间的关系来刻画,是简洁、无歧义的形式系统。代码无需将一个动态变化过程进行关键性地标记,当然也可以这样,而是直接把这一过程描述出来,相当于通过操作系统进行翻译的一个机器脚本。这个动态过程可以是规律性的,也可以是步骤性的。软件的代码描述和操作系统的脚本式驱动共同构造出软件这个生命实体。
软件的方向性和有序性。作为一个带有生命周期的生命实体,软件具有功能需求方面的刚性标准,该标准的达到保障就是代码功能安全体系:代码的保密机制、执行完整性检查、代码容错机制与自我调节,无论用户强调不强调、开发者重视不重视其中一个或多个方面。软件功能的完整实现便是其代码行为方向。
我们从以下几个方面来分析软件问题来源。
首先,软件与系统环境。软件是在操作系统下运行的,软件与操作系统的交互——软件访问系统资源和系统查询软件信息——是软件代码行为异常的来源之一。访问的资源得不到应答时,以及操作系统局部异常或关键异常将直接导致代码行为异常。特别是访问的资源越处于系统底层,需要开发者维护的工作和职责就越多,越容易发生致命性异常。
其次,软件和使用者。软件的功能实现和业务的正常处理,取决于各种形式的数据输入和指令输入,如数据文件的数据、命令行指令或图形界面指令等,因此,如果使用者本身是一种无序的、非理性的、非目标业务预期的,可能会出现以下结果:软件运行时没有任何问题,但是得不到正确的业务结果。或者,这些数据或指令不符合实现某个功能的代码的语义要求或形式要求,将会导致代码行为异常。通俗地说,实实在在的问题是问题,没有相应操作技能的用户也是问题。
第三,软件定义与功能实现。软件功能的实现即是用户需求的实现,也即解决问题的过程实现,从而定义软件本身。问题求解自然是产生问题的高危地带,同时也是解决问题的必经过程。代码对业务处理的执行控制的复杂程度取决于业务复杂程度,越复杂对开发者的逻辑严密性、处理问题策略性要求越高。对于C/S架构的、支持并发方式处理业务的、带有前后端的软件,软件行为一直保持在自身闭环内很关键,即软件是在和架构内另一端的自己对话及其实现。而如果业务安全度较高,处理的信息非常机密,那么对于多种软件协作处理共同业务时,进行数据通信的各方是否属于同一个业务处理集群以及数据加密很关键。
后面会通过一个抛研引玉的小例子就上述三个方面进行探讨。
3、代码容错机制与异常
首先明白一点,对于软件来说,工具性是第一位的,其他一切机制都是围绕保障这种工具性的实现展开的。因此,在设计过程中,业务逻辑和业务逻辑异常的处理是主线,对于执行控制异常和系统级别的异常是“卡关键点”。当然,对于生态平台性的系统则不是仅仅是卡关键点,机制和策略的系统性很重要。异常发生时,最佳状态是,代码行为在业务处理或问题求解上的流程虽然被暂时中断,但仍旧保持在软件自身内部。通过一番调整,为待重新求解,或撤销之前代码的处理结果回到最初状态,或保存当前的处理状态,或调节自身状态回到业务逻辑上另一“地点”,整个过程代码行为始终保持在自身可控范围,这便是代码的容错机制。
什么是代码异常?任何在软件运行过程中出现的,业务处理及支持业务处理方面的非预期性行为或反馈都是代码异常问题,这种异常可能是操作系统级的,可能是自身执行控制系统的,也可能是业务逻辑的。
4、一个微型实例
问题定义:为数据文件中的每位客户建立指定路径下的工作目录
问题分析:
1、用户提供数据文件,文件中有客户信息,客户信息按一定结构存放,每位客户的记录结构为:客户ID,姓名,电话号码(客户相关信息代表)。
2、用户指定客户工作目录所在路径。
3、为每位客户建立各自的工作目录。
4、信息提示与反馈界面。
问题解决:接受指定路径与数据文件的输入,提取数据文件中相关客户信息(这里是客户的姓名)为其创建目录,输出结果为指定路径下创建好的每位客户的工作目录。
任何一个能够实现需求的软件都是一个问题得到解决的结果。首先要观察问题情境,理解其各组成部分及之间的联系,按照自顶向下的原则逐层分解,当分解到一定层次后,再分析该层次下制约问题解决的各种条件,理顺它们的先后关系并根据IPO(输入-处理-输出)定义出模块。所有的原子模块和集成模块一起便构成了整个问题的解。
在观察问题情境时,为避免不必要的业务逻辑异常,要确定好业务内和业务间的关系,以便考虑权限与可见;要确定业务的驱动形式与结果反馈,以便考虑输入、输出的表达和规范;要确定软件的性能需求、运行平台需求、质量需求,以便考虑问题能够得到解决的先行条件和约束要求。这些考虑在需求分析就要体现,形成整套系统,不向后堆积。
4.1 业务逻辑异常
什么是业务?“业务”二字在营销中出现得多,但现在可泛指一个岗位职责事务,业务能力就是实现一个岗位职责所需的事务处理能力。业务逻辑是指业务处理的信息化、形式化、代码化,实际上就是模仿和虚拟化,只不过模仿者和模仿对象从人与自然变成机器与人。在代码内部,业务逻辑是指确保所有输入都正确(语法正确、语义正确)的基础上,按照要求输出预期结果的整个处理流程。业务逻辑问题体现在业务逻辑异常上。在这个实例中,业务逻辑的异常将集中在输入、处理和输出结果的表达上。先看一种极简单的求解:
import os print("当前工作目录是:{}".format(os.getcwd())) filename=input("请输入用户信息文件:\n") with open(filename.strip(),"r") as f: targetDir=input("请输入要创建的各客户个人目录的父目录:\n") num=int(input("请输入用户名称在信息文件中的第几列(起始列为0)\n")) for i in f: cc=i.split(",") client=cc[num] os.mkdir(targetDir+"\\"+name) print("生成客户个人目录完成,再见!")
整个程序流程很简单,业务逻辑也很简单,在提示当前的工作目录后,接收用户输入的数据文件、客户个人目录的父目录、客户姓名所在列号,然后处理数据,这里只是提取相关信息,并生成客户工作目录。
这个业务逻辑是建立在非常理想状态下的,即:所有的输入都是有意义的,所有的操作都是可实现的,任何时刻程序运行的条件都是满足的,以及数据文件内容是极优质的,即不存在引发更多求解步骤的数据。
我们可以从行为角度分析这些代码的性质:输入与输出部分,涉及到程序与用户、程序与操作系统的交互,发生异常的可能性受到用户和系统环境双重影响;输入和输出之间的业务逻辑,才是完全受程序自身决定的,对于其间可能发生的异常完全能够在业务流程内解决。
那么,业务逻辑异常处理从哪里开始?是按输入-处理-输出,还是先实现业务逻辑和软件功能再引入异常处理机制?是一部分一部分的完成还是一起完成?这取决于我们思维能同时关注的维度的数量,也取决于程序的编写习惯,有时候也受限于熊(安全)与鱼(功能)的取舍。总之,对于普通软件来说,功能和问题求解优先,再决定其安全。技术手段无法触碰的范围要制定必要的、保障软件正常运行的软件使用管理规范。用户多做一点软件实现就容易一点,用户少做一点软件就可能要复杂很多,这涉及投入预算与软件规模。特别是带有语义的数据,用户进行语义保证是很简单的事情,若由代码提供语义识别,将复杂许多。
这里就从业务逻辑实现上入手吧。假设数据文件不是最优质,但也不是很劣质(无序,无意义数据较多),在用户输入指定列以后,面临三种情况:
第一种情况,指定列不存在:最好解决,交给语句语法检查与异常处理;
第二种情况,指定列存在但不是客户姓名列:这属于语义正确性检查,较难处理,可以以输入规范和语法规则解决为主,再辅以特征检查(但不是绝对有效),最好是,用户的问题还是交给用户解决:删掉成功建立的目录(但不是预期的)重来一次。
第三种情况,指定列存在也是客户姓名列但存在相同姓名的客户:这是个问题吗?这取决于创建目录的函数的实现过程:当存在同名客户,上面用到的os.mkdir创建目录时会认为目录已存在而引发异常。这个比较好解决,创建目录前先验证文件中客户姓名数量,若有同名同姓者则以“姓名(客户ID)”作目录名。改进代码如下:
import os from sys import exc_info print("当前工作目录是:{}".format(os.getcwd())) filename=input("请输入用户信息文件:\n") try: with open(filename.strip(),"r") as f: targetDir=input("请输入要创建的各客户个人目录的父目录:\n") num=int(input("请输入用户名称在信息文件中的第几列(起始列为0)\n")) s=f.read() f.seek(0) #文件指针移回文件首,以便下面的访问 for i in f: cc=i.split(",") client=cc[num] if s.count(client)>1: sss=targetDir+"\\"+client+"(学号{})".format(cc[0]) else: sss=targetDir+"\\"+client os.mkdir(sss) print("生成客户个人目录完成,再见!") except: t,v,tb=exc_info() st=str(t) t=st[st.find("'")+1:st.rfind("'")] print("指定列内容有没有问题?以下是问题详情:\n{}:{}".format(str(t),v))
第一种情况
第二种情况,我把语义问题完全交给用户解决:删除目录,再运行一次。从图中也可以看出,第三种同名情况能得到处理。
以上业务逻辑异常类型及相应解决方式并未使运行脱离代码自身范围,这可为得到真正的、所需的“解”提供最大保障,因而是容错的。是的,对于简单实例来说很多人都能做到这一点,这不就是普通意义上的测试与调试吗?但是稍有不同的是,调试会消除程序中的已知问题,而这种代码的容错机制并不是完全这样:各种类型语句或函数抛出的异常要处理,为解决某类局部问题或改变业务的和执行的处理流程而主动抛出的异常要处理,对只在某些极特殊情况才出现但影响极大的异常要处理(这需要一双有洞察力的双眼和严谨的逻辑),某个功能实现过程中、或某个业务处理中出现的异常也要处理。对于一些不可消除的异常,各种可能性级别的异常,代码会如何调整自己的行为呢?这需要形成策略性和系统性机制。并且,当软件一旦规模变大,如何处理突然显现的潜在BUG、关于业务的平衡性策略又是如何,都值得仔细思考。
4.2 执行控制异常
执行控制是软件保证正常业务逻辑、业务辅助逻辑、软件本体逻辑正常运行的功能性逻辑。如果所有的业务逻辑和业务辅助逻辑能够缩小为一条语句,那整个软件系统就是一个执行控制逻辑(模块)。执行控制异常是导致软件本体完整性丢失,业务逻辑流无法正常流动,或业务逻辑无法继续进展的异常。
例子比较简单,就说说输入输出吧。输入和输出分别是一个业务逻辑的基本出发点和归宿点,输入关系到业务逻辑的正常进展和软件功能的具体实现,输出关系到软件本身的执行控制流向,是内在业务逻辑与外在执行控制逻辑的交接点。当然,这个例子中的输入、输出相对于内部业务逻辑的起始点、归宿点来说,更侧重于代码和用户、代码和系统之间的交互。
先看代码和用户。对于用户闭上眼睛瞎摸乱打导致的问题,全都可以交给语法解决,只要能捕捉语法问题导致的异常即可。需要费心的是语义性输入问题。例如,程序要求用户提供姓名,在用户输入后,程序怎么知道这不是一个姓名的问题。但是,这种问题的解决现在有着非常成熟策略:输入内容的规范化,即按照一定的语义性词法和语法输入。这也是让人多做一点的策略的体现,最典型的莫过于开发软件时需要程序员输入的代表问题解决过程某种程序设计语言了:虽然硬件设备只知道如何做但不知道“自己”在做什么,但是操作系统是清楚的;虽然操作系统只知道如何做但不知道“自己”在做什么,但是软件本身却是清楚的。根据问题定义,要为客户创建工作目录,需要用户提供的信息有:父目录、数据文件、姓名所在列。
父目录:输入的路径要符合python的语法,要符合创建/检查父目录的语句或函数的使用要求。无需语义处理,完全交给语法及异常捕获解决。如果目录已存在,将忽略创建,否则将创建指定目录;如果父目录路径输入不合法,提示用户重新输入。
数据文件:分三个层次。首先,输入的内容代表一个文件;其次,是一个数据型文件;最后,是符合业务处理逻辑“期待”的数据文件。最后一个层次实际上是对前两个层次的统合,因此以它为标准即可。是否是合法文件交由语法解决,是否是符合业务逻辑期待,我这里交由用户自己解决,即假定它是符合期待的。
姓名所在列:内容合法性交由语法解决,语义合法性交由用户解决。
代码对用户的要求是:形式合法,意义合法。用户对代码执行结果的要求是:符合形式,符合预期。代码运行结果是:在指定位置出现每位客户的工作目录。
再看代码和系统。代码通过打开文件与创建目录来和操作系统交互。打开文件用于获取数据,有可能被创建的父目录用于存放各个客户工作目录,因而这两者都可以看作是一种“输入”。而将创建的客户工作目录则是代码的“输出”行为。
打开文件:这里涉及的问题主要有路径是否合法、软件是否有权限进行这样的操作、文件打开过程中是否出错等。这些都可以交由异常捕获解决。
创建目录:目录创建实际上也是路径合法性与语句要求问题、执行权限问题、执行过程问题。
尽可能地对正常逻辑和语法问题之外的潜在的运行时错误或逻辑设计漏洞作应对策略,是代码容错机制的强力保证,也是代码具有较强容错性的体现。改进代码如下。
import os from sys import exc_info from time import sleep while True: print("当前工作目录是:{}".format(os.getcwd())) targetDir=input("请输入要创建的各客户个人目录的父目录:\n") try: os.mkdir(targetDir) break except FileExistsError: print("父目录已存在,将略过创建!继续...") break except: print("路径名称输入有误或其他未知错误,3秒后请重输!") sleep(3) os.system("cls") filename=input("请输入用户信息文件:\n") try: with open(filename.strip(),"r") as f: num=int(input("请输入用户名称在信息文件中的第几列(起始列为0)\n")) s=f.read() f.seek(0) for i in f: cc=i.split(",") client=cc[num] if s.count(client)>1: sss=targetDir+"\\"+client+"(学号{})".format(cc[0]) else: sss=targetDir+"\\"+client try: os.mkdir(sss) print("客户目录 【{}】 创建成功!".format(sss)) except FileExistsError: print("客户目录 【{}】 已存在,将略过创建!".format(sss)) print("\n生成客户个人目录完成,再见!") except: t,v,tb=exc_info() st=str(t) t=st[st.find("'")+1:st.rfind("'")] print("文件名或路径名是对的吗?指定列内容有没有问题?以下是问题详情:\n{}:{}".format(str(t),v))
父目录路径不对:为空
父目录路径不对:os.mkdir要求最后一级目录前的路径是存在的,第一个test不存在。
父目录指定为当前目录,已存在
创建目录时没有权限
父目录成功创建
输入的数据文件问题
客户工作目录成功创建
重复性任务,将忽略新的创建过程
运行中,指定目录权限“突然”发生变更,没有访问权限
以上每项测试代表一个代码异常及相应处理行为,各项测试之间没有关系,测试条件分别单独设计。
4.3 系统级别异常
上面所说的执行控制异常中,输入、输出所涉及的权限问题也可以划分至系统级别的异常中来。由于输入、输出导致的异常或多或少地影响到正常业务处理逻辑流动,暂且先归入执行控制异常。系统级别的异常多来至软件外部操作系统环境的变更,和正常的问题求解过程无关,和语法、形式无关,和业务逻辑设计无关,和潜在的BUG、运行时动态出现的问题有关,和软件运行时的操作系统环境有关,和隐性问题的敏锐觉察与应对策略有关,和运行的时机有关。
第一种情况,和业务逻辑相关的系统环境变化。比如,在即将创建客户工作目录时,父目录由于某种原因被删除,从而导致创建失败。这种问题是异常捕捉机制设计策略决定的。我们可以有两种方式来推进业务逻辑的向前进展:一是代码行为流向的安全职责分布到各阶段,每完成一个阶段,就表示处于该阶段的风险完全得到消除,后续阶段将假定前面阶段不再有遗留问题,不再做重复性检查。二是每次在关键操作处检查执行该操作需满足的各种条件,代码行为流向安全由局部的统一处理保证。两种方式都各有优劣。这里用的是第一种策略:创建客户工作目录时,应该具备的条件在前面都得到保证后才能从业务逻辑上行进到这里,在代码内部,此时是可以断定是没有创建失败风险的。
第二种情况,我是我自己吗?也即代码是否是在一个真实的操作系统下运行,代码的行为是否是自发的。例如,通过专业手段,直接跳过前面各阶段的代码执行某种操作,此时,由于软件本体安全壁垒被攻破,运行时的各种临时数据可以被随意修改,既能引发很深的信息安全问题(比如说代码处理授权范围有限制或非公开的某些信息),执行该操作的各种先决条件也得不到可靠保证。这种问题只能通过执行完整性相关的检查机制解决。
第三种情况,软件正常运行在操作系统下的刚性系统条件变更。比如,软件依赖的某个系统组件、服务出错,突然断电等。解决这种问题要把握两个方向:一个方向是在软件内部要有运行状态保存策略,以便再次运行时继续执行;或者状态清理策略,以便再次运行时在多方认同的基础上重新求解问题。另一个方向是对于软件的部署实施要有危机处理策略,比如为计算机加装一台安全电延装置,当断电发生时,能为计算机提供一段安全时间续电,并向计算机发出已断电信号;而当软件接收到已断电信号后,进行相应处理后立即结束运行。改进代码如下,这里主要解决的是第一种情况,第二、三种情况有机会、有条件时再一起探讨,但是会对第二种情况做一个模拟演示:
import os from sys import exc_info from time import sleep while True: print("当前工作目录是:{}".format(os.getcwd())) targetDir=input("请输入要创建的各客户个人目录的父目录:\n") try: os.mkdir(targetDir) break except FileExistsError: print("父目录已存在,将略过创建!继续...") break except: print("路径名称输入有误或其他未知错误,3秒后请重输!") sleep(3) os.system("cls") filename=input("请输入用户信息文件:\n") flag=[] try: with open(filename.strip(),"r") as f: num=int(input("请输入用户名称在信息文件中的第几列(起始列为0)\n")) s=f.read() f.seek(0) for i in f: cc=i.split(",") client=cc[num] if s.count(client)>1: sss=targetDir+"\\"+client+"(学号{})".format(cc[0]) else: sss=targetDir+"\\"+client try: os.mkdir(sss) print("客户目录 【{}】 创建成功!".format(sss)) flag.append(1) except FileExistsError: print("客户目录 【{}】 已存在,将略过创建!".format(sss)) flag.append(1) except FileNotFoundError: print("客户目录 【{}】 创建失败!请检查路径是否发生变更!".format(sss)) flag.append(0) if sum(flag): print("\n生成客户个人目录完成,再见!") else: print("\n生成客户个人目录失败,再见!") except: t,v,tb=exc_info() st=str(t) t=st[st.find("'")+1:st.rfind("'")] print("文件名或路径名是对的吗?指定列内容有没有问题?以下是问题详情:\n{}:{}".format(str(t),v))
假设运行前text\text目录已存在,在运行至输入指定列时将最后的text删除。
最后一级的text即父目录被删除后,创建客户工作目录失败
改动程序,在flag=[]语句下加一句:haha=False,然后在try中flag.append(1)下面加一句:if client=="王五":
if haha==True:os._exit(-1)
其他不变:
import os from sys import exc_info from time import sleep while True: print("当前工作目录是:{}".format(os.getcwd())) targetDir=input("请输入要创建的各客户个人目录的父目录:\n") try: os.mkdir(targetDir) break except FileExistsError: print("父目录已存在,将略过创建!继续...") break except: print("路径名称输入有误或其他未知错误,3秒后请重输!") sleep(3) os.system("cls") filename=input("请输入用户信息文件:\n") flag=[] haha=False try: with open(filename.strip(),"r") as f: num=int(input("请输入用户名称在信息文件中的第几列(起始列为0)\n")) s=f.read() f.seek(0) for i in f: cc=i.split(",") client=cc[num] if s.count(client)>1: sss=targetDir+"\\"+client+"(学号{})".format(cc[0]) else: sss=targetDir+"\\"+client try: os.mkdir(sss) print("客户目录 【{}】 创建成功!".format(sss)) flag.append(1) if client=="王五": if haha==True:os._exit(-1) except FileExistsError: print("客户目录 【{}】 已存在,将略过创建!".format(sss)) flag.append(1) except FileNotFoundError: print("客户目录 【{}】 创建失败!请检查路径是否发生变更!".format(sss)) flag.append(0) if sum(flag): print("\n生成客户个人目录完成,再见!") else: print("\n生成客户个人目录失败,再见!") except: t,v,tb=exc_info() st=str(t) t=st[st.find("'")+1:st.rfind("'")] print("文件名或路径名是对的吗?指定列内容有没有问题?以下是问题详情:\n{}:{}".format(str(t),v))
这样改动为了在代码内部模拟一次系统环境变更导致的异常:当运行到为客户王五生成工作目录后,突然遇到某个系统性原因导致代码运行终止。
这是一个模拟环境,模拟代码的非自发运行。实际上这是一个调试状态,通过调试环境模拟代码在虚拟环境下的非自发运行,此时可以说代码并非操作系统下真实的自己。在原有的业务逻辑中,haha一直处于False状态,但是可以通过局部变量窗口手动修改它的值为True,来改变代码的执行控制流程和业务逻辑流程,并以此来模拟操作系统环境变更导致的异常终止。此时业务处理状态为:
这是假设系统故障排除后,重新(接着)运行的结果
最后,将刚才用于模拟环境异常的语句去掉,再加入界面信息,改进代码如下:
import os from sys import exc_info from time import sleep while True: print("当前工作目录是:{}".format(os.getcwd())) targetDir=input("请输入要创建的各客户个人目录的父目录:\n") try: os.mkdir(targetDir) break except FileExistsError: print("父目录已存在,将略过创建!继续...") break except: print("路径名称输入有误或其他未知错误,3秒后请重输!") sleep(3) os.system("cls") filename=input("请输入用户信息文件:\n") print("\n"+"*"*20) flag=[] try: with open(filename.strip(),"r") as f: num=int(input("请输入用户名称在信息文件中的第几列(起始列为0)\n")) print("\n"+"*"*20) s=f.read() f.seek(0) for i in f: cc=i.split(",") client=cc[num] if s.count(client)>1: sss=targetDir+"\\"+client+"(学号{})".format(cc[0]) else: sss=targetDir+"\\"+client try: os.mkdir(sss) print("客户目录 【{}】 创建成功!".format(sss)) flag.append(1) except FileExistsError: print("客户目录 【{}】 已存在,将略过创建!".format(sss)) flag.append(1) except FileNotFoundError: print("客户目录 【{}】 创建失败!请检查路径是否发生变更!".format(sss)) flag.append(0) print("*"*20) if sum(flag): print("\n生成客户个人目录完成,再见!\n目标文件夹:") print(os.listdir(targetDir)) print("*"*20) except: if flag==[]: print("(此处空空)\n"+"*"*20) print("\n生成客户个人目录失败,再见!") t,v,tb=exc_info() st=str(t) t=st[st.find("'")+1:st.rfind("'")] print("文件名或路径名是对的吗?指定列内容有没有问题?以下是问题详情:\n{}:{}".format(str(t),v)) print("*"*20)
任务成功完成
创建任务失败
任务再续成功
数据文件打开失败
5、代码容错机制与自我调节总结
从信息加工作视角来看,计算机和人具有“大致相仿”的宏观结构和行为,但我们仍将计算机看作是“计算机”;但是对于具有人工智能系统的机器设备,我们会进一步称之为“人”:机器人。可见,不是它真的是人,只是我们将它与人的相似性特征和它一起视为“人”。基于这种观点,从独立客体角度出发,我们可以认为软件是一个客观存在的对象,那么对于软件内部的代码,则是主体的构成。因此,代码是有自我意识的。
软件存在的最大价值是其功能,具有工具性。如果说,以前的物质工具和精神工具还比较楚汉分明的话,那么软件的出现则模糊了这两者之间的界线。为确保软件功能得以正常实现,软件具备代码安全系统,具体来说是代码保密性、代码执行完整性的保障机制和代码容错机制与自我调节。为确保某个原子性功能,也就是在一个维度下无法再细分的功能对外是不可见、不可知的,需要将相关代码进行保密。当软件运行时其内部代码间的执令流动、数据流动都是软件本身发起的,且基于软件自身“控制机构”的“设计规律”,那么这些代码行为都是预期的。预期的代码行为可以保证信息机密、业务机密、代码机密不被非授权性访问、修改。如何保证所有的代码行为都是预期的,这是代码执行控制和完整性检查要做的事。一旦软件功能在实施过程中遇到内部代码执行困难,将触发代码容错机制,并进行自我调节,使得代码的执行控制始终保持在从软件运行到软件结束(此时不一定完全解决某个问题)这一功能实现期内,从而保证业务处理涉及的方方面面都能得到最优处理。
在代码容错机制展开时,可能会遇到业务逻辑异常、执行控制异常和系统级别异常。业务逻辑异常大多是得到某个结果的先决条件不具备,或者进行业务处理的方法、策略不对,分类、分级的分情况处理不全面、不完善。执行控制异常往往导致代码行为偏离业务逻辑流和软件本体功能流的正常“跑道”,这个时候就要小心部署,以期能够捕获各种代码行为异常,并进行相应调节,回到软件的本次功能实现。系统级别异常是非软件自身能够掌控的,要做的是及时得到系统异常信号,最大限度的完成相关的撤销清理或状态保存工作。
代码行为异常的几个经典原因,一是来自用户。用户在使用时要提供一定的所需数据和执行条件,这就涉及到数据的合法性、所需性与执行业务处理的合理性。我们还是遵循那个原则:过程性的问题交由技术解决,意义性的问题将由用户解决。用户操作规范少一点,代码就要复杂一点;用户操作规范多一点,代码就要精准一点。这是策略性的问题,具体问题具体分析,但是,适当的语义定义和尽可能地让用户做选择而不是提供数据是解决用户、软件之间交互问题的通用做法。说到用户和软件的使用交互,由于用户操作的不规范、业务不熟悉等原因,有时能导致用户引发的业务逻辑异常,这种异常往往是BUG(漏洞)性的。二是来自系统。软件与软件之间资源使用同步问题、业务处理同步问题,软件与操作系统交互问题,操作系统的环境突变问题,都是代码容错机制和自身调节重点关注对象,特别是涉及到操作系统底层资源,越底层关注度就应越大。上面两种代码行为异常原因侧重于策略和机制层面,实际上因为开发者对某个函数或方法等理解不够而导致代码行为异常的情况并不少见。
代码异常发生的时机也是应当重视的。即便语法没问题,业务处理逻辑没问题,解决方法很正确,仍然可能会有想像不到的异常“蹦”出来。在设计代码时,一些问题交由语法解决,如捕获语法问题导致的异常;一些问题交由语义解决,如按一定规范分析某个对象;一些问题交由先行条件检查解决,如检查处理该业务时是否具备条件,但是,还是有一些看似相当正常的代码属于认知误区或问题解决误区之内的,认知不清晰、忽略对它们的关注(态度)、检查的忽略(思维缺陷)本身就是潜藏BUG的关键原因。这类错误往往能通过词法、语法检查和编译,但是在代码运行的时候非必然性的、偶然性地概率性地出现。一旦出现,对于软件自身来说就是致命性的,对于重要业务处理来说是代价惨重的。
虽然代码容错机制与自我调节很重要,但也不必逐变量逐表达式地生抠死查。一是根据开发财务预算,二是根据业务的重要性完全可以采用不同等级策略。对于代价不是体现在一定数量级的人力、物力、资源上,不是体现在严格授权等级的越级上,不是体现在信息机密上,不是体现在非常关键非常重视的数据上,等等,完全可以将保障软件安全运行的重任交给用户。
最后再看一下通过python函数装饰器实现的相似异常的统一管理。统一管理异常的方法有很多种,就不展开了。
from os import mkdir,getcwd from sys import exc_info def Boom_and_Watch(objF): def wrap(*args,**kwargs): of=True try: of=objF(*args,**kwargs) except FileExistsError: print("目录 【{}】 已存在,将略过创建!".format(args[0])) of=False except FileNotFoundError: print("系统找不到路径:{}".format(args[0])) of=False except: t,v,b=exc_info() t=str(t) t=t[t.find("'")+1:t.rfind("'")] print("{}:{}".format(t,v)) of=False return of return wrap mkdir=Boom_and_Watch(mkdir) open=Boom_and_Watch(open) ################################################################ print("当前工作目录是:{}".format(getcwd())) targetDir=input("请输入要创建的各客户个人目录的父目录:\n") mkdir(targetDir) filename=input("请输入用户信息文件:\n") num=int(input("请输入用户名称在信息文件中的第几列(起始列为0)\n")) print("\n"+"*"*20) ################################################################ try: with open(filename.strip(),"r") as f: s=f.read() f.seek(0) for i in f: cc=i.split(",") client=cc[num if 0<=num<len(cc) else 1] sss=targetDir+"\\"+client+"(学号{})".format(cc[0]) if s.count(client)==1: sss=sss[0:sss.find("(")] if mkdir(sss)==None: print("目录 【{}】 创建成功!".format(sss)) except:pass print("*"*20) print("\n本次创建客户个人目录任务完成,再见!")
-
加强容错设计
2022-01-09 14:52:58这世界几乎不存在完全正确的软件系统,目前的趋势是:系统规模越来越大,逻辑越来越复杂,要求越来越高。这种情况下追求完全正确会让成本变得不可控。理论上,设计、实现、环境都正确的...出于对现实的妥协,容错技术应这世界几乎不存在完全正确的软件系统,目前的趋势是:系统规模越来越大,逻辑越来越复杂,要求越来越高。这种情况下追求完全正确会让成本变得不可控。理论上,设计、实现、环境都正确的软件可以做到完全正确;现实是,这三条一条都做不到。一,就算是小型商业软件,无论测试还是形式化证明,工作量都是巨大无比,所以只能妥协而采取近似解。二,开发工具、第三方库不会完全正确,或多或少的存在缺陷。三,运行环境不一定和设计环境相同,比如:操作系统、数据库系统版本号不一致,操作系统、数据库系统本身的缺陷等。
出于对现实的妥协,容错技术应运而生,讲的是如何尽早发现缺陷,并消除或减少不利影响。容错技术可以在不同的级别实现,比如:系统级、设备级(电脑、手机)、组件级、模块级、代码级等。容错的技术的关键是冗余,消耗更多的资源以增强可靠性。资源包括三种:时间、信息(数据)、结构(组件)。
时间容错,代码级容错,执行诊断系统排除瞬时故障。目的:排除随机干扰。信息容错,代码级容错,在数据中增加一部分正常系统不需要的数据,以提前发现错误,主要消除重要数据通信的外在故障、人为篡改。结构容错,系统级、组件级容错,利用相异设计(不同的开发者、不同的开发语言)完成同一功能。
-
-
-
-
-
- 信息容错
-
-
-
-
信息偏差发生的时机主要在:一,数据传输过程中。二,数据存储过程中。三,数据运算过程中。常见的信息容错有如下三种:
-
-
-
-
-
-
- 冗余码、校验码。
-
-
-
-
-
身份证号码的最后一位就是校验码,如果输错一位,100%能发现。
-
-
-
-
-
-
-
- 奇校验码
-
-
-
-
-
-
奇校验码在原始的二进制数据最后(或最前)加上二进制1或二进制0,使得二进制1的位数为奇数。偶验证类似。都可以发现错1位、3位、5位...错误,都无法发现错2位、4位、6位...错误。绝大部分情况下是错1位。
-
-
-
-
-
-
-
- 海明码
-
-
-
-
-
-
当只有1位错误时,海明码可以定位错误位,并修正。修正方法:错误位1改成0,0改成1。下面以8位原始数据为例来说明原理。绿色表示正常,红色表示异常。
错误位
总校验码
验证码一
验证码二
验证码三
无错
第0位
第1位
第2位
第3位
第4位
第5位
第6位
第7位
绿色为1,红色为0,4个校验码各一个二进制位。
下表表示4位原始码错2位,4位原始数据需要3位验证码,下表只考虑错两位的情况,且不考虑总验证码。
错误的两位
验证码一
验证码二
0,1
0,2
0,3
1,2
1,3
2,3
上表结论:
- 如果错两位,无论如何都无法纠正。
- 如果错两位,可以发现错误。
海明码总结:
- 总验证位验证所有位。
- 各分验证位验证一半的位。
-
-
-
-
-
- 多处存储
-
-
-
-
-
将重要数据保存多处,以避免偶然性故障(比如:断电)。访问时,先判断是否一致,如果一致就读取,否则就转入异常处理。
-
-
-
-
-
-
- 日志和备份
-
-
-
-
-
理论上:只新增,不修改、不删除的系统永远不会出错。比如银行只记录存款、取款、转账操作,不修改账号余额,就不会出错。但这样存储开销太大,运行性能太低。折中一下,每天04:00统一修改一次余额,其它时间在此的基础上统计余额。每天的余额就是备份,每天的操作记录就是日志。有了备份和日志,可以在严重操作失误、硬盘损坏、天灾人祸、病毒破坏的情况下,快速恢复系统。
-
-
-
-
-
- 时间容错
-
-
-
-
失败后,重做。类似通过减法验算加法。包括:指令复执、程序卷回,两者的本质是相同的,前者从程序员的角度来看问题,后者从概要设计师的角度看问题。指令复执,指的是重复执行语句。比如:轮询,每10毫秒查询客户端是否有数据发过来。程序卷回,指的是某串行功能设置若干个恢复点,发现异常时,程序回到前一个恢复点继续执行。某CDC软件开发商,为了增加稳定性,将从相机取图和图像检测分成两个exe,取图exe启动一个实例,检测exe启动3到5个实例。这样一个检测exe崩溃后,其它检测exe可以继续运行。检测exe崩溃的几率大约100万分之一,检测100万帧大约需要10天。如果超时(在指定时间没有收到结果),则重新发送请求。无论运行了多少检测exe,每个请求只会执行一次。如果因为超时重发而收到两个结果,以先收到的结果为准。
-
-
-
-
-
- 结构容错
-
-
-
-
本部分包括三部分:一,结构容错的核心:相异性设计。二,两种结构容错。三,两种结构容错的优缺点。
-
-
-
-
-
-
- 相异性设计
-
-
-
-
-
- 由不同的人员完成。包括但不限于:分析、设计、实现、测试人员。
- 不同的思想。比如:面向对象、面向过程,不同的架构模式、设计模式。
- 不同的开发语言,如:C++、C#、JAVA。
- 不同的开发环境,VS、QT;不同的框架、类库。
- 不同的算法,比如:图像平移,可以直接加减法,也可以用矩阵实现仿射变换。
- 不同的运行环境,比如;操作系统、数据库软件。
-
-
-
-
-
- N版程序
-
-
-
-
-
对于同一功能,N(N>2)个开发团队开发N个可运行的程序,在不同的机器上运行。最终结果由这N个程序的结果综合得到。表决方式可以是多数表决或一致表决。结果很可能有误差,所以表决的时候,要考虑误差。表决的时候不一定等权,某些程序可能权重更高。结果不一定正确,可能异常,要做好异常处理。N版程序的改进版,只对某个模块进行N版设计。
-
-
-
-
-
-
- 恢复块
-
-
-
-
-
通俗的说,恢复块不但有正常的模块,还有一到多个备用模块。正常模块运行失败、异常、结果异常时,运行备用模块。难点:环境的恢复。有两个方法:一,运行前备份环境,运行前利用备份恢复环境。二,通过逆运算恢复环境。前者实现简单,后者性能好。备用模块的来源:一,专门设计的。二,淘汰下来的旧模块。三,重新设计、实现的低要求模块,比如:降低性能要求、降低精度要求。
-
-
-
-
-
-
- N版程序、恢复块优缺点
-
-
-
-
-
N版程序设计的优点:简单可行,多进程(多线程)加速。
恢复块优点:无需增加硬件,支持细粒度。
N版程序设计缺点:
- 工作量增加了几倍。
- 通信麻烦,局域网、跨进程、跨线程。
- 要处理复杂的同步、异常。
恢复块缺点:
- 运行时间不确定、不稳定。运行多个备用块,显然用时较多,可能引起网络、数据库超时。
- 环境复杂的时候,备份工作会大幅增加开发工作量和内存(甚至硬盘)消耗。
- 验证测试困难。理论上要需要知道所有错误的可能,而这往往不可能。
-
-
9种常用的软件容错处理方式
2021-12-16 00:37:41本文重点讨论软件容错的问题。一个完整的系统在内部是由很多小服务构成,服务之间以及服务与资源之间会存在远程调用,每个系统的可用性不可能达到100%,所以容错处理显得尤为重要!容错的目标是降低...本文重点讨论软件容错的问题。
一个完整的系统在内部是由很多小服务构成,服务之间以及服务与资源之间会存在远程调用,每个系统的可用性不可能达到100%,所以容错处理显得尤为重要!容错的目标是降低或者最小化故障对系统可用性、可靠性、安全性等的影响。
一般而言,系统故障从大的角度看来自两个方面,分别是硬件故障和软件故障,硬件故障通常是不可自恢复的故障,必须人为去检修处理;而软件故障可以通过多种方式去规避预防,最大程度保证系统可用性。
硬件容错常用的方法包括使用冗余多备份技术、增加内存、能源系统冗余等,硬件错误通常能够在两台物理机上进行隔离处理。软件容错的方式更加多样,今天我们重点探讨一下软件容错的问题。
故障的演进
软件系统异常并不是一蹴而就的,毕竟在系统上线前要经过严格的单元测试、集成测试、回归测试等环节,至少会把很多显性的、容易暴露的问题发现并fix掉,没有达到测试标准的系统也不会上线。那么故障到底来自于哪里呢?
说来也简单,就是一个fault(缺陷)到error(错误)到failure(故障)的转换过程,系统缺陷在某种特定环境下被激活,然后系统产生错误,紧接着系统错误运行使得系统发生某种故障。
要注意的是,错误并不一定导致系统故障,可以理解错误是故障的充分条件。一个最简单的例子是发生了网络错误,但这个网络错误可能只是暂时的不可访问状态,并不一定会升级为故障。
故障的由来
在我们日常开发工作中,最常见的故障来自于系统单点故障,单点故障迟迟得不到处理后便升级为系统性故障甚至全面瘫痪。
单一故障点是指没有备用的冗余组件的硬件或软件组件,而这些组件是系统重要的组成部分。该组件出现故障会使系统无法继续提供服务。设计容错系统时,必须确定并消除潜在的单一故障点。
一个典型的故障升级可能是这样的:系统中资金冻结服务存在严重的缺陷,所有部署该服务的机器平均响应速度逐渐慢下来,当大量下单请求进来时,慢慢消耗掉系统所有资源,进而导致整个系统不可用。
故障的常用容错方法
软件故障的容错方法如果用一句话来简单概况的话也简单:通过定义规则来容忍系统缺陷。但这样的定义未免过于大而空,我们需要切实有效可落地的方式。下面介绍9种常用的处理方式。
▐ Process Pairs
也就是最简单的backup方案,保证系统在某一个时刻总能有一个进程来处理客户的输入请求,能处理短暂的软件错误。
▐ Graceful Degradation
就是我们常说的降级,在系统遭遇某个错误之后不提供完整功能,只给用户开放部分基础能力,此解决方案通常是上面的backup方案持续性不work的时候采取的保护措施。
▐ Selective Retry
选择性重试也是可选的方案之一,它主要适用于是突发式高负载资源短缺的场景,例如,网络瞬时打满峰值不可访问或者内存资源短缺,重试能够增加资源分配成功的可能性。
▐ State Handling
在系统不能提供服务后,又要保证client的无状态属性。服务端需要持续保存当前的状态,用于故障后的重试。
▐ Linking Process
有些程序进程是相互依赖的,如果某个进程出错,其他依赖的进程需要侦测到错误,明确做相应的处理,通常是结束全部依赖进程。
▐ Checkpoint
周期性的保存进程的状态。如果需要保证数据正确,回滚到最近保存的状态即可,只是会有部分的数据丢失。
▐ Update Lost
上面方案的补充版,在两个checkpoint之间系统故障,需要保存客户请求,在rollback前一个版本之后重新处理这些请求。
▐ Process Pools
使用资源预分配技术,按照经验设定好某些请求资源的需求量,为程序分配合适的资源。就像我们为某个任务分配线程池大小一样。
▐ Micro reboot
通过解耦系统组件,使得系统在遭遇故障时,只需要重启需要的组件,而不必重启整个系统。核心是组件和数据分离,数据的处理通过持久化存储的方式保证一致。
容错、熔断、隔离?
“隔离”是一种异常检测机制,常用的检测方法是请求超时、流量过大等。一般的设置参数包括超时时间、同时并发请求个数等。
“熔断”是一种异常反应机制,“熔断”依赖于“隔离”。熔断通常基于错误率来实现。一般的设置参数包括统计请求的个数、错误率等。
“容错”是一种异常处理机制,“容错”依赖于“熔断”。熔断以后,会调用“容错”的方法。一般的设置参数包括调用容错方法的次数等。
总结
对可用性的要求达四个或五个九通常要求系统必须是一个容错系统。容错系统必须能够在硬件或软件出现故障时继续运行。通常,容错的实现手段是为提供关键服务的硬件(如 CPU、内存和网络设备)及软件配置冗余组件。
容错系统的实现和维护成本高昂。需要确保先了解业务可用性要求的本质,然后再考虑能够满足这些要求的可用性解决方案的策略和成本。
一定程度上看,代码中的容错处理体现了一个程序员的基本素养。不管是平凡无奇的业务开发还是程序语言本身的设计,无处不体现了容错处理的重要性,在开发过程中需要不断磨炼思考。
团队介绍
我们是阿里巴巴淘系技术部的新品平台技术团队, 依托于淘系大数据正在建立一套完整的涵盖消费者洞察、宏观及细分市场分析、竞争分析、市场策略研究、产品创新机制等的新品研发和创新孵化平台, 为品牌、商家及行业提供规模化的新品孵化和运营能力, 沉淀新品孵化机制和运营策略, 最终建立起一套基于大数据驱动的从市场研究、新品研发到新品投放营销的全链路新品运营平台。发送邮件到tianhang.th#alibaba-inc.com(发送邮件时,请把#替换成@)
✿ 拓展阅读
作者|马刺
编辑|橙子君
出品|阿里巴巴新零售淘系技术
-
debug容错 缺陷抓取
2012-05-21 20:36:00客户端混淆过的,不过还是很快的被反出来了. Error #2044: 未处理的 ...虽然第2次登陆游戏报这个有些诡异,但强大之处是顶着几个问题,依然坚挺的进入了游戏可以任意操作,无其他数据异常,这样的容错是不是该学习下。 -
Flink 容错机制
2022-04-04 09:02:42概述 ... 在 Flink 中,有一套完整的容错机制(fault tolerance)来保证故障后的恢复,其中最重要的就是检查点(checkpoint)。在前面,我们已经介绍过检查点的基本概念和用途,接下来我们就深入探 -
MapReduce的容错机制(一)
2020-09-07 20:34:12前言 现实中,用户代码错误、进程崩溃、机器故障等等都可能导致MapReduce程序失败,但是Hadoop最主要的... 子任务失败:最常见的就是map或reduce中用户代码抛异常,此时子任务JVM进程会在退出前向其父tasktracke... -
【09-异常处理】
2018-07-03 21:46:06增加了异常处理机制后的程序有更好的容错性,更加健壮。 传统错误处理的缺陷 •传统错误处理机制,主要如下两个缺点: –无法穷举所有异常情况:因为人类知识的限制,异常情况总比可以考虑到的情况多... -
Hystrix服务容错
2021-10-21 19:06:15Hystrix是一个库,可以通过添加等待时间容限和容错逻辑来帮助你控制这些分布式服务之间的交互。Hystrix 通过隔离服务之间的访问点,停止服务之间的级联故障并提供后备选项来实现此目的,所有这些都可以提高系统的... -
Hadoop之Hadoop高容错
2020-12-20 18:37:22Hadoop高容错性大概分为三大块 1:HDFS的副本容错机制 2:YARN的容错机制 3:ZOOKEEPER高可用集群容错性 首先了解一下HDFS的副本机制 ##1:为什么要有副本机制## HDFS视硬件错误为常态,硬件服务器随时有可能发生... -
软件缺陷管理
2022-01-27 15:20:52缺陷管理1 缺陷定义2 缺陷的判定标准3 缺陷产生的原因4 缺陷产生的根源5 缺陷信息6 缺陷状态7 BUG类型8 严重程度9 优先级10 缺陷跟踪11 缺陷密度12 缺陷数据分析12.1 关注的问题12.2 重要性12.3 数据指标13 寻找缺陷... -
异常项
2021-07-22 00:25:40异常指的是在程序运行过程中发生的异常事件,通常是由外部问题(如硬件...中文名异常项外文名exception item学科计算机科学原因程序设计的缺陷、人为导致定义系统在运行过程遇到异常有关术语异常异常项简介编辑语音异... -
软件缺陷
2021-05-10 21:36:16软件缺陷 IEEE 1983 of IEEE Standard 729中对软件缺陷作了一个标准的定义:从产品内部看,软件缺陷是软件产品开发或维护过程中所存在的错误、毛病等各种问题;从外部看,软件缺陷是系统所需要实现的某种功能的失效... -
5.1 拜占庭容错技术
2018-09-30 14:48:23Tolerance,BFT)是一类分布式计算领域的容错技术。拜占庭假设是对现实世界的模型化,由于硬件错误、网络拥塞或中断以及遭到恶意攻击等原因, 计算机和网络可能出现不可预料的行为。拜占庭容错技术被设计用来处理... -
3.可靠性设计 -高可靠系统中软件容错技术的应用
2021-11-03 11:34:48本文以分布式大容量终端平台为例,主要论述了软件容错技术和方法在该平台中的具体应用。通过采用以集群化的形式进行应用部署;通过主备形式的数据库部署进行软件容错;通过程序设计方面进行软件的容错与避错。事实... -
YARN容错机制
2020-02-07 12:16:18使用hadoop的好处之一就是可以它能处理这类故障并成功完成任务。需要考虑的实体失败任务为:任务(job),Application Master,NodeManager和ResourceManager。 任务失败 可能存在以下情况: MapTask或者ReduceTask... -
Dolphinscheduler源码分析-容错篇
2020-06-12 20:48:16DS调度是分布式部署,实现调度和运行隔离,设计了master和worker master负责拆分DAG,监控任务状态,根据依赖条件,提交任务实例。...一旦master/worker服务挂掉或者网络异常原因,服务会失去zk的连接,触 -
10分钟带你彻底搞懂集群容错和服务隔离
2021-07-21 15:59:30在分布式系统中,由于网络条件以及系统自身缺陷等问题,服务与服务的调用过程难免会出现失败。为了把这种失败的影响程度降到最小,目前,业界有两种主流的最佳实践方案,分别是集群容错和服务隔离。这节课,我就带你... -
测试用例设计方法_异常分析法(游戏向)
2021-07-15 15:52:24异常分析法是针对游戏中玩法、系统有可能存在的异常操作、游戏缺陷引起的联合性缺陷、疑难杂症、故障等各类问题进行分析,依此设计测试用例。主要针对软件系统/游戏的容错能力、故障恢复能力进行测试。通俗而言... -
亿级Web系统的高容错性实践
2018-03-23 10:57:54原文地址:https://blog.csdn.net/linuxnews/article/details/51371338背景介绍大概三年前,我在腾讯负责的活动运营系统,因为业务流量规模的数倍增长,系统出现了各种各样的异常,当时,作为开发的我,7*24小时地... -
微服务 第四节 限流容错Sentinel,挺好玩的一个组件,也很强大
2021-06-04 21:01:12三、Sentinel流量控制,容错,降级 开始整活: com.alibaba.cloud spring-cloud-starter-alibaba-sentinel 1.7.1 这里说明一下,不用DashBoard,需要写代码,缺陷很大,具体的缺陷有: (1)业务侵入性很大,需要... -
容错技术介绍
2017-05-22 13:00:00常见的增强鲁棒性机制的...在软件容错中,常常使用fault(缺陷),error(错误),failure(故障)来表示系统异常的由来。系统缺陷在某种特定环境下被激活,到至系统产生错误,系统错误运行是的是的系统发生某种故障。 常... -
【区块链】PBFT(实用拜占庭容错)算法详解
2019-04-07 21:05:14拜占庭将军问题: 寻找一个方法,使得将军们能在一个有叛徒的非信任环境中建立对战斗计划的共识。 共识算法的核心是在正常的节点间形成对网络状态的共识。 共识算法协议的属性: ...BFT拜占庭容错系统: ... -
异常处理与实践
2022-01-23 12:21:22超时设置与处理 超时 超时设置应该被重视,因为超时设置的问题,已经引发了多起 P3 以上级别的事件。 通过配置合理的超时时间,可以防止依赖... 异常处理类 Java 把异常当做是破坏正常流程的一个事件,当事件发生后,就... -
正交表和软件缺陷
2019-11-15 14:14:00一、正交表 根据正交性从全面试验中挑选出有代表性的点进行测试,点具备 均匀分散、整齐可比 ...容错处理(功能缺陷,无引导提示) 数据转换(增删改查) 性能缺陷(内存占用高、页面打开时间长) -
性能测试之常见性能缺陷
2021-08-21 16:27:09性能测试,是结合被测系统应用架构、业务场景和实现细节、逻辑,对软件响应时间、处理速率、容错能力等进行分析测试,找到系统的性能瓶颈,并确认问题得到解决的过程。 二、性能测试缺陷分类 缺陷类型:硬件、网络... -
【Java】J2EE异常处理设计整理
2020-02-17 19:46:15我们在处理应用中的异常时,通常可以将应用中所遇到的异常分为两大类,一种是业务异常,一种是非业务异常。 业务异常是指在进行正常的业务处理时,由于某些业务的特殊需求而导致处理不能继续执行所抛出的异常,这种... -
YARN容错机制-hadoop
2020-08-18 10:46:14使用hadoop的好处之一就是可以它能处理这类故障并成功完成任务。需要考虑的实体失败任务为:任务(job),Application Master,NodeManager和ResourceManager。 1.任务失败 1.1 可能存在以下情况: MapTask或者... -
第一阶段——软件缺陷与软件质量
2021-04-13 19:12:00软件缺陷与软件质量 一、软件缺陷 1.什么是缺陷? 不符合设计要求、不满足用户确定需求 2.产生缺陷的原因 人员之间的沟通交流不够,交流上有误解或者根本不进行交流 文档不完善 需求不断的变化 参与人员的过度自信 ...