概述
目录
Java
MySql
分布式事务
ElasticSearch
Kafka
Spring
Spring Cloud
RPC框架
注册中心 zk、eureka
redis
计算机网络
LevelDB
Flink
HBase
Java
- String str = "abc" + new String("def"); 一共创建了多少个对象?
new string(abc)创建了几个对象_面试题系列第2篇:new String()创建几个对象?有你不知道的..._田小圣的博客-CSDN博客
String str = “abc“ + new String(“def“);到底创建了多少个对象?_凡凡轶崔的博客-CSDN博客 - synchronize原理,锁升级、锁消除、锁粗化
Java synchronized原理总结 - ReadWriteLock也支持公平与非公平模式(ReentrantReadWriteLock)。但是有一点需要注意,那就是只有写锁支持条件变量,读锁是不支持条件变量的,读锁调用 newCondition() 会抛出 UnsupportedOperationException 异常。
- JDK8引入的StampedLock,相比ReadWriteLock,模式有写锁、悲观读、乐观读,其中乐观读是无锁的。首先通过调用 tryOptimisticRead() 获取了一个 stamp,读完后在通过调用 validate(stamp)验证一下是否存在写操作。若有,则通过代码显示的吧乐观读锁升级为悲观读锁(stamp = sl.readLock();)
- StampedLock不支持重入,并且StampedLock 的悲观读锁、写锁都不支持条件变量
StampedLock 写模板 long stamp = sl.writeLock(); try { // 写共享变量 ...... } finally { sl.unlockWrite(stamp); }
StampedLock 读模板 final StampedLock sl = new StampedLock(); // 乐观读 long stamp = sl.tryOptimisticRead(); // 读入方法局部变量 ...... // 校验stamp if (!sl.validate(stamp)){ // 升级为悲观读锁 stamp = sl.readLock(); try { // 读入方法局部变量 ..... } finally { //释放悲观读锁 sl.unlockRead(stamp); } } //使用方法局部变量执行业务操作 ......
- hashmap扩容成环原理:当hashmap中存放的数据超过容量(默认16)*加载因子(默认0.75)的时候,就会发生扩容现象,数组长度会扩大一倍,扩容会调用resize()方法和rehash()方法,在多线程情况下调用resize方法后,将数组扩容,然后rehash方法将原有的entry重新计算hash值,再插入到新数组中,在这个插入新数组中的过程中,两个线程同时操作,就会使链表形成一个环,然后,如果get()操作,刚好到了此链表上,就会发生死循环。 hash成环过程:HashMap原理及线程不安全详解 - 木子H的个人空间 - OSCHINA - 中文开源技术交流社区
- ThreadLocal内存泄漏
ThreadLocal 内存泄露问题_JH灰色的博客-CSDN博客_threadlocal内存泄露 - TransmittableThreadLocal、InheritableThreadLocal原理
Transmittable-Thread-Local:阿里开源的线程间上下文传递解决方案_luoxn28的专栏-CSDN博客 - 逃逸分析:深入理解Java中的逃逸分析_HollisChuang's Blog-CSDN博客_逃逸分析
- StringBuffer线程安全,其也是final类别的,不允许被继承,其中的绝大多数方法都进行了同步处理,其toString方法会进行对象缓存,以减少元素复制开销。
public synchronized String toString() { if (toStringCache == null) { toStringCache = Arrays.copyOfRange(value, 0, count); } return new String(toStringCache, true); }
StringBuilder非线程安全,其也是final类别的,不允许被继承,方法除了没使用synch修饰以外基本一致,不同之处在于最后toString的时候,会直接返回一个新对象。
public String toString() { // Create a copy, don’t share the array return new String(value, 0, count); }
-
父类静态数据,构造函数,字段,子类静态数据,构造函数,在类实例化中的执行顺序。
父类静态代码块(变量)、
子类静态代码块(变量)、
父类非静态变量(父类实例成员变量)、
父类构造函数、
子类非静态变量(子类实例成员变量)、
子类构造函数。 -
Class.forName()与ClassLoader.loadClass()的区别
ClassLoader.loadClass()与Class.forName()的区别 - 张国平的个人空间 - OSCHINA - 中文开源技术交流社区 -
重写String类,但加载机制规定不允许加载任何包路径以java.开头的自定义类
Java类加载器--手写一个String类能否被类加载器加载?_Doit_kang的博客-CSDN博客 -
单例模式,懒汉式、饿汉式、双重校验锁、静态内部类、枚举
单例模式-控制实例数目,5种写法 :懒汉,恶汉,双重校验锁,枚举和静态内部类。 - 洋哥的空间 - OSCHINA - 中文开源技术交流社区 -
gc root节点有哪些?
虚拟机栈(栈帧中的本地变量表)中的引用的对象。
方法区域中的类静态属性引用的对象。
方法区域中常量引用的对象。
本地方法栈中JNI(Native方法)的引用的对象。 -
各种垃圾回收器
2.垃圾收集器 · jvm梳理
CMS 和G1 的区别 - 简书 -
新生代晋升老年代情况总结
(1)、Eden区满时,进行Minor GC,当Eden和一个Survivor区中依然存活的对象无法放入到Survivor中,则通过分配担保机制提前转移到老年代中。
(2)、若对象体积太大, 新生代无法容纳这个对象,-XX:PretenureSizeThreshold即对象的大小大于此值, 就会绕过新生代, 直接在老年代分配, 此参数只对Serial及ParNew两款收集器有效。
(3)、长期存活的对象将进入老年代。
虚拟机对每个对象定义了一个对象年龄(Age)计数器。当年龄增加到一定的临界值时,就会晋升到老年代中,该临界值由参数:-XX:MaxTenuringThreshold来设置。
如果对象在Eden出生并在第一次发生MinorGC时仍然存活,并且能够被Survivor中所容纳的话,则该对象会被移动到Survivor中,并且设Age=1;以后每经历一次Minor GC,该对象还存活的话Age=Age+1。
(4)、动态对象年龄判定。
虚拟机并不总是要求对象的年龄必须达到MaxTenuringThreshold才能晋升到老年代,如果在Survivor区中相同年龄(设年龄为age)的对象的所有大小之和超过Survivor空间的一半,年龄大于或等于该年龄(age)的对象就可以直接进入老年代,无需等到MaxTenuringThreshold中要求的年龄。
-
缓存穿透、缓存击穿、缓存雪崩
缓存穿透
缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。
1)、接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
2)从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
3)布隆过滤器,它说的不存在一定是不存在的,它说的存在不一定是存在的。
缓存击穿
对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里针对某一key缓存,前者则是很多key。
缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
1)设置热点数据永远不过期
2)缓存过期,加锁从数据库取数
缓存雪崩
缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。
1)缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
2)如果缓存数据库是分布式部署,将热点数据均匀分布在不同的缓存数据库中。
3)设置热点数据永远不过期 -
分布式锁实现方案及优缺点
分布式锁的几种实现方式~-HollisChuang's Blog
MySql
- 已提交读和可重复读均会产生快照,只是产生时机不一样:RR下,事务在第一个Read操作时,会建立Read View;RC下,事务在每次Read操作时,都会建立Read View
- redolog、binlog、二阶段提交:mysql redolog binlog 之二阶段提交_welcome to daijiguo's blog-CSDN博客
- InnoDB行记录格式及BLOB/TEXT字段优化https://blog.csdn.net/qq_33300570/article/details/120014310
- redo与undo的区别
mysql的redo与undo_凡凡轶崔的博客-CSDN博客_mysql的undo和redo - change buffer
mysql的change buffer_凡凡轶崔的博客-CSDN博客 - 主从同步流程
mysql主从复制原理 - 知乎 - hash索引优缺点
InnoDB存储引擎中的哈希算法
InnoDB中采用除法散列函数,冲突机制采用链接法。
BTree索引和哈希索引的区别
Hash索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位,不像B-Tree索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以Hash索引的查询效率要远高于B-Tree索引。
可能很多人又有疑问了,既然Hash索引的效率要比B-Tree高很多,为什么大家不都用Hash索引而还要使用B-Tree索引呢?任何事物都是有两面性的,Hash索引也一样,虽然Hash索引效率高,但是Hash索引本身由于其特殊性也带来了很多限制和弊端,主要有以下这些:
1)Hash索引仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询。哈希索引只支持等值比较查询,包括=、 IN 、<=> (注意<>和<=>是不同的操作)。 也不支持任何范围查询,例如WHERE price > 100。
由于Hash索引比较的是进行Hash运算之后的Hash值,所以它只能用于等值的过滤,不能用于基于范围的过滤,因为经过相应的Hash算法处理之后的Hash值的大小关系,并不能保证和Hash运算前完全一样。
2)Hash索引无法被用来避免数据的排序操作。
由于Hash索引中存放的是经过Hash计算之后的Hash值,而且Hash值的大小关系并不一定和Hash运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算;
3)Hash索引不能利用部分索引键查询。
对于组合索引,Hash索引在计算Hash值的时候是组合索引键合并后再一起计算Hash值,而不是单独计算Hash值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash索引也无法被利用。
4)Hash索引在任何时候都不能避免表扫描。
前面已经知道,Hash索引是将索引键通过Hash运算之后,将 Hash运算结果的Hash值和所对应的行指针信息存放于一个Hash表中,由于不同索引键存在相同Hash值,所以即使取满足某个Hash键值的数据的记录条数,也无法从Hash索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较,并得到相应的结果。
5)Hash索引遇到大量Hash值相等的情况后性能并不一定就会比BTree索引高。
对于选择性比较低的索引键,如果创建Hash索引,那么将会存在大量记录指针信息存于同一个Hash值相关联。这样要定位某一条记录时就会非常麻烦,会浪费多次表数据的访问,而造成整体性能低下。
分布式事务
ElasticSearch
- 链接: https://pan.baidu.com/s/124c1WxuCRYIsJAwXUQYh0g 密码: w97w
- 「扫盲」Elasticsearch - 知乎
Kafka
-
Kafka高可用架构设计
① 消息备份
Kafka允许同一个Partition存在多个消息副本(Replica),每个Partition的副本通常由1个Leader及0个以上的Follower组成,生产者将消息直接发往对应Partition的Leader,Follower会周期地向Leader发送同步请求,Kafka的Leader机制在保障数据一致性地同时降低了消息备份的复杂度。同一Partition的Replica不应存储在同一个Broker上,因为一旦该Broker宕机,对应Partition的所有Replica都无法工作,这就达不到高可用的效果。为了做好负载均衡并提高容错能力,Kafka会尽量将所有的Partition以及各Partition的副本均匀地分配到整个集群上。举个例子,当集群中部署了3台Broker,TopicA共有4个Partition,每个Partition均有3个Replica时下图就是一种合理的分布方式。
②ISR
ISR(In-Sync Replicas)指的是一个Partition中与Leader“保持同步”的Replica列表(实际存储的是副本所在Broker的BrokerId),这里的保持同步不是指与Leader数据保持完全一致,只需在replica.lag.time.max.ms时间内与Leader保持有效连接
Follower周期性地向Leader发送FetchRequest请求,发送时间间隔配置在replica.fetch.wait.max.ms中,默认值为500。各Partition的Leader负责维护ISR列表并将ISR的变更同步至ZooKeeper,被移出ISR的Follower会继续向Leader发FetchRequest请求,试图再次跟上Leader重新进入ISR。
ISR中所有副本都跟上了Leader,通常只有ISR里的成员才可能被选为Leader。当Kafka中unclean.leader.election.enable配置为true(默认值为false)且ISR中所有副本均宕机的情况下,才允许ISR外的副本被选为Leader,此时会丢失部分已应答的数据。
③ACKs为了讲清楚ISR的作用,下面介绍一下生产者可以选择的消息应答方式,生产者发送消息中包含acks字段,该字段代表Leader应答生产者前Leader收到的应答数
acks=0
生产者无需等待服务端的任何确认,消息被添加到生产者套接字缓冲区后就视为已发送,因此acks=0不能保证服务端已收到消息,使用场景较少,本文不做任何讨论
acks=1
Leader将消息写入本地日志后无需等待Follower的消息确认就做出应答。如果Leader在应答消息后立即宕机且其他Follower均未完成消息的复制,则该条消息将丢失
acks=all(-1)
Leader将等待ISR中的所有副本确认后再做出应答,因此只要ISR中任何一个副本还存活着,这条应答过的消息就不会丢失。acks=all是可用性最高的选择,但等待Follower应答引入了额外的响应时间。Leader需要等待ISR中所有副本做出应答,此时响应时间取决于ISR中最慢的那台机器,下图中因复制产生的额外延迟为3秒。
④LEO & HW
每个Kafka副本对象都有下面两个重要属性:
LEO(log end offset) ,即日志末端偏移,指向了副本日志中下一条消息的位移值(即下一条消息的写入位置)
HW(high watermark),即已同步消息标识,因其类似于木桶效应中短板决定水位高度,故取名高水位线
所有高水位线以下消息都是已备份过的,消费者仅可消费各分区Leader高水位线以下的消息,对于任何一个副本对象而言其HW值不会大于LEO值
Leader的HW值由ISR中的所有备份的LEO最小值决定(Follower在发送FetchRequest时会在PartitionFetchInfo中会携带Follower的LEO) - Kafka高性能架构设计
①批量发送消息
Kafka的消息是一个一个的键值对,键可以设置为默认的null。键有两个用途,可以作为消息的附加信息,也可以用来决定该消息被写入到哪个Partition。Topic的数据被分成一个或多个Partition,Partition是消息的集合,Partition是Consumer消费的最小粒度。
Kafka通过将Topic划分成多个Partition,Producer将消息分发到多个本地Partition的消息队列中,每个Partition消息队列中的消息会写入到不同的Leader节点。消息经过路由策略,被分发到不同的Partition对应的本地队列,然后再批量发送到Partition对应的Leader节点。
Kafka中Topic有多个Partition,那么消息分配到某个Partition的策略称为路由策略。Kafka的路由策略主要有三种:
1)Round Robin:Producer将消息均衡地分配到各Partition本地队列上,是最常用的分区策略。
2)散列:Kafka对消息的key进行散列,根据散列值将消息路由到特定的Parttion上,键相同的消息总是被路由到相同的Partition上。
3)自定义分区策略:Kafka支持自定义分区策略,可以将某一系列的消息映射到相同的Partition。
Producer先生产消息、序列化消息并压缩消息后,追加到本地的记录收集器(RecordAccumulator),Sender不断轮询记录收集器,当满足一定条件时,将队列中的数据发送到Partition Leader节点。Sender发送数据到Broker的条件有两个:
消息大小达到阈值
消息等待发送的时间达到阈值
②消息持久化
kafka采用顺序写的方式来做消息持久化。
Producer传递到Broker的消息集中的每条消息都会分配一个顺序值,用来标记Producer所生产消息的顺序,每一批消息的顺序值都从0开始。
Producer创建的消息集中每条消息的顺序值只是相对于本批次的序号,所以这个值不能直接存储在日志文件中。服务端会将每条消息的顺序值转换成绝对偏移量(Broker从Partition维度来标记消息的顺序,用于控制Consumer消费消息的顺序)。Kafka通过nextOffset(下一个偏移量)来记录存储在日志中最近一条消息的偏移量
Broker将每个Partition的消息追加到日志中,是以日志分段(Segment)为单位的。当Segment的大小达到阈值(默认是1G)时,会新创建一个Segment保存新的消息,每个Segment都有一个基准偏移量(baseOffset,每个Segment保存的第一个消息的绝对偏移量),通过这个基准偏移量,就可以计算出每条消息在Partition中的绝对偏移量。 每个日志分段由数据文件和索引文件组,数据文件(文件名以log结尾)保存了消息集的具体内容,索引文件(文件名以index结尾)保存了消息偏移量到物理位置的索引。
Broker中通过下一个偏移量元数据(nextOffsetMetaData),指定当前写入日志的消息的起始偏移值,在追加消息后,更新nextOffsetMetaData,作为下一批消息的起始偏移量
③基于索引文件的查询
假设有1000条消息,每100条消息写满了一个日志分段,一共会有10个日志分段。客户端要查询偏移量为999的消息内容,如果没有索引文件,我们必须从第一个日志分段的数据文件中,从第一条消息一直往前读,直到找到偏移量为999的消息。有了索引文件后,我们可以在最后一个日志分段的索引文件中,首先使用绝对偏移量999减去基准偏移量900得到相对偏移量99,然后找到最接近相对偏移量99的索引数据90,相对偏移量90对应的物理地址是1365,然后再到数据文件中,从文件物理位置1365开始往后读消息,直到找到偏移量为999的消息。
Kafka的索引文件的特性:
1)索引文件映射偏移量到文件的物理位置,它不会对每条消息都建立索引,所以是稀疏的。
2)索引条目的偏移量存储的是相对于“基准偏移量”的“相对偏移量” ,不是消息的“绝对偏移量”
3)由于Broker是将消息持久化到当前日志的最后一个分段中,写入文件的方式是追加写,采用了对磁盘文件的顺序写。对磁盘的顺序写以及索引文件加快了Broker查询消息的速度。
4)偏移量是有序的,查询指定的偏移量时,使用二分查找可以快速确定偏移量的位置。
5)指定偏移量如果在索引文件中不存在,可以找到小于等于指定偏移量的最大偏移量。
6)稀疏索引可以通过内存映射方式,将整个索引文件都放入内存,加快偏移量的查询。
由于Broker是将消息持久化到当前日志的最后一个分段中,写入文件的方式是追加写,采用了对磁盘文件的顺序写。对磁盘的顺序写以及索引文件加快了Broker查询消息的速度。
③零拷贝Kafka中存在大量的网络数据持久化到磁盘(Producer到Broker)和磁盘文件通过网络发送(Broker到Consumer)的过程。这一过程的性能直接影响到Kafka的整体性能。Kafka采用零拷贝这一通用技术解决该问题。
零拷贝技术可以减少数据拷贝和共享总线操作的次数,消除传输数据在存储器之间不必要的中间拷贝次数,减少用户应用程序地址空间和操作系统内核地址空间之间因为上下文切换而带来的开销,从而有效地提高数据传输效率。
Kafka的数据传输通过TransportLayer来完成,其子类PlaintextTransportLayer通过Java NIO的FileChannel的transferTo()和transferFrom()方法实现零拷贝。transferTo()和transferFrom()并不保证一定能使用零拷贝,实际上是否能使用零拷贝与操作系统相关,如果操作系统提供sendfile这样的零拷贝系统调用,则这两个方法会通过这样的系统调用充分利用零拷贝的优势,否则并不能通过这两个方法本身实现零拷贝。
-
列举一下会reblance的情况:
增加partition
增加消费者
消费者主动关闭
消费者宕机了
coordinator自己也宕机了对于「新成员加入」、「组成员主动离开」都是我们主动触发的,能比较好地控制。但是「组成员崩溃」则是我们预料不到的,遇到问题的时候也比较不好排查。但对于「组成员崩溃」也是有一些通用的排查思路的,下面我们就来聊聊「rebalance问题的处理思路」。
要学会处理 rebalance 问题,我们需要先搞清楚 kafaka 消费者配置的四个参数:
session.timeout.ms 设置了超时时间
heartbeat.interval.ms 心跳时间间隔
max.poll.interval.ms 每次消费的处理时间
max.poll.records 每次消费的消息数
session.timeout.ms 表示 consumer 向 broker 发送心跳的超时时间。例如 session.timeout.ms = 180000 表示在最长 180 秒内 broker 没收到 consumer 的心跳,那么 broker 就认为该 consumer 死亡了,会启动 rebalance。heartbeat.interval.ms 表示 consumer 每次向 broker 发送心跳的时间间隔。heartbeat.interval.ms = 60000 表示 consumer 每 60 秒向 broker 发送一次心跳。一般来说,session.timeout.ms 的值是 heartbeat.interval.ms 值的 3 倍以上。
max.poll.interval.ms 表示 consumer 每两次 poll 消息的时间间隔。简单地说,其实就是 consumer 每次消费消息的时长。如果消息处理的逻辑很重,那么市场就要相应延长。否则如果时间到了 consumer 还么消费完,broker 会默认认为 consumer 死了,发起 rebalance。
max.poll.records 表示每次消费的时候,获取多少条消息。获取的消息条数越多,需要处理的时间越长。所以每次拉取的消息数不能太多,需要保证在 max.poll.interval.ms 设置的时间内能消费完,否则会发生 rebalance。
简单来说,会导致崩溃的几个点是:
消费者心跳超时,导致 rebalance。
消费者处理时间过长,导致 rebalance。消费者心跳超时
我们知道消费者是通过心跳和协调者保持通讯的,如果协调者收不到心跳,那么协调者会认为这个消费者死亡了,从而发起 rebalance。而 kafka 的消费者参数设置中,跟心跳相关的两个参数为:
session.timeout.ms 设置了超时时间
heartbeat.interval.ms 心跳时间间隔
这时候需要调整 session.timeout.ms 和 heartbeat.interval.ms 参数,使得消费者与协调者能保持心跳。一般来说,超时时间应该是心跳间隔的 3 倍时间。即 session.timeout.ms 如果设置为 180 秒,那么 heartbeat.interval.ms 最多设置为 60 秒。为什么要这么设置超时时间应该是心跳间隔的 3 倍时间?因为这样的话,在一个超时周期内就可以有多次心跳,避免网络问题导致偶发失败。
消费者处理时间过长
如果消费者处理时间过长,那么同样会导致协调者认为该 consumer 死亡了,从而发起重平衡。而 kafka 的消费者参数设置中,跟消费处理的两个参数为:
max.poll.interval.ms 每次消费的处理时间
max.poll.records 每次消费的消息数
对于这种情况,一般来说就是增加消费者处理的时间(即提高 max.poll.interval.ms 的值),减少每次处理的消息数(即减少 max.poll.records 的值)。除此之外,超时时间参数(session.timeout.ms)与 消费者每次处理的时间(max.poll.interval.ms)也是有关联的。max.poll.interval.ms 时间不能超过 session.timeout.ms 时间。 因为在 kafka 消费者的实现中,其是单线程去消费消息和执行心跳的,如果线程卡在处理消息,那么这时候即使到时间要心跳了,还是没有线程可以去执行心跳操作。很多同学在处理问题的时候,明明设置了很长的 session.timeout.ms 时间,但最终还是心跳超时了,就是因为没有处理好这两个参数的关联。
对于 rebalance 类问题,简单总结就是:处理好心跳超时问题和消费处理超时问题。
对于心跳超时问题。一般是调高心跳超时时间(session.timeout.ms),调整超时时间(session.timeout.ms)和心跳间隔时间(heartbeat.interval.ms)的比例。阿里云官方文档建议超时时间(session.timeout.ms)设置成 25s,最长不超过 30s。那么心跳间隔时间(heartbeat.interval.ms)就不超过 10s。
对于消费处理超时问题。一般是增加消费者处理的时间(max.poll.interval.ms),减少每次处理的消息数(max.poll.records)。阿里云官方文档建议 max.poll.records 参数要远小于当前消费组的消费能力(records < 单个线程每秒消费的条数 x 消费线程的个数 x session.timeout的秒数)。 - kafka的rebalance流程
- consumer给coordinator发送JoinGroupRequest请求。
-
这时其他consumer发heartbeat请求过来时,coordinator会告诉他们,要reblance了。
-
其他consumer发送JoinGroupRequest请求。
-
所有记录在册的consumer都发了JoinGroupRequest请求之后,coordinator就会在这里consumer中随便选一个leader。然后回JoinGroupRespone,这会告诉consumer你是follower还是leader,对于leader,还会把follower的信息带给它,让它根据这些信息去分配partition
-
consumer向coordinator发送SyncGroupRequest,其中leader的SyncGroupRequest会包含分配的情况。
-
coordinator回包,把分配的情况告诉consumer,包括leader。
-
kafka如何保证消费者可靠性Kafka-如何保证消费者的可靠性 - 嘣嘣嚓 - 博客园
1.group.id:如果两个消费者具有相同的group.id,并且订阅了同一个主题,那么每个消费者会分到主题分区的一个子集,也就是说他们只能读到所有消息的一个子集(不过群组会读取主题所有的消息)。如果希望消费者可以看到主题的所有消息,那么需要为它们设置唯一的group.id。
2.auto.offset.reset:默认latest,这个参数指定了在没有偏移量可提交时或者请求的偏移量在broker上不存在时,消费者会做什么。这个参数有两种配置:
earliest:消费者会从分区的开始位置读取数据,不管偏移量是否有效,这样会导致消费者读取大量的重复数据,但可以保证最少的数据丢失。
latest:消费者会从分区的末尾开始读取数据,这样可以减少重复处理消息,但是很有可能会错过一些消息。
3.enable.auto.commit:默认true,这是一个非常重要的配置参数,可以让消费者基于任务调度自动提交偏移量,也可以在代码里手动提交偏移量。自动提交的一个最大好处是,在实现消费者逻辑时可以少考虑一些问题。如果在消费者轮询操作里处理所有的数据,那么自动提交可以保证只提交已经处理过的偏移量。自动提交的缺点:无法控制重复处理消息(比如消费者在自动提交偏移量之前停止处理消息),而且如果把消息交给另外一个后台线程去处理,自动提交机制可能会在消息还没有处理完毕就提交偏移量。4.auto.commit.interval.ms:此参数与enable.auto.commit有直接的联系,如果选择了自动提交偏移量,可以通过此参数配置提交的频度,默认值是每5秒钟提交一次。一般来说,频繁提交会增加额外的开销,但也会降低重复处理消息的概率。
-
kafka exactly once如何实现
Kafka Exactly Once语义与事务机制原理 | 技术世界 | kafka,大数据,集群,消息系统,郭俊 Jason,kafka 架构,kafka 事务,exactly once,正好一次
Kafka 0.11.0.0 是如何实现 Exactly-once 语义的 - 简书
1)producer:
幂等:partition内部的exactly-once顺序语义
事务:跨partition的原子性写操作
2)consumer:
有两种策略去读取事务写入的消息,通过"isolation.level"来进行配置:①read_committed
:可以同时读取事务执行过程中的部分写入数据和已经完整提交的事务写入数据;②read_uncommitted
:完全不等待事务提交,按照offsets order去读取消息,也就是兼容
Spring
- spring mvc 请求执行流程
- spring容器启动过程
1)资源定位:找到配置文件
2)BeanDefinition载入和解析
3)BeanDefinition注册
4)bean的实例化和依赖注入BeanDefinition载入、解析、注册
1、找到配置文件Resource。
2、将配置文件解析成BeanDefinition
3、将BeanDefinition向Map中注册 Map<name,beandefinition>
总结:容器启动的过程可以分为2大步
1:获取、解析、注册配置信息,将配置的文件信息转换Map<name,beanDefinition>
2:根据上述的Map<name,beanDefinition>去实例化bean,并完成以来注入
- spring bean生命周期Spring Bean的生命周期(非常详细) - Chandler Qian - 博客园
- spring通过三级缓存解决Bean加载循环依赖问题。Spring-bean的循环依赖以及解决方式_惜暮-CSDN博客_spring循环依赖
- Spring 事务的传播属性
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
①TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
②TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
③TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
④TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
⑤TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
⑥TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
⑦TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。 - AOP实现
Java程序员从笨鸟到菜鸟之(七十四)细谈Spring(六)spring之AOP基本概念和配置详解_曹胜欢-CSDN博客
Spring Cloud
- 优缺点:SpringCloud常见面试题(2020最新版) - 乖怪丶 - 博客园
- springcloud各组件
- Spring Cloud Config
集中配置管理工具,分布式系统中统一的外部配置管理,默认使用Git来存储配置,可以支持客户端配置的刷新及加密、解密操作。 - Spring Cloud Netflix
Netflix OSS 开源组件集成,包括Eureka、Hystrix、Ribbon、Feign、Zuul等核心组件。
Eureka:服务治理组件,包括服务端的注册中心和客户端的服务发现机制;
Ribbon:负载均衡的服务调用组件,具有多种负载均衡调用策略;
Hystrix:服务容错组件,实现了断路器模式,为依赖服务的出错和延迟提供了容错能力;
Feign:基于Ribbon和Hystrix的声明式服务调用组件;
Zuul:API网关组件,对请求提供路由及过滤功能。 - Spring Cloud Bus
用于传播集群状态变化的消息总线,使用轻量级消息代理链接分布式系统中的节点,可以用来动态刷新集群中的服务配置。 - Spring Cloud Consul
基于Hashicorp Consul的服务治理组件。 - Spring Cloud Security
安全工具包,对Zuul代理中的负载均衡OAuth2客户端及登录认证进行支持。 - Spring Cloud Sleuth
Spring Cloud应用程序的分布式请求链路跟踪,支持使用Zipkin、HTrace和基于日志(例如ELK)的跟踪。 - Spring Cloud Stream
轻量级事件驱动微服务框架,可以使用简单的声明式模型来发送及接收消息,主要实现为Apache Kafka及RabbitMQ。 - Spring Cloud Task
用于快速构建短暂、有限数据处理任务的微服务框架,用于向应用中添加功能性和非功能性的特性。 - Spring Cloud Zookeeper
基于Apache Zookeeper的服务治理组件。 - Spring Cloud Gateway
API网关组件,对请求提供路由及过滤功能。 - Spring Cloud OpenFeign
基于Ribbon和Hystrix的声明式服务调用组件,可以动态创建基于Spring MVC注解的接口实现用于服务调用,在Spring Cloud 2.0中已经取代Feign成为了一等公民
RPC框架
- 一次 RPC 请求的流程是什么。
1)服务消费方(client)调用以本地调用方式调用服务;
2)client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
3)client stub找到服务地址,并将消息发送到服务端;
4)server stub收到消息后进行解码;
5)server stub根据解码结果调用本地的服务;
6)本地服务执行并将结果返回给server stub;
7)server stub将返回结果打包成消息并发送至消费方;
8)client stub接收到消息,并进行解码;
9)服务消费方得到最终结果。 - dubbo框架介绍?
分布式框架dubbo原理解析 - loda0128的个人空间 - OSCHINA - 中文开源技术交流社区 - dubbo集群容错策略?
集群容错:在集群调用失败时,Dubbo提供了多种容错方案,缺省为failover重试。
1)Failover Cluster:失败自动切换,当出现失败,重试其它服务器。重试次数可以配置,默认为两次。
2)Failfast Cluster:快速失败,只发起一次调用,失败立即报错。
3)Failsafe Cluster:失败安全,出现异常时,直接忽略。
4)Failback Cluster:失败自动恢复,后台记录失败请求,每个5秒定时重发。
5)Forking Cluster:并行调用多个服务器,只要一个成功即返回。
6)Broadcast Cluster:广播调用所有提供者,逐个调用,任意一台报错则报错。如果都成功,则返回最后一台的执行结果。 - dubbo负载均衡策略?
负载均衡:在集群负载均衡时,Dubbo提供了多种均衡策略,缺省为random随机调用。
1)Random LoadBalance:随机,按权重比率设置随机概率。
2)RoundRobin LoadBalance:轮循,按公约后的权重比率设置轮循比率。
3)LeastActive LoadBalance:最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
4)ConsistentHash LoadBalance:一致性Hash,相同参数的请求总是发到同一提供者。当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。 - dubbo的协议有哪些?
1).默认的dubbo协议:
单一长连接、NIO异步通信、并发数量小:适合多consumer少provider
2).rmi协议(少用):
短链接:适用于文件传输------>consumer≈provider
3).hessian协议(少用):
短链接:需同时给应用程序和浏览器JS使用的服务。--------->consumer数<provider数
4).http协议:
json序列化,consumer数<provider数
5).webservice协议:
soap文本序列化,适用场景:系统集成,跨语言调用
精通Dubbo——Dubbo支持的协议的详解_路漫漫,水迢迢-CSDN博客_dubbo支持哪些协议
注册中心 zk、eureka
-
服务注册中心的数据也就是返回的可用服务节点(ip+端口号) 服务A开了0-9十个服务节点,服务B需要调用服务A,两次查询返回0-8,1-9 不一致的数据。产生的影响就是0 和9 节点的负载不均衡
只要注册中心在 SLA 承诺的时间内(例如 1s 内)将数据收敛到一致状态(即满足最终一致),流量将很快趋于统计学意义上的一致,所以注册中心以最终一致的模型设计在生产实践中完全可以接受。
- zk和eureka的区别(CAP原则) - qtyy - 博客园
- zk是CP。
zookeeper在选举leader时,会停止服务,直到选举成功之后才会再次对外提供服务,这个时候就说明了服务不可用,但是在选举成功之后,因为一主多从的结构,zookeeper在这时还是一个高可用注册中心,只是在优先保证一致性的前提下,zookeeper才会顾及到可用性
- eureka是AP
eureka 保证了可用性,实现最终一致性。
Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性),其中说明了,eureka是不满足强一致性,但还是会保证最终一致性 -
每一个微服务中都有eureka client,用于服务的注册于发现 (服务的注册:把自己注册到eureka server) (服务的发现:从eureka server获取自己需要的服务列表)
每一个微服务启动的时候,都需要去eureka server注册 当A服务需要调用B服务时,需要从eureka服务端获取B服务的服务列表,然后把列表缓存到本地,然后根据ribbon的客户端负载均衡规则,从服务列表中取到一个B服务,然后去调用此B服务 当A服务下次再此调用B服务时,如果发现本地已经存储了B的服务列表,就不需要再从eureka服务端获取B服务列表,直接根据ribbon的客户端负载均衡规则,从服务列表中取到一个B服务,然后去调用B服务 微服务,默认每30秒,就会从eureka服务端获取一次最新的服务列表
如果某台微服务down机,或者添加了几台机器, 此时eureka server会通知订阅他的客户端,并让客户端更新服务列表, 而且还会通知其他eureka server更新此信息
心跳检测,微服务每30秒向eureka server发送心跳, eureka server若90s之内都没有收到某个客户端的心跳,则认为此服务出了问题, 会从注册的服务列表中将其删除,并通知订阅它的客户端更新服务列表, 而且还会通知其他eureka server更新此信息
eureka server保护机制,通过打卡开关,可以让eureka server处于保护状态,主要是用于某eureka server由于网络或其他原因,导致接收不到其他微服务的心跳,此时不能盲目的将其他微服务从服务列表中删除。 具体规则:如果一段时间内(15分钟),85%的服务都没有发送心跳,则此server进入保护状态,此状态下,可以正常接受注册,可以正常提供查询服务,但是不与其他server同步信息,也不会通知订阅它的客户端,这样就不会误杀其他微服务 -
ZooKeeper 的 ZAB 协议对每一个写请求,会在每个 ZooKeeper 节点上保持写一个事务日志,同时再加上定期的将内存数据镜像(Snapshot)到磁盘来保证数据的一致性和持久性,以及宕机之后的数据可恢复,这是非常好的特性,但是我们要问,在服务发现场景中,其最核心的数据 - 实时的健康的服务的地址列表是不需要数据持久化的
需要持久化存储的地方在于一个完整的生产可用的注册中心,除了服务的实时地址列表以及实时的健康状态之外,还会存储一些服务的元数据信息,例如服务的版本,分组,所在的数据中心,权重,鉴权策略信息,service label 等元信息,这些数据需要持久化存储,并且注册中心应该提供对这些元信息的检索的能力。
-
使用 ZooKeeper 作为服务注册中心时,服务的健康检测常利用 ZooKeeper 的 Session 活性 Track 机制 以及结合 Ephemeral ZNode 的机制,简单而言,就是将服务的健康监测绑定在了 ZooKeeper 对于 Session 的健康监测上,或者说绑定在 TCP 长链接活性探测上了。
这在很多时候也会造成致命的问题,ZK 与服务提供者机器之间的 TCP 长链接活性探测正常的时候,该服务就是健康的么?答案当然是否定的!注册中心应该提供更丰富的健康监测方案,服务的健康与否的逻辑应该开放给服务提供方自己定义,而不是一刀切搞成了 TCP 活性检测!
健康检测的一大基本设计原则就是尽可能真实的反馈服务本身的真实健康状态,否则一个不敢被服务调用者相信的健康状态判定结果还不如没有健康检测。
-
选型依据:
在粗粒度分布式锁,分布式选主,主备高可用切换等不需要高 TPS 支持的场景下有不可替代的作用,而这些需求往往多集中在大数据、离线任务等相关的业务领域,因为大数据领域,讲究分割数据集,并且大部分时间分任务多进程 / 线程并行处理这些数据集,但是总是有一些点上需要将这些任务和进程统一协调,这时候就是 ZooKeeper 发挥巨大作用的用武之地。
但是在交易场景交易链路上,在主业务数据存取,大规模服务发现、大规模健康监测等方面有天然的短板,应该竭力避免在这些场景下引入 ZooKeeper,在阿里巴巴的生产实践中,应用对 ZooKeeper 申请使用的时候要进行严格的场景、容量、SLA 需求的评估。
所以可以使用 ZooKeeper,但是大数据请向左,而交易则向右,分布式协调向左,服务发现向右。
参考:谈谈注册中心 zookeeper 和 eureka中的CP和 AP - 胖大星- - 博客园
redis
- redis数据结构底层实现
redis数据结构底层实现_凡凡轶崔的博客-CSDN博客 - 内存过期策略
Redis的过期策略以及内存淘汰机制_Felix-CSDN博客_redis的内存淘汰策略
定期删除、惰性删除 - 内存淘汰策略
1、noeviction:添加数据时,如果redis判断该操作会导致占用内存大小超过内存限制,就返回error,然后啥也不干
2、allkeys-lru:添加数据时,如果redis判断该操作会导致占用内存大小超过内存限制,就会扫描所有的key,淘汰一些最近未使用的key
3、volatile-lru:添加数据时,如果redis判断该操作会导致占用内存大小超过内存限制,扫描那些设置里过期时间的key,淘汰一些最近未使用的key
4、allkeys-random:添加数据时,如果redis判断该操作会导致占用内存大小超过内存限制,就会扫描所有的key,随机淘汰一些key
5、volatile-random:添加数据时,如果redis判断该操作会导致占用内存大小超过内存限制,扫描那些设置里过期时间的key,随机淘汰一些key
6、volatile-ttl:添加数据时,如果redis判断该操作会导致占用内存大小超过内存限制,扫描那些设置里过期时间的key,淘汰一些即将过期的key
7、volatile-lfu:添加数据时,如果redis判断该操作会导致占用内存大小超过内存限制,就会淘汰一些设置了过期时间的,并且最近最少使用的key
8、allkeys-lfu:添加数据时,如果redis判断该操作会导致占用内存大小超过内存限制,就会扫描所有的key,淘汰一些最近最少使用的key
- redis为何单线程 效率还这么高 为何使用跳表不使用B+树做索引(阿里) - aspirant - 博客园
- redis为什么能支持10W+qps?
Redis为什么这么快
1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。
2、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU;
3、使用多路I/O复用模型,非阻塞IO;
4、使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;多路 I/O 复用模型
多路I/O复用模型是利用 select、poll、epoll 可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。
单线程redis和多核CPU
单一线程也只能用到一个CPU核心,所以可以在同一个多核的服务器中,可以启动多个实例,组成master-master或者master-slave的形式,耗时的读命令可以完全在slave进行。
-
IO模型
Linux IO模型漫谈(2)-阿里云开发者社区 -
BIO、NIO、AIO
JAVA BIO与NIO、AIO的区别(这个容易理解) -
select,poll,epoll区别
select的本质是采用32个整数的32位,即32* 32= 1024来标识,fd值为1-1024。当fd的值超过1024限制时,就必须修改FD_SETSIZE的大小。这个时候就可以标识32* max值范围的fd。
对于单进程多线程,每个线程处理多个fd的情况,select是不适合的。
1.所有的线程均是从1-32*max进行扫描,每个线程处理的均是一段fd值,这样做有点浪费
2.1024上限问题,一个处理多个用户的进程,fd值远远大1024
所以这个时候应该采用poll,
poll传递的是数组头指针和该数组的长度,只要数组的长度不是很长,性能还是很不错的,因为poll一次在内核中申请4K(一个页的大小来存放fd),尽量控制在4K以内,
epoll还是poll的一种优化,返回后不需要对所有的fd进行遍历,在内核中维持了fd的列表。select和poll是将这个内核列表维持在用户态,然后传递到内核中。但是只有在2.6的内核才支持。
epoll更适合于处理大量的fd ,且活跃fd不是很多的情况,毕竟fd较多还是一个串行的操作
聊聊IO多路复用之select、poll、epoll详解 - mingaixin - 博客园select
诞生于2000年左右,系统调用的原型函数为:
#include <sys/select.h> int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
IO多路复用这种IO模式,它所复用的是处理线程,也就是复用了“哪个IO就绪了,可以处理哪个IO了”这个过程。它是通过监控文件描述符(file descriptor, fd)来实现,如果有一个或以上的文件描述符处于“就绪”(ready)状态,就返回其中一个即可。
那么,这些fd在系统内核中是通过何种数据结构存储的呢?是通过bitmap存放的(数据结构为fd_set),它默认大小是1024(对于64bit有2048个)。因此,对于大于1024的fd,基本效果就不可控了,这客观限制了并发量的上限。
因此,总结一下select的问题:fd存储数据结构的存储上限对高并发非常不友好;
轮询的时间复杂度是O(n)
涉及较多用户态和内核态拷贝
poll
poll对select有了些许改进,如修正了fd数量的上限等等,但其他改进的幅度不大,此处不详谈。epoll
epoll最初的版本是在2.5.44,后来在2.6的版本后陆续稳定。epoll的诞生就是为了解决历史遗留问题,因此,epoll的优势主要有:1)修正了fd数量的限制
2)放弃使用bitmap数据结构,底层改用了链表、红黑树.
3)采用事件驱动
4)无需重复拷贝fd
IO多路复用的select, poll, epoll之间的区别和联系总结_技术笔记-CSDN博客 -
redis 主从复制流程
1 全量同步
Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份。具体步骤如下:
1)从服务器连接主服务器,发送SYNC命令;
2)主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
3)主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
4)从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
5)主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
6)从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
完成上面几个步骤后就完成了从服务器数据初始化的所有操作,从服务器此时可以接收来自用户的读请求。
2 增量同步
Redis增量复制是指Slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程。
增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。
3 Redis主从同步策略
主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
4 注意点
如果多个Slave断线了,需要重启的时候,因为只要Slave启动,就会发送sync请求和主机全量同步,当多个同时出现的时候,可能会导致Master IO剧增宕机。
-
复制功能实现?redis从机器断线重连过程?
分为两个版本,2.8之前仅支持sync全量同步,2.8版本及之后支持psync部分重同步。
2.8之前:
1)从服务器向主服务器发送sync命令,主服务器收到sync命令后执行bgsave命令,在后台生成RDB文件,并使用一个发送缓冲区记录从现在开始执行的所有写命令。
2)主服务器执行bgsave完毕后,主服务器会将RDB文件发送给从服务器,从服务器接收并载入RDB文件,将自己的数据库状态同步到执行bgsave命令时的状态。
3)主服务器将记录在自己发送缓冲区的所有写命令发送给从服务器,从服务器接收这些写命令,将自己的数据库状态更新至主服务器当前所处的状态。
2.8及之后:
1)从服务器在初次同步后会记录主服务器的runID,当从服务器断线重连时,从服务器向主服务器发送之前保存的runID,如果与主服务器的runID不同则必须执行完整重同步操作。如果与主服务器runID相同,则可能会执行部分重同步操作。
2)从服务器重连主服务器发送psync命令,会同时将自己的复制偏移量一同发送过去。确认runID后,判断如果复制偏移量之后的数据还在主服务器维护的一个复制积压缓冲区(长度固定,FIFO,默认1MB,可通过repl-backlog-size调节大小,一般设为2*second平均多少秒重连到主库*write_size_per_second每秒写入数据量)中,那么主服务器将给从服务器发送+COTINUE回复,表示将以部分同步的方式进行。如果offset偏移量之后的数据不在复制缓冲区内则主服务器对从服务器执行全量重同步操作(同上)。
3)若部分重同步,则主服务器会将offset偏移量之后的数据都发送给从服务器,从服务器接收后将回到与主服务器一致的状态 -
哨兵模式故障转移
计算机网络
- 三次握手四次挥手
- TIME_WAIT 和 CLOSE_WAIT 的区别。
TIME_WAIT状态就是用来重发可能丢失的ACK报文。
TIME_WAIT是客户端的状态,CLOSE_WAIT 是服务端的状态。 -
HTTP 响应码,比如 200, 302, 404。
1xx:信息,请求收到,继续处理
2xx:成功,行为被成功地接受、理解和采纳
3xx:重定向,为了完成请求,必须进一步执行的动作
4xx:客户端错误,请求包含语法错误或者请求无法实现
5xx:服务器错误,服务器不能实现一种明显无效的请求
200 ok 一切正常
302 Moved Temporatily 文件临时移出
404 not found
Http响应码及其含义--摘自apache官网 - gavin_jin的个人空间 - OSCHINA - 中文开源技术交流社区 -
Reactor模式
Reactor是一种基于事件驱动的设计模式,Reactor模式首先是事件驱动的,有多个输入源,有多个不同的EventHandler来处理不同的请求,Initiation Dispatcher用于管理EventHander,EventHandler首先要注册到Initiation Dispatcher中,然后Initiation Dispatcher根据输入的Event分发给注册的EventHandler;然而Initiation Dispatcher并不监听Event的到来,这个工作交给Synchronous Event Demultiplexer来处理。
Reactor模式结构如下:
Handle:即操作系统中的句柄,是对资源在操作系统层面上的一种抽象,它可以是打开的文件、一个连接(Socket)、Timer等。由于Reactor模式一般使用在网络编程中,因而这里一般指Socket Handle,即一个网络连接(Connection,在Java NIO中的Channel)。这个Channel注册到Synchronous Event Demultiplexer中,以监听Handle中发生的事件,对ServerSocketChannnel可以是CONNECT事件,对SocketChannel可以是READ、WRITE、CLOSE事件等。
Synchronous Event Demultiplexer:阻塞等待一系列的Handle中的事件到来,如果阻塞等待返回,即表示在返回的Handle中可以不阻塞的执行返回的事件类型。这个模块一般使用操作系统的select来实现。在Java NIO中用Selector来封装,当Selector.select()返回时,可以调用Selector的selectedKeys()方法获取Set<SelectionKey>,一个SelectionKey表达一个有事件发生的Channel以及该Channel上的事件类型。上图的“Synchronous Event Demultiplexer ---notifies--> Handle”的流程如果是对的,那内部实现应该是select()方法在事件到来后会先设置Handle的状态,然后返回。不了解内部实现机制,因而保留原图。
Initiation Dispatcher:用于管理Event Handler,即EventHandler的容器,用以注册、移除EventHandler等;另外,它还作为Reactor模式的入口调用Synchronous Event Demultiplexer的select方法以阻塞等待事件返回,当阻塞等待返回时,根据事件发生的Handle将其分发给对应的Event Handler处理,即回调EventHandler中的handle_event()方法。
Event Handler:定义事件处理方法:handle_event(),以供InitiationDispatcher回调使用。
Concrete Event Handler:事件EventHandler接口,实现特定事件处理逻辑。
Reactor模块之间的交互1. 初始化InitiationDispatcher,并初始化一个Handle到EventHandler的Map。
2. 注册EventHandler到InitiationDispatcher中,每个EventHandler包含对相应Handle的引用,从而建立Handle到EventHandler的映射(Map)。
3. 调用InitiationDispatcher的handle_events()方法以启动Event Loop。在Event Loop中,调用select()方法(Synchronous Event Demultiplexer)阻塞等待Event发生。
4. 当某个或某些Handle的Event发生后,select()方法返回,InitiationDispatcher根据返回的Handle找到注册的EventHandler,并回调该EventHandler的handle_events()方法。
5. 在EventHandler的handle_events()方法中还可以向InitiationDispatcher中注册新的Eventhandler,比如对AcceptorEventHandler来,当有新的client连接时,它会产生新的EventHandler以处理新的连接,并注册到InitiationDispatcher中。
LevelDB
- LevelDB底层原理Leveldb实现原理 - 下潜z - 博客园
Flink
- Flink、Storm、Spark区别
低延迟:Storm>Flink>Spark
高吞吐:Spark>Flink>Storm
容错性:Storm:(ACK),Spark、Flink:(Check Point)Flink及Storm、Spark主流流框架比较_扎克begod的专栏-CSDN博客_flink spark storm 对比综合对比spark、storm和flink的功能、容错和性能(总结如下图)
不难发现, flink是一个设计良好的框架,它不但功能强大,而且性能出色。此外它还有一些比较好设计,比如优秀的内存管理和流控。但是,flink目前成熟度较低,还存在着不少问题,比如 SQL支持比较初级;无法像storm一样在不停止任务的情况下动态调整资源;不能像spark一样提供很好的streaming和static data的交互操作等。
-
窗口计算
Flink(十)窗口计算_又小雨的博客-CSDN博客_flink窗口计算
HBase
- 架构与原理我终于看懂了HBase,太不容易了... - 知乎
- HBase是一个NoSQL数据库,一般我们用它来存储海量的数据(因为它基于HDFS分布式文件系统上构建的)
- HBase的一行记录由一个RowKey和一个或多个的列以及它的值所组成。先有列族后有列,列可以随意添加。
- HBase的增删改记录都有「版本」,默认以时间戳的方式实现。
- RowKey的设计如果没有特殊的业务性,最好设计为散列的,这样避免热点数据分布在同一个HRegionServer中。
- HBase的读写都经过Zookeeper去拉取meta数据,定位到对应的HRegion,然后找到HRegionServer
- HMaster会处理 HRegion 的分配或转移。如果我们HRegion的数据量太大的话,HMaster会对拆分后的Region重新分配RegionServer。(如果发现失效的HRegion,也会将失效的HRegion分配到正常的HRegionServer中)。即HMaster会处理元数据的变更和监控RegionServer的状态。
最后
以上就是敏感小笼包为你收集整理的个人学习易忘点汇总JavaMySql分布式事务ElasticSearchKafkaSpringSpring CloudRPC框架注册中心 zk、eurekaredis计算机网络LevelDBFlinkHBase的全部内容,希望文章能够帮你解决个人学习易忘点汇总JavaMySql分布式事务ElasticSearchKafkaSpringSpring CloudRPC框架注册中心 zk、eurekaredis计算机网络LevelDBFlinkHBase所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复