服务端备忘

消息队列

  1. kafka

  • 核心概念:
    Broker:服务器节点为broker
    Topic:消息类别
    Partition:一个Topic分隔为1个或多个Partition,单个Partition中是有序的,如果需要保证topic有序需要将partition设置为1
    Producer:
    Consumer:
    Counsumer Group: 消费者再平衡rebalance,将分区分配给对应的消费者。一个分区对于同一个消费组只对应一个消费者,但是可以对应多个不同消费组的消费者
    Leader:
    Follwer:

  • kafka使用Zookeeper来做协调服务,controller来负责partition的分配和leader选举

  • ISR: in sync replicas 同步副本

  • AR: assigned replicas

  • OSR: out sync replicas

  • AR = ISR + OSR

  • 顺序写,

  • 零拷贝

  • mmap

  • 多副本同步, 集群拓展,高可用

  • partition分区数决定了同组消费者个数的上限

  • 消费组保存了offset
    Kafka的分区数和消费者个数
    参考

   spring.kafka.producer.acks取值:
   - acks=0 生产者不会等待来自服务器的任何确认,该记录将立即添加到套接字缓冲区并视为已发送,这种情况下,无法保证服务器已经收到记录,并且重试配置也不会生效(因为客户端通常不会知道任何故障)
   - acks=1 这意味着leader会将记录写入本地日志,但无需等待所有副本服务器的完全确认即可做出回应,在这种情况下,如果leader在确认记录后立即失败,但在将数据复制到所有副本服务器之前,则记录将会丢失
   - acks=all 这意味着leader将等待完整的同步副本集以确认记录,这保证了只要至少一个副本服务器任然存活就不会丢失,这是最强有力的保证,相当于acks=-1的设置

kafka消费模式
AbstractMessageListenerContainer.AckMode的枚举中定义

  • MANUAL
  • MANUAL_IMMEDIATE
  • RECORD
  • TIME
  • COUNT

kafka高可用
20道经典的Kafka面试题详解
kafka面试题
kafka为什么这么快
kafka&RocketMq顺序消费
kafka集成springboot
kafka集成springcloud todo

kafka的文件系统结构设计:


文件系统结构设计
  1. RocketMQ

Broker: 集群中的节点
NameServer:无状态节点,集群部署,节点之间无信息同步,主要是维护Broker的信息,Topic信息,broker会定时发送心跳信息到NameServer
Topic:主题
Tag:标签
Queue:队列,一个topic会对应多个Queue,顺序消息的话需要设置为顺序消费,发送时通过队列选择器将数据发送到同一个队列

事务消息: 流程: 
1.发送half消息 
2.执行本地事务 
3.根据本地事务成功或者失败发送状态 
4.如果因为网络等其他因素没有收到事务执行的状态,mq服务端通过回查接口获取事务的执行状态



RocketMQ架构设计图


架构设计图

参考


MySQL

1.数据库分表分库,shardingjdbc 
  概念:1.逻辑表  2.广播表 
2.mvcc机制  multi version concurrency control 
3.索引底层数据结构
  b+树,b树
4.redolog undolog
5.事务隔离级别
  读未提交 Read Uncommitted
  读已提交 Read Committed
  可重复读-mysql默认隔离级别 Repeatable Read
  串行化 Serial
6.锁机制
  间隙锁,可重复读机制下的锁机制,主键命中记录为行锁,否则锁区间
  行锁
  表锁
7.索引失效情况
8.物理结构 最小的存储单位是页
9.索引分类
  1.聚族索引 2.非聚族索引  
MVCC
  • trx_id: 事务id,递增的
  • roll_pointer 回滚指针,指向undolog中的上一个版本的位置
  • 可重复读Repeatable Read和读已提交Read Committed隔离级别下的实现
  • ReadView: 读视图,RR在第一次select时生成ReadView,RC在每次select是都会生成一个新的ReadView
  • 参考
间隙锁
  • 记录锁、间隙锁、临键锁,都属于排它锁;
  • 记录锁就是锁住一行记录;
  • 间隙锁只有在事务隔离级别 RR 中才会产生;
  • 唯一索引只有锁住多条记录或者一条不存在的记录的时候,才会产生间隙锁,指定给某条存在的记录加锁的时候,只会加记录锁,不会产生间隙锁;
  • 普通索引不管是锁住单条,还是多条记录,都会产生间隙锁;
    间隙锁会封锁该条记录相邻两个键之间的空白区域,防止其它事务在这个区域内插入、修改、删除数据,这是为了防止出现 幻读 现象;
  • 普通索引的间隙,优先以普通索引排序,然后再根据主键索引排序(多普通索引情况还未研究);
  • 事务级别是RC(读已提交)级别的话,间隙锁将会失效
  • 参考
  • MySQL加锁问题
