再有人问你分布式事务,把这篇扔给他

再有人问你分布式事务,把这篇扔给他

前言 不知道你是否遇到过这样的情况,去小卖铺买东西,付了钱,但是店主因为处理了一些其他事,居然忘记你付了钱,又叫你重新付。又或者在网上购物明明已经扣款,但是却告诉我没有发生交易。这一系列情况都是因为没有事务导致的。这说明了事务在生活中的一些重要性。有了事务,你去小卖铺买东西,那就是一手交钱一手交货。有了事务,你去网上购物,扣款即产生订单交易。 事务的具体定义 事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元,组成事务的所有操作只有在所有操作均能正常执行的情况下方能提交,只要其中任一操作执行失败,都将导致整个事务的回滚。简单地说,事务提供一种“要么什么都不做,要么做全套(All or Nothing)”机制。 数据库本地事务 ACID 说到数据库事务就不得不说,数据库事务中的四大特性,ACID: A:原子性(Atomicity) 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。 就像你买东西要么交钱收货一起都执行,要么要是发不出货,就退钱。 C:一致性(Consistency) 事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。 I:隔离性(Isolation) 指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。 打个比方,你买东西这个事情,是不影响其他人的。 D:持久性(Durability) 指的是只要事务成功结束,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。 打个比方,你买东西的时候需要记录在账本上,即使老板忘记了那也有据可查。 InnoDB实现原理 InnoDB是mysql的一个存储引擎,大部分人对mysql都比较熟悉,这里简单介绍一下数据库事务实现的一些基本原理,在本地事务中,服务和资源在事务的包裹下可以看做是一体的: 我们的本地事务由资源管理器进行管理: 而事务

数据结构和算法在存储中的经典应用

数据结构和算法在存储中的经典应用

Algorithms + Data Structures = Programs —— Niklaus Wirth 先搬出写了 Pascal、又拿了图灵奖的大师的名言,这里不讨论该断言的合理性,只作为本文的引子。在数据库领域,究其原理,绕不开数据存储。本文从几个经典应用出发,管窥数据结构在存储中所起到的作用。 引入 通常,像电商交易、支付系统的后端服务,往往是 I/O 密集型,I/O 性能会制约整个服务的性能。因此后端工程师往往会非常关注数据库的读写 TPS,IOPS 等监控指标。在特定的技术环节,比如为数据库表设计索引,用 Kafka 为秒杀场景提供大并发写的吞吐,这些大家非常熟悉的技术,其实都包含了对数据结构的运用。 磁盘 I/O 对数据库的读写本质是磁盘 I/O(不考虑 Redis 等内存数据库)。在讲存储中的数据结构之前,先简单介绍磁盘 I/O 特性对数据库设计的影响,详细的解释可以阅读美团技术博客 《磁盘 I/O 那些事》[1]。 传统意义上数据库需要将数据以文件的形式存储到磁盘上,对数据库的操作可以简单抽象为对磁盘文件的读写,而磁盘 I/O 耗时会影响数据库的读写性能。一次磁盘 I/O 可以拆分为:磁头寻道时间 seek time、扇区旋转延迟时间 latency time、数据传输时间 transmission time,参考下图示意。 磁头寻道:磁头移动到数据所在磁道位置,参考值 3-15ms; 扇区旋转:通过盘片的旋转,将数据所在扇区移动到磁头下方,参考值 2-5ms; 数据传输:数据通过系统总线从磁盘加载到内存的时间,通常小于 1ms; 寻道时间 > 旋转延迟 >> 数据传输,所以磁盘 I/O 耗时 ≈ seek time + latency time,IOPS = 1000 / (seek time + latency time)。 我们已经知道,磁盘的顺序 I/O 比随机 I/O 更快(参考下图),原因在于顺序 I/O 磁头几乎不用换道,或者换道的时间很短;而随机 I/O 磁头则会频繁换道。对随机 I/O 而言,7200 转的磁盘,随机 I/O 的 IOPS 通常为 70 ~ 80。而对顺序 I/O,比如读取一块连续存储的文件,理想的情况是在一次 I/O 后就可以顺序读写,其 IOPS 会非常高。因此包括数据库在内,但凡涉及存储,都会考虑更多利用顺序 I/O 来提高性能。 相对于读,写的性能瓶颈会更凸显,因此对存储的设计会优先考虑提升写性能。由于文件系统保证了文件是顺序写入,所以可以采用追加写入文件的方式实现顺序写。由于是对文件的增量追加写入,所以在数据读取时,需要倒过来检索,从最新的文件逐个往回查,比如通过简单的二分,二叉搜索树等算法进一步优化,减少 I/O 次数,归根结底性能优化

