软件架构设计

做技术的,特别是做互联网技术的朋友,如果大学没有学习过计算机科班课程的,可能对于程序架构设计不是很清楚,不清楚这个程序为啥还要有架构设计,程序架构设计是什么,进行程序架构设计需要做些什么。当然也不会清楚程序架构设计在什么时候做。

本文将回答以上问题,同时介绍写程序相关的概念,并在此基础上对程序架构设计进行讲解,对于程序架构设计关注点进行剖析,最后会将工作中的应用和实践进行分享。

1 一些基础概念

1.1 什么是程序

什么是程序,学习过计算机专业的课程都知道,程序就是一份代码,然后经过以下编译(解析)到执行的过程细节:

代码-编译-连接-可执行文件代码-解析-中间文件-解析执行所以程序就是一份代码经过编译(解析)处理后编程成为计算机系统(包括移动硬件的系统)可以识别执行的指令,然后在系统中进行运行的进程的表现形式。可以认为程序就是代码编译后所有的资源的统称,一般程序又有这些名称,客户程序,后台程序,移动应用程序,和可执行程序等。

1.2 什么是进程

程序运行的时候,在内存中 的实例,称呼为进程。进程是操作系统调度的最小单元。在操作系统的调度中,对于进程的内存有分段分块分配,对于进程的cpu需要进行调度。内存主要划分为:代码段,静态数据段,堆栈数据段这几个。

1.3 什么是线程

程序运行的一个路径,一条执行线索。线程也是轻量级的进程。线程在操作系统中往往和主机硬件的多核心有关,当需要进行并发设计的时候可以考虑多线程的程序架构模式。当然还有其他的模式,如多进程。

2 程序架构设计

2.1 总体介绍

程序架构设计其实是软件架构设计的子集(对于软件架构设计,请参考我百家号另外一篇专门讲解架构设计总体介绍的文章),不过程序架构设计更专注于程序本身的架构,关注程序的运行架构,部署架构,以及程序运行的性能和可用性是否满足产品的性能需求。

2.2 处在什么阶段

程序架构设计往往对应于软件工程过程中的详细设计阶段(软件工程过程:需求-UI设计-概要设计-详细设计-单元测试-集成测试-上线)。请查看软件开发流程:

产品研发流程

2.3 考虑因素

为了满足产品对性能的要求,考虑稳定性方面因素,以及维护和部署的效率和影响面,往往程序架构设计需要优先考虑多进程,多线程等的混合程序架构设计。首先,对于简单的功能直接采用单进程的程序架构模式即可。

再次,而对于复杂的功能,特别是对并发性能有要求,这个时候需要考虑多进程架构,或者多线程架构,或者多进程多线程的架构。

最后,需要确定程序的部署方式,和对主机资源的要求(CPU核心数,内存数,网络带宽等)。

2.4 分类

从总体和功能以及业务情况来划分,常见的程序架构有MVC,组件化,分组,分层,对象化,以及过程化,零散的架构分类。备注说明:途中数值为虚构,并不是真实的统计数据。

根据业务的架构分类
根据运行架构的分类

3 应用和实践

3.1 进程,线程,协程的区别

定义上的区别

进程和线程共享栈数据之外的所有内容数据。

协程不是一个操作系统的实体对象,只是一个开发模式的概念。由开发者对协程的调度实现方式重新进行设计。

细节如下图

内存划分的区别

3.2 程序架构选择

对于多进程,多线程架构的选择,需要根据实际的业务功能需求来,以及团队的开发模式。其中在进行选择的时候,以下方面是需要进行参考的:

多进程的优势——进程相互独立,内存占用(溢出,出错等)都相互不影响,如果新功能模块单独一个进程进行编码实现和处理,这个时候对上线和运维都会非常高效。多线程的优势——并发和多核的充分利用,不过虽然是多线程也不代表线程数越多越好,常用的模式还是线程池的做法。或者实践中会把线程数控制在和核心数一致。对于当今比较流行的区块链,分布式计算,分布式服务产品,以及微服务架构(开发模式),都是多进程架构的基础。不管是在可用性,性能,还是模块化更好维护,更方便协作等等都体现出来非常优秀的价值。4 程序架构分享

4.1 浏览器内核的多进程多线程架构

浏览器内核架构设计

图片来源:chromium浏览器官网。

浏览器内核的主要进程有:Browser进程,Renderer进程,进程间通信通过IPC进行。每一个独立的页面采取的机制是一个独立的Renderer进程进行渲染。多进程渲染模式有一个好处就是,单个页面的渲染出问题,不会影响其他的页面打开和渲染。这就给浏览器的程序带来很棒的用户体验。

而每个Renderer线程中由由一个Main线程和Render线程的多线程架构,做到并发处理模式。也可以认为是一种分工和合作。

4.2 web服务器NGINX的多进程架构

nginx架构设计

图片来源:nginx官网。

NGINX的多进程架构划分为MASTER进程(主进程)和子进程,主进程负责调度和接收连接,多个子进程负责对每个请求进行数据组装和响应,还有cache的管理和加载。每个子进程相互独立,对于某个请求导致的子进程处理出错,只会影响这个子进程本身,不会对其他有任何影响。