分布式事务
分布式事务,两种常见的实践:
• 补偿事务
• 后置提交优化
MySQL主从延时优化
• mysql5.5:不支持并行复制,大伙快升级MySQL版本;
• mysql5.6:按照库并行复制,建议使用“多库”架构;
• mysql5.7:按照GTID并行复制;
MySQL的主键与唯一索引约束
总结,对于主键与唯一索引约束:
• 执行insert和update时,会触发约束检查
• InnoDB违反约束时,会回滚对应SQL
• MyISAM违反约束时,会中断对应的SQL,可能造成不符合预期的结果集
• 可以使用 insert … on duplicate key 来指定触发约束时的动作
• 通常使用 show warnings; 来查看与调试违反约束的ERROR
chmod 755 剖析
第一位7:4+2+1,创建者,可读可写可执行
第二位5:4+1,组用户,可读可执行
第三位5:4+1,其他用户,可读可执行
InnoDB,快照读,在RR和RC下有何差异
• 事务总能够读取到,自己写入(update /insert /delete)的行记录
• RC下,快照读总是能读到最新的行数据快照,当然,必须是已提交事务写入的
• RR下,某个事务首次read记录的时间为T,未来不会读取到T时间之后已提交事务写入的记录,以保证连续相同的read读到相同的结果集
4种事务的隔离级别
• 并发事务之间相互干扰,可能导致事务出现读脏,不可重复度,幻读等问题
• InnoDB实现了SQL92标准中的四种隔离级别
(1)读未提交:select不加锁,可能出现读脏;
(2)读提交(RC):普通select快照读,锁select /update /delete 会使用记录锁,可能出现不可重复读;
(3)可重复读(RR):普通select快照读,锁select /update /delete 根据查询条件情况,会选择记录锁,或者间隙锁/临键锁,以防止读取到幻影记录;
(4)串行化:select隐式转化为select ... in share mode,会被update与delete互斥;
• InnoDB默认的隔离级别是RR,用得最多的隔离级别是RC
MyISAM与InnoDB的索引差异
MyISAM和InnoDB都使用B+树来实现索引:
• MyISAM的索引与数据分开存储
• MyISAM的索引叶子存储指针,主键索引与普通索引无太大区别
• InnoDB的聚集索引和数据行统一存储
• InnoDB的聚集索引存储数据行本身,普通索引存储主键
• InnoDB一定有且只有一个聚集索引
• InnoDB建议使用趋势递增整数作为PK,而不宜使用较长的列作为PK
数据库索引,到底是什么
• 数据库索引用于加速查询
• 虽然哈希索引是O(1),树索引是O(log(n)),但SQL有很多“有序”需求,故数据库使用树型索引
• InnoDB不支持哈希索引
• 数据预读的思路是:磁盘读写并不是按需读取,而是按页预读,一次会读一页的数据,每次加载更多的数据,以便未来减少磁盘IO
• 局部性原理:软件设计要尽量遵循“数据读取集中”与“使用到一个数据,大概率会使用其附近的数据”,这样磁盘预读能充分提高磁盘IO
• 数据库的索引最常用B+树:
(1)很适合磁盘存储,能够充分利用局部性原理,磁盘预读;
(2)很低的树高度,能够存储大量数据;
(3)索引本身占用的内存很小;
(4)能够很好的支持单点查询,范围查询,有序性查询;
InnoDB的七种锁
(1)自增锁(Auto-inc Locks)
(2)共享/排它锁(Shared and Exclusive Locks)
(3)意向锁(Intention Locks)
(4)插入意向锁(Insert Intention Locks)
(5)记录锁(Record Locks)
(6)间隙锁(Gap Locks)
(7)临键锁(Next-key Locks)
InnoDB怎么应对高并发
总结
(1)常见并发控制保证数据一致性的方法有锁,数据多版本;
(2)普通锁串行,读写锁读读并行,数据多版本读写并行;
(3)redo日志保证已提交事务的ACID特性,设计思路是,通过顺序写替代随机写,提高并发;
(4)undo日志用来回滚未提交的事务,它存储在回滚段里;
(5)InnoDB是基于MVCC的存储引擎,它利用了存储在回滚段里的undo日志,即数据的旧版本,提高并发;
(6)InnoDB之所以并发高,快照读不加锁;
(7)InnoDB所有普通select都是快照读;
InnoDB5项最佳实践
在大数据量,高并发量的互联网业务场景下,对于MyISAM和InnoDB
• 有where条件,count(*)两个存储引擎性能差不多
• 不要使用全文索引,应当使用《索引外置》的设计方案
• 事务影响性能,强一致性要求才使用事务
• 不用外键,由应用程序来保证完整性
• 不命中索引,InnoDB也不能用行锁
Cache Aside Pattern
Cache Aside Pattern建议,先操作数据库,再操作缓存。
究竟先操作缓存,还是数据库
(1)读请求,先读缓存,如果没有命中,读数据库,再set回缓存
(2)写请求
(2.1)先缓存,再数据库
(2.2)缓存,使用delete,而不是set
缓存,究竟是淘汰,还是修改
允许cache miss的KV缓存写场景:
• 大部分情况,修改value成本会高于“增加一次cache miss”,因此应该淘汰缓存
• 如果还在纠结,总是淘汰缓存,问题也不大
进程内缓存
除了常见的redis/memcache等进程外缓存服务,缓存还有一种常见的玩法,进程内缓存。
db如何快速回滚+恢复
保证数据的安全性是DBA第一要务:
(0)理论上可以恢复+跑路;
(1)全量备份+增量备份+定期演练;
(2)1小时延时从库;
(3)双份1小时延时从库+提高资源利用率;
选redis还是memcache
memcache和redis是互联网分层架构中,最常用的KV缓存。不少同学在选型的时候会纠结,到底是选择memcache还是redis。
Java之Holder技术
为了解决上面提到的将函数内分配的空间传递到函数外的过程,Holder技术被发现了。原理其实非常简单,引用类型在函数执行的前后可以改变的是引用类型指向的内容,那么将我们想要的引用类型封装在另外一个引用类型中就可以对我们想要的引用类型进行自由变化了。
朋友圈微博feed流,推拉实践
feed流业务的推拉模式小结:
• 拉模式,读扩散,feed存一份,存储小,用户集中访问数据,性能差
• 推模式,写扩散,feed存多份,用冗余存储换锁冲突,性能高
feed流拉取,读扩散
优点:
• 存储结构简单,数据存储量较小,关系数据与feed数据都只存一份
• 取消关注,发布feed的业务流程非常简单
• 存储结构,业务流程都比较容易理解,非常适合项目早期用户量、数据量、并发量不大时的快速实现
缺点也显而易见:
• 拉取朋友圈feed流列表的业务流程非常复杂
• 有多次数据访问,并且要进行大量的内存计算,大量数据的网络传输,性能较低
GFS(Google File System)架构
GFS的架构,体现了很多经典的设计实践:
• 简化系统角色,单点master降低系统复杂度
• 不管是文件还是服务,均通过“冗余+故障自动转移”保证高可用
• 由于存在单点master,GFS将“降低与单点master的交互”作为性能优化核心
• 通过写日志,原子修改,checksum,快速监控快速恢复等方式保证可靠性与完整性
• 通过串行化保证多个副本数据的一致性
• 控制流与数据流分离,提高性能
集合合并与查找-并查集
分离集合(disjoint set)是一种经典的数据结构,它有三类操作:
Make-set(a):生成包含一个元素a的集合S;
Union(X, Y):合并两个集合X和Y;
Find-set(a):查找元素a所在集合S,即通过元素找集合句柄;
内容反爬技术解析
爬虫是一种按照某种特定的规则,自动抓取万维网信息的程序或者脚本。反爬虫是运用各种技术阻止爬虫抓取数据的同时还能让正常用户获取数据。随着爬虫技术进步,程序很难能完全分辨出请求者是否为爬虫,由此反爬虫技术衍生出了一个新的分支---内容反爬。
磁盘满了,为啥du却显示还有很大空间
• du:disk usage
• df:disk free
• lsof:list open files
• echo "" > access.log
点评网的反爬
点评网对数字做了处理,一些数字的信息像评论条数、人均、评分等都做了反爬保护。上面的网页中评论条数是1405条,但在页面源码中,除了第一个数字1以外,后面的数字我们看不到,都是一些像随机编码一样的css class。
Google MapReduce(四)
MapReduce离线业务的特点是:
• 吞吐量比较小,同时发起的任务比较少
• 每个任务,处理的数据量非常大
• 用户对处理时延容忍性大
这类业务,使用“固定数据,移动CPU”的分层架构是合理的。
Google MapReduce(三)
Google MapReduce架构,提现了很多经典架构实践:
• 单点master简化系统复杂度
• 单点master不高可用,简化系统复杂度
• master对worker的监控以及重启,保证worker高可用
• 幂等性,保证结果的正确性
• 多个worker执行同一个任务优化长尾问题
Google MapReduce(二)
Google MapReduce实施了一系列的优化。
• 分区函数:保证不同map输出的相同key,落到同一个reduce里
• 合并函数:在map结束时,对相同key的多个输出做本地合并,节省总体资源
• 输入文件到map如何切分:随意,切分均匀就行
Google MapReduce(一)
• 并行计算
• 数据分发
• 错误处理
• 集群通讯
• …
这些综合到一起,就成为了一个困难的问题,这也是Google MapReduce工程架构要解决的问题
多点登录和消息漫游设计实现
“多点登录”是指多个端同时登录一个帐号,同时收发消息,关键点是:
(1) 需要在服务端存储同一个用户多个端的状态与登陆点;
(2) 发出消息时,要对发送方的多端与接收端的多端,都进行消息投递;
“消息漫游”是指一个用户在任何端,都可以拉取到历史消息,关键点是:
(1) 所有消息存储在云端;
(2) 每个端本地存储last_msg_id,在登录时可以到云端同步历史消息;
(3) 云端存储所有消息成本较高,一般会对历史消息时间(或者条数)进行限制;
Google BigTable
BigTable是一个稀疏的、分布式的、持久化的、多维度排序的、大数据量存储系统,它能够解决符合上述map数据模型业务的存储问题。
离线消息设计实现
“离线消息”的玩法,可能比大家想象的要复杂,常见的优化有:
(1) 对于同一个用户B,一次性拉取所有用户发给ta的离线消息,再在客户端本地进行发送方分析,相比按照发送方一个个进行消息拉取,能大大减少服务器交互次数;
(2) 按需拉取,是无线端的常见优化;
(3) 分页拉取,是一个请求次数与包大小的折衷;
(4) 应用层的ACK,应用层的去重,才能保证离线消息的不丢不重;
(5) 下一页的拉取,同时作为上一页的ACK,能够极大减少与服务器的交互次数;
消息顺序性设计实现
(1)要“有序”,先得有衡量“有序”的标尺,可以是客户端标尺,可以是服务端标尺;
(2)大部分业务能够接受大范围趋势有序,小范围误差;绝对有序的业务,可以借助服务器绝对时序的能力;
(3)单点序列化,是一种常见的保证多机时序统一的方法,典型场景有db主从一致,gfs多文件一致;
(4)单对单聊天,只需保证发出的时序与接收的时序一致,可以利用客户端seq;
(5)群聊,只需保证所有接收方消息时序一致,需要利用服务端seq,方法有两种,一种单点绝对时序,另一种id串行化;
群消息设计实现
群消息还是非常有意思的,做个简单总结:
(1)不管是群在线消息,还是群离线消息,应用层的ACK是可达性的保障;
(2)群消息只存一份,不用为每个用户存储离线群msg_id,只需存储一个最近ack的群消息id/time;
(3)为了减少消息风暴,可以批量ACK;
(4)如果收到重复消息,需要msg_id去重,让用户无感知;
(5)离线消息过多,可以分页拉取(按需拉取)优化;
微服务架构服务拆分粒度
总的来说,细粒度拆分的优点有:
• 服务都能够独立部署
• 扩容和缩容方便,有利于提高资源利用率
• 拆得越细,耦合相对会减小
• 拆得越细,容错相对会更好,一个服务出问题不影响其他服务
• 扩展性更好
细粒度拆分的不足也很明显:
• 拆得越细,系统越复杂
• 系统之间的依赖关系也更复杂
• 运维复杂度提升
• 监控更加复杂
• 出问题时定位问题更难
微服务架构,RPC细节
什么是RPC调用?
像调用本地函数一样,调用一个远端服务。
为什么需要RPC框架?
RPC框架用于屏蔽RPC调用过程中的序列化,网络传输等技术细节。让调用方只专注于调用,服务方只专注于实现调用。
什么是序列化?为什么需要序列化?
把对象转化为连续二进制流的过程,叫做序列化。磁盘存储,缓存存储,网络传输只能操作于二进制流,所以必须序列化。
同步RPC-client的核心组件是什么?
同步RPC-client的核心组件是序列化组件、连接池组件。它通过连接池来实现负载均衡与故障转移,通过阻塞的收发来实现超时处理。
异步RPC-client的核心组件是什么?
异步RPC-client的核心组件是序列化组件、连接池组件、收发队列、收发线程、上下文管理器、超时管理器。它通过“请求id”来关联请求包-响应包-回调函数,用上下文管理器来管理上下文,用超时管理器中的timer触发超时回调,推进业务流程的超时处理。
微服务设计
• 每个服务都是一个轻量级、独立和松散耦合的业务单元。
• 每个服务都有自己的代码库,由一个小团队管理和开发(主要是用于敏捷环境中)。
• 每个服务负责一部分功能或者说业务能力,并且做得很好。
• 每个服务都可以为其用例选择最佳的技术栈(无需将整个应用程序绑定在一个框架中)。
• 每个服务都有自己的DevOps计划(测试、发布、部署、扩展、集成和独立维护)。
• 每个服务都部署在一个独立自给的环境中。
• 服务通过使用定义良好的API(智能端点)和简单协议如基于HTTP 的REST协议(哑管道)相互通信。
• 每个服务负责持久化自己的数据和保持外部状态(只有当多个服务使用相同的数据时,这种情况才在公共数据层中处理)。
为什么要做服务化
好处一:调用方简单
好处二:复用性,防止代码拷贝
好处三:专注性,屏蔽底层复杂度
好处四:SQL质量得到保障
好处五:数据库解耦
好处六:提供有限接口,无限性能
好处七:…
两阶段提交
2PC在执行过程中,所有节点都处于阻塞状态,所有节点所持有的资源(例如数据库数据,本地文件等)都处于封锁状态。
分布式系统CAP
• CAP可以理解为一致性,可用性,联通与扩展性
• CAP三者只能取其二
• 最常见的实践是AP+最终一致性