当年,兔子学姐靠这个面试小抄拿了个22k,2024年最新今日头条面试有几轮

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

短连接表示“业务处理+传输数据的时间 远远小于 TIMEWAIT超时的时间”的连接。

UDP想可靠

======

就要接收方收到UDP之后回复个确认包,发送方有个机制,收不到确认包就要重新发送,每个包有递增的序号,接收方发现中间丢了包就要发重传请求,当网络太差时候频繁丢包,防止越丢包越重传的恶性循环,要有个发送窗口的限制,发送窗口的大小根据网络传输情况调整,调整算法要有一定自适应性。

网络访问过程

==============================================================================================================================

域名解析

–> 发起TCP的3次握手 拿到域名对应的IP地址之后,浏览器向服务器的WEB程序(tomcat,nginx)80端口发起TCP连接请求。

–> 建立TCP连接后发http请求

–> 服务器响应http请求,浏览器得到html代码

–> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片)

–> 浏览器对页面渲染呈现

域名解析:搜索浏览器的DNS缓存 操作系统的DNS缓存  hosts文件C:\Windows 迭代DNS解析请求(根名称/顶级名称/二级名称/权威名称服务器)

为什么tcp可靠?

=================================================================================================================================

流量控制(滑动窗口)

发送方通过维持一个发送窗口确保不会发生发送方发太快接收方无法及时处理。

TCP如何保证可靠传输?

1**、确认和重传:**接收方收到报文就会确认,发送方发送一段时间后没有收到确认就重传。

2**、数据校验**

1**)ack:数据丢失或延迟。发送时会起定时器,如果指定时间内没接收到ACK seq + 1,就再发一次。**

2**)数据乱序:接收方上一个收到的正确数据是seq + 4,它返回seq + 5作为ACK。这时候它收到了seq + 7,因为顺序错了,所以接收方会再次返回seq + 5给发送方。**

3**)数据错误:每一个TCP数据都会带着数据的校验和。接收方收到数据seq + 3以后会先对校验和进行验证。如果结果不对,则发送ACK seq + 3,让发送方重新发送数据。**

4**)数据重复:接收方直接丢弃重复数据。**

3**、流量控制:**当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。

4**、拥塞控制:**当网络拥塞时,减少数据的发送。

流量控制与滑动窗口

流量控制是为了控制发送方发送速率,保证接收方来得及接收。

接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为0,则发送方不能发送数据。

发送方和接收方各有一个窗口,接收方通过窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其它信息设置自己的窗口大小。

TCP使用累计确认(发送方一次发送多个连续包,接收方只需要确认最后一个包),快速重传(收到3个冗余的ACK包立马重传,不用等待超时)以及选择重传(只对丢失的包进行重传)提高效率

TCP****的拥塞控制与拥塞窗口

拥塞控制:防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。

发送方维持一个拥塞窗口 cwnd的状态变量。动态地在变化。发送方让自己的发送窗口等于拥塞。

原则:没拥塞,窗口就增大一些,以便把更多的分组发送出去。

出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数。

几种拥塞控制方法:慢开始、拥塞避免、快重传和快恢复。

**慢开始:**不清楚网络的负荷情况。因此先探测一下,由小到大逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值。

通常在刚刚开始发送报文段时,先把拥塞窗口 cwnd 设置为一个最大报文段MSS的数值。而在每收到一个对新的报文段的确认后,把拥塞窗口增加至多一个MSS的数值。用这样的方法逐步增大发送方的拥塞窗口 cwnd ,可以使分组注入到网络的速率更加合理。

慢开始门限ssthresh的用法如下:

当 cwnd < ssthresh 时,使用慢开始算法

当 cwnd > ssthresh 时,改用拥塞避免算法。

当 cwnd = ssthresh 时,都可以

拥塞避免算法:经过一个往返时间RTT就把拥塞窗口cwnd加1,不是加倍。按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。

只要发送方判断网络出现拥塞(其根据就是没有收到确认),就要把门限ssthresh设置为出现拥塞时的发送方窗口值的一半(但不能小于2)。然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。目的就是要迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。

快速恢复算法:发送方认为网络很可能没有发生拥塞,因此而是把cwnd值设置为门限减半后的数值,然后使拥塞窗口线性增大。

UDP可靠

=====

最简单的方式是在应用层模仿传输层TCP的可靠性传输。下面不考虑拥塞处理,可靠UDP的简单设计。

1、添加seq/ack机制,确保数据发送到对端

2、添加发送和接收缓冲区,主要是用户超时重传。

3、添加超时重传机制。

详细说明:送端发送数据时,生成一个随机seq=x,然后每一片按照数据大小分配seq。数据到达接收端后接收端放入缓存,并发送一个ack=x的包,表示对方已经收到了数据。发送端收到了ack包后,删除缓冲区对应的数据。时间到后,定时任务检查是否需要重传数据。

目前有如下开源程序利用udp实现了可靠的数据传输。分别为RUDP、RTP、UDT。

HTTP and HTTPS

======================================================================================================================================

通信使用明文,内容可能被窃听(重要密码泄露)

不验证通信方身份,有可能遭遇伪装(跨站点请求伪造)

无法证明报文的完整性,有可能已遭篡改(运营商劫持)

http+加密+认证+完整性保护=https

1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。

2、https则是通过TLS加密后传输。SSL 是“Secure Sockets Layer”的缩写,中文叫做“安全套接层”

3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

对称密钥加密,又称私钥加密,即发送方和接收方用同一个密钥去加密解密。优势是速度快,适合于对大数据量进行加密,但密钥管理困难。

非对称密钥加密,又称公钥加密,需要使用一对密钥分别完成加密和解密,一个公开发布,即公开密钥,另一个由用户自己保存,即私用密钥。信息发送者用公开密钥去加密,而信息接收者则用私用密钥去解密。

从功能角度而言非对称加密比对称加密功能强大,但加密和解密速度却比对称密钥加密慢得多。

