一、MR - 同流合污的技术
MapReduce:大而化小,分而治之。Map负责把大任务分割为小任务,Reduce负责对Map结果进行汇总。子问题相互独立,子问题的解合并后可得到原问题的解。
架构:MRMater负责分配任务、协调任务,并为Mapper分配map()函数操作,为Reducer分配reduce()函数操作。Mapper Worker负责map函数功能,即执行子任务。Reducer Worker负责reduce函数功能,即负责汇总任务。

二、Stream - 流式计算。
流数据:源源不断的、具有时效性的数据。
特点:实时加载数据,不存储数据,处理过程计算逻辑不可更改,逻辑一旦修改之前的数据无法重新计算,低时延。适合对时间敏感的实时计算,数据密集型但可以拆分为小批量数据的任务。如Storm、IBM、淘宝银河等。
Storm:Nimbus运行在主节点负责分发代码和任务分配。Worker进程分为Spout用来接收数据和Bolt用来处理数据。

三、Actor - 封装的实现
开发分布式模式时,需要维护进程之间的状态、数据等,工作量巨大。而Actor就帮我们实现了。指定了Actor内部的计算逻辑和多个Actor之间的通信规则。
多个Actor以消息传递,每个Actor都有个信箱。
实现了更高级别的抽象、非阻塞、无锁、并发高、易扩展。但代码重用性小、系统开销大、实现复杂、不适用严格要求消息顺序的系统。
应用有:Erlang/OTP、Akka、Quasar等。

四、流水线
节点1处理任务A第一步 -> 随后,节点2处理任务A第二步,空闲的节点1处理任务B第一步。把同个任务拆分为多个步骤交由不同节点执行。每个节点顺序的处理多个任务中特定的某一步。
MapReduce强调大任务拆分为小任务,任务间执行相同的逻辑且无依赖。流水线强调同一个任务分为不同的步骤,一个节点的输出是下一个节点的输入。
例如:TensorFlow的机器学习流水线来讲:

  • 节点1处理第N任务的数据的输入,然后交由节点2,节点1继续处理第N+1个任务的输入。
  • 节点2执行数据转换,然后交由节点3。节点2继续做下一个任务的数据转换。
  • 节点3做特征提取,然后交由节点4。节点3继续做下一个任务的特征提取
  • 节点4做模型训练。

一、分布式结构体系 - 集中式
把多个服务器管理起来,作为一个统一的资源提供服务,即主从结构。
1、Borg:Google内部使用的集群管理系统,负责提交、调度、开始、重启等。闭源,单层调度框架,基本调度单元是Job,基本操作单元是Task。客户有Google。
2、Kubernetes:用于自动部署、扩展、容器管理。开源,单层调度框架,基于Borg实现。消除编排计算、网路和存储设施负担。基本调度单元是Pod,基本操作单元是Service。客户有网易云、华为等
3、Mesos:Apache旗下开源分布式资源管理框架,被称为分布式系统内核。开源,双层调度框架。为用户的数据中心提供动态的资源分配。基本调度单元是容器、Jon,基本操作单元是Task。客户有Twitter、Apple、爱奇艺等

二、分布式结构体系 - 非集中式
服务的执行和数据的存储被分散到不同的服务器集群,集群间通过消息通信。没有中央服务器和节点服务器之分,所有服务器地位平等。
1、Akka:完全去中心化的集群管理系统,每个节点进行数据处理和任务执行,节点间可通信。使用Gossip协议,成员之间P2P结构的网络拓扑。需要选主。
2、Redis集群:使用Gossip协议,基于哈希槽的网络拓扑。需要选主。为高可用每个节点都需要有一个从库。
3、Cassandra:一致性哈希的P2P结构,使用Gossip协议,不需要选主。

