Docker 常用配置

Kafka Kafdrop services: kafdrop: image: obsidiandynamics/kafdrop container_name: kafdrop ports: - "9000:9000" environment: KAFKA_BROKERCONNECT: "localhost:9092" SERVER_SERVLET_CONTEXTPATH: "/" restart: unless-stopped KRaft 模式 services: kafka: image: apache/kafka:3.9.0 container_name: kafka hostname: kafka ports: - "9092:9092" environment: KAFKA_NODE_ID: 1 KAFKA_PROCESS_ROLES: broker,controller KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093 # 注意:这里不要换行,不要逗号 KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093 # 外部访问地址 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 CLUSTER_ID: MkU3OEVBNTcwNTJENDM2Qk volumes: - ./data:/var/lib/kafka/data restart: unless-stopped

2026-07-09 11:04:37 AM · 1 分钟

Java GC 是如何驱赶“老年群体”的

在 Java 的世界里,“分代年龄”(Age) 是专门为 JVM 垃圾回收(GC)设计的一个计数器。 简单来说,它记录了一个 Java 对象在垃圾回收中活过了多少轮。就像打游戏刷副本一样,对象每在垃圾回收的“清洗”中幸存下来一次,它的分代年龄就会 +1。 1. 为什么需要“分代年龄”? 这源于 Java 垃圾回收领域著名的 弱分代假说(Weak Generational Hypothesis): 绝大多数的 Java 对象都是“朝生夕死”的。 比如你在一个方法里 new 了一个局部变量,方法结束了,这个对象就没用了。但也有极少数对象(如 Spring 的 Bean、数据库连接池)会一直存活。 为了高效管理内存,JVM 把堆内存分成了两大区域: 新生代(Young Generation): 存放刚出生、寿命短的对象。 老年代(Old Generation): 存放寿命长、常驻内存的对象。 “分代年龄”就是对象从“新生代”晋升到“老年代”的资格证和进度条。 2. 它的工作流程是怎样的? 我们可以把新生代想象成一个“新手村”,老年代想象成“满级主城”: 出生(0岁): 绝大多数新对象在新生代的 Eden(伊甸园)区 出生。 第一次渡劫(1岁): 发生了一次 Minor GC(新生代垃圾回收)。如果这个对象没被回收,它会幸存下来,被移动到 Survivor(幸存者)区,同时它的分代年龄变成 1 岁。 继续熬资历(每活过一轮 +1岁): 以后每发生一次 Minor GC,只要它还在幸存者区折腾且没死掉,它的年龄就会加 1 岁。 晋升老年代: 当它的年龄达到一定阈值(默认是 15 岁,由 JVM 参数 -XX:MaxTenuringThreshold 决定)时,JVM 就会认为:“这小伙子挺能活,应该是个核心常驻对象。” 于是把它晋升(Promote)到老年代。 3. 它存在对象的什么地方? 正如我们在讨论“锁”时提到的,分代年龄存在于每个 Java 对象的 对象头(Object Header)的 Mark Word 里面。 ...

2026-07-09 10:19:20 AM · 1 分钟

为什么每个java对象都有锁的属性?这样不是浪费内存吗

1. 为什么当初要这样设计?(设计初衷) Java 诞生于 20 世纪 90 年代中期,当时多线程编程(并发)正在兴起。Java 的设计者高斯林(James Gosling)希望 Java 成为一门简单易用的多线程语言。 简化并发编程 如果对象没有内置锁,你每次想给一段代码加锁,都必须显式地创建一个 Lock 对象: // 如果没有内置锁,你得这么写: Lock myLock = new ReentrantLock(); void doSomething() { myLock.lock(); try { // 业务逻辑 } finally { myLock.unlock(); } } 而 Java 设计者引入了 synchronized 关键字,直接让对象充当锁,把复杂的同步简化成了: // 极简的同步写法 synchronized(this) { // 业务逻辑 } “万物皆对象,万物皆可为锁”的设计,让开发者不需要管理一堆乱七八糟的锁对象,只要拿到目标对象,就能直接进行同步控制。 2. 这样不浪费内存吗?JVM 是怎么“偷懒”的? 你担心的内存浪费,JVM 工程师早就想到了。他们绝对不会傻到给每个刚 new 出来的对象都分配一个沉重的操作系统级别的锁(Monitor)。 JVM 解决这个问题的核心思路是:按需分配,动态升级。 秘密武器:对象头(Object Header) 在 Java 中,每个对象的内存结构里都有一个叫 Mark Word(标记字) 的区域(在 64 位虚拟机上占 8 个字节 / 64 位)。 ...

