语言之外面试汇总

4 篇文章 0 订阅
2 篇文章 0 订阅

k8s面试题

  • 什么是Kubernetes?
    K8s是用于自动部署、扩展和管理容器化应用程序的开源系统

  • k8s好处
    在这里插入图片描述

  • Kubernetes与Docker有什么关系?
    Docker提供容器的生命周期管理,Docker镜像构建运行时容器。但是,由于这些单独的容器必须通信,因此使用Kubernetes。因此,我们说Docker构建容器,这些容器通过Kubernetes相互通信。因此,可以使用Kubernetes手动关联和编排在多个主机上运行的容器。

  • k8s集群规模,使用的版本及部署方式,master节点跑了什么组件,每个组件作用?
    k8s部署方式:个人推荐使用 kubeadm 和 二进制 部署
    K8S Master 节点一般跑了: ETCD、ApiServer、Controller Manager、Scheduler(有四个组件)
    ApiServer:负责对外提供restful的Kubernetes API服务
    ETCD:是 Kubernetes 提供的一个高可用的键值数据库,用于保存集群所有的网络配置和资源对象的状态信息
    Controller Manager:负责维护集群的状态,比如故障检测、自动扩展、滚动更新等
    Scheduler:监听新建pod副本信息,并通过调度算法为该pod选择一个最合适的Node节点

  • kubernetes 认证
    比如客户端证书、静态token、静态密码文件、ServiceAccountTokens等等

  • controller-manager 和etcd 通信吗?
    controller-manager 和 scheduler 它们都是和 kube-apiserver通信,然后 kube-apiserver 再和etcd通信

  • 对外提供服务的pod暴露方式有哪些
    1.NodePort
    2.LoadBalancer:只能在service上定义,是公有云提供的负载均衡器
    3.Ingress

在这里插入图片描述

  • pod的生命周期
    在这里插入图片描述
  • kubernetes是如何发现并重启另一个pod的?
    Replication Controller 可以保证Pod始终处于规定的副本数。
    监控RC和RC内Pod的状态,从而增删Pod,以实现维持特定副本数的功能。
  • Kubernetes 的负载均衡器
    负载均衡器是暴露服务的最常见和标准方式之一。
    根据工作环境使用两种类型的负载均衡器,即内部负载均衡器或外部负载均衡器。内部负载均衡器自动平衡负载并使用所需配置分配容器,而外部负载均衡器将流量从外部负载引导至后端容器。
  • 述kube-proxy原理,一个请求是如何经过层层转发落到某个pod上的整个过程。请求可能来自pod也可能来自外部
    kube-proxy为集群提供service功能,相同功能的pods对外抽象为service,service可以实现反向代理和服务发现。可以分为iptables模式和userspace模式
  • 查看ops这个命名空间下的所有pod,并显示pod的IP地址
kubectl get pods -n ops -o wide
  • Endpoints表示一个Service对应的所有Pod副本的访问地址。只有service关联的pod才可能成为endpoint
kubectl get ep -n test
  • ingress是什么
    虽然通过kube-proxy可以帮助实现集群内外的pod相互通信,但是随着service的增多,nodeIP越来越多,并且kube-proxy生成的规则链也会越来越多,对Linux内核也是负担,因此引入loadbalancers,而且kube-proxy在7层网络架构中,只能限制到第四层,也就是传输层,对应用层(应用层在第七层)无能为力,所以引入ingress。
    你可以把它理解为传统的 nginx,用以配置自己网站的域名使之能够通过外网访问。在这里插入图片描述
    在这里插入图片描述

ingress contronler通过与k8s的api进行交互,动态的去感知k8s集群中ingress服务规则的变化,然后读取它,并按照定义的ingress规则,转发到k8s集群中对应的service。而这个ingress规则写明了哪个域名对应k8s集群中的哪个service,然后再根据ingress-controller中的nginx配置模板,生成一段对应的nginx配置。然后再把该配置动态的写到ingress-controller的pod里,该ingress-controller的pod里面运行着一个nginx服务,控制器会把生成的nginx配置写入到nginx的配置文件中,然后reload一下,使其配置生效。以此来达到域名分配置及动态更新的效果。

ingress可以简单理解为service的service,他通过独立的ingress对象来制定请求转发的规则,把请求路由到一个或多个service中。这样就把服务与请求规则解耦了,可以从业务维度统一考虑业务的暴露,而不用为每个service单独考虑在这里插入图片描述

  • 如何在不进入pod内查看命名空间为test,pod名称为test-5f7f56bfb7-dw9pw的hosts
kubectl exec -it test-5f7f56bfb7-dw9pw -n test -- cat /etc/hosts
  • k8s master节点都有什么
    在集群管理方面,K8s将集群中的机器划分为一个Master节点和一群工作节点Node。
    Master指的是集群控制节点。每个K8s集群里需要有一个Ms节点负责整个集群的管理和控制。Kubernetes Master提供集群的独特视角,并且拥有一系列组件。在这里插入图片描述

  • Node节点
    每个节点都运行如下Kubernetes关键组件。在这里插入图片描述Kube-proxy(相当于负载均衡器)负责service的实现,实现了内部从pod到service和外部node port向service的访问

  • POD
    Pod其实有两种类型:普通的Pod及静态Pod(static Pod),static Pod并不存放在Kubemetes的etcd存储里,而是存放在某个具体的Node上的一个具体文件中,并且只在此Node上启动运行。而普通的Pod一旦被创建,就会被放入到etcd中存储,确后会被KubernetesMaster调度到某个具体的Node上并进行绑定(Binding),随后该Pod被对应的Node上的kubelet进程实例化成一组相关的Docker容器并启动起来。在默认情况下,当Pod里的某个容器停止时,Kubemetes会自动检测到这个问题并且重新启动这个Pod(重启Podel)的所有容器),如果Pod所在的Node完机,则会将这个Node上的所有Pod重新调度到其他节点上

  • 外部是怎么访问到pod的
    每个Pod都会被分配一个单独的IP地址,而且每个Pod都提供了一个独立的Endpoint(Pod lP + ContainerPort)以被客户端访问
    现在多个Pod副本组成了一个集群来提供服务,客户端要想访问集群,一般的做法是部署一个负载均衡器
    为这组Pod开启一个对外的服务端口如8000端口,并且将这些Pod的Endpoint列表加入8000端口的转发列表中,客户端就可以通过负载均衡器的对外IP地址 + 服务端口来访问此服务,而客户端的请求最后会被转发到哪个Pod,则由负载均衡器的算法所决定

  • pod和service关系
    Kubernetes中Pod的生命是短暂了,它随时可能被终止。即使使用了Deployment或者ReplicaSet保证Pod挂掉之后还会重启,但也没法保证重启后Pod的IP不变。从服务的高可用性与连续性的角度出发,我们不可能把Pod的IP直接暴露成service端口。因此我们需要一个更加可靠的“前端”去代理Pod,这就是k8s中的Service。

    也可以说,Service作为“前端”提供稳定的服务端口,Pod作为“后端”提供服务实现。Service会监控自己组内的Pod的运行状态,剔除终止的Pod,添加新增的Pod。配合k8s的服务发现机制,我们再也不用担心IP改变,Pod终止等问题了。kube-proxy则是实现Service的关键组件

  • kube-proxy工作原理
    Kube-proxy进程获取每个Service的Endpoints,实现Service的负载均衡功能在这里插入图片描述
    Service在很多情况下只是一个概念,而真正将Service的作用实现的是kube-proxy服务进程。
    每个Node节点上都会运行一个kube-proxy服务进程

到目前为止共有3种实现模式:在这里插入图片描述iptables是一种Linux内核功能,旨在成为高效的防火墙,并具有足够的灵活性来处理各种常见的数据包操作和过滤需求
IPVS是专门用于负载平衡的Linux内核功能。在IPVS模式下,kube-proxy 对IPVS负载均衡器进行编程,而不是使用iptables。IPVS 专 为负载均衡大量服务而设计;它优化了API和查找目标的方式,而不是顺序查找。
IPVS模式下的kube-proxy的连接处理的计算复杂度为O(1)。换句话说,在大多数情况下,其连接处理性能将保持恒定,与群集大小无关

作为专用的负载平衡器,IPVS拥有多种不同的调度算法,例如循环调度,最短期望延迟,最少连接和各种哈希方法。iptables 中的 kube-proxy 只能使用随机等价选择算法。

  • 什么是负载均衡?
    将负载(工作任务,访问请求)进行平衡、分摊到多个操作单元(服务器,组件)上进行执行。是解决高性能,单点故障(高可用),扩展性(水平伸缩)的终极解决方案。

  • Ingress怎么实现负载均衡

  • Scheduler的理解
    当运行一个容器的时候,放在哪台节点上,这个过程是调度。对于Kubernetes,调度是由一个单独的进程scheduler负责的。

  • k8s的理解
    简单来说就是数据库(etcd)增删改查,用户可以声明各种高级工作对象(Deployment,Service,ReplicaSet,Job等等),然后写到etcd里。一堆服务都盯着etcd的特定数据类型的变化呢(通过list watch机制,通过chunk get一个资源实现)
    在这里插入图片描述
    在这里插入图片描述

  • etcd通信
    etcd 是一个响应快、分布式、一致的 key-value 存储。因为它是分布式的,故可以运行多个 etcd 实例来获取高可用性和更好的性能。

唯一能直接和 etcd 通信的是 Kubernetes 的 API 服务器。所有其他组件通过 API 服务器间接地读取、写入数据到 etcd。这带来一些好处,其中之一就是增强乐观锁系统、验证系统的健壮性;并且,通过把实际存储机制从其他组件抽离,未来替换起来也更容易。值得强调的是,etcd 是 Kubernetes 存储集群状态和元数据的唯一的地方。

Kubernetes API服务器作为中心组件, 其 他组件或者客户端(如kubectl)都 会去调用它。以 RESTful API的形式提供了可以查询、修改集群状态的 CRUD(Create、Read、Update、Delete)接口。它将状态存储到 etcd 中。

