当前浏览器不支持播放音乐或语音,请在微信或其他浏览器中播放 那女孩对我说 黄义达 – 歌曲合辑 0x00.前言 众所周知数据结构和算法是面试重点,我们持续发力是十分明智的,要不然最后肯定是要吃亏的,少打打游戏刷刷微博可以改变我们的生活水平哦。 不过本文不是要讲述数据结构和算法的,而是另外一个面试重点Redis,因为Redis也是跨语言的共同技术点,无论是Java还是C++都会问到,所以是个高频面试点。 笔者是2017年才开始接触Redis的,期间自己搭过单机版和集群版,不过现在公司大一些都完全是运维来实现的,我们使用者只需要在web页面进行相关申请即可,很多细节都被屏蔽了,这样当然很方便啦,不过我们还是要深入理解一下的。 在工作几年中笔者接触过Redis、类Redis的SSDB和Pika、谷歌的Key-Value存储引擎LevelDB、FackBook的Key-Value存储引擎RocksDB等NoSQL,其中Redis是基于标准C语言开发的,是工程中和学习上都非常优秀的开源项目。 之前笔者写过几篇左右Redis的文章,但是知识点都分散着不利于阅读,所以本次就把之前的文章进行汇总补充,来形成一个全一些的集合,希望对关注我的读者有所帮助就足够啦。 文中列出来的考点较多并且累计达3w+字 ,因此建议读者收藏,以备不时之需,通过本文你将了解到以下内容: Redis的作者和发展简史 Redis常用数据结构及其实现 Redis的SDS和C中字符串的原理和对比 Redis有序集合ZSet的底层设计和实现 Redis有序集合ZSet和跳跃链表问题 Redis字典的实现及渐进式Rehash过程 Redis单线程运行模式的基本原理和流程 Redis反应堆模式的原理和设计实现 Redis持久化方案及其基本原理 集群版Redis和Gossip协议 Redis内存回收机制和基本原理 Redis数据同步机制和基本原理 话不多说,时速400公里的大白号 开始加速! 笔者尽量详细地阐述每个问题,旨在深入理解避免囫囵吞枣的背诵,当然也会存在一些不足,如有问题可私信我。 0x01. 什么是Redis及其重要性? Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久化的高性能键值对数据库。 Redis的之父是来自意大利的西西里岛的Salvatore Sanfilippo,Github网名antirez,笔者找了作者的一些简要信息并翻译了一下,如图: 从2009年第一个版本起Redis已经走过了10个年头,目前Redis仍然是最流行的key-value型内存数据库的之一。 优秀的开源项目离不开大公司的支持,在2013年5月之前,其开发由VMware赞助,而2013年5月至2015年6月期间,其开发由毕威拓赞助,从2015年6月开始,Redis的开发由Redis Labs赞助。 笔者也使用过一些其他的NoSQL,有的支持的value类型非常单一,因此很多操作都必须在客户端实现,比如value是一个结构化的数据,需要修改其中某个字段就需要整体读出来修改再整体写入,显得很笨重,但是Redis的value支持多种类型,实现了很多操作在服务端就可以完成了,这个对客户端而言非常方便。 当然Redis由于是内存型的数据库,数据量存储量有限而且分布式集群成本也会非常高,因此有很多公司开发了基于SSD的类Redis系统,比如360开发的SSDB、Pika等数据库,但是笔者认为从0到1的难度是大于从1到2的难度的,毋庸置疑Redis是NoSQL中浓墨重彩的一笔,值得我们去深入研究和使用。 Redis提供了Java、C/C++、C#、 PHP 、JavaScript、 Perl 、Object-C、Python、Ruby、Erlang、Golang等多种主流语言的客户端,因此无论使用者是什么语言栈总会找到属于自己的那款客户端,受众非常广。 笔者查了datanyze.com网站看了下Redis和MySQL的最新市场份额和排名对比以及全球Top站点的部署量对比(网站数据2019.12): 可以看到Redis总体份额排名第9并且在全球Top100站点中部署数量与MySQL基本持平,所以Redis还是有一定的江湖地位的。 0x02. 简述Redis常用的数据结构及其如何实现的? Redis支持的常用5种数据类型指的是value类型,分别为:字符串String、列表List、哈希Hash、集合Set、有序集合Zset,但是Redis后续又丰富了几种数据类型分别是Bitmaps、HyperLogLogs、GEO。 由于Redis是基于标准C写的,只有最基础的数据类型,因此Redis为了满足对外使用的5种数据类型,开发了属于自己独有的一套基础数据结构,使用这些数据结构来实现5种数据类型。 Redis底层的数据结构包括:简单动态数组SDS、链表、字典、跳跃链表、整数集合、压缩列表、对象。 Redis为了平衡空间和时间效率,针对value的具体类型在底层会采用不同的数据结构来实现,其中哈希表和压缩列表是复用比较多的数据结构,如下图展示了对外数据类型和底层数据结构之间的映射关系: 从图中可以看到ziplist压缩列表可以作为Zset、Hash、List三种数据类型的底层实现,看来很强大,压缩列表是一种为了节约内存而开发的且经过特殊编码之后的连续内存块顺序型数据结构,底层结构还是比较复杂的。 0x03. Redis的SDS和C中字符串相比有什么优势? 在C语言中使用N+1长度的字符数组来表示字符串,尾部使用’\0’作为结尾标志,对于此种实现无法满足Redis对于安全性、效率、丰富的功能的要求,因此Redis单独封装了SDS简单动态字符串结构。… Continue reading 3w字深度好文|Redis面试全攻略,读完这个就可以和面试官大战几个回合了
Author: admin
万字长文|全(小区局域)网最强TCP/IP拥塞控制总结…
一.先唠唠嗑 按照计划,今天该出分布式一致性系列的第四篇-Paxos算法,但是又鸽了。 Paxos这个算法要很好地表达写出来并不容易,所以到现在还没有完成,于是就有了这篇组装的带有丝丝标题党感觉的干货文章,全小区最强TCP/IP总结…逃… 在正式开始文章技术点之前,想先聊一下我对面试中的TCP/IP问题的一些拙见,希望对盆友们有所帮助。 在招聘岗位描述中,几乎必然有一条熟悉、掌握、精通TCP/IP协议、Http协议、网络编程技术。 对于我们求职者来说,肯定知道的越多越好,但是就像过日子一样钱要花在刀刃上,准备面试也是一样的,我们该怎么准备这部分呢? 我个人认为合理的优先级排序是:网络编程技术 > Http协议 > TCP/IP协议热点问题 > TCP/IP协议普通问题。 从面试官的角度来说,面试中还是要注重实战,问一些边边角角的细节或者自己平时遇到的奇怪问题,并不能探测出侯选人的边界,反而让侯选人觉得这个面试官抓不住重点。 有时候遇到一些侯选人说自己哪块掌握的比较好,那可以交流一下,比如之前遇到侯选人说自己读过Redis源码,顿时让我很有兴趣,简单了解了对方阅读的版本之后,就开始切磋,很快就可以探测出侯选人的所说的Redis源码边界。 回到网络这块,C/C++的话轮子比较少,有时候需要自己搞一个Socket写个小型的服务端或者客户端,像Python/Go这些语言做的已经非常好了,可能不到5行一个简单的echo服务就跑起来了。因为之前自己是写C++服务端的,回忆起第一次用Python的Tornado框架写服务,着实被惊艳了,开发速度着实很快,性能也很不错。 说这个的目的在于,如果对于时间紧任务重的求职者就不要胡子眉毛一把抓,抓几个重点问题好好理解一下就可以了,如果真遇到问边角问题的面试,那也不必懊恼,可能大概率以后共事脑回路也不一样,还是相忘于江湖比较好。 在掌握一些重点问题的面试套路和回答之后,还是建议去深入了解一些这些技术细节,更多的是去培养和锻炼我们思考问题的方法和意识,之前在知乎就有这样的问题,就像研究往年的高考题一样,我们去思考TCP/IP在发展过程中的问题以及解决方案,并且当前存在的瓶颈作出自己的判断和思考,都是很有益的。 我想这也是打开TCP/IP的正确方式吧:实战派和训练思维派。 今天和大家一起学习下TCP/IP中的热点问题:拥塞控制。本文本着实战和思维训练兼顾的原则将从以下几个方面展开: 拥塞控制的算法策略分类 拥塞控制出现的意义和目的 实现拥塞控制的几种算法和侧重点 拥塞控制的主要过程和关键点 BBR算法的一些原理和思路 2. 我和TCP/IP协议 我在5年前研究生刚毕业的时候,在一家做深度包检测DPI的公司待了差不多两年,可能读者要问啥是深度包检测? 简单提一下哈,深度包检测 DPI (Deep Packet Inspection)就是识别TCP/IP网络协议中各种各样的报文,来进行流量管控和分析,在网络安全领域应用很多,属于通信&互联网领域的交叉业务。 整个DPI系统是非常复杂的,目前业界有硬件DPI和软件DPI两种主流类型,硬件的吞吐量大造价也高,软件的比较灵活成本也相对低廉。 当时每天的工作就是抓包分析、用C++写业务插件来处理各种丢包/乱序/重传问题等等,有时候业务需要还要单独开发wireshark的插件来解析自定义的报文。 现在看看这份工作开启了我和TCP/IP协议网络的友谊之门。 在刚毕业前3年换工作的时候,几乎总会被问到TCP/IP协议的一些东西,碰到一些专业人士问的就比较深入,好在近两年的经验让这些问题基本都在射程之内。 所以经历都是财富,好好学一下,说不准哪天就派上用场了呢。 三. 走心推荐 TCP/IP协议是一个协议族,如果真的非常感兴趣或者工作需要建议直接卷一卷二卷三,但是对于大多数读者来说,应付面试或者平时排查问题掌握一些重点内容也就够了。 TCP/IP详解的三本书译文难免失真,有决心和兴趣的同学可以搞几本英文原版的,这是豆瓣读书上的一些评分: 四.聊聊拥塞控制算法 我们知道TCP/IP协议栈是一个简化的分层模型,是互联网世界连接一切的基石,一起来看一张七层模型vs四层模型的简图: 看到一篇文章说到TCP拥塞控制算法并不是简单的计算机网络的概念,也属于控制论范畴,感觉这个观点很道理。 TCP拥塞控制算法的目的可以简单概括为:公平竞争、充分利用网络带宽、降低网络延时、优化用户体验,然而就目前而言要实现这些目标就难免有权衡和取舍。 但是现在的网络通信基础设施水平一直在飞速提高,相信在未来的某个时间点这些目标都可以达到,小孩子才选择,我们大人全都要! 算法演进 在理解拥塞控制算法之前我们需要明确一个核心的思想:闻道有先后 术业有专攻,笔者觉得这是一个非常重要的共识问题,把A踩在泥土里,把B吹捧到天上去,都不是很好的做法。 实际的网络环境十分复杂并且变化很快,并没有哪个拥塞控制算法可以全部搞定,每一种算法都有自己的特定和适用领域,每种算法都是对几个关键点的权衡,在无法兼得的条件下有的算法选择带宽利用率,有的算法选择通信延时等等。 在明确这个共识问题之后,我们对待各个拥塞控制算法的态度要平和一些,不要偏激地认为谁就是最好,几十年前的网络状况和现在是截然不同的,我们永远都是站在巨人的肩膀之上的,这也是科学和文明进步的推动力。 算法分类 传统拥塞控制算法并不是一蹴而就的,复杂的网络环境和用户的高要求推动着拥塞控制算法的优化和迭代,我们看下基于丢包策略的传统拥塞控制算法的几个迭代版本,如图所示: 与此同时还有一类算法是基于RTT延时策略来进行控制的,但是这类算法在发包速率上可能不够激进,竞争性能不如其他算法,因此在共享网络带宽时有失公平性,但是算法速率曲线却是很平滑。… Continue reading 万字长文|全(小区局域)网最强TCP/IP拥塞控制总结…
计算机时间到底是怎么来的?
阅读本文大约需要 13 分钟。 这篇文章我想和你聊一聊「时间」这个话题。 时间总是在不经意间流逝,我们在写代码时,也经常会调用「时间 API」,你有思考过这背后的原理吗? 关于时间的问题还有很多,例如: 为什么计算机的时间有时候「走不准」? 计算机究竟是怎么「自动校准」时间的? 我们经常看到的 UTC 时间,到底是什么? 我们在新闻上看到的「北京时间」,真的来自北京吗? 这篇文章,我们就来揭秘时间背后的秘密。 这篇文章非常有意思,希望你可以耐心读完。 时间为什么总是走“不准”? 你肯定遇到过这样的场景,家里买了一个钟表,时间一长,就会发现它走得「不准」了。 又或者,一台长时间不使用的电脑,它的时间也会发生偏差。 遇到这些情况,你可能会不以为然。时间不准,那我们就「人工」调准它。 但你有没有停下来想一想,为什么它们的时间会越走越不准呢? 要回答这个问题其实不难,我们只需要搞清楚,它们的时间是怎么来的。 钟表和计算机内部都有一个叫做「晶体振荡器」的东西,给它加上电压,它就会以固定的频率振动。但这个振动频率的「稳定性」,取决于它的制造工艺,以及外界环境的影响。 出于成本的考虑,钟表的制作工艺没那么高,所以它更容易有误差。而电脑制造工艺虽然比较高,但它内部的晶体振荡器也会受到「温度」变化带来的影响,在工作过程中,也会有产生误差。 虽然它们的误差很小,但日积月累下来,误差就越来越明显。 因此,我们现在使用的计算机,都有「自动校准」时间的功能。但是如何校准呢? 如何校准时间? 很简单,只要你把电脑连上了「网络」,你会发现,它会自动与「网络时间」保持同步。 可问题是,这个「网络时间」哪儿来的? 我猜你大脑的第一反应是,每台电脑肯定配置了一个「时间服务器」,之后这台电脑会与服务器定时同步,自动校准。 没错,确实是这样,不光是电脑,我们平时使用的手机、平板、智能手表等电子设备,只要能连接网络,都会自动同步网络时间。 那继续追问,这个「时间服务器」的时间就一定是准的吗? 理论来讲,它应该也是一台计算机,难道它不会遇到我们前面说的问题吗? 此外,这个网络时间究竟是怎么「同步」到我们的电脑上的? 你可能会说,那肯定是通过网络数据包。 问题又来了,网络传输数据也是有「延迟」的,同步服务器时间,不还是存在误差吗? 环环相扣,像一个俄罗斯套娃,很难解释清楚。 要想彻底搞清楚这些问题,就要深入到时间的「源头」来寻找答案。 时间是怎么来的? 时间是一个非常抽象的概念,多少年来,吸引着无数科学家、物理学家、甚至哲学家花费毕生精力去解释时间的本质是什么,从宇宙大爆炸到时空相对论,从黑洞到量子力学,都能看到关于时间这个问题的身影。 这里我们不探讨高深莫测的学术知识,只把目光放聚焦在计算机这个很小的范畴内。但要想清楚解释这个问题,也并非想的那么简单。 我们从最简单的开始说起。 想要知道时间是怎么被定义的,首先要知道「天」是怎么来的? 答案是:观察太阳。 由于地球的「自转」,人们可以看到日出日落,人们日出而作,日落而息,所以就把这一周期现象定义为「天」。 地球除了自转,还在围绕太阳公转,所以公转一周就被定义为一「年」。 从这些现象就能看出来,很早之前的人们,是以「天文现象」来确定时间的。 再后来,人们为了把时间定义得更「精确」,就把一天平均划分为 24 等份,这就是「时」。 同样地,把 1 小时划分 60「分钟」,1 分钟划分为 60「秒」。… Continue reading 计算机时间到底是怎么来的?
36 张图详解 DNS :网络世界的导航
上帝视角 我们平时在访问网站时,不使用 IP 地址,而是网站域名。但是抓包发现:交互报文是以 IP 地址进行的。那么 IP 地址是从哪来的呢?这是因为 DNS 把网站域名自动转换为 IP 地址。 报文交互抓包 DNS 出现 TCP/IP 是基于 IP 地址进行通信的,但是 IP 地址不太好记。于是出现了另一种方便记忆的标识符,那就是主机名。为计算机配置主机名,在进行网络通信时,直接使用主机名,而不用输入一大串的 IP 地址。同时,系统通过一个叫 hosts 的文件,实现主机名转换 IP 地址的功能。hosts 文件包括主机名和 IP 地址的对应关系。当需要通过主机名访问主机时,它就会查看本地的 hosts 文件,从文件中找到相对应的 IP 地址,然后进行报文发送。如果在 hosts 文件中没找到相关信息,则主机访问失败。 hosts 文件是主机的本地文件,优点是查找响应速度快。它主要用来存储一些本地网络的主机名和 IP 地址的对应信息。这样,主机在以主机名访问本地网络主机时,通过 hosts 文件可以迅速获得相应的 IP 地址。 hosts文件 每台主机的 hosts 文件都需要单独手工更新。随着网络规模的不断扩大、接入计算机的数量不断增加,维护难度越来越大,每台主机同步更新,几乎是一件不可能完成的任务。 hosts维护难 为了解决 hosts 文件维护困难的问题,出现了 DNS 域名系统,一个可以解决主机名和 IP 地址互相转换的系统。无论网络规模变得多么庞大,都能在一个小范围内通过 DNS 进行管理。 DNS域名系统 DNS 介绍… Continue reading 36 张图详解 DNS :网络世界的导航
CPU到底如何切换线程的?
计算机系统中有很多程序员习以为常但又十分神秘的存在:函数调用、系统调用、进程切换、线程切换以及中断处理。 函数调用能让程序员提高代码可复用性,系统调用能让程序员向操作系统发起请求,进程线程切换让多任务成为可能,中断处理能让操作系统管理外部设备。 这些机制是计算机系统中的基石,可是你知道这些机制是如何实现的吗? 这篇文章将告诉你答案,其背后的实现如此优雅且一致。 速度与激。。寄存器 你有没有想过,CPU为什么需要寄存器? 原因很简单:速度。 通常CPU可以在一个时钟周期内访问一次寄存器,CPU访问内存的速度大概要比访问寄存器慢100倍左右。 因此如果CPU没有寄存器而完全依赖内存的话,那么计算速度将比现在慢的多。 作为程序员来说,当我们使用高级语言编写的程序时,其操作的数据都存放在内存中,而对于负责运算类的机器指令来说其操作的数据都存放在寄存器中。 实际上寄存器和内存没有什么本质的区别,都是用来存储信息的。 当然,除了临时保存中间计算结果之外,还有很多有趣的寄存器。根据用途,寄存器有很多类型,但是,我们感兴趣的有以下几种寄存器。 栈寄存器:Stack Pointer 函数在运行时都有一个运行时栈,对于栈来说最重要的信息就是栈顶,栈顶信息就保存在栈寄存器中,stack pointer,通过该寄存器就能跟踪函数的调用栈。 最为程序员我们知道,函数在运行时会有一块独立的内存空间,用来保存函数内定义的局部变量、传递的参数以及返回值信息等,这块独立的内存空间就叫栈帧,随着函数调用层次的加深,栈帧也随之增加;当函数调用完成后栈帧由按照相反的顺序依次减少,这些栈帧就构成了栈区。 函数的运行时栈信息是关于程序运行状态最重要的信息之一。 那么其它的之一呢? 指令地址寄存器:Program Counter 这类寄存器的名称比较多,基于历史原因,大部分将其称为Program Counter,PC,即我们熟悉的程序计数器;在x86下则被称为Instruction Pointer,IP,怎么称呼不重要,重要的是理解其作用。在本文中统一将其称为PC寄存器。 我们都知道,程序员用高级语言编写的程序最终通过编译器生成最终的机器指令,那么一个问题就是在茫茫的机器指令海洋中,CPU怎么知道该去执行哪条机器指令呢? 原来,奥秘就藏在指令地址寄存器中。 程序在启动时会把机器指令的首地址写入到PC寄存器中,这样CPU需要做的就是根据PC寄存器中的地址去内存中取出指令。 通常来说,指令都是顺序执行的,也就是说PC寄存器中的值不断的+1,但对于一些涉及控制转移的机器指令来说,这些指令会把一个新的指令地址放到PC寄存器中,这包括分支跳转——也就是if语句、函数调用以及返回等。 控制了CPU的PC寄存器就掌握了CPU的航向,机器指令自己会根据执行状态指挥CPU接下来该去执行哪些指令,这才是真正的自动驾驶,非常amazing有没有! 指令地址寄存器是关于程序运行时状态另一个最重要的信息之一。 状态寄存器:Status Register CPU内部除了上述两类寄存器外,还有一类状态寄存器,Status Register;在x86架构下被称为FLAGS register,ARM架构下被称为application program status register,以下统称状态寄存器。 从名字也能看出来,该寄存器是保存状态信息的,有什么有趣的状态信息呢? 比如对于涉及到算术运算的指令来说,其在执行过程中可能会产生进位,也可能会溢出,那么这些信息就保存在状态寄存器中。 除此之外,你肯定听说过程序的执行一般有两种模式:内核态和用户态。 对于大部分的程序员其编写的应用程序运行在用户态,在用户态下不能执行特权指令,比如你没办法写一个程序直接去控制系统中的各种硬件资源。 而在内核态下,CPU可以执行任意的特权指令,内核就工作在内核态,因此内核可以掌控一切。关于用户态内核态完整的阐述参见博主深入理解操作系统第2章,关注公众号码农的荒岛求生并回复操作系统即可。 那么我们怎么知道当前程序运行在哪种状态呢? 答案就在CPU内部的状态寄存器中,该寄存器中有特定的比特位来标记当前CPU正工作在哪种模式下。 现在你应该知道寄存器的重要作用了吧。 上下文:Context 通过这些寄存器,你可以知道程序运行到当前这一刻时最细粒度的切面,这一时刻这些寄存器中保存的所有信息就是我们通常所说的上下文,context。 上下文的作用是什么呢? 只要你能拿到一个程序运行时的上下文并保存起来,那么你可以随时暂停该程序的运行,也可以随时利用该信息恢复该程序的运行。 为什么要保存和恢复上下文信息呢?原因就在于CPU的个数是有限的,这就意味一个CPU可能会执行多个进程,即这些进程要共享该CPU资源,更具体的是CPU的计算资源和这里所说的各种寄存器。 这是实现函数调用、系统调用、进程切换、线程切换以及中断处理的基本机制。 而程序在运行过程中逃不出函数调用、系统调用、进程切换、线程切换以及中断处理这几项操作,由此可见上下文信息的保存和恢复在计算机科学中重要的作用。 那么上下文信息又该如何保存呢?保存到哪里呢?又该怎么恢复呢?函数调用、系统调用、进程切换、线程切换以及中断处理又是怎样实现的呢?… Continue reading CPU到底如何切换线程的?
图解 | 为嘛有 TCP 粘包和拆包
事情从一个健身教练说起吧。 李东,自称亚健康终结者,尝试使用互联网+的模式拓展自己的业务。在某款新开发的聊天软件琛琛上发布广告。 键盘说来就来。疯狂发送”李东”,回车发送!,”亚健康终结者”,再回车发送! 还记得四层网络协议长什么样子吗? 四层网络协议 四层网络模型每层各司其职,消息在进入每一层时都会多加一个报头,每多一个报头可以理解为数据报多戴一顶帽子。这个报头上面记录着消息从哪来,到哪去,以及消息多长等信息。比如,mac头部记录的是硬件的唯一地址,IP头记录的是从哪来和到哪去,传输层头记录到是到达目的主机后具体去哪个进程。 在从消息发到网络的时候给消息带上报头,消息和纷繁复杂的网络中通过这些信息在路由器间流转,最后到达目的机器上,接受者再通过这些报头,一步一步还原出发送者最原始要发送的消息。 四层网络协议 (1) 为什么要将数据切片 软件琛琛是属于应用层上的。 而”李东”,”亚健康终结者”这两条消息在进入传输层时使用的是传输层上的 TCP 协议。消息在进入传输层(TCP)时会被切片为一个个数据包。这个数据包的长度是MSS。 可以把网络比喻为一个水管,是有一定的粗细的,这个粗细由网络接口层(数据链路层)提供给网络层,一般认为是的MTU(1500),直接传入整个消息,会超过水管的最大承受范围,那么,就需要进行切片,成为一个个数据包,这样消息才能正常通过“水管”。 数据分片 MTU 和 MSS 有什么区别 MSS和MTU的区别 MTU: Maximum Transmit Unit,最大传输单元。 由网络接口层(数据链路层)提供给网络层最大一次传输数据的大小;一般 MTU=1500 Byte。 假设IP层有 <= 1500 byte 需要发送,只需要一个 IP 包就可以完成发送任务;假设 IP 层有> 1500 byte 数据需要发送,需要分片才能完成发送,分片后的 IP Header ID 相同。 MSS:Maximum Segment Size 。TCP 提交给 IP 层最大分段大小,不包含 TCP Header 和 TCP Option,只包含… Continue reading 图解 | 为嘛有 TCP 粘包和拆包
面试必备!TCP协议经典十五连问!
前言 TCP协议是大厂面试必问的知识点。整理了15道非常经典的TCP面试题,希望大家都找到理想的offer呀 公众号:捡田螺的小男孩 1. 讲下TCP三次握手流程 开始客户端和服务器都处于CLOSED状态,然后服务端开始监听某个端口,进入LISTEN状态 第一次握手(SYN=1, seq=x),发送完毕后,客户端进入 SYN_SEND 状态 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1), 发送完毕后,服务器端进入 SYN_RCVD 状态。 第三次握手(ACK=1,ACKnum=y+1),发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手,即可以开始数据传输。 2.TCP握手为什么是三次,不能是两次?不能是四次? TCP握手为什么是三次呢?为了方便理解,我们以谈恋爱为例子:两个人能走到一起,最重要的事情就是相爱,就是我爱你,并且我知道,你也爱我,接下来我们以此来模拟三次握手的过程: 为什么握手不能是两次呢? 如果只有两次握手,女孩子可能就不知道,她的那句我也爱你,男孩子是否收到,恋爱关系就不能愉快展开。 为什么握手不能是四次呢? 因为握手不能是四次呢?因为三次已经够了,三次已经能让双方都知道:你爱我,我也爱你。而四次就多余了。 3. 讲下TCP四次挥手过程 第一次挥手(FIN=1,seq=u),发送完毕后,客户端进入FIN_WAIT_1 状态 第二次挥手(ACK=1,ack=u+1,seq =v),发送完毕后,服务器端进入CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态 第三次挥手(FIN=1,ACK1,seq=w,ack=u+1),发送完毕后,服务器端进入LAST_ACK 状态,等待来自客户端的最后一个ACK。 第四次挥手(ACK=1,seq=u+1,ack=w+1),客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。 4. TCP挥手为什么需要四次呢? 举个例子吧! ★… Continue reading 面试必备!TCP协议经典十五连问!
Linux 篇: Epoll 实现的多路复用为什么这么快?
坚持思考,就会很酷 在 Linux 系统之中有一个核心武器:epoll 池,在高并发的,高吞吐的 IO 系统中常常见到 epoll 的身影。 IO 多路复用 在 Go 里最核心的是 Goroutine ,也就是所谓的协程,协程最妙的一个实现就是异步的代码长的跟同步代码一样。比如在 Go 中,网络 IO 的 read,write 看似都是同步代码,其实底下都是异步调用,一般流程是: write ( /* IO 参数 */ ) 请求入队 等待完成 后台 loop 程序 发送网络请求 唤醒业务方 Go 配合协程在网络 IO 上实现了异步流程的代码同步化。核心就是用 epoll 池来管理网络 fd 。 实现形式上,后台的程序只需要 1 个就可以负责管理多个 fd 句柄,负责应对所有的业务方的 IO 请求。这种一对多的 IO 模式我们就叫做 IO 多路复用。 多路是指?多个业务方(句柄)并发下来的 IO 。 复用是指?复用这一个后台处理程序。 站在 IO… Continue reading Linux 篇: Epoll 实现的多路复用为什么这么快?
内存随机也比顺序访问慢,带你深入理解内存IO过程
点击上方蓝色小字,关注“涛哥聊Python” 重磅干货,第一时间送达 来源:开发内功修炼 平时大家都知道内存访问很快,今天来让我们来思考两个问题: 问题1: 内存访问一次延时到底是多少?你是否会进行大概的估算? 例如笔者的内存条的Speed显示是1066MHz,那是否可以推算出内存IO延时是1s/1066MHz=0.93ns? 这种算法大错特错。 问题2: 内存存在随机IO比顺序IO慢的问题吗?我们都知道磁盘的随机IO要比顺序IO慢的多(操作系统底层还专门实现了电梯调度算法来缓解这个问题),那么内存的随机IO会比顺序IO慢吗? 要想彻底弄明白以上两个问题,我想我们得从内存IO的物理过程中来寻找答案。 1 先给你讲个图书管理员的故事 在开始介绍枯燥的内存工作原理之前。我想先给你讲一个故事,并带你去认识一个人,图书馆的管理员。 在我们的这个故事中,你是故事的主角。你有一所房子,房子里有一个仆人,他每天帮你处理各种各样的图书数据。但是北京房价太贵,所以你的这个房子很小,只能放的下64本书。你家的马路对面,就是北京图书馆(你家房子虽然小但是地段还不错),你所需要的所有的图书在那里都可以找到。图书馆有个管理员,他负责帮你把你想要的书找出来。 图1 图书管理员的故事 好接下来,故事开始进行! 场景1: 你发现你需要编号为0的书的计算结果,你的仆人穿过马路告诉了图书管理员,告诉他请帮我把第0-63本书取出来。图书管理员帮你在电脑前查得该书在二楼。于是他,花了点时间坐电梯到了二楼。等到了二楼,他又花了点时间帮你找了出来。然后你的仆人抱着64本书放到了客厅,拿起第0本书帮你处理了起来。 场景2: 你发现你需要编号为1的书的计算结果,告诉你的仆人。你的仆人直接从客厅拿出来就可以处理了,这次你等的时间最短。 场景3: 你发现需要编号为65的书,你又告诉你的仆人。你的仆人穿过马路又去找了图书管理员。图书管理员还在二楼呢,听说这次需要65-127,这次他不用再花时间找楼层了。只是花时间找书就可以了。你的仆人把65-127的书放到了客厅(以前的0-63就都扔了),并帮你开始处理起65号书来。 场景4: 你发现你需要编号为10000的书,你告诉了你的仆人。你的仆人穿过马路去图书馆,找到了管理员。这次管理员查得你需要的书是在10楼,他得花点时间坐电梯过去。去了之后,他又得花点时间帮你找出来。 这四个场景里,我觉得你一定发现了不同情形下耗时的差异。 场景1和场景4花费的时间最多。因为图书管理员需要花时间坐电梯找楼层,需要花时间在楼内找书。 场景3次之,因为图书管理员直接就在楼层内,只需要花时间在楼内找书既可 场景2最快,因为只需要仆人帮你从客厅拿过来就好,连马路都不需要过。 之所以编造这么一个例子,是因为内存的工作方式和它太像了。接下来我们进入内存的实际分析。 2 内存物理结构 在《带你理解内存对齐最底层原理》中我们了解了内存颗粒的物理构造以及IO过程,今天我们再来复习一下。 内存是由chip构成。每个chip内部,是由8个bank组成的。其构造如下图: 图2 内存颗粒chip内部结构 而每一个bank是一个二维平面上的矩阵,前面文章中我们说到过。矩阵中每一个元素中都是保存了1个字节,也就是8个bit。 图3 bank内部物理结构 每当CPU向内存请求数据的时候,内存芯片总是8个bank并行一起工作。每个bank在定位到行地址后,把对应的行copy到row buffer。再根据列地址把对应的元素中的数据取出来,8个bank把数据拼接一下,一个64位宽的数据就可以返回给CPU了。 图4 一次内存IO的过程示意 根据上面几张图我们可以大致了解内存的IO过程,在这个过程中每一步操作之间都有一些延迟,让我们来继续了解这些延迟。 3 内存IO延迟 在《从DDR发展到DDR4,内存核心频率指标其实基本上就没太大的进步》里我们提到内存的延迟很大程度是受核心频率制约的,你也应该记得我们提到了内存延迟一般是通过CL-tRCD-tRP-tRAS四个参数来标识的。我们今天来详细理解一下这四个参数的含义: CL(Column Address Latency):发送一个列地址到内存与数据开始响应之间的周期数 tRCD(Row Address to Column Address Delay):打开一行内存并访问其中的列所需的最小时钟周期数… Continue reading 内存随机也比顺序访问慢,带你深入理解内存IO过程
图解|高性能服务器设计之缓存系统一致性
缓存系统交互 缓存系统设计是后端开发人员的必备技能,也是实现高并发的重要武器。 对于读多写少的场景,我们通常使用内存型数据库作为缓存,关系型数据库作为主存储,从而形成两层相互依赖的存储体系。 < data-tool=”mdnice编辑器” style=”border-top: none; border-bottom: none; font-size: 0.9em; overflow: auto; color: #6a737d; padding: 10px 10px 10px 20px; margin-bottom: 20px; margin-top: 20px; border-left-color: rgba(0, 0, 0, 0.65); border-right: 1px solid rgba(0, 0, 0, 0.65); background: #f9f9f9;”> 共识:我们将使用Redis和MySQL作为缓存和主存的实体,展开今天的话题。 </> 缓存系统需要处理读取场景和更新场景: 读取时只要之前MySQL和Redis中的数据是一致的,后续只要没有更新操作就不会有什么问题,借助于内存读取速度来提高并发能力,这也是我们设计缓存系统的初衷。 单纯读取的情况并不多,即使是读多写少的业务模型,也还是会有更新操作,由于操作MySQL和Redis并非天然的原子操作,因此需要我们特殊处理。 读取过程示意: < data-tool=”mdnice编辑器” style=”border-top: none; border-bottom: none; font-size: 0.9em; overflow: auto; color:… Continue reading 图解|高性能服务器设计之缓存系统一致性