SSL/TLS协议,公钥加密法,客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密,如何保证公钥不被篡改?

解决方法:将公钥放在数字证书中,只要证书是可信的,公钥就是可信的。

HTTP方法及相互区别

===================================================================================================================================

GET 用于获取,而 POST 用于传输实体主体。

GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体中。不能因为 POST 参数存储在实体主体中就认为它的安全性更高,因为照样可以通过一些抓包工具(Fiddler)查看

因为 URL 只支持 ASCII 码,因此 GET 的参数中如果存在中文等字符就需要先进行编码。例如中文会转换为%E4%B8%AD%E6%96%87 ,而空格会转换为%20。POST参数支持标准字符集。

GET请求在URL中传送的参数是有长度限制的,而POST么有

HEAD获取报文首部,和 GET 方法类似,但是不返回报文实体主体部分

状态码

===========================================================================================================================

1正常2成功3重定向4客户端错误5服务端错误

100 Continue :表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。

200 OK

204 No Content :请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。

206 Partial Content :表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容。

301 Moved Permanently :永久性重定向

302 Found :临时性重定向

303 See Other :和 302 有着相同的功能,但是 303 明确要求客户端应该采用 GET 方法获取资源。

304 Not Modified :表示资源在由请求头中的If-Modified-Since或If-None-Match参数指定的这一版本之后,未曾被修改。在这种情况下,由于客户端仍然具有以前下载的副本,因此不需要重新传输资源。

307 Temporary Redirect :临时重定向,与302相反,当重新发出原始请求时,不允许更改请求方法。

400 Bad Request :请求报文中存在语法错误

401 Unauthorized :该状态码表示发送的请求需要有认证信息。如果之前已进行过一次请求,则表示用户认证失败

403 Forbidden :请求被拒绝

404 Not Found :请求失败,请求所希望得到的资源未被在服务器上发现,但允许用户的后续请求。

500 Internal Server Error :服务器正在执行请求时发生错误

503 Service Unavailable :服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。

504 Gateway Timeout作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器

http结构

==============================================================================================================================

一个HTTP请求报文由四个部分组成:请求行、请求头部、空行、请求数据。

1.请求行:由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。比如 GET /data/info.html HTTP/1.1

方法字段就是HTTP使用的请求方法,比如常见的GET/POST

其中HTTP协议版本有两种:HTTP1.0/HTTP1.1 可以这样区别:

HTTP1.0对于每个连接都只能传送一个请求和响应,请求就会关闭,HTTP1.0没有Host字段;而HTTP1.1在同一个连接中可以传送多个请求和响应,多个请求可以重叠和同时进行,HTTP1.1必须有Host字段。

2.请求头部

指明请求类型(一般是GET或者 POST)。大多数请求头并不是必需的,但post的Content-Length除外。

Accept: 浏览器可接受的MIME类型。

Accept-Charset:浏览器可接受的字符集。

Accept-Encoding:浏览器能够进行解码的数据编码方式,比如gzip。

Accept-Language:浏览器所希望的语言种类

Authorization:授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中。

Content-Length:表示请求消息正文的长度。

Host: 客户机通过这个头告诉服务器,想访问的主机名。Host头域指定请求资源的Intenet主机和端口号,必须表示请求url的原始服务器或网关的位置。HTTP/1.1请求必须包含主机头域,否则系统会以400状态码返回。

Referer:客户机通过这个头告诉服务器,它是从哪个资源来访问服务器的(防盗链)。包含一个URL,用户从该URL代表的页面出发访问当前请求的页面。

User-Agent:User-Agent头域的内容包含发出请求的用户信息。浏览器类型,如果Servlet返回的内容与浏览器类型有关则该值非常有用。

Cookie:客户机通过这个头可以向服务器带数据,这是最重要的请求头信息之一。

From:请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用到它。

Connection:处理完这次请求后是否断开连接还是继续保持连接。

同时指定几个范围:bytes=500-600,601-999

3.空行

它的作用是通过一个空行,告诉服务器请求头部到此为止。

4.请求数据

若方法字段是GET,则此项为空,没有数据

若方法字段是POST,则通常来说此处放置的就是要提交的数据

HTTP****响应报文由三部分组成:响应行、响应头、响应体

**1.**响应行

响应行一般由协议版本、状态码及其描述组成 比如 HTTP/1.1 200 OK

其中协议版本HTTP/1.1或者HTTP/1.0,200就是它的状态码,OK则为它的描述。

//常见状态码:

100~199:表示成功接收请求,要求客户端继续提交下一次请求才能完成整个处理过程。

200~299:表示成功接收请求并已完成整个处理过程。常用200

300~399:为完成请求,客户需进一步细化请求。例如:请求的资源已经移动一个新地址、常用302(意味着你请求我,我让你去找别人),307和304(我不给你这个资源,自己拿缓存)

400~499:客户端的请求有错误,常用404(意味着你请求的资源在web服务器中没有)403(服务器拒绝访问,权限不够)

500~599:服务器端出现错误,常用500

**2.**响应头

响应头用于描述服务器的基本信息,以及数据的描述,服务器通过这些数据的描述信息,可以通知客户端如何处理等一会儿它回送的数据。

设置Cookie,指定修改日期,指示浏览器按照指定的间隔刷新页面,声明文档的长度以便利用持久HTTP连接,……等等许多其他任务。

常见的响应头字段含义:

Allow:服务器支持哪些请求方法(如GET、POST等)。

Content-Encoding:文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。

Content-Length:表示内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据。

Content- Type:表示后面的文档属于什么MIME类型。Servlet默认为text/plain,但通常需要显式地指定为text/html。由于经常要设置 Content-Type,因此HttpServletResponse提供了一个专用的方法setContentType。

Date:当前的GMT时间,例如,Date:Mon,31Dec200104:25:57GMT。Date描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。你可以用setDateHeader来设置这个头以避免转换时间格式的麻烦。

