目录
Linux常用的命令
-
文件和目录操作:
ls
:列出目录内容。cd
:改变当前目录。pwd
:显示当前目录路径。mkdir
:创建新目录。rmdir
:删除空目录。rm
:删除文件或目录(使用-r
递归删除目录)。cp
:复制文件或目录。mv
:移动或重命名文件或目录。
-
文件内容查看和编辑:
cat
:连接文件并打印到标准输出。more
:逐页查看文件内容。less
:逐页查看文件内容,支持向前翻页。head
:显示文件的前几行。tail
:显示文件的后几行(使用-f
选项实时监控文件变化)。nano
、vi
、vim
:文本编辑器,用于编辑文件。awk
: 扫描文件或字符串,并对其内容进行格式化和报告。
-
文件权限和所有权:
chmod
:改变文件或目录的权限。chown
:改变文件或目录的所有者。chgrp
:改变文件或目录的所属组。
-
系统信息:
uname
:显示系统信息(使用-a
显示所有信息)。df
:显示文件系统磁盘空间使用情况。du
:显示文件或目录的磁盘使用情况。top
:实时显示系统运行的进程和系统资源使用情况。ps
:显示当前系统的进程列表。
-
网络:
ifconfig
:显示或配置网络接口。ping
:测试网络连通性。netstat
:显示网络相关信息(如网络连接、路由表等)。scp
:通过SSH在主机之间安全地复制文件。ssh
:通过SSH登录到远程主机。
-
归档和压缩:
tar
:创建、解压和管理归档文件(如tar.gz)。gzip
:压缩文件。gunzip
:解压文件。zip
:压缩文件。unzip
:解压文件。
-
包管理:
apt-get
:Debian和Ubuntu系统中的包管理工具(如apt-get install
安装软件包)。yum
:CentOS和Red Hat系统中的包管理工具(如yum install
安装软件包)。
-
其他有用的命令:
echo
:显示一段文本。man
:显示命令的帮助文档(如man ls
)。alias
:为命令创建别名。history
:显示命令历史。grep
:搜索文本文件中的内容。find
:查找文件或目录。
awk:
打印文件的每一行:awk '{print}' filename
打印第二列:awk '{print $2}' filename
将文件中的所有old
替换为new
:awk '{gsub(/old/, "new"); print}' filename
删除文件中的空行:awk 'NF > 0' filename
netstat:
显示TCP连接: netstat -t
显示路由表:netstat -r
以数字形式显示IP地址和端口: netstat -n
查看所有与端口80相关的连接: netstat -an | grep ':80'
统计所有接口的接收和发送数据包:netstat -i
网络抓包:
指定接口 eth0
捕获数据包:sudo tcpdump -i eth0
只捕获端口80的数据包:sudo tcpdump -i eth0 port 80
查看程序运行栈信息:
获取PID: jps
查看线程堆栈: jstack pid > thread_dump.txt
查看僵死进程: ps aux | grep 'Z'
用于显示当前系统上所有进程: ps -ef
进程、线程、协程
进程是一个运行中的程序,是操作系统分配资源的基本单位。每个进程都有自己的内存空间、数据段、代码段和堆栈段。
线程是进程中的一个执行单元,是CPU调度的基本单位。线程共享同一个进程的内存空间和资源,但每个线程有自己的栈、程序计数器和寄存器。
协程是一种比线程更轻量级的存在,是一种用户态的上下文切换技术。协程允许在函数执行过程中暂停和恢复,以实现非阻塞的并发执行。
进程通信方式
匿名管道:用于具有亲缘关系的进程之间(通常是父子进程)进行通信,单向通信。
在Linux中,使用 pipe()
系统调用创建匿名管道。
命名管道:用于无亲缘关系的进程之间通信,双向通信。
在Linux中,使用 mkfifo
命令创建命名管道文件。
消息队列:允许一个或多个进程向消息队列中发送和接收消息,可以进行有序且结构化的通信。
共享内存:允许多个进程共享一段内存,以进行快速的数据交换,但要同步机制来避免竞争条件。
信号量:用于进程间的同步,避免竞争条件和确保资源的有序使用。
套接字:用于不同主机之间的进程通信,可以通过网络传输数据。
信号:用于进程间发送简单的通知或控制命令。
输入一个网址,涉及到什么协议
1.URL解析 http 浏览器首先解析输入的URL
2.DNS解析 dns 浏览器需要将主机名转换为IP地址
3.TCP连接 tcp
浏览器通过三次握手(Three-Way Handshake)与服务器建立TCP连接。
- 客户端发送一个SYN(synchronize)包给服务器。
- 服务器返回一个SYN-ACK(synchronize-acknowledge)包给客户端。
- 客户端再发送一个ACK(acknowledge)包确认连接建立。
4.服务器接收到HTTP请求后,处理请求并返回HTTP响应。
5.浏览器接收到HTTP响应后,开始渲染页面。
DNS解析
用户输入域名:用户在浏览器中输入一个域名。
本地DNS缓存检查:浏览器检查本地缓存是否已有该域名的IP地址。
递归DNS查询:如果本地缓存中没有,操作系统将查询请求发送到配置的DNS服务器。
DNS服务器查询:递归DNS服务器通过多个步骤查询DNS记录。
返回结果:DNS服务器将查询结果返回给客户端。
为什么要三次握手,不是两次
第一次握手:客户端需要通知服务器自己希望建立连接
第二次握手:服务器需要确认收到客户端的SYN请求,并告知客户端自己也希望建立连接,并提供一个自己的序列号。通过这种方式,双方都能够确认对方的存在和同步状态。
第三次握手:客户端需要确认服务器的SYN-ACK报文段,确保双方的序列号和连接请求都得到了确认。
防止重复连接请求:如果只有两次握手,可能会出现重复连接请求的问题。服务器可能会误认为客户端的SYN请求是对之前连接的回应。第三次握手可以避免这种情况,因为它确保了客户端能够接收到服务器的确认,防止了旧的连接请求被重复处理。
连接同步:三次握手不仅建立了连接,还同步了双方的初始序列号。这对于确保数据的顺序和完整性至关重要。序列号在数据传输过程中用于跟踪和重组数据包。
确认双方收发能力:第一次握手(SYN)和第二次握手(SYN-ACK)确认了双方的存在和能力,但没有完全确认双方都能进行数据传输。第三次握手(ACK)确保双方都可以收到对方的确认,并完成了连接建立过程。
三次握手四次挥手区别,为什么多一次
1.客户端发送一个FIN报文段,表示它已经完成了数据的发送,要求断开连接。此时,客户端进入FIN_WAIT_1状态。
2.服务器收到客户端的FIN报文段后,回复一个ACK报文段,确认收到客户端的FIN报文段。此时,服务器进入CLOSE_WAIT状态,客户端进入FIN_WAIT_2状态。
3.服务器在处理完所有剩余的数据后,发送一个FIN报文段,表示服务器也完成了数据的发送,要求断开连接。此时,服务器进入LAST_ACK状态。
4.客户端收到服务器的FIN报文段后,回复一个ACK报文段,确认收到服务器的FIN报文段。此时,客户端进入TIME_WAIT状态,等待足够的时间以确保服务器收到了ACK,然后进入CLOSED状态。服务器在收到ACK后进入CLOSED状态。
可靠断开连接:断开连接时,双方需要独立确认对方的数据传输已经完成。这意味着一方可以先关闭连接发送数据,另一方在关闭连接之前可能仍需要时间来处理剩余的数据。
防止数据丢失:断开连接时,需要确保双方都完成了数据传输,以避免数据丢失。四次挥手确保所有剩余的数据都已经传输完毕,并且双方都确认对方的数据传输状态。
处理半关闭状态:四次挥手允许这种情况的正确处理,通过独立关闭接收和发送通道来确保可靠断开。
TIMEWAIT过多发生什么
端口耗尽,无法建立新连接:大量的 TIME_WAIT
状态可能会导致可用端口耗尽,阻止新的连接的建立。
系统资源浪费: 过多的 TIME_WAIT
状态会消耗更多的系统内存和处理能力。
数据冲突:旧数据包可能会在网络中停留较长时间,干扰新的连接,导致数据混乱或错误。
优化 TIME_WAIT
状态
优化网络环境,减少网络延迟和丢包率,扩大服务端 端口范围
允许在 TIME_WAIT
状态下重用端口,通过设置 SO_REUSEADDR
选项来实现
用连接池\长连接减少连接的频繁建立和断开。
缓存击穿、缓存雪崩、缓存穿透:
缓存击穿:在缓存中某个热点数据的缓存失效时,所有的请求都直接去访问数据库,造成数据库瞬间承受大量请求的现象。
解决方案:
- 使用互斥锁:在缓存失效时,使用互斥锁(或分布式锁)确保只有一个请求去重新加载数据,其他请求等待加载完成后从缓存中获取数据。
- 使用预热机制:提前加载数据到缓存中,在缓存失效之前快速刷新缓存。
缓存雪崩:指的是缓存中的大量数据在同一时间过期(或者Redis故障宕机),导致大量请求直接访问数据库,从而使数据库瞬间承受巨大的压力。
解决方案:
- 设置过期时间:设置缓存过期时间的随机偏移,避免大量缓存同时过期。
- 使用预热机制:在缓存失效之前,提前加载数据到缓存中,以避免大规模的缓存失效。
- 使用分布式缓存部署:例如,使用本地缓存和远程缓存相结合的方式,减少单点故障的影响。
- 程序限流
缓存穿透:指的是请求的数据在缓存中不存在,并且数据库中也不存在,导致每次请求都直接访问数据库。缓存穿透通常发生在请求的数据是无效数据或攻击者故意构造的无效数据时。
- 使用预热机制:在缓存失效之前,提前加载数据到缓存中,以避免大规模的缓存失效。
- 使用布隆过滤器:过滤无效请求
- 查询结果为空的数据,设置一个默认值和较短的缓存过期时间
Redis和MySQL数据同步
先删除缓存再更新数据库:如果有读请求,会因为缓存已经删除而去数据库读取旧数据,然后这些数据重被写入缓存,导致不一致
先更新数据库在删除缓存:如果有读请求,会读取到缓存中的旧数据。如果删除缓存失败,也会导致数据不一致。
解决方案:
1.延迟双删:先删缓存,更新数据库,延迟几百毫秒再次删除缓存(延迟时间把控)
2.更新数据库成功后,将删除缓存的操作放入消息队列,如果删除失败可以利用消息队列的重试机制来重新删除。(系统压力)
MySQL乐观锁、悲观锁
乐观锁假设数据在并发操作期间不会发生冲突,因此不对数据加锁。它使用版本号或时间戳等机制,在数据提交时检测冲突。只有version字段在更新前后一致才会更新。(适用读操作多场景)
悲观锁在读取数据时对数据加锁,认为数据可能会被其他事务修改,因此在操作期间持有锁以确保数据的一致性。(适用写操作多场景,需要确保强一致性)
MySQL的慢SQL排查
监控数据性能:CPU或者内存使用率过高
开启慢查询日志:SET GLOBAL slow_query_log = 'ON';
检查查询计划:使用 EXPLAIN
语句查看查询的执行计划。可以看到查询的执行计划,包括使用的索引、表的扫描方式等。
mysqldumpslow
工具可以分析慢查询日志
慢SQL优化
确保查询中使用的字段有合适的索引。缺少索引可能导致全表扫描,影响查询性能。
优化查询语句:使用联接(JOIN)替代子查询、避免 SELECT *、使用 LIMIT
限制返回的记录数。
调整数据库参数:如最大连接数、innodb缓存池大小
缓存、分库分表
MySQL底层数据结构
B+树,非叶子节点不存储数据,只存储键值和指向子节点的指针,所有数据存储在叶子节点。
降低树高,容纳更多的键值,叶子节点构成有序链表,查询高效,另外B+树有较好的平衡性。