- 职场最重要的几件事
- 投资最重要的事情
- 不要碰自己不懂的行业,只知道皮毛不算懂,最好自己从事什么行业,就投资这个行业的头部公司
- 如果只是投一点点钱玩玩,没必要天天看涨跌或喜或忧的,放那不动,好好工作,最后你会发现还是工作来钱快
- 因为无知,所以大家不敢重点投资一两家公司,买几个十几个股票的大有人在,因为你还不够了解,如果你足够了解市场和公司的时候就应该只投几家你足够有把我的公司然后等风来。
- 人生只需要把握一到两次重大的投资 all in进去即可翻身了,几万几千的小打小闹不会改变你的生活,如果没这个认知之前,不如好好工作赚钱买房来的实在,浅显的投资会分散你的精力
- 投资本身涉及的点不应该局限于眼前,而是未来,行业的未来,公司在这个行业所处的地位,未来几年是否有重大突破,管理层价值观你是否认可等等一系列因素,不要因为你觉得好就买了,这根赌没啥区别
- 学习方法
- 集合
- 基础
- 多线程
- JVM
- Spring
- Redis
- MySQL
- Zookeeper
- Dubbo
- RocketMQ
- 分布式锁
- 算法
- 扩展知识
- 遇到过的坑
- 有什么想问我的
- 项目
- 个人项目
- 设计方案
- HR面
职场最重要的几件事
健康工作、开心生活
工作中多和领导沟通,让对方知道你现在的困难点,疑惑点这样有利于自己的快速成长 项目遇到阻力也要第一时间表达出来,按时完成是你和领导共同的kpi 你延期了他可能比你还难受,而他不会丢饭碗,你会
确保当前做的事情是有意义的,能给自己不断带来成长的,职场前几年不要太看重钱,能力上去钱很容易就来了
跳出当前所做事情的局限,带着leader的思维去干好你每一年的工作你才有可能加速让自己成为leader
定期给自己定一些小目标,确保目标是正确的,然后拆分目标一件件落实
埋头苦干之前,先抬头看路
投资最重要的事情
不要碰自己不懂的行业,只知道皮毛不算懂,最好自己从事什么行业,就投资这个行业的头部公司
如果只是投一点点钱玩玩,没必要天天看涨跌或喜或忧的,放那不动,好好工作,最后你会发现还是工作来钱快
因为无知,所以大家不敢重点投资一两家公司,买几个十几个股票的大有人在,因为你还不够了解,如果你足够了解市场和公司的时候就应该只投几家你足够有把我的公司然后等风来。
人生只需要把握一到两次重大的投资 all in进去即可翻身了,几万几千的小打小闹不会改变你的生活,如果没这个认知之前,不如好好工作赚钱买房来的实在,浅显的投资会分散你的精力
投资本身涉及的点不应该局限于眼前,而是未来,行业的未来,公司在这个行业所处的地位,未来几年是否有重大突破,管理层价值观你是否认可等等一系列因素,不要因为你觉得好就买了,这根赌没啥区别
学习方法
我的学习方法比较简单,北极星目标,给自己定下目标之后,不断拆分 每次完成小目标就离大目标进一步
卸载掉哪些信息流软件,他们杀你时间的方式太简单粗暴了
- 我之前是大数据团队的我们会和算法有很多合作,我知道算法推荐不断完善模型背后的目的,就是杀死用户的时间
我看书学习的时候会把手机丢很远,其实也不会有什么重要的人和事情找你,不要一直看,真的着急他们会打电话的。
坚持
集合
HashMap
- 1.7
- 数组+链表
- 头插
- 1.8
- 数组+链表+红黑树
- 尾插
- 扩容机制
- LoadFactor 默认0.75
- 创建一个空数组重新Hash
- Hash公式跟长度有关
- 线程不安全
- 2的幂次
- 方便位运算
- 均匀分布
- 重写equals必须重写HashCode
ConcurrentHashMap
- 安全失败
- 1.7
- 数组+链表
- segment分段锁
- 继承了reentranLock
- 尝试获取锁存在并发竞争 自旋 阻塞
- get高效 volatile修饰 不需要加锁
- volatile修饰节点指针
- HashEntry
- 1.8
- 数组+链表+红黑树
- CAS+synchronized
- cas失败自旋保证成功
- 再失败就sync保证
- cas失败自旋保证成功
- node
ArrayList
- 数组
- 查找 访问速度快 增删效率低 线程不安全
LinkedList
- 双向链表
- 适合插入删除频繁的情况 内部维护了链表的长度
基础
UDP
- 语音
- 视频
- 直播
TCP
- 三次握手
- syn seq
- syn ack seq
- ack seq
- 为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
- 四次挥手
- fin ack seq
- ack seqfin ack seq
- ack seq
- 场景
- 网络会话
- 文件传输
- 发送接收邮件
- 远程登录
- 如何保证可靠
HTTP
HTTPS
- 为啥安全
BIO
- 阻塞等待链接
- 阻塞等待数据
- 开线程处理并发
- 耗资源
NIO
- 非阻塞IO
- epoll
粘包/拆包
- 在报文末尾增加换行符表明一条完整的消息,这样在接收端可以根据这个换行符来判断消息是否完整。将消息分为消息头、消息体。可以在消息头中声明消息的长度,根据这个长度来获取报文(比如 808 协议)。规定好报文长度,不足的空位补齐,取的时候按照长度截取即可。
多路复用
- select
- 单个进程可监视的fd数量被限制,即能监听端口的大小有限。
- 对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低:
- 需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大
- poll
- 大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义
- poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。
- epoll
- 没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口);
- 效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。
- 内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递;即epoll使用mmap减少复制开销。
neetty 非异步 阻塞 response trse id 感觉
序列化
多线程
synchronized
- 对象
- 对象头(Header)
- Mark Word(存储对象的HashCode,分代年龄和锁标志位信息。)
- Klass Point(对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。)
- Monitor
- EntryList
- Owner(会指向持有 Monitor 对象的线程)
- WaitSet
- 实例数据
- 对其填充
- 对象头(Header)
- 方法
- ACC_SYNCHRONIZED
- 代码块
- monitorenter
- monitorexit
- 程序计数器 count
- 加减
- 锁膨胀
- 无锁
- 偏向锁
- mark Word 中有线程信息 cas 比较
- 轻量级
- 复制了一份mark work 叫 Lock record 也是cas尝试改变指针
- 自旋
- 死循环
- 重量级
- 特性保证
- 有序性
- as-if-serial
- happens-before
- 可见性
- 内存强制刷新
- 原子性
- 单一线程持有
- 可重入性
- 计数器
- 有序性
- 重锁
- 用户态内核态切换
- sync 和 Lock的区别
- synchronized是关键字,是JVM层面的底层啥都帮我们做了,而Lock是一个接口,是JDK层面的有丰富的API。synchronized会自动释放锁,而Lock必须手动释放锁。synchronized是不可中断的,Lock可以中断也可以不中断。通过Lock可以知道线程有没有拿到锁,而synchronized不能。synchronized能锁住方法和代码块,而Lock只能锁住代码块。Lock可以使用读锁提高多线程读效率。synchronized是非公平锁,ReentrantLock可以控制是否是公平锁。
- 劣势
- 锁升级不可逆
ThreadLocal
- 内存泄露
- session
Lock
- ReentrantReadWriteLock
- ReadLock
- WriteLock
- ReentrantLock
- NonfairSync
- tryAcquire
- acquireQueued
- CAS
- FairSync
- hasQueuedPredecessors
- 如果是当前持有锁的线程 可重入
- AbstractQueuedSynchronizer
- 入队 出队
- 头结点设计
- 共享和独享的实现
- CAS
- 实际应用
- 存在的问题
- cpu开销
- 只能保证一个共享变量原子操作
- AtomicReference
- ABA
- 标志位 时间戳
- NonfairSync
- StampedLock
volatile
- MESI
- 当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取
- 锁bus
- volitale会一直嗅探 cas 不断循环无效交互 导致带宽达到峰值
- 总线风暴
- Java内存模型JMM
- 高速缓存
- 可见性
- 嗅探机制 强制失效
- 处理器嗅探总线
- 嗅探机制 强制失效
- 有序性
- 禁止指令重排序
- lock 前缀指令 内存屏障
- 源代码->编译器优化重排序->指令级并行重排序->内存系统重排序->最终执行的指令序列
- lock 前缀指令 内存屏障
- happens-before
- volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。
- as-if-serial
- 禁止指令重排序
- AtomicInteger
- 跳出死循环
线程池
- newFixedThreadPool
- newCacheThreadPool
- SynchronousQueue
- newSIngleTheadExecutor
- newScheduledThewadPool
- DelayedWorkQueue
- newWorkStealingPool
- ThreadPoolExecutor
- 参数意义
- 核心线程数
- 默认没线程等任务来了才调用 除非调用了 预创建线程 一个或者全部
- 最大线程数
- 空闲时间&单位
- 没有执行任务多久会终止 当线程池的线程数大于核心线程才会起作用 调用allowCoreThreadTimeOut会起作用
- 缓冲队列
- LinkedBlockingQueue
- 无界 当心内存溢出
- ArrayBlockingQueue
- 有界队列
- 加锁保证安全 一直死循环阻塞 队列不满就唤醒
- 入队
- 阻塞调用方式 put(e)或 offer(e, timeout, unit)阻塞调用时,唤醒条件为超时或者队列非满(因此,要求在出队时,要发起一个唤醒操作)进队成功之后,执行notEmpty.signal()唤起被阻塞的出队线程
- 在进行某项业务存储操作时,建议采用offer进行添加,可及时获取boolean进行判断,如用put要考虑阻塞情况(队列的出队操作慢于进队操作),资源占用。
- Synchronous
- LinkedBlockingQueue
- 工厂方法
- 拒绝策略
- 抛异常
- 丢弃
- 重试
- 丢弃最早提交的
- 使用Has表维护线程的引用
- submit
- 使用future获取任务的执行结果
- 核心线程数
- 实际使用
- 商品详情界面
- 批处理
- 执行过程
- 核心线程->队列->最大线程->拒绝策略
- 运行状态
- 有个Volatile的状态码
- running
- shutdown
- stop
- terminated
- 所有线程销毁
- corePoolSize、maximumPoolSize、largestPoolSize 有意思
- 有个Volatile的状态码
- 故障
JUC
常见问题
- 线程间是怎么进行通信的?
- 主要可以介绍一下 wait/notify 机制,共享变量的 synchronized 或者 Lock 同步机制等。
- volatile
- CountDownLatch
- CyclicBarrier
- ThreadLocal 用来解决什么问题?
- 可以从尽量减少临界区范围,使用 ThreadLocal,减少线程切换、使用读写锁或 copyonwrite 等机制这些方面来回答。
- 如何尽可能提高多线程并发性能?
- ThreadLocal 是如何实现的?可以重点回答 ThreadLocal 不是用来解决多线程共享变量的问题,而是用来解决线程数据隔离
- 读写锁适用于什么场景?
- 可以回答读写锁适合读并发多,写并发少的场景,另外一个解决这种场景的方法是 copyonwrite。
- 如何实现一个生产者与消费者模型?
- 可以尝试通过锁、信号量、线程通信、阻塞队列等不同方式实现。
线程状态
- 线程就绪
- start
- sleep休眠超时
countDownLatch
- 只有一个构造方法 只会被赋值一次
- 没有别的方法可以修改 count
JVM
JVM内存模型
- 堆
- 栈
- 方法区
- 本地方法栈
- 程序计数器
类加载机制
- 加载->验证->准备->解析->初始化->使用->卸载
- 双亲委派原则
- 父类加载 不重复加载
分代回收
- 年轻代
- Eden/s1/s2
- 老年代
- 永久代/元空间
- 晋升机制
- 根据存活时间
垃圾回收机制
- 标记清除
- 适用场景
- 对象存活比较多的时候适用
- 老年代
- 缺点
- 提前GC
- 碎片空间
- 扫描了两次
- 标记存活对象
- 清除没有标记的对象
- 适用场景
- 标记复制
- 适合场景
- 存活对象少 比较高效
- 扫描了整个空间(标记存活对象并复制异动)
- 适合年轻代
- 缺点
- 需要空闲空间
- 需要复制移动对象
- 适合场景
- 引用计数
- 没办法解决循环引用的问题
- 标记整理
垃圾回收器
- CMS
- 分代
- 年轻
- edan
- s1
- s2
- minor gc
- 通过阈值晋升
- 老年
- major gc 等价于 full gc
- 永久
- 年轻
- 缺点
- 对cpu资源敏感
- 无法处理浮动垃圾
- 基于标记清除算法 大量空间碎片
- 分代
- G1
- 分区概念 弱化分代
- 标记整理算法 不会产生空间碎片 分配大对象不会提前full gc
- 可以设置预设停顿时间
- 充分利用cpu 多核条件下 缩短stw
- 收集步骤
- 初始标记 stw 从gc root 开始直接可达的对象
- 并发标记 gc root 对对象进行可达性分析 找出存活对象
- 可达性分析算法
- 最终标记
- 筛选回收
- 根据用户期待的gc停顿时间指定回收计划
- 回收模式
- young gc
- 回收所有的eden s区
- 复制一些存活对象到old区s区
- 回收所有的eden s区
- mixed gc
- young gc
- GC模式
- 区别
- g1分区域 每个区域是有老年代概念的 但是收集器以整个区域为单位收集
- g1回收后马上合并空闲内存 cms 在stw的时候做
- 内存区域设置
- XX:G1HeapRegionSize
- 复制成活对象到一个区域 暂停所有线程
full gc
- 老年代写满
- system。gc
- 持久代空间不足
STW
实战
- 性能调优
- 设置堆的最大最小值 -xms -xmx
- 调整老年和年轻代的比例
- -XX:newSize设置绝对大小
- 防止年轻代堆收缩:老年代同理
- -XX:newSize设置绝对大小
- 主要看是否存在更多持久对象和临时对象
- 观察一段时间 看峰值老年代如何 不影响gc就加大年轻代
- 配置好的机器可以用 并发收集算法
- 每个线程默认会开启1M的堆栈 存放栈帧 调用参数 局部变量 太大了 500k够了
- 原则 就是减少gc stw
- FullGC 内存泄露排查
- jasvism
- dump
- 监控配置 自动dump
oom种类
逃逸分析
可达性
- 虚拟机栈(栈帧中的本地变量表)中引用的对象方法区中类静态属性引用的对象方法区中常量变量引用的对象本地方法栈中JNI(即一般说的Native方法)引用的对象活跃线程的引用对象
JVM调优
- OOM
- 内存泄露
- 线程死锁
- 锁争用
- Java进程消耗CPU过高
JVM性能检测工具
- Jconsole
- Jprofiler
- jvisualvm
- MAT
内存泄露
- help dump
- 生产机 dump
- mat
- jmap
- -helpdump
CPU100%
- topc -c
- top -Hp pid
- jstack
- 进制转换
- cat
Spring
设计模式
- 单例
- 工厂
- 适配器
- 根据不同商家适配
- 责任链
- 继承 process 链路执行
源码
Bean
- 生命周期
- 扫描类
- invokeBeanFactoryPostProcessors
- 封装beanDefinition对象 各种信息
- 放到map
- 遍历map
- 验证
- 能不能实例化 需要实例化么 根据信息来
- 是否单例等等
- 判断是不是factory bean
- 单例池 只是一个ConcurrentHashMap而已
- 正在创建的 容器
- 得到 class
- 推断构造方法
- 根据注入模型
- 默认
- 得到构造方法
- 反射 实例化这个对象
- 后置处理器合并beanDefinition
- 判断是否允许 循环依赖
- 提前暴露bean工厂对象
- 填充属性
- 自动注入
- 执行部分 aware 接口
- 继续执行部分 aware 接口 生命周期回调方法
- 完成代理AOP
- beanProstprocessor 的前置方法
- 实例化为bean
- 放到单例池
- 销毁
- 扫描类
- 作用域
- 单例(singleton)
- 多例(prototype)
- Request
- Session
循环依赖
- 情况
- 属性注入可以破解
- 构造器不行
- 三级缓存没自己 因二级之后去加载B了
- 三级缓存
- 去单例池拿
- 判断是不是正在被创建的
- 判断是否 支持循环依赖
- 二级缓存 放到 三级缓存
- 干掉二级缓存
- GC
- 下次再来直接 三级缓存拿 缓存
- 缓存 存放
- 一级缓存 单例Bean
- 二级缓存 工厂 产生baen
- 产生bean 复杂
- 三级缓存 半成品
父子容器
事务实现原理
- 采用不同的连接器
- 用AOP 新建立了一个 链接
- 共享链接
- ThreadLocal 当前事务
- 前提是 关闭AutoCommit
AOP
- 静态代理
- 实现类
- 动态代理
- JDK动态代理
- 实现接口
- java反射机制生成一个代理接口的匿名类
- 调用具体方法的时候调用invokeHandler
- java反射机制生成一个代理接口的匿名类
- 实现接口
- cjlib
- asm字节码编辑技术动态创建类 基于classLoad装载
- 修改字节码生成子类去处理
- asm字节码编辑技术动态创建类 基于classLoad装载
- JDK动态代理
IOC
类加载机制
- 过程
- 加载
- 生成一个class对象
- 验证
- 文件格式验证
- 元数据验证
- 字节码验证
- 符号引用验证
- 准备
- 默认值
- static会分配内存
- 解析
- 解析具体类的信息
- 引用等
- 解析具体类的信息
- 初始化
- 父类没初始化 先初始化父类
- 使用
- 卸载
- 加载
- 加载方式
- main()
- class。forName
- ClassLoader。loadClass
- 类加载器
- Appclass Loade
- Extention ClassLoader
- Bootstrap ClassLoader
- 双亲委派原则
- 可以避免重复加载
- 安全
Redis
数据结构
- String
- Hash
- set
- zset
- score
- 随机层数
- 只需要调整前后节点指针
- 不止比较score
- 还会比较value
- 场景
- 成绩
- 积分
- 排行榜
- List
- 分页的坑
- HyperLogLog
- Geo
- Pub/Sub
- BitMap
- 底层
- SDS
- 键值的底层都是SDS
- AOF缓存区
- 记录本身长度 C需要遍历
- 修改字符减少内存重新分配
- 空间预支配
- 惰性空间释放
- 二进制安全
- C只能保存文本数据 无法保存图片等二进制数据
- sds是使用长度去判断
- 杜绝缓冲区溢出
- 兼容部分C字符串函数
- 链表
- 保存多个客户端的状态信息
- 列表订阅发布 慢查询 监视器
- 字典
- 数据库 哈希键
- Hash表节点
- hash冲突用单向链表解决
- 渐进式 rehash
- 会逐渐rehash 新的键值对全部放到新的hash表
- 每个字典带 两个hash表
- 一个平时用 一个rehash时候用
- 压缩列表
- 整数集合
- SDS
常见命令
- Keys
- setnx
- exprie
高可用
- 持久化
- RDB
- 5分钟一次
- 冷备
- 恢复的时候比较快
- 快照文件生成时间久,消耗cpu
- AOF
- appendOnly
- 数据齐全
- 回复慢文件大
- 数据初始化
- 从节点发送命令主节点做bgsave同时开启buffer
- RDB
- 数据同步机制
- 主从同步
- 指令流
- offset
- 指令流
- 快照同步
- RDB
- 缓冲区
- RDB
- 主从同步
- 哨兵
- 集群监控
- 消息通知
- 故障转移
- 配置中心
- 脑裂
- 集群
- 链表
- 多主
- 横向扩容
- 分片
常见问题
- 缓存雪崩
- 加随机值
- 集群部署
- 缓存击穿
- 互斥锁
- 热点数据不失效
- 缓存穿透
- 布隆过滤器
- 双写一致性
- 延时双删
- 并发竞争
- 分布式锁
- 大Key
- bigkey命令 找到干掉
- Redis 4.0引入了memory usage命令和lazyfree机制
- 热点key
- 缓存时间不失效
- 多级缓存
- 布隆过滤器
- 读写分离
过期策略
- 定时删除
- 消耗内存
- 创建一个定时器
- 消耗内存
- 惰性删除
- 可能存在大量key
- 定期删除
- 检查 删除 但是是随机的
淘汰机制
- LUR
- 最少使用
备用方案
- 主从+哨兵+cluster
- ecache+Hystrix+降级+熔断+隔离
- 持久化
限流
- setnx ex
- zset
- 窗口滑动
- zset会越来越大
- 令牌
- 定时push
- 然后leftpop
- 问题
- 空轮训
- blpop
- 空连接异常
- 重试
- 空连接异常
- blpop
- 空轮训
- 漏桶 funnel
- make_space 灌水之前调用漏水 腾出空间 取决于流水速率
- Hash
- 原子性有问题
- Redis-Cell
- 原子性有问题
- Hash
- make_space 灌水之前调用漏水 腾出空间 取决于流水速率
- redis cell
选择方案
- 热点key
- 二级缓存
- 备份热key 走不同的机器
扩展
- 跳跃表
- 令牌
- 漏桶
- scan
多路IO复用
- read得读到很多才返回 为0会卡在那 直到新数据来或者链接关闭
- 写不会阻塞除非缓冲区满了
- 非阻塞的IO 提供了一个选项 no_blocking 读写都不会阻塞 读多少写多少 取决于内核的套接字字节分配
- 非阻塞IO也有问题 线程要读数据 读了一点就返回了 线程什么时候知道继续读?写一样
- 一般都是select解决 但是性能低 现在都是epoll
MySQL
分库分表
- 唯一主键
事务隔离级别
- 读未提交
- 没视图概念 都是返回最新的
- 读已提交
- 不同的read view
- 可重复度
- 用一个read view
- 序列化
- 回滚日志
- 没更早的read view删除
- 5.5之前回滚段删了文件也不会变小
- 没更早的read view删除
索引
- B+
- Hash
- 等值查询
- 优化流程
- 预发跑sql explain
- 排除 缓存 sql nocache
- 看一下行数对不对 不对可以用analyze table t 矫正
- 添加索引 索引不一定是最优的 force index 强制走索引 不建议用
- 存在回表的情况
- 覆盖索引避免回表,不要*
- 主键索引
- 联合索引 不能无限建 高频场景
- 最左前缀原则 按照索引定义的字段顺序写sql
- 合理安排联合索引的顺序
- 5.6之后 索引下推 减少回表次数
- 给字符串加索引
- 前缀索引
- 倒序存储
- Hash
- 数据库的flush的时机
- redo log满了 修改checkpoint flush到磁盘
- 系统内存不足淘汰数据页
- buffer pool
- 要知道磁盘的io能力 设置innodb_io_capacity 设置为磁盘的IOPS fio测试
- innodb_io_capacity设置低了 会让innoDB错误估算系统能力 导致脏页累积
- buffer pool
- 系统空闲的时候 找间隙刷脏页
- MySQL正常关闭,会把内存脏页flush到磁盘
- innodb刷盘速度
- 脏页比例
- redolog 写盘速度
- innodb_flush_neighbors 0
- 机械磁盘的随机io不太行 减少随机io性能大幅提升 设置为 1最好
- 现在都是ssd了 设置为0就够了 8.0之后默认是0
- 索引字段不要做函数操作,会破坏索引值的有序性,优化器会放弃走树结构
- 如果触发隐式转换 那也会走cast函数 会放弃走索引
- 字符集不同可能走不上索引
- convert 也是函数所以走不上
- 聚集索引
- 非聚集索引
- 多扫描一次
- 减少回表
- 多扫描一次
- 索引维护
- 页满了 页分裂 页利用率下降
- 数据删除 页合并
- 自增 只追加可以不考虑 也分页
- 索引长度
- 索引选择
- 普通索引
- 找到第一个之后 直到朋友不满足的
- 唯一索引
- 找到第一个不满足的就停止了
- 覆盖索引
- 包含主键索引值
- 最左前缀原则
- 安排字段顺序
- 索引空间问题
- hash
- 5.6之后索引下推
- 不需要多个回表 一边遍历 一边判断
- 页的概念
- 更新
- change buffer
- 更新操作来了 如果数据页不在内存 就缓存下来 下次来了 更新 在就直接更新
- 唯一索引 需要判断 所以 用不到change buffer
- innodb的处理流程
- 记录在页内存
- 唯一索引 判断没冲突插入
- 普通索引 插入
- 记录不再页中
- 数据页读入内存 判断 插入
- change buffer
- 数据读是随机IO 成本高
- 机械硬盘 change buffer 收益大 写多读少 marge
- 记录在页内存
- 普通索引
MVCC
- 版本链 在聚集索引中 有两个隐藏列 trx_id roll_pointer
- 读未提交
- 直接读取最新版本
- 序列化
- 加锁
- Read View
- 读已提交
- 每次读取前生成一个
- 可重复度
- 第一次生成一个
- 读已提交
锁
- 全局锁
- 全库逻辑备份
- 表锁
- lock table read/write
- MDL(metadata lock)
- MySQL5.5引入 自动添加 读锁不互斥 写锁互斥
- 多个事务之前操作,如果查询的时候修改字段容易让线程池饱满
- MySQL的information_schema 库的 innodb_trx 表 找到对应长事务 kill掉
- alter table里面设定等待时间
- Myisam是不支持表锁的
- 行锁
- 需要的时候才加上 并不是马上释放 等事务结束才释放 两阶段锁协议
- 死锁
- 超时时间
- innodb_lock_wait_timeout
- 默认是50s太久 但是如果设置太短会误判 一般采用死锁监测
- innodb_lock_wait_timeout
- 死锁机制 事务回滚
- innodb_deadlock_detect = on
- 超时时间
- 热点行
- 死锁消耗CPU
- 临时关闭
- 关掉死锁会出现大量重试
- 临时关闭
- 控制并发度
- 更多的机器 开启比较少的线程 消耗就少了
- 分治
- 死锁消耗CPU
- 间隙锁
- 读写锁
- 读
- lock in share mode
- for update
- 行锁
- 写
- 读
- innodb如何加锁
- Record lock: 对索引项加锁。Gap lock:对索引项之间的‘间隙’,第一条记录前的间隙,或最后一条记录后的间隙 加锁Next-Key:前两种的组合,对记录及前面的间隙加锁
B+
log
- undo log
- 回滚 mvcc
- redo log
- 物理日志 内存操作记录
- sync_binlog 可以优化日志写入时机
- 物理日志 内存操作记录
- binlog
- 组提交机制,可以大幅度降低磁盘的IOPS消耗。
- 两段式提交 redo 准备 binglog 提交
count1 *
- mvcc影响
主备延迟
- 强制走主
- sleep
join
- 驱动表
id用完
- bigint
- row_id 没设置主键的时候
- thread_id
mysql io性能瓶颈
- 设置 binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count参数,减少binlog的写盘次数。这个方法是基于“额外的故意等待”来实现的,因此可能会增加语句的响应时间,但没有丢失数据的风险。将sync_binlog 设置为大于1的值(比较常见是100~1000)。这样做的风险是,主机掉电时会丢binlog日志。将innodb_flush_log_at_trx_commit设置为2。这样做的风险是,主机掉电的时候会丢数据。
常见命令
- show processlist
- 查看空闲忙碌链接
- wait_timeout
- 客户端空闲时间
- 定时断开链接
- mysql_reset_connection 恢复链接状态
- 客户端空闲时间
- innodb_flush_log_at_trx_commit
- redolog事务持久化
- sync_binlog
- binlog事务持久化
真实故障
- 数据库挂了 show processlist 一千个查询在等待 有个超长sql kill 但是不会引起flush table 周末 优化脚本 analyze 会导致 MySQL 监测到对应的table 做了修改 必须flush close reopen 就不会释放表的占用了
Zookeeper
选举机制
过半机制
预提交 ack 2pc
ZAB协议?
zk节点宕机如何处理?
如何实现分布式一致性
Dubbo
Netty
- 零拷贝
- bio
- 阻塞IO 读写都阻塞
- 问题 带宽 资源等
- 每个请求过来 开一个线程阻塞
- nio
- 不阻塞来着不拒
- 但是可能等待时间太久 响应延迟大了 太短了 会重试
- IO多路复用
- 便捷的通知机制
- 程序注册一组socket文件描述符给操作系统,表示“我要监视这些fd是否有IO事件发生,有了就告诉程序处理”
- 便捷的通知机制
- select
- 遍历 判断事件是否可达 然后继续
- poll
- 做了优化
- epoll
- 有转态 会创建 文件描述符指向的表 监听增删改查
- IO多路复用
- 通道 buffer 多路复用
- 监听事件
- aio
- 架构设计思路
- 执行链路
- 初始化channel
- 注册 channel到selector
- 任务队列
- 轮训accept事件 处理这些简历 channel的链接
- 注册 channel到selector 接收方
- 轮训写 事件 开线程去处理
- 任务队列
- 线程组
- boss
- 监听端口所有准备就绪的时间
- work
- 监听准备工作
- boss
调用链路
服务暴露过程
- IOC 启动加载dubbo配置的标签
- 解析标签 ServiceBean 会生成一个Bean
- 实现了 initializingBean
- afterpropertiesSet
- get provider
- set provider
- 各种信息 保存在 ServiceBean
- afterpropertiesSet
- IOC完成 还实现了一个 ApplicationListener监听器
- 回调onapplicationEvent
- 是否暴露 不是延迟暴露
- 回调onapplicationEvent
- 暴露
- 信息校验 doexport
- 检查
- doexportURL 暴露URL
- 加载注册中心信息
- 循环协议 端口
- 代理工厂获取invoke 封装
- 暴露invoke
- 根据spi来
- 本地暴露
- 打开 服务器 exchangeServer
- 启动服务器netty 监听端口
- 注册中心 注册服务
- 注册表
- 执行器
- 注册表
- 暴露 p 和 s 两个invoker的map保存了地址
- spi
- 暴露invoke
- 代理工厂获取invoke 封装
- 信息校验 doexport
服务引用
- factoryBean ->getObject ->get
- init
- 信息检查
- 创建代理对象 createProxy
- 远程引用 获取到zk 获取到信息 订阅
- dubbo 执行远程引用
- 创建 netty客户端
- 返回invoke
- 注册到注册表进去
- 返回invoke
- 成功
SPI
- java spi
- Java 没ioc aop
- 具体的spi kv形式
- 静态代理
容错机制
- failover
- 直接切换
- failfast
- 快速失败
- failsafe
- failback
- forking cluster
- broadcast cluster
- 整合 hystrix
- 失败回调
- 返回默认
降级
- return null
- 失败返回空
负载均衡
- 随机 加权
- 轮训
- 最少活跃数
- hash一致
选举算法
注册中心
协议
- dubbo
- 默认 nio 单一长连接
- 二进制系列化 小数据量 100k
- 数据量中等 不适合文件传输
- memcached
- redis
- webService
- http
RocketMQ
基础组成
- NameServer
- 无状态模式
- broker向发心跳顺便带上所有的Topic信息
- 早期是zk后来改了
- Broker
- 中转消息,消息持久化
- 底层通信基于Netty
- Producer
- 同步
- 异步
- 单向
- Consumer
- pull
- push
支持集群模式
- 多master
- 多master多slave异步复制
- 多master多slave双写
消费保证
- 发送成功后返回consume_success
- 回溯消费
高可用
- 集群
- NameService 集群
- Broker 主从 双主 双从
- Consumer 自动切换
- producer 链接两个Broker
- 刷盘
- 同步 超时会返回错误
- 异步 不返回
- 消息的主从复制
- 同步复制
- 异步复制
- 主从同步 异步刷盘
顺序消息
- Hash取模
- RocketMQ提供了MessageQueueSelector队列选择机制
- 顺序发送 顺序消费由 消费者保证
- 消费者是多线程
- 顺序发送 顺序消费由 消费者保证
- RocketMQ提供了MessageQueueSelector队列选择机制
消息去重
- 幂等
- 去重
- 消息表主键冲突
分布式事务
- 最大努力
- 消息表 不断轮训 人工干预
- 半消息
- 发送半消息 发送成功 本地事务 觉得是否提交还是回滚 服务端没收到回查 检查本地事务 根据本地事务决定 提交
- 2/3pc
- 最终一致
- 预发 持久化 返回状态 发送处理结果 判断是否干掉持久化的 发送
完整的一个调用链路
- producer 和NameService 节点建立一个长连接
- 定期从NameService获取Topic信息
- 并且向Broker Master 建立链接 发送心跳
- 发送消息给 Broker Master
- consumer 从 Mater 和 Slave 一起订阅消息
消息重试
- 顺序消息重试
- 不断重试 16次 4小时46分钟 可以修改尝试次数
- 对一个消费者设置 组内都会设置
- 可以获取消息重试次数
- 无序消息重试
死信队列
- 不再被正常消费
- 保存3天
- 面向消费者组
- 控制台 重发 重写消费者 单独消费
事务消息
消息丢失
消息积压
- 决定是否丢弃
- 判断吞吐量
- 停止消费 加机器 加topic
分布式锁
Zookeeper
- 死锁
- 羊群效应
- 临时节点顺序
- 性能没redis高
Redis
- jedis.set(String key, String value, String nxxx, String expx, int time)
- 性能比较高
数据库
- 死锁
- 设置一个失效时间用定时任务去跑
- 数据库集群 主备同步
- 搞个死循环排队
- 可重入设计一个字段累加
- 排它锁
- 用数据库自身的锁就可以了 行锁 索引
- select XX for update
- 记得 提交
- 宕机数据库也会自动释放锁
- 缺点
- 比其他的更消耗资源
- 复杂
特点
- 互斥
- 安全性
- 死锁
- 容错
算法
贪心
分治
动态规划
快排
堆排
二叉树
链表反转
成环
环节点
跳楼梯
扩展知识
内存屏障
指令乱序
分支预测
NUMA
CPU亲和性
遇到过的坑
sync遇到了bgsave
- CPU彪升
- bgsave之后会做一个emptyDB
- 这个时候做bgsave cow的机制就没了
- 会重新加载整个RDB
- 然后就swap
- 会重新加载整个RDB
- 这个时候做bgsave cow的机制就没了
- bgsave之后会做一个emptyDB
高并发场景下无限同步
- tps过高的时候
- master 复制缓存挤压区的时候 有个参数client-output-buffer-limit 默认1M
- 大量请求会让值升高 超出阈值断开
- 重连
- 大量请求会让值升高 超出阈值断开
- master 复制缓存挤压区的时候 有个参数client-output-buffer-limit 默认1M
slave做RDB同步的时候会导致TPS过高无法加载
- 阻塞久了复制缓冲区的数据就被冲掉了,是个队列会踢掉之前的数据
- slave重连对比offset发现空档重新sync
- 预估体量参数动态调整
- slave重连对比offset发现空档重新sync
canal 并发修改
es 自动机构建
redis es 深分页
实在没有可以去网上找找 但是得记熟悉
有什么想问我的
我的回答有什么建议么
阿里的解决方案
团队主要做的事情
项目
一定要有核心亮点
- 并发 多线程
- 业务亮点
- 技术亮点
- 比如我自己之前做的一些中间件改造优化
- 大数据底层优化 融合改造
突出你在项目中做的事情和收获
- 可以是业务上的也可以技术上的
- 最好让对方看到你在团队视角的视野和格局,而不是局限于一个coder
一定要对你简历上的每一个细节都了如指掌
个人项目
全局报警
分布式事务组件
- 拦截spring事务
设计方案
高并发下单
订单生成
HR面
为什么换工作
- 想去XX
- 成长受限
- 薪资
- 个人原因
- 渴望大平台