API 服务器需要认证发送请求的客户端。这是通过配置在 API 服务器上的一个或多个认证插件来实现的。API 服务器会轮流调用这些插件,直到有一个能确认是谁发送了该请求。除了认证插件,API 服务器还可以配置使用一个或多个授权插件。它们的作用是决定认证的用户是否可以对请求资源执行请求操作。如果请求尝试创建、修改或者删除一个资源,请求需要经过准入控制插件的验证

除了前面讨论的,API 服务器没有做其他额外的工作。例如,当你创建一个 ReplicaSet 资源时,它不会去创建 pod, 同时它不会去管理服务的端点。那是控制器管理器的工作。其他组件通过建立和 API 服务器的连接来监听元数据的变化,当 API server 将元数据变化的事件发送到客户端后,客户端会自动做相应的工作。

  • 什么是无状态服务
    无状态请求,服务器端所能够处理的数据全部来自于请求所携带的信息,无状态服务对于客户端的单次请求的处
    理,不依赖于其他请求,处理一次请求的信息都包含在该请求里。最典型的就是通过cookie保存token的方式传输
    请求数据。也可以理解为Cookie是通过客户端保持状态的解决方案。

  • 什么是分布式系统
    分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据。

  • k8s为什么要弃用docker
    Docker 并不支持 CRI(容器运行时接口)这一 Kubernetes 运行时 API,而 Kubernetes 用户一直以来所使用的其实是名为“dockershim”的桥接服务。Dockershim 能够转换 Docker API 与 CRI,但在后续版本当中,Kubernetes 将不再提供这项桥接服务,因为Kubernetes 社区发现了与之相关的维护问题

**为什么要部署在容器上在这里插入图片描述
**

  • K8s创建一个pod的完整流程
    1.简单介绍:Pod 是 K8s 系统的基础单元,是由用户创建或部署的最小组件,也是 K8s 系统上运行容器化应用的资源对象。Pod 生命周期中的几种不同状态包括pending、running、succeeded、failed、Unknown
    2.在这里插入图片描述
    在这里插入图片描述
    3.创建service

在这里插入图片描述

  • k8s pod指定部署到固定Node上
    1.node打上labels,通过nodeSelect调度到含有指定lables的Node上
    2.用nodeName指定Node的名称。
  • k8s pod ip node ip cluster ip区别
    Node节点的IP地址,即物理网卡的IP地址。Pod的IP地址,即docker容器的IP地址,此为虚拟IP地址。Service的IP地址,此为虚拟IP地址
    外部访问时,先到Node节点网络,再转到service网络,最后代理给pod网络。k8s在其所有节点上开放一个端口给外部访问(所有节点上都使用相同的端口号), 并将传入的连接转发给作为Service服务对象的pod。这样我们的pod就可以被外部请求访问到在这里插入图片描述

mongo面试

  • 1.什么是MongoDB, 为什么用MOngoDB?
    MongoDB是一个文档数据库,提供好的性能,领先的非关系型数据库。采用BSON存储文档数据。
    BSON()是一种类json的一种二进制形式的存储格式,简称Binary JSON.
    相对于json多了date类型和二进制数组。在这里插入图片描述

  • K8S声明式和命令式的区别
    声明式就像你告诉你朋友画一幅画,你不用去管他怎么画的细节
    命令式就像按照你的命令,你朋友一步步把画画出来

  • MongoDB的优势有哪些
    面向文档的存储:以 JSON 格式的文档保存数据。
    任何属性都可以建立索引。
    高可扩展性自动分片。
    丰富的查询功能,快速的即时更新。

  • 什么是集合(表)
    集合就是一组 MongoDB 文档。它相当于关系型数据库(RDBMS)中的表这种概念。集合位于单独的一个数据库中。
    一个集合内的多个文档可以有多个不同的字段。

  • 什么是文档
    文档由一组key value组成。文档是动态模式,这意味着同一集合里的文档不需要有相同的字段和结构。在关系型
    数据库中table中的每一条记录相当于MongoDB中的一个文

  • 什么是非关系型数据库
    非关系型数据库的显著特点是不使用SQL作为查询语言,数据存储不需要特定的表格模式。

  • monogodb 中的分片什么意思
    分片是将数据水平切分到不同的物理节点。当应用数据越来越大的时候,数据量也会越来越大。当数据量增长
    时,单台机器有可能无法存储数据或可接受的读取写入吞吐量。利用分片技术可以添加更多的机器来应对数据量增加以及读写操作的要求。

  • MongoDB支持哪些数据类型
    在这里插入图片描述

  • "ObjectID"有哪些部分组成
    一共有四部分组成:时间戳、客户端ID、客户进程ID、三个字节的增量计数器

  • 如何添加索引

db.collection.createIndex()在集合中创建一个索引
  • 如何查询集合中的文档
    db.collectionName.find({key:value})
  • 什么是聚合
     聚合操作能够处理数据记录并返回计算结果。聚合操作能将多个文档中的值组合起来,对成组数据执行各种操作,返回单一的结果。它相当于 SQL 中的 count(*) 组合 group by。对于 MongoDB 中的聚合操作,应该使用aggregate()方法。
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
  • 在MongoDB中什么是副本集(避免单点故障)
    在MongoDB中副本集由一组MongoDB实例组成,包括一个主节点多个次节点,MongoDB客户端的所有数据都
    写入主节点(Primary),副节点从主节点同步写入数据,以保持所有复制集内存储相同的数据,提高数据可用性。
  • 如何执行事务/加锁?
     mongodb没有使用传统的锁或者复杂的带回滚的事务,因为它设计的宗旨是轻量,快速以及可预计的高性能
  • mongo分页的实现
mongoDB的分页查询是通过limit(),skip(),sort()这三个函数组合进行分页查询的

消息队列

  • 为什么要使用消息队列
    解耦、异步、削峰
    传统模式的缺点:系统间耦合性太强,系统A在代码中直接调用系统B和系统C的代码,如果将来D系统接入,系统A还需要修改代码,过于麻烦!将消息写入消息队列,需要消息的系统自己从消息队列中订阅,从而系统A不需要做任何修改。
    传统模式的缺点:一些非必要的业务逻辑以同步的方式运行,太耗费时间。
    并发量大的时间,所有的请求直接怼到数据库,造成数据库连接异常,消息队列:系统A慢慢的按照数据库能处理的并发量,从消息队列中慢慢拉取消息。在生产中,这个短暂的高峰期积压是允许的。
  • 使用了消息队列会有什么缺点在这里插入图片描述
  • 如何保证消息不被重复消费(如何保证消息队列的幂等性?)
    正常情况下,消费者在消费消息的时候,消费完毕后,会发送一个确认消息给消息队列,消息队列就知道该消息被取消了,就会将该消息从消息队列中删除。只是不同的消息队列发出的确认消息形式不同,例如RabbitMQ是发送一个ACK确认消息,RocketMQ是返回一个CONSUME_SUCCESS成功标志,kafka实际上有个offet的概念,简单说一下,就是每一个消息都有一个offset,kafka消费过消息后,需要提交offset,让消息队列知道自己已经消费过了。

那造成重复消费的原因?,就是因为网络传输等等故障,确认信息没有传送到消息队列,导致消息队列不知道自己已经消费过该消息了,再次将消息分发给其他的消费者。

分以下三种情况来解决:
在这里插入图片描述

  • 如何保证消费的可靠性传输?
    可靠性分三个方面:
    生产者弄丢数据:从生产者弄丢数据这个角度来看,RabbitMQ提供transaction和confirm模式来确保生产者不丢消息。
    transaction机制就是说,发送消息前,开启事务,然后发送消息,如果发送过程中出现什么异常,事务就会回滚,如果发送成功则提交事务
    消费队列丢失;
    处理消息队列丢数据的情况,一般是开启持久化磁盘的配置。这个持久化配置可以和confirm机制配合使用,你可以在消息持久化磁盘后,再给生产者发送一个Ack信号。这样,如果消息持久化磁盘之前,rabbitMQ阵亡了,那么生产者收不到Ack信号,生产者会自动重发。
    消费者丢数据:消费者丢数据一般是因为采用了自动确认消息模式。这种模式下,消费者会自动确认收到信息。这时rabbitMQ会立即将消息删除,这种情况下,如果消费者出现异常而未能处理消息,就会丢失该消息。
    至于解决方案,采用手动确认消息即可。
  • 怎么确保消息顺序
    1、单线程消费来保证消息的顺序性;2、对消息进行编号,消费者处理时根据编号判断顺序。
  • 设计MQ思路

在这里插入图片描述

  • 大量消息在mq里积压了几个小时了还没解决,怎么办
    在这里插入图片描述
  • 消息队列过期失效问题?
    假设用的是rabbitMQ。rabbitMQ是可以设置过期时间的。如果消息在queue里积压一定时间就会被rabbitMQ清掉,造成的问题是因积压超时而丢数据了。

解决方法是: 重导入数据。手工查找丢的数据,重新灌入MQ里面去(一般不设rabbitMQ的过期时间)

  • 如何确保消息正确地发送至 RabbitMQ? 如何确保消息接收方消费了消息?
    发送方确认模式

将信道设置成 confirm 模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的 ID。
一旦消息被投递到目的队列后,或者消息被写入磁盘后(可持久化的消息),信道会发送一个确认给生产者(包含消息唯一 ID)。

如果 RabbitMQ 发生内部错误从而导致消息丢失,会发送一条 nack(notacknowledged,未确认)消息。