2026-07-09 10:11:43 AM · 1 分钟

H mod C = H & (C - 1) ?

在 Java 后端开发面试或源码阅读中,HashMap 永远是避不开的核心。很多人能熟练地背出它的扩容阈值、红黑树化条件,但当深入到源码底层,看到诸如 e.hash & (newCap - 1) 和 e.hash & oldCap 这样的位运算时,往往会陷入沉思。 一、 起源:为什么数组长度必须是 2 的次幂? 在散列表中,为了让数据均匀分布,最直观的想法是对哈希值进行取模(求余数): $$\text{索引位置} = \text{hash} \pmod{\text{Capacity}}$$然而,在 CPU 的底层底层执行中,除法和取模(%)是非常昂贵的算术操作(可能需要几十个时钟周期)。为了追求极致的性能,底层的数论定理为我们提供了一个完美的替代方案: 数学定理:当容量 $C$ 是 $2$ 的次幂($2^n$)时,对于任意整数 $H$,满足: $$H \pmod C \equiv H \ \& \ (C - 1)$$ 位运算(&)在 CPU 中只需要 1 个时钟周期!为了享受到这个性能红利,HashMap 在源码中将容量死死限制为 2 的次幂: // 默认初始容量 16 (2的4次方) static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 裁剪器的魔术:hash & (newCap - 1) 以容量 16 为例,16 - 1 = 15(二进制:0000 1111)。任何 Hash 值与 15 进行 & 运算,高位都会被无情“抹零”,只有最后 4 位被保留下来: ...

2026-07-08 05:38:40 PM · 2 分钟

懒惰的五个层级:你穷,可能不是因为你不努力,而是因为你和所有人一样“努力”

先撕掉一个谎言 你被灌输过一个观念——资源是稀缺的,所以竞争是残酷的,所以你穷是正常的。 这句话每一个字都是错的。 真正的稀缺,几乎从来不是物质的稀缺,而是认知的稀缺。石油曾经是让农田绝收的黑色毒水,稀土曾经是矿渣里没人要的废石,页岩气曾经被写进教科书当作"永远无法开采"的典型。它们不是突然变多了——它们一直在那里,只是人类的技术终于配得上它们了。 所以请记住这个地基,因为后面所有的推理都建立在它之上: 地球的资源上限是未知的,人类的需求是无限的。真正把你困住的,从来不是这个世界没有位置,而是你不知道位置在哪。 明白了这一点,我们才能谈真正的问题——不是资源不够,而是人太懒,并且懒得如此整齐划一。 一、“懒"是人性的底层代码,但懒有段位之分 先说清楚:我说的"懒”,不是道德批判。 懒是人性的默认设置——用最小的付出,换取自己想要的生活。 这没有错,它甚至是效率的本能。真正决定你命运的,不是你懒不懒(你一定懒),而是你懒在哪个段位上。 段位不同,议价能力天差地别。有人懒得一贫如洗,有人懒得财富自由。下面这五层,就是从地狱到天堂的完整阶梯。你现在站在第几层,决定了你现在过什么日子。 flowchart TD A["LV1 懒到活不下去饥饿倒逼求生——不稳定,会被自动弹走"] --> B["LV2 懒到刚好活着被随意替换的螺丝钉——90%的人被困死在这里"] B --> C["LV3 拒绝被剥削看清了机制,愤怒觉醒——但光愤怒没用"] C --> D["LV4 转向勤奋逃离红海,构筑不可替代性——真正的分水岭"] D --> E["LV5 明知的勤奋哪里空缺补哪里——从心所欲不逾矩"] style A fill:#3a1c1c,stroke:#e57373,color:#fff style B fill:#3a2e1c,stroke:#ffb74d,color:#fff style C fill:#3a3a1c,stroke:#fff176,color:#fff style D fill:#1c3a24,stroke:#81c784,color:#fff style E fill:#1c2e3a,stroke:#64b5f6,color:#fff 二、五层地狱与天堂 LV1|懒到活着都成问题——这一层留不住人 理论上存在,现实中几乎没人能停在这里。 原因很简单:再懒的人也要吃饭睡觉,这是生理的铁律。 当你懒到把自己饿倒的地步,饥饿会立刻接管你的身体,把"逃离饥饿"瞬间转化为"活下去"的暴力驱动。 所以这一层是不稳定的——它自带一个弹射装置,会强行把人推向 LV2。你不需要努力离开它,饥饿会替你完成这件事。 这一层的教训是:纯粹的懒,连活着都做不到。人被迫劳动的第一推动力,是恐惧。 LV2|懒到刚好能活着——90%的人死在这里,而且死得心安理得 这是绝大多数人的段位,也是最危险的段位——因为它足够舒适,舒适到让你放弃挣扎。 刚好能活着,意味着你满足于温饱线上的生活:有口饭吃,有张床睡,还能刷刷手机。你不愿多付出一分,因为"活着"这个目标已经达成了。 但你有没有想过,你为此付出的代价是什么? 代价是:你的劳动彻底丧失了议价能力。 想想供需关系。当你只求"活着",你就等于向市场宣告——我可以被任何一个同样只求活着的人替换。而这样的人,遍地都是。你不是稀缺品,你是标准件。资本给标准件定价,从来不看你付出了多少,只看换掉你要花多少成本。而换掉你,几乎零成本。 这才是剥削的真相:剥削不是资本太贪婪,而是你太普通。 你和身边所有人懒在同一条水平线上,你们互为替代品,于是你们集体丧失了定价权。资本只是顺水推舟,开出一个和你真实价值南辕北辙的工资——你还得感恩戴德。 记住这句话:你穷,不是因为你不努力。恰恰是因为你和所有人一样努力。 LV3|懒到绝不承受剥削——觉醒的那一刻,愤怒是有价值的 某个瞬间,你突然看穿了这一切。 你意识到:问题的根源不在于我不够卖力,而在于我和所有人长得一模一样。 正因为大家都懒在同一层,资本才敢肆无忌惮地压价。工资和劳动价值的背离,不是资本坏,是这个位置上的人可以随便换。 这是觉醒。这份愤怒是宝贵的,它是你打破 LV2 舒适麻醉的唯一炸药。 但请注意——光有愤怒,你依然一无所有。 ...

