面试题总结

进程通信IPC(Inter-ProcessCommunication)是进程之间互相交换信息的工作。进程的互斥、同步、通信是用来解决并发进程的资源竞争与协作的手段。通信包含同步,同步又包含互斥。

信号,管道,管道又分为匿名管道和命名管道,共享资源。AT&T在UNIXSystemV中又引入了三种通信方式分别是:消息队列、信号量和共享内存。统称为SystemVIPC。

管道分为匿名管道和命名管道。匿名管道只能用于父子进程通讯,命名管道也就是FIFO管道可以用于公共通信。

1>管道:速度慢,容量优先,只能用于父子进程通信。

2>FIFO:速度慢,任何进程都能通信。

3>消息队列:容量受系统限制,而且要注意第一次读的时候要考虑上一次没有读完数据的问题。

4>信号量:不能传递复杂消息,只能用来同步。

5>共享内存区:能够很容易控制容量,速度快,但要保持同步。

进程是程序在执行过程中分配和管理资源的基本单位。线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(程序计数器、一组寄存器和栈),它与进程的其他线程共享进程的资源。

进程和线程是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其他进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但是线程没有单独的地址空间。一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大。对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

进程的通信包含资源的通信和状态的同步。因为线程资源是共享的,所以线程的通信基本就是线程的同步。

锁机制:悲观锁、乐观锁

同步原语:如volatile、sychronized、final

等待唤醒机制:wait、notify

线程需要返回数据的可以用Callable、Future、FutureTask这些。

通过在读写操作前后添加内存屏障,达到两个效果:1是强制将修改的值写入主存,并将工作内存的值缓存失效,保证了不同线程对这个变量进行操作时的可见性。2是禁止指令重排。

根据JSR133规范

1>对于final变量的初始化重排查规则是:final关键字修饰的变量初始化的代码不能重排序到构造函数结束之后。

2>对final变量的读取重排序规则是:初次读对象引用与初次读该对象包含的final域,JMM禁止处理器重排序这两个操作。

其他方面,编译器有很大自由,能将对final字段的读操作移到同步屏障之外,也允许编译器将final字段的值保存到寄存器,在非final字段需要重新加载的那些地方,final字段无需重新加载。

进入管程时将同步块内使用到的变量从工作内存清除,退出管程时把共享变量刷新到主内存。

互斥量、读写锁、条件变量、自旋锁以及屏障

最常用的是5个:open、read、write、lseek和close。

悲观锁:获取数据时先加锁。如Synchronized关键字和基于AQS的锁。

乐观锁:基于无锁编程,常用的是CAS算法。如JUC的atomic包下的原子类。

阻塞:需要操作系统切换CPU状态。

非阻塞:不需要切换CPU状态。

自旋锁:底层也是通过CAS实现。

1>BIO是同步阻塞通信

服务器实现模式为一个连接一个线程:客户端有连接请求时服务器端就需要启动一个线程进行处理。如果这个连接不做任何事情会造成不必要的线程开销。

2>NIO是同步非阻塞通信

服务器实现模式为一个请求一个线程:客户端发送的连接请求都会注册到多路复用器上,多路复用器轮序到连接有IO请求时才启动一个线程进行处理。

3>AIO是异步非阻塞通信

服务器实现模式为一个有效请求一个线程,客户端的IO请求是由操作系统先完成,再通知服务器应用去创建线程进行处理。

XNS(XeroxNetworkSystems)协议、IPX(网际包交换)/SPX(排序包交换)协议、AppleTalk、SNA、TCP/IP

大体分为三部分

1>Internet协议(IP)

2>传输控制协议(TCP)和用户数据报文协议(UDP)

3>处于TCP和UDP之上的一组协议专门开发的应用程序。它们包括:TELNET、文件传送协议(FTP)、域名服务(DNS)和简单的邮件传送程序(SMTP)等许多协议。

1>数据传送

2>寻址

3>路由选择

4>数据报文的分段

URG紧急指示字段

ACK如果设置,该包包含确认

PSH推入功能

RST恢复链接

SYN用于建立序号(同步序号)

FIN数据不再从连接的发送点进入,结束总报文

1>流式套接字(如TCP)

2>数据报套接字(如UDP)

3>原始套接字

1>阻塞I/O

2>非阻塞I/O

进程不断调用recvfrom进行检查,如果程序数据区还没有数据则立即返回一个错误。直到recvfrom检查到数据正常返回。

3>I/O多路复用

I/O多路复用是先调用select函数或poll函数,当有数据时才调用recvfrom进行真正的读写。

4>信号驱动I/O(SIGIO)

使用信号让内核在文件描述符就绪的时候使用SIGIO信号来通知。