发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息

  • 为什么不应该对所有的 message 都使用持久化机制?
    必然导致性能的下降,因为写磁盘比写 RAM 慢的多

  • RabbitMQ 上的一个 queue 中存放的 message 是否有数量限制?
    可以认为是无限制,因为限制取决于机器的内存,但是消息过多会导致处理效率的下降

  • RabbitMq如何保证高可用
    采用镜像集群模式,这种模式才是高可用模式. 与普通集群模式的主要区别在于. 无论queue的元数据还是queue中的消息都会同时存在与多个实例上.
    跟普通集群模式不一样的是,在镜像集群模式下,无论队列中的元数据还是消息都会存在于多个实例上,就是说,每个 RabbitMQ 节点都有这个 队列的一个完整镜像。然后每次写消息到队列的时候,都会自动把消息同步到多个实例上
    这种方式的好处就在于, 任何一个服务宕机了,都不会影响整个集群数据的完整性, 因为其他服务中都有queue的完整数据, 当进行消息消费的时候,连接其他的服务器节点一样也能获取到数据.在这里插入图片描述

  • Kafka 分区向消费者分配的策略:
    1.range策略是默认的。range分配策略针对的是主题,对于每个主题,我们以数字顺序排列可用分区,以字典顺序排列消费者。然后,将分区数量除以消费者总数,以确定分配给每个消费者的分区数量。如果没有平均划分(PS:除不尽),那么最初的几个消费者将多负责一个分区。
    2 roundrobin(轮询)策略:轮询分配策略是基于所有可用的消费者和所有可用的分区的,与前面的range策略最大的不同就是它不再局限于某个主题,如果所有的消费者实例的订阅都是相同的,那么这样最好了,可用统一分配,均衡分配

  • 怎么才是消费成功
    offset偏移量+1,commit提交成功;
    但是很多时候是客户端消费了数据 但是commit失败,这时候会有别的客户端来进行消费消息。这个很难做事务,一般都是做业务幂等,自行做消息去重。(去重:将消息的唯一标识保存到外部介质中,比如消息去重表,每次消费处理时判断是否处理过)

  • kafka怎么保证数据的一致性
    kafka一致性指的是不管是老的leader还是新的leader,consumer都能读到一样的数据。
    木桶原理(High water mark)只有High water mark以上的message才能被consumer读取在这里插入图片描述

web

  • Cookie和Session的区别
    在这里插入图片描述
  • 反向和正向区别
    在这里插入图片描述

在这里插入图片描述

  • 孤儿进程 僵尸进程在这里插入图片描述
    在这里插入图片描述
    解决僵尸进程:
    #方法一,传递信号给其父进程,命令其回收子进程的资源
    kill -CHLD + 父进程号

    #方法二,直接 KILL 掉其父进程,将此进程变成孤儿进程,交给 init 进程管理,init 进程回收此进程的资源
    kill -9 + 父进程号

Docker

  • Docker是一个容器化平台,它以容器的形式将您的应用程序及其所有依赖项打包在一起,以确保您的应用程序在任何环境中无缝运行。
  • Docker与虚拟机有何不同
    docker设计小巧,部署迁移快速,运行高效,应用之间相互独立,管理人员可以看到所有容器的内容,虚拟化技术比较臃肿,不论什么应用都需要先创建新的系统,并且并非按照应用隔离,而是按照系统隔离,管理员无法看到系统内部信息。

举个例子,Docker就是手机中的各种APP,只需要一个系统就可以下载自己所需的应用,但是虚拟化技术相当于你的苹果手机安装一个庞大软件,这个软件上安装安卓系统、魅族系统等,每个系统上还要安装各类应用,比较麻烦。

  • ocker容器有几种状态
    四种状态:运行、已暂停、重新启动、已退出。

  • Dockerfile中的命令COPY和ADD命令有什么区别
    COPY指令和ADD指令的唯一区别在于是否支持从远程URL获取资源。COPY指令只能从执行docker build所在的主机上读取资源并复制到镜像中。而ADD指令还支持通过URL从远程服务器读取资源并复制到镜像中。在这里插入图片描述

  • 解释一下dockerfile的ONBUILD指令
    当镜像用作另一个镜像构建的基础时,ONBUILD指令向镜像添加将在稍后执行的触发指令。如果要构建将用作构建其他镜像的基础的镜像(例如,可以使用特定于用户的配置自定义的应用程序构建环境或守护程序),这将非常有用

  • docker容器之间怎么隔离?
    Linux中的PID、IPC、网络等资源是全局的,而NameSpace机制是一种资源隔离方案,在该机制下这些资源就不再是全局的了,而是属于某个特定的NameSpace,各个NameSpace下的资源互不干扰。
    虽然有了NameSpace技术可以实现资源隔离,但进程还是可以不受控的访问系统资源,比如CPU、内存、磁盘、网络等,为了控制容器中进程对资源的访问,Docker采用control groups技术(也就是cgroup),有了cgroup就可以控制容器中进程对系统资源的消耗了,比如你可以限制某个容器使用内存的上限、可以在哪些CPU上运行等等。

    有了这两项技术,容器看起来就真的像是独立的操作系统了。

  • docker容器和系统共享什么资源
    1.docker是共享宿主机的内核,所有容器都是公用一个系统内核

  • 设计docker
    docker包括三个基本概念:镜像,容器,仓库

  • 多个 Docker 容器之间共享数据怎么办?

  • 如果是同一个宿主,那么可以绑定同一个数据卷,当然,程序上要处理好并发问题。

    如果是不同宿主,则可以使用分布式数据卷驱动,让分布在不同宿主的容器都可以访问到的分布式存储的位置

  • dokcer主要的概念–镜像,容器,仓库
    在这里插入图片描述在这里插入图片描述

  • docker进程ID
    Docker容器本质上是宿主机上的进程。
    容器进程ID就是宿主机进程ID,因为它们是相同的

  • Docker之间网络请求模式
    一 同宿主机
    1.bridge 模式
    当docker进程启动时,主机上会创建一个名为docker0的虚拟网桥,容器内部会创建一个只能容器内部看到的接口eth0,eth0 和docker0工作方式就像物理二层交换机一样,可以互相通信。
    2.第二种:host模式
    容器启动时候用host模式,那么容器不会像第一张那样有个独立Network NameSpace。而是和主机共享一个Network NameSpace。
    使用宿主机的ip和端口,但是容器的系统,进程列表等还是和主机隔离。
    3.第3种:none模式
    none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。
    二. 跨主机通信
    单台主机上面的docker容器通过docker0来通信。不同主机上面的容器只能在主机上做端口映射来完成。端口映射方式对很多集群应用来说极不方便。
    方法一:现在用docker主机上添加静态路由直接实现跨宿主机容器之间通信
    方法二:借助pipework容器网络配置工具。

  • docker compose是什么?
    Compose 是一个用户定义和运行多个容器的 Docker 应用程序,负责实现对Docker容器集群的快速编排

数据库redis

  • 什么是redis主从复制
    主从复制就是现在有俩台redis服务器,把一台redis的数据同步到另一台redis数据库上。前者称之为主节点(master),后者为从节点(slave)。数据是只能master往slave同步单向
  • zset与set
    在这里插入图片描述
    zset 的每个元素都会关联一个分数(分数可以重复),redis 通过分数来为集合中 的成员进行从小到大的排序。

1.set 底层采用散列表(根据(Key value)访问数据)来存储,value都为null,通过散列表key的唯一性保证set中元素的不重复。
2.redis中 zset 底层采用散列表+跳跃列表(skiplist)来存储数据。
在同时满足一下两个条件的时候使用ziplist,其他时候使用skiplist,两个条件如下:
有序集合保存的元素数量小于128个
有序集合保存的所有元素的长度小于64字节
skiplist结构核心点主要包括一个dict对象和一个skiplist对象。dict保存key/value,key为元素,value为分值;skiplist保存的有序的元素列表,每个元素包括元素和分值,使用skiplist按序保存元素及分值,使用dict来保存元素和分值的映射关系。

  • redis几种集群模式
    1.主从同步/复制
    优点:a为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成
    b支持主从复制,主机会自动将数据同步到从机,可以进行读写分离
    缺点:aRedis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败
    b主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性

2.哨兵模式
 哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。第一种主从同步/复制的模式,当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,造成一段时间内服务不可用。 所以我们优先考虑哨兵模式。
