记录下题目,涉及多个方面,答案有自己总结,也有来源与网络,并不是标准答案,仅供参考。
数据结构和算法
了解的数据结构,区别和优势?
- 数组、字符串
- 链表
- 栈
- 队列
- 双端队列
- 树
- 优先队列
- 图
- 前缀树
- 线段树
- 树状数组
平衡二叉树怎样才能称为平衡?
- 可以是空树;
- 如果不是空树,任何一个节点的左子树和右子树都是平衡二叉树,且高度差不超过1;
如何实现幂等?
幂等关键是操作是不是幂等的
数据库不可能三角,读性能,写性能,一致性。
定时重算余额,牺牲一致性换取读写性能。
写入的时候同时重算一次写入计算冗余,牺牲写性能。
读取的时候的时候重算,牺牲读性能。- 唯一ID
- 去重表
- 数据库插入或更新 InsertOrUpdate
- 版本控制
- 状态机
连个字符串s1和s2,写方法求出两个字符串都拥有的字符.
答:参考Go 求两个数组切片交集,使用[]rune("abc")
转换字符串.利用array实现栈,要求线程安全.
答:参考Go 实现线程安全栈假定一个二叉树T,给定两个节点n1和n2,查找出两个节点共同的父节点,节点定义如下:
1
2
3
4type TreeNode struct {
LeftNode *TreeNode
RightNode *TreeNode
}从一个字符串中找出第一个只出现一次的字符并返回下标。
青蛙跳台阶,青蛙一次跳1级或者2级台阶,问N级台阶一共有多少种跳法?
流量削峰怎么实现?
- 消息队列
- 层层削峰
- 答题
参考秒杀之流量削峰
一个500G文件,存着用空格分割的随机数字,如何排序?
安全
- 什么是加密?什么是签名?区别是什么?
- 加密:使用密钥以某种算法改变原有内容数据,防止被他人获取数据内容,只能使用密钥解密得到原始数据,分为对称加密(如AES)和非对称加密(如RSA);
- 签名:使用密码散列函数从数据中提出摘要,然后使用私钥对摘要进行加密,就是数据签名了,主要是为了保证数据一致性;
计算机原理
- 进程、线程和协程的区别
- 进程:系统进行分配和调度的一个独立单元。拥有自己的独立内存空间,依靠进程间通讯来通讯,重量大,上下文切换开销大,相对稳定安全。
- 线程:线程是进程的一个实体,是处理器调度的基本单元,且进程至少拥有一个主线程。线程基本不拥有系统资源,只拥有运行中必不可少的资源(计数器、寄存器和栈),但是可以与同一进程下的其他线程共享进程的全部资源,主要通过共享内存方式。上下文切换开销比进程小,速度比较快,但是不够稳定容易丢失。
- 协程:一种用户态的轻量级线程,分配和调度完全由程序控制。拥有自己的寄存器上下文和栈,切换时,将寄存器和栈保存到其他地方,切换回来时,恢复保存的寄存器和栈,切换速度非常快,开销非常小。
- 多路复用原理,一台服务器怎么支持几十万连接的?
Golang
- context包
- Done
- WithCancel
- WithDeadline
- WithTimeout
- WithValue
- sync包用法?
- Waitgroup
管理等待协程 - Mutex/RWMutex
互斥锁、读写锁 - Map
线程安全的map - Pool
对象池 - Cond
用户goroutine协作,控制goroutine挂起和唤醒,Wait/Signal/Broadcast - Once
确保函数只运行一次
- Waitgroup
- Goroutine调度器四个概念?Goroutine如何调度?
- G: Goroutine
每个 Goroutine 对应一个G结构体,G 存储 Goroutine 的运行堆栈、状态以及任务函数,可重用。G并非执行体,每个 G 需要绑定到 P 才能被调度执行; - P: Processor
逻辑处理器,维护一个自己的 G 队列,并找到可用的 M 来执行 G; - M: Machine
操作系统线程并抽象为 Machine,M 在执行系统调用时可能会阻塞,默认 M 的数量大于 P 的数量,这样某个 M 在执行某个 G 阻塞后,P 可以找另一个空闲的 M 继续跑其它的 G; - S: Schedule
进程中唯一的调度器,负责创建监控线程和 G、P、M 以及分配和维护资源队列。
- G: Goroutine
- GC,三色标记法原理?
- GC 触发时机?
- 内存扩大一倍时
- 默认2分钟
- 手动调用runtime.GC()
- Goroutine为什么开销小?
goroutine是应用层实现的用户态的轻量级线程,运行在线程池上,由golang的runtime实现调度,因为调度时不需要像线程一样涉及到系统调用,不需要进行内核态的切换,所以开销比线程小很多。 - 抢占式goroutine调用是什么意思?
goroutine 遇到阻塞或者主动调用 runtime.Gosched 的情况下可能会产生重新调度,让出计算资源给其他goroutine使用,如果一个 goroutine 不包含上面提到的情况,那么其他的 goroutine 就无法被调度到相应的 CPU 上面运行,这是不应该发生的。这时候就需要抢占机制来打断长时间占用 CPU 资源的 goroutine ,发起重新调度。Golang 运行时(runtime)中的系统监控线程 sysmon 可以找出“长时间占用(10ms)”的 goroutine,从而标记相应 goroutine ,待 goroutine 运行到检查点(抢占检查点是编译器预先插入)时才被抢占。 - append切片的时候,为什么要返回?(重点,值传递)
golang所有方法和函数参数都是值传递,调用append方法的时候,方法接收到的slice参数实际上是复制了一份slice结构拷贝,所以append内部在对这个拷贝进行操作的时候,并不会影响到调用append时传入的slice结构,所以需要返回修改后的slice结构。 - slice 扩容规则?
- 容量 大于 新长度,不扩容
- 扩容一倍 小于 新长度,扩容到新长度
- 新长度 小于 1024,扩容1倍
- 新长度 大于 1024,扩容1.25倍
- 内存对齐
- 什么时候传值,什么时候传址?
- 希望函数对对象的修改不影响原对象,传值
- 传的对象较大,从对象拷贝开销考虑,传址
- map底层数据结构?
hmap/bucket/bmap/tophash/overflow - struct 怎么比较,哪些能比较,哪些不能比较?
- 如果结构体的所有成员变量都是可比较的,那么结构体就可比较
- 如果结构体中存在不可比较的成员变量,那么结构体就不能比较
- 结构体之间进行转换需要他们具备完全相同的成员(字段名、字段类型、字段个数)
- 切片和map不能比较
- golang的内存模型,多小才是小对象,为什么小对象多了会造成gc压力?
- 什么是channel,为什么它可以做到线程安全?
Golang的Channel,发送一个数据到Channel 和 从Channel接收一个数据 都是 原子性 的。而且Go的设计思想就是”不要通过共享内存来通信,而是通过通信来共享内存“,前者就是传统的加锁,后者就是Channel。 - channel 的缓存长度怎么确定?
- channel 如果消费者消费能力跟不上生产者生产能力,怎么处理?
网络
tcp协议
为什么需要三次握手?四次挥手?
- 三次握手中的每一次都是必须的。如果是两次握手,在第二次结束后,服务器并不能保证客户端已经收到了第二次的请求,如此一来的话,服务器会一直保存着这个通信过程,因为TCP通信都是要占用端口的,造成了一定的资源浪费。所以,就一定要让客户端来发送ACK的确认请求。
- 四次挥手不能像三次握手一样,三次握手可以将ACK+SYN 一起发送,ACK用于确认信息,SYN却是用来建立联机的;四次挥手中ACK是不能和FIN一起发送,ACK只是告诉客户端确认我收到了,等我将数据发送完毕之后会向其发送FIN的标志,所以四次挥手是不能够改变的。
TIME_WAIT和CLOSE_WAIT状态解释?
TIME_WAIT过多怎么处理,如何避免?
短时间内大量并发的短链接会造成大量TIME_WAIT状态,导致其他连接请求不能进入。
编辑内核文件/etc/sysctl.conf
net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout 修改系默认的 TIMEOUT 时间
net.ipv4.tcp_keepalive_time = 1200 表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。
net.ipv4.ip_local_port_range = 1024 65000 表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为1024到65000。
net.ipv4.tcp_max_syn_backlog = 8192 表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_max_tw_buckets = 5000 表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。单台服务器并发TCP连接数到底可以有多少?
udp协议
http协议
https协议,好处和缺点分别是什么?
优点:使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器
TTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性
缺点:
- HTTPS协议握手阶段比较费时
- HTTPS连接缓存不如HTTP高效,会增加数据开销和功耗
- CA机构颁发的证书需要费用
- http协议中GET/POST/PUT/PATCH/DELETE有什么意义?是否了解Resful设计原则和约束条件?
答:参考REST,以及RESTful的讲解 - http分片提交是怎么实现的?
- 客户端如何验证证书是否合法?
各大浏览器和操作系统已经维护了所有的权威证书机构的名称和公钥。客户端只需要知道是哪个权威机构发的证书,使用对应的机构公钥,就可以解密出证书签名;接下来,客户端使用同样的规则,生成自己的证书签名,如果两个签名是一致的,说明证书是合法有效. - HTTP1.0 HTTP1.1 HTTP2.0 各有什么特性?
http1.0
- 无状态、无连接
- 无法复用连接,每次请求进行一个TCP连接
- 队头阻塞
http1.1
- 支持长连接 connection keep-alive
- 请求管道化 pipelining
- 加入缓存处理 cache-control
- 增加Host 一个服务器能创建多个web站点
http2.0
- 二进制分帧 frame
- 多路复用 stream
- 头部压缩
- 服务器推送
- 浏览器从输入域名到渲染出页面的整个过程?
- DNS解析URL
- 与服务器交互获取数据
- 浏览器渲染HTML
- nginx 反向代理?负载均衡?
Mysql
数据库的ACID?
- 原子性(Atomicity):整个事务中的所有操作,要么全部完成,要么全部不完成。
- 一致性(Correspondence):在事务开始以前和事务结束以后,数据库的完整性约束没有被破坏。
- 隔离性(Isolation):串行化请求,使得在同一时间仅有一个请求用于同一数据。
- 持久性(Durability):在事务完成后,该事务对数据库所作的更改持久的保存在数据库中。
数据库连接种类
- 内连接 inner join
- 左连接 left join/left outer join
- 右连接 right join/right outer join
- 全连接 full join
- 交叉连接 cross join
数据库索引的创建对新增、修改、查询、删除有什么影响?
- 加快数据检索速度
- 减少磁盘IO
- 占用空间
- 降低增加、修改、删除操作速度,因为需要同步修改索引
explain?
显示mysql如何使用索引来处理select语句以及连接表,可以帮助选择更好的索引和写出更优化的查询语句。innodb 的底层实现?
在多并发的API中如何保证数据的唯一性,如多人同时注册相同用户名?
- 添加唯一索引
- 锁表 并发差
- 修改数据库隔离级别
- 采用insert select 语句
建立索引后为什么查询快?原因是什么?
索引建立
- 在经常需要搜索的列上,可以加快搜索的速度;
- 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
- 在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
- 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
- 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
- 在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
联合索引最左匹配原则
参考mysql索引最左匹配原则的理解隔离级别有哪些?脏读幻读会在什么情况下出现?
脏读:事务1 读取了 事务2 未提交的数据,然后事务2回滚
不可重复读:事务1 第一次读取了数据,事务2 提交数据,导致 事务1 第二次读取数据内容与第一次不同(内容不同)
幻读:事务1 第一次读取了rows1,事务2 提交,事务1 第二次读取了row1和row2(记录数不同)隔离级别 脏读 不可重复读 幻读 Read uncommitted (读未提交) √ √ √ Read committed (读已提交) × √ √ Repeatable read (可重复读) × × √ Serializable (序列化) × × × 乐观锁
乐观的假设锁在更新数据的时候可以拿到,然后在更新时使用 版本号 或者 时间戳 验证数据是否最新,不是最新的就先获取最新版本再更新。悲观锁实现
要使用悲观锁,需要关闭mysql数据库的自动提交属性,因为mysql默认使用autocommit模式,也就是说,当你执行一个更新操作后,mysql会立即将结果进行提交。
使用命令设置mysql 为非autocommit模式:set autocommit =0;
一般使用select … for update对所选择的数据进行加锁处理,例如,select status form t_goods where id in (‘1’,’2’) for update;这条sql语句会锁定t_goods表中id为1和id为2的记录。
使用场景举例:商品t_goods表有一个字段status,status为1代表商品未被下单,status为2代表商品已经被下单,那么我们队某个商品下单是必须确保该商品status为1.假设商品的id为1
①begin/begin work/start transaction; //开始事务(三者选一就可以)
②select status from t_goods where id=1 for update; //查询出商品信息
③insert into t_orders(id,goods_id) value (null,1); //根据商品信息生成订单
④update t_goods set status=2; //修改商品status为2
⑤commit/commit work; //提交事务为什么有数据库连接池?有什么作用?
- 节约资源,不用频繁创建和销毁
- 限定连接数量,增加稳定性,避免连接数过多导致崩溃
- 提高响应速度,直接从池中申请不用创建
怎么在不停止服务的情况下往一个大数据量表中增加字段?
- 建立包含新字段的新表,每次操作都将原表中受影响的记录移到新表,逐步完成转移
- 建立关联表,用外键连接
连接池中的连接数怎么确定?
核心数*2 + 有效磁盘数
参考 数据库连接池到底应该设置多大?批量写入和逐条写入有什么区别?
批量写入节约数据库连接开销,不用频繁创建和销毁数据库连接sql和nosql的区别?
sql: 关系型数据库,创建在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。现实世界中的各种实体以及实体之间的各种联系均用关系模型来表示。- 事务一致性、复杂查询、容易理解、使用方便、易于维护
nosql: 非关系型数据库,是对不同于传统的关系数据库的数据库管理系统的统称。
- 弱一致性、以键值对存储、结构不固定、水平可扩展性
Redis
redis好处
- 速度快
- 数据类型丰富
- 支持事务,操作都是原子性
- 丰富的特性:用于缓存,消息队列,设置过期时间自动删除
如何保证redis中的数据是热点数据/redis存储满了如何处理
通过redis的数据淘汰策略- no-enviction(驱逐):禁止驱逐数据,新增返回no
- volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
- volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
- volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
- allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
- allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
- 如果voltile-lru/volatile-ttl/volatile-random 没有可以淘汰的数据,同no-enviction处理
Redis与Memcache区别
- 存储方式
- Memcache 全内存
- Redis 支持持久化
- 数据类型
- Memcache 字符串
- 多种数据结构
- 底层模型
- Redis直接自己构建了VM 机制,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
- value大小
- Memcache 1MB
- Redis 1GB
- 存储方式
Redis为什么能这么快,原因是什么?
- 纯内存操作
- 单线程,避免了不必要的上下文切换和竞争条件
- 使用多路I/O复用模型,io阻塞机制
- 高效的数据结构
- 合理的数据编码
- 其他方面的优化
Redis 持久化机制?
- RDB 持久化
- 将某个时间点的所有数据都存放到硬盘上。可以将快照复制到其它服务器从而创建具有相同数据的服务器副本。如果系统发生故障,将会丢失最后一次创建快照之后的数据。如果数据量很大,保存快照的时间会很长。
- AOF 持久化
- 将写命令添加到 AOF 文件(Append Only File)的末尾。使用 AOF 持久化需要设置同步选项,从而确保写命令同步到磁盘文件上的时机。这是因为对文件进行写入并不会马上将内容同步到磁盘上,而是先存储到缓冲区,然后由操作系统决定什么时候同步到磁盘。有以下同步选项:
- 选项同步频率always每个写命令都同步everysec每秒同步一次no让操作系统来决定何时同步
- always 选项会严重减低服务器的性能;
- everysec 选项比较合适,可以保证系统崩溃时只会丢失一秒左右的数据,并且 Redis 每秒执行一次同步对服务器性能几乎没有任何影响;
- no 选项并不能给服务器性能带来多大的提升,而且也会增加系统崩溃时数据丢失的数量
- 随着服务器写请求的增多,AOF 文件会越来越大。Redis 提供了一种将 AOF 重写的特性,能够去除 AOF 文件中的冗余写命令。
Redis的同步机制
主从同步。第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。缓存穿透、缓存击穿、缓存雪崩
- 缓存穿透:就是客户持续向服务器发起对不存在服务器中数据的请求。客户先在Redis中查询,查询不到后去数据库中查询。
- 缓存击穿:就是一个很热门的数据,突然失效,大量请求到服务器数据库中
- 缓存雪崩:就是大量数据同一时间失效。
解决办法。
- 缓存穿透:
- 接口层增加校验,对传参进行个校验,比如说我们的id是从1开始的,那么id<=0的直接拦截;
- 缓存中取不到的数据,在数据库中也没有取到,这时可以将key-value对写为key-null,这样可以防止攻击用户反复用同一个id暴力攻击
缓存击穿:最好的办法就是设置热点数据永不过期
缓存雪崩:
- 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
- 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
支持的数据类型?
- String(字符串)(键值对)
- List(列表)(双向链表)
- Hash(字典)(HashMap)
- Set(集合)(value永远为null的HashMap)
- Sorted Set(有序集合)(HashMap和跳跃表(SkipList))
应用场景
缓存
计数器 INCRBY
队列 PUB/SUB
分布式锁
最新列表 List LPUSH
排行榜 SortedSet ZADD
好友关系,利用集合的一些命令,比如求交集、并集、差集等。可以方便搞定
Redis如何一次执行多条指令,节约网络、提升吞吐量?
使用pipeline,将请求合并成一次IO
- 优点:降低延迟,提升系统吞吐量
- 缺点:需要等待所有指令执行完毕后才能返回结果/无法提供原子性保证
- Redis事务
- MULTI 开始事务
- EXEC 执行事务队列
- DISCARD 取消事务
- WATCH 监控键
- UNWATCH 取消监控键
- 事务提供了一种将多个命令打包,然后一次性、有序地执行的机制;
- 多个命令会被人队到事务队列中, 然后按先进先出(FIFO)的顺序执行;
- 事务在执行过程中不会被中断,当事务队列中的所有命令都被执行完毕之后,事务才会结束;
- 带有WATCH命令的事务会将客户端和被监视的键在数据库的watched_keys字典关联,当键被修改时,程序会将所有监视被修改键的客户端的REDIS_DIRTY_CAS标识打开,服务只有在REDIS_DIRTY_CAS标识没有打开时,才会执行客户端提交的事务,否则服务器拒绝执行事务;
- redis事务不支持回滚机制;
- Redis的事务总是具有ACID中的原子性、一致性和隔离性,当服务器运行在AOF持久化模式下,并且appendfsync选项的值为always时,事务也具有耐久性.
kafka
- kafka基本概念
- Broker
消息队列中常用的概念,在Kafka中指部署了Kafka实例的服务器节点。 - Topic
用来区分不同类型信息的主题。比如应用程序A订阅了主题t1,应用程序B订阅了主题t2而没有订阅t1,那么发送到主题t1中的数据将只能被应用程序A读到,而不会被应用程序B读到。 - Partition
每个topic可以有一个或多个partition(分区)。分区是在物理层面上的,不同的分区对应着不同的数据文件。Kafka使用分区支持物理上的并发写入和读取,从而大大提高了吞吐量。 - Record
实际写入Kafka中并可以被读取的消息记录。每个record包含了key、value和timestamp。 - Producer
生产者,用来向Kafka中发送数据(record)。 - Consumer
消费者,用来读取Kafka中的数据(record)。 - Consumer Group
一个消费者组可以包含一个或多个消费者。使用多分区+多消费者方式可以极大提高数据下游的处理速度。
- Broker
- 如何保证消息有序?
- 单分区时:
kafka本身是有序的; - 多分区时:
- 使用message key来指定消息发送到哪个分区,相同key会发送到同一个分区;
- 指定partition,将需要有序的数据指定发送到同一分区;
- 单分区时:
- 消费者异常怎么处理?
消费者采用手动提交,消费者消费成功后再commit offset,如果在处理时报异常,可以尝试固定次数,如果仍然失败,可以先将record保存到数据库中,先提交commit offset,然后再手动处理record。
docker
- ADD COPY 区别?
- ADD 可以添加 指定的文件或目录src 到 指定的文件或路径dest
- 如果 dest 以
/
结尾,默认为目录, - COPY 是 ADD 的一种简化版本,目的在于满足大多数人“复制文件到容器”的需求,没有下面两个功能。
- ADD src如果是压缩文件,会被解压到dest
- ADD src如果是url,会下载文件到dest
- CMD ENTRYPOINT 区别?
- docker镜像用什么方式创建?