5>异步I/O我们如果想进行I/O操作,只需要告诉内核我们要进行I/O操作,然后内核会马上返回。具体的I/O和数据的拷贝全部由内核来完成,我们的程序可以继续向下执行。当内核完成所有的I/O操作和数据拷贝后,内核将通知我们的程序。异步I/O和信号驱动I/O的区别是:信号驱动I/O模式下,内核在操作可以被操作的时候通知给我们应用程序发送SIGIO消息。异步I/O模式下,内核在所有的操作都已经被内核操作结束之后才会通知我们的应用程序。

第一次握手:建立连接时,客户端发送SYN包到服务器,并进入syn_send状态。

第二次握手:服务器收到syn包,确认客户端的syn为收到的序号+1,同时自己也发送一个syn包,即发送(syn+ack)包,此时服务器进入syn_recv状态。

第三次握手:客户端收到服务器的syn+ack包,向服务器发送确认包ack,其中ack的值+1,此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

第一次挥手,客户端A发送一个FIN,用来关闭客户端到服务器的数据传送。

第二次挥手,服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号+1。

第三次挥手,服务器关闭与客户端的连接,发送一个FIN给客户端。

第四次挥手,客户端发回ACK报文确认,并将确认序号设置为收到序号+1。

根据JSR133规范,内存模型描述了一个给定程序和它的执行路径是否是一个合法的执行路径。

与这个相近的一个概念是JVM内存结构:

对象的实例(包括对象头、实例数据和填充数据)存储在堆,对象的元数据存储在方法区(元空间),对象的引用存储在栈。

数据结构我会用hashmap来保存对象的加减计数,要避免循环引用,需要添加辅助的工具比如基于引用遍历的垃圾回收器来清理它们。

1>虚拟机栈中的局部变量表中引用的对象

2>方法区中类静态属性引用的对象

3>方法区中常量引用的对象

4>本地方法栈中JNI引用的对象

5>由系统类加载器加载的类

6>存活的线程

7>用作同步监控的对象

8>被JVM持有的对象比如重要的异常处理类

在java9中,finalizers的替代者是cleaners

AQS抽象队列同步器本身是基于CLH队列的,通过自旋锁来进行资源的获取和释放,它本身就是一种锁实现。所以避免加锁可能是一个伪命题。但是有些常用的减少锁竞争的优化方式:比如在ConcurrentHashMap中使用锁分段技术来减小锁粒度,读写锁代替独占锁。

-server编译速度慢,启动后性能更高

-XX:CompileThreshold默认1w次

-XX:MaxFreqInlineSize=N

-XX:MaxInlineSize=N

1>针对特定CPU型号的编译优化

2>热点数据减少查表次数

3>逃逸分析,直接栈上分配内存

4>寄存器分配

6>热点代码缓存

7>方法内联

Java运行时内存的各个区域,对于程序计算器、虚拟机栈、本地方法栈这三个部分而言,生命周期随线程而生、随线程而灭。线程结束时内存就回收了。

而方法区和堆区需要使用对象是否存活的算法来判断是否可以回收。

常用的判断是否可回收算法有:引用计数器、可达性分析算法。

引用计数器算法采用引用加减的方法,优点是速度快,基本不需要STW,缺点是循环引用对象无法回收。可达性分析算法是从GCROOT开始向下搜索,当一个对象没有和任何一个GCROOT相连时,证明对象不可达。

对象的回收还和引用强弱有关,按照引用强弱又可分为强引用、软引用、弱引用、虚引用。

目前一般垃圾收集器中采用的是可达性分析算法来标记引用。

垃圾回收算法主要有标记-清除、复制算法、标记-整理算法、分代收集算法。

1>该类所有的实例都已经被回收,也就是Java堆中不存在该类的实例。

2>加载该类的类加载器已经被回收。

3>该类对应的Class对应没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

因为使用了字节码文件

把类型明确的工作推迟到创建对象或调用方法的时候。只要在编译期没出现告警,运行期就不会出现ClassCastException。

基于单一抽象方法类型的接口,也就是函数式接口来实现。它会调用编译器生成静态方法,使用lambda表达式的地方,通过传递内部类实例,来调用函数式接口方法。

java.lang.Runnable、java.util.Comparator

在处理数据和多个缓存服务器之间对应关系的时候,可以使用哈希值取模运算,但是这时候如果需要增加或减少服务器,很多缓存会失效。一致性哈希是这个问题的一个解决方案:从0为起点到2的32次方-1做成一个哈希环。将服务器的IP地址对2的32次方取模,如果需要,每个服务器也可以复制一些虚拟节点同样映射到哈希环上。将数据的哈希值对2的32次方进行取模(2^32刚好是无符号整形的最大值)。根据取模结果离哪个节点最近决定映射到哪台服务器上。这样增加和减少节点,影响的都是它临近的节点。由于增加了虚拟节点,所以数据的压力会分散。