索引失效情况
  • 查询条件 or ,not in ,<> ,is null, is not null
  • 隐式类型转换(不同的字符集或者不同的数据类型)
  • like查询非前缀匹配
  • 复合索引没有用左列字段
  • 对where字段进行函数操作
  • 参考

分表分库
shardingjdbc实战
京东shardingjdbc
shardingjdbc实战问题分析
shardingjdbc


redis

1.数据结构
  String
  Hash
  BitMap
  List
    可靠队列。RPOPLPUSH,LREM
  Set
  ZSet skipList跳表
  Geo
  Pub-sub

  jedis,lettuces
2.redis的持久化机制
  RDB:快照,会有丢失情况
  AOF:写命令的日志追加,文件过大
3.内存淘汰策略
  内存淘汰机制:
     A:定时删除,在设置了过期时间的key中随机抽取一部分,将过期的删除掉,如果过期的比例达到一定值则继续此动作
     B:惰性删除
  LRU:最近最少使用
  LFU: 使用频率最低
  a.no-evication
  b.allkeys-lru
  c.volatile-lru
  d.allkeys-random
  e.volatile-random
  f.allkeys-lfu 
  j.volatile-lfu
  k.volatile-ttl
 4.一致性hash
 5.部署模式
  1.单点
  2.主从,一主多从,需要手动切换
  3.集群 16384个槽,crc16算法计算属于哪个槽。然后定向到哪一台服务器
  4.哨兵模式
    a.哨兵是一个单独的进程。原理是哨兵通过发送命令,等待服务器响应,从而监控运行的多个redis实例,
    b.failover故障切换,主观下线:一个哨兵检测到主服务器不可用,当多个哨兵都监测到哨兵不可用时就会发起一次投票,进行failover.切换成功,通过发布订阅通知主服务器切换,成为客观下线。
    c.哨兵除了监控redis服务器外,各个哨兵节点也会进行监控。
    d.哨兵模式部署,1主2从3哨兵
  5.redission
  6.分布式锁
    setNX set if not exist ,如果不存在的话设置成功,如果存在则设置失败,加锁失败
  7.缓存穿透 明显不存的数据。布隆过滤器或者缓存控制
  8.缓存击穿 热点数据失效导致数据击穿缓存请求数据库,提前更新,分布式锁
  9.缓存雪崩 缓存同时失效。导致请求到数据库,从而拖垮数据库,分散过期时间。
  10.热点数据全部集中到一台redis服务器,可以使用随机值将数据分布到多台服务器,减少请求倾斜
  11.缓存一致性问题 [https://blog.csdn.net/hukaijun/article/details/81010475]
     1.更新数据,删除缓存
     2.删除缓存,更新数据库 延时双删(del cache,udate database,sleep,del cache)
     3.cache aside pattern: 
       a.失效Missing: 从数据查询,加载到缓存
       b.命中Hit: 返回
       c.更新:更新数据库,失效缓存

redis集群模式传送门
redis集群模式为什么不使用一致性哈希,而采用分配哈希槽的模式 答案


zookeeper

分布式协调服务,kafka. dubbo. 
zookeeper分布式锁原理:
  利于zookeeper的临时顺序节点,第一个客户端创建临时顺序节点,创建成功则加锁成功,后续的客户端查询是否为集合中的第一个节点,如果不是一个节点,会监控前一个节点是否被删除,删除代表释放了锁。判断是否为第一个节点,如果是则加锁成功。[https://www.cnblogs.com/ysw-go/p/11444993.html]

InterProcessMutex lock = InterProcessMutex(client,"/lock/my_lock")
lock.acqiure();// 获取锁
lock.release();// 释放锁

JVM

[https://www.cnblogs.com/chenpt/p/9803298.html]
jvm内存模型
1.java虚拟机栈:线程私有 栈帧,局部变量、操作数栈、动态链接、方法出口
2.本地方法栈:线程私有
3.程序计数器:线程私有  当前线程的行号指示器
4.堆:线程共享
  年轻代:survivor区,Eden区
  老年代:
5.方法区:线程共享 类信息,常量,静态变量,运行时常量池

内存分配:
   方法逃逸,锁消除,锁粗化
   即时编译JIT
   栈上分配-> TLAB(Thread Local Allocation Buffer线程本地分配缓存区) -> 是否需要分配到老年代,如果不需要则分配到Eden区
   TLAB:默认占用Eden区的1%
   
GC垃圾回收
1.垃圾回收判断机制:
  a.可达性分析,GCROOT引用链,一个对象到GCRoot没有任何引用链时则认为对象不可用,可以作为GCRoot对象的有,虚拟机栈中引用的对象,常量,静态属性,native引用的对象
  b.引用计数法,相互引用问题
2.垃圾回收算法
  a.复制回收算法,主要是年轻代
  b.标记清除,会产生内存碎片
  c.标记整理  老年代 CMS收集器 
  d.分代回收
3.垃圾回收器
  a.serial
  b.ParNew
  c.Parallel Scavenge 
  d.serial Old 作为CMS收集器的后备方案,在并发收集Concurent Mode Failure时使用。
  e.parallel old
  f.CMS
    A:初始标记。B:并发标记 C:重新标记 D:并发清除
  j.G1 (garbage first)
    A:可预测的停顿,将堆内存划分为多个Region区域,根据允许的时间,收集部分Region,从而能在指定时间内完成垃圾回收
 4.垃圾回收概念
   a.并行:多个线程同时收集
   b.并发:垃圾回收线程工作的同时,用户线程可以继续运行
   c.吞吐量:CPU运行用户代码的时间与CPU总运行时间的比值
   d.STW:Stop the world 
   方法区垃圾回收
   A.废弃常量和无用的类
        回收条件:a.该类的实例都已经被回收 b.加载该类的ClassLoader被回收 c.该类对应的Class没有在任何地方引用,无法通过反射访问该类的方法
 5.jvm调优 
   [https://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html] 参数详解
   -Xmx 最大堆
   -Xms 最小堆
   -Xmn 年轻代
   -Xss 栈大小

6.java类加载过程
加载 -> 验证 -> 准备 -> 解析 -> 初始化

7.双亲委派机制:
  当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。
   


   

JVM 锁升级过程:

  • jdk1.6之前,synchronized是只有两种锁状态,无锁和重量级锁,加锁依赖操作系统的互斥量mutex,因此效率低下。
  • jdk1.6之后,对synchronized进行了优化,锁的状态分为四种,无锁、偏向锁、轻量级锁、重量级锁。
  • 无锁:默认就是无锁状态
  • 偏向锁:当一个线程访问同步代码块时,就会将锁状态置为偏向锁状态
  • 轻量级锁:当存在锁竞争(锁竞争的定义:如果多个线程轮流获取锁,并且每次获取都很顺利,不存在阻塞,那就不存在锁竞争,只有当某个线程尝试获取锁时,发现锁已经被占用,只能等待其释放,这才发生了竞争),偏向锁将会升级为轻量级锁,没有抢到锁的线程将自旋获取锁(通过CAS操作将markWord中的线程id修改为自己线程id),这就是一种忙等待的状态。会消耗CPU
  • 重量级锁:当锁竞争比较严重的时候(自旋次数达到一定的次数,默认是10次,可以通过jvm[-XX:PreBlockSpin=<n>]参数修改),锁将升级为重量级锁,这时候,其他线程想要获取锁的线程将处于阻塞状态。

G1收集器可调参数

  • 暂停时间: -XX:MaxGcPauseMills 默认是200ms,垃圾回收器会尽量达成这个时间
  • Region大小 -XX:G1RegionHeapSize,来指定,若未指定则默认最多生成2048块,每块的大小需要为2的幂次方,如1,2,4,8,16,32,最大值为32M。Region的大小主要是关系到Humongous Object的判定,当一个对象超过Region大小的一半时,则为巨型对象,那么其会至少独占一个Region,如果一个放不下,会占用连续的多个Region。当一个Humongous Region放入了一个巨型对象,可能还有不少剩余空间,但是不能用于存放其他对象,这些空间就浪费了。所以如果应用里有很多大小差不多的巨型对象,可以适当调整Region的大小,尽量让他们以普通对象的形式分配,合理利用Region空间
  • 新生代比例:-XX:G1NewSizePercent,默认值5%,上限值-XX:G1MaxNewSizePercent(默认值60%)
  • 参考来源

Java基础

HashMap原理
   数组加链表
   默认大小是16
   扩容 2的幂次方
   负载因子 0.75
   数组不可变,所以如果在知道容量大小的情况下,初始化容量。减少因为数组复制导致的开销。
   线程不安全,线程安全版本ConcurrentHashMap.
   1.8优化,链表的长度大于8时,链表转为红黑树,小于6时会转回链表
ConcurrentHashMap
   线程安全
   1.7通过分段锁机制
   1.8转为通过CAS加synchronized。数据结构也转为红黑树
ArrayList&LinedkList
   ArrayList:
     数组实现,支持随机访问,搜索和读取效率高。删除数据效率低,因为要移动后面的数据,默认容量为10,扩容1.5倍。
   LinkedList:
     链表实现,不支持随机访问,搜索效率低。插入删除效率高。
CAS
   无锁化
   自旋 消耗CPU
volatile:
   内存屏障,禁止指令重排,内存可见性,对volatile修饰的变量的修改会立即同步到主内存,读取时也会直接从主内存读取,而不会读取工作内存

锁升级
- 偏向锁:单个线程,Java偏向锁旨在对于无并发争用的前提下,进行真正意义上的无锁同步
- 轻量级锁:多于一个线程竞争时会升级为轻量级锁
- 重量级锁: 有实际竞争,且锁竞争时间长

锁粗化,锁消除
- 在开启逃逸分析和锁消除的情况下(-server -XX:+DoEscapeAnalysis -XX:+EliminateLocks),如果编译器认为锁定区域没有逃出作用域,不存在共享数据竞争问题就会消除不必要的加锁
   
   
单例模式,双重检查锁机制
1.懒汉模式
2.饿汉模式
public class SafeDoubleCheckedLocking {
    private volatile static Instance instance;

    public static Instance getInstance() {
        if (instance == null) {
            synchronized (SafeDoubleCheckedLocking.class) {
                if (instance == null)
                    instance = new Instance();//instance为volatile,现在没问题了
            }
        }
        return instance;
    }
}

线程池
1.线程池核心参数
  核心线程数
  最大线程数
  队列
  拒绝策略
    a.直接丢弃 discard 
    b.丢弃最老的 discardOldest
    c.抛出异常 abort   
    d.调用线程执行 callerRunPolicy
  keepAliveTime:线程的空闲存活时间
  
 

线程池execute时的逻辑:

  • 如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
    如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
  • 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maxPoolSize,建新的线程来处理被添加的任务。
  • 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maxPoolSize,那么通过handler所指定的策略来处理此任务。也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程 maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
  • 当线程池中的线程数量大于corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

线程的几个状态 参考

image.png

image.png


springboot

springboot自动配置原理
@EnableAutoConfiguration
加载META-INF下的spring.factories下的EnableAutoConfiguration的值,将这些值作为自动配置类导入到spring容器中。这些自动配置类通过@Condition条件式注解加载相应的bean到spring容器


BeanFactory,FactoryBean,ApplicationContext

spring ioc 
依赖注入,控制反转,将对象的创建获取交给spring容器来管理。降低耦合


springboot 生命周期
Bean实例化
↓
bean属性注入
↓
BeanNameAware.setBeanName
↓
BeanFactoryAware.setBeanFactory
↓
ApplicationContextAware.setApplicationContext
↓ bean的初始化
BeanPostProcessor.postProcessBeforeInitialization
↓
IninitalizingBean.afterPropertiesSet
↓
init-method
↓
BeanPostProcessor.postProcessAfterInitialization
↓
bean的使用
↓ bean的销毁
DisposableBean.Destory
↓
destory-method方法


AOP:基于动态代理模式
jdk动态代理:实现接口
cglib动态代理:字节码生成技术,继承类,对final类无效

动态代理:实现InvocationHandler
静态代理:实现相同的接口


springboot自动装配原理
spring如何解决循环依赖问题

一级缓存:
/** 保存所有的singletonBean的实例 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);

二级缓存:
/** 保存所有早期创建的Bean对象,这个Bean还没有完成依赖注入 */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
三级缓存:
/** singletonBean的生产工厂*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
 
/** 保存所有已经完成初始化的Bean的名字(name) */
private final Set<String> registeredSingletons = new LinkedHashSet<String>(64);
 
/** 标识指定name的Bean对象是否处于创建状态  这个状态非常重要 */
private final Set<String> singletonsCurrentlyInCreation =
    Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));


spring cloud

注册中心
  eureka,consul,zookeeper,nacos
网关
  springcloud gateway,zuul
断路器
  hystrix,sentinel
  hystrix:基于线程隔离、信号量,控制影响范围。断路器,当失败次数达到一定比例后会开启熔断,返回fallback,定时探测,当服务恢复后,可以关闭熔断机制。命令模式。hystrixCommand
openFeign
ribbon
springcloud Bus,Stream
配置中心
  nacos,spring config,disconf,阿波罗,consul
链路追踪
  zipkin,sluth
  
  
  
分布式事务
zookeeper和eureka
CAP定理,一致性,可用性,分区容错性,只能同时满足两项
BASE理论:基本可用,软状态,最终一致性
seta:强一致性方案
基于消息表的最终一致性
基于事务消息
两阶段提交
spring cloud 组件

consul配置中心
consul注册中心
eureka注册中心心跳机制
Hystrix
Feign


Dubbo

Dubbo官方文档

Dubbo架构图


Dubbo Arctitecture

Dubbo注解配置示例
Dubbo SPI
Dubbo 负载均衡

  • 最少活跃数LeastActive: 发送请求数据减去返回请求数的值越少的优先调用,能者多劳
    sPI

ElasticSearch


golang

channel
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容