【总结笔记】数据密集型应用系统设计

数据库、消息队列、高速缓存等被视为不同类型的数据系统。
Redis 既可以用于数据存储也适用于消息队列,Apache Kafka 作为消息队列也具备了持久化存储保证。
备注:消息队列 MQ 主要用来:1)解耦应用;2)异步化消息;3)流量削峰填谷
目前常用的有ActiveMQ,RabbitMQ,kafka等。除此之外,Redis 也可以实现轻量级 MQ 的过程。
相比上述的组件,Redis 实现轻量级 MQ降低了服务端的工作量。Redis提供的list数据结构非常适合做消息队列。 如何实现即时消费,符合实现 ACK 机制?
1)如何实现即时消费
使用 Redis 中 list 的操作 BLPOP 或 BRPOP,即列表的阻塞式(blocking)弹出。

BRPOP key [key ...] timeout

列表的阻塞式弹出有 2 个特点:
1)若 list 无任务的时候,该连接会被阻塞;
2)连接的阻塞有一个超时时间,当超时时间设置为 0 时,即可无限等待,直到弹出消息。
备注:在生产-消费者模型中,如果队列空,消费者陷入阻塞。为了更好的优化性能,可以设置阻塞时间,超过某个时间就返回错误信息;对于生产者而言,也如此。

在复杂的应用系统中,单个组件无法满足所有数据处理与存储需求,因而需要将任务分解,每个组件负责高效完成其中一部分,多个组件依靠应用层代码驱动有机衔接起来。
eg:某个应用包含缓存层(Memcached)与全文索引服务器(ES),二者与主数据库保持关联,通常由应用代码负责缓存、索引与主数据库之间的同步。
备注:请设计一个复杂的数据存储系统,谈谈有几个组件,分别有什么功能?

1)本地高速缓存(Memcache 或 Redis 缓存服务器)【本地 map 映射数据就是本地缓存】;2)全文索引服务器 ES,负责搜索分析数据;3)保证持久化的数据库;4)消息队列,与外部主机通信
由应用代码负责缓存、索引、主服务器之间的同步。

客户端发起一个请求,服务端首先会在本地缓存查看该请求,若有直接拿数据,若缓存未命中,则从主数据库读取数据。若数据库的数据发生变动,则应用代码也要更新 ES 的索引信息。这样客户端向 ES 发起查询请求,所获取的数据就是最新的。如果服务端需要与外部主机通信,会起一个异步任务,通过消息队列将数据传送出去。【主机与外部通信,数据结构是消息队列,但最终还是走 socket 缓冲区】

设计数据系统或数据服务时, 定会碰到很多棘手的问题。例如,当系统内出现了局部失效时,如何确保数据的正确性与完整性?当发生系统降级( degrade )时,该如何为客户提供 致的良好表现?负载增加时,系统如何扩展?友好的服务API该如何设计?

1)当系统内出现了局部失效时,如何确保数据的正确性与完整性?
从可靠性与可维护性回答。
· 可靠性。如果是硬件故障,可以通过添加硬件冗余来减少系统故障率,同时也可以通过软件容错的方式作为硬件容错的有力补充;
· 可维护性。首先系统要保证数据复制,例如主从复制,在主从复制里又有一个同步复制结点,多个异步复制结点。如果是主节点失效,则节点切换主节点发生故障。不仅需要将某个从节点提升为主节点(通过选举机制),客户端也需要更新。这样之后的写请求会发送给新的主节点。如果是从节点失效,则通过Append 模式恢复。根据从节点的复制日志,从节点可以知道发生故障前所处理的最后一笔事务,然后向主节点发起请求,请求这笔事务之后中断期间内所有的数据变更。
2)当发生系统降级( degrade )时,该如何为客户提供始终如一的良好性能?
可以通过限流的方式。
3)负载增加时,系统如何扩展?

参考链接:https://learn.lianglianglee.com/专栏/高并发系统设计40问/26 负载均衡:怎样提升系统的横向扩展能力?.md
4)友好的服务API该如何设计?
谈RESTful 与 RPC 的区别。

