0%

redis高可用

主从复制

主从复制

  • 一个master可以拥有多个slave,一个slave又可以拥有多个slave,如此下去,形成了强大的多级服务器集群架构
  • master用来写数据,slave用来读数据,经统计:网站的读写比率是10:1
  • 通过主从配置可以实现读写分离
  • master和slave都是一个redis实例(redis服务)

全量同步过程

主从复制

  1. 当一个从数据库启动时,会向主数据库发送sync命令
  2. 主数据库接收到sync命令后会开始在后台保存快照(执行rdb操作),并用缓存区记录后续的所有写操作
  3. 当主服务器快照保存完成后,redis会将快照文件发送给从数据库。
  4. 从数据库收到快照文件后,会丢弃所有旧数据,载入收到的快照。
  5. 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令。
  6. 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令。

 

增量同步的过程

Redis增量复制是指slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程。 

增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。

 

Redis主从复制全量与增量同步的选择

主从服务器刚刚连接的时候,会先进行全量同步;全同步结束后,再进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。

主从复制优缺点:

优点:

  • 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离
  • 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成
  • Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。
  • Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。
  • Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据

缺点:

  • Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
  • 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
  • Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。

哨兵模式(Redis Sentinel)

哨兵模式

功能

Sentinel 的主要功能包括 主节点存活检测、主从运行情况检测、自动故障转移 (failover)、主从切换。Redis 的 Sentinel 最小配置是 一主一从。
Redis 的 Sentinel 系统可以用来管理多个 Redis 服务器,该系统可以执行以下四个任务:

  • 监控

    Sentinel 会不断的检查 主服务器 和 从服务器 是否正常运行。

  • 通知

    当被监控的某个 Redis 服务器出现问题,Sentinel 通过 API 脚本 向 管理员 或者其他的 应用程序 发送通知。

-自动故障转移

当 主节点 不能正常工作时,Sentinel 会开始一次 自动的 故障转移操作,它会将与 失效主节点 是 主从关系 的其中一个 从节点 升级为新的 主节点,并且将其他的 从节点 指向 新的主节点。

  • 配置提供者

    在 Redis Sentinel 模式下,客户端应用 在初始化时连接的是 Sentinel 节点集合,从中获取 主节点 的信息。

主观下线和客观下线

默认情况下,每个 Sentinel 节点会以 每秒一次 的频率对 Redis 节点和 其它 的 Sentinel 节点发送 PING 命令,并通过节点的 回复 来判断节点是否在线。

主观下线

主观下线 适用于所有 主节点 和 从节点。如果在 down-after-milliseconds 毫秒内,Sentinel 没有收到 目标节点 的有效回复,则会判定 该节点 为 主观下线。

客观下线

客观下线 只适用于 主节点。如果 主节点 出现故障,Sentinel 节点会通过 sentinel is-master-down-by-addr 命令,向其它 Sentinel 节点询问对该节点的 状态判断。如果超过 个数的节点判定 主节点 不可达,则该 Sentinel 节点会判断 主节点 为 客观下线。

更多参考

哨兵模式的优缺点

优点

  • 哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有。
  • 主从可以自动切换,系统更健壮,可用性更高。

缺点

  • Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。

集群模式

Redis 3.0 之前,使用 哨兵(sentinel)机制来监控各个节点之间的状态。Redis Cluster 是 Redis 的 分布式解决方案,在 3.0 版本正式推出,有效地解决了 Redis 在 分布式 方面的需求。当遇到 单机内存、并发、流量 等瓶颈时,可以采用 Cluster 架构方案达到 负载均衡 的目的。

数据分区

虚拟槽分区

redis集群中数据是和槽(slot)挂钩的,其总共定义了16384个槽,所有的数据根据一致哈希算法会被映射到这16384个槽中的某个槽中;

另一方面,这16384个槽是按照设置被分配到不同的redis节点上的,比如启动了三个redis实例:cluster-A,cluster-B和cluster-C,这里将0-5460号槽分配给cluster-A,将5461-10922号槽分配给cluster-B,将10923-16383号槽分配给cluster-C(总共有16384个槽,但是其标号类似数组下标,是从0到16383)。也就是说数据的存储只和槽有关,并且槽的数量是一定的,由于一致hash算法是一定的,因而将这16384个槽分配给无论多少个redis实例,对于确认的数据其都将被分配到确定的槽位上。redis集群通过这种方式来达到redis的高效和高可用性目的。