网络io模型

网络io模型

对于io模型这块内容之前基本完全没有接触过,有了些许了解之后还是很困昏,select、poll、epoll的关系以及服务器ngnix、apache的工作机制,还有JAVA NIO、BIO、AIO这么多的概念混杂起来实在是不好理解,想稍微梳理一下。 网络IO模型 网络IO的本质是socket的读取,socket在linux系统被抽象为流,IO可以理解为对流的操作 IO其实我们并不陌生,站在操作系统的角度上说,io一般指访问磁盘数据,可以分为两步,以read操作举例的话: 第一阶段:等待数据准备 (Waiting for the data to be ready)。 第二阶段:将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)。 而网络IO也是如此,只不过它是读取的不是磁盘,而是socket: 第一步:通常涉及等待网络上的数据分组到达,然后被复制到内核的某个缓冲区。 第二步:把数据从内核缓冲区复制到应用进程缓冲区。 在理解网络IO模型之前,我们得先准备些IO模型的基础知识 IO模型 Unix 有五种 I/O 模型: 阻塞IO(bloking IO) 非阻塞IO(non-blocking IO) 多路复用IO(multiplexing IO) 信号驱动式IO(signal-driven IO) 异步IO(asynchronous IO) 每个 IO 模型都有自己的使用模式,它们对于特定的应用程序都有自己的优点。下面提供一个简单的图片以供了解。 image 阻塞式 IO 应用进程被阻塞,直到数据复制到应用进程缓冲区中才返回。 应该注意到,在阻塞的过程中,其它程序还可以执行,因此阻塞不意味着整个操作系统都被阻塞。因为其他程序还可以执行,因此不消耗 CPU 时间,这种模型的 CPU 利用率效率会比较高。 下图中,recvfrom 用于接收 Socket 传来的数据,并复制到应用进程的缓冲区 buf 中。这里把 recvfrom() 当成系统调用。 [图片上传失败...(image-111ada-1538122299754)] 非阻塞式 IO 应用进程执行系统调用之后,内核返回一个错误码。应用进程可以继续执行,但是需要不断的执行系统调用来获知 I/O 是否完成,这种方式称为轮询(polling)。 由于 CPU 要处理更多的系统调用,因此这种模型的 CPU 利用率是比较低的。 [图片上传失败...(image-76babc-1538122299754)] 多路复用IO 由于阻塞式IO通过轮询得到的只是一个IO任务是否完成,而可能有多个任务在同时进行,因此就想到了能否轮询多个IO任务的状态,只要有任何一个任务完成,就去处理它。这就是所谓的IO多路复用。LINUX下具体的实现方式就是select、poll、epoll。 这种机制可以让单个进程具有处理多个 IO 事件的能力。

JVM内存结构、Java内存模型和Java对象模型

