FreeWheel 首席工程师:我对软件分层设计的思考

article/2025/9/27 8:27:47

在刚刚圆满落幕的亚马逊云科技中国峰会上海站,FreeWheel的Tech Lead曹宇先生和大家分享了现代化应用和无服务器的奥秘。点击下方视频,一探究竟。

今天,我们为大家带来FreeWheel首席工程师杨敏关于软件分层设计的思考和见解,以下为全文:

*本文2021年7月29日首发于微信公众号“架构头条”

在日常开发中,经常听到大家说一句话“任何需求都可以通过一个间接的中间层来解决”。今天,通过几个case就“分层”话题梳理下自己的思考,其中,有些case比较直观,而有些不那么直观,甚至有些微妙,需要我们自己多品味。这意味着学习过程需要我们不断将新知识与旧知识进行关联,形成自己的知识体系,而非一个个知识孤岛。

????  想要了解更多亚马逊云科技最新技术发布和实践创新,敬请关注2021亚马逊云科技中国峰会!点击图片报名吧~

什么是分层设计?

它有何好处?

分层设计将软件划分成若干层,每一层只解决一部分问题,通过所有层的协作来完成整体目标。一个复杂问题通过分解成一个个系统子问题,这样就有效的降低了每个子问题的规模与复杂度。

分层设计带来的好处:

  • 降低了系统软件的复杂度,将一个复杂问题通过分解,分而治之

  • 功能的复用和封装

计算机语言的发展

机器语言

早期,软件开发是机器语言,直接用二进制0和1表示机器可以识别的指令和数据,看起来像这样:

0010000100100011

这就是计算机CPU唯一可以理解的语言。对人类来说,二进制的程序是不可读的。

汇编语言

为了解决语言可读性的问题,汇编程序诞生了。汇编程序是人类可读的机器代码。它又被称为“符号语言”,使用助记符来代替机器的操作码。

汇编语言是二进制的文本形式,与CPU的指令是一一对应的关系。而我们不同的CPU体系结构(比如PC的 X86、嵌入式的ARM)是不同的,面向机器的语言带来的问题就是:对于不同的CPU体系架构,就需要不同的汇编语言。

高级语言

为了解决语言对机器的无关性,高级语言诞生了。一条高级语言通常由若干条机器语言实现的,并且不具有对应性。

高级语言让开发者不需要关注底层CPU体系结构与指令,只关注业务即可。

计算机语言的发展就是不断的抽象,只有通过抽象,将一个复杂的的系统变成一层层的接口集合,让我们每次只需要考虑关注当前层集合内的逻辑,而不用去考虑当前层次以上或者以下的复杂度,才有可能让我们从复杂系统中解放出来,逐步理解以及构造一个复杂系统。

Linux内核

内核功能层与内核硬件层

操作系统内核,可以简化理解成三大层:

  • 内核接口层:向上对用户态应用程序提供一套接口子集,开发者使用的系统调用APIs。

  • 内核功能层:这一层完成各种实际的功能,我们知道OS主要负责资源管理、内存、进程这些资源,物理内存如何申请、释放,进程如何调度。具体来说进程管理、内存管理、中断管理、设备管理。

  • 内核硬件层:分离硬件的相关性,我们知道一个OS可以运行不同的指令集,也就是运行在不同的硬件平台。

不管是ARM体系结构,还是X86,选择一个进程调度的算法是可以相同的,需要改变的进程切换相关代码,因为不同的硬件平台的上下文是不同的,CPU的寄存器也不同。这时候最好的设计是分层,当操作系统运行在不同的硬件平台时,就只需要修改硬件平台相关层代码,实现操作系统的高可移植性

操作系统有两个关键设计:

  • 内核接口层区分用户态与内核态,来保护硬件资源受限访问。

  • 内核硬件层分离多种硬件平台相关性。这种分层的架构,极大提升了系统的稳定性和扩展性。

MMU抽象层

操作系统负责管理物理内存,而用户进程使用虚拟内存。操作系统呈现给用户进程的是连续的虚拟空间,但不一定是连续的物理空间。因为物理内存被整个OS共享。