哨兵模式的作用:
通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器;
当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机;在这里插入图片描述

  • 缓存穿透是什么意思 怎么预防
    缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,请求直接打在了数据库上。
    对于缓存穿透的话一般来说只需要针对空值缓存就行,过期时间设置5-10分钟,这样就流量就不会打在数据库上导致死机宕机。

  • 缓存击穿,如何预防?
    缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
    缓存击穿的话,设置热点数据永远不过期。或者加上互斥锁就能搞定了。

  • 缓存雪崩,如何预防?在这里插入图片描述

  • 乐观锁,悲观锁应用场景和实现思路
    乐观锁和悲观锁的使用场景及应用在这里插入图片描述

    3.Cluster 集群
    每台 Redis 服务器都存储相同的数据,很浪费内存,所以在redis3.0上加入了 Cluster 集群模式,实现了 Redis 的分布式存 储,也就是说每台 Redis 节点上存储不同的内容。
    当其它主节点ping一个主节点A时,如果半数以上的主节点与A通信超时,那么认为主节点A宕机了。

  • 哨兵模式实现原理
    1.发现故障原理:定时任务;每个哨兵节点维护了3个定时任务。定时任务的功能分别如下:通过向主从节点发送info命令获取最新的主从结构;通过发布订阅功能获取其他哨兵节点的信息;通过向其他节点发送ping命令进行心跳检测,判断是否下线。
    2.客观下线后恢复:选举领导者哨兵节点:当主节点被判断客观下线以后,各个哨兵节点会进行协商,选举出一个领导者哨兵节点,并由该领导者节点对其进行故障转移操作。监视该主节点的所有哨兵都有可能被选为领导者,选举使用的算法是Raft算法;Raft算法的基本思路是先到先得:即在一轮选举中,哨兵A向B发送成为领导者的申请,如果B没有同意过其他哨兵,则会同意A成为领导者。选举的具体过程这里不做详细描述,一般来说,哨兵选择的过程很快,谁先完成客观下线,一般就能成为领导者。

  • pipline用来干嘛
    管道(pipeline)可以一次性发送多条命令并在执行完后一次性将结果返回,pipeline通过减少客户端与redis的通信次数来实现降低往返延时时间
    pipeline的作用是将一批命令进行打包,然后发送给服务器,服务器执行完按顺序打包返回。

  • redis事务
    redis 的事务是非原子性的
    在这里插入图片描述

  • 怎么让redis事务具有原子性
    严格的说Redis的命令是原子性的,而事务是非原子性的,我们要让Redis事务完全具有事务回滚的能力,需要借助于命令WATCH来实现。
    Redis使用WATCH命令来决定事务是继续执行还是回滚,那就需要在MULTI之前使用WATCH来监控某些键值对,然后使用MULTI命令来开启事务,执行对数据结构操作的各种命令,此时这些命令入队列。

    当使用EXEC执行事务时,首先会比对WATCH所监控的键值对,如果没发生改变,它会执行事务队列中的命令,提交事务;如果发生变化,将不会执行事务中的任何命令,同时事务回滚。当然无论是否回滚,Redis都会取消执行事务前的WATCH命令。

  • 关系型数据库的四个特性
    关系型数据库的事务具有四个特性:
    原子性 2. 一致性 3. 隔离性 4. 持久性

  • redis的 rdb 和 aof 持久化的区别
    aof,rdb是两种 redis持久化的机制。用于crash后,redis的恢复。RDB是根据指定的规则定时将内存中的数据备份到硬盘上,AOF是在每次执行命令后命令本身记录下来,所以RDB的备份文件是一个二进制文件,而AOF的备份文件是一个文本文件

  • redis的网络模型,单进程单线程方式也这么快
    Redis采用的是基于内存的采用的是单进程单线程模型的KV数据库,由C语言编写。官方提供的数据是可以达到100000+的qps
    Redis快的主要原因是:

     1.完全基于内存数据结构简单 2. 对数据操作也简单使用多路   3. I/O 复用模型
    

    多路复用模型:用select、poll、epoll可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作
    “多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗)

  • 什么时候更新redis(三种更新策略)
    1.先更新数据库,再更新缓存
    数据库更新成功以后,由于缓存和数据库是分布式的,更新缓存可能会失败,数据库是新的,但缓存中数据是旧的.
    2.先删缓存,再更新数据库
    可能出现的问题是请求A进行写操作,删除缓存,请求B查询发现缓存不存在,请求B去数据库查询得到旧值,请求B将旧值写入缓存,请求A将新值写入数据库
    可采用延时双删策略
    在这里插入图片描述

    3.先更新数据库,再删缓存
    这个是经典的缓存 + 数据库读写的模式
    读的时候,先读缓存,缓存没有的话,那么就读数据库,然后取出数据后放入缓存,更新的时候,先更新数据库,数据库更新成功之后再删除缓存。

  • 多级缓存之间如何同步数据呢?
    常见方案是通过消息队列通知的方式,就是在数据库更新后,通过事务性消息队列加监听的方式,失效对应的缓存。
    比如通过给数据添加版本号,或者通过时间戳 + 业务主键的方式,控制缓存的数据版本实现最终一致性。

  • redis分布式事务锁机制

    redis启动事务:multi
    回滚事务:discard
    提交事务:exec
    

    1.redis中它会用一个队列来保存用户的事务操作,当你exec提交事务后它会按照顺序来执行每一条语句。当你启动事务,每执行一个操作,它并不是真正的执行,而是暂时放在这个队列中,等待事务的提交。提交事务后执行时中间有一个语句出错的话,会将所有的事务取消
    2.redis中,它默认使用的是乐观锁,每次更新数据都要判断是否被其他事务修改过,如果有的话正在提交的事务会回滚。

  • 利用golang+redis怎么实现延时队列
    利用zadd将数据添加到zset中,每个数据的score值设置为数据的延时时间+当前时间戳,后台goroutine不断zrange轮询zset,取出score值小于当前时间戳的数据,然后再对数据进一步处理,这样就实现了简单延时队列的功能。
    Zrange 返回zset中,指定区间内的成员。zset成员的位置按分数值递增(从小到大)来排序。不同的是每个元素都会关联一个double类型的分数。reids正是通过分数来为集合中的成员进行从小到大的排序,zset的成员是唯一的,但分数(score)却可以重复

  • redis消息队列怎么用
    利用的Redis的列表(lists)数据结构。比较好的使用模式是,生产者lpush消息,消费者lpop消息,并设定超时时间(但是相对简单,没有ack机制,如果消息取出来的话 消费失败了 依靠记录日志或者重新Push到队列里面)

  • redis实现计数器的应用
    1.incr方法 可以自增。同时使用MULTI和EXEC命令,将递增操作和设置过期时间的操作放在了一个事务中, 从而保证了两个操作的原子性。

  • redis 一些操作
    哈希:HMSET,HGET List(列表):lpush 往里推 lrange 往外拿 Set:sadd key member 往里推 smembers key 往外拿 ;zset(有序集合):zadd key score value 往里推 ZRANGEBYSCORE key 往外拿

  • redis批量命令
    1.批量get/set(multi get/set) mget mset hmget hmset(适用hash)
    2.管道(pipelining)可以一次性发送多条命令并在执行完后一次性将结果返回,pipeline通过减少客户端与redis的通信次数来实现降低往返延时时间
    3.事务

  • 布隆过滤器
    解决缓存穿透问题:当一个查询请求过来时,先经过布隆过滤器进行查,如果判断请求查询值存在,则继续查;如果判断请求查询不存在,直接丢弃。
    原理它本身是一个很长的二进制向量,存放的不是0,就是1;
    就是一个对一个key进行k个hash算法获取k个值,在比特数组中将这k个值散列后设定为1,然后查的时候如果特定的这几个位置都为1,那么布隆过滤器判断该key存在。
    布隆过滤器可能会误判,如果它说不存在那肯定不存在,如果它说存在,那数据有可能实际不存在
    布隆过滤器另一个用途——推荐去重
    如果历史记录存储在关系数据库里,去重就需要频繁地对数据库进行 exists 查询。如果使用缓存把历史记录都放入缓存里,占用空间太大明显不现实。布隆过滤器就登场了,它就是专门用来解决这种去重问题的。它在起到去重的同时,在空间上还能节省 90% 以上,只是稍微有那么点不精确,也就是有一定的误判概率。

  • 从海量数据里查询某一固定前缀的key
    用 scan

    scan  0 match k1* count 10 //每次十行
      k1524564
      k1548423
      k1201778		
    

Docker

  • cmd与run,ENTRYPOINT区别
    两者都是用于执行命令,区别在于执行命令的时机不同,RUN命令适用于在 docker build 构建docker镜像时执行的命令,而CMD命令是在 docker run 执行docker镜像构建容器时使用,可以动态的覆盖CMD执行的命令。
    CMD命令是用于默认执行的,且如果写了多条CMD命令,则只会执行最后一条,如果后续存在ENTRYPOINT命令,则CMD命令或被充当参数或者覆盖,而且Dockerfile中的CMD命令最终可以被在执行 docker run命令时添加的命令所覆盖。而ENTRYPOINT命令则是一定会执行的

  • Redis通信协议
    RESP 是redis客户端和服务端之前使用的一种通讯协议,RESP 的特点:实现简单、快速解析、可读性好
    优势在于实现异常简单,解析性能极好

  • Redis 有哪些架构模式?
    1.单机版
    2主从复制
    3哨兵:能在主服务器下线时自动进行故障转移

    监控: Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
    提醒: 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
    自动故障迁移: 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作。
    

    4集群(proxy 型)
    在这里插入图片描述
    5集群(直连型)cluster模式
    在这里插入图片描述
    特点:
    1、无中心架构(不存在哪个节点影响性能瓶颈),每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。少了 proxy 层。
    2、数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布。
    3、高可用性,部分节点不可用时,集群仍可用。

  • 一致性哈希算法和哈希槽
    一致性哈希算法,其实就是解决了这里面的水平分库分表 存取规则 的问题,有了这个一致性哈希算法,我们能够准确的知道我们要取的数据落在哪个机器的哪个数据库中。
    其实哈希槽的本质和一致性哈希算法非常相似,不同点就是对于哈希空间的定义。一致性哈希的空间是一个圆环,节点分布是基于圆环的,无法很好的控制数据分布,可能会产生数据倾斜问题。而 Redis 的槽位空间是自定义分配的,类似于 Windows 盘分区的概念。这种分区是可以自定义大小,自定义位置的。Redis 集群包含了 16384 个哈希槽,每个 Key 经过计算后会落在一个具体的槽位上,而槽位具体在哪个机器上是用户自己根据自己机器的情况配置的,机器硬盘小的可以分配少一点槽位,硬盘大的可以分配多一点。如果节点硬盘都差不多则可以平均分配。所以哈希槽这种概念很好地解决了一致性哈希的弊端。

  • redis分布式锁
    锁的实现主要基于redis的SETNX命令

    SETNX key value
    将 key 的值设为 value ,当且仅当 key 不存在。
    若给定的 key 已经存在,则 SETNX 不做任何动作。
    SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。
    
  • Redis做异步队列
    一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。
    能不能生产一次消费多次呢?
    使用pub/sub主题订阅者模式,可以实现1:N的消息队列

  • 缓存雪崩避免?
    1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
    2:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期
    3:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