三、分布式调度 - 单体调度
一个集群中只有一个节点运行调度进程,该节点可访问其他节点,搜集其他节点的资源信息和状态。根据用户下发的任务需求选择最合适的节点执行。单体调度器拥有全局资源视图和全局任务,可以很容易地实现对任务的约束并实施全局性的调度策略。如Borg、Kubernetes等。
调度设计:以任务为单位调度。
调度算法:

  • 筛选可行:如某任务指定在1、3、5节点执行,并需要内存多少CPU多少。
  • 评分取优,包括最差匹配:选择资源最宽松的节点,但会导致每个节点都有无法满足其他任务的资源碎片;最优匹配:先把一个节点的资源用满,在选择其他节点。

四、分布式调度 - 两层调度
解决单体调度的性能瓶颈,部署在节点集群中的一层负责收集资源信息,并同步给二层,二层和业务部署在一起,二层来根据资源和任务进行节点选择,选择的节点和任务再下发给一层,由一层下发给执行节点。
1、Apache Mesos:每个集群只有一个Master节点,用于管理Slave节点。并对接上层框架(如Hadoop)。

  • Master进程收集所有节点信息并上报给注册的上层框架,上层框架进行任务调度,并将匹配结果下发给Master,由Master转发给执行器。
  • 调度算法:最大最小公平算法:兼顾公平的同时尽可能让更多人满足资源分配。主导资源公平算法:考虑公平性的前提下考虑任务具体需求(CPU密集任务主要用CPU,内存密集型任务主要用内存)

五、分布式调度 - 共享状态调度
基于单体调度模式,分解为多个调度器,每个调度器都有全局的资源信息。解决了单体调度的瓶颈问题,解决了两层调度的无法匹配最优解,但存在资源冲突的问题且实现复杂。如Google Omega。

一、分布式互斥
多个请求只有第一个可以取得资源,其他请求需要等待资源释放,这种资源称为临界资源。
1、霸道总裁式:引入一个协调者,先来先得。简单高效,但可用性低。适用于协调者可靠性和性能有一定保障的前提下的广泛场景。
2、民主协商式:征得其他请求同意后使用临界资源。可用性高,但复杂度高、通信成本高。适用于系统规模小且资源使用频率低。
3、轮值CEO(令牌环):所有参与者为一个环,轮流使用。单个参与者通信效率高可用性高,但当参与者使用频率低时有较多的无用通信。适用于系统规模小且每个程序使用资源频率高时间短。

二、分布式选举
分布式系统中多节点选举出有一个主,负责数据同步,保持各节点的一致性。本质上选举问题就是传统的分布式共识方法,主要是基于多数投票策略实现的。
1、Bully:节点ID最大的的为leader。易于实现复杂度低,但信息存储量大且频繁易主。适用小规模场景如MongoDB集群。
2、Raft:少数服从多数。速度快复杂度低,但系统需要全链且通信量大。适用于中小规模场景如k8s集群三节点选举。
3、ZAB:倾向于数组最新或节点ID最大的作为主。性能高无环境特殊需求,但选举时间长复杂度高。适用于大规模分布式场景如Zookeeper

三、分布式共识 - 求同存异
基于多数投票策略的分布式选举方法,用于分布式在线记账一致性问题中,那么记账权通常会完全掌握到主节点的手里,这使得主节点容易造假且存在性能瓶颈。分布式在线记账,是指没有集中的发行方(银行),任意一台电脑都能参与买卖,所有看到该交易的服务器都可以记录这笔交易,并且记录信息最终都是一致的,以保证交易的准确性。如区块链技术。
共识描述的是达成一致的过程,一致性强调的是结果。
1、PoW:按劳分配,每节点靠算力竞争记账权。相对公平、有容错、去中心,但不适合私有链、共识效率低、交易服务费高。如比特币。
2、PoS:由系统权益代替算力决定区块记账权的共识机制,权益越大越容易。资源消耗低、服务费低、达成共识周期短,但交易量较低、容易垄断、无法处理分叉连。如以太坊、点点币。
3、DPoS:解决PoS垄断问题,由持币人进行投票选出一个节点作为代表来参与竞争。能耗低、交易量高、无垄断、服务费低,但持币人投票积极性不高、故障解决效率低。如太股、EOS等。

