导图社区 java基础知识总结
Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。本思维导图是对java基础知识总结,比较全面,干货,实际开发总慢慢的总结的,花费了大量的时间,希望对你有帮助!
编辑于2020-02-13 08:47:43计算机基础
分布式
分布式数据一致性
ZAB协议
什么是Zab协议
Zab协议是为分布式协调服务Zookeeper专门设计的一种 支持崩溃恢复 的 原子广播协议
Zab 协议的特性
Zab 协议需要确保那些已经在 Leader 服务器上提交(Commit)的事务最终被所有的服务器提交
Zab 协议需要确保丢弃那些只在 Leader 上被提出而没有被提交的事务
Zab 协议的作用
使用一个单一的主进程(Leader)来接收并处理客户端的事务请求(也就是写请求),并采用了Zab的原子广播协议,将服务器数据的状态变更以 事务proposal (事务提议)的形式广播到所有的副本(Follower)进程上去
保证一个全局的变更序列被顺序引用,Zookeeper是一个树形结构,很多操作都要先检查才能确定是否可以执行,比如P1的事务t1可能是创建节点"/a",t2可能是创建节点"/a/bb",只有先创建了父节点"/a",才能创建子节点"/a/b"
主进程出现异常的时候,整个zk集群依旧能正常工作
Zab 协议原理
Zab协议要求每个 Leader 都要经历三个阶段:发现,同步,广播
发现:要求zookeeper集群必须选举出一个 Leader 进程,同时 Leader 会维护一个 Follower 可用客户端列表,将来客户端可以和这些 Follower节点进行通信
同步:Leader 要负责将本身的数据与 Follower 完成同步,做到多副本存储。这样也是提现了CAP中的高可用和分区容错,Follower将队列中未处理完的请求消费完成后,写入本地事务日志中
广播:Leader 可以接受客户端新的事务Proposal请求,将新的Proposal请求广播给所有的 Follower
Zab 协议核心
定义了事务请求的处理方式
所有的事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被叫做 Leader服务器。其他剩余的服务器则是 Follower服务器
Leader服务器 负责将一个客户端事务请求,转换成一个 事务Proposal,并将该 Proposal 分发给集群中所有的 Follower 服务器,也就是向所有 Follower 节点发送数据广播请求(或数据复制)
分发之后Leader服务器需要等待所有Follower服务器的反馈(Ack请求),在Zab协议中,只要超过半数的Follower服务器进行了正确的反馈后(也就是收到半数以上的Follower的Ack请求),那么 Leader 就会再次向所有的 Follower服务器发送 Commit 消息,要求其将上一个 事务proposal 进行提交
Zab 协议包括两种基本的模式:崩溃恢复 和 消息广播
Zab 协议内容
当整个集群启动过程中,或者当 Leader 服务器出现网络中弄断、崩溃退出或重启等异常时,Zab协议就会 进入崩溃恢复模式,选举产生新的Leader
当选举产生了新的 Leader,同时集群中有过半的机器与该 Leader 服务器完成了状态同步(即数据同步)之后,Zab协议就会退出崩溃恢复模式,进入消息广播模式
这时,如果有一台遵守Zab协议的服务器加入集群,因为此时集群中已经存在一个Leader服务器在广播消息,那么该新加入的服务器自动进入恢复模式:找到Leader服务器,并且完成数据同步。同步完成后,作为新的Follower一起参与到消息广播流中
协议状态切换
当Leader出现崩溃退出或者机器重启,亦或是集群中不存在超过半数的服务器与Leader保存正常通信,Zab就会再一次进入崩溃恢复,发起新一轮Leader选举并实现数据同步。同步完成后又会进入消息广播模式,接收事务请求
保证消息有序
在整个消息广播中,Leader会将每一个事务请求转换成对应的 proposal 来进行广播, 并且在广播 事务Proposal 之前,Leader服务器会首先为这个事务Proposal分配一个全局单递增的唯一ID,称之为事务ID(即zxid),由于Zab协议需要保证每一个消息的严格的顺序关系,因此必须将每一个proposal按照其zxid的先后顺序进行排序和处理
消息广播具体步骤
客户端发起一个写操作请求
Leader 服务器将客户端的请求转化为事务 Proposal 提案,同时为每个 Proposal 分配一个全局的ID,即zxid
Leader 服务器为每个 Follower 服务器分配一个单独的队列,然后将需要广播的 Proposal 依次放到队列中取,并且根据 FIFO 策略进行消息发送
Follower 接收到 Proposal 后,会首先将其以事务日志的方式写入本地磁盘中,写入成功后向 Leader 反馈一个 Ack 响应消息
Leader 接收到超过半数以上 Follower 的 Ack 响应消息后,即认为消息发送成功,可以发送 commit 消息
Leader 向所有 Follower 广播 commit 消息,同时自身也会完成事务提交。Follower 接收到 commit 消息后,会将上一条事务提交
崩溃恢复
一旦 Leader 服务器出现崩溃或者由于网络原因导致 Leader 服务器失去了与过半 Follower 的联系,那么就会进入崩溃恢复模式
崩溃恢复主要包括两部分:Leader选举 和 数据恢复
如何保证数据一致性
新选举出来的 Leader 不能包含未提交的 Proposal
新选举的 Leader 节点中含有最大的 zxid
Zab 协议如何数据同步
完成 Leader 选举后, Leader 服务器会首先确认事务日志中的所有的 Proposal 是否已经被集群中过半的服务器 Commit
Leader 服务器需要确保所有的 Follower 服务器能够接收到每一条事务的 Proposal ,并且能将所有已经提交的事务 Proposal 应用到内存数据中,确保后Leader 才会把该 Follower 加入到真正可用的 Follower 列表中
Zab 节点有三种状态
Following:当前节点是跟随者,服从 Leader 节点的命令
Leading:当前节点是 Leader,负责协调事务
Election/Looking:节点处于选举状态,正在寻找 Leader
Zab协议四个阶段
选举
发现
同步
广播
paxos协议
通过一个提案分为两个阶段
prepare阶段
批准阶段
三个角色
Proposer(提议发起者)
Acceptor(提议接受者)
Learner(提议学习者)
raft协议
Raft的日志广播过程
发送日志到所有Followers
Followers收到日志后,应答收到日志
当半数以上的Followers应答后,Leader通知Followers日志广播成功
于其他分布式一致性算法,Raft 有效的解决了 分布式一致性算法过于复杂及难于实现的问题
一致性哈希
一致性Hash算法的思想
通过一致性Hash环的数据结构实现key到缓存服务器的映射
算法的具体过程
先构造一个长度为232的整数环(称作一致性Hash环)
根据节点名称的Hash值(其分布范围为[0, 232-1])将缓存服务器 节点放置在这个Hash环上;(要保证n个服务器节点均衡地放置在环上)
根据缓存数据的key的Hash值(其分布范围也为[0, 232-1])在Hash环上顺时针查找距 离这个key的Hash值最近的缓存服务器节点,即为该数据应该放置的的服务器
负载不均衡问题的解决方案是使用虚拟层
将每台物理服务器虚拟为一组虚拟缓存服务器
将虚拟缓存服务器的Hash值放置在Hash环上
缓存数据通过key的Hash值首先找到虚拟服务器节点
再找到这个虚拟服务器节点对应的物理服务器
新加入一台服务器将会分摊原集群中所有服务器的一部分负载
分布式锁
redis分布式锁
RedLock 算法
轮流尝试在每个 master 节点上创建锁,过期时间较短,一般就几十毫秒
尝试在大多数节点上建立一个锁,比如 5 个节点就要求是 3 个节点 n / 2 + 1;
客户端计算建立好锁的时间,如果建立锁的时间小于超时时间,就算建立成功了
要是锁建立失败了,那么就依次之前建立过的锁删除,去轮询
redis的setnx()方法,以及使用redis的KV结构,lock作为key, <br>key对应的value使用map结构,map中使用请求 requestId<br>作为map的key,过期时间作为map的 value,<br>获取锁使用cas算法,比较时间是否过期来 获取锁和释放锁<br>
zookeeper分布式锁
某个节点尝试创建临时 znode,此时创建成功了就获取了这个锁; 这个时候别的客户端来创建锁会失败,只能注册个监听器监听这个锁。 释放锁就是删除这个 znode,一旦释放掉就会通知客户端,然后有一 个等待着的客户端就可以再次重新加锁。
多任务排队获取锁,每客户端监听自己前面的是否释放锁
redis 分布式锁和 zk 分布式锁的对比
redis 分布式锁,其实需要自己不断去尝试获取锁,比较消耗性能。
zk 分布式锁,获取不到锁,注册个监听器即可, 不需要不断主动尝试获取锁,性能开销较小。
如果是 redis 获取锁的那个客户端 出现 bug 挂了, 那么只能等待超时时间之后才能释放锁;而 zk 的话, 因为创建的是临时 znode,只要客户端挂了,znode 就没了,此时就自动释放锁
分布式事务
两阶段提交(2PC)
第一阶段:请求/表决阶段(点击放大)
第二阶段:提交/执行阶段(正常流程)
3PC
CanCommit阶段
是一种事务询问操作
PreCommit阶段
事务预提交
DoCommit阶段
参与者节点在收到提交请求后就会各自执行事务提交操作
补偿事务(TCC)
本地消息表(异步确保)
核心思想是将分布式事务拆分成本地事务进行处理
MQ 事务消息
以 RocketMQ 中间件为例,其思路大致为:
第一阶段Prepared消息,会拿到消息的地址。
第二阶段执行本地事务,
第三阶段通过第一阶段拿到的地址去访问消息,并修改状态。
降级策略
页面降级
当在大促时,某些页面占用了稀缺资源,可以对整个 页面进行降级;当页面上会异步加载推荐信息等一些 非核心的业务时,此时如果响应变慢,则可以进行降级处理
服务读降级
比如用户账户余额,这个一般只从DB里面获取, 而且是主库里面去读取。当大促来临时,此时可以 降级为从库里面或者缓存里面去获取余额信息
服务写降级
在秒杀抢购业务中,由于并发的数量比较大,对 写库进行降级,可以将库存扣减操作在内存中进行, 当高峰过去之后,再异步的同步至DB中做扣减操作
超时降级
当访问的数据库/HTTP服务/远程调用响应慢,如果此服务 不是核心服务的话,可以在超时后执行自动降级。如商品 详情页中的评论信息,可以在查询超时后直接降级,然后 前端可以再进行单独的评论信息的查询
统计失败次数降级
当系统依赖外部的接口调用失败达到一定次数时, 可以自动降级,然后开启一个异步的线程去探测 是否恢复,恢复后执行自动取消降级
故障降级
当系统发生故障时,处理的方案可以有:默认值(库存默认有货)、 兜底数据(广告系统挂了,可以直接返回之前准备好的静态页面)、缓存等
限流降级
系统负载过大时,可以使用排队页面、无货或者错误页等
人工开关降级
其他
在系统繁忙时,可以将爬虫的流量直接丢弃,当高峰过后,再自动恢复
秒杀业务中,风控系统可以识别刷子/机器人,然后可以直接对这些用户执行拒绝服务
降级框架Hystrix
hystrix是什么
是保证系统高可用的框架。主要通过线程资源隔离、熔断、超时、降级、限流来保证
提供机制
将服务依赖的访问进行隔离
阻止依赖服务故障的连锁反应
提供容错处理策略
基本原理
所有的依赖都被封装在HystrixCommand(HystrixObservableCommand, 命令模式)中,并在隔离的线程池中运行
超时的调用执行的时间只会稍大与于指定的阈值(例如观测耗时的99.5%分位数)
为每一个依赖服务提供一个小型线程池(或信号量), 如果线程池满,后续达到该服务的请求会被快速拒绝而不是排队处理
提供对成功、失败、超时、和线程池慢导致的请求拒绝监控
提供一个断路器在特定的时间对某个服务的所有请求进行中断处理,可以人工触发,或者在服务错误率达到一个指定阈值触发
提供请求失败的容错机制:1)拒绝;2)超时;3)熔断
提供准实时的监控和配置变更
作用
对于依赖服务的失败和超时提供保护和管控机制
在复杂分布式系统中阻止故障的连锁反应(雪崩效应)
快速失败并快速恢复
提供失败回退机制,并在合适的场景优雅降级
提供准实时的监控预警和在线操作
分布式数据库
分布式消息中间件
Kafka
RabbitMQ
分布式session问题
粘性 Session 共享机制
一个用户的 Session 会绑定到一个 Tomcat 上,redis只是起到备份作用
非粘性 Session 共享机制
Tomcat 本身不存储 Session,而是存入redis中,Memcached 集群构建主从复制架构
负载均衡
随机,轮询(Round Robin),最小资源数,hash
CAP
一致性
多个数据副本是否能保持一致的特性
可用性
系统提供的服务一直处于可用的状态
分区容忍性
指分布式系统中的节点被划分为多个区域, 每个区域内部可以通信,但是区域之间无法通信
linux
如何避免开发过程中linux和windows 下路径拼接不一致的问题
统一使用File.separator