什么是MMU呢?它是硬件,即内存管理单元,它对CPU发出的访存地址进行映射与检查,可以让处理器发出的访存地址访问不同的物理内存单元。

如果将计算机上有限的物理内存分配给多个应用程序使用,如果让应用程序直接访问物理内存,如果没有MMU这层抽象呢?带来的问题是每个应用程序地址空间不隔离,内存使用率低,程序运行地址也无法固定。

解决的问题:虚拟内存VA与物理内存PA的映射——通过在CPU与内存之间加入MMU抽象层,让CPU在运行指令时发出的VA虚拟地址通过 MMU 转换后变成PA物理地址,然后再去访问物理内存。

MMU引入带来的好处:

  • 权限控制。可以对一些虚拟地址进行访问控制,比较代码段为只读,用户程序代可写。

  • 提升内存使用率:物理内存按需申请。fork子进程的对应的物理空间是能过写时复制才进行真正的物理内存分配。

  • 不同进程之间可以使用相同的虚拟内存地址空间,而进程的物理内存又可以隔离。

  • 系统运行多个进程,所分配的内存之和可以大于实际物理内存大小。

这是我认为最经典、最本质、最受启发的中间抽象层的设计。

CPU与外设的通信

CPU访问外设有两种方法;

  • IO与内存统一编址

  • IO与内存的独立编址

外设接口中的IO寄存器(即IO端口)与主存单元一样看待,每个端口占用一个存储单元的地址,将主存的一部分划分出来用作IO的地址空间。

把外设的寄存器当做是一个内存地址,从而CPU以类似访问内存相同的方式来操作外设。

对IO外设的端口映射到一个物理内存单元地址,在CPU与外设之间的“内存”抽象层,带来好处是访问内存一样去访问外设。

小结

Linux中的内核硬件层设计、MMU、CPU与IO外设通信设计处处体现了分层/中间层的设计思想。

TCP/IP网络协议堆栈

从最底层的物理链路层层层向上封装抽象,解决了复杂的网络通信的问题。同样的,任何复杂的问题,通过分层最终总能够回归最本质、最简单。这个分层架构,对所有开发者而言,再熟悉不过,它的引入是想与后续介绍的 Netty 形成对比。这里先卖个关子,后面解开谜底。

举例说明:

来自杭州西湖区某个小区的商务人士来京出差后,被确诊新冠肺炎,实施在京隔离措施,同时北京将此报告先发给浙江省,接着浙江省发给杭州市政府,然后市政府再向西湖区发送,最后到达某小区。这个发送报告过程也是分层报告思想。

DNS 中间层

DNS(domain name system)是域名系统,是用来将主机转换为IP地址的服务。我们有至少三种方式在互联网上标识一台主机、主机名、IP地址以及MAC地址。为什么有引入DNS中间抽象层呢? 主要是主机名便于记忆,而IP地址方便于在计算机网络设备的处理,因此需要设计出一个DNS协议(中间层)来做主机名到IP地址的转换。

ARP中间层

ARP(address resolution protocol)是地址解析协议,它根据IP地址来获取物理地址。上面也谈到,MAC与IP都可以用来标识一台主机。那二者区别是什么?

同一个局域网中的一台主机和另一台主机通信的时候,需要通过 MAC 地址进行定位,之后才能进行数据包的传送。

而在网络层和传输层中,主机之间是通过IP地址来定位的,对应的数据包中必须携带目标主机的IP地址, 而没有MAC地址。

因此,ARP协议(中间层)用来实现从IP到MAC地址的转换。

Netty

Netty提供了异步的,基于事件驱动的网络应用程序框架。目前分布式搜索引擎,Spark框架底层是扩展使用Netty框架。Netty本身的架构理解有些曲线,为了讲清楚,我还是希望循序渐进方式,通过它的发展历史来一步步介绍。先铺垫再介绍,大家需要一些耐心。

传统阻塞IO服务模型

思路:

  • 采用阻塞IO模式获取输入数据

  • 每个连接都需要独立的线程完成数据的输入,业务的处理和数据返回

问题:

  • 当并发数很大时,就会创建大量的线程,占用了很大的系统资源。

  • 连接创建后,如果当前线程没有数据可读,这个线程会阻塞在read方法上,造成资源浪费。