更多参考

Redis虚拟槽分区的特点

  • 解耦数据和节点之间的关系,简化了节点扩容和收缩难度。
  • 节点自身维护槽的映射关系,不需要客户端或者代理服务维护槽分区元数据。
  • 支持节点、槽、键 之间的映射查询,用于数据路由、在线伸缩等场景

Redis集群的功能限制

Redis 集群相对单机在功能上存在一些限制。

  • key批量操作支持有限。

    类似mset、mget操作,目前只支持对具有相同slot值的key执行 批量操作。对于映射为不同slot值的key由于执行mget、mget等操作可能存在于多个节点上,因此不被支持。

  • key事务操作支持有限。

    只支持多key在同一节点上的事务操作,当多个key分布在不同的节点上时无法使用事务功能。

  • key作为数据分区的最小粒度

    不能将一个大的键值对象如hash、list等映射到不同的节点。

  • 不支持多数据库空间

    单机下的Redis可以支持16个数据库(db0 ~ db15),集群模式 下只能使用一个数据库空间,即db0

  • 复制结构只支持一层

    从节点只能复制主节点,不支持嵌套树状复制结构。

redis常见问题

缓存雪崩

缓存雪崩我们可以简单的理解为:由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。

解决方案:

  • 排队加锁
  • 缓存增加标记,过期前就更新
  • 缓存时间增加随机属性,错开同一时间过期

缓存穿透

缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。

解决方案:

  • 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。
  • 如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。通过这个直接设置的默认值存放到缓存,这样第二次到缓存中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴!

缓存击穿

对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里针对某一key缓存,前者则是很多key。

缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

解决方案:

  • 使用互斥锁(mutex key)
  • “设置永不过期”,参考

缓存预热

缓存预热就是系统上线后,提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

什么是流式计算

流式计算一般被用来和批量计算做比较。批量计算往往有一个固定的数据集作为输入并计算结果。而流式计算的输入往往是“无界”的(Unbounded Data),持续输入的,即永远拿不到全量数据去做计算;同时,计算结果也是持续输出的,只能拿到某一个时刻的结果,而不是最终的结果。(批量计算是全量的:拿到一批数据,计算一个结果;流式计算是增量的:数据持续输入,持续计算最新的结果)

流式计算框架

Storm Trident Spark Streaming Flink Samza Kafka streams
数据流模型 原生 微批 微批 原生 原生 原生
状态存储 不支持状态管理 本地存储,外部数据库 多种状态存储方式 多种状态存储方式 本地存储,Kafka主题 本地存储,日志变更主题
时延
吞吐量
保障机制 at-least-once exactly-once exactly-once exactly-once at-least-once exactly-once
容错机制 record ack record ack RDD based,checkpoint checkpoint Kafka log-base Kafka log
成熟度 较多不足,但实际应用比较广泛 Storm基础上改进 流行的框架之一,Spark大环境 较新的流处理框架,性能非常优秀 基于Kafka作为数据源 完全基于Kafka集群实现
定位 框架 框架 框架 框架 框架 类库

Kafka Streams

Kafka Streams is a client library for building applications and microservices, where the input and output data are stored in Kafka clusters. It combines the simplicity of writing and deploying standard Java and Scala applications on the client side with the benefits of Kafka’s server-side cluster technology.

Kafka Streams是一个构建应用程序和微服务的客户端库,并且输入数据个输出数据均是保存在Kafka集群上的。Kafka Streams主要有如下特点:

  • 非常简单的客户端库,可以非常容易的嵌入到任何java应用程序与任何应用程序进行封装集成。
  • 使用Kafka集群作为消息层,没有外部依赖。
  • 支持本地状态存储。
  • 提供了快速故障切换分布式处理和容错能力。
  • 提供了非常方便的API。
  • 支持exactly-once语义
  • 支持纪录级的处理,实现毫秒级的延迟
  • 提供High-Level的Stream DSL和Low-Level的Processor API