共2的14次方个槽,每台服务器分管一部分。插入数据时,根据CRC(循环冗余检验)16算法计算key对应的值,用该值对2的14次方取余数。在添加或删除节点时,只需要对节点的上哈希槽做调整。调整过程中映射先不改变,等数据迁移完成后,映射才修改。客户端可以向任何一个节点发送请求,然后由节点将请求重定向到正确的节点上。

CRC16会输出一个16位结果,redis作者测试发现这个数对2的14次方取模会将key分布的很均匀,因此选了这个值。

在有序数组中,每次先判断中间位置是否满足条件。满足则直接返回;不满足就看在前半段还是后半段。在可能满足目标条件的半段再次这样按照中间位置查找直接找到满足条件的或者确定不能满足条件。

Spring的目标:是要最大限度的简化开发工作,让开发人员集中精力于自己的业务逻辑,也是业务领域的开发。

开发的两个核心问题解耦和复用spring是这样解决的:

1>对于解耦

开发人员希望聚焦于业务领域的开发,首先要解决的事情是我修改一个业务代码,不希望显示层、模型层和控制层都要改。不希望改一个类,依赖它的类也需要改。Spring为了应对这个问题使用了控制反转的理念。将所有的依赖都由框架注入到一个上下文环境中(DI)。在这个环境中,Bean之间可以自由的使用。

2>对于复用

一些逻辑,比如日志,鉴权,很多地方都需要用到。这些与业务逻辑的关系又不是很紧密。这就用到了AOP(面向切面编程)。

Spring对解耦和复用的解决方案就是控制反转、依赖注入和AOP,在实现上

需要用到RobertMartin提出的SOLID原则。分别是单一职责、开放封闭、里氏替换、接口隔离和依赖倒置。控制反转、依赖注入和AOP,分别对应了三个spring的jar包:spring-beans、spring-context、spring-aop。每个包单一的负责一个核心功能的实现。这些都需要先做对象的实例化,这个功能由spring-core这个jar包来实现。在Spring-beans中,Spring使用工厂模式来管理程序中使用的对象Bean。每个Bean实例以BeanDefinition的形式被创建,通过java的反射机制将需要初始化的字段写入,最终保存在BeanDefinitionMap中。这整个过程由容器来实现,完成了控制反转。有了控制反转,开发者可以通过调用getBean获取到所需要的对象。spring-context提供文件列表的读入,将所有依赖的Bean放到一个Context中,就是常说的依赖注入。AOP的主要作用是不通过修改源代码的方式将功能代码织入来实现对方法的增强。实现的关键在于使用了代理模式。

使用约定大于配置的方式进一步简化Spring开发

SpringCloud是Spring为微服务架构思想做的一个一站式实现。它提供了服务注册发现NetflixEureka、配置中心springcloudconfig、负载均衡NetflixRibbon、断路器NetflixHystrix、路由NetflixZuul。基本就是这些,因为美团这边主要用octo,springcloud了解的不多。在实际项目中只用过springcloudfeignhystrix。

hystrix主要提供2种容错方法:资源隔离和熔断、降级。

资源隔离主要是线程的隔离,hystrix提供了两种线程隔离方式:线程池和信号量。线程池隔离是为每个类型的命令配置一个线程池,当线程池或请求队列饱和时,hystrix做快速失败处理,防止级联故障。

信号量隔离是对每个请求做信号量计数来控制并发请求量,防止请求线程大面积阻塞,从而达到限流和防止雪崩的目的。

熔断

降级

降级主要是做快速失败,使用者可以自定义fallback方法来定义失败后的处理逻辑。

Spring中大量使用设计模式

1>简单工厂模式,如Spring的BeanFactory

2>工厂方法,如Spring的FactoryBean接口

3>单例模式,Spring依赖注入Bean实例默认是单例的

4>适配器模式,SpringMVC的HandlerAdapter根据不同规则找到对应的Handler

5>代理模式,比如AOP

6>策略模式,比如加载资源文件的方式可以用ClassPathResource、FileSystemResource、ServletContextResourse、UrlResource。AOP的实现可以采用JDK动态代理和CGLIB代理。

7>装饰器模式,ApacheCommon大量使用装饰器模式,比如StringUtils、CollectionUtils这些工具类。

8>我自己写过一个观察者模式的,我做基于kubernetes的容器化项目,线上有几十个kubernetes集群。这些集群的信息是从数据库中读取的,因为比较少并改动不频繁。默认初始化时加载到内存中,数据库就相当于事件源。有一个线程会定时轮询数据库中的信息,一旦发生变化,就相当于是监听器监听到事件变化,则更新内存中数据。这样所有使用它的地方直接读取的就是最新的数据。

事务是n个事件要不全部成功要不全部失败。数据库事务是刚性事务,遵循ACID强一致性原则(原子性、一致性、隔离性、持久性)。