单Reactor单线程

思路:

  • 通过引入selector事件选择器来监听多路连接的请求。

  • Reactor对象通过selector监控客户端请求事件后,通过Dispatch进行分发。

  • 如果建立连接请求事件,则由 Acceptor负责建立一个连接,然后创建一个Handler对象处理连接完成后的业务处理。

问题:

  • 模型简单,没有多线程,资源竞争的问题。所以工作在一个线程完成。

  • 性能问题,一个线程,无法发挥多核CPU的性能。

  • 可靠性问题,线程crash,会导致整个系统不可用。

主从Reactor多线程

主React处理所有socket连接事件的监听和响应,而从React处理所有socket的读写事件的监听与响应。主从React都在多线程中运行。

Netty模型

Netty主要基于主从Reactor多线程模型发展出来的。

Netty逻辑架构

前面Netty的发展阶段都是铺垫,Nettty逻辑架构为典型网络分层架构设计,从下到上分别为网络通信层、事件调度层、服务编排层。

网络通信层:它执行网络I/O操作,核心组件包含BootStrap、ServerBootStrap、Channel。——Channel通道,提供了基础的API用于操作网络IO,比如bind、connect、read、write、flush等等。它以JDK NIO Channel为基础,提供了更高层次的抽象,同时屏蔽了底层Socket的复杂性。Channel有多种状态,比如连接建立、数据读写、连接断开。随着状态的变化,Channel处于不同的生命周期,背后绑定相应的事件回调函数。

事件调度层:它的核心组件包含 EventLoopGroup、EventLoop。——EventLoop本质是一个线程池,主要负责接收Socket I/O请求,并分配事件循环器来处理连接生命周期中所发生的各种事件。

服务编排层:它的职责实现网络事件的动态编排和有序传播——ChannelPipeline 基于责任链模式,方便业务逻辑的拦截和扩展;本质上它是一个双向链表将不同的 ChannelHandler链接在一块,当I/O读写事件发生时,会依次调用 ChannelHandler对Channel(Socket) 读取的数据进行处理。

ChannelPipeline私有协议栈vs.TCP/IP协议栈

前面铺垫这么久,就是为了自然过渡到上面的图,请务必与TCP/IP协议栈进行对比。

socket。read经过TCP/IP协议栈后,进入netty的网络通信层,事件调度层,最后来到服务编排层。而服务编排层的channelPipeline的设计也是一个upstream/downstream的stack,一进一出的二个pipeline。负责处理流入/流出的数据包。

上面的stack就非常类似TCP/IP协议栈。根据公司组织的需要可以定制分层的私有协议栈,比如从authentication-handler、message-validation-handler、message-encode-handler、message-decoder-handler。

微服务分层

grpc-gateway——它是一个开源框架,读取protobuf接口定义并生成一个反向代理服务器,此服务器一步将 restful http API转换成grpc服务.

middleware——实现鉴权功能, 比如哪些URL需要权限检验

handler通用处理层——参数检验: handler层负责执行与客户端约定参数的检验, 检验通过后再组装成后端服务需要的数据结构发往后端;接口聚合/组合服务: handler层可以根据业务需要, 调用多个后端服务的endpoint 来组合实现一个新的接口,同时将下层返回的数据进行聚合处理.

service/model业务逻辑层——对业务逻辑的封装, 负责将多个DAO数据结构转换和封装成一个有逻辑意义的模型;可以引入缓存策略,优化数据存取效率.

DAO层——数据访问层,主要负责操作DB中某张表并映射到内存中某个DAO 模型;与数据表结构一一对应,通过DAO内存模型向上层传递数据源的对象.

数据访问层DAL——对底层的数据源做统一的抽象, 屏蔽数据库.如果没有DAL的存在,那么几乎所有的业务逻辑层都会去与具体的数据库存储强挷定.耦合性就很高.

还有一个补充点:

业务逻辑层中的服务在实际场景中不可避免的会出现互相调用的场景,这种情况往往需要将耦合/公共的功能进行下沉,比如数据请求下沉为数据访问层服务,而业务下沉为稳定的通用业务服务,被其它服务稳定依赖。

Rails On Rack