消息队列

  • 为什么用消息队列
    1、 解耦 2.异步 3。削峰

  • 消息队列通信的模式
    1.点对点模式
    点对点模式通常是基于拉取或者轮询的消息传送模型,这个模型的特点是发送到队列的消息被一个且只有一个消费者进行处理。生产者将消息放入消息队列后,由消费者主动的去拉取消息进行消费。
    2.发布订阅模式
    发布订阅模式是一个基于消息送的消息传送模型,改模型可以有多种不同的订阅者。生产者将消息放入消息队列后,队列会将消息推送给订阅过该类消息的消费者(类似微信公众号)。由于是消费者被动接收推送,所以无需感知消息队列是否有待消费的消息!但是consumer1、consumer2、consumer3由于机器性能不一样,所以处理消息的能力也会不一样,所以会出现资源的浪费

  • 什么是kafka在这里插入图片描述

  • kafka为什么要做分区呢?

    1.方便扩展。因为一个topic可以有多个partition,所以可以通过扩展机器去轻松的应对日益增长的数据量。
    2 . 提高并发。以partition为读写单位,可以多个消费者同时消费数据,提高了消息的处理效率。

  • 如果某个topic有多个partition,producer又怎么知道该将数据发往哪个partition呢?
    在这里插入图片描述

  • 那producer在向kafka写入消息的时候,怎么保证消息不丢失呢?!!!重要
    在这里插入图片描述

  • Partition 结构
    Partition在服务器上的表现形式就是一个一个的文件夹,每个partition的文件夹下面会有多组segment文件,每组segment文件又包含.index文件、.log文件、.timeindex文件(早期版本中没有)三个文件, log文件就实际是存储message的地方,而index和timeindex文件为索引文件,用于检索消息。
    kafka就是利用分段+索引的方式来解决查找效率的问题。

  • Message存储策略
    无论消息是否被消费,kafka都会保存所有的消息。那对于旧数据有什么删除策略呢?
      1、 基于时间,默认配置是168小时(7天)。
      2、 基于大小,默认配置是1073741824。
      需要注意的是,kafka读取特定消息的时间复杂度是O(1),所以这里删除过期的文件并不会提高kafka的性能!

  • 建议消费者组的consumer的数量与partition的数量一致!
    消费者组内的消费者小于partition数量的情况,所以会出现某个消费者消费多个partition数据的情况。
    如果是消费者组的消费者多于partition的数量,那会不会出现多个消费者消费同一个partition的数据呢?上面已经提到过不会出现这种情况!多出来的消费者不消费任何partition的数据。

  • kafka是怎么查找数据的??
    partition划分为多组segment,每个segment又包含.log、.index、.timeindex文件,log文件就实际是存储message的地方存放的每条message包含offset、消息大小、消息体……我们多次提到segment和offset,查找消息的时候是怎么利用segment+offset配合查找的呢?
    offset:offset是一个占8byte的有序id号,它可以唯一确定每条消息在parition内的位置!
    假如现在需要查找一个offset为368801的message是什么样的过程呢?
    1、 先找到offset的368801message所在的segment文件(利用二分法查找)
    2、 打开找到的segment中的.index文件。该文件采用的是稀疏索引的方式存储着相对offset及对应message物理偏移量的关系
    3、 根据找到的相对offset为4的索引确定message存储的物理偏移位置为256。打开数据文件,从位置为256的那个地方开始顺序扫描直到找到offset为368801的那条Message。
    这套机制是建立在offset为有序的基础上,利用segment+有序offset+稀疏索引+二分查找+顺序查找等多种手段来高效的查找数据!

  • kafka是pull还是push
    producer将消息推送到broker,consumer从broker拉取消息。

  • 什么是稀疏索引在这里插入图片描述

  • 高并发怎么保证接口幂等
    1.前端:让用户只点击一次,比如点击后按钮变灰,或用loading显示
    2.后端:使用唯一索引
    对业务关键字段建立唯一索引,这样当数据重复时,让数据抛异常
    防重表
    多在数据库中增加一个表,用于防重

  • kafka中的broker 是干什么的
    broker 是消息的代理,Producers往Brokers里面的指定Topic中写消息,Consumers从Brokers里面拉取指定Topic的消息,然后进行业务处理,broker在中间起到一个代理保存消息的中转站。

  • zookeeper在kafka中的作用
    Kafka将元数据信息保存在Zookeeper中,但是发送给Topic本身的数据是不会发到Zk上的,否则Zk就疯了。kafka使用zookeeper来实现动态的集群扩展,不需要更改客户端(producer和consumer)的配置。broker会在zookeeper注册并保持相关的元数据(topic,partition信息等)更新。而客户端会在zookeeper上注册相关的watcher。一旦zookeeper发生变化,客户端能及时感知并作出相应调整。这样就保证了添加或去除broker时,各broker间仍能自动实现负载均衡
    绕过Zookeeper并直接连接到Kafka服务器是不可能的,所以没有ZooKeeper不可以使用Kafka

  • 消费者组到底是什么?
    消费者组,其实就是一组 消费者 的集合,
    消费者组是kafka提供的可扩展且具有容错性的消费者机制。既然是一个组,那么组内必然可以有多个消费者和消费者实列,他们共享一个公共的ID,这个ID被称为GroupID。组内的消费者协调在一起消费订阅主题的所有分区。当然,每个分区只能由同一个消费者组内的一个Consumer实列来消费。
    消费者组之间批次独立,互不影响,他们能订阅相同的主题而互不干涉。kafka仅仅使用消费者组这一种机制,却实现了传统消息引擎系统的俩大模型:如果所有实列属于同一个Group,那么它实现的就是消息队列模型;如果所有实列分别属于不同的Group,那么他实现的就是发布/订阅模型。
    在这里插入图片描述
    在这里插入图片描述

  • 消费组的好处
    1.高性能在这里插入图片描述
    2.消费模式灵活
    在这里插入图片描述
    3.故障容灾

  • 分区分配消费者过程?
    在这里插入图片描述

  • 领导者和追随者的概念
    在Kafka的每个分区中,都有一个服务器充当领导者,0到多个服务器充当追随者的角色。
    Kafka 副本当前分为领导者副本和追随者副本。只有 Leader 副本才能对外提供读写服务,响应 Clients 端的请求。Follower 副本只是采用拉(PULL)的方式,被动地同步 Leader 副本中的数据,并且在 Leader 副本所在的 Broker 宕机后,随时准备应聘 Leader 副本。

  • kafka怎么保证高并发的?
    1,做的是linux系统的页缓存技术

    2,磁盘的顺序写

    3,零拷贝技术

在这里插入图片描述
在这里插入图片描述
零拷贝并不是不需要拷贝,而是减少不必要的拷贝次数。通常是说在IO读写过程中。
底层的网卡驱动程序直接读取内核缓存区的数据并发送到网络。在整个过程中,只发生了2次数据拷贝。一次是从磁盘到内核缓存区,另一次是从内核缓存区到网络。既然有发生数据拷贝,为什么还叫“零拷贝”,那是因为所说的零拷贝是指数据在内存中没有发生数据拷贝。

  • 消息是否按照时间有序,kafka分区的数据是否有序,如何保证有序
    保证有序的两种方案:
    在这里插入图片描述
  • kafka会消息重复消费吗
    offset: 一个连续的用于定位被追加到分区的每一个消息的序列号。
    kafka的重复消费问题究其底层根本原因就是:已经消费了数据,但是offset没提交(kafka没有或者不知道该数据已经被消费)。 基于这种原因总结以下几个易造成重复消费的配置:
    原因1:强行kill线程,导致消费后的数据,offset没有提交(消费系统宕机、重启等)。
    原因2:设置offset为自动提交,关闭kafka时,如果在close之前,调用 consumer.unsubscribe() 则有可能部分offset没提交,下次重启会重复消费。
    原因3:(重复消费最常见的原因):消费后的数据,当offset还没有提交时,partition就断开连接。比如,通常会遇到消费的数据,处理很耗时,导致超过了Kafka的session timeout时间,那么就会re-blance重平衡,此时有一定几率offset没提交,会导致重平衡后重复消费。
  • kafka为什么这么快
  • 为什么选用kafka

Redis

  • Redis支持的数据类型?
    String 哈希 list 集合 有序集合
  • Redis 有哪些架构模式?讲讲各自的特点
    1.单机模式
    2.主从复制
    Redis 的复制功能允许用户根据一个 Redis 服务器来创建任意多个该服务器的复制品,其中被复制的服务器为主服务器,而通过复制创建出来的服务器复制品则为从服务器。 只要主从服务器之间的网络连接正常,主从服务器两者会具有相同的数据,主服务器就会一直将发生在自己身上的数据更新同步 给从服务器,从而一直保证主从服务器的数据相同。
    3.哨兵
    在这里插入图片描述4.集群
  • Redis做异步队列么
    一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。
  • 什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?
    一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。
    如何避免?
    1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。
    2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。
    缓存雪崩
    当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。导致系统崩溃。
    如何避免?
    1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
    2:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期
    3:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
  • Redis特点
    与传统数据库不同的是 Redis 的数据是存在内存中的,所以读写速度非常快,
  • Redis为什么这么快
    1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速
    2、数据结构简单,对数据操作也简单
    3、使用多路 I/O 复用模型,非阻塞 IO
  • 事务管理(ACID)在这里插入图片描述
  • 高可用,分布式,DevOps是什么意思
    高可用:高可用是bai系统架构设计中必须考虑的因zhi素之一,dao它通常是指,通过设计zhuan减少系统不能提shu供服务的时间。如果一台系统能够不间断的提供服务,那么这台系统的可用性据说100%。那如果系统每运行100个时间单位,就会出现1个时间单位无法提供服务,那么该台系统的可用性是99%。目前大部分企业的高可用目标是4个9,也就是99.99%,也就是允许这台系统的年停机时间为52.56分钟。