分布式事务是在分布式系统环境下由不同的服务之间通过网络协作完成的事务。分布式事务一般采用柔性事务。基于BASE(BasicallyAvailable、Softstate、Eventuallyconsistent)理论。

我在实际工作中常用的主要有4种:

1>两阶段提交:预提交阶段判断是否满足条件,不满足则返回失败。满足则将资源预占住执行提交,提交阶段成功则返回成功,不成功则撤销提交操作。

举个我实际应用的例子:在我们申请服务器接口请求层就使用了这种方法,先预提交检查是否有服务器资源,有的话就将资源预占住,然后提交操作真正执行服务器申请。

2>异步确保型

将同步阻塞的事务操作变为异步操作。

举个我实际应用的例子:刚才提到的申请服务接口请求层。申请服务器接口实际上分成了请求层和执行层两层。因为申请服务器是一个耗时很长的操作。因为需要执行一系列的kubernetes操作,把容器创建出来,服务启动起来这些。平均需要30s。我们系统采用的方式是请求层判断是否满足申请服务器的条件,如果满足则发送两个mq,然后返回请求层的响应。这两个mq,一个是立即执行申请服务器的后续流程。另外一个是发送到延迟消息队列,5分钟后检查容器的状态看是否存在超时,超时则进行补偿处理。用户收到请求层提示成功后,再自己去轮询执行层的真正结果。

3>还有一个TCC解决方案是两阶段提交的改进,将整个业务逻辑显式的分成了try、confirm和cancel三个操作。这属于一种补偿性事务。

在之前负责美团金融交易时就使用过这种方式:先尝试支付,收到支付成功消息则返回结果,否则发起冲正(就是撤销)操作。

4>最大努力通知型

我做过一个统一降级开关的项目,一个降级开关是要对好几个子服务进行降级。这个降级接口收到请求验证符合降级条件后就返回「请求已受理,实际执行结果以通知为准」。同时异步的对每个子服务发起降级请求,请求有重试。所有请求成功或者重试超限后会发出通知各子服务的最终返回状态。

5>数据一致性算法

我听说过一些数据一致性算法,没有实际直接用过:比如Paxos、Raft、ZAB、Gossip这些少数服从多数的算法。具体内容没有研究过。由于目前的工作还是偏工程,所以我学习过的算法也就仅限于一致性哈希这种的。

Kubernetes采用主从分布式架构,包括主节点、从节点,以及客户端命令行工具和其他附加项。

1>主节点

其中主节点负责对集群进行调度管理。由APIServer、Scheduler、ClusterStateStore(etcd)和ControllerManagerServer组成。我们线上一个大集群master节点都是部署在三台物理机上,1主2从的架构。

1.2>Scheduler负责资源调度,按照预定的调度策略将Pod调度到相应的节点上。

1.3>ClusterStateStore保存了整个集群的状态,主要用来共享配置和服务发现。我们这边用的是默认的etcd。

1.4>Controller-ManagerServer负责维护集群的状态,比如故障检测、自动扩展、滚动更新等。默认提供RepicationController、Nodecontroller、NamespaceController、ServiceController、EndpointsController、PersistentController、DaemonSetController。由于美团这边对容器的用法还是接近与虚拟机的用法。所以这边的容器管理已经全部从原来的基于RC的创建方式改成了直接基于Pod的创建方式。

2>再说从节点

从节点包含kubelet、kubeproxy和ContainerRuntime。

2.1>kubelet维护容器的生命周期,并管理CSI(ContainerStorageInterface)和CNI(ContainerNetworkInterface)。存储方面美团这边主要使用FlexVolume插件进行LVM本地存储(逻辑卷管理)。目前也有部分是基于CSI连接EBS(弹性块存储)磁盘的。

2.2>kube-proxy基于一种公共访问策略提供访问pod的途径。

2.3>ContainerRuntime负责镜像管理以及Pod和容器的真正运行,我们这边用的docker。

3>kubectl

用于通过命令行与APIServer进行交互,实现在集群中进行各种资源的维护与管理操作。

4>附加项:对kubernetes核心功能的扩展,主要有网络、服务发现和可视化三类。

DDD不需要特殊的架构,只要是能将技术问题与业务问题分离的架构即可。强调保持领域模型复杂性与技术代码复杂性的隔离。核心价值点是协作、通用语言UL以及有界上下文。

战术有CQRS命令查询隔离、事件溯源、RESTful服务、消息传递、MVP最小可行产品、ACL防止损坏层、提炼核心、支撑和通用域。还有消除依赖、弱化依赖和控制依赖。这是我自己提出来的一个战术。并在之前的项目得到很好的应用。

针对不同的场景和痛点,整体的方案也会不同。有一些主要的战术。

1>领域拆分隔离方面

ACL防止损坏层

有界上下文

提炼核心、支撑和通用域