2026-07-08 02:02:47 PM · 1 分钟

限流降级研究笔记 更新中 

主流算法 固定窗口计数器 每秒一个计数器,+1超过阈值就拒绝 缺点 0.51s 和 1.51s 之间产生2倍流量 滑动窗口 把时间切成更细的小格,滑动统计 缺点 解决临界问题,但是实现复杂 漏桶 请求进桶,匀速流出,桶满则弃 缺点流出速度恒定,扛不了正常的突发 令牌桶 匀速往桶里放令牌,来请求拿令牌,没令牌被拒绝 缺点允许一定突发

2026-07-07 04:05:10 PM · 1 分钟

久坐用电脑如何最大程度减少脖子酸痛 更新中 

1. 屏幕高度必须与视线平齐 屏幕上缘应接近或略低于眼睛水平线,禁止长期低头使用设备。 2. 上肢支撑优先于肩部用力 键盘与鼠标位置需确保手肘自然下垂约90度,避免肩部抬起或前伸代偿。 3. 头部位置以“耳朵对肩”为标准 耳朵应位于肩峰正上方或略后方,一旦出现前伸即为错误姿势。 4. 静态坐姿持续时间不得超过45分钟 每30–45分钟必须进行至少30秒站立或活动调整,打断颈部静态负荷。 5. 禁止长时间塌陷式坐姿 避免骨盆后倾、胸椎塌陷及“窝在椅子里”使用电脑的姿势。 6. 每日进行基础颈深屈肌激活训练 执行下巴后收(chin tuck)10次,用于恢复头颈中立位控制能力。 核心原则 保持头颈中立位、减少前伸负荷、避免长时间静态固定。

2026-06-29 03:55:23 PM · 1 分钟

个人总结的一些相机小知识 更新中 

什么是一般连拍和速度优先连拍? 在[速度优先连拍]模式下,当半按下快门按钮时,为第一张影像决定对焦,并且后续拍摄的对焦被锁定。

2026-06-22 10:41:17 PM · 1 分钟

自创memes 更新中 

2026-06-22 11:09:51 AM · 0 分钟

我的高中

2026-06-22 10:37:22 AM · 0 分钟