Location:这个头配合302状态码使用,用于重定向接收者到一个新URI地址。表示客户应当到哪里去提取文档。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302。

Refresh:告诉浏览器隔多久刷新一次,以秒计。

Set-Cookie:设置和页面关联的Cookie。Servlet不应使用response.setHeader(“Set-Cookie”, …),而是应使用HttpServletResponse提供的专用方法addCookie。

Transfer-Encoding:告诉浏览器数据的传送格式。

注:设置应答头最常用是HttpServletResponse的setHeader,方法有两个参数:应答头的名字和值。和设置状态代码相似,设置应答头应该在发送任何文档内容之前进行。

setDateHeader方法和setIntHeadr方法专门用来设置包含日期和整数值的应答头,前者避免了把Java时间转换为GMT时间字符串的麻烦,后者则避免了把整数转换为字符串的麻烦。

HttpServletResponse设置

setContentType:设置Content-Type头。大多数Servlet都要用到这个方法。

addCookie:设置一个Cookie(Servlet API中没有setCookie方法,因为应答往往包含多个Set-Cookie头)。

**3.**响应体

响应体就是响应的消息体,如果是纯数据就是返回纯数据,如果请求的是HTML页面,那么返回的就是HTML代码,如果是JS就是JS代码,如此之类。

Tcp结构

=============================================================================================================================

六位标志位包含以下几项:

URG:表示紧急指针是否有效;

ACK:表示确认号是否有效,携带ACK标志的数据报文段为确认报文段;

PSH:提示接收端的应用程序应该立即从TCP接受缓冲区中读走数据,为接受后续数据腾出空间;

RST:表示要求对方重新建立连接,携带RST标志位的TCP报文段成为复位报文段;

SYN:表示请求建立一个连接,携带SYN标志的TCP报文段为同步报文段;

FIN:通知对方本端要关闭了,带FIN标志的TCP报文段为结束报文段。

确认序号:

Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。

TCP头部选项:

TCP头部选项是一个可变长的信息,这部分最多包含40字节,因为TCP头部最长60字节,(其中还包含前面20字节的固定部分)。

为什么在TCP首部的开始便是首部长度字段而UDP首部却没有?

因为UDP提供无连接服务,它的数据包包头,是固定长度的8字节,不存在可选字段,可以减少很多传输开销,所以它无需使用首部字段长,因为它的首部就是固定的。

而TCP提供连接服务,它的数据包包头,除了固定的20字节之外,还存在一个可选项,这个可选项字段,是根据TCP连接的要求而变动。这一字段最常见到的就是最大报文大小MSS,它指明发送端所能接收的最大长度的报文段。因为这个字段的存在,所以TCP包头使用了首部长字段。它占4位,以四字节为单位表示TCP包头长度,也就是说,TCP的首部最大长度可以是15x4=60字节,而可选项长可以为60-20=40字节

Socket

======

ServerSocket serverSocket = new ServerSocket(12016);//监听

do {

Socket socket = serverSocket.accept();//获取IO流

InputStream is = socket.getInputStream();

OutputStream os = socket.getOutputStream();

byte[] cache = new byte[1024];

is.read(cache);//读

cmd = new String(cache);

os.write(returnText.getBytes());//写

os.flush();

is.close();

os.close();

} while (!returnText.equals(“end”));

redisredisredis****数据结构

===========================================================================================

字符串

相对于c的改进:

**获取长度:**c遍历字符串,redis直接读len

**缓冲区安全:**c字符串容易缓冲区溢出,比如:没有分配足够空间就执行拼接操作。

redis会先检查空间是否满足要求,如果不满足会自动扩充。

内存分配:c长度变化总是内存重新分配。

redis:1、预分配:如修改后大于1MB,分配  1MBfree空间。修改长度时检查,够的话就用free空间2、惰性空间释放:缩短时不需要释放空间,用free记录即可,留作以后使用。

二进制安全

c字符串程序读到空字符会误以为是结尾,所以 c字符串不能保存二进制文件。

而redis字符串二进制安全,因为有len记录长度。

链表:双端、无环、带长度记录、多态:用 void* 指针来保存节点值。

_字典:_数组、大小、掩码(等于size-1),已有节点数量

_整数集合:_数组、数量、编码方式

升级:计算新空间、转换并放入原来的数、放入新数

降级:无

压缩列表

连锁更新:在一个压缩列表中有多个连续的、长度介于 250 字节到 253 字节之间的节点 ,这时, 如果我们将一个长度大于等于 254 字节的新节点 new 设置为压缩列表的表头节点

对象

==============================================================================================================================

对象组成:// 类型// 编码// 指向底层实现数据结构的指针

不为对象关联固定编码,提升灵活性和效率,可以根据使用场景为对象设置不同编码。

字符串对象:long、字符串、embstr

列表对象:所有字符串元素长度小于 64 字节;元素数量小于 512 个:ziplist否则链表

哈希对象:所有键值对的字符串长度都小于 64 字节;数量小于 512 :ziplist 否则hashtable

集合对象:所有元素都是整数值;数量不超过 512 个:intset,否则hashtable

有序集合:所有元素的长度都小于 64 字节;元素数量小于 128 个;ziplist否则跳表

场景:

string_:常规计数:微博数,粉丝数等。_

hash 特别适合用于存储对象,如用户,商品

list__查找遍历等,可以lrange命令实现不断下拉分页

set__去重,点赞关注

sortedset 有序,做实时排行榜,礼物榜弹幕榜。

跳表

================================================================================================================================

比较

哈希表不是有序的。因此,在哈希表上只能做单个key的查找,不适宜做范围查找。

做范围查找,平衡树比skiplist操作要复杂。

在平衡树上,我们找到指定范围的小值之后,需要以中序遍历的顺序继续寻找其它不超过大值的节点。如果不对平衡树进行一定的改造,这里的中序遍历并不容易实现。而在skiplist上进行范围查找就非常简单,只需要在找到小值之后,对第1层链表进行若干步的遍历就可以实现。