JVM内存结构、Java内存模型和Java对象模型

Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模型和Java对象模型,这就是三个截然不同的概念,但是很多人容易弄混。 可以这样说,很多高级开发甚至都搞不不清楚JVM内存结构、Java内存模型和Java对象模型这三者的概念及其间的区别。甚至我见过有些面试官自己也搞的不是太清楚。不信的话,你去网上搜索Java内存模型,还会有很多文章的内容其实介绍的是JVM内存结构。 首先,这三个概念是完全不同的三个概念。本文主要对这三个概念加以区分以及简单介绍。 JVM内存结构 我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途。 其中有些区域随着虚拟机进程的启动而存在,而有些区域则依赖用户线程的启动和结束而建立和销毁。在《Java虚拟机规范(Java SE 8)》中描述了JVM运行时内存区域结构如下: 各个区域的功能不是本文重点,就不在这里详细介绍了。这里简单提几个需要特别注意的点: 1、以上是Java虚拟机规范,不同的虚拟机实现会各有不同,但是一般会遵守规范。 2、规范中定义的方法区,只是一种概念上的区域,并说明了其应该具有什么功能。但是并没有规定这个区域到底应该处于何处。所以,对于不同的虚拟机实现来说,是有一定的自由度的。 3、不同版本的方法区所处位置不同,上图中划分的是逻辑区域,并不是绝对意义上的物理区域。因为某些版本的JDK中方法区其实是在堆中实现的。 4、运行时常量池用于存放编译期生成的各种字面量和符号应用。但是,Java语言并不要求常量只有在编译期才能产生。比如在运行期,String.intern也会把新的常量放入池中。 5、除了以上介绍的JVM运行时内存外,还有一块内存区域可供使用,那就是直接内存。Java虚拟机规范并没有定义这块内存区域,所以他并不由JVM管理,是利用本地方法库直接在堆外申请的内存区域。 6、堆和栈的数据划分也不是绝对的,如HotSpot的JIT会针对对象分配做相应的优化。 如上,做个总结,JVM内存结构,由Java虚拟机规范定义。描述的是Java程序执行过程中,由JVM管理的不同数据区域。各个区域有其特定的功能。 Java内存模型 Java内存模型看上去和Java内存结构(JVM内存结构)差不多,很多人会误以为两者是一回事儿,这也就导致面试过程中经常答非所为。 在前面的关于J

C/C++ 語言測量時間函數,評估程式執行效能方法整理

C/C++ 語言測量時間函數,評估程式執行效能方法整理

這裡整理了 C/C++ 中各種測量時間的函數與用法,並提供完整的範例程式碼,讓程式開發者方便測量程式執行速度。 這裡我蒐集了一些在 C/C++ 中常見的程式執行速度測量方式,因為時間的量測方式與細節非常多,這裡只是簡單寫一些常用的方式與範例。 程式中的時間 在測量程式執行所花費的時間前,必須先認識一下時間的測量方式,不同的測量方法會得到不同的結果,其意義也不同。 Wall-Clock Time Wall-clock time 顧名思義就是真實世界的時間,相當於以牆上的時鐘為依據所計算出來的時間,這個時間會牽涉到校時、時區以及夏令時間之類的問題,詳細說明請參考維基百科的 Wall-clock time 說明。 由於 wall-clock time 並不是單調遞增(monotonic)的數值,所以它不是一個穩定的時間依據,只能做為參考用,若需要非常精準的量測程式效能,不建議使用這種時間。 CPU Time CPU time 是指程式真正使用 CPU 在執行的時間,而這個時間又可以細分為兩種: user time:程式本身執行的時間(user space)。 system time:作業系統層級執行的時間(kernel space)。 詳細說明請參考維基百科的 CPU time 與 User space 說明。 對於多執行緒(multithreading)的程式,其 CPU time 就是每條執行緒的執行時間總和,所以平行化的程式其 CPU time 可能會比 wall-clock time 還要長。 C 語言範例 這是一個利用蒙地卡羅演算法計算 pi 的範例: #include <stdlib.h> #include <stdio.h> #include <math.h> double pi(int n) { srand(5); int count = 0; double x, y; for (int i = 0; i < n; ++i) { x = (double) rand() / RAND_MAX; y = (double) rand() / RAND_MAX; if (x * x + y * y <= 1) ++count; } return (double) count / n * 4; } int main() { double result = pi(1e8); printf("PI = %f\n", result); } 使用 gcc 編譯: gcc -o pi pi.c 若使用比較舊的 gcc 編譯器,要加上 -std=c99 參數: gcc -std=c99 -o pi pi.c 以下我們將以這個程式為例,介紹測量程式執行時間的方法。 Linux time 指令 在 Linux 中有一個 time 指令可以直接測試程式的執行時間(CPU time): time ./pi PI = 3.142172 real 0m2.210s user 0m2.209s sys 0m0.001s time 指令的輸出分為 user time、system time 以及實際上所花費的時間。 如果在系統上同時有其他的程式也在使用 CPU 時,結果會有些差異。我先使用 stress 讓 CPU 滿載: stress --cpu

联系我们

联系电话

4000-640-466

联系邮箱

service@f-li.cn

办公地址

上海黄浦区外滩源1号

谢谢,您的信息已成功发送。
请填写信息。