什么是日志?数据库
日志就是按照时间顺序追加的、彻底有序的记录序列,其实就是一种特殊的文件格式,文件是一个字节数组,而这里日志是一个记录数据,只是相对于文件来讲,这里每条记录都是按照时间的相对顺序排列的,能够说日志是最简单的一种存储模型,读取通常都是从左到右,例如消息队列,通常是线性写入log文件,消费者顺序从offset开始读取。
因为日志自己固有的特性,记录从左向右开始顺序插入,也就意味着左边的记录相较于右边的记录“更老”, 也就是说咱们能够不用依赖于系统时钟,这个特性对于分布式系统来讲至关重要。数组
日志的应用缓存
日志在数据库中的应用性能优化
日志是何时出现已经无从得知,多是概念上来说太简单。在数据库领域中日志更多的是用于在系统crash的时候同步数据以及索引等,例如MySQL中的redo log,redo log是一种基于磁盘的数据结构,用于在系统挂掉的时候保证数据的正确性、完整性,也叫预写日志,例如在一个事物的执行过程当中,首先会写redo log,而后才会应用实际的更改,这样当系统crash后恢复时就可以根据redo log进行重放从而恢复数据(在初始化的过程当中,这个时候不会尚未客户端的链接)。日志也能够用于数据库主从之间的同步,由于本质上,数据库全部的操做记录都已经写入到了日志中,咱们只要将日志同步到slave,并在slave重放就可以实现主从同步,这里也能够实现不少其余须要的组件,咱们能够经过订阅redo log 从而拿到数据库全部的变动,从而实现个性化的业务逻辑,例如审计、缓存同步等等。服务器
日志在分布式系统中的应用数据结构
分布式系统服务本质上就是关于状态的变动,这里能够理解为状态机,两个独立的进程(不依赖于外部环境,例如系统时钟、外部接口等)给定一致的输入将会产生一致的输出并最终保持一致的状态,而日志因为其固有的顺序性并不依赖系统时钟,正好能够用来解决变动有序性的问题。
咱们利用这个特性实现解决分布式系统中遇到的不少问题。例如RocketMQ中的备节点,主broker接收客户端的请求,并记录日志,而后实时同步到salve中,slave在本地重放,当master挂掉的时候,slave能够继续处理请求,例如拒绝写请求并继续处理读请求。日志中不只仅能够记录数据,也能够直接记录操做,例如SQL语句。并发
日志是解决一致性问题的关键数据结构,日志就像是操做序列,每一条记录表明一条指令,例如应用普遍的Paxos、Raft协议,都是基于日志构建起来的一致性协议。异步
日志在Message Queue中的应用分布式
日志能够很方便的用于处理数据之间的流入流出,每个数据源均可以产生本身的日志,这里数据源能够来自各个方面,例如某个事件流(页面点击、缓存刷新提醒、数据库binlog变动),咱们能够将日志集中存储到一个集群中,订阅者能够根据offset来读取日志的每条记录,根据每条记录中的数据、操做应用本身的变动。
这里的日志能够理解为消息队列,消息队列能够起到异步解耦、限流的做用。为何说解耦呢?由于对于消费者、生产者来讲,两个角色的职责都很清晰,就负责生产消息、消费消息,而不用关心下游、上游是谁,不论是来数据库的变动日志、某个事件也好,对于某一方来讲我根本不须要关心,我只须要关注本身感兴趣的日志以及日志中的每条记录。性能
咱们知道数据库的QPS是必定的,而上层应用通常能够横向扩容,这个时候若是到了双11这种请求忽然的场景,数据库会吃不消,那么咱们就能够引入消息队列,将每一个队数据库的操做写到日志中,由另一个应用专门负责消费这些日志记录并应用到数据库中,并且就算数据库挂了,当恢复的时候也能够从上次消息的位置继续处理(RocketMQ和Kafka都支持Exactly Once语义),这里即便生产者的速度异于消费者的速度也不会有影响,日志在这里起到了缓冲的做用,它能够将全部的记录存储到日志中,并定时同步到slave节点,这样消息的积压能力可以获得很好的提高,由于写日志都是有master节点处理,读请求这里分为两种,一种是tail-read,就是说消费速度可以跟得上写入速度的,这种读能够直接走缓存,而另外一种也就是落后于写入请求的消费者,这种能够从slave节点读取,这样经过IO隔离以及操做系统自带的一些文件策略,例如pagecache、缓存预读等,性能能够获得很大的提高。
分布式系统中可横向扩展是一个至关重要的特性,加机器能解决的问题都不是问题。那么如何实现一个可以实现横向扩展的消息队列呢? 假如咱们有一个单机的消息队列,随着topic数目的上升,IO、CPU、带宽等都会逐渐成为瓶颈,性能会慢慢降低,那么这里如何进行性能优化呢?
1.topic/日志分片,本质上topic写入的消息就是日志的记录,那么随着写入的数量越多,单机会慢慢的成为瓶颈,这个时候咱们能够将单个topic分为多个子topic,并将每一个topic分配到不一样的机器上,经过这种方式,对于那些消息量极大的topic就能够经过加机器解决,而对于一些消息量较少的能够分到到同一台机器或不进行分区
2.group commit,例如Kafka的producer客户端,写入消息的时候,是先写入一个本地内存队列,而后将消息按照每一个分区、节点汇总,进行批量提交,对于服务器端或者broker端,也能够利用这种方式,先写入pagecache,再定时刷盘,刷盘的方式能够根据业务决定,例如金融业务可能会采起同步刷盘的方式。
3.规避无用的数据拷贝
4.IO隔离
结语
日志在分布式系统中扮演了很重要的角色,是理解分布式系统各个组件的关键,随着理解的深刻,咱们发现不少分布式中间件都是基于日志进行构建的,例如Zookeeper、HDFS、Kafka、RocketMQ、Google Spanner等等,甚至于数据库,例如Redis、MySQL等等,其master-slave都是基于日志同步的方式,依赖共享的日志系统,咱们能够实现不少系统: 节点间数据同步、并发更新数据顺序问题(一致性问题)、持久性(系统crash时可以经过其余节点继续提供服务)、分布式锁服务等等,相信慢慢的经过实践、以及大量的论文阅读以后,必定会有更深层次的理解。