**平衡树的插入和删除操作可能引发子树的调整,逻辑复杂,**而skiplist的插入和删除只需要修改相邻节点的指针,操作简单又快速。

**从内存占用上来说,skiplist比平衡树更灵活一些。**一般来说,平衡树每个节点包含2个指针(分别指向左右子树),而skiplist每个节点包含的指针数目平均为1/(1-p),具体取决于参数p的大小。如果像Redis里的实现一样,取p=1/4,那么平均每个节点包含1.33个指针,比平衡树更有优势。

**从算法实现难度上来比较,**skiplist比平衡树要简单得多。

Redis__中的skiplist和经典有何不同

skiplist的key允许重复。这在最开始介绍的经典skiplist中是不允许的。

在比较时,不仅比较key,还比较数据本身。在Redis的skiplist实现中,数据本身的内容唯一标识这份数据,而不是由key来唯一标识。另外,当多个元素分数相同的时候,还需要根据数据内容来进字典排序。

第1层链表不是一个单向链表,而是一个双向链表。这是为了方便以倒序方式获取一个范围内的元素。

在skiplist中可以很方便地计算出每个元素的排名(rank)。

作者原话

有几个原因:

1_)它们的记忆力不是很强。基本上由你决定。更改有关节点具有给定数量级别的概率的参数将使内存密集度低于btree。_

2_)排序集通常是许多Zrange或Zrevrange操作的目标,即作为链表遍历跳过列表。通过此操作,跳过列表的缓存区域性至少与其他类型的平衡树一样好。_

3_)它们易于实现、调试等。例如,由于跳过列表的简单性,我收到了一个补丁(已经在redis master中),其中包含在o(log(n))中实现zrank的扩展跳过列表。它只需要对代码稍作修改。_

HyperLogLog

=======================================================================================================================================

是一种概率数据结构,用来估算数据的基数。数据集可以是访客 IP 地址,E-mail 或用户 ID。

基数就是指一个集合中不同值的数目set

使用 Redis 统计集合的基数有三种方法:用 Redis 的 HashMap,BitMap 和 HyperLogLog。前两个在集合的数量级增长时,所消耗的内存会大大增加,但是 HyperLogLog 不会。

HyperLogLog 通过牺牲准确率来减少内存空间的消耗,只需要12K内存,在标准误差0.81%的前提下,能够统计2^64个数据。所以 HyperLogLog 是否适合在比如统计日活月活此类的对精度要不不高的场景。

这是一个很惊人的结果,以如此小的内存来记录如此大数量级的数据基数。

命令

_> PFADD visitors a b c//_插入

_(integer) 1//_数量变化返回1

_> PFCOUNT visitors//_获取数量

(integer) 3

> PFADD customers alice dan->(integer) 1

_> PFMERGE a b d//_合并

OK

> PFCOUNT everyone->(integer) 4

通过Hash函数,将元素转为64位比特串,0 代表反面,1 代表正面,从左往右第1个1

HyperLogLog_: 一共分了 2^14=16384 个桶,。每个桶中是一个 6 bit 的数组。将上文所说的 64 位比特串的低 14 位单独拿出,值对应桶号,然后将第一次出现 1 的位置值设置到桶中。50位中出现1的位置值最大为50,所以每个桶中的 6 位数组正好可以表示该值。_

HyperLogLog 对象中的 registers 数组就是桶,它有两种存储结构,分别为密集存储结构和稀疏存储结构,从中我们可以看到 Redis 对节省内存极致地追求。

真使用足够多的 uint8_t 字节去表示,只是此时会涉及到字节位置和桶的转换,因为字节有 8 位,而桶只需要 6 位。所以我们需要将桶的序号转换成对应的字节偏移量 offsetbytes 和其内部的位数偏移量 offsetbits。

当 offset_bits 小于等于2时,说明一个桶就在该字节内,只需要进行倒转就能得到桶的值。

offset_bits 大于 2 ,则说明一个桶分布在两个字节内,此时需要将两个字节的内容都进行倒置,然后再进行拼接得到桶的值。

Redis 为了方便表达稀疏存储,

单线程

=================================================================================================================================

1、完全基于内存

2、数据结构简单, Redis中的数据结构是专门进行设计的;

3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用考虑锁的问题,没有因为可能出现死锁。

4、使用多路I/O复用模型,非阻塞IO;

多路I/O复用模型是利用 select、poll、epoll 可以同时监察多个流的 I/O 事件的能力,空闲时,当前线程阻塞,当有流有 I/O 事件时,就唤醒,于是程序就会轮询一遍所有的流(epoll 只轮询那些发出了事件的流),并且只依次顺序的处理就绪的流,避免了大量无用操作。

持久化


RDB持久化-获得内存里的数据在某个时间点上的副本。 (这称为“半持久化模式”,RDB,redis****默认持久化方式);实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前文件,用二进制压缩存储。

优势:1,数据库将只包含一个文件,这对于文件备份来说非常完美;

2, 恢复容易。我们可以轻松的将一个文件压缩后转移到其它存储介质上;

3, 性能最大化;对于服务进程而言,开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。

劣势:

1, 存在数据丢失的可能。此前没有来得及写入磁盘的数据都将丢失。

2, 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。

AOF持久化-把每一次数据变化都写入到一个AOF文件中(“全持久化模式”)

优点:

1, 该机制可以带来更高的数据安全性。AOF有3种同步策略,即每秒同步、每修改同步和不同步。

缺点:平时运行效率低;AOF文件通常大于RDB文件;恢复速度慢。

Redis和数据库双写一致性

==============================================================================================================================================

读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据放入缓存,同时返回响应。

更新的时候,先删除缓存,然后更新数据库。

(1)先淘汰缓存

(2)再写数据库(这两步和原来一样)

(3)休眠1秒,再次淘汰缓存

这么做,可以将1秒内所造成的缓存脏数据,再次删除。