分层架构

CRUD增删改查简单架构

CQRS命令查询隔离

依赖消弱控

2>服务部署隔离方面

环境拆分

机房隔离

通道隔离

单元化

泳道

热点隔离

读写隔离

容器隔离

拆库拆表

动静隔离

非核心流量隔离

3>服务间交互隔离方面

超时熔断

失败率超限降级

4>服务内资源隔离方面

线程池隔离

信号量隔离

1>慢查询治理

2>超时治理

3>依赖治理:消除依赖、弱化依赖、控制依赖

4>系统破窗户治理

5>废弃代码资源治理

6>系统异常治理

7>告警治理

8>数据一致性治理

我们团队目前用的方案设计模板是我编写的,里面包含一个checklist有下面这些条目:

无状态化设计

幂等设计

包含容量预估与冗余设计

兜底策略设计

提供灰度方案

提供应急预案

核心链路尽量用成熟的技术,非核心链路可做技术探索

核心链路点对点设计,非核心链路有批量操作需设计审批流程或者熔断逻辑

包含超时和重试设计

核心数据需要对账

包含开关上线设计

敏感数据需要加密

1>设计规范

设计按照统一的设计模板来进行。

2>开发规范

与第三方交互,交互前后都要打日志。交互后的日志要把第三方返回的结果打印出来。一旦第三方出现问题。我们拿着第三方返回的结果来跟第三方沟通。避免责怪他人讹的出现。

3>上线规范

提测分支至少2名同学进行codereview。Reviewer一般为之前负责过此模块开发的同学和架构师。

Sonar静态代码检查、自动化测试要跑通。这些都是通过工具来保证的。

重大变更要开验收会进行项目验收。

因为我们有环境拆分,分成了线下环境和线上环境。发布线下环境后要观察2天以上才可以发布线上。发布有窗口期,只能在指定的流量低峰期发布。发布要提供紧急预案。

目前主流的架构是基于redis-cluster集群的无中心架构,采用哈希槽来做分布式存储。

redis与memcached相比,数据可以持久化,支持的数据类型丰富,支持服务端计算集合的并、交和补集。还支持多种排序功能。

Redis的所有数据保存在内存中,持久化方面支持半持久化模式和全持久化模式。

全持久化模式也叫AOF持久化是以日志的形式将每一次数据变化都写入到aof文件里。

目前主流的基于redis-cluster集群的无中心架构,采用哈希槽来做分布式存储。哈希槽对应的节点是一主多从的。主节点发生故障,父节点会代替主节点承担流量。

首先过滤掉不健康的数据节点,比如下线、断线的、失联的。然后选择slave-priority优先级最高的从节点返回,如果不存在则选择偏移量最大的从节点。也不存在则选择runid最小的节点。

因为redis是单线程程序,所以是线程安全。

redis是基于内存的,读写速度非常快,CPU不是瓶颈。单线程反而避免了不必要的上下文切换和竞争。另外采用了非阻塞的IO多路复用机制提高性能。

1.字符串-通过数值或SDS实现

2.列表-通过压缩列表或双端链表实现

3.哈希-通过压缩列表或字典实现

3.集合-通过整数集合或字典实现

4.有序集合-通过压缩列表的有序集合或跳跃表+字典组合的数据

1>redis的hash采用链地址法来处理冲突,没有使用红黑树优化。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

缓存穿透的解决方案:布隆过滤器、缓存空对象

缓存击穿:热点数据在失效的瞬间直接请求数据库,解决方案:热点数据永不过期。

Kafka是高吞吐量的、超强消息堆积的、有持久化能力的、快速进行消息处理的分布式消息系统中间件。

核心组件是producer、broker和consumer。broker和consumer通过zk来做分布式协调。client和server之间采用TCP协议。Kafka的存储架构方面……

Kafka是一个分布式的、分区的、复制的提交日志服务。

就是说消息会按照分区分布在集群的所有节点上。每个分区会有多个副本存储在不同的节点上。新的消息总是以追加的方式进行存储。

分区和副本之间是是主从关系。主分片负责读写,从分片只是从主分片同步消息,用于在主分片出现问题时代替主分片。AP表示分区的所有副本,ISR表示和主副本同步的所有副本。如果副本超出同步范围,就叫做OSR。

每个分区副本对应一个日志目录,目录下有多个日志分段。日志分段有大小上限,超过阈值会滚动创建新的日志分段。

在物理上,每个日志分段由一个数据文件和一个索引文件组成。数据文件存储的是消息的真正内容,索引文件存储的数据文件的索引信息。

索引文件采用内存映射加快读取速度。索引文件以稀疏的方式存储部分消息的偏移量到物理位置的对应关系,减少内存占用。这个偏移量是相对偏移量,并且单调递增。可以进一步减少内存的占用,并可使用二分查询快速确定偏移量的位置。

