Guava 解析
前言 Guava 本身适配不同的环境,Jdk 1.8 以上使用 jre flavor,Jdk 1.7 和 android 使用 android flavor。 类库的作者,不要使用 @Beta 成员,以后它们不会是 source-compatible。但我们可以使用其他成员,它们会是 binary-compatible,Guava 现在不会再因为非安全原因删除成员了,即使是 @Deprecated 的。 可用的功能见这个 User Guide。 common Collect 不可变集合 Guava 提供了强类型的不可变集合,这些集合一旦创建就不能被修改,非常适合用于构建线程安全的应用和防御性编程。 1234567891011121314151617181920212223242526import com.google.common.collect.ImmutableList;import com.google.common.collect.ImmutableSet;import com.google.common.collect.ImmutableMap;// 创建不可变 Lis...
一致性哈希与数据分片
数据分片的动机 随着互联网应用的快速发展,数据量和访问量呈现爆炸式增长。单机存储系统面临着两个根本性的瓶颈:存储容量和访问性能。 存储容量方面,单台服务器的磁盘空间是有限的。当数据量超过单机容量时,必须寻找横向扩展的解决方案。垂直扩展通过升级硬件配置可以在一定程度上缓解问题,但成本高昂且存在物理上限。更重要的是,单机无法无限扩展,当数据量达到TB甚至PB级别时,垂直扩展已经无法满足需求。 访问性能方面,单机的处理能力同样有限。随着用户数量和请求量的增加,CPU计算能力、内存带宽、磁盘I/O和网络带宽都会成为性能瓶颈。即使单机能够处理当前的负载,也无法保证未来业务的持续增长。 数据分片提供了一种水平扩展的解决方案。通过将数据分散到多台服务器上,每台服务器只存储部分数据并处理部分请求,从而实现存储容量和访问性能的线性扩展。这种架构具有更好的可扩展性,可以根据业务增长灵活地增加服务器节点。 朴素哈希分片 朴素哈希分片是最直观的数据分片方案。其核心思想是:对于给定的数据键key,通过哈希函数计算其哈希值,然后对节点数量N取模,确定该数据应该存储在哪个节点。 1node_index = h...
API 兼容性设计
在软件工程中,API 兼容性是一个至关重要但又经常被忽视的问题。良好的兼容性设计能够确保系统的平滑演进,避免因 API 变更导致的客户端崩溃和服务中断。本文将从多个维度探讨 API 兼容性设计的最佳实践。 什么是 API 兼容性 API 兼容性分为两种类型: 向前兼容:旧版本的客户端能够与新版本的服务端正常通信。即服务端升级后,旧客户端仍能正常工作。 向后兼容:新版本的客户端能够与旧版本的服务端正常通信。即客户端升级后,旧服务端仍能提供服务。 在实际项目中,我们通常更关注向前兼容,因为服务端的升级往往不可控,而客户端的更新节奏各异。 破坏性变更的分类 破坏性变更是指会导致现有客户端无法正常工作的 API 变更。主要分为三类: 1. 接口签名变更 123456789// 变更前public interface UserService { User getUser(String userId);}// 变更后 - 破坏性变更public interface UserService { User getUser(String userId,...
重读 Eric Evans 的 DDD 蓝皮书
引言 软件系统的复杂性往往被误解为技术问题。在多年的开发实践中,我们习惯了用各种设计模式、架构框架、技术栈来应对复杂性,却忽略了一个根本事实:软件的核心复杂性在于领域本身,而非技术实现。Eric Evans 在《领域驱动设计》一书中提出了这一深刻见解,并给出了一套系统化的方法论——领域驱动设计。 DDD 不是一套必须严格遵守的规范,也不是一个可以简单套用的框架,它是一种思维方式,一种通过深入理解业务领域来构建高质量软件的方法论。重读这本经典著作,让我们重新审视这些核心理念。 通用语言 通用语言是 DDD 的基石。开发团队与领域专家共享同一套语言,这套语言不仅用于沟通,也体现在代码中。代码即文档,文档即代码。 在传统开发模式中,业务专家使用业务术语,技术人员使用技术术语,两者之间存在天然的语言鸿沟。业务需求被翻译成技术文档,技术文档又被翻译成代码,每个翻译环节都会产生信息丢失和误解。通用语言的提出,就是为了消除这种鸿沟。 通用语言应该由开发和业务专家共同构建,在持续的交流中不断完善。它体现在所有方面:需求讨论、文档、代码、测试。当领域专家能够阅读代码并理解其含义时,当开发人员能够直...
HTTP/1.1 到 HTTP/3 的演进
引言 HTTP 协议作为现代互联网的基石,自 1991 年诞生以来经历了多次重大演进。从最初简单的请求-响应模型,到如今高效、安全的 HTTP/3,每一次版本更新都针对前一版本的局限性进行了针对性的改进。本文将系统性地梳理 HTTP/1.0、HTTP/1.1、HTTP/2 和 HTTP/3 的核心技术特性和演进路径,深入分析每一代协议的设计理念、性能优化以及面临的挑战。 HTTP/1.0 的局限性 HTTP/1.0 于 1996 年发布,奠定了现代 Web 通信的基础框架。然而,随着互联网应用的快速发展,HTTP/1.0 的局限性逐渐显现。 每个 TCP 连接只能处理一个请求 HTTP/1.0 采用最简单的请求-响应模型:客户端发起请求,建立 TCP 连接,服务器返回响应后关闭连接。对于包含多个资源(如 HTML、CSS、JavaScript、图片等)的网页,浏览器需要为每个资源建立独立的 TCP 连接。这种模式带来了严重的性能问题: TCP 连接建立和关闭需要消耗系统资源 三次握手和慢启动机制增加了延迟 无法充分利用网络带宽 缺乏 Host 头字段 HTTP/1.0 最初设...
Java 结构化并发
结构化并发(Structured Concurrency) 结构化并发是 Java 并发编程的重要演进方向,与虚拟线程紧密配合,旨在解决传统并发编程中的线程泄漏、错误处理困难等问题。 1. 历史背景 1.1 结构化并发的起源与核心类比 术语起源 “结构化并发”(Structured Concurrency)这个术语由 Martin Sústrik(ZeroMQ 作者)在 2016 年首次提出。随后,Nathaniel J. Smith 在 2018 年发表了著名的文章《Notes on structured concurrency, or: Go statement considered harmful》,系统性地阐述了结构化并发的理论基础。 timeline title 结构化并发发展历程 2016 : Martin Sústrik 首创术语 : 在 250bpm.com 发表系列文章 2018 : Nathaniel J. Smith 发表核心论文 : "Go statement considered ha...
G1/ZGC/Shenandoah 垃圾收集器对比
垃圾收集的核心挑战 垃圾收集器的设计始终面临三个核心指标的权衡:吞吐量、延迟和内存占用。这三个指标构成了一个不可能三角,优化其中一个指标往往需要牺牲其他指标。 吞吐量指单位时间内完成的工作量,通常用应用程序运行时间占总时间的比例来衡量。对于批处理任务、科学计算等场景,高吞吐量是首要目标。 延迟指垃圾收集造成的应用停顿时间。对于交互式应用、金融交易系统等对响应时间敏感的场景,低延迟至关重要。延迟通常关注最大停顿时间和停顿时间分布。 内存占用指垃圾收集器为了完成收集工作所需的额外内存空间。内存受限的环境下,收集器自身的内存开销成为关键约束。 传统垃圾收集器在三者之间做出明确取舍:Serial 和 Parallel GC 追求高吞吐量,但停顿时间较长;CMS GC 降低停顿时间,但牺牲吞吐量并占用更多内存。现代收集器试图在三者之间找到更优的平衡点。 G1(Garbage First)收集器 G1 收集器在 JDK 7u4 版本正式推出,是 JDK 9 之后的默认垃圾收集器。G1 的核心思想是打破传统分代收集的物理隔离,将堆内存划分为多个大小相等的 Region。 Region 化堆内存...
TLS 握手与加密通信
为什么需要 TLS HTTP 协议最初设计为明文传输协议,所有通信内容都以纯文本形式在网络中传输。这种设计在互联网早期是合理的,但随着网络应用的普及和敏感数据的增多,明文传输带来了严重的安全风险。 窃听风险 在明文传输模式下,任何能够访问网络链路的攻击者都可以轻易读取通信内容。这包括: 同一局域网内的其他用户 网络服务提供商(ISP) 恶意的路由器或交换机 公共 Wi-Fi 网络的运营者 攻击者可以使用诸如 Wireshark、tcpdump 等网络抓包工具捕获数据包,直接查看其中的内容。这意味着用户名、密码、信用卡号、私密消息等敏感信息都会暴露在攻击者面前。 篡改风险 明文传输不仅允许攻击者读取内容,还允许他们修改传输的数据。攻击者可以在数据包经过的任何位置插入、删除或修改内容,而接收方难以察觉。例如: 将银行转账金额从 100 元改为 10000 元 修改电子邮件的内容 在网页中插入恶意脚本 替换下载的软件包 冒充风险 由于缺乏身份验证机制,攻击者可以冒充合法的服务器与客户端通信。客户端无法确认与之通信的服务器是否真实可信。这使得钓鱼攻击成为可能:攻击者搭建一个与真实...
变更日志(Changelog)规范
什么是变更日志 变更日志(Changelog)是一个按时间顺序记录项目所有重要变更的文件。它帮助用户、开发者和利益相关者了解每个版本中发生了什么变化,包括新功能、Bug 修复、破坏性变更等。 为什么需要变更日志 用户友好:让用户快速了解新功能、修复的问题和需要注意的变更 版本追溯:帮助定位问题首次出现或修复的版本 团队协作:统一团队对变更的理解和沟通 发布管理:辅助版本发布流程和发布说明的撰写 与 Git Log 的区别 特性 变更日志 Git Log 目标受众 用户、开发者、利益相关者 开发者 内容粒度 功能级别的高级描述 每次提交的详细记录 可读性 高度结构化、易于阅读 技术性强、包含实现细节 维护方式 手动维护或自动化生成 自动记录所有提交 版本关联 按版本组织 按时间顺序 Git Log 记录所有的代码提交,包括内部重构、测试调整等;而变更日志只记录对用户有意义的变更。 Keep a Changelog 规范 Keep a Changelog 是目前最广泛采用的变更日志规范,由 Olivier Lacan 创建。 变更类型分类 Ke...
Kubernetes 核心概念
从 Docker 到 Kubernetes 的演进 Docker 的出现彻底改变了应用程序的打包和部署方式。通过容器化技术,开发人员能够将应用程序及其依赖项打包到一个轻量级的、可移植的容器中,确保了"一次构建,到处运行"的一致性体验。然而,随着容器化应用的规模扩大,单机容器管理的局限性逐渐显现。 在单机环境中,Docker 提供了容器生命周期管理、资源隔离、网络配置等基础功能。但当应用规模扩展到多台服务器时,运维团队面临诸多挑战:跨主机的容器调度、服务发现、负载均衡、故障自愈、滚动升级、资源配额等问题变得日益复杂。手工管理几十甚至上百个容器不仅效率低下,而且容易出错。 容器编排平台应运而生。Kubernetes(K8s)作为容器编排领域的领导者,提供了一个完整的平台,用于自动化部署、扩展和管理容器化应用。它解决了多机环境下的核心问题:自动化调度、服务发现、负载均衡、存储编排、自动扩缩容、滚动更新和回滚、自我修复等。Kubernetes 不仅是一个编排工具,更是一个云原生应用的基础设施平台。 Kubernetes 架构 Kubernetes 采用主从架构,由控制...