缓存击穿雪崩穿透

====================================================================================================================================

缓存击穿是针对缓存中没有但数据库有的数据。场景是,当某个Key失效后,瞬间涌入大量的请求同一个Key,这些请求不会命中Redis,都会请求到DB,导致数据库压力过大

解决办法

1、设置热点Key,自动检测热点Key,将热点Key的过期时间加大或者永不过期。

2、加互斥锁。当发现没有命中Redis,去查数据库的时候,在执行更新缓存的操作上加锁,当一个线程访问时,其它线程等待,这个线程访问过后,缓存中的数据会被重建,这样其他线程就可以从缓存中取值。

缓存雪崩是指大量Key同时失效,对这些Key的请求又会打到DB上,同样会导致数据库压力过大甚至挂掉。

解决办法

1)让Key的失效时间分散开,可以在统一的失效时间上再加一个随机值,或者使用更高级的算法分散失效时间。

2)构建多个redis实例,个别节点挂了还有别的可以用。

3)多级缓存:比如增加本地缓存,减小redis压力。

4)对存储层增加限流措施,当请求超出限制,提供降级服务(一般就是返回错误即可)

缓存穿透: 一些恶意的请求会故意查询redis不存在的key,请求量很大,就会对后端系统造成很大的压力。

1:对查询结果为空的情况也进行缓存,这样,再次访问时,缓存层会直接返回空值。缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。

2:对一定不存在的key进行过滤。具体请看布隆过滤器

解决Redis并发竞争Key问题

============================================================================================================================================

多个系统同时对一个 key 进行操作,但是最后执行的顺序和我们期望的顺序不同,这样也就导致了结果的不同!

推荐一种方案:分布式锁(zookeeper 和 redis 都可以实现分布式锁)。(如果不存在 Redis 的并发竞争 Key 问题,不要使用分布式锁,这样会影响性能)

Redis缓存策略

=========================================================================================================================================

1. volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

当需要淘汰一个key时,随机选择3个key,淘汰其中间隔时间最长的key。**基本上淘汰key效果很好。后来随机3个key改成一个配置项"N随机key"。但把默认值提高改成5个后效果大大提高。考虑到它的效果,你根本不用修改他。

版权声明:本文为CSDN博主「一只大白兔兔兔兔兔」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://fantianzuo.blog.csdn.net/article/details/102580321

2. volatile-ttl:挑选将要过期的数据淘汰

3. volatile-random:任意选择数据淘汰

4. allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的).

5. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

6. no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。

哨兵

==============================================================================================================================

1)Sentinel(哨兵) 进程用于监控集群中 Master 主服务器工作的状态

2)在主服务器故障时,可以实现 Master 和 Slave 服务器切换,保证系统的高可用

工作方式

1)每个 Sentinel(哨兵)进程每秒钟一次向所有服务器和哨兵进程发送一个 PING 命令。

2. 如果一个实例距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 这个实例会被 Sentinel(哨兵)进程标记为主观下线。

3. 如果一个 Master 主服务器被标记为主观下线,则正在监视这个 Master 主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认 Master 主服务器的确进入了主观下线状态。

4. 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认 Master 主服务器进入了主观下线状态, 则Master 主服务器会被标记为客观下线(ODOWN)。

5. 在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master 主服务器、Slave 从服务器发送 INFO 命令。

6. 当 Master 主服务器被 Sentinel(哨兵)进程标记为客观下线时,Sentinel(哨兵)进程向下线的 Master 主服务器的所有 Slave 从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。

7. 若没有足够数量的 Sentinel(哨兵)进程同意 Master 主服务器下线, Master 主服务器的客观下线状态就会被移除。若 Master 主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master 主服务器的主观下线状态就会被移除。

解决会话

========

(粘性session)

你可以设置nginx的分配策略,下次同一个还让同一个服务器来处理

但是很显然,这就和分布式和nginx初衷违背了:负载很难保证均衡。

(同步session)

一台服务器的session给所有服务器复制一份

第一,性能不好。第二,产生了一定的耦合

(专门session)

专门一台服务器来解决,存session,其它服务器来这个服务器取session再用。

但是也有问题:你这个服务器挂了怎么办?别的服务器都是依赖这个服务器工作的。我们分布式部署本来就是为了解决性能的瓶颈啊。

很容易想到,我们把那个处理session的服务器搞个集群:

更不行,想想就知道,本来就是为了解决分布式部署的问题,你把单独解决session的服务器又搞集群,和之前有什么区别呢?还不如一个服务器存一份简单呢。

可以,但是传统的关系数据库是存到硬盘里,速度太慢。

(nosql)

最终,我们的主流办法使用nosql数据库,比如redis,来解决这个问题的。

sqlsqlsqlsqllsqlslqslqslq数据类型

=============================

整数:1byte是tinyint 2 smallint 3mediumint 4int 8bigint

浮点数:float/double/real。定义方式为:FLOAT(M,D)一共显示M位其中D位小数点后面

Bit:MySQL把BIT当做字符串类型,而非数字类型。

字符串:CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。

Char固定长度,varchar随便,BINARY、VARBINARY是二进制,BLOB、TEXT是大的

mysql特点

=======

1.数据以表格的形式出现

2.每行为各种记录名称

3.每列为记录名称所对应的数据域

4.许多的行和列组成一张表单

5.若干的表单组成database

注:保证数据一致性。

注:关系型数据库,表与表之间存在对应关系。

注:非关系行数据库,表之间不存在关系,数据独立,随便存。

存储引擎

====

如果要提供提交、回滚和恢复的事务安全(ACID 兼容)能力,并要求实现并发控制,InnoDB

如果数据表主要用来插入和查询记录,则 MyISAM 引擎提供较高的处理效率。

如果只是临时存放数据,数据量不大,并且不需要较高的数据安全性,在内存的 MEMORY ,MySQL 中使用该引擎作为临时表,存放查询的中间结果。

增删改

===============================================================

