1、为什么使用UDP协议?缺点?
使用UDP协议的主要原因是它能够在网络中提供快速和高效的数据传输。与TCP协议相比,UDP协议没有建立连接和确认数据包的过程,因此具有更低的延迟和更高的吞吐量,适用于需要快速响应的应用场景,如在线游戏、视频和音频流等。
缺点,由于没有可靠性保证,数据包可能会丢失或乱序到达,因此在传输质量要求较高的应用场景下不太适用。此外,UDP协议对网络拥塞的控制能力很弱,如果网络出现拥堵,则容易造成数据包的丢失或延迟,从而影响用户体验。
2、简单说说Zookeper设计原理?怎么用的?
Zookeeper是一个分布式的协调服务,它能够提供分布式应用程序所需的一致性、可靠性和高性能特性。在后端系统中,Zookeeper常常被用于实现集群管理、配置管理、命名服务等功能。
其基本原理如下:
集群管理:Zookeeper将整个集群作为一个整体来管理,可以监控节点的状态、健康状况、可用性等信息,当某个节点宕机时,Zookeeper能够自动进行故障转移,保证整个系统的稳定性和可用性。
配置管理:Zookeeper可以将系统中的配置信息存储在其内部的节点树中,并且能够监听节点变化的事件,当配置发生变化时,Zookeeper会及时通知相关的客户端程序,以便客户端程序能够及时更新自身的配置信息。
命名服务:Zookeeper将分布式应用程序中的各种资源抽象成节点,每个节点都有一个唯一的路径名称,客户端程序可以像访问文件系统一样访问Zookeeper上的节点,从而实现对分布式资源的统一管理和访问。
使用Zookeeper时,需要先搭建Zookeeper集群,并将自己的应用程序注册到其中。然后,可以通过Zookeeper提供的API来实现对节点的创建、删除、修改、查询等操作,以及对节点变化事件的监听和处理。同时,Zookeeper还提供了Java、C、Python等多种编程语言的客户端库,方便开发者进行集成和开发。
3、ZK还没写完时,读请求过来能读到吗?提交一定能成功吗?
在Zookeeper中,读请求可以在写请求未完成时进行。这是因为,Zookeeper使用了多版本并发控制(MVCC)来实现数据的一致性和可靠性。每个节点都有一个版本号,当节点数据被修改时,其版本号会自动增加。读操作只会访问指定版本的节点数据,不会受到其他修改操作的影响,因此可以在写操作未完成时进行。
但是,提交请求并不一定能够成功。如果在提交请求的过程中,当前节点的状态发生了变化(例如被其他客户端修改),则该请求可能会失败,需要重新尝试提交。另外,如果在提交请求的过程中,网络出现异常或者Zookeeper服务器宕机了,也有可能导致请求失败。
因此,在使用Zookeeper时,应该对请求的提交结果进行检查,并在必要情况下进行重试。同时,应该采取一些策略来确保Zookeeper服务器的高可用性和稳定性,例如搭建多个Zookeeper服务器构成集群等。
4、服务实例起来到发现的过程?
服务实例起来到发现的过程可以分为以下几个步骤:
服务实例启动:服务启动后会向注册中心注册自己的信息,包括服务名称、IP地址、端口号等。
注册中心存储服务信息:注册中心将服务实例的信息存储在自己的数据库中,以便其他客户端能够查询和使用该服务。
服务发现:客户端需要使用某个服务时,会向注册中心发送查询请求。注册中心根据客户端的请求,从自己的数据库中查询相应的服务实例信息,返回给客户端。
客户端调用服务:客户端获取服务实例的信息后,就可以通过网络协议(如HTTP、RPC等)与服务实例进行通信,调用其中提供的API接口,获取所需的数据或执行相应的业务逻辑。
5、调用方时实时从ZK上取数据吗?
在Zookeeper中,服务提供者会将自己的信息注册到Zookeeper上,而服务调用方则通过访问Zookeeper来获取可用的服务实例。服务调用方可以选择不同的方式来从ZK上获取数据:
实时获取:在服务调用时,每次都向Zookeeper发送请求获取最新的服务实例列表。这种方式可以保证服务实例列表的及时性和准确性,但会造成不必要的网络开销和负载。
缓存获取:服务调用方定期从Zookeeper获取服务实例列表,并缓存到本地。在服务调用时,直接从本地缓存中获取可用的服务实例。这种方式可以减少网络开销和负载,但服务实例列表可能无法及时更新,存在数据不一致的风险。
6、ES怎么用的?为什么用ES?
Elasticsearch(ES)是一个开源的分布式搜索引擎,它可以快速、可靠地存储和搜索大量的结构化或非结构化数据。
使用ES需要先安装和配置ES集群,并通过RESTful API来与其交互。可以通过Java、Python、Node.js等多种编程语言的客户端库来连接ES集群。在使用过程中,开发者需要定义好索引(Index)、类型(Type)和映射(Mapping),并将数据存储到ES中。
为什么用ES?:
高性能:ES使用了多种优化技术,如倒排索引、分片、副本等,能够提供高效的搜索和数据访问性能。
易用性:ES提供了丰富的API和客户端库,易于开发者使用和集成到应用程序中。
可扩展性:ES采用分布式架构,能够将数据分散存储在多个节点上,并支持水平扩展,能够处理大规模数据。
稳定性:ES具有良好的容错和恢复机制,能够保证系统的稳定性和可靠性。
7、Redis怎么实现关注?两个key怎么保证数据一致性?
Redis可以使用以下两种方式来实现关注:
使用有序集合(Sorted Set):
每个用户对应一个有序集合,集合中存储着该用户关注的其他用户的ID,以及对应的关注时间(可以使用时间戳表示)。例如:对于用户A来说,他关注了用户B、C、D,那么A的有序集合就会存储如下数据:
ZADD user:A 1627039510 BZADD user:A 1627039515 CZADD user:A 1627039520 D
当用户A要查看自己关注的用户列表时,只需要使用ZRANGE命令按照关注时间顺序取出即可。
使用列表(List)和集合(Set):
使用两个key来存储数据,分别为用户的关注列表和被关注列表。例如:对于用户A来说,他关注了用户B、C、D,那么A的关注列表就会存储如下数据:
LPUSH following:A BLPUSH following:A CLPUSH following:A D
被关注列表则是以被关注用户的ID为key,对应的value为一个集合,这个集合存储了所有关注该用户的用户ID。例如:对于用户B来说,他被用户A、E、F关注,那么B的被关注列表就会存储如下数据:
SADD followers:B ASADD followers:B ESADD followers:B F
当用户A要查看自己关注的用户列表时,只需要使用LRANGE命令取出即可;当用户B要查看关注他的用户列表时,则需要使用SMEMBERS命令获取到所有关注他的用户ID,并根据这些ID去查询对应的用户信息。
为了保证数据一致性,需要在每次添加、删除关注关系时,同时修改两个key中的数据。可以使用Redis事务来实现这一操作,例如:
MULTIZADD user:A 1627039510 BLPUSH following:A BSADD followers:B AEXEC
这样可以确保两个key中的数据始终保持一致。
8、TCP三次握手四次挥手?
TCP三次握手:
客户端向服务端发送一个SYN(同步)标志位为1的数据包,表示客户端请求建立连接。
服务端接收到客户端的SYN数据包后,会回复一个ACK(确认)标志位为1的数据包,表示服务端已经收到了客户端的请求,并表示服务端也愿意建立连接。此时服务端还会发送一个SYN标志位为1的数据包,表示服务端也要求建立连接。
客户端收到服务端的SYN和ACK数据包后,会发送一个ACK标志位为1的数据包,表示客户端已经收到了服务端的确认,并进入已连接状态,双方可以开始传输数据。
TCP四次挥手:
当客户端想要关闭连接时,会向服务端发送一个FIN(结束)标志位为1的数据包,表示客户端不再需要连接。
服务端收到客户端的FIN数据包后,会发送一个ACK标志位为1的数据包,表示服务端已经收到了客户端的请求,但是服务端可能还有未传输完成的数据需要发送。
当服务端所有的数据都传输完成后,会向客户端发送一个FIN标志位为1的数据包,表示服务端已经完成了数据的传输。
客户端收到服务端的FIN数据包后,会回复一个ACK标志位为1的数据包,表示客户端已经收到了服务端的结束请求,并且也没有数据需要传输了。此时客户端进入TIME_WAIT状态,等待2MSL(最长报文段寿命)之后才会彻底关闭连接。
在TCP连接中,三次握手是建立连接,四次挥手是断开连接。三次握手保证了双方都已经准备好进行通信,四次挥手则保证了双方都能够安全、完整地结束通信。
9、Session和Cookie区别?
Session和Cookie都是Web开发中常用的技术,它们都可以用来存储用户的数据,但在实现方式和作用上有一些区别。
存储位置
Cookie存储在客户端浏览器中,而Session存储在服务器端内存或者磁盘中。
安全性
由于Cookie存储在客户端浏览器中,因此Cookie存在被篡改的风险。如果使用明文存储敏感信息,那么这些信息就可能被黑客窃取。而Session存储在服务端,只要保证服务器端的安全性,就能够保障用户的信息安全。
大小限制
Cookie的大小通常受到浏览器对Cookie数量和大小限制的限制(不同浏览器限制不同),而Session的大小通常只受到服务器硬件和软件的限制。
生命周期
Cookie可以设置生命周期,可以在客户端指定一个过期时间,在过期时间之前,浏览器会一直保存该Cookie。而Session通常在客户端关闭后就会被销毁。
作用域
Cookie的作用域可以控制Cookie的访问权限,可以设置为整个网站、某个目录或者某个页面。而Session通常只在当前应用程序范围内有效。
使用场景
Cookie通常用于记录用户的登录状态、购物车信息等。而Session通常用于存储用户会话信息、权限验证信息等。
10、常见的Linux IO模型?
常见的Linux IO模型有以下几种:
阻塞IO模型(Blocking IO):当应用程序调用read或write等IO操作时,如果内核没有准备好数据,那么应用程序就会一直阻塞等待,直到内核准备好数据后才会返回。在这种模型下,应用程序通常只能同时处理一个连接,效率较低。
非阻塞IO模型(Non-Blocking IO):应用程序调用read或write等IO操作后,如果内核没有准备好数据,那么应用程序不会被阻塞,而是立即返回一个EAGAIN或EWOULDBLOCK错误码,表示当前资源不可用。在这种模型下,应用程序需要不断轮询来检查是否有数据准备好,可以同时处理多个连接,但轮询频繁可能会占用过多CPU资源。
IO复用模型(IO Multiplexing):使用select、poll或epoll等系统调用来监听多个IO事件,当有IO事件发生时再进行处理。在这种模型下,应用程序也只需要通过一个线程来监听多个连接,效率比非阻塞IO模型要高。
信号驱动IO模型(Signal Driven IO):应用程序调用sigaction函数注册一个信号处理函数,在数据准备好时内核会向应用程序发送一个SIGIO信号,应用程序收到信号后再进行IO操作。这种模型比较适合于处理低频率的IO事件。
异步IO模型(Asynchronous IO):应用程序调用aio_read或aio_write等异步IO函数,内核会在IO操作完成后通知应用程序。在这种模型下,应用程序不需要等待IO操作完成,可以继续执行其他任务,当IO操作完成后再进行回调处理。异步IO模型在高并发场景下更具优势。
11、==和equals区别?hashCode和equals区别?HashMap的put操作流程?
==和equals区别:
==是比较两个对象的内存地址是否相同,即判断两个对象是否为同一个对象。而equals是比较两个对象的内容(属性)是否相同,即判断两个对象是否等价。
hashCode和equals区别:
hashCode是Java中Object类的一个方法,在进行哈希映射时使用。它用于计算存储对象的哈希码,不同的对象可以有相同的哈希码,但相等的对象必须具有相同的哈希码。equals方法则用于比较两个对象是否相等,如果两个对象相等,则其hashCode方法返回的哈希值也必须相等。
HashMap的put操作流程:
HashMap是一种基于数组和链表实现的哈希表,用于存储键值对数据。当执行put操作时,假设需要将key-value对(K1, V1)加入到HashMap中,它的操作流程如下:
计算K1的hashCode值。
根据hashCode值找到K1在数组中的索引位置,如果该位置没有元素,则将(K1, V1)插入到该位置,并返回null。
如果该位置已经存在元素,那么需要将(K1, V1)与该位置上的所有元素进行比较,如果找到了一个key与K1相等的元素,则将该位置上的value替换为V1,并返回旧的value值。
如果该位置上的元素都和K1不相等,那么需要将(K1, V1)插入到该位置上的链表中,并返回null。
如果链表长度大于8(默认值),则会将链表转化为红黑树,以提高查找效率。
如果数组中的元素个数超过了负载因子(默认是0.75),就需要进行扩容操作,将容量翻倍。
12、HashMap是线程安全的吗?
HashMap是非线程安全的,它不是线程安全的容器。如果在多线程环境下使用HashMap进行读写操作,可能会导致数据不一致的问题。
13、实现懒汉式单例模式
public class LazySingleton {private static LazySingleton instance = null;private LazySingleton() {// 私有构造方法}public static synchronized LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}}
在这个实现中,getInstance方法使用了synchronized关键字来保证线程安全,只有在instance为null时才创建LazySingleton对象,并返回该对象。由于synchronized关键字会降低性能,因此可以考虑使用双重检查锁定(Double Check Locking)和静态内部类等方式来提高性能和代码可读性。
需要注意的是,懒汉式单例模式在多线程环境下可能会出现问题,例如当两个线程同时进入if语句时,都判断instance为null,然后都创建一个LazySingleton对象并返回,这就导致了多个对象实例的存在。因此,需要在getInstance方法上增加同步锁或者使用volatile关键字来解决这个问题。