一些细碎的资料记录

11 阅读9分钟

关于Kafka

kafka.apache.org/documentati…

  1. 版本

最新版本 kafka_2.13-4.0.0 其中 2.13 是 scala 版本

0.7, 0.8, 0.9, 0.10, 0.11, 1.0, 1.1, 2.0.X, 2.1.X, 2.2.X, 2.3.X, 2.4.X, 2.5.X, 2.6.X, 2.7.X, 2.8.X, 3.0.X, 3.1.X, 3.2.X, 3.3.X, 3.4.X, 3.5.X, 3.6.X, 3.7.X, 3.8.X, 3.9.X.

  1. 概念

Topic 主题

Partition 分区 :

  • 每个 Topic 可以分为多个分区,可以提供消息的并发量;
  • 每个分区都可以有多个副本
  • 消息在每个分区里是有序的

生产者组

消费者组

  • 消息的状态被保存在consumer中,broker不会关心哪个消息被消费了被谁消费了,只记录一个offset值(指向partition中下一个要被消费的消息位置)
  • Producer只管向broker push消息,consumer只管从broker pull消息
  1. 思考点
  • 高性能实现
  • rebalance 机制
  • 消息幂等性处理
  • 顺序消息的实现

wait() notify() 和 notifyAll()

  • 如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
  • 当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争。
  • 优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。

命令式编程(Imperative) vs声明式编程( Declarative)

  • 命令式编程(Imperative):详细的命令机器怎么(How)去处理一件事情以达到你想要的结果(What);
  • 声明式编程( Declarative):只告诉你想要的结果(What),机器自己摸索过程(How)

SQL语言就是很典型的声明式编程语言

正则表达式(regular expressions)或者逻辑语言(Prolog)为声明式语言

常见的设计模式

创建型: 创建对象时,不再由我们直接实例化对象;而是根据特定场景,由程序来确定创建对象的方式,从而保证更大的性能、更好的架构优势。创建型模式主要有工厂方法、抽象工厂模式、单例模式、生成器模式和原型模式

结构型: 用于帮助将多个对象组织成更大的结构。结构型模式主要有适配器模式adapter、桥接模式bridge、组合器模式component、装饰器模式decorator、门面模式、亨元模式flyweight和代理模式proxy

行为型: 用于帮助系统间各对象的通信,以及如何控制复杂系统中流程。行为型模式主要有命令模式command、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式state、策略模式、模板模式和访问者模式


类模式:用于处理类与子类之间的关系,这些关系通过继承来建立,是静态的,在编译时便确定下来了;工厂方法、适配器、模板方法、解释器

对象模式:用户处理对象之间关系的,这些关系可以通过组合或聚合来实现,在运行时刻是可以变化的,更具动态性。

happens-before

happens-before 是JMM最核心的概念。对应Java程序员来说,理解happens-before是理解JMM的关键。

happens-before(先行发生)是Java中一个重要的多线程概念,用于描述不同线程之间操作的执行顺序。它是Java内存模型(Java Memory Model)中的一部分

在Java中,如果一个操作happens-before另一个操作,那么第一个操作的结果将对第二个操作可见,即第二个操作可以看到第一个操作的影响。

解释什么是 happens-before

死锁的四个必要条件

  • 互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源
  • 请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放
  • 不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
  • 环路等待条件:是指进程发生死锁后,若干进程之间形成一种头尾相接的循环等待资源关系
在Java开发中,死锁常发生在多线程资源竞争的场景中,以下是几种典型场景及示例:

一、锁顺序不当引发的死锁
当多个线程以不同的顺序请求多个锁时,容易形成循环等待。例如:

转账场景:线程A先锁账户A再请求账户B,线程B先锁账户B再请求账户A,导致互相等待。
动态锁顺序:若锁顺序由外部输入决定(如随机选择转账账户),可能打破固定顺序规则,导致死锁。
二、循环资源竞争
典型场景是哲学家就餐问题,多个线程(哲学家)同时竞争相邻资源(筷子),且每个线程持有资源并等待下一个资源释放。例如:

