首页 > 数据库 > 数据库开发技术 > 并发之道:三大问题与JMM 何干?

笔者曾经历过数据规模(每天)在万亿级的监控系统、近百亿级的链路追踪系统、亿级的网关系统、千万级的短信系统、千万级的网络电话系统等诸多高并发系统的建设
在高并发系统的架构设计、开发实现、加固调优方面有少许经验积累
欢迎关注公众号【架构染色】交流学习
现代计算机发展所遵循的基本结构形式始终是冯·诺依曼结构,这个结构存储程序的方式造成了系统对存储器的依赖,受制于存储元件的速度、存储器的性能和结构等诸多条件的约束,CPU + 存储器( 内存和硬盘) 这个三剑客组合已保持好多年未变,并且它们之间的速度相差很多,但 CPU 与存储器间信息交换的速度一直是影响系统性能的主要因素。
若要提升信息交换的速度,就需要解决 CPU、内存、硬盘之间的速度差异问题。计算机体系结构、操作系统、编译程序等各自发力提供了解决方案:
从发展史看,降低速度差异的改进其实很多,配合本篇并发问题探索的需求,仅关注这三味良药;有所得则必有所失,这三味良药也分别带来了副作用,也即今天要探讨的并发的三大问题。
原子即整体不可分割,原子性操作是由 CPU 指令来保证的,执行一个或一组指令完成原子操作的过程中,CPU 不能被中断;但在操作系统分时复用 CPU 的机制中,指令与指令之间可以发生中断,CPU 指令集中提供的不中断的原子操作特别少,根本无法满足应用层原子性逻辑操作的多样化诉求。

分时复用CPU(来自网络).png
程序要运行,就会将数据从内存加载到 CPU 缓存,或者将数据从 CPU 缓存存储到内存;SMP 对称多处理器架构中,基于总线嗅探机制衍生了多种不同的 CPU 缓存一致性协议,其中最常用的就是 MESI 协议。

多级缓存架构的缓存一致性机制(来自网络).png
虽然看起来 MESI 提供了缓存一致的能力,但需注意 MESI 在实现缓存一致性时加入 Store buffer 和 Invalidate message Queue,通过异步处理来提升性能。所以从效果看缓存之间并非同步变更,这种最终一致的机制还是会导致缓存可见性问题。而有些场景下,应用程序需要的是立即一致或者说是按需一致。

为了提高性能、效率,编译器、处理器等常会对指令进行重排序。一般重排序可以分为如下三种:


编译优化重排序(来自网络).png

编程语言面对并发的三大问题,它所做的是对多线程的通信、同步机制进行包装,为开发者提供使用轻便、功能丰富的多线程编程 API。

从上图可知,通过消息传递或者共享内存都可以实现线程间的通信、同步,不同的语言采用的方式可能不同,而 JAVA 采用的是共享内存的方式,似乎共享内存的方式开发者更容易理解。
Java 是采用共享内存的方式来进行线程间的通信、同步,为了屏蔽各个硬件平台和操作系统对内存访问机制的差异化,内存模型(Memory Model)诞生了,而 JAVA 的内存模型就叫 JMM。
JMM 以抽象方式约定了,共享变量会先放在主存中,每个线程都有属于自己的工作内存,并且会把位于主存中的共享变量拷贝到自己的工作内存,之后的读写操作均使用位于工作内存的变量副本,并在某个时刻将工作内存的变量副本写回到主存中去。

JMM内存模型的抽象结构示意图(来自网络).png
我曾疑惑许久 JMM 中的本地内存到底是啥?查阅的一些资料表明:本地内存是 JMM 中的一个抽象概念,并不真实存在;它涵盖了缓存、写缓冲区、寄存器以及其他的硬件和编译器优化,这正是以抽象的概念来屏蔽底层实现的证明。

Java内存模型和操作系统内存模型的关系(来自网络).png
这里需要特别注意,内存模型(MM)的工作目标是保证 内存一致性(Memory Consistency),而有了内存一致性的保证,自然就解决了可见性、重排序、原子性这些问题。了解一下 JMM 如何规范读写,就能明白这个因果关系:
这样的描述似乎不易理解,下边转换为面向编程的话术就是 JMM 规范了:
有序的读写还有这样经典的描述:
并发场景要解决好原子性问题、可见性问题、重排序问题。JAVA 很友好,多线程间通信、同步机制采用共享内存的方式,并且站在开发者的立场考虑问题,通过 JMM 屏蔽了复杂多样又难以理解的底层技术知识,以更亲民的方式提供给我们解决这些问题的规范和工具,让开发者只关注如何操作,而忽视底层的复杂实现。
要客观应对高并发场景,许多系统并非设计出来时便具备高并发的能力,而是在上线后根据实际请求、数据的分布情况,通过针对性的加固、调优反复打磨而成,比如全链路追踪系统 SkyWalking 的建设与实践,详情查看:《Skywalking on the way-千亿级的数据储能、毫秒级的查询耗时》。
后续笔者会不断将自己沉淀多年的高并发相关的知识整理输出,还望读者老师不吝指教。
如果这篇文章对您有帮助,或者有所启发的话,欢迎关注公众号【 架构染色 】进行交流和学习。您的支持是我坚持写作最大的动力。
Java 并发编程的艺术
Java 并发编程实战
原文作者:架构染色;如有侵权,请联系管理员删除。