分布式:简单来说分布式就是将一个系统的各个组件(MySQL、PHP、Apache …)分布在网络上的各台主机, 并且各组件之间仅通过消息传递来通信并协调工作。
分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据。
高并发是一种系统运行过程中遇到的一种“短时间内遇到大量操作请求”的情况,主要发生在web系统集中大量访问收到大量请求(例如:12306的抢票情况;天猫双十一活动)。该情况的发生会导致系统在这段时间内执行大量操作,例如对资源的请求,数据库的操作等。在这里插入图片描述Devops是“开发”与“运维”的缩写,它定义了一组流程,这些流程通过在开发和运维团队之间进行协作带来组织文化上的转变,
DevOps带来更高水平的协作和速度,使组织提高生产力,降低运营成本以有效地为客户提供服务并保持市场竞争力。

  • kafka怎么实现高并发(kafka为什么这么快)
    1.页缓存技术 + 磁盘顺序写
    Kafka对消息的存储和缓存依赖于文件系统,每次接收数据都会往磁盘上写,Kafka就是基于页缓存技术 + 磁盘顺序写 技术实现了写入数据的超高性能。
    操作系统本身有一层缓存,叫做page cache,是在内存里的缓存,我们也可以称之为os cache,意思就是操作系统自己管理的缓存。
    你在写磁盘文件的时候,可以直接写入os cache 中,也就是仅仅写入内存中,接下来由操作系统自己决定什么时候把os cache 里的数据真的刷入到磁盘中。
    通过这种方式可以将磁盘文件的写性能提升很多,其实这种方式相当于写内存,不是在写磁盘

    2.零拷贝技术
    从Kafka里我们经常要消费数据,那么消费的时候实际上就是要从kafka的磁盘文件里读取某条数据然后发送给下游的消费者
    Kafka 为了解决拷贝耗费性能这个问题,在读数据的时候是引入零拷贝技术。也就是说,直接让操作系统的cache中的数据发送到网卡后传出给下游的消费者
    那么对于零拷贝而言,并非真的是完全没有数据拷贝的过程,只不过是减少用户态和内核态的切换次数以及CPU拷贝的次数。

  • kafka怎么实现高可用
    1.HA机制
    提供了HA机制,就是replica副本机制。每个partition的数据都会同步到其他机器上,形成自己的多个replica副本。
    kafka的这种机制,就有所谓的高可用性了,因为如果某个broker宕机了,也没事儿,因为那个broker上面的partition在其他机器上都有副本的,那么此时会重新选举一个新的leader出来,大家继续读写那个新的leader即可。这就有所谓的高可用性了。
    在这里插入图片描述
    操作系统linux

  • linux惊群效应?
    惊群效应也叫雷鸣群体效应,简言之,就是多进程(线程)在同时阻塞等待同一个事件的时候(休眠状态),如果等待的这个事件发生,那么他会唤醒等待的所有进程(线程), 但是最终只可能有一个进程(线程)获得这个时间的"控制权",对该事件进行处理,而其他进程(线程)获得"控制权"失败,只能重新进入休眠状态,这种现象和性能浪费叫做惊群
    具体浪费了什么:
    (1)、系统对用户进程/线程频繁地做无效的调度,上下文切换系统性能大打折扣。
    (2)、为了确保只有一个线程得到资源,用户必须对资源操作进行加锁保护,进一步加大了系统开销。

  • Linux I/O模型一共有哪些?
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • 同步与异步的区别是什么?
    同步与异步的区别在于调用结果的通知方式上。 同步执行一个方法后,需要等待结果返回,然后继续执行下去。 异步执行一个方法后,不会等待结果的返回,调用方定时主动去轮询调用结果或者被调用方在执行完成后通过回调来通知调用方

  • 常用的负载均衡算法
    1.轮询法
    轮询法基本上算是最简单的负载均衡算法了,他的思想就是不管啥情况,对所有的服务器节点全部按顺序来,将请求按照顺序轮流地分配到各个服务器上。这种算法会使每台服务器处理的请求是相同的,所以适合用于服务器硬件条件基本都相同的情况。
    2.加权轮询法
    在轮询算法的基础上添加了权重的条件,让那些强悍的机器优先并多处理一些请求
    3.随机法
    这种算法基本思想很简单,随机生成一个数字(或者随机挑一个IP地址)出来,然后挑到谁就是谁,当然,如果随机数是等概况生成的,那时间长了,基本上跟轮询算法没有什么区别,区别最主要的还是在顺序上,随机算法没有那么严格的顺序。
    4.加权随机法
    5.最小连接法
    哪个服务器的连接数少,就分配给哪个服务器新的请求
    6.源地址哈希法
    源地址哈希法可以把客户端的IP地址拿出来,然后计算出IP地址的hash值,hash值是一个很大的正整数

  • 哈希算法(散列算法)介绍
    在这里插入图片描述

  • 用户态和内核态区别
    内核态与用户态是操作系统的两种运行级别,当程序运行在3级特权级上时,就可以称之为运行在用户态。因为这是最低特权级,是普通的用户进程运行的特权级,大部分用户直接面对的程序都是运行在用户态;

    当程序运行在0级特权级上时,就可以称之为运行在内核态。

    内核态:运行操作系统程序,操作硬件
    用户态:运行用户程序
    特权级别:R0、R1、R2和R3
    R0相当于内核态,R3相当于用户态
    在这里插入图片描述

  • linux sed iptables命令
    Linux sed 命令是利用脚本来处理文本文件。
    sed 可依照脚本的指令来处理、编辑文本文件
    iptables是一些防火墙规则

  • 什么是页面置换
    因为在地址映射过程中 如果发现要访问的页面不在内存中 会产生缺页中断,当发生此现象的时候 如果操作系统内存中没有空余 则操作系统必须在内存里面选择一个页面将其移出内存 所以这个如何选择是哪一个页面的算法被称为页面置换算法。
    最简单的页面置换算法是先入先出(FIFO)法。这种算法的实质是,总是选择在主存中停留时间最长(即最老)的一页置换,即先进入内存的页,先退出内存。
    LRU即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰

网络TCPUDPNETWORK

  • TCP粘包问题怎么解决
    在socket网络编程中,都是端到端通信,由客户端端口+服务端端口+客户端IP+服务端IP+传输协议组成的五元组可以明确的标识一条连接。在TCP的socket编程中,发送端和接收端都有成对的socket。发送端为了将多个发往接收端的包,更加高效的的发给接收端,于是采用了优化算法(Nagle算法),将多次间隔较小、数据量较小的数据,合并成一个数据量大的数据块,然后进行封包。那么这样一来,接收端就必须使用高效科学的拆包机制来分辨这些数据。
    TCP粘包就是指发送方发送的若干包数据到达接收方时粘成了一包,从接收缓冲区来看,后一包数据的头紧接着前一包数据的尾,出现粘包的原因是多方面的,可能是来自发送方,也可能是来自接收方。
    如何处理粘包?
    1.对于发送方造成的粘包问题,可以通过关闭Nagle算法来解决
    2.循环处理,应用程序从接收缓存中读取分组时,读完一条数据,就应该循环读取下一条数据,直到所有数据都被处理完成,但是如何判断每条数据的长度呢?可以让每条数据有规定格式 如开头末尾
    3.UDP则是面向消息传输的,是有保护消息边界的,接收方一次只接受一条独立的信息,所以不存在粘包问题。

  • 401,403区别
    401,表示发送的请求需要有通过 HTTP 认证的认证信息
    403,表示对请求资源的访问被服务器拒绝
    500,表示服务器端在执行请求时发生了错误
    503,表明服务器暂时处于超负载或正在停机维护,无法处理请求
    206,进行范围请求
    301,永久性重定向,表示资源已被分配了新的 URL

  • http能不能一次连接多次请求,不等后端返回,如果可以,怎么区分这多个请求的响应的
    http本质上是使用socket连接,因此发送请求,接写入tcp缓冲,是可以多次进行的,这也是http是无状态的原因
    HTTP2.0 增加了多路复用,增加了一个帧的概念,通过一次TCP连接,可以把多个HTTP请求封装到不同的帧,发送到服务端,服务器分别对请求做出响应,客户端收到响应后,根据帧的标识,分别交给请求发起者

  • 死锁的四个条件是:
    1.互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
    2.请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
    3.不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。
    4.循环等待条件: 若干进程间形成首尾相接循环等待资源的关系

  • tcp time_wait的作用
    4次握手的最后一个ACK是是由主动关闭方发送出去的,若这个ACK丢失,被动关闭方会再次发一个FIN过来。若主动关闭方能够保持一个2MSL的TIME_WAIT状态,则有更大的机会让丢失的ACK被再次发送出去。

  • 线程,进程调度算法
    1.先来先服务调度算法(FCFS)每次调度都是从后备作业队列中选择一个或多个最先进入该队列的作业
    2.短作业(进程)优先调度算法(SJPF):是指对短作业或短进程优先调度的算法。它们可以分别用于作业调度和进程调度。短作业优先(SJF)的调度算法是从后备队列中选择一个或若干个估计运行时间最短的作业,将它们调入内存运行
    3.高优先权优先调度算法:为了照顾紧迫型作业,使之在进入系统后便获得优先处理,引入了最高优先权优先(FPF)调度算法。

  • fork() exec()作用,区别
    1.当用户敲入命令执行一个程序的时候,对系统而言,它将启动一个进程。但和程序不同的是,在这个进程中,系统可能需要再启动一个或多个进程来完成独立的多个任务
    2.Linux下一个进程在内存里有三部分的数据,就是"代码段"、“堆栈段"和"数据段”
    3.有两个基本的操作用于创建和修改进程:函数fork( )用来创建一个新的进程,该进程几乎是当前进程的一个完全拷贝;函数族exec( )用来启动另外的进程以取代当前运行的进程。
    4.一个进程一旦调用exec类函数,它本身就"死亡"了,系统把代码段替换成新的程序的代码,废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,也就是说,对系统而言,还是同一个进程,不过已经是另一个程序了。

  • 进程间的通信
    管道、消息队列、共享内存、信号量、套接口(socket)

  • tcp窗口的概念
    滑动窗口实现了TCP流控制。首先明确滑动窗口的范畴:TCP是双工的协议,会话的双方都可以同时接收和发送数据。TCP会话的双方都各自维护一个发送窗口和一个接收窗口。各自的接收窗口大小取决于应用、系统、硬件的限制。滑动窗口解决的是流量控制的的问题
    2.滑动机制
    a.发送窗口只有收到发送窗口内字节的ACK确认,才会移动发送窗口的左边界。
    b.接收窗口只有在前面所有的段都确认的情况下才会移动左边界

  • 流量控制策略之RateLimit
    常用的限流算法有两种:漏桶算法和令牌桶算法
    漏桶算法思路很简单,请求先进入到漏桶里,漏桶以一定的速度出水,当水请求过大会直接溢出,可以看出漏桶算法能强行限制数据的传输速率。
    google开源工具包提供了限流工具类RateLimiter,该类基于“令牌桶算法”

  • TCP为什么是三次握手 四次挥手
    三次握手:三次握手的目的是 为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误
    在这里插入图片描述在这里插入图片描述四次挥手:

    (1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
    (2)第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
    (3)第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
    (4)第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
    在这里插入图片描述

3.为什么第二次,第三次挥手不一起发

但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭 SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步挥手。

time_wait作用

TIME_WAIT在四次挥手中有着不可替代的位置,如果没有TIME-WAIT,主动方就会直接进入CLOSED状态,(假设主动方时客户端,被动方时服务端)
这时候如果立即重启客户端使用相同的端口,如果因为网络中种种原因最后一次ACK丢失了,服务端就会重复FIN请求,这时这个FIN就会被重新启动的客户端接收到,或者新启动的客户端向服务端发起请求的时候,因为服务端正在等待最后一次ACK,因此新连接请求发送的SYN就会被服务端认为时请求码错误,服务端就会回复RET重置连接。
所以就需要主动方发送最后一次ACK之后进入TIME_WAIT状态,等待2MSL(两个报文最大生命周期),等待这段时间就是为了如果接收到了重发的FIN请求能够进行最后一次ACK回复,让在网络中延迟的FIN/ACK数据都消失在网络中,不会对后续连接造成影响

  • tcp连接时客户端突然挂掉了怎么办?
    在这里插入图片描述

  • 三次握手建立连接时突然挂掉怎么办
    初始化连接的 SYN 超时问题Client发送SYN包给Server后挂了,Server回给Client的SYN-ACK一直没收到Client的ACK确认,这个时候这个连接既没建立起来,也不能算失败。
    这就需要一个超时时间让Server将这个连接断开,否则这个连接就会一直占用Server的SYN连接队列中的一个位置,大量这样的连接就会将Server的SYN连接队列耗尽,让正常的连接无法得到处理。
    目前,Linux下默认会进行5次重发SYN-ACK包,总共需要 63s,TCP才会把断开这个连接。
    由于,SYN超时需要63秒,那么就给攻击者一个攻击服务器的机会,攻击者在短时间内发送大量的SYN包给Server(俗称SYN flood攻击),用于耗尽Server的SYN队列。

  • SYN攻击
    SYN 攻击指的是,攻击客户端在短时间内伪造大量不存在的IP地址,向服务器不断地发送SYN包,服务器回复确认包,并等待客户的确认。这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,导致目标系统运行缓慢,SYN 攻击是一种典型的 DoS攻击。
    检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的netstats 命令来检测 SYN 攻击。
    在这里插入图片描述

  • 什么半连接什么是全链接
    在tcp第一次握手后,会把链接放入半连接队列中,第三次握手结束后,会放入全连接队列中.
    1.多路复用,即连接共享,即每一个request都是是用作连接共享机制的。
    2.header压缩
    3.服务端推送,HTTP2.0也具有server push功能。

  • http1.1和http2.0区别
    HTTP2.0和HTTP1.X相比的新特性:

算法 数据结构

  • 排序算法在这里插入图片描述
    在这里插入图片描述

1.归并排序
将一个大的无序数组有序,我们可以把大的数组分成两个,然后对这两个数组分别进行排序,之后在把这两个数组合并成一个有序的数组。由于两个小的数组都是有序的,所以在合并的时候是很快的。
通过递归的方式将大的数组一直分割,直到数组的大小为 1,此时只有一个元素,那么该数组就是有序的了,之后再把两个数组大小为1的合并成一个大小为2的,再把两个大小为2的合并成4的 … 直到全部小的数组合并起来。
2.快速排序
我们从数组中选择一个元素,我们把这个元素称之为中轴元素吧,然后把数组中所有小于中轴元素的元素放在其左边,所有大于或等于中轴元素的元素放在其右边,显然,此时中轴元素所处的位置的是有序的。也就是说,我们无需再移动中轴元素的位置。
从中轴元素那里开始把大的数组切割成两个小的数组(两个数组都不包含中轴元素),接着我们通过递归的方式,让中轴元素左边的数组和右边的数组也重复同样的操作,直到数组的大小为1,此时每个元素都处于有序的位置。
3.基数排序
先以个位数的大小来对数据进行排序,接着以十位数的大小来多数进行排序,接着以百位数的大小…排到最后,就是一组有序的元素了。

  • 判断链表是否有回环
    使用快慢指针,慢指针每次只前进一步,快指针每次前进两步,直到慢指针遇上快指针。如果两个指针相等,说明有回环
  • 发转链表的实现
  • 在这里插入图片描述

git

  • git文件版本,使用顺序,merge跟rebase
    1.采用merge和rebase后,git log的区别,merge命令不会保留merge的分支的commit:
    在这里插入图片描述

  • redis热点key怎么处理
    redis上的某个特定key的访问数量过于集中。
    解决方案:
    1.使用二级缓存,可以使用 guava-cache或hcache,发现热点key之后,将这些热点key加载到JVM中作为本地缓存。访问这些key时直接从本地缓存获取即可,不会直接访问到redis层了,有效的保护了缓存服务器。
    2.备份(不建议),把热点key在多个redis上都存一份,当有热key请求进来的时候,在redis中随机选取一台,进行访问取值,返回数据。但是这种情况维护代价非常大,假设有100个备份KEY,那么在删除或者更新时,也需要更新100个KEY,所以这种方案不是很推荐。

  • 一致性hash算法(解决服务器负载均衡方案)
    在这里插入图片描述

  • rehash (重新散列)是什么
    rehash是在hash table哈希表的大小不能满足需求,造成过多hash碰撞后需要进行的扩容hash table的操作,其实通常的做法确实是建立一个额外的hash table,将原来的hash table中的数据在新的数据中进行重新输入,从而生成新的hash表。

mysql 数据库

  • 如何分库分表
    1)垂直分表

    也就是“大表拆小表”,基于列字段进行的。一般是表中的字段较多,将不常用的, 数据较大,长度较长(比如text类型字段)的拆分到“扩展表“。一般是针对那种几百列的大表,也避免查询时,数据量太大造成的“跨页”问题。

    2)垂直分库

    垂直分库针对的是一个系统中的不同业务进行拆分,比如用户User一个库,商品Producet一个库,订单Order一个库。切分后,要放在多个服务器上,提高性能。

    3)水平分库分表

    将单张表的数据切分到多个服务器上去,每个服务器具有相应的库与表,只是表中数据集合不同。水平分库分表能够有效的缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源等的瓶颈。

  • 开发的标准流程

