目录
术有千法,道本归一。
之所以这样说,是因为当前出现的纷繁复杂的后端技术,其本质其实都是为了解决同一套问题。
有哪些问题是后端体系一直在持续性关注的?这套问题总结起来其实就是:
机器的问题
人的问题
机械的问题是指,当前计算机的体系架构下,存在的一些问题。
人的问题指的是,工程协作和管理的问题。
也可以说一个是技术问题,一个是管理问题。
就当前我们所用到的这整个计算机系统而言,基本上可以看作三大部分:
存储
传输
计算
计算,其实指的是计算机算力的问题,硬件的算力是多少这个对于后端而言是无法控制的,后端需要做的是在编写代码的时候用最合理的数据结构和算法来充分发挥出计算机的算力,让机器在同等算力下能执行更多任务,完成更多工作。这一块相关的内容是计算机专业的基础课,即数据结构与算法。除了这一块,后端还需要考量的是契合操作系统的特性来尽量的利用好系统资源。
操作系统是什么?操作系统,是位于硬件和用户之间的中间层软件。面向用户提供用户接口,方便用户控制计算机,面向计算机,在硬件层上提供一套资源调度策略,负责完成资源调度管理。计算机如果只是单独的硬件拼凑,用起来会存在很多问题,至少可以归纳为三方面:
不友好
不安全
效率低
不友好:
硬件操作是十分复杂的,如果对计算机的操作都是直面硬件,对于操作者(用户或者应用软件)而言将会十分不友好。
不安全:
如果对计算机的操作都是直面硬件的,恶意应用软件对计算机的攻击会很容易。
效率低:
由于缺乏对于任务的调度管理,首先,指令的执行将会变得不可控。无法知晓指令何时执行完毕,高优先级的指令可能无法被率先执行。其次,资源的利用率将会很低。因为无法对指令的执行进行干预,当前指令执行所涉及的资源之外的资源将会被直接闲置浪费掉。
综上所述,在硬件和用户之间需要一个中间层,这就是操作系统。
既然操作系统是对计算机资源的一个管理系统,其核心管理的必然就是计算机的核心资源,计算机最核心的资源是什么?
答:内存和CPU。
现代操作系统来说,都是用进程来管理CPU资源,编址和分区来管理内存。
但是进程引入后,在进行进程切换时,CPU上下文的切换会造成很大的资源开销,也会白白浪费掉CPU的一些工作时间。在内存管理引入后,为了保证系统的安全在进行外部IO读写的时候内核段和用户段之间的数据复制也是拉低系统效率的一个点。
当前计算机的体系架构是有统一标准的,即——“冯诺依曼体系架构”。什么是标准?回想一下JDBC、AMQP等常见的标准,可以发现其实标准就是抽象模型,即这个东西由哪些部件组成。
我们所期待的计算机怎样去工作?
答:在人的控制下能不停的进行指令处理。
计算机的运算速度那么慢,要执行的指令肯定不能全都来自于外部输入,应该是预先准备好了海量任务,让计算机来处理,所以应该将程序编写好存储起来,等需要的时候再交给计算机运算。于是可以发现,计算机的核心在于“储蓄存储”和“持续控制”。为了实现这两个关键点,冯诺依曼开始攒计算机,最后攒来攒去得出了一个最科学的结论,也就是计算机由控制器、运算器、存储器、输入设备、输出设备五大部分组成,这样能很好的完成我们对计算机整个体系功能的期许。可以说当前计算机基本上都是冯诺依曼体系结构的,(控制器+存储器一般做在一起,叫CPU)但是任何体系结构一定会存在取舍和优劣。由于东西都存在存储器里,从存储器种读取内容,交给CPU这个过程中,由于CPU和存储设备之间速度差着一个量级,CPU的速度要远远高于存储设备的读写速度。所以这种从存储中读数据交给CPU的IO过程中,CPU资源的浪费是冯诺依曼体系结构中无法避免的一个点。如何去避免IO或者优化IO,一直是后端各种解决方案围绕的一个基准点。
为了支持网络边缘间的通信,就需要有互联互通的网络,就需要在两个实体间建立连接,并且要存在一系列机制保证在连接中通信的可靠与顺畅。如数据不能丢、不能乱序、链路断了怎么处理之类的。
于是在网络中进行传输时,我们每次发出去的东西,除了基础的需要交互的数据内容外,还需要携带一些额外的信息,这些额外的信息用于实现各种保证可靠传输的机制。其实就是通信协议。
网络传输,数据包本来就要在多个节点间转跳、往返,如何给这个过程松绑,如何让传输高效可靠是优化的一个大方向。
人的问题其实就是协作问题,在软件工程中,进行有一定体量的项目的开发的时候,一定是一个团队来进行协作的。彼此之间完成的只是整体的一个部分,在这种整体推进中,有两个方面是需要进行把控和管理的:
代码工程的管理
过程的把控。
编码这当然是个核心问题。
计算机是人造的,但是数学是神造的。
虽然说用什么样合适的数据结构去组织数据,用什么样合适的算法去解题,是编码的一个重点,但这些都是偏实现层面的细节了,这里我们要聊的是抽象维度更粗、更高的代码工程的管理层面。
在整个编码实现的过程中,代码工程的管理有哪些核心诉求?无非就两点:
让过程丝滑一点
让代码的可复用性高一点。
让过程丝滑一点:
在多人协作的开发过程里,持续迭代和可溯源是需要保证的两个重点。想有高效的开发过程,如何实现这两点就显得尤为重要。
让代码的可复用性高一点:
整个编码架构层面,追求的核心是什么?
答:良好的复用性。
也就是说怎么让代码具有高类聚,低耦合,良好的开闭性,这是需要关注的重点。
软件开发大体分为几步:
需求分析
设计
编码实现
但如何实现这几步,方法是多种多样的,就像我想从成都到自贡,达到这个目的,虽说大体可以分为出门、上路、到家,但整个过程是有多种路径可以选择的,可以自驾、高铁、长途汽车等等,软件的开发也是这样的,到底需要怎样是落地这个过程也是有多种办法的。
不管实现如何变化,其核心目的是什么?
当然是不停的向目的地靠近。
上面详细聊了几个方面存在的问题,好,现在回到文章一开头提出的:
当前出现的纷繁复杂的后端技术,其本质都是为了解决同一套问题。
机器的问题体现在:
基于当前计算机体系结构下的扬长避短。
人的问题体现在:
编码的可复用性和过程管理
遍观后端的各种技术:
数据存储技术:关系型、非关系型,内存型、硬盘型,文档存储、列存储、对象存储、列存储......
编程语言自身的IO相关能力:BIN、NIO、AIO......
编程语言自身的并发编程的能力:多线程、池化技术、虚拟线程......
各种关于传输上的考虑:序列化、自定义通信协议......
可以发现,他们本质上都在做一件事:
基于当前计算机的体系结构,扬长避短。所有后端技术均可以看作开发者与计算机基础体系间的中间层,计算机中百分之八十的问题都是可以通过加中间层来解决的,只是这新引入的中间层,又会引发新的问题,所以没有绝对完美的解法,基于自己的业务场景做好取舍和选择,就是对的。
遍观工程相关的各种技术:
各类开发框架:Spring、EJB......
各种开发方法论:瀑布模型、敏捷开发、领域建模、结构化方法、面向对象方法......
各种工具:设计模式、依赖管理、持续集成/持续发布、Devops、虚拟化、容器技术、云原生......
可以发现,他们本质上都在做一件事:
向目标不断靠近,并在过程中尽量保证过程的平滑、淡化开发之外的一切诸如部署、运维等工作,保持过程的持续性,以及尽量控制产出的质量,让产出具有良好的复用性。
最后说回来,博主为什么要在第200篇文章的时候,聊这些喃?
还是那句话:
所有后端技术都是基于当前计算机的体系结构,对其进行的扬长避短。
有这样的核心理解后,来看待纷繁复杂的后端技术栈时,可以理出一条主线来,避免乱花渐欲迷人眼。
举个例子:
dubbo是个高性能的RPC框架,那其高性能是从哪里来的?是从优化IO和自定义传输协议来实现的。
又比如Kafka和rocketmq,其为了保证消息的可靠,落磁盘是必须的,但又要保证吞吐量,所以就要尽量的来优化IO,于是给出了零拷贝的打法。
最后,本文只是罗列出来了一些大方向,篇幅有限,肯定是涵盖不全的,雅客斧正。