四、分布式事务
ACID:原子性、一致性、隔离性、持久性。强调的是强一致性。即刚性事务。
BASE:基本可用(Basically Available)、柔性状态、最终一致性。弱化后ACID,强调的是最终一致性。即柔性事务。
1、基于XA的二阶段提交协议:一个中央协调者,先把请求发给各节点,节点处理完毕后返回YES/NO;各节点都返回YES时,协调者发送提交请求。强一致性、同步执行、简单,但同步阻塞、单点故障、性能低、数据不一致问题。
2、三阶段提交协议:引入了超时机制,二阶段中间增加了准备机制,解决了同步阻塞和单点故障问题。强一致性、同步执行、无同步阻塞、无单点故障,但性能低、数据不一致。
3、基于分布式消息的最终一致性:事务通过消息或日志来异步执行,通过业务规则进行业务重试,增加多种中间状态,如已下单未付款、已付款商家未确认等。先请求MQ,MQ执行下单;再请求MQ、MQ执行库存;再请求MQ、MQ执行通知仓储。最终一致性、异步执行、无同步阻塞、无单点故障、高性能,但算法复杂度高。

五、分布式锁
1、数据库:创建一张锁表。容易理解,但单点故障、死锁问题、性能低、可靠性低。适用于性能和并发量低的场景。
2、redis缓存:通过setnx实现,并设置过期时间。性能高、有集群、易于实现,但可靠性不如Zookeeper、锁失效时间的控制不稳定。适用于高并发、高性能的场景。
3、ZooKeeper:对应的持久节点目录下为每个进程创建临时顺序节点,每个节点确定编号是否最小,最小编号获得锁,否则等待。无单点、无不可重入、无死锁、解决数据库锁和缓存锁的不足、可靠性高、易于实现,但性能不如内存缓存式高、难以理解。适用于大部分场景,但不适合极高性能要求的场景。

一、通过浏览器访问摄像头
1、流程:
两端一样:WebRTC终端(音视频采集、录制、检测)->signal(信令服务器,如加入房间、离开房间等消息传递)->创建连接
连接方式:优先P2P,NAT穿越失败时使用STUN/TURN,负责获取公网IP、消息转发。
2、概念:

  • 帧率:摄像头一秒钟采集图像的次数称为帧率。越高视频越平滑流畅,占用带宽越多。
  • 分辨率:摄像可设分辨率。越高图像越清晰,占用带宽越多。
  • 宽高比。分辨率的宽高比,常见16:9、4:3
  • 采样率:音频和视频一样可指定一秒的采样次数。
  • 采样位深:即采样大小,每个采样用几bit表示。
  • 轨(Track):WebRTC借鉴了多媒体概念,像火车轨道永不会相交。如MP4中的音频轨、视频轨被分别存储。
  • 流(Stream):即容器。分为媒体流(MediaStream)和数据流(DataStream)。媒体流可存0个或多个音频轨或视频轨,数据流可以存0个或多个数据轨。
    3、编码:
  • 使用getUserMedia对象获取设备,MediaStreamConstraints参数设置使用音频轨还是视频轨并配置。

二、设备检测
1、原理:

1)音频:需要采集、量化、编码三步,最终形成数字信号。
  • 采集的模拟信号转为数字信号。使用奈奎斯特定理(转换时采样率大于信号中最高频率2倍时会完整地保留了原始信息。即人类听觉范围20Hz~20kHz,日常8kHz即可。为了高保真需设置采样在40kHz以上,所以我们听歌会见到 44.1k、48k等。
  • 量化和编码时,采样大小决定了每个采样最大可以表示的范围。如采样8位则最大255,16位最大数值是 65535。

    2)视频:
  • 光通过镜头到摄像机后通过视频设备的模数转换,即光学传感器。数字信号就是RGB。
  • RGB通过DSP进行优化处理,如自动增强、白平衡、色彩饱和等,就得到24位真彩色图片(每种颜色8位)。
  • RGB进行压缩、传输,生成YUV格式图像。编码器输入格式为YUV I420,所以摄像头内有一个模块将RGB转为YUV。YUV是一种色彩编码方法,用于电视系统和模拟视频领域。将亮度Y与色彩UV分离,解决了彩色电视机与黑白电视的兼容。
    2、检测:

