Skip to content

Commit

Permalink
20241013
Browse files Browse the repository at this point in the history
  • Loading branch information
CompetitiveLin committed Oct 13, 2024
1 parent bd3afc4 commit 3bdbe0a
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 18 deletions.
19 changes: 11 additions & 8 deletions _posts/2022-06-21-java.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,17 +131,19 @@ Java的SPI:SPI 的本质是将接口实现类的全限定名配置在文件中
## 对象的创建过程
1. 类加载检查
2. 分配内存:指针碰撞或空闲列表
- 当多个对象并发争抢空间时,有两种解决办法:CAS 和本地线程分配缓冲(TLAB,默认方式)
- 当多个对象并发争抢空间时,有两种解决办法:CAS 和本地线程分配缓冲(TLAB,默认方式)
3. 初始化零值
4. 设置对象头
5. 执行构造方法

## 对象的内存布局

1. 对象头,两部分组成:存储自身运行时数据如哈希码,GC分代年龄;指向类的类型指针
2. 实例数据,真正存储有效信息的部分
3. 对齐填充,起占位作用

[对象的定位访问(针对JVM虚拟机栈中的局部变量表)](https://javaguide.cn/java/jvm/memory-area.html#%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%AE%BF%E9%97%AE%E5%AE%9A%E4%BD%8D)
## [对象的定位访问(针对JVM虚拟机栈中的局部变量表)](https://javaguide.cn/java/jvm/memory-area.html#%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%AE%BF%E9%97%AE%E5%AE%9A%E4%BD%8D)

1. 句柄,Java 堆中将会划分出一块内存来作为句柄池,局部变量表 reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与对象类型数据各自的具体地址信息。
2. 直接指针,局部变量表里 reference 中存储的直接就是对象的地址。

Expand Down Expand Up @@ -463,11 +465,12 @@ ThreadLocal: 提供线程内的局部变量,在多线程的环境中保证各
线程工厂用于创建新线程。线程工厂提供了创建线程的方法,可以自定义线程的名称、优先级等属性。

7. 拒绝策略(rejectedExecutionHandler):
拒绝策略定义了当线程池无法接受新任务时的处理策略。当工作队列已满且线程池中的线程数已达到最大线程数时,新任务将被拒绝执行。常见的拒绝策略有丢弃、丢弃最旧的任务、抛出异常等。
1. AbortPolicy 拒绝任务并抛出一个异常 RejectedExecutionException
2. DiscardPolicy 拒绝任务,不抛出异常。
3. DiscardOldestPolicy 把老的任务丢掉,执行新任务。
4. CallerRunsPolicy 直接调用线程处理该任务。
拒绝策略定义了当线程池无法接受新任务时的处理策略。当工作队列已满且线程池中的线程数已达到最大线程数时,新任务将被拒绝执行。常见的拒绝策略有丢弃、丢弃最旧的任务、抛出异常等。
1. AbortPolicy 拒绝任务并抛出一个异常 RejectedExecutionException
2. DiscardPolicy 拒绝任务,不抛出异常。
3. DiscardOldestPolicy 把老的任务丢掉,执行新任务。
4. CallerRunsPolicy 直接调用线程处理该任务。




Expand Down Expand Up @@ -521,7 +524,7 @@ JDK四种线程池:
- 非公平锁,每个线程获取锁的顺序是随机的,并不会遵循先来先得的规则,所有线程会竞争获取锁。

5. 可重入锁(递归锁),非可重入锁:ReentrantLock和synchronized都是可重入锁,**NonReentrantLock是非可重入锁**
- 可重入锁,指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提锁对象得是同一个对象或者class),不会因为之前已经获取过还没释放而阻塞。好处是一定程度避免死锁
- 可重入锁,指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法可以再次获取锁(前提锁对象得是同一个对象或者class),不会因为之前已经获取过还没释放而阻塞。好处是避免死锁
- 非可重入锁,如果一个方法中获取锁并调用另外方法,那么在调用另外方法前需要释放锁。

6. 独享锁(排它锁),共享锁
Expand Down
11 changes: 8 additions & 3 deletions _posts/2022-06-22-mysql.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pin: true
单机 QPS 为 4k 左右。

# MySQL select语句执行
- prepare 阶段,检查查询语句中的表活字段是否存在,将 `*` 拓展为表上的所有列。
- prepare 阶段,检查查询语句中的表或字段是否存在,将 `*` 拓展为表上的所有列。
- optimize 阶段,优化器决定使用哪个索引。
- execute 阶段,执行器,索引下推。

Expand Down Expand Up @@ -282,10 +282,15 @@ Binlog 的持久化:

#### Redolog

写入流程:
1. 写入 redo log buffer
2. 写入(write)到 page cache
3. 持久化(fsync)到磁盘中