采用one-record-at-a-time的消息处理方式,实现消息处理的低延迟。
但是Kafka Streams的设计目标是足够轻量,所以很难满足对大体量的复杂计算需求,并且数据的输入和输出均是依靠Kafka集群,对于其他的数据源需要借助Kafka connect将数据输入到Kafka主题中,然后在通过Kafka Streams程序进行处理,并通过Kafka connect将主题中的数据转存到其他数据源。

所以Kafka Streams更适合计算复杂度较小,数据流动过程是Kafka->Kafka的场景。

Storm

在Storm中,需要先设计一个实时计算结构,我们称之为拓扑(topology)。之后,这个拓扑结构会被提交给集群,其中主节点(master node)负责给工作节点(worker node)分配代码,工作节点负责执行代码。在一个拓扑结构中,包含spout和bolt两种角色。数据在spouts之间传递,这些spouts将数据流以tuple元组的形式发送;而bolt则负责转换数据流。

  • 状态管理:无状态,需用户自行进行状态管理
  • 窗口支持:对事件窗口支持较弱,缓存整个窗口的所有数据,窗口结束时一起计算
  • 消息投递:At Most Once/At Least Once
  • 容错方式:对每个消息进行全链路跟踪,失败或超时进行重发。

Spark Streaming

采用微批的方式,提高了吞吐性能。Spark streaming批量读取数据源中的数据,然后把每个batch转化成内部的RDD。Spark streaming以batch为单位进行计算,而不是以record为单位,大大减少了ack所需的开销,显著满足了高吞吐、低延迟的要求,同时也提供exactly once功能。但也因为处理数据的粒度变大,导致Spark streaming的数据延时不如Storm,Spark streaming是秒级返回结果(与设置的batch间隔有关),Storm则是毫秒级。

但是Spark Streaming的优点是可以与Spark大环境进行有效的结合。

Flink

Flink 是一种可以处理批处理任务的流处理框架。Flink 流处理为先的方法可提供低延迟,高吞吐率,近乎逐项处理的能力,并且提供了复杂计算的能力。

Flink 完全支持流处理,也就是说作为流处理看待时,输入数据流是无界的;批处理被作为一种特殊的流处理,只是它的输入数据流被定义为有界的。这与 Spark streaming 不同,Spark streaming 是将流处理视为无限个有界的批处理(microbatch)。

  • 有状态计算的 Exactly-once 语义。状态是指 flink 能够维护数据在时序上的聚类和聚合,同时它的 checkpoint 机制可以方便快速的做出失败重试;
  • 支持带有事件时间(event time)语义的流处理和窗口处理。事件时间的语义使流计算的结果更加精确,尤其在事件到达无序或者延迟的情况下;
  • 支持高度灵活的窗口(window)操作。支持基于 time、count、session,以及 data-driven 的窗口操作,能很好的对现实环境中的创建的数据进行建模;
  • 轻量的容错处理(fault tolerance)。它使得系统既能保持高的吞吐率又能保证 exactly-once 的一致性。通过轻量的 state snapshots 实现;
  • 支持高吞吐、低延迟、高性能的流处理;
  • 支持 savepoints 机制(一般手动触发),可以将应用的运行状态保存下来;在升级应用或者处理历史数据上,能够做到无状态丢失和最小停机时间;
  • 支持大规模的集群模式,支持 yarn、Mesos。可运行在成千上万的节点上;
  • 支持具有 Backpressure 功能的持续流模型;
  • Flink 在 JVM 内部实现了自己的内存管理,包括完善的内存架构和 OOM error prevention;
  • 支持迭代计算;
  • 支持程序自动优化:避免特定情况下 Shuffle、排序等昂贵操作,中间结果进行缓存。

说明一

通常来说,对于单独的消息系统而言,语义分为如下三种:

至多一次(At most once):不管 Writer 在等待 ACK 时是否发生超时或者得到错误异常,Writer 都不会重新发送 Event,因此会有数据丢失的风险。在具体的实现过程中,这一种语义无需做任何额外的控制,实现起来最为简单,因此也通常有着最优的性能。在某些特定的场景中,我们只希望追求极致的性能而不关心数据的丢失,可能会选用此方案。

