#并发 并行
并发 : 把任务在不同的时间点交给处理器去处理 在同一时间点,任务并不会同时运行
并行 : 把每一个任务分配给每一个处理器独立完成 在同一时间点,任务一定是同时运行虚拟内存
(主存 和 内存 指的一个东西, 外存 和 辅存 指的一个东西)
原因 : 有些进程需要内存很大,超过物理内存的容量
多道程序设计,使主存同时存放多个进程的逻辑,每个进程可用的物理内存更加稀缺
不可能无限的增加物理内存,物理内存总有不够的时候
分页(将一个进程离散的分配到内存中,此时程序的地址空间分为若干个固定大小的页,将内存空间分为块,页放入块)
虚拟内存(某时刻程序并不是全部都要使用主存,把程序使用的内存划分,根据局部性原理,将部分暂时不使用的内存放在外存)
逻辑地址空间 --> 物理地址空间 (程序编译时是逻辑地址表示的,编译后要运行则是物理地址)
虚拟内存受地址空间的影响,速度接近于内存,成本接近于辅存虚拟内存
32k的物理内存 64k的虚拟内存
也就是说虚拟内存一部分映射到物理内存,一部分是映射到磁盘的
运行时,将需要的内存小块移入内存,不需要的移出去
页表就是反映了虚拟内存和物理内存的映射
MMU(内存管理单元)
位于CPU内部,可通过硬件完成地址映射
多级页表会节省一部分空间
快表也位于CPU种(减少了MMU的计算成本)
内存(内存条RAM)
断电后信息消失
操作系统允许用户直接接触内存的话 2种结果
用户不小心操作到系统的内存
操作系统给用户程序做一些隔离的,要不然互相操作不走中断的话容易崩溃
地址空间就是把内存划分的一个个空间
基地址寄存器(18000+1、2、3)
界限寄存器(20000)不允许访问之外的地址
内存超载(内存不够用)的解决方案
交换 让这个进程相关的内存和磁盘做交互
虚拟内存 让用户以为自己的资源够用
交换存在的问题
占用大量内存的进程进行磁盘的交互(解决方式 --> 存一部分就行)
放入磁盘后会空出来一块,需要进行整理,真个内存会比较乱
#乐观锁,悲观锁
这两种锁是广义的概念,体现了看待线程同步的不同角度
悲观锁 : 访问临界资源时加锁,访问结束锁释放
乐观锁 : 访问时判断临界资源是否被更新,如果未被更新,则该线程进行更新资源,否则说明被其他的线程更新了,该线程放弃更新
悲观锁每次操作都加锁,乐观锁默认不添加锁
悲观锁适合写操作,乐观锁适合读操作
#ACID
原子性 : 事务是一个不可分割的单位,其中的操作要么都做,要么都不做
事务中一个 sql 执行失败 ,已执行的语句也必须回滚, 数据库退回到事务前的状态
持久性 : 事务一旦提交,它对数据库的改变就应该是永久性的。 接下来的其他操作或故障不应该对其有任何影响
隔离性 : 事务内部的操作与其他事务是隔离的 ,并发执行的各个事务之间不能相互干扰
一致性 : 事务执行前后,数据库的完整性约束没有被破坏
#联合(复合)索引
由多个字段组成的一个索引
每个节点包含多个字段的值(最大的特点)
可以通过 EXPLAIN 查看索引(KEY)
eg : idx(x, y, z) 建立联合索引当索引为 x,z 时,x会走xyz索引,z不会(会在x查询的结果后进行检索)
联合索引的使用遵循最左匹配原则 ,(联合索引从最左的字段进行依次匹配)是从建索引的最左边一个字段开始( where y ,z 是没有使用联合索引的)
where条件必须使用联合索引的第一个字段
联合索引和 where 条件的顺序无关 ,只和字段有关
#日志类型
二进制日志(binlog) --> 最常见
每一份对 Mysql 的操作都会同时往磁盘写一份 binlog
主要是用于备份与恢复
查询语句不影响 Mysql数据 ,所以在 binlog 中不会被记录下来
重做日志(redolog) --> 保护事务的原子性
事务操作的同时记录 redolog 到磁盘上
若事务提交故障, 则执行 redolog 恢复事务
若事务成功的落到磁盘上 ,则 redolog 就失去作用
回滚日志(undolog) --> 和 redolog 功能类似, 作用相反, 保护事务的原子性
若事务执行过程故障,则通过 undolog 回滚事务至事务执行前的状态
redolog 和 undolog 是为了 事务成功提交 和 事务回滚
DNS
DNS用到 UDP快
进程服务 IP+端口(说明具体是网络中的哪台主机的哪个进程来提供服务)
域名 -> IP地址 (这个过程就是 DNS 域名服务)
点 分割 不同的域
www.baidu.com 分别为 三级域 二级域 顶级域
DNS 的过程是发生在客户端的(把域名转换为 IP 地址)
迭代查询 : 本地域名服务器依次去查询根,顶级,权威域名服务器,最后返回 IP 地址
递归查询 : 每次都是不同的对象之间的查询 ,最后依次返回
#TCP 连接与释放
序号(seq) 确认号(ack) -> 表示下次希望收到的数据
标志位(ACK SYN)
如果两次握手 : 可能会产生建立多个 连接 的情况(客户端第一次发送了多个 SYN),可能产生异常情况
第二次挥手 ACK 并不是同时 FIN ,–> 第三次挥手 FIN
因为可能被动中断连接的一方还没有将数据发送完整 ,所以第二次挥手可能是一个正常的交互报文
被动中断连接的一方在第二、三次挥手之间有一个 close_wait 阶段(发送剩余的数据)
time_wait (2MSL | MSL 最长报文寿命)
最后一个报文没有确认 为了确认最后一个 ACK 报文一定能到达对方
2MSL 时间内,如果没有到达对方,那么对方会重新第三次挥手,确保连接正常释放
另外确保当前连接所有的报文都已经过期
滑动窗口
(TCP 的可靠传输)停止-等待协议
发送方接收方一直停止等待
发送方每发送消息都要保证确认信息回来
对信道的利用率不高
超时重传机制
保证可靠传输
连续ARQ协议 自动重传请求 两个点 滑动窗口和累计确认
(批量发送和确认)
累计确认 : 已确认的字节序号及其之前的数据都已被正确收到
滑动窗口的第一个字节就是确认号希望收到的数据
通过 TCP 协议头部的序列号,确认号,窗口等字段的控制,实现数据的接收
数据不再是串行的发送,可以进行并行发送每次重传是重传一段数据的
#Chan 底层
lock 锁,所有发送和接受之前都要加锁 -> 线程安全
buf缓存 表示 chan 缓存的大小 ,当chan满了时,写的协程G1会让出自己占有的线程,
同时协程会被加入到sendq队列中等待被唤醒,
此后有协程从buf取出数据时,chan会将G1唤醒并将G1写的数据加入到buf中然后把G1放到可运行的协程队列中
环形队列:buf的实现是一个环形队列,优点是不需要动态的内存释放和分配,可以对固定的内存大小反复使用
sendq:发送队列,当向chan写入数据,且chan已满时协程会被放到该队列
recvq:取出队列,当从chan中取出数据时,且chan已空时协程会被放入到该队列线程 进程
进程 : 最小的资源管理单元 可包含多个线程
线程 : 最小的执行单元 只属于一个进程 无地址空间,包含在进程的地址空间内是进程中实际运行工作的单位
协程 : 比线程更加轻量级 不再被内核调度,在用户态执行进程调度算法
从就绪队列中如何挑选就绪进程来运行的一个算法
前提是多道程序设计 CPU资源有限
算法要考虑CPU资源如何公平分配 进程的优先级
非抢占式调度 就绪进程只能等当前进程主动放弃CPU才能执行
抢占式调度 允许中断当前执行的进程
先来先服务 短进程优先 优先级调度
高响应比优先 综合考虑了执行时间和等待时间
时间片轮转 划分许多时间片共进程使用,使用后进程被塞到队列末尾 时间片过长会退化为先来先服务
多级反馈队列
#进程的三个基本状态转换
就绪 执行 阻塞
就绪 执行 : 时间片完就绪 就绪通过进程调度到执行
执行 -> 阻塞 : 等待某个事件发生而无法执行时,便放弃处理机而处于阻塞
执行 -> 就绪 : 处于阻塞状态的进程,若其等待的事件已经发生
#死锁的四个必要条件
互斥条件 即在一段时间内,某资源只能被一个进程占用
请求和保持 进程请求的资源被其他进程占有,此时请求进程阻塞,但对自己已获得的资源保持不放
不可抢占 进程已获得的资源在使用完之前不能被抢占
循环等待
#进程间的通信
比较简单常见的是信号量通信
可以用 go 中协程的 同步 来解释
TCP UDP
TCP 面向连接 通过三次握手,拥塞控制来保证可靠性
UDP 无连接 适用于传输大量数据,传输速度快 UDP首部开销小拥塞避免算法
目的 : 防止过多数据注入网络调解网络的负载
UDP没有拥塞控制,不会感知网络是否拥塞
拥塞窗口 门限值 传输轮次
(TCP 头部的一个变量) (拥塞窗口超过其时,开启拥塞避免) (一次报文发送和确认的时间)
慢启动 指数增长到门限值,开始拥塞避免
拥塞避免 拥塞避免超时后,重新开启慢启动
新的门限值 = 发生超时 时的拥塞窗口 / 2
快重传 让发送方尽早知道个别报文段的丢失(收到 3 次重复确认 ,立即重传)
快恢复 此时 门限值 = 拥塞窗口 / 2 拥塞窗口 = 门限值 开始拥塞避免算法#缓存穿透 缓存雪崩 缓存击穿
缓存穿透 : 查询一个一定不存在的数据,穿透了缓存层直接达到 db
解决 : 空值缓存 第一次查询完不存在的数据后,将该 key 与对应的空值放入缓存中,设定较短的失效时间
缓存雪崩 : 所有的缓存的失效时间相同 简单解决 : 交错失效时间
缓存击穿 : 对于某一特定的热点数据来说,一般是缓存时间到期,并发用户特别多,缓存没读到数据,去数据库去取数据
解决 : 请求数据库这一步上锁,保证只有一个线程去访问数据库
#最左前缀
where 子句中使用最频繁的一列放在最左边(例如 Uid)
#context
管理协程退出(例如在 http 服务中请求可能临时终止,context 管理协程退出)
ctx.Done() 代表将要退出协程 的 规范写法
使用 context 更重要的一点是 协程之间常存在级联关系,退出需要具有传递性
#数组
数组是定长的(然后再说 切片 即可)
#切片
数据结构 : array指针指向底层数组, len 切片长度 ,cap 底层数组容量
新建切片 cap 默认会和长度相等
每次长度超过容量时,就会发生扩容
扩容操作 : 扩容操作只关心 cap ,会把原切片数据拷贝到新切片指向的数组中,追加数据由 append(每次追加一个) 在扩容结束后完成
追加操作 : 若 cap 够用,则新元素追加进去,len ++,返回该切片 ;若 cap 不够,先扩容,获得新切片,将新元素追加进新切片,len ++ ,返回新切片
#接收器
值接收 运行时将接收器的值复制一份,修改无效
指针接收 调用方法修改接收器指针的任意成员变量是有效的 接近于面向对象中的 this 结构体太大,不用复制,提高一些性能
#pprof 性能调优
CPU,堆,栈,协程的使用情况
使用 net/http/pprof 借助 http 服务采样,访问 8080 查看结果
#存储引擎
InnoDB : 最大的特点是支持事务,同时有行锁,支持外键(MyISAM 不支持上述)
索引
为了提高数据查询的效率对于最普遍的查询有精确查询和范围查询
插入数据后,要考虑插入的性能 和 插入后查询的性能
B+ 树 (平衡的多叉树,同层级节点间有指针链接) 作为 Mysql 的索引 :
多节点降低树高提高性能 只有叶子节点保存数据且为双向链表来支持范围查询B树在叶子节点和根节点都保存数据,
叶子节点之间无指针相邻
不利于范围查询
在叶子节点保存数据对范围查询不友好
查询的时间复杂度是 NLogN
B+树和Hash索引的明显区别
● 如果是等值查询,那么hash索引具有绝对优势,
● 范围查询检索,就需要用到B+树
● Hash索引不支持联合索引的最左匹配原则
● 在有大量重复键值情况下,哈希索引的效率也是极低的,因为存在所谓的哈希碰撞问题。
聚簇 与 非聚簇 (数据与索引是否放在一起)
InnoDB(聚簇) : 将主键组织在 B+ 树,行数据存储在叶子节点中
一个数据表只有一个 聚簇 ,可以有多个 非聚簇
非聚簇 : 叶子节点保存的是 存储数据的指针#goPath Gomod
goPath : 配置完 gopath 环境变量后要创建三个文件
bin:存放编译后生成的二进制可执行文件
pkg:存放编译后生成的文件
src:源码存放为位置
问题 : 更新一个库时,会造成不兼容
gomod : 可以在任意文件目录创建项目
require: 应用特定的模块版本
#Http 2.0
多路复用 : 在一个信道上传输多路信号 (写信一寄一回 ,打电话双方互不影响)
二进制分帧是基础,通信单位不再是 报文
多请求并行不依赖多 TCP 连接
服务端推送 : 服务端未卜先知(又会省掉一些并行请求的 时间)
#请求状态码
2X 成功
3X 重定向 304(校验本地资源 ,向服务端发送请求,304 说明未被修改)
4X 客户端错误 404(说明服务器无法找到所请求的 URL, 例如 URL 对应的图片不存在)
5X 服务端错误 503(无法向外提供服务, 可能宕机)
#Get Post
最直观的区别 就是GET把参数包含在URL中,POST 通过 request body 传递参数
#王者
“游戏大厅” 承载了相当多的用户数 ,有挑战性的是 自动匹配玩家进入一个"房间"(服务器)
王者 UDP ,若 TCP 出现一个数据包丢失,所有事情都需要停下来等待这个数据包重发,玩家操作会出现卡顿以及响应不及时
采用 帧同步 ,并按照固定频率来同步玩家的输入信息到每一个c端,玩家网络延迟服务器的帧步进是不会等待,玩家感觉自己的操作延迟
服务器为每个玩家分配一个随机种子,保证暴击伤害是一致的
#创建
数据库 : 确定字符集(保持程序和数据库一致,避免乱码) 字符串排序规则(general_ci)
数据表 : 定义表的字段(是否为空,数据类型,默认值,是否递增) 主键,外键,索引
#varchar 和 char
varchar : 可变长 ,最大 65535 字节
char : 占用固定空间 ,最大 255 字节
#make 和 new
make 创建 chan, slice ,map(因为用 make 可以初始化好) 返回引用类型
new 内存置0 返回指针类型(传入类型的指针) --- > 最主要的区别#并发 – > 多协程的 通信 和 同步
通信 : (用 go func() 运行发送接收两个协程 )
channel
select -> 获取 IO 操作, 通常是从 chan 中获取数据
同步 : waitgroup
Add() Done()
Wait() 同步等待所有记录的协程全部结束#事务隔离级别、MVCC
脏读 : 看到未提交的数据 -- > 张三存钱 rollback
幻读 : 看到变更的数据(例如一个事务 delete 的操作)
乐观锁 : 加一个版本号 where version = 2
MVCC : 为 每一个事务 和 每一个 行 都创建了一个版本号
(通过版本号实现的一个脏读幻读的隔离)
默认 RR 可重复读
事务中对行的操作会使其版本达到事务的版本, 比其小的版本的事务就读不到改行的数据#defer, panic, recover
defer : 关闭资源等
panic : 错误触发, 终止程序
recover : 不希望程序因为 panic 而终止,比如 web 服务
#基础语句
INSERT INTO imooc_user(username,age) VALUES('pedro',23);
UPDATE imooc_user SET age = 18 WHERE username='pedro';
DELETE FROM imooc_user WHERE username='pedro'; (删除一行)
SELECT age, COUNT(*) FROM imooc_user GROUP BY age HAVING COUNT(*) > 1; (having 搭配 group by 使用)
Distinct 去重 AND 多条件查询之间 JOIN 连接
直接跟在语句最后 : LIMIT ORDER BY (默认升序) + DESC 降序
