数据文件的读取利用了现代操作系统针对磁盘读写的优化方案来加快磁盘的访问速度。比如,预读会提前将一个大磁盘快读入内存。后写会将很多小逻辑写合并起来组合成大物理写操作。还会将主内存剩余的所有空间内存都用作磁盘缓存。除了直接IO外的磁盘读写都会经过统一的磁盘缓存。消息直接在内核态使用零拷贝技术绕过用户缓冲区和socket缓冲区直接复制到网卡接口通过网络发送出去。

以上是Kafka的核心处理。管理方面,Kafka有日志管理器和副本管理器。

Kafka服务启动时会创建一个日志管理类。负责日志的创建、检索、清理。每个日志分区都有一个全局的检查点文件。检查点表示日志已经刷新到磁盘的位置,主要用于故障的恢复。日志管理器也会定时将页面缓存中的数据真正flush到磁盘文件中。消息追加到日志中,有下面两种场景会发生刷新日志的动作。1是新创建一个日志分段,立即刷新旧的日志分段。2是日志中未刷新的消息数量超过配置项的值。

副本管理器,追加消息时,生产者客户端会发送每个分区以及对应的消息集,拉取消息时,客户端会发送每个分区以及对应的拉取信息。服务端返回给客户端的响应结果也会按照分区分别返回。生产者可以用同步和异步模式发送生成请求给服务端。生产者发送的生产请求还有一个设置项,应答的值表示:生产者要求主副本收到指定数量的应答,才会认为生产请求完成了。如果生产者设置的应答值等于-1,服务端必须等待ISR所有副本都同步完消息,才会发送生产结果给生产者。Kafka在处理这种类型的请求时,会将延迟返回响应结果的请求放入延迟缓存队列。在操作完成或超时时,延迟操作会被从缓存队列中移除。

1>顺序写盘:Kafka在设计时采用追加方式来写入消息,这是典型的顺序写盘操作。可以充分利用操作系统对线性读写的深层优化,比如预读和后写。

预读会提前将一个大磁盘快读入内存。后写会将很多小逻辑写合并起来组合成大物理写操作。

2>页缓存,Kafka中大量使用了页缓存。消息都是先被写入页缓存,然后再由操作系统负责具体的刷盘操作。索引文件采用内存映射加快读取速度。索引文件以稀疏的方式存储部分消息的偏移量到物理位置的对应关系,减少内存占用。这个偏移量是相对偏移量,并且单调递增。可以进一步减少内存的占用,并可使用二分查询快速确定偏移量的位置。

3>零拷贝:消息直接在内核态使用零拷贝技术绕过用户缓冲区和socket缓冲区直接复制到网卡接口通过网络发送出去。

5>批量处理:生产者将多个消息封装成消息集,一次性发送到broker

mysql主从复制是mysql高可用、高性能的基础。有三种复制模式:全同步模式、半同步模式、异步模式。mysql默认使用异步模式。

主从复制设计三个线程,一个运行在主节点(logdumpthread),其余两个(I/Othread,SQLthread)运行在从节点。当从节点连接主节点时,主节点会创建一个logdump线程,用于发送binlog内容。在读取binlog中的操作时,此线程会对主节点的binlog加锁,当读取完成时锁会被释放。当从节点上执行startslave命令后,从节点会创建一个I/O线程用来连接主节点,请求主库中更新的binlog。I/O线程接收到主节点binlogdump进程发来的更新之后,保存在本地relaylog中。SQL线程负责读取relaylog中的内容,解析成具体的操作并执行,最终保证主从数据的一致性。

MySQL主从复制有三种方式:基于SQL语句的复制(statement-basedreplication,SBR),基于行的复制(row-basedreplication,RBR),混合模式复制(mixed-basedreplication,MBR)。它们分别对应三种binlog文件格式。

基于SQL语句的复制就是记录sql语句在binlog中,优点是只需要记录会修改数据的sql语句到binlog,减少binlog日志量,节约I/O,提高性能。缺点是在某些情况下,会导致主从节点中数据不一致(比如存储过程,函数等)。

混合模式复制是以上两种模式的混合,对于一般的复制使用基于SQL语句的复制,对于基于SQL语句无法复制的操作则使用基于行的复制,mysql会根据执行的sql语句自己选择日志保存方式。

当B+Tree的数据项是复合的数据结构,B+Tree是按照从左到右的顺序来建立搜索树的,所以符合最左匹配原则。

对经常用作查询条件的、表连接的和经常出现在orderby、groupby之后的字段创建索引。可以利用最左匹配原则减少索引数量。因为索引多了会影响数据更新效率。

数据库字段最好不要允许为null,因为mysql很难对空值做查询优化。作为索引的字段值尽量不要有大量相同值,尽量选择区分度高、离散度大的。