刷盘时机:
1. MySQL 正常关闭
2. redo log buffer 的写入量大于 redo log buffer 内存空间的一半时
3. 后台线程每隔一秒将 redo log buffer 持久化到磁盘
2. redo log buffer 的写入量大于 redo log buffer 内存空间(默认8MB)的一半时,write 到 page cache 中。
3. 后台线程每隔一秒调用 write 将 redo log buffer 写到 page cache,然后 fsync 持久化到磁盘
4. innodb_flush_log_at_trx_commit 参数
1. 当innodb_flush_log_at_trx_commit=0时,InnoDB会**每秒钟**将log buffer的数据**write**到文件系统缓存中,并调用**fsync**操作将数据缓存更新至磁盘中,与事务的执行与否无关。因此,在实例崩溃恢复场景中,可能会出现丢失1秒钟的事务。
2. 当innodb_flush_log_at_trx_commit=1时,InnoDB将在**每次事务提交**时将log buffer的数据**write**到文件系统缓存中,并调用**fsync**操作将数据缓存更新至磁盘中。此种方式下,数据库完全遵守ACID特性,安全性较高。
Expand Down
2 changes: 1 addition & 1 deletion _posts/2023-07-06-redis.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ Redis的删除策略是**惰性删除+定期删除**。定期删除如果检查
2. 进行数据淘汰
1. 在设置了过期时间的数据中进行淘汰
- volatile-random: 随机淘汰设置了过期时间的任意键值;
- volatile-ttl:优先淘汰更早过期的键值。
- volatile-ttl:优先淘汰离过期时间最近的键值;
- volatile-lru:淘汰所有设置了过期时间的键值中,最久未使用的键值;
- volatile-lfu:淘汰所有设置了过期时间的键值中,最少使用的键值;
2. 在所有数据范围内进行淘汰
Expand Down
4 changes: 2 additions & 2 deletions _posts/2023-08-11-springboot.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ Prototype(原型)对象和单例对象的区别:
- @SpringBootApplication 包含三个注解:
1. @SpringBootConfiguration, 继承@Configuration,标注当前类是配置类,并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例注册到spring容器中,并且实例名就是方法名。
2. [@EnableAutoConfiguration](https://www.cnblogs.com/kevin-yuan/p/13583269.html),主要由 @AutoConfigurationPackage@Import(EnableAutoConfigurationImportSelector.class)这两个注解组成的。
- @AutoConfigurationPackage 内部是 @({Registrar.class}),用于将启动类所在的包里面的所有组件注册到spring容器。扫描 @Entity, @Mapper 等第三方依赖注解。
- @Import(EnableAutoConfigurationImportSelector.class) 是将特定路径(META-INF/spring.factories)中所有符合自动配置条件(@ConditionalOnClass)的类加载到Ioc容器,例如mybatis-spring-boot-starter。`AutoConfigurationImportSelector.java` 中可以看到所有自动配置类的名称。[自动配置类原理](https://juejin.cn/post/7101477895331135495)
1. @AutoConfigurationPackage 内部是 @({Registrar.class}),用于将启动类所在的包里面的所有组件注册到spring容器。扫描 @Entity, @Mapper 等第三方依赖注解。
2. @Import(EnableAutoConfigurationImportSelector.class) 是将特定路径(META-INF/spring.factories)中所有符合自动配置条件(@ConditionalOnClass)的类加载到Ioc容器,例如mybatis-spring-boot-starter。`AutoConfigurationImportSelector.java` 中可以看到所有自动配置类的名称。[自动配置类原理](https://juejin.cn/post/7101477895331135495)
3. @ComponentScan,自动扫描并加载被@Component@Repository修饰的组件,最终将这些组件加载到容器中,默认路径是该注解所在类的package。


Expand Down
30 changes: 29 additions & 1 deletion _posts/2023-08-25-kafka-vs-rocketmq.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Page Cache(页面缓存)从内存中划出一块区域缓存文件页,如

- Broker: 同步刷盘;设置主从模式,配置副本

- Consumer: At least Once 的消费机制;消费重试;ACK机制;手动提交位移(Kafka)
- Consumer: At least Once 的消费机制;消费重试;手动提交偏移量(Kafka)


## 零拷贝
Expand Down Expand Up @@ -299,6 +299,23 @@ RocketMQ/Kafka 使用 Consumer Group 机制,实现了传统两大消息引擎

一个Topic分为多个Partition,一个Partition分为多个Segment。每个Segment对应三个文件:偏移量索引文件、时间戳索引文件、消息存储文件

## 根据偏移量/时间戳查找消息

![](https://raw.githubusercontent.com/CompetitiveLin/ImageHostingService/picgo/imgs/202410121820230.png)

偏移量文件中记录的是**稀疏索引**

### 偏移量 offset = x
1. 根据偏移量索引文件名和 offset 的值,进行二分查找,找到小于 x 的最大 offset 文件
2. 在该偏移量索引文件(.index)中,找到改 offset 对应的 position 位置
3. 在消息存储文件(.log)中,找到该 position 所对应的消息内容


### 时间戳 timestamp = t
1. 在时间戳索引文件(.timeindex)中,找到比 t 大的最小时间戳,与其所对应的 offset 值
2. 在偏移量索引文件(.index)中,找到该 offset 值对应的 position 位置
3. 在消息存储文件(.log)中,找到该 position 所对应的消息内容

## Producer 生产消息的流程
在消息发送的过程中,涉及到两个线程,main线程和sender线程,其中main线程是消息的生产线程,而sender线程是jvm单例的线程,专门用于消息的发送。在jvm的内存中开辟了一块缓存空间叫RecordAccumulator(消息累加器),用于将多条消息合并成一个批次,然后由sender线程发送给kafka集群。

Expand Down Expand Up @@ -347,3 +364,14 @@ Controller 用于在 ZK 的帮助下管理和协调整个 Kafka 集群。集群
3. 集群 Broker 管理
4. 数据服务,保存最完整的元数据信息

## 手动/自动提交偏移量区别

![](https://raw.githubusercontent.com/CompetitiveLin/ImageHostingService/picgo/imgs/202410121609254.png)

发生 Rebalance 时,自动提交偏移量有可能出现消息丢失/消息重复消费的问题,而手动提交偏移量则不会
1. 消息丢失:提交的偏移量**大于**消费者处理的最后一个消息的偏移量
2. 消费重复消费:提交的偏移量**小于**消费者处理的最后一个信息的偏移量




21 changes: 19 additions & 2 deletions _posts/2023-09-07-note-from-work.md
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,13 @@ SSL 加密是绝对安全的,但是 HTTPS 并不是绝对安全的,可以通

## 进程和线程

### 进程拥有的资源
1. 进程控制块
2. 文件描述符
3. 网络连接
4. 设备


区别:
1. 进程是系统资源分配的最小单位,实现了操作系统的并发;线程是CPU调度的最小单位,实现了进程内部的并发。
2. 进程在执行过程中拥有独立的内存单元,而多个线程共享进程的内存。
Expand Down Expand Up @@ -466,7 +473,7 @@ DNS 在进行区域传输的时候使用 TCP,其他情况使用 UDP。
7. 流量控制:滑动窗口实现

## OSI 七层模型和 TCP/IP 四层模型
1. 应用层:HTTP,DNS,FTP;网关
1. 应用层:HTTP,DNS,FTP,WebSocket;网关
1. 应用层
2. 表示层
3. 会话层
Expand Down Expand Up @@ -546,4 +553,14 @@ CPU 占用排查:使用 `top` 和 `top -Hp xxx` 命令定位占用率最高的
# 缓存 IO,直接 IO,裸 IO
- 缓存IO:读数据时先从内核空间的缓冲区读,如果没有则从磁盘中读并缓存到缓冲区;写数据将用户空间的数据复制到内核空间的缓冲区,并标记为脏页,操作系统后台将脏页写入磁盘中,一般用于频繁读写的小文件;
- 直接IO:直接读写文件,而不经过内核缓冲区,目的是减少一次内核缓冲区到用户程序缓存的数据复制,一般用于不需要频繁读写的大文件;
- 裸IO:绕过文件系统,直接读写磁盘块设备数据,一般用于数据库;
- 裸IO:绕过文件系统,直接读写磁盘块设备数据,一般用于数据库;

# Base64 和 Base62 的区别

## 编码
1. Base64:26 个大写字母 + 26 个小写字母 + 10 个数字 + `+` + `/`;并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的「/」和「+」字符变为形如「%XX」的形式。
2. Base62:26 个大写字母 + 26 个小写字母 + 10 个数字。

## 实现
1. Base64:将输入字符串按字节切分,取得每个字节对应的二进制值(若不足 8 比特则高位补 0),然后将这些二进制数值串联起来,再按照 6 比特一组进行切分(因为 2^6=64),最后一组若不足 6 比特则末尾补 0。若原字节序列数据长度不是 3 的倍数时且剩下 1 个输入数据,则在编码结果后加 2 个 =;若剩下 2 个输入数据,则在编码结果后加 1 个 =。将每组二进制值转换成十进制,然后找到对应的符号并串联起来就是 Base64 编码结果。
2. Base62:将输入字符串哈希后转成长整型,再用**62进制**编码成Base62格式。
9 changes: 8 additions & 1 deletion _posts/2024-02-27-go.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,11 @@ func main() {
## Byte 和 Rune 类型

- byte是uint8的别称,一个值就是一个ASICII码的值,占 1 个字节的英文类字符,使用 byte
- rune是int32的别称,一个值就是一个Unicode字符,占 1 ~ 4 个字节的其他字符,可以使用rune(或者int32),如中文、特殊符号等。
- rune是int32的别称,一个值就是一个Unicode字符,占 1 ~ 4 个字节的其他字符,可以使用rune(或者int32),如中文、特殊符号等。

## 内存对齐

### 好处
1. 平台原因:不是所有的硬件平台都能访问任意地址上的任意数据的,某些硬件平台只能在某些地址处取某些特定类型的数据
2. [提高访问效率](https://www.cnblogs.com/zongqingmeng/p/14620740.html):考虑到 CPU 是分块读取数据的,假设一次性读取4字节的数据,如果不进行内存对齐,则需要多次读取内存中的数据,再进行剔除等操作,极大降低CPU性能。

0 comments on commit 3bdbe0a

Please sign in to comment.