当前位置: 首页 > 科技观察

面试:Redis 是单线程,是怎么解决高并发问题的

时间:2023-03-19 19:58:32 科技观察

面试:Redis是单线程的。它是如何解决高并发问题的?这不,最近去别的公司面试,又被虐了。毛哥有几个问题一时语塞,今天就给大家分享一下。以后遇到此类问题时,可以尝试反虐。首先不得不说,不管是哪次面试,毛哥都免不了被问到两个问题:2-5分钟的自我介绍。如果你是外企或者跨国公司或者大厂,如果你能用流利的英语介绍自己,那肯定加分。朋友们,离开校园后,不要放弃学习英语。你最令人印象深刻的解决问题的经历,或者你最充实的经历。通过你的描述,看你对技术的兴趣,看你解决问题的方法,当然还有你的口头表达能力。没有遇到这两个问题的面试。准备面试的同学要好好准备,多排练。人生如戏,全靠演技。那么,说一下这次遇到的几个问题:1.配置uWSGI生产环境有两种方式,一种是socket,一种是http,这两种方式有什么区别?为什么使用socket而不是http?当时并不清楚为什么socket更好。他一脸茫然,恼怒自己只顾着这么用,却没想太多为什么要这么用。参考答案:通常情况下,Nginx与uWSGI协同工作,Nginx处理静态文件,将动态接口请求转发给uWSGI。这就是Nginx与uWSGI通信的协议。Nginx的uwsgi_pass选项告诉它使用特殊的uWSGI协议,这是uWSGI套接字使用的默认协议。uwsgi.ini示例:[uwsgi]master=truechdir=/root/KeJiTuan/rearEndsocket=:8000#http=:8000socket=%(chdir)/uwsgi.socketwsgi-file=rearEnd/wsgi.pyprocesses=1threads=4virtualenv=/root/KeJiTuan/envstatic-map=/static=/root/KeJiTuan/frontEnd/dist/staticstats=%(chdir)/uwsgi.statuspidfile=%(chdir)/uwsgi.piddaemonize=%(chdir)/uwsgi.log%如果你使用http选项配置uWSGI,这样uWSGI本身就可以为外界提供http服务,而不会做任何有用的事情。在这种情况下,NGINX将需要配置为使用HTTP与uWSGI通信,并且NGINX将不得不重写标头以指示它正在代理,最终会做更多的工作,因此性能不如套接字方式。也就是说配置为socket时实际使用的是TCP协议,配置为http时使用的是HTTP协议。TCP是传输层协议,处于较低级别。该程序处理更小的数据包和更快的性能,而HTTP是基于TCP的。上面的应用层协议需要处理更多的报文封装和解码。因此,生产环境uWSGI更倾向于socket配置。2.Redis是单线程的。它是如何解决高并发问题的?我当时是这样回答的:如果单线程想要高并发,就用到了像nginx的eventloop这样的技术。参考答案:redis是基于内存的,内存的读写速度非常快(纯内存);数据存储在内存中,数据结构使用HashMap。HashMap的优点是查找和运算的时间复杂度为O(1)。Redis是单线程的,节省了很多上下文切换线程的时间(避免线程切换的资源消耗)。Redis使用I/O多路复用技术来处理高并发连接(非阻塞I/O)。(如果你懂I/O多路复用,可以谈谈,说明你研究的深度)至此,毛大哥自己也有疑惑,什么是事件循环,什么是I/O多路复用,它们之间有什么关系他们俩?于是找了学习资料,整理如下。如有异议,欢迎在文末留言讨论。事件循环是一种编程范式。通常,我们在编写服务器处理模型的程序时,有以下几种模型:(1)每收到一个请求,就创建一个新的进程来处理该请求;(2)每收到一个请求当收到一个请求时,就创建一个新的线程来处理这个请求;(3)每次接收到一个请求,就把一个事件列表放到主进程中,通过非阻塞I/O的方式处理请求;三是事件驱动方式,比如Python中的协程就是事件循环,Nginx等大部分web服务器采用的方式。比如javascript,一大特点就是单线程,那你为什么不觉得浏览器里的javascript慢呢?当然不是,对吧,因为javascript在处理DOM的时候也是使用了事件循环。单线程是指所有的任务都需要排队,上一个任务完成后才会执行下一个任务。如果前一个任务耗时很长,后一个任务就得一直等下去。但是,如果任务是计算任务,CPU太忙,就会等待。如果是I/O任务,主线程可以不考虑I/O设备,将等待的任务挂起,先运行。后面的任务。等待I/O设备返回结果,继续执行挂起的任务。也就是说,在主线程之外还有一个任务队列。只要异步任务(异步I/O)有结果,就会在任务队列中放入一个事件。主线程中的任务执行完后,会去任务队列中取出结果。异步任务执行的具体过程如下图所示:由于整个过程是不断循环的,所以这种运行机制也称为事件循环。至此,相信你对事件循环已经有了比较清晰的印象。那么什么是I/O多路复用?这里借用知乎的好评回答:作者:柴小淼链接:https://www.zhihu.com/question/28594409/answer/52835876来源:知乎。这是一个模拟TCP服务器处理30个客户端套接字的示例。假设你是一位老师,请30名学生回答一个问题,然后检查学生是否做对了。你有以下几种选择:1.第一种选择:按顺序逐一检查,先检查A,再检查B,然后是C,D。。.如果一个学生卡在中间,整个班级就会被耽误。这种模式就像,你用一个循环一个一个的处理socket,完全没有并发能力。2.第二个选项:您创建30个头像,每个头像检查学生的答案是否正确。这类似于为每个用户创建一个进程或线程来处理连接。3、第三种选择,你站在讲台上等待,谁回答完就举手。这时,C、D举手,表示答题完毕。下去依次检查C、D的答案,然后继续回到讲台上等待。这时候E和A又举起了手,然后去对付E和A。。.这就是I/O多路复用模型,Linux下的select、poll、epoll就是这样做的。将用户socket对应的fd注册到epoll中,然后epoll会帮你监控哪些socket有消息到达,从而避免很多无用的操作。这时候socket应该采用非阻塞模式。这样整个进程只会在调用select、poll、epoll等调用时阻塞,发送和接收客户消息不会阻塞,整个进程或线程得到充分利用,这就是event-驱动。也就是说select、poll、epoll都是I/O多路复用机制。区别如下。到这里你应该明白了,事件循环是一种编程范式,很多场景下都可以这样设计代码,而I/O多路复用是一种I/O模型,是操作系统提供的一种机制,就是相当于进程和线程的概念,也就是说,现代操作系统提供了三种并发机制:连接上限和改进的并发性能。3、HTTP中Keep-Alive的作用是什么,是如何实现的?参考答案:HTTP建立在TCP之上。每次建立连接都要经过三次握手,每次断开连接都需要挥手四次,无论是建立连接还是断开连接都是代价高昂的。Keep-Alive是一个通用的消息头,可以让消息发送者指明连接的状态,也可以用来设置超时时间和最大请求??数。HTTP/1.1200OKConnection:keep-aliveContent-Encoding:gzipContent-Type:text/html;charset=utf-8Date:Thu,11Aug201615:23:13GMTKeep-Alive:timeout=5,max=1000Last-Modified:Mon,25Jul201604:32:39GMTServer:ApacheKeep-Alive使得客户端和服务器之间的连接持续有效。当有后续请求到服务器时,Keep-Alive功能避免建立或重新建立连接。现在的Web服务器基本都支持HTTPKeep-Alive。Keep-Alive带来以下优势:更少的CPU和内存使用(由于减少了同时打开的连接)允许请求和响应的HTTP流水线减少了拥塞控制(减少了TCP连接)减少了后续请求的延迟(不再握手需要)报错不需要关闭TCP连接缺点:保持连接会导致一些不必要的连接也会占用服务器资源,比如不断请求单个文件的服务(比如图片存储站点),Keep-Alive可以大大影响性能,因为它在请求文件后长时间保留不必要的连接。HTTPKeep-Alive是如何实现的?客户端向服务端发送connection:Keep-Alive头,如果服务端也接受Keep-Alive,如果双方代码匹配,则连接可以重用。之后,另一个HTTP数据直接来自此连接。当你想断开连接时,可以添加Connection:close来关闭连接。当然也可以设置Keep-Alive模式的属性,比如Keep-Alive:timeout=5,max=100,表示这个TCP通道可以保持5秒,max=100,表示长连接在接收到最多100个请求后将断开连接。但是如果开启了Keep-Alive模式,客户端怎么知道某个响应结束了呢?有两种方法:如果是静态响应数据,可以通过判断响应头中的Content-Length字段来判断数据是否达到这个大小,就知道数据传输结束了。但是返回的数据是动态变化的,服务端无法第一时间知道数据的长度,所以没有Content-Length关键字。在这种情况下,服务器以块的形式传输数据,Transfer-Encoding:chunk。这时候就要根据传输的数据chunk来判断了。当数据传输结束时,最后一个datachunk的长度为0。上次面试结束后,毛哥把自己回答的不是很好的问题记了下来,然后搜索了一下,得出的结论是希望对大家有所帮助。毛哥会不定时分享面试心得。有收获,不妨关注、观看、点赞、支持一波。本文转载自微信公众号“Python7号”,可通过以下二维码关注。转载本文请联系Python七号公众号。