索引字段要尽量小,因为索引所在的B+Tree的大小不超过一个内存页大小(mysql定制版16K),是固定的,保证访问1个节点只需要1次IO。

聚集还是非聚集指的是B+Tree叶子节点存的是指针还是数据记录

MyISAM引擎索引和数据分离,使用的是非聚集索引。

InnoDB引擎数据文件就是索引文件,主键索引就是聚集索引。

聚集索引的好处之一:它对主键的排序查找和范围查找速度非常快,叶子节点的数据就是用户所要查询的数据。

聚集索引的好处之二:范围查询(rangequery),即如果要查找主键某一范围内的数据,通过叶子节点的上层中间节点就可以得到页的范围,之后直接读取数据页即可。

聚集索引

1.纪录的索引顺序与物理顺序相同

因此更适合betweenand和orderby操作

2.叶子结点直接对应数据

3.每张表只能创建一个聚集索引

非聚集索引

1.索引顺序和物理顺序无关

2.叶子结点不直接指向数据页

3.每张表可以有多个非聚集索引,需要更多磁盘和内容

多个索引会影响insert和update的速度

分库分表分为垂直拆分和水平拆分。还有一种方式,同时结合和垂直拆分和水平拆分,比如主从表。

垂直拆分是按照领域分。水平拆分是数据量和流量的拆分。一般单表数据量超过千万性能会急剧下降需要拆表。单库TPS达到几千后,再增长就需要拆库。

刚才提到主从表,或者也有人成为子母表。是将业务主要信息放到主表,扩展信息用与主表关联的从表来存储。因为主表和从表的信息量不同。可以各自决定是否需要水平拆分。

先扫描表,查出有成绩小于80的人的姓名,然后再次扫描表,用notin或notexists方法。

磁盘预读:根据局部预读性原理,计算机操作系统在一次IO时,不光把当前磁盘地址的数据,而且把相邻的数据也都读取到内存缓冲区内。

5.1.9mysql主从自动切换

mysql主从自动切换使用的是相对成熟的mha(MasterHighAvailability),一旦检测到主服务器故障,就会自动进行故障转移。及时有些从服务器没有收到最新的relaylog,MHA自动从最新的从服务器上识别差异的relaylog并把这些日志应用到其他从服务器上,因此所有的从服务器保持一致性了。MHA通常在几秒内完成故障转移,9-12秒可以检测出主服务器故障,8-10秒内关闭故障的主服务器以避免脑裂,几秒钟内应用异常的relaylog到新的主服务器上,整个过程可以在1—30s

5.1.10事务的基本要素

原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durabillity)

5.1.10.1事务隔离级别和不同级别的并发问题

ReadUncommitted读未提交级别下会引起脏读的并发问题

ReadCommitted读提交级别下会引起不可重复读的并发问题

RepeatableRead重复读级别下如果使用的是基于锁的并发控制,会引起幻读的并发问题

Serializable串行化级别下没有并发问题,但是并发度很低。

并发问题解决的原理主要有两种:LBCC和MVCC。基于锁的并发控制是悲观机制,而多版本并发控制是乐观机制。

Innodb会为每一行添加两个隐藏字段,一个表示该行的创建版本,一个表示该行的删除版本。填入的事务的版本号。

5.1.11查询在什么时候不走索引

3种情况:1>不满足走索引的条件2>走索引效率低于全表扫描3>需要回表的查询结果集过大,超过了配置的范围

符合1的情况有:不满足最左匹配原则;查询条件使用了函数;or操作有一个字段没有索引;使用like条件以%开头

符合2的情况有:查询条件对null做判断,而null的值很多;一个字段区分度很小,比如性别、状态

