# 1. 自我介绍
大概可以使用这样一个模板来介绍:
大家好,我是XXX,一个有着丰富的互联网金融、支付行业开发经验的Java软件工程师。
我热爱编程,并对多线程、JVM、Dubbo、SpringBoot、Redis、Mybatis、MQ等主流技术中间件及其实现原理有着深入的了解和熟练的应用。
在项目中,我具有较强的分析和解决问题能力,逻辑思维和表达能力,良好的沟通和团队协作能力。
我热衷于参与和贡献开源社区,并在Github上开放了自己的仓库和个人博客。
我认为代码是艺术,每一行代码都应该经过精心设计和优化,以实现高效、可靠和易维护的软件系统。
我很荣幸能够有机会为贵公司提供我的技能和经验,并在这里与志同道合的人共同成长和进步。
# 2. 介绍最有价值的项目
介绍自己的最有价值项目,需要从以下几个方面入手:
- 项目的背景和目的:简要介绍项目是为什么而做,目的是什么,解决了哪些问题。
- 项目的技术难点和创新点:详细介绍项目在技术实现上所面临的难点和挑战,以及如何解决这些难点。同时,也介绍项目中的创新点和优势,如何在竞争中脱颖而出。
- 项目的业务价值和实际效果:阐述项目对业务的重要性和影响,以及实现后所带来的实际效果,如提高了生产效率,降低了成本,提高了用户满意度等。
- 个人贡献和团队协作:介绍在项目中所担任的角色和职责,并突出个人在项目中的贡献。同时,也需要强调项目的团队协作和沟通,展示自己良好的团队合作和沟通能力。
- 项目的发展和未来计划:最后,可以介绍项目的发展和未来计划,以及自己在未来工作中如何运用这些经验和技能。
总之,介绍自己的最有价值项目,需要结合实际情况,突出项目的重要性和实际效果,同时突出自己在其中的贡献和团队合作能力。
# 3. 介绍业务模式
根据所选项目、对方所提问的内容。
# 4. 架构方式
讲解自己项目中架构设计过程:比如对账清结算系统,可以从哪些方面进行架构设计
数据采集
- 消息队列,异步采集上游系统数据。
- 同一清洗到对账系统中
数据处理
- Hadoop、Spark等分布式计算框架对数据处理,将数据进行归一、校验、比对处理,结果回传到对账系统。
历史对账数据存储和处理
- MySQL、MongoDB等存储方案
- 根据数据特点选择不同的存储方案、存储结构。
对账算法和流程
- 差异数据处理
- 数据匹配
- 多账、少账、差错处理,各类调账机制
报表生成和展示
- 数据存储量、方便后续进行查询、分析。
异常告警
- 日志记录、告警通知方式对结果进行处理
- 根据优先级进行短信、邮件等方式通知
性能和扩展性
- 分布式架构、模块拆分,负载均衡提高并发性和性能
- 分库分表进行水平扩展。
安全性和准实时性
# 1.操作系统:进程和线程
# 1.1 两者区别介绍
典型回答:
- 进程:操作系统资源分配的基本单位,拥有独立的地址空间,是一个执行程序,一个进程崩溃后在保护模式下不会对另外进程产生影响。
- 线程:CPU调度和分配的基本单位,是进程内的控制流,线程是进程中不同的执行路径。
- 一个进程可拥有多个线程。
延伸回答:
对于上述问题中的关键字进行延伸回答,包括以下方面:
- OS资源分配的基本单位,可以介绍PCB (process control block)进程控制块的数据结构。
- 进程保护模式是什么?防止不同进程之间内存空间不被其他进程所读取,依赖于硬件级别实现,如CPU特权、段式内存管理等。
- CPU如何调度,调度策略有哪些,各自区别是什么
- 进程状态有哪些,是如何通过跃迁的。
- 作为OS资源分配的基本单位,那么其中包含哪些资源呢?
以下是我总结的内容:
进程(Process) 和 线程(Thread)是OS中执行多任务的概念,区别主要如下:
- 资源分配:进程是OS资源分配的基本单位,线程是CPU调度的基本单位。进程拥有独立的内存空间、文件句柄、打开的网络连接等资源。线程则是共享进程的资源。
- 调度:进程调度是CPU重要功能之一,进程与进程之前切换需要涉及大量开销,而线程切换则比进程切换快很多,因为线程是共享进程地址空间的。
- 并发性:多个进程之间相互独立,因此它们可以并发执行。而线程共享进程地址空间,因此它们之间也是并发的。多个线程共享进程的资源从而提高程序效率。
- 通信方式:进程之间通信代价较大,需要使用OS提供的IPC机制。而线程之间通信则是直接写、读进程内的同一共享变量,代价较小。
- 总的来说线程、进程都是实现多任务处理的方式,进程是资源分配的基本单位、线程是调度的基本单位,线程比进程拥有更加小的开销、更高的执行效率,但是进程更加独立,相互之间隔离性更好。在实际应用中根据不同场景和需求进行选择。
# 1.2 进程数据结构PCB模型
这块需要从CPU工作模式出发,进程作为最小资源分配单位,这里面的资源包括哪些内容?程序代码段、寄存器、程序计数器、进程堆栈等内容之间的配合。
解释进程的数据结构,这个数据结构称之为进程控制模块PCB(Process Control Block):这里面包含了进程各项资源:进程标志符、优先级、程序计数器、寄存器值、堆栈指针、内存使用情况、文件句柄、网络连接等已分配资源。当进程被调度时CPU通过访问PCB来获取进程的状态、上下文信息,以便与切换、恢复进程的执行。
- 进程标志符:描述该进程的唯一标志
- 进程状态:记录当前进程状态,包括:新建、运行、就绪、等待、终止等。
- 程序计数器:记录当前进程正在执行的指令地址
- 寄存器值:记录当前进程正在处理寄存器中的值
- 堆栈指针:记录当前进程使用的堆栈地址
- 内存使用情况:记录当前进程使用的内存区域及其大小
- 文件描述符:记录当前进程使用的文件句柄情况,已打开文件及其相关信息
- 进程优先级:记录进程调度优先级
- 已分配资源:记录当前进程已经获得的系统资源,IO资源、网络资源、内存、外设等信息
通过PCB,OS可以管理、调度多个进程,并且为其提供系统服务、保护机制。
从以上内容还可以进行扩展延伸,比如后续进程状态及其跃迁流程,进程优先级调度算法、进程通信等内容。
# 1.3 进程状态及如何跃迁的
进程状态极其跃迁过程,主要是记住这张图即可。
- 创建状态 New:进程正在创建,还没有被操作系统完全初始化。
- 就绪状态Ready:进程已经准备就绪,正在等待CPU进行调度分配时间片。
- 运行状态Running:CPU正在处理执行进程中代码块。
- 阻塞等待状态Waiting/Blocking:进程由于某些原因无法继续执行,等待某些时间发生,而被挂起,例如IO操作
- 终止状态Terminated:进程已经执行完毕或者终止,等待被操作系统资源回收。
主要是这几种状态代表的含义,以及状态之间扭转原因和时机:
- 就绪 ->运行:操作系统分配时间片给进程,进程从就绪状态转为运行状态 ,Scheduler Dispatch = 调度器调度,其中存在各类调度算法,也可以发散说明。
- 运行->就绪:进程执行完当前时间分片后,仍然有任务未完成;或当前进程执行时被中。等待CPU分配下一个时间片。interrupt /timeout 中断或超时
- 运行->阻塞:运行期间遇到某些需要等待的事件,这些事件通常耗时较长,例如IO事件,操作系统将进程状态转为阻塞状态,等待IO事件发生。IO or envent wait
- 阻塞->就绪:阻塞进程所等待的事件已发生,操作系统将进程状态转为就绪,等待CPU调度分配执行时间片。IO Completion or event occurs.
- 运行->终止:进程执行完所有任务,或者被操作系统终止,将进程状态转为终止,等待被回收。
通常对于该问题,说出五种进程状态,及其状态跃迁扭转发生时机即可。
# 1.4 进程调度策略
这部分看过或者说背过有个大致印象即可,主要是短作业优先级、先来先服务、时间轮片和多级反馈这几种吧,主流的CPU调度策略,当然不同型号可能存在其余的调度策略,这块儿可以作为知识叶子逐个发散补充。
根据上面进程状态的跃迁过程,进程的调度策略主要发生在对于多个就绪状态的进程,如何决定哪个进程优先执行的规则与算法。
- 先来先服务FCFS:按照进程请求CPU的顺序,是一种非抢占式调度策略
- 短作业优先SJF:按照估计运行时间最短进程优先进行调度,是一种非抢占式调度策略。但是通常情况下需要预估进程作业的时间长度,这是一个非常困难的事情。
- 优先级策略:按照优先级高的进程优先调用策略,可能导致优先级低的进程一直饥饿状态。是一种抢占式调度策略。
- 时间片轮转策略:为每个进程分配一个时间片,按照时间片轮流调度。是一种抢占式调度策略
- 多级反馈队列调度:将进程分为若干个队列,每个队列分配不同时间片,根据进程运行情况在不同队列中切换。是一种抢占式调度策略。
不同调度策略适用于不同场景和应用,根据实际情况选择。
通常情况下是要求知道调度策略种类,以及各自执行方式。如果深挖可以说说各类调度策略算法实现。
# 1.5 进程之间如何通信
进程之间通信方式主要有以下方式:
- 管道Pipe:半双工通信方式,一端写入、另一端读取。需要注意的是管道只能在具有亲缘关系的进程之间使用。
- 命名管道Named Pipe:允许不同进程之间通信,这些进程是彼此之间无关的进程。命名管道在文件系统中有一个路径名,各自线程可以打开路径名来建立管道。可以理解为Docker中不同Continer通过挂载volumes来实现相互资源共享。
- 信号Signal:异步通讯方式,通知进程已经发生的事情。比如当进程试图访问一个非法内存地址时,操作系统会向该进程发送一个sigsegv(读:西格塞夫)信号。
- 共享内存Shared Memory:共享内存允许多个进程访问同一物理内存,避免数据复制。不过对共享内存的访问需要进行同步,否则会出现竞争。
- 消息队列Message Queue:消息队列是一种消息传递机制,允许进城通过在队列中放置消息来实现进程之间通信
- 套接字Socket:套接字socket是网络通讯机制,允许在不同主机PC之间的不同进程之间通信。通常用于客户端-服务器之间通信。
总共有以上几种通信方式,通常情况下根据实际使用场景进行确认。
# 1.6 进程切换为何比线程切换慢
这个问题还是围绕着进程和线程区别来说,进程切换时所拥有的各类系统资源需要进行切换。
- 切换内存映射、IO、文件句柄、网络的各类系统资源。由于进程是系统资源分配最小单元,这些切换时有需要操作系统复杂管理处理。
- 内核态、用户态之间切换。
- 由于每个进程拥有自己的虚拟内存空间,页表、缓存等信息。寄存器、程序计数器等方面进行切换。
线程是在进程内执行的,因此线程执行只需要在进程内(用户空间、用户态)完成即可。并不需要操作系统内核接入。
主要还是围绕区别来说。
# 2. 计算机网络:TCP/IP
# 2.1 TCP/IP五层模型
这个需要背一下五层模型,及其各自角色作用。
- 应用层 Application :提供应用程序与网络之间的接口
- 传输层 Transaction:提供端到端之间连接通信,TCP和UDP。记住四元组模型就行了 IP+Port <=>IP+Port。
- 网络层 Internet:提供数据包的路由与转发。IP协议
- 数据链路层 Link:将数据包转化为帧进行传输,提供物理寻址和链路管理,以太网协议。
- 物理层Physcial:实际媒介传输,光纤、网线等。
# 2.2 如果需要解析IP和端口,需要在哪一层进行
记住了上面TCP/IP五层模型,那么就知道IP是在网络层获取解析,端口号在传输层中获取解析。
IP:用于标志网络中唯一的主机。
端口:标志主机上不同的进程。
通过四元组去理解这个通信方式。IP+Port <=>IP+Port。
# 2.3 传输层常用协议
同样从TCP/IP五层模型出发,传输层有TCP、UDP两种传输协议。
- TCP:Transmission Control Protocol传输控制协议
- UDP:User Datagram Protocol 用户数据报协议
TCP:
- 面向连接、可靠的传输协议。
- 此处两个特点可以说:连接、可靠,可以通过下图2.4说明。
- 提供数据传输流控制、拥塞控制、错误恢复。保证数据的完整性、有序性、可靠性。
- 基于这个特点,适用于数据传输需要可靠的应用层协议:HTTP、FTP
UDP
无连接、不可靠的传输协议
不提供流控制、拥塞控制机制。
负责将应用层数据打包成数据包发送给网络。
适用于实时性要求较高的应用。
- 音视频、流媒体传输。
上述提供了一些保证传输完整性、有序性、可靠性的内容,在于TCP中均有相应机制进行处理:
- 确认和重传:TCP确认机制保证数据的完整性和可靠性。发送数据后,需要等待接收方进行确认消息,如果接收方未进行及时确认,发送方会进行重传。
- 滑动窗口:TCP使用滑动窗口机制确保数据有序性。
- 接收方通过确认消息来告诉发送方已接收到的数据。
- 发送方通过接收方的反馈来调整滑动窗口大小、已达到合理流量控制和拥塞控制。
- 校验和:TCP在传输过程中会对数据进行校验和计算,监测传输过程中是否发生了变化。
- 超时重传:TCP通过重传机制确保数据的可靠性。若接收方未及时进行确认数据,发送方会认为数据丢失,进行重传。
- 流量控制:TCP通过流量控制来保证发送方发送的数据量不会超过接收方的处理能力,避免网络拥塞。
- 通过滑动窗口大小来控制发送数据量
通过以上机制确保数据可靠传输,确保传输过程中不会出现丢失、损坏、重复或者乱序等问题。
# 2.4 解释一下TCP协议
根据此图配合三次握手、建立连接、数据传输等方面进行回答。
# 2.5 TCP和UDP区别
可以从TCP和UDP特点上来说,包括稳定性、可靠性、连接、数据量、使用场景的各方面。
- 连接:TCP面向连接,UDP无连接。
- TCP建立连接、传输数据、释放连接均需要通过三次握手。
- UDP不需要进行连接。
- 可靠性:TCP提供可靠的传输服务,UDP传输不可靠存在丢包、乱序。
- TCP通过确认重传、滑动窗口、校验和、超时重传等机制保证数据完整、有序。
- UDP无需这些操作,直接将应用层数据打包发送给网络。
- 数据量:TCP没有数据包大小限制,UDP存在数据包大小限制。
- UDP通常为64K
- 应用场景:根据特性TCP适用于稳定性要求较高场景、UDP适用于实时性较高场景。
- TCP:HTTP、FTP、SMTP等协议
- UDP:音视频、流媒体。
# 3. Java基础
# 3.1 解释String s1 = "1" 和 String s2 = new String("1")的区别。
这是一个非常经典的Java内存模型问题,主要考察常量池、对象创建时堆栈分配空间问题。
首先明白String在Java中是属于不可变 final对象,一旦创建即不可改变,虽然上述两种方式均可创建字符串,但是有着天壤区别。
String s1 = "1"
这个使用字面值方式创建字符串对象,"1"便是字面值。- 会判断该字面值是否属于常量池中,有则直接将s1地址引用,否则将该字面值放入常量池,再地址引用。
- 此时如果多个字符串对象指向同一个字符串字面值,实际上指向的是同一个对象
String s2 = new String("1")
这个则是使用new关键字和构造方法的方式创建字符串变量,那么就从对象创建的过程中分析均可。- 无论常量池中是否存相同的字符串,均会新创建对象
- 若多个字符串变量都通过new关键字创建,那么他们也是不同的对象
- 对象创建过程字节码层面主要有这三个指令,第一步就会发现即便是同一个字符串,通过new时均是新开辟堆内存空间进行地址引用的。
- new : 开辟堆内存空间
- invocespecial.init 调用构造函数初始化对象
- astore_1 建立地址引用
- 延伸:对象创建的字节码指令又可以延伸出指令重排、内存屏障等问题。
# 3.2 Object o = new Object() 时 o 所占字节数。
这部分需要了解对象的存储堆内存存储结构,包括以下部分:
- 对象头 Object Header
- 标记字段 Mark Word 固定8字节
- 类型指针 Klass Pointer 指针压缩4字节、关闭指针压缩8字节
- 默认情况下hotspot虚拟机开启了指针压缩,因此该处为4字节
- 实例数据 Instance Data 0字节
- 对齐填充 Paddng Data 4字节对齐
- 对齐填充是因为需要保证对象所占字节能够被8整除
如果对象实例中还存在其余基本数据类型,需要相应添加字节长度:
- byte: 1 字节
- short: 2 字节
- int: 4 字节
- long: 8 字节
- float: 4 字节
- double: 8 字节
- char: 2 字节
- boolean: 1 字节
JVM 默认启用了指针压缩技术,因为在 64 位的 CPU 架构下,使用 32 位的指针访问内存的地址,可以显著减少内存占用并提高 CPU 缓存效率,从而提高性能.
因此:
- 标记字段固定8字节 + 类型指针4字节 + 对齐填充4字节 = 16字节
- 一个对象默认情况下占据12(8+4)字节,添加填充4字节 = 16字节
注意:如果关闭了指针压缩,仍然是16字节。 因为类型指针变为8字节,可被8整除,对齐填充则不进行对齐。
延伸:
1.8或更高版本JVM默认开启指针压缩,如需关闭可以采用java -XX:-UseCompressedOops
方式。
# 3.3 Java中同步机制有哪些
这个问题主要从两个方面回答:Synchronized关键字 和 Lock锁机制。
首先需要解释什么是同步?什么是锁?可以理解为同一时刻只有一个线程可以访问被同步的代码块,锁住的不是代码块,而是进行访问的线程。
然后Synchronized关键字可以从以下方面进行回答:
- Synchronized关键字修饰内容,包括代码块、修饰方法、类或者对象等情况。
- Synchronized是如何控制线程访问,需要从对象的监视锁Monitor回答,该部分需要了解对象头信息Mark Word中的内容进行回答,跟上述问题Object o = new Object中o占据几个字节问题一致。
- Lock锁的种类及其使用场景。
- Synchronized和Lock锁的区别
下面就说说两种方式如何保证同步的。
- Synchronized修饰方法,获取该方法所属对象的监视锁Monitor。也就是在对象头中写入当前线程的线程ID。
- 若该方法未被其他线程抢占,获取成功,进入修饰方法内部,执行完毕,释放锁,监视锁清空。
- 若该方法已被其他线程占用,当前线程阻塞状态,直到锁释放。知道该对象Monitor监视锁清空。
- Lock锁提供了更加细粒度的锁机制,使用时需要手动加锁、解锁。编码时需要进行try-catch-finally处理,一定不能忘记unlock释放锁,否则带来死锁问题。
- Lock锁需要显示的加锁、解锁,更加灵活可控的锁机制,避免了Synchronized的一些问题:死锁(锁住不同对象了)、效率低下。
- 从Lock锁种类来回答。
- 可重入锁ReentrantLock
- 读写锁ReadWriteLock
- 可重入读写锁ReentrantReadWriteLock:多线程同时读,一个线程写
- StampedLock:乐观锁机制,读时不加锁,写时通过CAS判断是否被修改了
- Condition:条件锁,与Synchronized中的notify、wait相似(Monitor监视锁类似),用于多线程之间通信。
- 从Lock锁种类来回答。
- Lock锁需要显示的加锁、解锁,更加灵活可控的锁机制,避免了Synchronized的一些问题:死锁(锁住不同对象了)、效率低下。
# 3.4 Synchronized 如何进行锁处理呢
这个问题需要回答对象的JMM模型,也就是常说的对象头 Object header结构。其中有一个mark word项,其中就包含了对象的锁信息。
这里可以看到对象头中记录着锁类型:偏向锁、轻量级锁、重量级锁、无锁状态等信息。
这边是Monitor监视锁信息。
可以理解为线程访问synchronized修饰的同步代码块时,线程会获取该方法所属对象的锁,也就是在对象头中写下该线程ID,表示该线程已拥有该对象访问权限。
Synchronized的锁处理是通过内部对象监视器(Monitor)实现的。
每个Java对象都可以关联一个Monitor对象,当这个对象被用作锁时,就相当于以这个对象的Monitor对象为同步器。
在代码块或方法被Synchronized修饰时,程序会尝试获取相应对象的Monitor对象的锁,如果获取失败,则该线程会进入阻塞状态,直到锁被释放为止。
# 4. MySQL
# 4.1 select id ,name ,age from t_xxx where name = "xxx";如何进行索引优化。
当数据量较大时,name作为where条件时,必须要进行索引优化,以便提升整体查询效率。
- 创建name列索引
- 避免对name列,或者索引列进行函数操作。
- 尽量使用覆盖索引:指索引包含了所需要查询的所有列,不需要回表操作,用于提高性能
- 创建联合索引
CREATE INDEX idx_name_age_id ON t_xxx (name, age, id);
- 查询语句使其覆盖索引中所有列。
- 避免使用or连接条件,如果使用索引优化查询。
- 可以使用union 或 union all 连接多个查询结果
# 4.2 以上SQL在索引执行时过程是怎样的
按照索引在B+树上执行流程来回答
- 从根节点开始,按照B+树的分裂策略逐层查找,直到查询到包含查询条件的叶子节点,此处的name字段。
- 从叶子节点上进行行查找,找到满足查询条件的行记录,此处的name= 'xxx'
- 如果查询条件中包含多个列,且B+树索引中不止一个索引列,则按照B+树索引中各个索引顺序查找。
- 如果查询条件中存在范围查找 beteewn 、>、<等。在B+树中进行范围查找,从满足条件的叶子节点开始,按照分裂策略向右遍历叶子节点,直到不满足条件。
- 在B+树中数据存储在叶子节点上,非叶子节点只存储索引,因此进行范围查找只需要遍历叶子节点即可,并非遍历整个B+树,查询效率较高。
- 同时,由于B+树的节点按照索引值有序存储,因此在进行范围查找时,利用叶子节点之间的顺序关系,减少不必要的IO磁盘,提高查询效率。
顺便可以说一下分裂策略:
- 立刻分裂:节点已满时,立即进行分裂
- 节点为叶子节点
- 数据按照一定规则分配到两个新的叶子节点
- 节点为非叶子节点
- 节点中的索引按照一定规则分配到两个新的节点
- 延迟分裂:节点已满时,不立即进行分裂
- 当一个节点已满时,并不会立即进行分裂,而是将该节点中的数据项或索引插入到新的节点中。当该节点再次被插满时再进行分裂。
区别:延迟分裂减少了分裂次数,降低了平均分裂代价,提高了查询性能。某些情况下会增加树的深度,降低树的性能。
上述的某些情况是指右节点数据也满了,只能够通过新加节点来容纳数据,就需要将前节点数据平均分配到两个新的节点上,然后将新节点插入到父节点中,涉及到多节点的变化,因此会增加树的深度。
# 5. 开放题
# 5.1 平时有什么好的编码习惯
可以通过提升代码的健壮性、稳定性、可读性、可扩展等方面回答:
- 命名规范:方法名、变量名、接口名采用小驼峰、见名知意,准确、能够清晰表达含义。
- 注释:适当增加注释可以让代码增加可读性
- 缩进与格式化:采用统一的格式化方式:idea、checkstyle等,增加代码可读性。
- 遵循编码规范:团队统一的编码规范,降低代码维护成本。
- 模块化设计:将代码划分为相对独立的模块、减少耦合,提升代码的复用性和可维护性。
- 异常处理:避免出现不必要的异常,对于必要的异常,根据异常类型进行分别处理。
- 测试驱动开发:开发之前确定好测试用例边界,持续增加代码测试用例、增加代码单测覆盖率。
- 持续集成:持续集成可以自动编译、测试、部署,提高代码质量和可靠性。
- 代码审查:对于重要的代码,应当进行代码审查,避免出现潜在问题,同时也能纠正代码习惯。
- 不断学习:保持学习心态,关注最新的技术和编码规范,不断学习提升自己的编码规范。
# 5.2 介绍微服务和单体服务
可以从单体服务和微服务开发方式、部署方式、团队运营维护成本等方面回答。
单体应用:
- 传统的应用架构方式,所有的功能均在一个进程中执行。
- 单一的JAR、WAR可执行文件进行部署。
- 部署简单、易于管理和调试。
- 无法进行水平扩展、部署时间长、灵活性较低。
微服务:
- 将大型应用拆分为多个独立小型服务,每个服务均可从业务领域垂直划分。
- 每个服务独立开发、独立部署,易于扩展。
- 服务之间通过API进行通信。
- 快速部署、易于扩展、灵活性高、技术栈灵活
- 服务之间协调性、服务治理、测试、部署较为复杂。
- 分布式架构,可快速弹性伸缩部署,更好的适应于业务规模变化增长。
如何选择需要考虑多方原因:业务服务度、团队规模、部署环境、运维成本等各方面考虑。
还可以进行扩展延伸出来其他的各类服务架构:
- 单体服务架构:应用作为单一服务运行在同一个应用服务器中,包括所有功能模块。
- 分层架构:应用拆分为多层,数据访问层、业务逻辑层、用户表示层等。
- 微服务架构:应用拆分为小服务,服务独立运行,拥有各自对外接口、数据库,服务之间API通信。
- 事件驱动架构:所有事件均通过异步消息传递机制处理,各个组件通过事件通信。
- 服务化架构:SOA,应用即服务
全文完。
了解更多内容,可以关注我的微信公众号,更多首发文章。