–1. 表名后没有指定属性列:插入一条完整的

insert into student values (‘201215128’, ‘陈东’, ‘18’, ‘男’, ‘IS’);

–2. 在表明后指定要插入数据的表名及属性列,属性列的顺序可与表定义中的顺序不一致

insert into student(sno, sname, sage, ssex, sdept)

values (‘201215138’, ‘陈东栋’, ‘18’, ‘男’, ‘CS’);

–3. 插入部分列,未显示给出的列按空值计算,当然前提条件是那些列可以为空值

insert into student(sno, sname) values (‘201215148’, ‘陈栋’);

–1. 修改某些符合where子句中的条件的元组的值

update student set sage = 92 where sno = ‘200215121’;

–2. where子句缺省,默认修改所有元组的该属性的值

–3. 带子查询的修改

update sc set grade = 100

where ‘CS’ in (select sdeptfrom studentwhere sc.sno = student.sno);

Delete from student where sno = ‘201215148’;

范式

==============================================================

最重要的好处归结为三点:

1.减少数据冗余(这是最主要的好处,其他好处都是由此而附带的)

2.消除异常(插入异常,更新异常,删除异常)

3.让数据组织的更加和谐

第一范式 – 每表中的字段不可再分割

第二范式 – 要有主键,并且其他字段依赖于主键(方便唯一确定数据行,并定位其他字段)

第三范式 – 在二范式的基础上,消除传递依赖,各种信息只在一个地方存储,不出现在多张表中。比如学生信息表的学号为主键,此时要查看他所在的系信息,那么不能直接将系信息存储在学生信息表中,因为系信息已经在系别管理表中,此时只能在学生信息中添加系别管理表中的系编号字段(主键),这样既能根据系编号找到系别信息,又避免了冗余存储的问题。

BC范式 – 每个表中只有一个候选键(唯一标识表中每一行的键,候选键可以包含多个属性)

优化:

1)1对N关系中复制非键属性以减少连接

例:查询学生以及所在学院名,可以在学生表中不仅存储学院id,并且存储学院名

维护时:

如果在UI中,只允许用户进行选择,不能自行输入,保证输入一致性

如果是程序员,对于类似学院名这种一般不变的代码表,在修改时直接对两张表都进行修改;如果经常变化,则可以加一个触发器。

2)N对N关系中复制属性,把两张表中经常需要的内容复制到中间关系表中以减少连接

索引优缺点和使用原则

======================================================================

优点:

1、所有的MySql列类型(字段类型)都可以被索引,也就是可以给任意字段设置索引

2、大大加快数据的查询速度

缺点:

1、创建索引和维护索引要耗费时间,并且随着数据量的增加所耗费的时间也会增加

2、占空间,数据也会有最大上线设置的,大量索引文件可能比数据文件更快到上线

3、对表中的数据进行增加删改时,索引也需要动态的维护,降低了数据的维护速度。

使用原则:

1、对经常更新的表避免过多索引,对经常用于查询的字段应建索引,

2、数据量小的表最好不要使用索引,可能查询全部数据比遍历索引的时间还要短,

3、在值少的列上不要建立索引,比如"性别"字段上只有男女。

3-5、尽量选择区分度高的列,公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少

唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0

一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录

4、最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配

5、索引列不能参与计算,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因:存的都是数据表中的字段值,需要所有元素都应用函数才能比较

索引分类

================================================================

普通索引

(1)直接创建索引CREATE INDEX index_name ON table(column(length))

(3)创建表的时候同时创建索引

CREATE TABLE `table` (

`id` int(11) NOT NULL AUTO_INCREMENT ,

`title` char(255) CHARACTER NOT NULL ,

PRIMARY KEY (`id`),

INDEX index_name (title(length))

)

唯一索引

列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。

(1)创建唯一索引CREATE UNIQUE INDEX indexName ON table(column(length))

(3)创建表的时候直接指定

主键索引

特殊的唯一索引,一个表只能有一个主键,不允许有空值。建表同时创建主键索引:

CREATE TABLE `table` (

`id` int(11) NOT NULL AUTO_INCREMENT ,

`title` char(255) NOT NULL ,

PRIMARY KEY (`id`)

);

组合索引

指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀集合

ALTER TABLE `table` ADD INDEX name_city_age (name,city,age);

全文索引

主要用来查找文本中的关键字,而不是直接与索引中的值相比较。fulltext索引跟其它索引大不相同,它更像是一个搜索引擎,而不是简单的where语句的参数匹配。

fulltext索引配合match against操作使用,而不是一般的where语句加like。

它可以在create table,alter table ,create index使用,不过目前只有char、varchar,text 列上可以创建全文索引。

在数据量较大时候,现将数据放入一个没有全局索引的表中,然后再用CREATE index创建fulltext索引,要比先为一张表建立fulltext然后再将数据写入的速度快很多。

CREATE TABLE `table` (

`id` int(11) NOT NULL AUTO_INCREMENT ,

`content` text CHARACTER NULL ,

PRIMARY KEY (`id`),

FULLTEXT (content)

);

聚集索引的叶子节点存储行记录,因此, InnoDB必须要有,且只有一个聚集索引:

(1)如果表定义了PK,则PK就是聚集索引;

(2)如果表没有定义PK,则第一个not NULL unique列是聚集索引;

(3)否则,InnoDB会创建一个隐藏的row-id作为聚集索引;

所以PK查询非常快,直接定位行记录。

回表:查到一个字段,再去找对应行

5.6优化,索引下推:a=1 and b like….and c like……,之前按查出第一个条件,返回数据,再筛,现在按索引筛完了like再返回查。

索引区别

================================================================

哈希索引适合等值查询,但是无法范围查询

哈希索引没办法利用索引完成排序

哈希索引不支持多列联合索引的最左匹配规则

如果有大量重复键值的情况下,哈希索引的效率会很低,因为存在哈希碰撞问题