熟悉Ruby On Rails Web应用框架的开发者,肯定知道Rack是如何成为应用容器(webserver)和应用框架之间的桥梁的。

Rack在webserver和应用框架之间提供了一套最小的API接口,如果webserver都遵循Rack提供的这套规则,那么所有的框架都能通过协议任意地改变底层使用webserver。

Rack分层设计非常类似Decorate Pattern或者Chain of Responsibility Pattern。

总结

本文作者结合自身工作经验, 总结一些典型分层设计案例

  • 计算机语言的发展

  • Linux内核设计(内核功能层与内核硬件层,MMU抽象层,CPU与外设的通信)

  • TCP/IP网络协议堆栈(DNS和ARP协议)

  • Netty框架发展以及分层私有协议栈分析

  • 微服务分层

  • 应用框架 Rails On Rack

这些案例充分说明了计算机系统本身就是通过一层一层抽象构造出来的。

  • 硬件方面是从一个个小的晶体管,抽象成一个个门电路,再到CPU器件,最后抽象组成计算机。

  • 软件设计也是一个层次一个层次功能完善叠加的,无论是自顶向下还是自底向上。


本篇作者

杨敏

FreeWheel 首席工程师

负责 SFX 团队的整体工作。目前从事服务化框架、容器化平台相关。关注与感兴趣的技术主要有 Python/Java 虚拟机、Golang、K8s、分布式数据库、分布式搜索引擎 ElasticSearch。

听说,点完下面4个按钮

就不会碰到bug了!


http://chatgpt.dhexx.cn/article/tmC15Nu0.shtml

相关文章

freewheel面试java经验

freewheel 一面 自我介绍介绍下对freewheel的认识项目介绍,项目的流量大小,QPS,每天处理多少数据的流量sql题,1 查询表中1-5,2020-08-26 00:00:00的rate(汇率);2 根据rate表&#x…

迈向云原生:名企FreeWheel应用架构演进

FreeWheel是美国传媒巨头康卡斯特(Comcast)集团旗下的高端视频广告技术供应商,90%以上的美国主流电视媒体和运营商都在使用FreeWheel的广告平台和技术。本文将带你了解名企FreeWheel核心业务系统研发团队将单体应用改造成云原生微服务应用的演…

2022年4月16日freewheel机试题

具体题目名字记不太清了,大概如下 第一题 给搜索二叉树的前序遍历结果,重构搜索二叉树,返回根结点。 思路:递归维护两个值,一个是可插入的最大值和可插入的最小值。 1、当前插入的值满足小于可插入的最大值和大于可插…

访FreeWheel总架构师邓就庆:架构与成长之道

特约记者:卢亿雷,精硕科技(AdMaster)技术副总裁兼总架构师,CCF(中国计算学会)大数据专委委员,北京航空航天大学特聘教授。 受访嘉宾:邓就庆(Jack),FreeWheel高…

迈向云原生:名企FreeWheel应用架构演进 | 文末粉丝福利

点击“博文视点Broadview”,获取更多书讯 FreeWheel是美国传媒巨头康卡斯特(Comcast)集团旗下的高端视频广告技术供应商,90%以上的美国主流电视媒体和运营商都在使用FreeWheel的广告平台和技术。本文将带你了解名企FreeWheel核心业…

FreeWheel容力:着眼行业 我们走在视频广告变革的浪尖上

随着大数据、人工智能时代的到来,越来越多的传统企业面临着转型的压力。FreeWheel作为提供高端互联网视频广告投放、监测、预测、增值等关键解决方案的外企,有着很多国际化大数据方案落地的经验。CSDN记者有幸与FreeWheel公司高级副总裁容力,…

FreeWheel是一家怎样的公司?

在知乎上有一个帖子,题目就是“FreeWheel是一家怎么样的公司?”这个帖子获得了85,860的阅读量以及数百条赞同和评论,可以说在“公司怎样系列”的外企中应该是名列前茅了。而在老孙所知晓的众多外企中,FreeWheel应该算是一家蛮特别…

如何把Windows 7英文系统转换为中文系统