THE END
1.系统架构笔记2计算机系统基础知识顺序图:描述对象之间的交互,其中循环,选择等复杂交互使用序列片段表示。对象之间的消息类型包括同步消息/异步消息/返回消息/参与者创建消息/参与者销毁消息。 其中交互概览图、定时图、顺序图(序列图)、通信图(协作图)均被称为交互图。除此以外,动态模型还包括状态图和活动图等。 https://blog.csdn.net/HL_LOVE_C/article/details/142323515
2.异步消息传递异步消息通信机制mob64ca13f6bbea的技术博客异步消息传递 异步消息通信机制, 一、同步与异步概念:同步和异步关注的是消息通信机制(synchronouscommunication/asynchronouscommunication)。解释:涉及到IO通知机制;所谓同步,就是发起调用后,被调用者处理消息,必须等处理完才直接返回结果,没处理完之前是不https://blog.51cto.com/u_16213577/10541200
3.消息中间件第八讲:消息队列RocketMQ版实战集群及原理同步刷盘:消息被写入内存的PAGECACHE,返回写成功状态,当内存里的消息量积累到一定程度时,统一触发写磁盘操作,快速写入 。吞吐量高,当磁盘损坏时,会丢失消息 异步刷盘:消息写入内存的PAGECACHE后,立刻通知刷盘线程刷盘,然后等待刷盘完成,刷盘线程执行完成后唤醒等待的线程,给应用返回消息写成功的状态。吞吐量低,但https://developer.aliyun.com/article/1352571
4.UML图详解(七)——交互图(时序图与协作图)对象的行为也称为消息(Message),通常当一个对象调用另一个对象中的行为时,即完成了一次消息传递。 2.表示方式 在生命线间的带有实心箭头表示消息 3.消息命名 信号或消息名(参数:参数类型):返回值 4.简单消息、同步消息、异步消息 消息分为简单消息(Simple Message)、同步消息(Synchronous Message)和异步消息(Asynchhttps://www.360doc.cn/article/9824753_689086442.html
5.下列选项属于消息的类型的是()下列选项属于消息的类型的是( ) A. 同步消息 B. 返回消息 C. 异步消息 D. 简单消息 E. 交互消息 题目标签:消息选项列选如何将EXCEL生成题库手机刷题 如何制作自己的在线小题库 > 手机使用 分享 反馈 收藏 举报 参考答案: A B C D 复制 纠错 举一反三 下列哪些方面属于数据库加密技术的功能https://www.shuashuati.com/ti/bd97b5557b5547b5a61600aa31c9b1a0.html
6.第八届全国职工职业技能大赛(网络和信息安全管理员)山西选拔赛63.“用户信息”可以理解为在用户使用产品或者服务过程中收集的信息构成用户信息,包括() A、IP地址 B、用户名和密码C、上网时间 D、Cookie信息 20 答案:ABCD 64.目前对MD5,对SHA1算法的攻击描述错误的是: A、能够构造出两个不同的消息,这两个消息产生了相同的消息摘要 B、对于一个已知的消息摘要,能够构造出https://max.book118.com/html/2024/0804/8036015104006116.shtm
7.UML答案214、简述顺序图中消息的分类 答:可分为同步消息、异步消息、返回消息三类。 同步消息:调用某个操作和方法。 异步消息:表示通信信号的非嵌套控制流,该信号异步激活操作。 返回消息:表明该消息从某个消息调用返回 ●必要时为每个消息附加上前置条件和后置条件。 ●调整图的布局,尽力减少线的交叉,使图尽可能地直观、https://m.360docs.net/doc/4a0ad13a3968011ca3009141.html
8.消息队列RocketMQ顺序消息消息队列RocketMQ功能特性用户购买商品生成订单为例,此时若以普通消息发送,则下游订单系统可能消息消费顺序混乱,例如订单出库先执行,后生成订单,从而系统数据不正确。顺序消息就能解决此问题,上游系统发送顺序消息,下游订单系统在同一消费组,会依次按顺序消费,执行相应的逻辑。 典型场景二: 数据实时增量同步 https://ecloud.10086.cn/op-help-center/doc/article/67007
9.消息队列(mq)是什么?有新消息写入,两个 follower 分区会同步 master 变更。两个 Consumer 分别从不同的 master 分区获取https://www.zhihu.com/question/54152397/answer/2654914176
10.3分钟白话RocketMQ系列——如何保证消息不丢失普通有序消息:发送普通有序消息,通过指定「消息筛选器selector」,动态决定发送哪个队列。异常默认不重试,可以用户自己重试,并发送到其他队列。 严格有序消息:发送严格有序消息,通过指定队列,保证严格有序,异常默认不重试。 消息发送模式: 同步:调用发送消息方法后,同步阻塞,直到返回SendResult。配置retryTimesWhenSendFaihttps://blog.itpub.net/70024923/viewspace-2983505/
11.计算机网络HTTP(Hyper Text Transfer Protocol)协议: 又称为超文本传输协议,HTTP由一个客户端和一个服务端来实现,运行在不同端系统中的客户端和服务端通过交换HTTP报文进行会话,而HTTP定义了这些报文的结构及进行报文交换时的方式。 HTTP是在TCP协议上运行的,客户端发起HTTP 请求,服务器做出响应处理后,返回HTTP 响应报文。 https://www.nowcoder.com/discuss/435756266465579008
12.大田县政法系统跨部门智慧执法办案管理平台建设项目服务类①价格项(F1×A1)满分为10分。 a.价格分采用低价优先法计算,即满足招标文件要求且投标价格最低的投标报价为评标基准价,其价格分为满分。其他投标人的价格分统一按照下列公式计算:投标报价得分=(评标基准价/投标报价)×100。因落实政府采购政策需进行价格扣除的,以扣除后的价格计算评标基准价和投标报价。 b.价格扣http://zfcg.cz.sm.gov.cn/upload/document/20211105/5f069fc764594cfea5cfa97e5b021347.html