局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用——程序运行期间所需要的数据通常比较集中。磁盘顺序读取的效率很高(不需寻道时间,只需很少的旋转时间)

预读的长度一般为页的整倍数。

在经典B+Tree的基础上进行了优化,增加了顺序访问指针。

平衡树缺点:深、离得远、

B和b+:只存索引,值全在叶子节点。

默认16KB一页,1行数据1K,一页16条数据。假设 bigint=8字节,指针在innodb是6字节,8+6=14,16KB/14=1170,三层可满足千万记录。

事务特性:ACID

=====================================================================

原子性(Atomicity):事务作为一个整体执行,对数据的操作要么全被执行,要么都不执行。

一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束(约定好的约束,如:AB相互转钱,A有500,B也有500,那么无论他们怎么转,最后的数额总数都会是1000)

隔离性(Isolation):多个事务并发执行时,不互相影响。

持久性(Durability):一个事务一旦提交,他对数据库的修改应该永久保存在数据库中。

并发错误

================================================================

第一类丢失更新:某一个事务的回滚,导致另外一个事务已更新的数据丢失了。

第二类丢失更新:某一个事务的提交,导致另外一个事务已更新的数据丢失了。

脏读:另一个事务修改了,但尚未提交,本事务读到未被提交的数据。

不可重复读:一个执行中,另一个更新,本事务先后读到的数据不一致。

幻读:某事务对同一个表前后查询到的行数不一致(中间有人插入)

幻读解决办法:使用串行化读的隔离级别

隔离级别

====

- Read Uncommitted:读取未提交的数据。事务可以读取到另一个事务未提交的修改。

- Read Committed:(有的库默认)读取已提交的数据。事务只能读取另个事务已提交修改。

- Repeatable Read:(mysql默认)可重复读。同一个事务多次读取相同数据返回结果一样。

- Serializable:串行化 事务串行执行。读写数据锁表

1、读提交时,写数据只会锁住相应的行

2、可重复读时,如果检索条件有索引(包括主键索引),默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。

是否会发生

并发控制技术(锁)

=====================================================================

封锁(locking)(主要使用的)

基本的封锁类型有两种:排它锁(X锁,exclusive locks)、共享锁(S 锁,share locks)

排它锁又称写锁,对A加排它锁之后,其他事务不能对A加 任何类型的锁(排斥读和写)

共享锁又称读锁,对A加共享锁之后,其他事务只能对A加S锁,不能加X锁(只排斥写)

表级锁:开销小,加锁快、锁冲突概率高、不死锁。

行级锁:mysql默认,开销大、加锁慢、锁冲突概率高、可能死锁

间隙锁(NK):行级,使用范围条件时,对范围内不存在的记录加锁。一是为了防止幻读,二是为了满足恢复和复制的需要

增加行级锁之前,InnoDB会自动给表加意向锁;

• 执行增删改语句时,InnoDB会自动给数据加排他锁;

• 执行查询语句时

共享锁(S):SELECT … FROM … WHERE … LOCK IN SHARE MODE;

排他锁(X):SELECT … FROM … WHERE … FOR UPDATE;

间隙锁(NK):上述SQL采用范围条件时,InnoDB对不存在的记录自动增加间隙锁。

MVCC的实现,是通过保存数据在某个时间点的快照来实现的。也就是说,不管需要执行多长时间,每个事务看到的数据是一致的。根据事务开始的时间不同,每个事物对同一张表,同一时刻看到的数据可能是不一样的。

否则就更新数据(版本号+1)。

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。

使用数据版本(Version)记录机制实现

乐观锁(自定义)

- 版本号、时间戳等。。。在更新数据前,检查版本号是否发生变化。若变化则取消本次更新,

1. 版本号机制

UPDATE … SET …,VERSION=#{version+1} WHERE … AND VERSION=${version}

2. CAS算法(Compare and swap)

是一种无锁的算法,该算法涉及3个操作数(内存值V、旧值A、新值B),当V等于A时,

采用原子方式用B的值更新V的值。该算法通常采用自旋操作,也叫自旋锁。它的缺点是:

• ABA问题:某线程将A该为B,再改回A,则CAS会误认为A没被修改过。

• 自旋操作采用循环的方式实现,若加锁时间长,则会给CPU带来巨大的开销。

• CAS只能保证一个共享变量的原子操作。

死锁

==

• 场景

事务1: UPDATE T SET … WHERE ID = 1; UPDATE T SET … WHERE ID = 2;

事务2: UPDATE T SET … WHERE ID = 2; UPDATE T SET … WHERE ID = 1;

• 解决方案

1. 一般InnoDB会自动检测到,并使一个事务回滚,另一个事务继续;

2. 设置超时等待参数 innodb_lock_wait_timeout;

• 避免死锁

1. 不同的业务并发访问多个表时,应约定以相同的顺序来访问这些表;

2. 以批量的方式处理数据时,应事先对数据排序,保证线程按固定的顺序来处理数据;

3. 在事务中,如果要更新记录,应直接申请足够级别的锁,即排他锁;

分布式事务

=================================================================

分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。

分布式事务产生的原因总的来说有两个:1.service产生多个节点2.resource产生多个节点

CAP理论

- **C (**一致性):对某个指定的客户端来说,读操作能返回最新的写操作。

对于数据分布在不同节点上的数据来说,如果在某个节点更新了数据,那么在其他节点如果都能读取到这个最新的数据,那么就称为强一致,如果有某个节点没有读取到,那就是分布式不一致。

A (可用性):非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。

可用性的两个关键一个是合理的时间,一个是合理的响应。合理的时间指的是请求不能无限被阻塞,应该在合理的时间给出返回。合理的响应指的是系统应该明确返回结果并且结果是正确的,这里的正确指的是比如应该返回50,而不是返回40。

**P (分区容错性):当出现网络分区后,系统能够继续工作。**打个比方,这里个集群有多台机器,有台机器网络出现了问题,但是这个集群仍然可以正常工作。