先排查视频设备,再排查音频设备,需要调用两次getUserMedia。
3、编码:

  • MediaDevices接口提供了访问设备的方法。部分字段(如label)需要HTTPS

三、浏览器拍照
1、概念:

  • 非编码帧:摄像头采集的帧或通过解码后的帧。一般是YUV或RGB。播放器需要的也是非编码帧。
  • 编码帧:通过编码器(如 H264/H265、VP8/VP9)压缩后的帧。如H264编码后包括:

    • I帧:关键帧,压缩率低,可单独解码成完整图像。
    • P帧:参考帧,压缩率较高,解码时依赖于前面已解码的数据。
    • B 帧:前后参考帧,压缩率最高,解码时依赖前面已经解码的帧,还依赖它后面的P帧。
      2、编码:
  • 依赖Canvas对象

四、录制
1、录制后的格式:

  • FLV是流式的,可在任何位置进行读写操作都可以正常处理。缺点是必须按顺序播放,但UDP这种不可靠传输是不保证顺序的。
  • 原始数据:FLV不支持多路数据。
    2、录制后如何播放:

多人互动且回放要和直播时一样,就必须使用私有播放器,普通播放器不支持同时播放多路视频的。
3、录制后多久播放:

  • 边录边看:将视频按N分钟为单位录制成一段一段的,然后录完一段播一段。
  • 录完后看。
  • 录完过会看:录制后做编码处理。
    4、编码:
  • MediaRecorder对象。
  • WebRTC用Blob类型存储录制的流。

五、抓取桌面
1、编码:getDisplayMedia对象。

六、原理
1、RTP和RTCP:TCP性能低,七次重试共耗时2分07秒,所以实时音视频必须使用UDP。

  • 为了解决UDP无序问题,给每个分片(一个大数据会切为多个分片)加上RTP头(序号、起始帧结束帧的标记),这样就可以对数据包排序组装。
  • RTP包传输会遇到丢包、抖动、乱序的问题,引入RTCP协议,包含RR和SR两个报文,用来描述网络质量。
    2、SDP:WebRTC驱动核心,描述各端的处理能力,包括音视频、传输协议、支持的码率、采样率(32000、48000)、编码器名称(VP8、VP9)等。

3、媒体协商:依靠RTCPeerConnection对象,各端通过信令服务器发送SDP,协商最终使用的编解码器、传输协议等参数。
4、建立连接:

  • 两端在内网:走内网或公网绕一圈。
  • 两端在异地:优先P2P,不通时使用中继服务器(也称relay服务器或TURN 服务器)
  • 两端收集Candidate,包括内网IP端口、NAT映射后内网IP端口(STUN协议)、中继服务器IP端口。WebRTC根据优先级排序,选择最佳的方式。
  • NAT的作用:多台主机公用一个外网IP,内部使用内网IP通信,一是节省IPv4,二是有NAT挡住更安全。缺点是复杂度更高,主机直接通信需要NAT穿越。
    5、NAT穿越原理:
  • 完全锥型:在NAT上打个洞(NAT对内网主机做了映射),使用UDP协议。
  • IP 限制锥型:只有主机访问过的外网IP,才可以打洞成功。
  • 端口限制锥型:只有主机访问过的外网IP和端口,才可以打洞成功。
  • 对称型:只有主机访问过的外网IP和端口,才可以打洞成功,并且主机访问外网的洞,和外网访问主机的洞,不是同一个洞。因此如果两端都是对称型或对称型+端口限制型,基本穿越失败。
    通过发UDP包的方式,判断哪条路可以通,就是哪种类型。

一、消息通道高可用设计。

1、连的上

  • HTTP Tunnel:在部分公司或酒店的网络代理,只允许通过HTTP访问外网。这时就需要用HTTP Tunnel。就是用HTTP协议封装私有的TCP或UDP等不被网关认可的协议。
  • 多端口备用
  • 多IP:HTTPDNS提供IP列表

2、连的快:

  • 跨网延迟:用户和机房在同一个运营商。
  • 跑马竞速:链接前遍历HTTPDNS的IP列表,选一个最快的。