Linux常用命令学习
系统负载
free 命令显示系统使用和空闲的内存情况
(1)-b,-k,-m,-g 表示输出显示的单位为 bytes, KB, MB, or GB,不添加选项的话默认以 KB 为单位显示 (2)-h 以人类可读的方式显示,即后边会自动带上单位 (3)-l 显示详细的低内存和高内存统计信息(增加了 Low 和High 这两行显示) (4)-o 使用旧的格式显示(不显示 -/+buffers/cache 这一行) (5)-t 增加显示 Total 行,Total = Mem + Swap (6)-s delay 每 delay 秒重复打印一次,delay 为具体的秒数 (7)-c count 重复打印 count 次后退出,count 为具体的次数。需要配合 -s delay 使用 (8)-V 显示版本信息
物理内存Mem
交互区内存(swap)
内核缓冲区内存
top 命令可以查看进程的CPU、 内存等资源的使用情况
top 运行中常用命令
N – 以 PID 的大小的顺序排列表示进程列表
P – 以 CPU 占用率大小的顺序排列进程列表
M – 以内存占用率大小的顺序排列进程列表
q – 退出 top
vmstat命令可以查看系统整体的cpu,内存的使用情况
uptime查看系统负载
ps(最基本进程查看命)
ps aux/ps -ef列出目前所有的正在内存当中的程序
ps -A/ps -e:所有的进程均显示出来
ps -u wangxi:查看用户'wangxi'的进程
ps是显示瞬间进程的状态,并不动态连续;如果想对进程进行实时监控应该用top命令
但是使用ps的好处是你能够定义显示的字段,你能够选择你想查看的字段。
ls 执行的功能: 列出指定目录中的目录,以及文件
-a 所有文件
-l 详细信息,包括大小字节数,可读可写可执行的权限等
chmod:文件权限修改
chmod 751 file: 给file的属主分配读、写、执行(7)的权限,给file的所在组分配读、执行(5)的权限,给其他用户分配执行(1)的权限
chmod u+x file:给file的属主增加执行权限
u 表示该文件的拥有者,g 表示与该文件的拥有者属于同一个群体(group)者,o 表示其他以外的人,a 表示这三者皆是
+ 表示增加权限、- 表示取消权限、= 表示唯一设定权限
r 表示可读取,w 表示可写入,x 表示可执行
若要rwx属性则4+2+1=7
若要rw-属性则4+2=6
若要r-x属性则4+1=5
grep:文本搜索工具
grep 'MANPATH':匹配文件中包含 MANPATH 的那一行
grep -v 'MANPATH':匹配文件中不包含 MANPATH 的那一行
grep -E "word1|word2|word3" file.txt:满足其中任意条件(word1、word2和word3之一)就会匹配
grep word1 file.txt | grep word2 |grep word3:必须同时满足三个条件(word1、word2和word3)才匹配
scp:服务器之间复制文件
递归传输文件,加上-r参数
cp:文档的复制
若复制文件夹,加上-r参数
systemctl stop firewalld.service:关闭防火墙
怎么看端口占用状态。答lsof -i, netstat
查看所有的端口占用情况netstat -ano
netstat -aon|findstr "端口号"
exit:执行退出
clear:清屏
mkdir:创建目录
touch,vi 也可以创建文件,其实只要向一个不存在的文件输出,都会创建文件
-p参数可以递归的创建目录
搜索文件用什么命令? 格式是怎么样的?
find
find . -name "*.c":将目前目录及其子目录下所有延伸档名是 c 的文件列出来
find /etc/ -name passwd ##查找/etc/下名称中带有passwd的文件
whereis 加参数与文件名
locate 只加文件名
which 查看可执行文件的位置,从全局环境变量PATH里面查找对应的路径,默认是找 bash内所规范的目录
Linux统计文件夹、文件数量的命令
https://www.cnblogs.com/uzipi/p/6100790.html
Linux jmap查看Java程序堆内存的使用情况
移动文件、重新命名mv
telnet
远程服务器是否可以访问:telnet 192.168.120.209
域名是否可以解析:telnet www.baidu.com
telnet 118.10.6.128 88方式测试远程主机端口是否打开
nmap工具检测开放端口
查看访问做多的IP地址
awk
sort
uniq
查看目录/硬盘的使用情况命令
df -h //以G为单位查看
df -m //以M为单位查看
linux服务器磁盘满了的处理方法
df -h命令:通过df -h命令查看硬盘的使用情况
du -h --max-depth=1命令,找到占用空间的文件进行分析
文件的删除rm
-i 删除前逐一询问确认
-f 即使原档案属性设为唯读,亦直接删除,无需逐一确认
-r, -R, --recursive 指示rm将参数中列出的全部目录和子目录均递归地删除
tar -xvf file.tar
Linux查看进程打开多少文件描述符命令-lsof
建立软链接(快捷方式),以及硬链接的命令
软链接: ln -s slink source
硬链接: ln link source
终端文件 /dev/tty
进程的控制终端
黑洞文件 /dev/null
它丢弃一切写入其中的数据(但报告写入操作成功)
在默认的情况下,wc将计算指定文件的行数、字数,以及字节数
一般都是使用 &amp; 在命令结尾来让程序自动运行。(命令后可以不追加空格)
哪个命令专门用来查看后台任务?
job -l
把后台任务调到前台执行 命令:fg
把停下的后台任务在后台执行起来 命令:bg
终止进程kill
kill-9 pid
查看 ip 地址及接口信息
ifconfig
查看用过的命令列表
history
查看当前谁在使用该主机:who
查找自己所在的终端信息:who am i
Netstat 命令用于显示各种网络相关信息, 如网络连接,路由表,接口状态
列出所有端口 netstat -a
列出所有 tcp 端口 netstat -at
列出所有 udp 端口 netstat -au
只显示监听端口 netstat -l
只列出所有监听 tcp 端口 netstat -lt
只列出所有监听 udp 端口 netstat -lu
查看文件内容
cat: 由第一行开始显示档案内容
more: 一页一页的显示档案内容
less 与 more 类似,可以翻页
head: 查看头几行
tail: 查看尾几行
quota
限制用户对磁盘空间的使用量
显示两个文件的差异
同时显示两个文件的差异diff -c file1 file2
以并列的方式显示两个文件的差异diff -y file1 file2
nslookup/dig
查dns信息用
buffer和cache如何区分
CPU写数据到磁盘时,磁盘速度比较慢,所以CPU先把数据存进buffer, 然后CPU去执行其他任务,buffer中的数据会定期写入磁盘;
CPU从磁盘读入数据,由于磁盘速度比较慢,把即将用到的 数据提前存入cache,CPU直接从Cache中拿数据要快的多
自定义解析域名的时候,我们可以编辑哪个文件? 是否可以一个ip对应多个域名?是否一个域名对应多个ip?
编辑 /etc/hosts ,可以一个ip对应多个域名,不可以一个域名对多个ip
DHCP是动态主机配置协议的简称,其作用是:为网络中的主机分配IP地址
CentOS 和 Linux的关系
linux内核,原始车,centos是车的一种,还有ubantu,debian,kali等车型
fork()
每个进程有唯一的PID标识进程,PID是一个 从1到32768的正整数,其中1一般是特殊 进程init,其它进程从2开始依次编号, 当用完32768后,从2重新开始
linux中有一个叫进程表的结构用来存储当前正在运行的进程, 可以使用“ps aux”命令查看所有正在运行的进程
进程在linux中呈树状结构,init为根节点, 其它进程均有父进程,某进程的父进程就是 启动这个进程的进程,这个进程叫做父进程的子进程
fork的作用是复制一个与当前进程一样的进程。新进程的所有数据 (变量、环境变量、程序计数器等)数值都和原进程一致,但是 是一个全新的进程,并作为原进程的子进程
经典面试题:https://www.cnblogs.com/ylan2009/p/4321962.html
进程创建的底层实现
新的进程通过复制父进程而建立
通过fork()系统调用来复制一个 现有进程来创建一个全新的进程
首先在系统的物理内存中为新进程创建一个 task_struct 结构, 将旧进程的 task_struct 结构内容复制到其中,再修改部分数据
接着,为新进程分配新的堆栈,分配新的进程标识符 pid
然后,将这个新 task_struct 结构的地址填到 task 数组中, 并调整进程链关系,插入运行队列中
Linux的fork()使用写时拷贝(copy-on-write)页实现
资源的复制只有在需要写入的时候才进行
资源的复制只有在需要写入的时候才进行, 在此之前,只是以只读方式共享
当你在 Linux 的 bash 中按下 Ctrl+C 时,操作系统会 做出什么反应,给操作系统发出的那个信号怎么拼写
硬中断
由硬件产生的,比如,像磁盘,网卡,键盘,时钟等, 每个设备或设备集都有它自己的IRQ(中断请求)
基于IRQ,CPU可以将相应的请求分发到对应的硬件驱动上
软中断
由当前正在运行的进程所产生的
软中断并不会直接中断CPU
硬中断和软中断区别
软中断是执行中断指令产生的,而硬中断是由外设引发的
硬中断的中断号是由中断控制器提供的,软中断的 中断号由指令直接指出,无需使用中断控制器
硬中断是可屏蔽的,软中断不可屏蔽
伙伴系统
解决外部碎片的问题
宗旨就是用最小的内存块来满足内核的对于内存的请求
伙伴关系
由一个母实体分成的两个各方面属性一致的两 个子实体,这两个子实体就处于伙伴关系
三个条件
两个块具有相同大小记为 2^K
它们的物理地址是连续的
从同一个大块中拆分出来
原理:伙伴系统基于2的方幂来申请释放内存页
分配内存
伙伴系统首先检查与申请大小相同的内存块链表中,检看是 否有空闲页,如果有就将其分配出去,并将其从链表中删除
否则就检查上一级,如果上一级有空闲内存,就将其分配出去, 同时将剩余的一部分(即未分配出去的一半)加入到下一级空闲链表中
如果上一级没有,就依次类推,直到分配成功或者彻底失败
释放内存
在释放内存页时,会检查其伙伴是否也是空闲的, 如果是就将它和它的伙伴合并为更大的空闲内存块, 该检查会递归进行,直到发现伙伴正在被使用或者 已经合并成了最大的内存块
惊群效应
惊群现象就是多进程(多线程)在同时阻塞等待同一个事件的时候 (休眠状态),如果等待的这个事件发生,那么他就会唤醒等待的 所有进程(或者线程),但是最终却只可能有一个进程(线程) 获得这个时间的“控制权”,对该事件进行处理,而其他进程 (线程)获取“控制权”失败,只能重新进入休眠状态
nginx如何处理惊群:同一时刻只允许一个nginx worker在自己的epoll中处理监听句柄
一个文件夹内批量替换文本
find -name '要查找的文件名' | xargs perl -pi -e 's|被替换的字符串|替换后的字符串|g'
批量修改文件夹权限
find . -type -d -name *.html|xargs chmod 755
批量修改文件权限
find . -type -f -name *.html|xargs chmod 644
操作系统
操作系统的基本特性
并发
并发性是指两个或多个事件在同一时间间隔内发
共享
系统中的资源可供内存中多个并发执行 的进程(线程)共同使用
虚拟
把一个物理实体变为若干个逻辑上的对应物
异步
进程的执行不是一贯到底,而是走走停停,已不可预知的速度向前推进
计算机系统启动
第一阶段:BIOS
BIOS是什么
这块芯片里的程序叫做”基本輸出輸入系統” (Basic Input/Output System),简称为BIOS
开机程序被刷入ROM芯片,计算 机通电后,第一件事就是读取它
BIOS程序首先检查,计算机硬件能否满足运行的基本条件
硬件自检完成后,BIOS把控制权转交给下一阶段的启动程序
第二阶段:主引导记录
读取主引导记录和分区表
第三阶段:硬盘启动
运行事先安装的启动管理器
用户选择启动哪一个操作系统
将控制权转交给内核
第四阶段:操作系统
操作系统的内核首先被载入内存
产生init进程,加载系统的各个模块
跳出登录界面,等待用户输入用户名和密码
进程间通信方式
共享内存
消息队列
套接字
管道
一种半双工的通信方式,数据只能单向流动, 而且只能在具有亲缘关系的进程间使用。 进程的亲缘关系通常是指父子进程关系
命名管道
有名管道也是半双工的通信方式, 它允许无亲缘关系进程间的通信
信号量
信号量是一个计数器,可以用来控制多个进程对共享资源的访问
信号
用于通知接收进程某个事件已经发生
进程调度方法
先来先服务
短作业优先
优先权调度算法
高响应比优先调度算法
响应比 =(等待时间+要求服务时间)/ 要求服务时间
基于时间片的轮转调度算法
进程的状态和转换
进程和线程的区别
线程是程序执行的最小单位, 而进程是操作系统分配资源的最小单位
一个进程由一个或多个线程组成, 线程是一个进程中代码的不同执行路线
进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间 (包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号), 某进程内的线程在其它进程不可见
调度和切换:线程上下文切换比进程上下文切换要快得多
线程上下文切换和进程 上下文切换的异常同
异
进程切换分两步
切换页目录以使用新的地址空间
切换内核栈和硬件上下文
对于linux来说,线程和进程的最大区别就在于地址空间。 对于线程切换,第1步是不需要做的,第2是进程和线程切换都要做的
进程切换改变虚拟内存空间的时候,处理的页表缓冲等将会被全部刷新, 这将导致内存的访问在一段时间内相当的低效
同
两种上下文切换的处理都是通过操作系统内核来完成的,内核的这种 切换过程伴随的最显著的性能损耗是将寄存器中的内容切换出
上下文的切换会扰乱处理器的缓存机制,一旦去切换上下文, 处理器中所有已经缓存的内存地址一瞬间都作废了
进程切换比线程切换的代价大
进程切换比线程切换开销大是因为进程切换时 要切页表,而且往往伴随着页调度
进程切换会扰乱处理器的缓存机制
如何减少上下文切换
无锁并发编程
多线程竞争时,会引起上下文切换,所以多线程处理数据时, 可以用一些办法来避免使用锁,将数据Id按hash算法取模来分段, 不同的线程处理不同时端的数据
CAS算法
Java的atomic包使用CAS算法来更新数据,面不需要加锁; Atomic变量的更新可以实现数据操作的原子性及可见性; 这个是由volatile 原语及CPU的CAS指令来实现的
使用最少的线程和使用协程
若任务少,但创建了很多线程来处理, 这样会造成大量的线程处于等等状态
在单线程里实现多任务的调度,并在单线程里维持 多个任务间切换。java语言级别原生并不支持协程, 可以看下kilim,利用java增强字节码实现角色模型(actor)
线程同步机制
临界区
通过对多线程的串行化来访问公共资源
每个进程中访问临界资源的那段代码称为临界区(访问打印机)
互斥量
锁
信号量
它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的数目
事件
通过通知操作的方式来保持线程的同步
线程的状态
中断机制
强制性中断
硬件故障中断,程序性中断,外部中断和输入输出中断等
自愿性中断
正在运行的进程执行一条访管指令用以请求系统调用而引起的中断
中断响应过程
是否有中断事件发生
若有中断发生,保护断点信息
启动操作系统的中断处理程序工作
中断处理
保护被中断进程的现场信息
分析中断原因
处理发生的中断事件
中断屏蔽
中断屏蔽技术是在一个中断处理没有结束之前不响应 其他中断事件,或者只响应比当前级别高的中断事件
程序中断保存哪些内容
程序状态字
中断屏蔽寄存器
CPU中某些寄存器的内容
磁盘臂调度算法
FCFS:先来先服务算法
SSTF:最短寻道时间算法
SCAN:扫描算法(也叫电梯调度算法)
CSCAN:循环扫描算法
操作系统的内存管理
内存管理的功能
内存空间的分配与回收
由操作系统完成主存储器空间的分配和管理,使 程序员摆脱存储分配的麻烦,提高编程效率
地址转换
在多道程序环境下,程序中的逻辑地址与内存中的物理地址不可能一致 因此存储管理必须提供地址变换功能,把逻辑地址转换成相应的物理地址。
内存空间的扩充
利用虚拟存储技术或自动覆盖技术,从逻辑上扩充内存
存储保护
保证各道作业在各自的存储空间内运行,.互不干扰
程序的链接有以下三种方式
静态链接:在程序运行之前,先将各目标模块及它们 所需的库函数链接成一个完整的可执行程序,以后不再拆开
装入时动态链接:将用户源程序编译后所得到的一组目标模块, 在装入内存时,釆用边装入边链接的链接方式。
运行时动态链接:对某些目标模块的链接,是在程序执行中需要该目标模块时, 才对它进行的链接。其优点是便于修改和更新,便于实现对目标模块的共享
子主程序在装入内存时, 同样有以下三种方式
绝对装入
逻辑地址与实际内存地址完全相同
可重定位装入
可将装入模块装入到内存中任何允许的位置,故可用于多道程序环境
动态运行时装入, 也称为动态重定位
程序在内存中如果发生移动,就需要釆用动态的装入方式
地址转换推迟到程序真正要执行时才进行
需要一个重定位寄存器的支持
虚拟存储器
问题
有的作业很大,其所要求的内存空间超过了内存总容量, 作业不能全部被装入内存, 致使该作业无法运行
有大量作业要求运行,只能将少数作业装入内存 让它们先运行,而将其它大量的作业留在外存上等待
局部性原理
实现方法
分页请求系统
请求分页的页表机制
缺页中断机构
地址变换机构
实现请求分页的软件
请求分段系统
请求分段的段表机制
缺段中断机构
地址变换机构
相应的软件支持
虚拟内存
原理
(1)物理内存不够用,所以利用内存+外存+虚拟寻址技术为进程服务
(2)当进程加载数据时,首先要进行寻址,如果该数据在内存中,寻址结束,否则需要到外存中加载数据
(3)加载数据可用会用到换页算法
基本思想
内存被可以分为若干个块(页),都是一段连续的地址, 对于进程来看,逻辑上貌似有很多内存空间,其中一部分 对应物理内存上的一块,还有一些没加载在内存中的对应在硬盘上
换页方法
FIFO:先来先出(FIFO)算法
LRU:最近使用最少算法
时钟(CLOCK)置换算法
OPT:最佳置换算法
内存保护
内存分配前,需要保护操作系统不受用户进程的影响, 同时保护用户进程不受其他用户进程的影响
通过釆用重定位寄存器和界地址寄存器来实现这种保护
内存覆盖与内存交换
覆盖与交换技术是在多道程序环境下用来扩充内存的两种方法
内存覆盖
把用户空间分成一个固定区和若干个覆盖区, 将经常活跃的部分放在固定区,其余部分按调用关系分段
打破了必须将一个进程的全部信息装入主存后才能运行的限制, 但当同时运行程序的代码量大于主存时仍不能运行
内存交换
把处于等待状态的程序从内存移到辅存,把内存空间腾出来, 这一过程又叫换出;把准备好竞争CPU运行的程序从辅存 移到内存,这一过程又称为换入
内存连续分配管理方式
单一连续分配
用于单用户、单任务的操作系统中
固定分区分配
将用户内存空间划分为若干个固定大小的区域, 每个分区只装入一道作业。当有空闲分区时, 便可以再从外存的后备作业队列中,选择适当 大小的作业装入该分区,如此循环
分区大小相等:用于利用一台计算机去控制多个相同对象的场合,缺乏灵活性
分区大小不等:划分为含有多个较小的分区、适量的中等分区及少量的大分区
建立一张分区说明表,其中各表项包括每个分区的起始地址、大小及状态
存在两个问题
程序可能太大而放不进任何一个分区中
程序小于固定分区大小时,也占用了一个完整的内存分区空间
动态分区分配
进程装入内存时,根据进程的大小动态地建立分区
分区分配中的数据结构
空闲分区表
空闲分区链
分区分配算法
首次适应算法
循环首次适应算法
最佳适应算法
把能满足要求、又是最小的空闲分区,分配给作业
子主题
最坏适应算法(worst fit)
快速适应算法
分区分配操作
分配内存
利用某种分配算法,从空闲分区链(表)中找到所需大小的分区
回收内存
子主题
问题:
内碎片(静态分区)
内碎片是占用分区内未被利用的空间
外碎片(静态分区)
外碎片是占用分区之间难以利用的空闲分区(通常是小空闲分区)
内存紧缩
将各个占用分区向内存一端移动,然后将各个空闲分区合并成为一个空闲分区
内存非连续分配管理方式
分页
把主存空间划分为大小相等且固定的块,块相对较小,作为主存的基本单位
页面
页面大小应是 2 的幂,通常 为 512 B~8 KB
页面小内存利用率高,但页表长占用内存多,页面换进换出效率低
页面大页表占用内存少,页面换进换出效率高,但内存碎片大
页表
记录页面在内存中对应的物理块号
两级和多级页表
地址变换机构
页面映射表的作用就是用于实现,从页号到物理 块号的变换,地址变换任务是借助于页表来完成的
基本的地址变换机构
访问内存中的页表,从中找到指定页的物理块号,以形成物理地址
从第一次所得地址中获得所需数据
具有快表的地址变换机构
增加高速缓存
页号存在高速缓存中,直接从快表中读出该页 所对应的物理块号,并送到物理地址寄存器中
基本分页式存储管理 需要几次访问内存
最坏情况是3次:现在快表中查询页号,但是没有查到系统 给出的页号(这是第一次访问内存),所以只能再去页表中 查询相应的页号,进而得到物理块号(这是第二次访问内存), 最后一次是得到了物理地址后访问真的系统所需数据,这是第三次。
最好的情况是2次:第一步在快表中查询到了相应的页号, 从而就没有第二部了,直接到了第三部,这种情况下,需要访问2次内存
分段
作业的地址空间被划分为若干个段,每个段定义了一组逻辑信息
引入分段存储管理方式的目的
方便编程
信息共享
分段是以信息的逻辑单位为基础的
“页”只是存放信息的物理单位(块),并无完整的意义
信息保护
动态增长
数据段,在使用过程中会不断地增长,而事先 又无法确切地知道数据段会增长到多大
动态链接
运行过程中又需要调用某段时,才将 该段(目 标程序)调入内存并进行链接
段表
每个进程都有一张逻辑空间与内存空间映射的段表
段表是用于实现从逻辑段到物理内存区的映射
地址变换机构
首先将逻辑地址的段号S与段表长度TL进行比较,若S>TL, 表示段号太大,是访问越界,于是产生越界中断信号
未越界则根据段表的始址和该段的段号,计算出该段对应段表项的位置
如果使用快表,且在快表中命中,则只需要访问内存1次
注意:分段的数据访问一个字节的数据/指令需访问内存也是两次 (段表一次,内存一次)。
分段和分页的不同
分页是系统管理的需要:减少内存碎片;分段是:应用程序的需要:提供一组完整的信息
一条指令或一个操作数可能会跨越两个页的分界处,而不会跨越两个段的分界处
页大小固定且由系统决定;段的长度不固定
页式系统地址空间是一维的;分段的作业地址空间是二维的, 程序员在标识一个地址时,既需给出段名,又需给出段内地址
页号直接加上页内地址
二维:段名和段内地址,先找到某段,再找到段内地址
段页
分段和分页原理的结合
页式存储管理能有效地提高内存利用率,而分段存储管理能反映程序的逻辑结构并有利于段的共享
作业的地址空间首先被分成若干个逻辑段,每段都有自己的段号, 然后再将每一段分成若干个大小固定的页
在一个进程中,段表只有一个,而页表可能有多个
在段页式系统中,为了获得一条 指令或数据,须三次访问内存
第一次访问是访问内 存中的段表,从中取得页表始址
第二次访问是访问内存中的页表,从中取出该页所在的物理 块号,并将该块号与页内地址一起形成指令或数据的物理地址
从第二次访问所得的地址中,取出指令或数据
如果使用快表,且在快表中命中,则只要访问一次高速缓冲存储器,访问内存1次
在分页、分段和段页式存储管理中,当访问 一条指令时,需要访问内存几次各做什么操作
在分页和分段系统中,首先需要访问页表或段表, 然后才能访问实际数据,因此需要至少访问内存2次。
在段页式存储管理中,首先要访问段表,最后访问相关段的页表, 最后才能访问实际数据,因此一共需访问内存至少3次。
如果采用的是多级页表,则访问次数还将增加。
如果使用快表,且在快表中命中,只要访问一次高速缓冲存储器, 一次主存,这样可加速查找并提高指令执行速度。
内存抖动
下次要使用的页在被替换出去了,这样的现象就称为抖动
操作系统的文件管理
记录
记录是一组相关数据项的集合
数据项
用于描述一个对象的某种属性的字符集
文件
是指由创建者所定义的、具有文件名的一组相关 元素的集合,可分为有结构文件 和无结构文件两种
在有结构的文件中,文件由若干个相关记录组成
而无结构文件则被 看成是一个字符流
文件的属性
文件类型:可以从不同的角度来规定文件的类型,如源文件、目标文件及可执行文件等
文件长度:文件长度指文件的当前长度,长度的单位可以是字节、字或块,也可能 是最大允许的长度
文件的物理位置:该项属性通常是用于指示文件在哪一个设备上及在该设备的哪个 位置的指针
文件的建立时间:这是指文件最后一次的修改时间等
名称:文件名称唯一,以容易读取的形式保存
保护:对文件进行保护的访问控制信息
标识符:标识文件系统内文件的唯一标签,通常为数字,它是对人不可读的一种内部名称
文件基本操作
创建文件
首先为新文件分配必要的外存空间,并在文件 系统的目录中,为之建立一个目录项。目录项中 应记录新文件的文件名及其在外存的地址等属性
删除文件
系统应先从目录中找到要删除文件的目录项, 使之成为空项,然后回收该文件所占用的存储空间
读文件
读同样要查找目录,找到指定的目录项,从中得到被读文件 在外存中的位置。 在目录项中,还有一个指针用于对文件的读/写
写文件
先查找目录,找到指定文件的目录项, 再利用目录中的写指针进 行写操作
截断文件
如果一个文件的内容已经陈旧而需要全部更新时,一种方法是将此文件删除, 再重新创建一个新文件,但如果文件名和属性均无改变,则可采取截断文件的方法, 其将原有的文件长度设置为0,放弃原有文件的内容
设置文件的读/写位置
用于设置文件读/写指针的位置,以便每次读/写文件时,不需要从始端 开始而是从所设置的位置开始操作。可以改顺序存取为随机存取
文件的“打开”和“关闭”操作
大致都是这样两步: 第一步是通过检索文件目录来找到指定 文件的属性及其在外存上的位置;第二步是对文件实施相应的操作
“打开”
当对一个文件实施多次操作时,为了避免多次重复地检索目录,在大多数 OS 中都引入了“打开”(open)这一文件系统调用,当用户第一次请求 对某文件进行操作时,先利用 open 系统调用将该文件打开,并记录于打开列表中
关闭
利用“关闭”(close)系统调用来关闭此文件, OS 将会把该文件从打开文件表中的表目上删除掉
有结构文件
顺序文件
由一系列记录按某种顺序排列所形成的文件。其中的记录 通常是定 长记录,因而能用较快的速度查找文件中的记录
索引文件
当记录为可变长度时,通常为之建立一张索引表,并为 每个记录设置一 个表项,以加快对记录检索的速度
索引顺序文件
这是上述两种文件构成方式的结合,它为文件建立一张 索引表,为 每一组记录中的第一个记录设置一个表项
哈希(Hash)文件
用Hash函数可将记录键值转换为相应记录的地址,为了能实现文件存储空间 的动态分配,通常由Hash函数所求得的并非是相应记录的地址,而是指向一 目录表相应表目的指针,该表目的内容指向相应记录所在的物理块
目录管理
文件目录也是一种数据结构,用于标识系统中的文件 及其物理地址,供检索时使用,对目录的管理要求如下:
实现按名存取,即用户只须向系统提供所需访问的文件的名字,便能够快速准确 地找到指定文件在外存上的存储位置,这是目录管理中最基本的功能
提高对目录检索速度,通过合理地组织目录结构的方法, 可加快对目录的检索速度,从而提高对文件的存取速度
文件共享,在多用户系统中,应该允许用户共享一个文件
允许文件重名,系统应允许不同用户对不同文件采用相同 的名字,以便用户按照自己的习惯给文件命名和使用文件
文件控制块
设置用于描述和控制文件的数据结构,称之为文件控制块FCB
索引结点
索引节点是指在许多类Unix文件系统中的一种数据结构。每个索引节点保存了 文件系统中的一个文件系统对象的元信息数据,但不包括数据内容或者文件名
目录查询技术
当用户要访问一个已存在的文件时,系统首先利用用户提供的文件名对目录进行查询, 找出该文件的文件控制块或对应索引结点,然后,根据FCB或索引结点中所记录的 文件物理地址(盘块号),换算出文件在磁盘上的物理位置,最后,再通过磁盘 驱动程序,将所需文件读入内存。目前常用的方式有线性检索法和Hash方法
64位和32位的区别
运行能力不同
64位可以一次性处理8个字节的数据量,32位一次性只可以处理4个字节的数据量
内存寻址不同
64位最大寻址空间为2的64次方;32位的最大寻址空间为2的32次方
运行软件不同
32位和64位CPU的指令集是不同的;所以需要区分32位和64位版本的软件
cpu
作用:
通过计算机的输入设备向内存输入数据或指令,CPU 取存计算后写存,输出设备取存转换为我们需要的结果
主要构成是:
运算器、控制器、寄存器
寄存器
空间比较小在kb级别
是CPU内部的元件, 拥有非常高的读写速度
cache(高速缓冲存储器)
位于CPU与主内存间的一种 容量较小但速度很高的存储器
比寄存器要慢1倍左右
空间可以达到MB级别
内存
比缓存要慢10倍左右
空间可以达到GB级别
磁盘
速度更慢
空间也很大
(读写速度由快到慢依次是)CPU (寄存器)--- > 缓存--- >内存-->磁盘
死锁
必要条件
互斥
请求和保持
循环等待
不可剥夺
防止死锁
预防
避免
检测
解除
银行家算法
当一个进程申请使用资源的时候,银行家算法通过先 试探 分配给该进程资源,然后通过安全性算法判断分配后的系统 是否处于安全状态,若不安全则试探分配作废,让该进程继续等待
具体步骤
假设资源P1申请资源,银行家算法先试探的分配给它(当然先要看看当前资源池中的资 源数量够不够),若申请的资源数量小于等于Available,然后接着判断分配给P1后剩余 的资源,能不能使进程队列的某个进程执行完毕,若没有进程可执行完毕,则系统处于不 安全状态(即此时没有一个进程能够完成并释放资源,随时间推移,系统终将处于死锁状态)
若有进程可执行完毕,则假设回收已分配给它的资源(剩余资源数量增加), 把这个进程标记为可完成,并继续判断队列中的其它进程,若所有进程都可执 行完毕,则系统处于安全状态,并根据可完成进程的分配顺序生成安全序列
(如{P0,P3,P2,P1}表示将申请后的剩余资源Work先分配给P0–>回收 (Work+已分配给P0的A0=Work)–>分配给P3–>回收 (Work+A3=Work)–>分配给P2–>······满足所有进程)
pv操作
宏观: P就是请求资源,V就是释放资源
P操作是减法运算(S:=S-1),当信号量S小于0 时申请资源;V操作是加法运算(S:=+1),当信号 量小于等于0时释放资源;P、V操作二者必须成出现
在生产者、消费者问题中应该注意
在每个程序中用于实现互斥的P、V操作必须成对出现
对资源信号量的操作,同样需要成对的出现, 但他们可以处于不同的程序中
在每个程序中多个P操作顺序不能颠倒, 否则在一定条件下会出现死锁现象
核心态
运行操作系统程序
当程序运行在0级特权级上时, 就可以称之为运行在内核态
处于核心态执行中的进程,则能访问所有的内存 空间和对象,且所占有的处理机是不允许被抢占的
用户态
运行用户程序
内核态与用户态是操作系统的两种运行级别, 当程序运行在3级特权级上时,就可以称之为运行在用户态
运行在用户态下的程序不能直接访问操作系统内核数据结构和程序
处于用户态执行时,进程所能访问的内存空间和对象 受到限制,其所处于占有的处理机是可被抢占的
用户态到内核态的切换
系统调用
用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作
fork()实际上就是执行了一个创建新进程的系统调用
异常
发生触发由当前运行进程切换到处理此异常的内核相关程序
缺叶异常
外围设备的中断
比如硬盘读写操作完成,系统会切换到硬盘 读写的中断处理程序中执行后续操作等
堆与栈的区别
管理方式不同
栈由操作系统自动分配释放,无需我们手动控制;堆的申请和释放工作 由程序员控制,容易产生内存泄漏,java中一般内存有java自动管理
空间大小不同
每个进程拥有的栈的大小要远远小于堆的大小。理论上, 程序员可申请的堆大小为虚拟内存的大小,进程栈的大小 64bits的Windows默认1MB,64bits的Linux默认10MB
生长方向不同
堆的生长方向向上,内存地址由低到高
栈的生长方向向下,内存地址由高到低
分配方式不同
堆都是动态分配的,没有静态分配的堆
栈有2种分配方式:静态分配和动态分配。静态分配是由操作系统完成的,比如局部变量 的分配。动态分配由malloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态 分配是由操作系统进行释放,无需我们手工实现。
分配效率不同
栈由操作系统自动分配,会在硬件层级对栈提供支持:分配专门的寄存器存放 栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。
堆则是由C/C++提供的库函数或运算符来完成申请与管理,实现机制较为复杂, 频繁的内存申请容易产生内存碎片。显然,堆的效率比栈要低得多。
存放内容不同
栈存放的内容,函数返回地址、相关参数、局部变量和寄存器内容等
堆,一般情况堆顶使用一个字节的空间来存放堆的大小, 而堆中具体存放内容是由程序员来填充的
计算机网络
七层模型
应用
应用层有哪些协议
TELNET、HTTP、FTP、NFS、SMTP、https
是否为有状态协议
HTTP,UDP都是无状态协议
TCP,FTP是有状态协议
http和socket区别
http只可以基于tcp;socket可以基于tcp和udp
http是“请求-服务”,socket服务端可以主动向客户端发消息
Http协议(80端口)
特性
无状态:就是每个请求都是独立的,与前面的请求和后面的请求都是没有直接联系的
幂等性
任意多次执行对资源本身所产生的影响均与一次执行的影响相同
类别
长连接
适用于客户端和服务端通信频繁的场景,例如聊天室,实时游戏等
短连接
适用于网页浏览等数据刷新频度较低的场景
HTTP的请求过程
TCP建立连接后,客户端会发送报文给服务端
服务端接收报文并作出响应
客户端收到响应后解析给用户
如何保持状态(会话跟踪技术)
COOKIE
参数是存放在请求头部里的
浏览器可以保存Cookie一段时间
URL重写
参数是存放在 url 里的
当Cookie被禁用时依旧能够工作
不存在持久性,一旦浏览器关闭就结束
隐藏表单域
参数是存放在请求实体里的,不支持 GET 请求方法,因为 GET 没有请求实体
当Cookie被禁用时依旧能够工作
不存在持久性,一旦浏览器关闭就结束
Session
每一次请求中只传输唯一一个参数:JSESSIONID
基于前三种会话技术
HTTP状态码共分为5种
1**(信息,服务器收到请求,需要请求者继续执行操作)
100继续。客户端应继续其请求
101切换协议。服务器根据客户端的请求切换协议
2**(成功,操作被成功接收并处理)
200成功,操作被成功接收并处理
201已创建,成功请求并创建了新的资源
202已接受。已经接受请求,但未处理完成
3**(重定向,需要进一步的操作以完成请求)
301永久重定向
302临时重定向
305所请求的资源必须通过代理访问
4**(客户端错误,请求包含语法错误或无法完成请求)
400 Bad Request客户端请求的语法错误,服务器无法理解
401请求要求用户的身份认证
403服务器拒绝请求
404not found
5**(服务器错误,服务器在处理请求的过程中发生了错误)
500服务器内部错误
502服务器网关错误
503:服务器当前不能处理客户端的请求,一段时间后可能恢复正常
HTTP首部字段
HTTP首部字段是构成HTTP报文的要素之一,它可以给浏览器、 服务器提供报文主体大小、所使用的语言、认证信息等
Cache-Control
控制缓存的行为
Date
创建报文的日期时间
Accept
用户代理可处理的媒体类型
Accept ranges
是否接受字节范围请求
allow
资源可支持的http方法
Content-type 的几种常见类型
是什么
是Http的实体首部字段,用于说明请求或返回的消息主体是用 何种方式编码,在request header和response header里都存在
application/x-www-form-urlencoded
(1)浏览器的原生form表单
(2)form提交的数据按照 key1=val1&key2=val2 的 方式进行编码,key和val都进行了URL转码
multipart/form-data
常见的 POST 数据提交的方式。我们使用表单上传 文件时,必须让 form 的 enctype 等于这个值
application/json
消息主体是序列化后的 JSON 字符串
text/xml
是一种使用 HTTP 作为传输协议, XML 作为编码方式的远程调用规范
常用方法get/post的区别
post实际上发生了两次请求
GET比POST更不安全,因为参数直接暴露在URL上;post放在response里面
安全问题
通信使用明文
不验证通信方身份
无法验证报文完整性
HTTP2.0新特性
二进制分帧
将所有传输信息分割为更小的消息和帧, 并对它们采用二进制格式的编码将其封装
首部压缩
流量控制
多路复用
可以在共享TCP链接的基础上同时发送请求和响应
请求优先级
每个流都可以带有一个31bit的优先值:0表示最高优先级
服务器推送
服务端根据客户端的请求,提前返回多个响应,推送额外的资源给客户端
Https协议(SSL安全通信线路;443端口)
与http相比
内容加密
对称加密
身份认证
非对称加密
数据完整性
https一般是单向认证
双向认证
服务端保存着客户端的证书并信任该证书, 客户端保存着服务端的证书并信任该证书
单向认证
客户端保存着服务端的证书并信任该证书即可
HTTPS的加密过程详解
认证服务器
协商会话密钥
加密通讯
HTTPS的请求过程
客户端发送请求到服务端
服务器返回证书和公钥
客户端验证证书和公钥的有效性,如果有效, 则生成对称密钥并使用公钥加密发送到服务端
服务端使用私钥解密报文,并使用收到 的对称密钥加密报文,发送到客户端
客户端使用对称密钥解密报文
SSL加密建立
表示
会话
传输层
tcp
粘包
发送端
比如:将较小的数据包进行合并发送
接收端
比如:放数据的速度大于应用层拿数据速度
如何保证可靠性传输
首部和数据的检验和
超时重传机制
提供流量控制
使用滑动窗口
选择确认ACK
发送方如何确认网络拥塞:
发送方发送一些报文时,如果发送没有在规定的时间 间隔内收到接收方的应答,则就可以认为网络拥塞
拥塞窗口
某一源端数据流在一个RTT内可以最多发送的数据包数。 发送端根据网络拥塞程度所预设的一个大小值,这个值就是拥塞窗口。
拥塞控制如何实现
慢开始
从小到达逐渐增大发送端的拥塞控制窗口数值
拥塞避免
快重传
发送方只要一连收到三个重复确认M2就应当立即重传对方尚未收到的报文段M3
快恢复
流量控制与拥塞控制区别
流量控制是端到端的控制,例如A通过网络给B发数据, A发送的太快导致B没法接收(B缓冲窗口过小或者处理过慢), 这时候的控制就是流量控制,原理是通过滑动窗口的大小改变来实现
拥塞控制是A与B之间的网络发生堵塞导致传输过慢或者丢包,来不及传输
最大tcp连接数为65535
心跳机制
udp
udp如何实现可靠性传输
在应用层实现确认机制
在应用层实现重传机制
网络
ip/icmp
数据链路
建立逻辑连接、进行硬件地址寻址、差错校验等功能
物理
建立、维护、断开物理连接
三次握手
过程
建立连接时,客户端发送syn包(syn=j)到服务器, 并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号
服务器收到syn包,必须确认客户的SYN(ack=j+1), 同时自己也发送一个SYN包(seq=k),即SYN+ACK包, 此时服务器进入SYN_RECV状态
客户端收到服务器的SYN+ACK包,向服务器发送确认包 ACK(ack=k+1),此包发送完毕,客户端和服务器进入 ESTABLISHED(TCP连接成功)状态,完成三次握手
流程图
四次挥手
过程
TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送
服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1
服务器关闭客户端的连接,发送一个FIN给客户端
客户端发回ACK报文确认,并将确认序号设置为收到序号加1
流程图
出现大量time_wait的危害
大量端口被占用
如何消除大量短连接引发的TIME_WAIT
修改为长连接
增大端口可用范围
首先服务器可以设置SO_REUSEADDR套接字选项来通知内核, 如果端口忙,但TCP连接位于TIME_WAIT状态时可以重用端口
TIME_WAIT等两倍时间,为什么要这么设计
为了保证A发送的最后一个ACK报文能够到达B
A在发送完ACK报文段后,再经过2MSL时间, 就可以使本连接持续的时间所产生的所有报文段 都从网络中消失。这样就可以使下一个新的连接中 不会出现这种旧的连接请求的报文段
http/tcp关闭的closing状态
当你发送FIN报文后,按理来说是应该先收到(或同时收到) 对方的ACK报文, 再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有 收到对方的ACK报文,反而却也收到了对方的FIN报文。
浏览器输入URL执行全部过程
域名解析
发起TCP的3次握手
建立http连接后,发起http请求
浏览器解析html代码,并请求html代码中的资源
断开连接
浏览器对页面渲染呈现给用户
DNS递归查询和迭代查询的区别
递归查询模式下DNS 服务器接收到客户机请求后,如果 DNS 服务器本地没有存储查询DNS 信息,该服务器会 询问其他服务器,并将返回的查询结果提交给客户机
迭代查询下DNS 服务器并不直接回复查询结果,而是 告诉客户机另一台DNS 服务器地址,客户机再向这台 DNS 服务器提交请求,依次循环直到返回查询的结果
ping原理
先构建一个固定格式的ICMP请求数据包,连同目的地址一起交给IP层协议
ip层将原地址、目的地址以及其他控制信息构成ip数据包,交给数据链路层
原地址主机先查自己的MAC地址表,如果没有目的地址的MAC地址,就会向外发送一个ARP广播包
交换机会收到这个报文后,会检索自己有没有保存目的竹节有MAC, 如果有,就返回给源主机,如果没有,就会向所有端口发送ARP广播,
当主机发现不是在找自己,就丢弃报文
当目的主机收到报文便作出响应,同样的ARP报文格式返回给源主机
ip地址的划分
A
0-127
B
128-191
C
192-223
D
224-239
E
240-255
网络地址转换(NAT)
首先:一般使用私网ip作为局域网内部的主机标识,使用公网ip作为互联网上通信的标识
在整个NAT的转换中, 最关键的流程有以下几点:
网络被分为私网和公网两个部分,NAT网关设置在私网到 公网的路由出口位置,双向流量必须都要经过NAT网关
网络访问只能先由私网侧发起,公网无法主动访问私网主机;
NAT网关在两个访问方向上完成两次地址的转换或翻译, 出方向做源信息替换,入方向做目的信息替换;
NAT网关为了实现双向翻译的功能,需要 维护一张关联表,把会话的信息保存下来。
静态NAT
一个内部主机唯一占用一个公网IP
用户希望隐藏内部主机的真实IP
动态NAT
将未注册的IP地址映射到注册IP地址池中的一个地址
NAT重载
利用端口号实现公网和私网的转换,只需使用一个公网ip地址, 就可将数千名用户连接到因特网
NAT技术的优点
节省合法的公有ip地址
地址重叠时,提供 解决办法
网络发生变化时,避免重新编址 (可以继续使用原来的区域网地址)
NAT技术的缺点
无法进行端到端的ip跟踪(破坏了端对端通信的平等性)
很多应用层协议无法识别(比如ftp协议 )
子网掩码的作用
将某个IP地址划分成网络地址和主机地址两部分
URL和URL
URI:通过URI标记可以把网络世界里面的每一个事物都加以标记并区分开来
URL:网络地址
网络传输的压缩和字符编码
微博限制字数
url地址过长
利用放号器
初始值为0,对于每一个短链接生成请求, 都递增放号器的值,再将此值转换为62进制
将短链接服务器域名与放号器的62进制值进行字符串连接,即为短链接的URL
浏览器访问短链接服务器时,根据URL Path取到原始的链接,然后进行302重定向
如何保证发号器的大并发高可用
多个发号器,不同的发号规则, 比如一个发单号,一个发双号。
ARP地址解析协议
作用:ARP协议提供了网络层地址(IP地址)到物理地址(mac地址)之间的动态映射
过程
首先,每个主机都会在自己的ARP缓冲区中建立一个ARP列表, 以表示IP地址和MAC地址之间的对应关系
当源主机要发送数据时,首先检查ARP列表中是否有对应 IP地址的目的主机的MAC地址,如果有,则直接发送数据, 如果没有,就向本网段的所有主机发送ARP数据包,该数据包 包括的内容有:源主机 IP地址,源主机MAC地址,目的主机的IP 地址。
当本网络的所有主机收到该ARP数据包时,首先检查数据包中的IP地址是否是自己的IP 地址,如果不是,则忽略该数据包,如果是,则首先从数据包中取出源主机的IP和MAC 地址写入到ARP;列表中,如果已经存在,则覆盖,然后将自己的MAC地址写入;ARP响 应包中,告诉源主机自己是它想要找的MAC地址
源主机收到ARP响应包后。将目的主机的IP和MAC地址写入ARP列表, 并利用此信息发送数据。如果源主机一直没有收到ARP响应数据包,表示ARP查询败。
广播发送ARP请求,单播发送ARP响应。
虚拟ip
给路由器分配一个实体IP,之后每个连接这个路由器的设备给他分配一个虚拟IP, 当某个设备访问网络数据时,先经过路由器,然后路由器与网络进行数据交换, 然后路由器再根据自己分配的虚拟IP发送到相应的设备
例子:对外提供数据库服务器的主机除了有一个真实IP外还有一个虚IP, 使用这两个IP中的 任意一个都可以连接到这台主机,所有项目中数据库 链接一项配置的都是这个虚IP,当服务器发生故障无法对外提供服务时, 动态将这个虚IP切换到备用主机
主机宕机,备用机器通过ARP协议广播,使得其他主机更新自己的ARP缓存表
DHCP如何实现分配ip的
动态主机配置协议,是一个应用层协议
作用
集中的管理、分配IP地址,使网络环境中的主机动态的获得IP地址、 Gateway地址、DNS服务器地址等信息,并能够提升地址的使用率
原理
采用客户端/服务器模型,主机地址的动态分配任务由网络主机驱动。 当DHCP服务器接收到来自网络主机申请地址的信息时,才会向网络 主机发送相关的地址配置等信息,以实现网络主机地址信息的动态配置
步骤
发现阶段:DHCP客户端在网络中广播发送DHCP DISCOVER请求报文,发现DHCP服务器,请求IP地址租约
提供阶段:DHCP服务器通过DHCP OFFER 报文向DHCP客户端提供IP地址预分配
选择阶段:DHCP客户端通过DHCP REQUEST报文 确认选择第一个DHCP服务器为它提供IP地址自动分配服务
确认阶段:被选择的DHCP服务器通过DHCP ACK报文 把在DHCP OFFER报文中准备的IP地址租约给对应DHCP客户端
网络编程三层和两层
三层
核心层
汇聚层
接入层
两层
核心层
接入层
路由器和交换机的区别
工作层次不同
交换机在数据链路层,路由器在网络层
数据的转发对象不同
交换机是根据MAC地址转发数据帧;路由器是根据IP地址来转发数据报
分工不同
交换机主要是用于组建局域网,路由器则负责让主机连接外网
冲突域和广播域
交换机分割冲突域;路由器分割广播域
虚拟专用网 VPN
是什么
虚拟专用网络,是一门网络新技术,为我们提供了一种通过 公用网络安全地对企业内部专用网络进行远程访问的连接方式
实现原理
VPN网关一般会采用双网卡结构,内网卡接入公司总部 A的内部局域网络,外网卡使用公共IP接入Internet
保证通信的安全性
隧道协议
身份验证
数据加密
cdn
CDN部署在网络提供商的机房,使用户在请求网站服务时, 可以从距离自己最近的网络提供商机房获取数据;
反向代理
部署在网站的中心机房,当用户请求到达中心机房后, 首先访问的服务器反向代理服务器,如果反向代理服务 器中缓存着用户请求的资源,就将其直接返回给用户
servlet和filter的区别
概念
servlet是一种运行在服务器端的Java应用程序, 独立于平台和协议,可以动态的生成web页面, 它工作于客户端请求和服务器的中间层
filter是一个可以复用的代码片段,用来转换请求, 响应以及头信息,filter不能产生请求和响应, 只能在请求到达servlet之前对请求进行修改, 或者在请求返回客户端之前对响应进行处理
职责
servlet可以动态创建基于客户请求的页面; 可以读取客户端发来的隐藏数据和显示数据; 可以和其他的服务器资源进行通讯; 通过状态代码和响应头向客户端返回数据
filter主要是对请求到达servlet之前对请求和请求头信息进行前处理, 和对数据返回客户端之前进行后处理
区别
servlet的流程比较短,url来了之后就对其进行处理, 处理完就返回数据或者转向另一个页面
filter的流程比较长,在一个filter处理 之后还可以转向另一个filter进行处理
数据库
数据库的分类和常用的数据库
关系型数据库
非关系型数据库
数据库连接池的作用
同时创建多个链接,等待使用,使用时候从连接池取出链接, 不用创建。使用结束,链接释放回连接池
数据库优化方面的事
使用查询缓存
使用数据库连接池
选择合适的数据库引擎
选择合适的索引
数据库优化之分表
垂直分表
水平分表
分库
根据业务不同把相关的表且分到不同的数据库
对于特别大的访问量
主从复制
读写分离
负载均衡
连接
内连接
只显示符合连接条件的记录
外连接
左外连接
以左表为基准,找到右表匹配的数据,找不到用null补齐
右外连接
以右表为基准,找到左表匹配的数据,找不到用null补齐
全外连接
除了显示符合条件的连接记录外,其他的记录也显示出来
存储过程
定义
是一组为了完成特定功能的SQL 语句集,经编译后存储在数据库。用户可以 通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它
优点
减少网络传输
增加了使用的安全性
执行速度更快
首先,在存储过程创建的时候,数据库已经对其进行了一次解析和优化
其次,存储过程一旦执行,在内存中就会保留一份这个存储过程, 这样下次再执行同样的存储过程时,可以从内存中直接调用
缺点
调试麻烦
可移植性差
三范式
原子性,不可再分
非主键属性必须完全依赖于主键属性
任何非主键属性不依赖于其他非主键属性;每列都与主键有直接关系,不存在传递依赖
事务
ACID
原子性
原子性是指事务是一个不可分割的工作单位, 事务中的操作要么都发生,要么都不发生
一致性
系统状态是一致的。即,在并发操作时, 系统的状态也要和串行执行事务时一样
隔离性
多个并发事务之间要相互隔离,不能被其他事务的操作所干扰
持久性
在事务完成后,事务对数据库的操作会 被持久保存在数据库中,不会被回滚
数据库事务的隔离级别
读未提交
读已提交
可重复读
串行化
脏读
事务A读取了事务B提交的数据,但是B事务由于某种原因 导致事务回滚,但是A读取的仍然是事务B回滚之前的数据
读取未提交成功的数据
不可重复读
事务A读取了一条数据,这时事务B将该条数据修改, 事务A再次读取该条数据时,和最开始读取的数据不一致
前后多次读取,数据内容不一致
幻读
同一事务中,用同样的操作读取两次,得到的记录数不相同
幻读针对的是一批数据两次读取中,有新增或者减少
三者的区别
不可重复读的重点是修改 ,针对的是同一个主键的数据 同样的条件, 读取过的数据, 再次读取出来发现值不一样
幻读的重点在于新增或者删除 同样的条件, 第1次和第2次读出来的记录数不一样
脏读针对读取了未提交数据
幻读和不可重复读都是读取到了另一条 已经提交的事物,这一点和脏读不同
next-key(间隙锁)
在当前读读情况下,mysql通过next-key来避免幻读
next-key(间隙锁)的优势
是实时数据
next-key(间隙锁)的缺点
需要加锁
对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”, InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁 (Next-Key锁)[行锁+gap锁]
select * from emp where empid > 100 for update; 其中 empid 在表中的数据有 1,2...100,101 对于 empid > 101 的 数据也会加锁,这个锁就是 “间隙锁”
InnoDB不仅会对符合条件的empid值为101的记录加锁,也会对empid大于101(这些记录并不存在)的“间隙”加锁
不加锁其他事务插入了empid大于100的任何记录, 那么本事务如果再次执行上述语句,就会发生幻读
MVCC
在快照读读情况下,mysql通过mvcc来避免幻读
MVCC 是一种并发控制的方法,一般在数据库管理系统中, 实现对数据库的并发访问;在编程语言中实现事务内存。
MVCC 使用了一种不同的手段,每个连接到数据库的读者, 在某个瞬间看到的是数据库的一个快照,写者写操作造成的变化在写操作完成之前 (或者数据库事务提交之前)对于其他的读者来说是不可见的。
实现
MVCC 使用时间戳(TS)、递增的事务 ID(T)实现事务一致性
通过维护多版本数据,保证一个读事务不会被阻塞
快照读是通过MVVC(多版本控制)和undo log来实现的
当前读是通过加record lock(记录锁)和gap lock(间隙锁)来实现的
mvcc的优势
不加锁,并发性高
mvcc的缺点
会存储多个版本数据的冗余开销
不是实时数据
redo和undo日志
undo日志用于存放数据修改被修改前的值,假设修改 tba 表中 id=2的行数据,把Name=’B’ 修改为Name = ‘B2’ , 那么undo日志就会用来存放Name=’B’的记录,如果这个 修改出现异常,可以使用undo日志来实现回滚操作,保证事务的一致性
当buffer pool 中的data page变更结束后,会把相应修改记录记录到redo文件, 那么当DB服务发生crash的情况,恢复DB的时候,也可以根据这个文件的 记录内容,重新应用到磁盘文件,数据保持一致。
日志的级别
级别高到低为:error、warn、info、debug、trace
并发控制的方式
乐观锁
版本号
时间戳
悲观锁
数据库如何保证数据一致性
事务
悲观锁
乐观锁
索引分类
索引原理
将无序的数据变得有序
按照存储方式分为
聚集索引
表中的物理顺序与键值的索引顺序一致
索引的叶节点就是数据节点
一个表中只能拥有一个聚集索引
插入数据需重排序
因此修改慢
非聚集索引
表中的物理顺序与键值的索引顺序不一致
非聚簇索引的叶节点仍然是索引节点
一个表中可以拥有多个非聚集索引
插入数据不需要重排序
非聚集索引和聚集索引的区别在于, 通过聚集索引可以查到需要查找的数据, 而通过非聚集索引可以查到记录对应的主键值 ,再使用主键的值查找到需要的数据
按照维护与管理索引角度分为
唯一索引
在表上一个或者多个字段组合建立的索引,索引不可重复
非唯一索引
在表上一个或者多个字段组合建立的索引,索引可重复
主键索引
以主键作为索引,是唯一索引的特定类型
某一个属性组能唯一标识一条记录如:学生表(学号, 姓名,班级,性别等等),学号是唯一标识的,可以作为主键
组合索引
判断组合索引对查询是否生效
满足最左匹配原则,并且不是以下两种情况
范围查询在第一列,排序在第二列:A&amp;gt;5 ORDER BY B
两列以不同的顺序排序:ORDER BY&amp;nbsp; A ASC,B DESC
详细参考:https://blog.csdn.net/u013705066/article/details/82257099
组合索引注意事项
索引应该建在选择性高的字段上(键值唯一的记录数/总记录条数), 选择性越高索引的效果越好、价值越大,唯一索引的选择性最高
组合索引中字段的顺序,选择性越高的字段排在最前面
where条件中包含两个选择性高的字段时,可以考虑分别创建索引, 引擎会同时使用两个索引(在OR条件下,应该说必须分开建索引
不要重复创建彼此有包含关系的索引,如index1(a,b,c) 、index2(a,b)、index3(a)
组合索引的字段不要过多,如果超过4个字段, 一般需要考虑拆分成多个单列索引或更为简单的组合索引
过多的索引不仅仅会增加物理存储的开销,对于插入、删除、更新操作 也会增加处理上的开销,而且会增加优化器在选择索引时的计算代价
in一般不会导致索引失效,但最终数据库会将in语句解析为or语句
使用or查询需要条件中的每一列都建立索引
not exists后面的从句应该是可以走索引
not in 走不了索引
最左匹配失效
组合索引未使用最左前缀
like未使用最左前缀
使用or但是条件中的每一列没都建立索引
在where子句中进行null值判断的话会导致引擎放弃索引而产生全表扫描
在where子句中使用!= ,< >这样的符号,会导致引擎放弃索引而产生全表扫描
避免在where子句中使用or来连接条件,因为如果俩个字段 中有一个没有索引的话,引擎会放弃索引而产生全表扫描
全文索引
全文索引只能用于数据库引擎为MYISAM的数据表
MySql自带的全文索引只能对英文进行全文检索
可以采用Sphinx(斯芬克斯)/Coreseek技术来处理中文
覆盖索引
select的数据列只用从索引中就能够取得,不必读 取数据行,换句话说查询列要被所建的索引覆盖
覆盖索引必须要存储索引的列,而哈希索引、空间索引和全文索引等 都不存储索引列的值,所以MySQL只能使用B-Tree索引做覆盖索引
空间索引
网格索引
四叉树索引
R树家族索引
金字塔索引
哈希索引
于哈希表实现,只有精确匹配索引所有列的查询才有效。对于每一行数据, 存储引擎都会对所有的索引列计算一个哈希码(hash code),哈希码是一个 较小的值,并且不同键值的行计算出来的哈希码也不一样。哈希索引将所有的 哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针
hash索引的限制
哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行
哈希索引数据并不是按照索引值顺序存储的,所以也就无法用于排序
哈希索引也不支持部分索引列匹配查找,因为哈希索引始终是使用索引列的全部内容来计算哈希值的
不支持任何范围查询,例如WHERE price>100
访问哈希索引的数据非常快,除非有很多哈希冲突(不同的索引列值却有相同 的哈希值)。当出现哈希冲突的时候,存储引擎必须遍历链表中所有的行指 针,逐行进行比较,直到找到所有符合条件的行
JDBC
定义
用Java语言来操作数据库,JDBC是接口,而JDBC驱动才是接口的实现
使用
一是使用DriverManager来注册驱动,二是使用DriverManager来获取Connection对象
常用方法
executeQuery()查询方法
executeUpdate()更新方法
得到PreparedStatement对象后,调用它的setXXX()方法为“?”赋值
三层架构
视图层
与用户进行交互
业务逻辑层
完成业务功能
数据访问层
对数据库表进行CRUD操作
如何进行事务处理
connect. setAutocommit commit rollback
提供,调用,提交,回滚
Connection 提供了事务处理的方法,通过调用setAutoCommit(false)可以设置 手动提交事务;当事务完成 后用 commit()显式提交事务;如果在事务处理过程中发 生异常则通过 rollback() 进行事务回滚。除此之外,较新 的 JDBC 标准还引入了 Savepoint(保存点)的概念,允许事务回滚到指定的保存点。
C3P0是一个开源的JDBC连接池
Statement和PreparedStatement有什么区别
PreparedStatement接口代表预编译的语句,它主要的优势在于可以减少SQL的编译错误
PreparedStatement中的SQL语句是可以带参数的, 避免了用字符串连接拼接SQL语句的麻烦和不安全并 增加SQL的安全性(减少SQL注射攻击的可能性)
数据库可以将编译优化后的SQL语句缓存起来,下次执行相同结构的语句时就会很快
sql语句
在使用 join 时,on 和 where 条件的区别
on 条件是在生成临时表时使用的条件,它不管 on 中的条件是否为真,都会返回左边表中的记录
where 条件是在临时表生成好后,再对临时表进行过滤的条件,条件不为真的就全部过滤掉
sql语句优化小技巧
使用索引,索引能够更有效率的查询数据
大数据量执行插入更新操作建议使用批处理,降低访问数据库的次数
查询尽可能使用limit
使用explain查看语句执行效果
尽量不要使用like进行模糊查询
尽量不使用select *
一个 SQL 执行的很慢
偶尔很慢
数据库在刷新脏页,例如 redo log 写满了需要同步到磁盘
执行的时候,遇到锁,如表锁、行锁
一直很慢
没有用上索引:例如该字段没有索引;由于对字段进行运算、函数操作导致无法用索引
数据库选错了索引
主机本身配置不行,其他进程吃了内存
SQL语句编写的有问题
Intersect和Minus
Intersect,对两个结果集进行交集操作,不包括重复行,同时进行默认规则的排序;
Minus,对两个结果集进行差操作,不包括重复行,同时进行默认规则的排序
union和union all的区别
UNION去重且排序
UNION ALL不去重不排序
where、having之间的区别和用法
count(1) and count(*)
统计表中的所有的记录数(行数),包含字段为null 的记录
如果表多个列并且没有主键,则 count(1) 的执行效率优于 count(*)
特殊情况下
如果表只有一个字段,则 select count(*)最优。
如果有主键,则 select count(主键)的执行效率是最优的
count(1)和count(列名)
count(列名) 会统计该字段在表中出现的次数,忽略字段为null 的情况
列名为主键,count(列名)会比count(1)快
列名不为主键,count(1)会比count(列名)快
现需要求出各科成绩前三名的学生和成绩,与相应的课程
where和having的区别
“Where” 是一个约束声明,使用Where来约束来自数据库的数据,Where是在结果返回之前起作用的,且Where中不能使用聚合函数。
“Having”是一个过滤声明,是在查询返回结果集以后对查询结果进行的过滤操作,在Having中可以使用聚合函数。
用having就一定要和group by连用 用group by不一有having (它只是一个筛选条件用的)
join中on与where区别
on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录
where条件是在临时表生成好后,再对临时表进行过滤的条件
limit
连接
内连接
只显示符合连接条件的记录
外连接
左外连接
以左表为基准,找到右表匹配的数据,找不到用null补齐
右外连接
以右表为基准,找到左表匹配的数据,找不到用null补齐
全外连接
除了显示符合条件的连接记录外,其他的记录也显示出来
sql语句的执行顺序
FORM、ON、JOIN、WHERE、GROUP BY、CUBE | ROLLUP、 HAVING、 SELECT、DISTINCT、 ORDER BY、 LIMIT
数据结构
数组
字符串
图
有向图
无向图
链表
单向链表
双向链表
循环链表
跳表
在普通链表上建立索引
插入、删除、查询、范围查询
跳表与红黑树和AVL树对比
跳表更节省内存,平均一个节点1.33个指针, 树的一个节点平均两个指针
并发环境下,跳表更新的数据少,锁住的东西少, 平衡树涉及到的节点多,锁住的数据多
树有封装好的现成的包,跳表有个随机数生成器不太好实现
跳表的高度是随机的不稳定
哈希
一致性哈希
队列
单向队列
双向队列
循环队列
栈
树
红黑树
五个特性
根节点是黑色
叶子节点(NIL)是黑色
从根节点到叶子节点黑色节点的个数相同
节点为黑色或者红色
红色节点的两个子节点为黑色
优点
并不追求“完全平衡”——它只要求部分地达到平衡要求, 降低了对旋转的要求,从而提高了性能。
二叉搜索树
b树
定义
1.定义任意非叶子结点最多只有M个儿子;且M>=2
2.根结点的儿子数为[2, M];
3.除根结点以外的非叶子结点的儿子数为[M/2, M];
4.每个结点存放至少M/2-1(取上整) 和至多M-1个关键字;(至少2个关键字)
5.非叶子结点的关键字个数=指向儿子的指针个数-1;
6.非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
7.非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于 K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键 属于(K[i-1], K[i])的子树;
8.所有叶子结点位于同一层;
特性
1.关键字集合分布在整颗树中;
2.任何一个关键字出现且只出现在一个结点中;
3.搜索有可能在非叶子结点结束;
4.其搜索性能等价于在关键字全集内做一次二分查找;
5.自动层次控制;
b+树
定义
其定义基本与B-树同,除了:
1.非叶子结点的子树指针与关键字个数相同;
2.非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树 (B-树是开区间);
3.为所有叶子结点增加一个链指针;
4.所有关键字都在叶子结点出现;
特性
1. 所有关键字都出现在叶子结点的链表中(稠密索引), 且链表中的关键字恰好是有序的;
2.不可能在非叶子结点命中;
3. 非叶子结点相当于是叶子结点的索引(稀疏索引), 叶子结点相当于是存储(关键字)数据的数据层;
4.更适合文件索引系统;
b树和b+树区别
B树中同一键值不会出现多次,并且它有可能出现在叶结点, 也有可能出现在非叶结点中。而B+树的键一定会出现在叶结点中, 并且有可能在非叶结点中也有可能重复出现,以维持B+树的平衡
因为B树键位置不定,且在整个树结构中只出现一次, 虽然可以节省存储空间,但使得在插入、删除操作复杂度明显增加。 B+树相比来说是一种较好的折中。
B树的查询效率与键在树中的位置有关,最大时间复杂度与 B+树相同(在叶结点的时候),最小时间复杂度为1(在根结点的时候)。 而B+树的时候复杂度对某建成的树是固定的
B*树
定义
是B+树的变体,在B+树的非根和非叶子结点再增加指向兄弟的指针;
特性
B*树定义了非叶子结点关键字个数至少为(2/3)*M,即块的最低使用率为2/3
b*和b+的区别
B+树的分裂:当一个结点满时,分配一个新的结点,并将原结点中1/2的数 据复制到新结点,最后在父结点中增加新结点的指针;B+树的分裂只影响原结 点和父结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针;
分支主题
AVL树
定义
相比于”二叉查找树”,它的特点是: AVL树中任何节点的两个子树的高度最大差别为1。
失去平衡的可以概括为4种姿态
左左
左子树的左子树导致的失衡
左右
左子树的右子树导致的失衡
右左
右子树的左子树导致的失衡
右右
右子树的右子树导致的失衡
总结:发生问题的那个节点要成为根节点才能解决问题。 不管我们是执行插入还是删除操作,只要不满足上面的条件, 就要通过旋转来保持平衡,而旋转是非常耗时的, 由此我们可以知道AVL树适合用于插入删除次数比较少,但查找多的情况。
哈夫曼树
是一种带权路径长度最短的二叉树
如何译码
Tire树
定义
字典树(Trie)可以保存一些
使用场景
典型应用是用于统计和排序大量的字符串(但不仅限于字符串), 所以经常被搜索引擎系统用于文本词频统计
基本性质
(1) 根节点不包含字符, 除根节点意外每个节点只包含一个字符。
(2)从根节点到某一个节点, 路径上经过的字符连接起来,为该节点对应的字符串。
(3)每个节点的所有子节点包含的字符串不相同。
(4)如果字符的种数为n,则每个结点的出度为n, 这也是空间换时间的体现,浪费了很多的空间。
(5)插入查找的复杂度为O(n),n为字符串长度。
Trie的核心思想是空间换时间。利用字符串的 公共前缀来降低查询时间的开销以达到提高效率的目的。
K-D tree
如何高效使用日志
什么时候应该打日志
当遇到问题的时候,可以通过debug功能来确定问题, 也应该考虑打日志,可以通过日志进行问题定位
当你碰到if…else 或者 switch这样的分支时, 要在分支的首行打印日志,用来确定进入了哪个分支
以功能为核心进行开发,应该在提交代码前, 可以确定通过日志可以看到整个流程
基本格式
必须使用参数化信息的方式
对于debug日志,必须判断是否为debug级别后,才进行使用
不要进行字符串拼接,那样会产生很多String对象,占用空间,影响性能
使用[]进行参数变量隔离
不同级别的使用
ERROR
影响到程序正常运行、当前 请求正常运行的异常情况
打开配置文件失败
所有第三方对接的异常(包括第三方返回错误码)
所有影响功能使用的异常, 包括:SQLException和除 了业务异常之外的所有异常 (RuntimeException和Exception)
不应该出现的情况
比如要使用Azure传图片,但是Azure未响应
如果进行了抛出异常操作, 请不要记录error日志, 由最终处理方进行处理
WARN
不应该出现但是不影响程序、 当前请求正常运行的异常情况
找不到配置文件,但是系统能自动创建配置文件
缓存池占用达到警告线
业务异常的记录
INFO
系统运行信息
Service方法中对于系统/业务状态的变更
job需要记录开始和结束
主要逻辑中的分步骤
对于复杂的业务逻辑,需要进行日志打点, 以及埋点记录,比如电商系统中的下订单逻辑, 以及OrderAction操作(业务状态变更)
外部接口部分
客户端请求参数(REST/WS)
对于整个系统的提供出的接口 (REST/WS),使用info记录入参
调用第三方时的调用参数和调用结果
调用其他第三方服务时,所有 的出参和入参是必须要记录的
DEBUG
可以填写所有的想知道的相关信息
生产环境需要关闭DEBUG信息
如果在生产情况下需要开启DEBUG 需要使用开关进行管理,不能一直开启
基本用法
变量查看
计算表达式
智能步入
断点条件设置
多线程调试
回退断点
中断Debug
TRACE
特别详细的系统运行完成信息,业务代码中, 不要使用.(除非有特殊用意,否则请使用DEBUG级别替代)