5个线程各自持有1个资源并等待下一个,形成环形依赖。
三、事务中的资源竞争
在数据库操作中,若多个事务以不同顺序获取表锁或行锁,可能触发死锁:

订单与库存场景:事务A先锁库存表再锁订单表,事务B先锁订单表再锁库存表,导致互等。
长时间事务:事务持有锁时执行复杂业务逻辑,其他事务被迫长时间等待。
四、协作对象间的锁嵌套
当调用外部方法时未释放当前锁,可能与其他线程形成嵌套死锁:

车队调度案例:线程A持有出租车锁并调用调度方法(需获取调度锁),而线程B持有调度锁并尝试获取出租车锁。
五、线程通信机制错误
若线程间互相等待通知,例如线程A等待线程B的信号,同时线程B也在等待线程A的信号,会导致双方永久阻塞。

如何避免这些场景
统一锁顺序:强制所有线程按固定顺序获取锁(如按资源ID排序)。
超时机制:使用
tryLock()
设置超时,放弃等待后重试。
减少锁粒度:拆分大锁为多个小锁,降低竞争概率。
事务优化:缩短事务持有锁的时间,避免跨表操作的顺序冲突。
具体案例分析可参考:转账死锁示例 、哲学家问题代码 。

atomic 的原理

AtomicX -> private static final Unsafe U = Unsafe.getUnsafe();

Unsafe 类是 Java 中一个提供低级别操作能力的工具类,它允许开发者直接对内存进行读写,以及执行其他一些类似于 C 语言的底层操作。这些功能使得 Java 在运行效率和底层资源操作能力方面得到了增强。然而,由于 Unsafe 类提供了指针操作内存空间的能力,使用不当可能会带来程序错误的风险,因此在使用时需要格外小心。

CAS 操作 避免了锁竞争

动态代理

JDK动态代理是Java原生的代理实现方式,它要求被代理的目标类必须实现接口。JDK动态代理通过反射机制,利用InvocationHandler和Proxy类,为目标接口生成一个实现该接口的代理类。

CGLIB动态代理则不同,它不要求目标类实现任何接口,因为它是通过继承目标类的方式来创建代理对象。CGLIB(Code Generation Library)是一个第三方代码生成库,它通过底层的字节码技术,动态生成目标类的子类,并在子类中拦截所有方法的调用。

缓存穿透

缓存穿透是指客户端请求的数据既不在缓存中,也不在数据库中,导致每次请求都直接到达数据库。这种情况通常发生在恶意用户构造无效请求时,可能会导致数据库压力过大,甚至崩溃。解决缓存穿透的方法包括:

  • 使用布隆过滤器来过滤无效请求。
  • 对请求参数进行合法性校验,确保请求的数据在数据库中存在。
  • 对频繁请求的无效数据进行限流,减少对数据库的压力

G1(Garbage-First)

G1自JDK9起成为默认GC

  • 基于 “标记-整理” 算法,收集后不会产生内存碎片。
  • 可以非常精确控制停顿时间,在不牺牲吞吐量前提下,实现低停顿垃圾回收。

G1 垃圾收集器将堆内存划分为若干个 Region,每个 Region 分区只能是一种角色,Eden区、S区、老年代O区的其中一个,空白区域代表的是未分配的内存,最后还有个特殊的区域H区(Humongous),专门用于存放巨型对象,如果一个对象的大小超过Region容量的50%以上,G1 就认为这是个巨型对象。

每个 Region 分区 分配了一个 RSet(Remembered Set),它内部类似于一个反向指针,记录了其它 Region 对当前 Region 的引用情况,这样就带来一个极大的好处:回收某个Region时,不需要执行全堆扫描,只需扫描它的 RSet 就可以找到外部引用,来确定引用本。G1 每次 GC 时 所有的新生代都会被扫描,因此引用源是年轻代的对象不需要在RSet中记录;所以最终只需要记录老年代到新生代之间的引用即可

MySQL 事务、锁、索引

Spring

Arthas

Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率

trace demo.MathGame run

关于代码质量

Sonar代码质量扫描

分布式事务(Seata、2PC、3PC、TCC)