3、通道保持稳定:

  • 接入层和业务层解耦:业务层功能迭代发布重启,不会影响接入层,用户的长链接也就不会断开。接入层还可以多节点分别接入不同运营商。
  • 上下行通道隔离:大型直播中,下行推送量很大,上行很少。因此,短连接上行,避免维护长链接的开销,可以优化为短连接发完不立即断开,上行消息到达上行业务层,进行业务处理和存储,通过消息给到下行业务层,进行分发,下行是一个长链接。
  • 多媒体资源会用新通道,避免占用上下行通道。

二、文件上传

1、直接传到文件存储,返回唯一标识,这个表示作为文本消息进行下发。
2、分片上传:客户端分块并标记,服务器收到后按编号组装存储。重试也只重传一个分片。
3、分片大小:太小时TCP链接太多,报文也是浪费。可以粗略分:wift下2M,4G下1M,3G/2G下256K等。
4、断点续传:每个文件的多个块,都有同一个唯一标记,暂停时告诉服务器这个唯一标记的所有资源先别删(不能永久放)。
5、秒传:微博统计一周30%的图片和视频是重复的,所以先计算MD5并存储,如果已经有了,就不需要传文件了。

三、水平扩展

1、接入层:

  • 入口 VIP 瓶颈可以通过 DNS 轮询;
  • 接入层服务通过中央的“在线状态”资源,来解耦业务层的依赖。

2、业务层:通过“服务化”改造,用“注册发现”解决接入层寻址问题。
3、资源层:数据分片缓解主从库压力。

四、监控

1、系统层监控:Nagios、Zabbix等工具上报CPU内存等信息。
2、应用层监控:QPS、耗时、推送失败等。为数据规模和聚合查询,一般使用时序数据库,如 OpenTSDB、InfluxDB 等。
3、常见方案:

  • Statsd + Graphite + Grafana 方案
  • ELK(Elasticsearch + Logstash + Kibana)方案

4、trace链路追踪:

  • trace:一个完整的链路,携带一个统一的traceId。
  • span:一个服务的请求/响应叫做一个span。一个trace由多个span组成。
  • annotation:自定义事件和参数,如房间ID用户ID等。
  • 成熟系统:Twitter 的 Zipkin、Uber 的 Jaeger、阿里的鹰眼、美团的 Mtrace等。

5、回环探测:主动监控,模拟真实场景调用服务。

五、万人群聊

1、存储:存一份群消息,一份群最新消息id。先获取最新消息id,把群排序展示,再获取每个群的消息。
2、新入群只看新消息:用加群时间做条件。
3、未读数:对高热度群,通过应用层的“合并变更”,来缓解未读资源的写入压力。
4、离线消息:只存消息ID。
5、ACK:参考TCP的Delay ACK机制,在接收方批量ACK。
6、中央全局的在线状态:超大群用户一般分布在多台网关机中,群聊中优化成“网关机本地自治维护”的方式,以解决高并发下推时全局资源的瓶颈。

六、直播间和群聊的在线关系:

  • 直播间:房间之间状态隔离。每次用户进入新房间时,需要“加入房间”、“切换房间”等信令告诉网关机当前连接的是哪个房间。网关机才能够在服务端标记这个“用户 -> 房间 -> 连接”的映射关系。消息从业务层给到网关机时,服务端只需要按房间维度下发消息即可。所以在直播互动场景中,消息的扇出是可以推迟到网关机层的。
  • 群聊:群和群之间并不是隔离状态。对于任何群的消息,服务端都需要通过一条长连接通道来进行消息的下推。所以在 App 打开建立好长连后,客户端发出的“上线”这个操作,只是会上报一个当前用户信息,不需要、也没有办法再告知自己当前进入了哪个群,因而在服务端网关机也只会建立一个“用户” -> “连接”的映射。因此,在群聊场景中,当某一个群有一条消息发出时,我们需要在业务层将这条消息从群维度扇出成 UID 维度,再下发给网关机。我们尽量不在网关机做业务逻辑,所以在业务层扇出后,再提交到网关机进行处理。