在这里插入图片描述

  • 读写锁和互斥锁区别
    互斥:
    1.互斥锁有两种操作,获取锁和释放锁
    2.当有一个goroutine获取了互斥锁后,任何goroutine都不可以获取互斥锁,只能等待这个goroutine将互斥锁释放
    3.互斥锁适用于读写操作数量差不多的情况
    读写:
    当有一个goroutine获得写锁时,其他goroutine不可以获得读锁或者写锁,直到这个写锁释放
    当有一个goroutine获得读锁时,其他goroutine可以获得读锁,但是不能获得写锁。

  • 你用过mysql那些存储引擎,他们都有什么特点和区别?
    MyISAM:默认表类型它是存储记录和文件的标准方法。不是事务安全的,而且不支持外键,如果执行大量的select,insert MyISAM比较适合
    InnoDB:支持事务安全的引擎,支持外键、行锁、事务是他的最大特点。如果有大量的update和insert,建议使用InnoDB

    2.InnoDB是聚集索引,使用B+Tree作为索引结构,数据文件是和(主键)索引绑在一起的(表数据文件本身就是按B+Tree组织的一个索引结构),必须要有主键,通过主键索引效率很高
    3.MyISAM是非聚集索引,也是使用B+Tree作为索引结构,索引和数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
    4.Innodb不支持全文索引,而MyISAM支持全文索引,查询效率上MyISAM要高
    5.MyISAM 强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持,MyISAM更适合读密集的表,而InnoDB更适合写密集的的表。

  • SQL优化
    1.使用EXPLAIN关键词检查SQL。EXPLAIN可以帮你分析你的查询语句或是表结构的性能瓶颈
    2,查询的条件尽量使用索引字段,如某一个表有多个条件,就尽量使用复合索引查询
    3,多表关联尽量用join,减少子查询的使用 尽量使用limit进行分页批量查询,不要一次全部获取。

  • 大表数据查询 怎么优化
    1.优化shema、sql语句+索引;
    2.第二加缓存,redis;
    3.主从复制,读写分离;主库负责写,从库负责读;
    3.限定数据的范围: 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内。
    4.垂直分区,简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表

  • 水平分区: 保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。举个例子:我们可以将用户信息表拆分成多个用户信息表,这样就可以避免单一表数据量过大对性能造成影响。

  • 事务的并发问题

    (1)脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

    (2)不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果因此本事务先后两次读到的数据结果会不一致。

    (3)幻读:幻读解决了不重复读,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。

    幻读定义:事务A 按照一定条件进行数据读取, 期间事务B 插入了相同搜索条件的新数据,
    事务A再次按照原先条件进行读取时,发现了事务B 新插入的数据 称为幻读
    表现:一个事务在前后两次查询同一范围的时候,后一次查询看到了前一次查询没有看到的行。
    解决:将两行记录间的空隙加上锁,阻止新记录的插入;这个锁称为间隙锁
    
  • 索引失效的场景及原因
    1.前导模糊查询不能利用索引(like '%XX’或者like ‘%XX%’):不能利用索引的顺序,必须一个个去找,看是否满足条件。这样会导致全索引扫描或者全表扫描
    字符串在B+树里面存储的时候,它也是按照字母的大小去排序。首先按照第一个字母去比较,如果第一个字母相同则按照第二个字母去比较和最佳左前缀法则相似。如果左边用了%,那后面的字符是无序的,此时就不能使用二分查找来定位元素还是退化为了全表扫描。

    2.如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引

  • Mysql中的索引查询为什么使用了B+树结构,而不使用哈希索引或者B树?
    1.哈希值是无序的,不能够进行范围查找。
    2.B树的最大特点是一个节点可以存储多个值,这样可以使得树的高度变矮,从而使得树的查找速度变快。但是其也存在回旋查找的问题。比如说当存在范围查询>5的时候定位到该元素之后还得回溯到前面的节点元素6,7
    B+树则解决了这个问题,它的非叶子节点存储的是key,其叶子节点既存储了key也存储了value并且其叶子节点是有序的,节点之间用指针相连也正是因为这一点使得B+树在范围查询的时候不存在回旋问题。
    3.范围查询右边失效原理

    select * from testTable where a>1 and b=2
    

    首先a字段在B+树上是有序的,所以可以用二分查找法定位到1,然后将所有大于1的数据取出来,a可以用到索引。b有序的前提是a是确定的值,那么现在a的值是取大于1的,可能有10个大于1的a,也可能有一百个a。大于1的a那部分的B+树里,b字段是无序的,所以b不能在无序的B+树里用二分查找来查询,b用不到索引。

  • 优化mysql的sql语句
    1.否则将引擎放弃使用索引而进行全表扫描的情况:
    a.应尽量避免在 where 子句中对字段进行 null 值 判断;where num is null可改为where num=0
    b.应尽量避免在 where 子句中使用 or 来连接条件
    2.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引

  • 事务隔离级别
    在这里插入图片描述
    1.读未提交:就是一个事务可以读取另一个未提交事务的数据。
    2.读提交,就是一个事务要等另一个事务提交后才能读取它的数据,否则是读取不到另外一个事务的更改的。
    3.可重复读,就是在开始读取数据(事务开启)时,不再允许修改操作
    4.可串行化 就是解决幻读问题的,可重复读是行级锁,而可串行化是表级锁,把整张表锁住了
    mysql默认的事务隔离级别是可重复读

  • mysql主从复制是怎么做到的

    1.主服务器将对数据的操作都记录到二进制日志中。
    2.从服务器将二进制日志拷贝到其中继日志中
    3.从服务器重做中继日志里面的事件,更新从服务器里面的数据与主服务器达到数据一致。
    
  • explain关键字
    explain被称为执行计划,如果在select语句前放上关键词explain,mysql将解释它如何处理select,提供有关表如何联接和联接的次序。

  • mysql索引区别
    MySQL中用较多的索引有Hash索引,B+树索引等,而经常使用的InnoDB存储引擎默认索引实现为:B+树索引.
    1.hash索引底层是hash表,进行查找时,调用一次hash函数就可获取到相应的键值,之后进行回表查询获得实际数据.B+树底层实现是多路平衡查找树.对于每一次的查询都是从根节点出发,查找到叶子节点方可以获得所查键值
    2.所以hash索引进行等值查询更快,但是却无法进行范围查询.而B+树的的所有节点皆遵循(左节点小于父节点,右节点大于父节点),天然支持范围.
    3.hash索引不支持使用索引进行排序

  • mysql什么时候不需要回表查询数据?
    在B+树的索引中,叶子节点可能存储了当前的key值,也可能存储了当前的key值以及整行的数据,这就是聚簇索引和非聚簇索引. 在InnoDB中,只有主键索引是聚簇索引
    当查询使用聚簇索引时,在对应的叶子节点,可以获取到整行数据,因此不用再次进行回表查询.

  • MySQL都有哪些锁呢?
    从锁的类别上来讲,有共享锁和排他锁.
    共享锁: 又叫做读锁. 当用户要进行数据的读取时,对数据加上共享锁.针对同一份数据,多个读操作可以同时进行而不会互相影响
    排他锁: 又叫做写锁. 当用户要进行数据的写入时,对数据加上排他锁

  • MySQL中的varchar和char有什么区别.
    char是一个定长字段,假如申请了char(10)的空间,那么无论实际存储多少内容.该字段都占用10个字符,而varchar是变长的,也就是说申请的只是最大长度

  • mysql超大分页怎么实现?
    limit语法支持两个参数,offset和limit,前者表示偏移量,后者表示取前limit条数据
    优化:
    1.用id优化 先找到上次分页的最大ID,然后利用id上的索引来查询;这样的效率非常快,因为主键上是有索引的,但是这样有个缺点,就是ID必须是连续的
    2.用覆盖索引优化
    mysql的查询完全命中索引的时候,称为覆盖索引,是非常快的,因为查询只需要在索引上进行查找,之后可以直接返回,而不用再回数据表拿数据.因此我们可以先查出索引的ID,然后根据Id拿数据.
    3.靠缓存,可预测性的提前查到内容,缓存至redis等k-V数据库中

  • 横向分表和纵向分表,可以分别举一个适合他们的例子吗?
    横向分表:一个表里存了个大字段,比如成绩表里面存了作文内容,把作文内容单独拿出来
    水平分表:数据太多,放一张表里耗费性能,query insert的时候都从不同的表里面,比如用id%100 会得到0-99的数,把这个数拼接到表名后面table89 能快速寻找到

  • 说一说三个范式
    第一范式: 每个列都不可以再拆分. 第二范式: 非主键列完全依赖于主键,而不能是依赖于主键的一部分. 第三范式: 非主键列只依赖于主键,不依赖于其他非主键.
    在设计数据库结构的时候,要尽量遵守三范式

  • mysql去重的用法
    在使用mysql时,有时需要查询出某个字段不重复的记录,这时可以使用mysql提供的distinct这个关键字来过滤重复的记录

  • MYSQL支持事务吗?
    在默认模式下,MYSQL是autocommit模式的,所有的数据库更新操作都会即时提交,所以在缺省情况下,mysql是不支持事务的。但是如果你的MYSQL表类型是使用InnoDB Tables 或 BDB tables的话,你的MYSQL就可以使用事务处理,使用SET
    AUTOCOMMIT=0就可以使MYSQL允许在非autocommit模式,在非autocommit模式下,你必须使用COMMIT来提交你的更改,或者用ROLLBACK来回滚你的更改。

  • mysql缓存机制
    在这里插入图片描述

  • mysql,redis怎么定位慢查询
    MySQL通过慢查询日志定位那些执行效率较低的SQL 语句,用–log-slow-queries[=file_name]选项启动时,mysqld 会写一个包含所有执行时间超过long_query_time 秒的SQL语句的日志文件,通过查看这个日志文件定位效率较低的SQL.
    Redis slowlog是Redis用来记录查询执行时间的日志系统

  • 大数据量下的数据库查询与插入如何优化?

    1.尽量使语句符合查询优化器的规则避免全表扫描而使用索引查询
    
    2.避免频繁创建和删除临时表,以减少系统表资源的消耗。
    
    3.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
    
    4.建立高效的索引
    
  • 系统设计需要考虑什么安全性问题
    服务集群,多线程锁,异常处理,缓存雪崩,缓存击穿,缓存穿透,缓存预热,Lua控制Redis事务

  • mysql的where和having区别
    where和having子句都可以实现过滤记录的功能
    WHERE 子句作用于表和视图,HAVING 子句作用于组
    having一般跟在group by之后,执行记录组选择的一部分来工作的。
    where则是执行所有数据来工作的

  • mysql最左前缀原则
    在mysql建立联合索引时会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配,

    create unique index uni_Gid_Cid_SId on student(Gid,Cid,SId)
    

    联合索引 uni_Gid_Cid_SId 实际建立了(Gid)、(Gid,Cid)、(Gid,Cid,SId)三个索引。
    1.最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
    2.=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式
    3.B+树的数据项是复合的数据结构,比如 (name,age,sex) 的时候,b+树是按照从左到右的顺序来建立搜索树的

  • innodb为什么能支持事务
    1.ACD三个特性是通过Redo log(重做日志)和Undo log 实现的。 而隔离性是通过锁来实现的。
    2.undo用来保存数据更改之前的数据,保证原子性。redo用来保存数据更改之后的数据(注意是物理的修改信息),保证持久性
    3.Undo Log的原理很简单,为了满足事务的原子性,在操作任何数据之前,首先将数据备份到一个地方,也就是 Undo Log,然后进行数据的修改。如果出现了错误或者用户执行了ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态。
    4.Redo Log记录的是新数据的备份。在事务提交前,只要将Redo Log持久化即可,当系统崩溃时,虽然数据没有持久化,但是Redo Log已经持久化。系统可以根据Redo Log的内容,将所有数据恢复到最新的状态
    5.事务的完整流程

    当执行update he set name='liuwenhe' where id=5;
    1)事务开始
    2)对id=5这条数据上排他锁,并且给5两边的临近范围加gap锁,防止别的事务insert新数据;
    3)记录id=5的数据到undo log. 5)记录修改id=5的信息到redo log.
    4)修改id=5的name='liuwenhe'.
    5)commit
    6)事务结束
    
  • b+树为什么更快,Mysql为什么innoDB用B+树作为索引结构
    1.为什么不用平衡二叉树(所有节点的左右子树高度差不超过1)
    单纯从性能速度上看,平衡二叉树(这里暂时不展开各种数据结构)查找效率高于B+树,核心原因是受限于磁盘i/o读取速度。mysql一般用于存储比较大的数据,使用的都是机械硬盘。机械硬盘一次数据读取的时间是毫秒级的,和内存读取远远不在一个量级。如果使用二叉树这种多层级结构,会导致磁盘的多次读取,每读取下一层数据,都是一次磁盘重新寻址。b+树特点是扁而宽,层级少。
    2.为什么不用B树(B-tree也是B树)?
    B,B+树主要区别:B树的节点为关键字和相应的数据,B+树非叶子节点只包含key信息,不存储实际的值(因此在内存页中能够存放更多的key),所有的叶子节点和相邻的节点使用链表相连,便于区间查询。
    在查找时,B+树每次都需要查询到叶子节点,B树可能第一层查询到就结束了。查找单个节点,B树查询可能会更快(mongodb采用B树,是文档型数据库,单个节点的查找,B树性能可能要高于B+),而B+树这种数据结构能更好满足范围查询输出。
    3.为什么不用二叉查找树
    在某些情况下,二叉树会退化成线性结构,查找效率和顺序查找一样,效率极低
    在这里插入图片描述
    4.为什么不用有序数组
    有序数组在做等值查询和区间查询效率都是很高的,但是插入数据的时候,效率会很低。因为为了维护连续性和有序性,后面所有的元素必须挪动,代价很大。
    5.B+树查找时间复杂度: m表示低数,n表示总数。以m为低n的对数。O(log m n)

  • 为什么官方建议使用自增长主键作为索引
    结合B+Tree的特点,自增主键是连续的,在插入过程中尽量减少页分裂,即使要进行页分裂,也只会分裂很少一部分。并且能减少数据的移动,每次插入都是插入到最后。

  • mongo底层的索引结构是什么

  • mysql怎么分表分页
    1.就是表的id是范围性的,且id是连续的,比如第一张表id是1到10万,第二张是10万到20万,这样分页没什么问题。
    2.多库分别按条件查询,查询后按照条件重新筛选,筛选后选择对应的数据,同时记录好这次每个库的最大取值,作为下一页的条件

  • mysql innodb比myisam的优势在哪里
    1.InnoDB 最小的锁粒度是行锁,MyISAM 最小的锁粒度是表锁(表级锁定)。一个更新语句会锁住整张表,导致其他查询和更新都会被阻塞,因此并发访问受限。
    2.InnoDB 是聚集索引,MyISAM 是非聚集索引。聚簇索引的文件存放在主键索引的叶子节点上,因此 InnoDB 必须要有主键,通过主键索引效率很高。 MyISAM 是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针
    3 InnoDB支持事务,MyISAM 不支持

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值