后端好书阅读与推荐系列文章:
后端好书阅读与推荐
后端好书阅读与推荐(续)
后端好书阅读与推荐(续二)
后端好书阅读与推荐(续三)
后端好书阅读与推荐(续四)
后端好书阅读与推荐(续五)html
Redis设计与实现 (豆瓣): https://book.douban.com/subje...前端
经过前面这本书咱们已经知道redis怎么用比较好了,如今咱们来看看 Redis 的实现原理。这本书是做者本身看着源码写出来的,不得不佩服做者的智慧与毅力。这本书基于redis3.0,此刻redis最新版是4.0.9,咱们看书的时候能够本身去看看源码,看看redis有啥变化没,源码在此。java
亮点:node
SDS(简单动态字符串)
这一抽象类型,被用于键、字符串的表示,还有AOF中的缓冲区、客户端输出缓冲区等buffer的表示。 SDS的优点在于:记录了长度信息不须要遍历(空间换时间)、有长度因此会先检查空间是否足够而不会溢出、记录了free(未使用空间)长度从而避免频繁的内存从新分配(实现了空间预分配和惰性释放)、二进制安全等等List
结构、发布订阅、慢查询、监视器等功能)、字典Dict(基于两个hash表,一个平时用、一个rehash用,主要用于实现数据库、Hash
结构,须要注意渐进式rehash而不是java中Hashmap的一次性rehash,渐进式主要是避免键数量太大致使服务器暂时中止服务)、跳跃表SkipList(用于实现SortedSet
结构、集群节点)、整数集合(用于实现Set
结构)、压缩列表(用于实现List
和Hash
结构,主要是面向小整数和短字符串,能够节省空间)、对象redisObject(redis的五种数据结构就是五种对象,key value都是对象,是对前面全部数据结构的一种封装,实现类型判断、编码、引用计数与对象共享和内存回收、过时删除等功能)等数据结构来实现特定功能redisServer
数据结构,包含一个redisDb
的链表,每个数据库都是一个数据结构redisDb
,中间有一个dict
的数据结构保存了这个数据库全部的键值对,叫作键空间(key space)。键空间会维护命中次数、最后使用时间、过时清除、键监视、键空间(关注键自己)/键事件(关注操做自己如del、sadd、set等)通知等事件。此外还有一个clients
字段保存了全部客户端redisDb
有一个dict
类型的链表expire
,保存了全部键的过时时间。过时键有三种删除策略:定时删除
,设置timer,过时当即删除,对内存友好,可是浪费CPU时间片,并且大量的timer也不现实;惰性删除
,听任无论,获取的时候检查是否过时,过时再删除,会浪费必定的内存,可是节省CPU时间;按期删除
,每隔一段时间就检查过时键并删除,须要好好设计执行时长与频率。redis实际使用的是后二者AOF
和RDB
。RDB能够手动执行也可按期执行(BGSAVE)用内存数据生成压缩过的二进制RDB文件,SAVE
命令会阻塞服务器,而BGSAVE
会fork一个子进程来建立RDB文件,因此期间新的数据变化是不能提现到RDB文件中的,此外,RDB文件的载入是服务器启动自动完成的;AOF不直接记录数据,而是记录每个redis命令,分为append、文件写入(可能在系统缓冲中)、文件同步sync(强制刷到磁盘)三个步骤,文件同步有三种选项always(写入文件就刷盘)、everysec(默认)、no(由操做系统决定什么时候刷盘)while(true)
的无限循环,叫作事件循环,每一个循环里服务器要处理两种事件:文件事件,完成网络通讯(基于Reactor模式);时间事件,完成定时、周期操做之类。Sentinel
实例监视任意多的redis主服务器以及所属的从服务器(从服务器复制主服务器的数据),完成主备切换等功能。实现原理是Sentinel
每隔10秒就向全部主服务器发送info
命令,获取各个主服务器及其对应的从服务器的信息,而后也会以相同形式给从服务器发送info
命令。另外会以两秒一次的频率向全部主从服务器发送一个publish
的命令,而后会subscribe
这个频道,这样就能得到每一个服务器的相关信息了。Sentinel
之间只有命令链接,没有频道链接。ping
来实现,当超过一个Sentinel
的时限down-after-milliseconds
还没得到一个服务器的回复这个Sentinel
就认为此服务器主观下线,而后会询问其余Sentinel
,若是超过quorum
个Sentinel
都认为此服务器主观下线那么这些Sentinel
就认为这个服务器就客观下线了。当一个主服务器下线时,Sentinel
们会选举一个领头Sentinel
(Raft
leader选举)来对这个服务器群进行主备切换,具体算法就不说了redis-trib
实现。showlog-log-slower-than
选项执行时间的命令会被记录到慢查询日志,日志采用保存最近的,数量由slowlog-max-len决定。本书配合着官方文档来学习是最佳的,文档在此,中文文档。mysql
MySQL技术内幕 (豆瓣): https://book.douban.com/subje...linux
经过前面这本书咱们已经知道 mysql 怎么用比较好了,如今咱们来看看 mysql 的实现原理。nginx
亮点:git
InnoDB
支持事务、行锁、外键,主要面向在线事务处理应用(OLTP),经过MVVC提升并发性,默承认重复读级别使用 next-key locking避免幻读,此外还提供插入缓冲、二次写、自适应hash索引、预读等高性能与高可用功能;MyISAM
不支持事务与行锁,可是支持全文索引,主要面向OLAP应用;NDB
是一个集群引擎,数据所有在内存因此速度很快,可是链接操做不是在引擎层面解决的,效率较低;Memory
也是内存存储的引擎,适合临时表存储中间结果使用,默认使用hash索引,只支持表锁;Archive
只支持insert和select,支持压缩适合存储归档数据;还有太多不经常使用的,就不一一列举了Master Thread
负责将缓冲池中的数据异步刷新到磁盘,保证数据一致性,包括脏页刷新,合并插入缓冲,undo页回收;IO thread
负责写操做AIO的回调处理;Purge Thread
负责undo log的回收,减轻Master Thread的负担;Page cleanner Thread 负责脏页刷新,减轻master thread 负担写缓冲
与WAL
将随机写改为了顺序写提升了吞吐量,同时保证数据持久性,若是宕机就会用redo
与undo
两阶段的日志来将数据恢复到数据库文件中。可是mysql基本页面通常是16KB,而操做系统基本页面通常是4KB,若是在写入到数据库文件时发生宕机,就可能引发partial write
问题,亦即一个mysql页面只写入了一部分,这时就要依靠double write
:同步缓冲区数据时,不是直接写入文件,而是写入内存中的double write buffer
再调用fsync写到共享表空间文件,而后立刻调用fsync同步至数据库文件,这样若是发生了partial write
,就能够去共享表空间找到该页副本并复制到数据库文件中,而后再进行redo,undo
。固然,若是文件系统自己有防范机制就没必要启用double write
了Fileheader、Pageheader、FileTrailer
(检查完整性)是固定的,记录一些该页的信息如checksum
、页所在B+树层数。userrecords、freespace、pagedirectory
(页相对位置,B+索引只记录一条数据所在页,真正查找还需把这一页加载如内存,靠二分搜索这一条记录)是实际的行记录存储空间,所以大小是动态的。Cardinality
能帮助咱们决策是否须要创建索引,能够经过show index
来观察,通常好比性别这个字段Cardinality
就很低,由于可能一个类型female
就占据了全部行的一半,根本不必创建索引,而名字这个字段Cardinality
就很高,适合创建索引(固然也得是应用经常按名字检索,这样才有必要创建索引)事务的实现主要依靠:程序员
redo
实现持久性,亦即commit
操做必须将专门的redo
日志文件fsync
刷新到磁盘才能返回成功,合并多条语句插入优于一句一句插入也是由于减小了日志刷盘频率,因为redolog
块与磁盘扇区块大小一致,因此无需doublewrite
;undo
实现回滚操做和MVCC,是存在于数据库内部共享表空间的一个特殊段(undo
段)中的逻辑日志,记录了事务执行的反效果便于回滚,MVCC的实现是经过若某行记录已被其余事物占用,当前事务能够经过undo
日志获得改行以前版本的信息,需注意undolog
也会产生redolog
,亦即undolog
也须要持久性维护;purge
最终完成delete
和update
操做,由于Innodb支持MVCC,因此记录不能在提交时当即处理,purge
操做判断合什么时候真正清理数据并回收undo page
,具体来讲,若是一行数据不被真正引用那就可清理delete
和update
数据了;group commit
将多个事务的数据一次性调用fsync刷新到磁盘减小刷盘次数;binlog
,用来实现Point-In-Time
的恢复以及主从复制的实现,很是相似于redolog
,可是二者本质有很大不一样:redolog
产生于下层只针对Innodb引擎产生,是物理格式日志,记录针对每一页的修改,事务过程当中不断被写入;binlog
产生于中层,针对任何引擎都会产生,是逻辑日志,记录针对每条SQL语句,事务提交后一次写入binlog
的,事务提交时既要写binlog
也要写redolog
,这就会涉及原子性问题,亦即两个日志必须同时写入,经过先作prepare操做,将事务的xid写入,而后写入binlog,而后提交存储引擎并写入redolog 深刻Linux内核架构 (豆瓣): https://book.douban.com/subje...github
这是一本能把linux内核全貌展示给咱们的大部头,涵盖了包括进程管理,内存管理、锁与通讯、设备驱动、文件系统等等。要采起观其大略,用时细读的策略,去宏观的把握linux的设计哲学。
亮点:
fork
(父子进程只有PID不一样,使用COW使得fork更高效,亦即子进程只复制页表,只有父子某一进程要向内存写入数据时才真正复制物理内存,若只读则能够共享而没必要复制,这样就延迟甚至消除了了大量的复制,节约了内存和CPU时间)和exec
(将一个新程序加载到当前内存中执行,旧的程序内存页将刷出)。linux使用clone建立线程(或者说轻量级进程),相似于fork,可是能精确检查哪些资源与父进程共享哪些为线程独立建立实际运行时间*(NICE_0_LOAD/权重nice值)
)最小的进程位于左下方会被调度器优先考虑,休眠进程被放入等待队列中,唤醒后会从新被加入红黑树。实时进程是指该进程必须在指定的时间内完成好比飞机飞行控制指令,于是通常都有相对非实时进程较高的优先级,不一样于非实时进程调度proc
标准挂载点是/proc
,其信息不能从块设备读取,只有在读取文件内容时才动态生成相关信息,也能够在不从新编译内核源码的状况下修改内核行为,与内核通讯,包含网络信息、内存管理、进程特征数据、文件系统、设备驱动、电源、终端、系统控制参数;sysfs
的标准挂载点是/sys
,是一个向用户空间导出内核对象的文件系统,提供了查看和修改内核数据结构的能力;用于专门目的的小文件系统同窗们,堪称整个现代互联网软件基石的Linux内核源码就在这里,有没有勇气去瞅瞅?
还有这本书更精简,推荐给不想看太多源码和细节的同窗: Linux内核设计与实现(原书第3版)。
Kafka权威指南 (豆瓣): https://book.douban.com/subje...
Kafka是一个高吞吐量的分布式(支持分区partition、多副本replica、使用zookeeper协调)消息系统,目前普遍用来进行实时大数据处理如:hadoop批处理、storm/Spark流式处理引擎,web日志、消息队列等等,因此做为一个后端开发者,颇有必要了解一下。我想的是把kafka做为消息队列的表明进行学习,未来若是要用ActiveMQ、RabbitMQ、ZeroMQ、RocketMQ等或者要本身要开发一个MQ均可以触类旁通或者进行借鉴。
亮点:
ProducerRecord
对象,包含Topic
和value
,还可能有key
或者partition
,对象序列化后发送到分区器上,若是有partition则不操做,若无则根据key来指定partition(partition的设计目的是取消消息大小限制和提升并行度)。选好partition后发往对应的topic和partition的记录批次,这一批记录等待一次性的发往对应的broker(因此批的大小影响延迟和吞吐量),整个过程有失败自动重试功能,超过必定次数返回客户端异常。生产者经过设置ack=n
,能够保证一个ProducerRecord
有n个副本(一个Partition的全部副本中有一个Leader负责与客户端交互,其他副本做为Follower从Leader复制数据,提供容错性)被写入成功才会收到成功的ack消息。整个topic的顺序没法保证,1个分区的顺序能够经过设置retries>0
(重试次数),和max.in.flight.requests.per.connection=1
(1次只发1条消息避免后到的消息先成功)来保证,不过会严重影响生产者性能,若非严格顺序要求不建议使用/brokers/ids
的临时节点并订阅其变动事件,在broker加入或退出时获得消息;集群中有一个控制器对应/controller
临时节点(全部broker均可以尝试建立节点成功则成为Controller,失败则知道Controller已经存在,全部broker都会监听这个节点的变动,经过递增的controller epoch来忽略旧控制器消息避免脑裂),除了完成broker功能以外还负责partition副本的leader选举;持续获得来自leader最新消息的副本叫作同步的副本,当leader失效时,只有同步的副本才可能被选为新的leader;不一样partition的副本和leader都均匀的分布在全部broker之间避免热点问题,副本尽可能放在不一样机架提升容错性partition
都分红了许多segment,一个segment包含1GB或者1周的数据(较小为准),正在写入数据的叫作活跃片断,永远不会被删除。每一个分区还有一个索引提高查询效率看完这本书基本就能把kafka的使用方法和基本原理搞清楚了,可是翻译有时候有点点问题,我以为普通的段落能够翻译,可是专用名词如segment
、partition
等仍是直接保留比较好,省得有歧义,固然总体上来来讲配合官网文档读起来仍是没问题的。
要想深刻的话源码在此。
NoSQL精粹 (豆瓣): https://book.douban.com/subje...
本书先分析了传统关系数据库的不足而后引入NoSQL,讲到了键值、文档、列族、图等多种数据库并分析了其优点劣势,可让咱们对NoSQL有一个全面的了解,为咱们进一步NoSQL的探索之路开一个好头。
亮点:
schemaless
)的数据。传统关系数据库有可持久化、模型标准便于共享和集成、事务支持等优势,NoSQL有无模式便于程序对象与数据库之间的映射、适应集群等优势。因此NoSQL和传统关系数据库各有所长,发展过程当中也在互相借鉴优势,谁也不能取代谁,未来都会在各自的领域中发光发热aggregate
)。聚合的边界划分没有标准答案,取决于你以后准备怎样操做数据。由于以聚合为单位复制和分片比较天然因此集群中操做数据库仍是聚合更简单。若数据操做大多在同一聚合内执行则应使用面向聚合的数据库(键值、文档、列族数据库),若交互须要多种不一样的格式则最好选聚合无知式(aggregate-ignorant
)数据库(关系数据库、图数据库),若待处理数据中有大量的关系最好就选关系数据库,可是若是关系复杂、并行交错最好选图数据库(插入费时、查询比复杂的join
快得多)polyglot persistence
),好比购物车能够用键值数据库存储,可是订单要用关系型数据库。因此除非是编程语言狂热爱好者,咱们大部分人都不该该去争论什么语言好,什么数据库好,不要想着一把刷子走遍世界,而应该普遍了解,解决问题的时候选择合适的工具,必要的时候也要本身改工具甚至造工具 本书的一个问题就是有点旧了,2013年第一版,这5年来NoSQL发展很快,已经被普遍用于企业级的系统之中了,尤为是Redis和MongoDB,因此有需求就大胆的用吧。
大型网站技术架构 (豆瓣): https://book.douban.com/subje...
把事情作大是咱们许多人的追求,这本书就可让咱们了解一下一个大型网站的架构应该要注意些什么,不管是摸得着的tech仍是比较摸不着的leadership,都值得借鉴。固然,书很薄,大多只能泛泛而谈,要想真正掌握,每一部分咱们都得本身单独深挖,因此本书能够看作一个大目录,为接下来的学习指引方向。
亮点:
99.99%
,一年小于53分钟不可用),实现高可用架构的主要手段是数据和服务的冗余备份和失效转移。应用层(文库、贴吧、知道)和服务层(帐户服务、session服务)由于通常无状态因此很容易扩展(负载均衡),新节点上下线都很容易,可是服务层须要注意好分级管理、超时设置、异步调用、服务降级、幂等设计等。数据层(数据库、文件、缓存)为了保证数据不丢失须要复制并均匀分布在集群中读完发现本书几乎全程“黑友商”,有的甚至好几遍(* ̄︶ ̄),有点不纯粹啊。
这本书是infoq上的系列博客造成的一本很薄的书,对于了解JMM仍是颇有用的。
深刻理解Java内存模型(二)——重排序: http://www.infoq.com/cn/artic...
亮点:
Store
和Load
的排列 ,其中StoreLoad Barriers
是一个全能型的屏障,同时具备其余三个屏障的效果,它确保store
数据对其余处理器的load
可见深刻分布式缓存:从原理到实践 (豆瓣): https://book.douban.com/subje...
缓存在现在的互联网中已经几乎是标配了,分布式缓存更是大型网站不可或缺的,本书就让咱们从原理到开源实现到业务实践一块儿打包了解了。
亮点:
1次和N次
结果同样,这个在分布式系统中很重要是由于网络抖动等因素经常致使重发;分布式系统的本质是一堆廉价的硬件攒在一块儿得到更好的吞吐量和性能以及可用性,有几个问题广泛关心:活性检测(周期心跳、累计失效检测)、高可用(主备、双主、集群)、容错处理(冷热切换、冗余、备份)、重试机制(失败重试、事务补偿)、负载均衡(多机分担请求),也有几个实践很重要:全局ID(数据库自增id如flicker、UUID、snowflake、预生成置于缓存中)、哈希取模分配、一致性哈希(单调性、分散性)、路由表与数据拆分