至少一次(At least once):如果 Writer 在等待 ACK 时发生超时或者得到错误异常,Writer 将会重新发送消息,这样能保证每个 Event 至少被处理一次,保证了数据不会丢失,从而提高了系统的可靠性,但同时会带来数据重复的问题,例如,当 Writer 往 Stream 中成功写入一个 Event,但是当系统尝试给 Writer 返回 ACK 的时候出现网络异常,Writer 因没有收到 ACK 而判断为写入 Event 失败,因此 Writer 还是会重新发送此 Event,导致数据重复。

仅一次(Exactly once):在系统发生异常时,Writer 可以尝试多次重新发送 Event,同时能保证最终每个 Event 只被写入一次。一些对数据准确性要求非常高的系统需要保证 exactly-once 语义,譬如支付系统,当用户在移动端付款时,很有可能会因为网络原因导致延时较长甚至超时,用户可能会手动进行刷新操作,如果没有 exactly-once 的语义支持,很有可能会发生两次扣费,我们绝对不希望此类错误发生。

说明二

美团flink测试

测试结论

推荐使用 Flink 的场景

  • 实时计算场景建议考虑使用 Flink 框架进行计算:
  • 要求消息投递语义为 Exactly Once 的场景;
  • 数据量较大,要求高吞吐低延迟的场景;
  • 需要进行状态管理或窗口统计的场景。

说明三 - 语言支持

Spark和flink都是JVM语言开发,在API层对java和Scala语言支持较好,python语言API支持,但是效率不高,其它语言几乎不支持。

什么是serverless?

简单的定义

Serverless(无服务器架构)指的是服务端逻辑由开发者实现,运行在无状态的计算容器中,由事件触发,完全被第三方管理,而业务层面的状态则记录在数据库或存储资源中。

进阶的定义

Serverless是由事件(event)驱动(例如 HTTP、pub/sub)的全托管计算服务。用户无需管理服务器等基础设施,只需编写代码和选择触发器(trigger),比如 RPC 请求、定时器等并上传,其余的工作(如实例选择、扩缩容、部署、容灾、监控、日志、安全补丁等)全部由 serverless 系统托管。用户只需要为代码实际运行消耗的资源付费——代码未运行则不产生费用。

对比serverful

Serverless 相对于 serverful,对业务用户强调 noserver(serverless 并不是说没有服务器,只是业务人员无需关注服务器了,代码仍然是运行在真实存在的服务器上)的运维理念,业务人员只需要聚焦业务逻辑代码。

Serverless 相比 serverful,有以下 3 个改变(来自 Berkeley 的总结):

  • 弱化了存储和计算之间的联系。服务的储存和计算被分开部署和收费,存储不再是服务本身的一部分,而是演变成了独立的云服务,这使得计算变得无状态化,更容易调度和扩缩容,同时也降低了数据丢失的风险。
  • 代码的执行不再需要手动分配资源。不需要为服务的运行指定需要的资源(比如使用几台机器、多大的带宽、多大的磁盘等),只需要提供一份代码,剩下的交由 serverless 平台去处理就行了。当前阶段的实现平台分配资源时还需要用户方提供一些策略,例如单个实例的规格和最大并发数,单实例的最大 CPU 使用率。理想的情况是通过某些学习算法来进行完全自动的自适应分配。
  • 按使用量计费。Serverless按照服务的使用量(调用次数、时长等)计费,而不是像传统的 serverful 服务那样,按照使用的资源(ECS 实例、VM 的规格等)计费。

serverless分类

Serverless 不如 IaaS 和 PaaS 那么好理解,因为它通常包含了两个领域 BaaS(Backend as a Service)和 FaaS(Function as a Service)。

BaaS

BaaS(Backend as a Service)后端即服务,一般是一个个的 API 调用后端或别人已经实现好的程序逻辑,比如身份验证服务 Auth0,这些 BaaS 通常会用来管理数据,还有很多公有云上提供的我们常用的开源软件的商用服务,比如亚马逊的 RDS 可以替代我们自己部署的 MySQL,还有各种其它数据库和存储服务。

FaaS

FaaS(Functions as a Service)函数即服务,FaaS 是无服务器计算的一种形式,当前使用最广泛的是 AWS 的 Lambada。