为什么使用 NoSQL?
1)高扩展性和高可用性,即支持超大数据集或超高写入吞吐量
关系型数据库难以通过配置来进行横向扩展。
2)海量数据的读写效率高
在高并发场景下,对关系型数据库而言,I/O 开销是一个很大的挑战。关系型数据库不能很好地支持一些特定的查询操作;

数据流模式

每当一些数据发送到非共享内存的另一个进程时,若当通过网络发送数据或者把它写入文件时,都需要将数据编码为字节序列。
下述探讨一些最常见的进程间数据流动的方式:
1)通过数据库(基于数据库的数据流)
2)通过服务调用(基于服务的数据流:REST 和 RPC )
RPC 模型试图使用远程网络服务发出请求看起来与在同一进程中调用编程语言中的函数或方法相同。根本缺陷:
· 本地函数调用可预测,成功与否取决于传入的参数;网络请求不可预测,请求或响应可能由于网络问题丢失。
RESTful API 的优点:有利于实验和调试
3)通过异步消息传递(基于消息队列的数据流)
与直接 RPC 相比,使用消息代理有如下优点:
3-1)具有缓冲区,提高系统的可靠性;
3-2)消息队列会自动将消息发送到对方进程,防止消息丢失;
3-3)数据发送方与接收方完全解耦,无需知道对方的存在;
3-4)支持单播或多播

数据复制

3 种流行的复制数据变化:主从复制、多主节点复制和无主节点复制。

1 主从复制,包括一个同步的从节点和一个异步的从节点

从节点 1 的复制是同步的,主节点需等待直到从节点 1 确认完成了写入,然后向用户报告完成。从节点 2 的复制都是异步的:主节点发送完消息之后立即返回,无需等待从节点 2 的完成确认。
同步复制优点:保证从节点的数据与主节点尽可能相同。
同步复制缺点:主节点在未得到从节点的确认前,会一直阻塞,无法对外提供读写服务。
备注:若数据库启动用同步复制,通常意味着其中某一个从节点是同步的,其他节点是异步模式(所以,准确说法叫半同步模式)。
通常主从复制被设置为全异步模式。若主节点发生失败且不可恢复,则所有尚未复制到从节点的写请求都会丢失。
异步复制优点:系统吞吐性能好。无需等待从节点的确认,直接响应写请求。
异步复制缺点:无法完全保证数据的持久化。

如何通过主从复制技术来实现系统高可用?
从节点失效:Append 模式恢复
根据从节点的复制日志,从节点可以知道发生故障前所处理的最后一笔事务,然后向主节点发起请求,请求这笔事务之后中断期间内所有的数据变更。
主节点失效:节点切换
主节点发生故障,不仅需要将某个从节点提升为主节点(通过选举机制),客户端也需要更新。这样之后的写请求会发送给新的主节点。

主从复制带来的问题:写后读一致性 【重点】

问题:若用户在写入不久即查看数据,则新数据可能尚未到达从节点。导致写后读不一致。

解决办法:
方案 1)若用户访问可能会被修改的内容(例如社交网络的用户首页信息),则从主节点读取;否则(读取其他用户的配置信息),在从节点读取。
方案2)客户端可以记住最近更新时的时间戳,并附带在读请求中。若提供服务的节点上的本条数据未超过该时间戳,则由另外个从节点提供读服务,或等待更新。【类似多版本并发控制的思想】

分区与复制

组合使用复制和分区:每个节点同时充当某些分区的主副本和其他分区的从副本

键-值数据的分区
分区的主要目标是将数据和查询负载均匀分布在所有节点上,数据和查询负载越均匀,则吞吐量越大,越不均匀,就越容易造成热点问题,吞吐量越小。
分区所要解决的重要问题是:避免热点
避免热点最简单的方法是将记录随机分配给所有节点,缺点是:无法知道数据保存在哪个节点上,读取特定数据时,需要并行查询所有节点。
改进方法:一致性哈希。

posted @   MasterBean  阅读(1869)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示