如何把Windows 7英文系统转换为中文系统 Windows 7 Ultimate版才有多语言(MUI)支持,但是并非一定要MUI版本才能安装新语言。Windows 7虽然没有MUI的支持,但使用Vistalizator工具可以巧妙避开这一功能,直接将语言包植入操作系统,同…

win7 professional 英文版 改 中文

转载自:http://blog.sina.com.cn/s/blog_6f108d3e0100pl1k.html Windows 7 语言包微软 Windows Update 官方服务器下载For Windows 7 32位:简体:http://download.windowsupdate.com/msdownload/update/software/updt/2009/08/windows6.1-kb972813-x86-zh…

此语言无法安装在此计算机上win7,win7系统无法安装英文语言包解决方法

有用户由于学习或工作需要,需要给win7旗舰版系统安装英文语言包,但是下载了windows6.1-kb2483139-x64-en-us_9b9c8a867baff2920507fbf1e1b4a158572b9b87.exe后点击安装,提示安装失败,尝试在安全模式下安装也失败了。使用lp.cab 以…

wifidog接口文档

wifidog是搭建无线热点认证系统的解决方案之一,他比nocat更适合互联网营销思路。目前支持openwrt系统,他实现了路由器和认证服务器的数据交互,在路由器方是用C语言代码,通过wifidog程序和linux iptables防火墙实现接入用户的认证跳…

公共场所wifi认证解决方案wifidog+authpuppy

服务器:linux mint 17.3 authpuppy 路由器:DB120 wifidog 手机一部 一、在OpenWrt的路由器上安装Wifidog应用程序 安装Wifidog程序有两种方式,一种是在刷了OpenWrt的路由器上直接安装Wifidog;或者是把Wifidog直接编译进OpenW…

wifidog 配置文件

下面回到路由器,编辑wifidog.conf,一般情况下,我们之后配置ExternalInterface,GatewayInterface和AuthServer这三项就可以,其他默认。下面是我的配置: opk安装包:luci-app-wifidog-all.ipk 链…

Portal Server搭建(wifidog安装)

可以参考这篇文档: http://dev.wifidog.org/wiki/doc/install/ubuntu/auth-server#Configurelocaleinwifidog.conf 一、 安装前准备 打开终端(用普通用户进入终端,不要用超级用户)。 sudo apt-get update sudo apt-get instal…

wifidog+authpuppy搭建WiFi 接入设备认证测试平台

0:前提 其实搭建认证环境都是基础,重要的是要对WiFidog的代码进行详细的研究,了解清楚wifidog与authpuppy之间进行了哪些数据交互,WiFidog的程序框架及iptables的建立及生效规则,这才是重点。WiFidog和之前nodogsplas…

wifidog authpuppy 服务器搭建

安装环境(64位 Ubuntu 14.04.4 LTS \n \l )一、安装各种软件包1、apache和php sudo apt-get updatesudo apt-get install apache2 php5 复制代码 2、安装数据库(postgresql或者mysql) sudo apt-get install postgresql 复制代码 3、安装需要的库 sudo ap…

wifidog认证流程图

一. 用户上线 1. 用户访问网络,通过iptables将未认证的用户dnat到wifidog进程,wifidog通过307报文将用户重定向到认证服务器 2. 用户打开认证服务器登录页面,输入用户名密码,发送认证请求 3. 认证成功的话服务器会发送302报文&…

wifidog+authpuppy认证页面的配置

路由器上用的是wifidog client,服务器后端管理用的是authpuppy。 首先,选择自己的操作系统,在http://www.authpuppy.org/doc/Main_Page网站里面,我的操作系统是Linux。 然后到这个网站http://www.authpuppy.org/doc/Getting_Star…

openwrt-看门狗watchdog

一、硬件watchdog和软件watchdog Linux内核不仅为各种不同类型的watchdog硬件电路提供了驱动,还提供了一个基于定时器的纯软件watchdog驱动,软件watchdog基于内核的定时器实现,当内核或中断出现异常时,软件watchdog是无法复位系统…

wifidog认证流程(图文版)

学习使用wifidog一段时间了,觉得这玩意真的不错,虽然有些代码写的不够严谨,运行效率不够高,但是少量人数情况下实现portal是很好的方案。 下面是我摘自一个博客的内容和apfree写的文档中的一部分发上来的,希望能对研究…