Serverless 的使用场景

虽然 Serverless 的应用很广泛,但是其也有局限性,Serverless 比较适合以下场景:

  • 异步的并发,组件可独立部署和扩展
  • 应对突发或服务使用量不可预测(主要是为了节约成本,因为 Serverless 应用在不运行时不收费)
  • 短暂、无状态的应用,对冷启动时间不敏感
  • 需要快速开发迭代的业务(因为无需提前申请资源,因此可以加快业务上线速度)

Serverless 的使用场景示例如:

  • ETL
  • 机器学习及 AI 模型处理
  • 图片处理
  • IoT 传感器数据分析
  • 流处理
  • 聊天机器人

serverless与云原生

Serverless 是云原生技术发展的高级阶段,可以使开发者更聚焦在业务逻辑,而减少对基础设施的关注。
Serverless 在云原生技术中的地位

开源serverless框架

Kubernetes 的蓬勃发展由催生了一系列以它为基础的 Serverless 应用,目前开源的 Serverless 框架大多以 Kubernetes 为基础。

开源框架

  • Apache OpenWhisk,一种多功能、具有行业优势的 Serverless 解决方案
  • Fission,第一个真正的 Kubernetes Serverless 平台
  • Kubeless,在 Serverless 中使用 Kubernetes API 的早期先驱
  • OpenFaaS,Kubernetes 上的简单 serverless
  • Knative,又被戏称为:所有你的 OSS serverless(和 Ingress)均属于我们
  • 其他开源 serverless 平台,仔细观察#serverless 空间,你还会注意到还有很多其他产品,比如 -来自Oracle 的Fn , Pivotal 的Riff, VMWare 的 Dispatch, Galatic Fog , Nuclio , Virtual Kubelet ,PipelineAI, Nuclio ,可能还有更多。对不起,乍一眼看的话,它们中的大多数都很快就会不敌 Knative。

更多请点击…

原文链接

原文链接

安装

kubectl apply -f https://raw.githubusercontent.com/influxdata/docs-v2/master/static/downloads/influxdb-k8-minikube.yaml
kubectl get pods -n influxdb
kubectl describe service -n influxdb influxdb
kubectl port-forward -n influxdb service/influxdb 9999:9999

yaml

---
apiVersion: v1
kind: Namespace
metadata:
    name: influxdb
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
    labels:
        app: influxdb
    name: influxdb
    namespace: influxdb
spec:
    replicas: 1
    selector:
        matchLabels:
            app: influxdb
    serviceName: influxdb
    template:
        metadata:
            labels:
                app: influxdb
        spec:
            containers:
              - image: quay.io/influxdb/influxdb:2.0.0-beta
                name: influxdb
                ports:
                  - containerPort: 9999
                    name: influxdb
                volumeMounts:
                  - mountPath: /root/.influxdbv2
                    name: data
    volumeClaimTemplates:
      - metadata:
            name: data
            namespace: influxdb
        spec:
            accessModes:
              - ReadWriteOnce
            resources:
                requests:
                    storage: 10G
---
apiVersion: v1
kind: Service
metadata:
    name: influxdb
    namespace: influxdb
spec:
    ports:
      - name: influxdb
        port: 9999
        targetPort: 9999
    selector:
        app: influxdb
    type: ClusterIP

docker run --name influxdb -p 9999:9999 quay.io/influxdb/influxdb:2.0.0-beta
docker run -p 9999:9999 quay.io/influxdb/influxdb:2.0.0-beta --reporting-disabled
docker exec -it influxdb /bin/bash

tag的使用

  • 把你经常查询的字段作为tag
  • 如果你要对其使用GROUP BY(),也要放在tag中
  • 如果你要对其使用InfluxQL函数,则将其放到field中
  • 如果你需要存储的值不是字符串,则需要放到field中,因为tag value只能是字符串
  • tags不要包含高度可变的信息,如UUID,哈希值和随机字符串,这将导致数据库中的大量series cardinality。

    series cardinality高是许多数据库高内存使用的主要原因

  • 用tag区分数据比使用详细的measurement名字更好
  • 不要把多条信息放到一个tag里面