**熟悉CAP的人都知道,三者不能共有,**如果感兴趣可以搜索CAP的证明,在分布式系统中,网络无法100%可靠,分区其实是一个必然现象,如果我们选择了CA而放弃了P,那么当发生分区现象时,为了保证一致性,这个时候必须拒绝请求,但是A又不允许,所以分布式系统理论上不可能选择CA架构,只能选择CP或者AP架构。

分布式事务常见的方案:2PC(两阶段提交)协调者(都成功才执行)

运行过程:

准备阶段(协调者询问参与者事务是否执行成功,参与者发回事务执行结果)

提交阶段(如果事务在每个参与者上都执行成功,事务协调者发送通知让参与者提交事务;否则,协调者发送通知让参与者回滚事务)

需要注意的是,在准备阶段,参与者执行了事务,但是还未提交。只有在提交阶段接收到协调者发来的通知后,才进行提交或者回滚。

存在问题:

1.同步阻塞:所有事务参与者在等待其它参与者时都阻塞。

2.单点问题:协调者在 2PC 中起到非常大的作用,发生故障将会造成很大影响。

3.数据不一致:网络异常,只有部分参与者接收到 Commit 消息,只有部分参与者提交了事务,使得系统数据不一致。

SQL语句性能优化

=====================================================================

1.    对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

2.    应尽量避免在 where 子句中使用!=或<>操作符, MySQL只有对以下操作符才使用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE。

3.    应尽量避免在 where 子句中使用 or 来连接条件, 否则将导致引擎放弃使用索引而进行全表扫描,可以使用UNION合并查询

4.    尽可能的使用 varchar代替 char, 因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

索引的优化

=================================================================

1.避免有索引但未被用到的情况:(1) Like的参数以通配符开头时(2)where条件不符合最左前缀原则时(3)使用!= 或 <> 操作符时(4)使用or来连接条件

2.避免使用 Select *

3.对order by语句进行优化:1.重写order by语句以使用索引 2.避免在order by子句中使用表达式。

4.对group by语句进行优化:将不需要的记录在group by之前过滤掉

5.使用exists代替in

分库分表

================================================================

垂直分库就是根据业务耦合性,将关联度低的不同表存储在不同的数据库。

水平切分分为库内分表和分库分表,是根据表内数据内在的逻辑关系,将同一个表按不同的条件分散到多个数据库或多个表中,每个表中只包含一部分数据,从而使得单个表的数据量变小,达到分布式的效果。

Kafka

=====

Docker步步实践

目录文档:

①Docker简介

②基本概念

③安装Docker

④使用镜像:

⑤操作容器:

⑥访问仓库:

⑦数据管理:

⑧使用网络:

⑨高级网络配置:

⑩安全:

⑪底层实现:

⑫其他项目:

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
都成功才执行)

运行过程:

准备阶段(协调者询问参与者事务是否执行成功,参与者发回事务执行结果)

提交阶段(如果事务在每个参与者上都执行成功,事务协调者发送通知让参与者提交事务;否则,协调者发送通知让参与者回滚事务)

需要注意的是,在准备阶段,参与者执行了事务,但是还未提交。只有在提交阶段接收到协调者发来的通知后,才进行提交或者回滚。

存在问题:

1.同步阻塞:所有事务参与者在等待其它参与者时都阻塞。

2.单点问题:协调者在 2PC 中起到非常大的作用,发生故障将会造成很大影响。

3.数据不一致:网络异常,只有部分参与者接收到 Commit 消息,只有部分参与者提交了事务,使得系统数据不一致。

SQL语句性能优化

=====================================================================

1.    对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

2.    应尽量避免在 where 子句中使用!=或<>操作符, MySQL只有对以下操作符才使用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE。

3.    应尽量避免在 where 子句中使用 or 来连接条件, 否则将导致引擎放弃使用索引而进行全表扫描,可以使用UNION合并查询

4.    尽可能的使用 varchar代替 char, 因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

索引的优化

=================================================================

1.避免有索引但未被用到的情况:(1) Like的参数以通配符开头时(2)where条件不符合最左前缀原则时(3)使用!= 或 <> 操作符时(4)使用or来连接条件

2.避免使用 Select *

3.对order by语句进行优化:1.重写order by语句以使用索引 2.避免在order by子句中使用表达式。

4.对group by语句进行优化:将不需要的记录在group by之前过滤掉

5.使用exists代替in

分库分表

================================================================

垂直分库就是根据业务耦合性,将关联度低的不同表存储在不同的数据库。

水平切分分为库内分表和分库分表,是根据表内数据内在的逻辑关系,将同一个表按不同的条件分散到多个数据库或多个表中,每个表中只包含一部分数据,从而使得单个表的数据量变小,达到分布式的效果。

Kafka

=====

Docker步步实践

目录文档:

[外链图片转存中…(img-Cx4lmazM-1713468798960)]

[外链图片转存中…(img-WUM1xlHP-1713468798961)]

①Docker简介

②基本概念

③安装Docker

[外链图片转存中…(img-Y8FMHGiz-1713468798961)]

④使用镜像:

[外链图片转存中…(img-iRObhFJO-1713468798962)]

⑤操作容器:

[外链图片转存中…(img-gsrev5uL-1713468798963)]

⑥访问仓库:

[外链图片转存中…(img-m106jJyZ-1713468798964)]

⑦数据管理:

[外链图片转存中…(img-50wEqvXQ-1713468798964)]

⑧使用网络:

[外链图片转存中…(img-iQBZ9Y17-1713468798965)]

⑨高级网络配置:

[外链图片转存中…(img-iN03xuII-1713468798965)]

⑩安全:

[外链图片转存中…(img-VN8Sf7GN-1713468798966)]

⑪底层实现:

[外链图片转存中…(img-QtlQ4kZh-1713468798966)]

⑫其他项目:

[外链图片转存中…(img-LsrwA5KO-1713468798967)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-adlGX0dU-1713468798968)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值