Redis详解——概述下载安装

Redis详解——概述下载安装,第1张

互联网需求的3高: 高并发,高可扩,高性能。

Redis 是一种运行速度很快,并发性能很强,并且运行在内存上的NoSql(not only sql)数据库

NoSQL数据库 和 传统数据库 相比的优势:

NoSQL数据库无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。

而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段 简直就是一个噩梦。

Redis的常用使用场景:

缓存 ,毫无疑问这是Redis当今最为人熟知的使用场景。在提升服务器性能方面非常有效;一 些频繁被访问的数据,经常被访问的数据如果放在关系型数据库,每次查询的开销都会很 大,而放在redis中,因为redis 是放在内存中的可以很高效的访问

排行榜 ,在使用传统的关系型数据库(mysql oracle 等)来做这个事儿,非常的麻烦,而利 用Redis的SortSet(有序集合)数据结构能够简单的搞定;

好友关系 ,利用集合的一些命令,比如求交集、并集、差集等。可以方便搞定一些共同好 友、共同爱好之类的功能;

Session共享 ,以jsp为例,默认Session是保存在服务器的文件中,如果是集群服务,同一个 用户过来可能落在不同机器上,这就会导致用户频繁登陆;采用Redis保存Session后,无论 用户落在那台机器上都能够获取到对应的Session信息。

下载: redis:>

展开全部

IT培训>数据库教程

细说分布式Redis架构设计和踩过的那些坑

作者:课课家教育2015-12-1410:15:25

摘要:本文章主要分成五个步骤内容讲解

Redis、RedisCluster和Codis;

我们更爱一致性;

Codis在生产环境中的使用的经验和坑们;

对于分布式数据库和分布式架构的一些看法;

Q&A环节。

Codis是一个分布式Redis解决方案,与官方的纯P2P的模式不同,Codis采用的是Proxy-based的方案。今天我们介绍一下Codis及下一个大版本RebornDB的设计,同时会介绍一些Codis在实际应用场景中的tips。最后抛砖引玉,会介绍一下我对分布式存储的一些观点和看法,望各位首席们雅正。

细说分布式Redis架构设计和踩过的那些坑_redis分布式_redis分布式锁_分布式缓存redis

一、Redis,RedisCluster和Codis

Redis:想必大家的架构中,Redis已经是一个必不可少的部件,丰富的数据结构和超高的性能以及简单的协议,让Redis能够很好的作为数据库的上游缓存层。但是我们会比较担心Redis的单点问题,单点Redis容量大小总受限于内存,在业务对性能要求比较高的情况下,理想情况下我们希望所有的数据都能在内存里面,不要打到数据库上,所以很自然的就会寻求其他方案。比如,SSD将内存换成了磁盘,以换取更大的容量。更自然的想法是将Redis变成一个可以水平扩展的分布式缓存服务,在Codis之前,业界只有Twemproxy,但是Twemproxy本身是一个静态的分布式Redis方案,进行扩容/缩容时候对运维要求非常高,而且很难做到平滑的扩缩容。Codis的目标其实就是尽量兼容Twemproxy的基础上,加上数据迁移的功能以实现扩容和缩容,最终替换Twemproxy。从豌豆荚最后上线的结果来看,最后完全替换了Twem,大概2T左右的内存集群。

在Redis集群中,每个节点都会保存槽信息,比如Redis集群默认有16384个槽,假设node0节点保存了0-4000槽数据,node1保存了4001-8000槽数据,node2 保存了80001-16383槽数据,则在每个节点中,都保存有当前节点处理哪些槽数据,哪些数据由其他节点处理,如node0保存了0-4000由node0处理,4001-8000由node1处理,80001-16383由node2处理。

客户端请求过来。如果首先到达node0,当时这个key(假设计算出槽节点为10086)所在的槽并不在node0 节点上(假设node0通过自己保存结构查询出来处理key的节点为node1,地址为127001:7001),node0 会返回给客户端一个MOVED错误,结果类似如下

这样客户端就知道它应该去127001:7001再做请求

Redis 因具有丰富的数据结构和超高的性能以及简单的协议,使其能够很好的作为数据库的上游缓存层。但在大规模的 Redis 使用过程中,会受限于多个方面:单机内存有限、带宽压力、单点问题、不能动态扩容等。

基于以上, Redis 集群方案显得尤为重要。通常有 3 个途径:官方 Redis Cluster ;通过 Proxy 分片;客户端分片 (Smart Client) 。以上三种方案各有利弊。

Redis Cluster( 官方 ) :虽然正式版发布已经有一年多的时间,但还缺乏最佳实践;对协议进行了较大修改,导致主流客户端也并非都已支持,部分支持的客户端也没有经过大规模生产环境的验证;无中心化设计使整个系统高度耦合,导致很难对业务进行无痛的升级。

Proxy :现在很多主流的 Redis 集群都会使用 Proxy 方式,例如早已开源的 Codis 。这种方案有很多优点,因为支持原声 redis 协议,所以客户端不需要升级,对业务比较友好。并且升级相对平滑,可以起多个 Proxy 后,逐个进行升级。但是缺点是,因为会多一次跳转,平均会有 30% 左右的性能开销。而且因为原生客户端是无法一次绑定多个 Proxy ,连接的 Proxy 如果挂了还是需要人工参与。除非类似 Smart Client 一样封装原有客户端,支持重连到其他 Proxy ,但这也就带来了客户端分片方式的一些缺点。并且虽然 Proxy 可以使用多个,并且可以动态增加 proxy 增加性能,但是所有客户端都是共用所有 proxy ,那么一些异常的服务有可能影响到其他服务。为每个服务独立搭建 proxy ,也会给部署带来额外的工作。

而我们选择了第三种方案,客户端分片 (Smart Client) 。客户端分片相比 Proxy 拥有更好的性能,及更低的延迟。当然也有缺点,就是升级需要重启客户端,而且我们需要维护多个语言的版本,但我们更爱高性能。

下面我们来介绍一下我们的Redis集群:

概貌:

如图0所示,

我们的 Redis 集群一共由四个角色组成:

Zookeeper :保存所有 redis 集群的实例地址, redis 实例按照约定在特定路径写入自身地址,客户端根据这个约定查找 redis 实例地址,进行读写。

Redis 实例:我们修改了 redis 源码,当 redis 启动或主从切换时,按照约定自动把地址写到 zookeeper 特定路径上。

Sentinel : redis 自带的主从切换工具,我们通过 sentinel 实现集群高可用。

客户端( Smart Client ):客户端通过约定查找 redis 实例在 ZooKeeper 中写入的地址。并且根据集群的 group 数,进行一致性哈希计算,确定 key 唯一落入的 group ,随后对这个 group 的主库进行 *** 作。客户端会在Z ooKeeper 设置监视,当某个 group 的主库发生变化时,Z ooKeeper 会主动通知客户端,客户端会更新对应 group 的最新主库。

我们的Redis 集群是以业务为单位进行划分的,不同业务使用不同集群(即业务和集群是一对一关系)。一个 Redis 集群会由多个 group 组成 ( 一个 group 由一个主从对 redis 实例组成 ) 。即 group 越多,可以部署在更多的机器上,可利用的内存、带宽也会更多。在图0中,这个业务使用的 redis 集群由 2 个 group 组成,每个 group 由一对主从实例组成。

Failover

如图1所示,

当 redis 启动时,会 把自己的 IP:Port 写入到 ZooKeeper 中。其中的 主实例模式启动时会在 /redis/ 业务名 / 组名 永久节点写入自己的 IP:Port (如果节点不存在则创建)。由 主模式 变成 从模式 时,会创建 /redis/ 业务名 / 组名 /slaves/ip:port 临时节 点,并写入自己的 IP:Port (如果相同节点已经存在,则先删除,再创建)。而从实例 模式 启动时会创建 /redis/ 业务名 / 组名 /slaves/ip:port 临时节点,并写入自己的 ip:port (如果相同节点已经存在,则先删除,再创建)。由 从模式 变成 主模式 时,先删除 /redis/ 业务名 / 组名 /slaves/ip:port 临时节点,并在 /redis/ 业务名 / 组名 永久节点写入自己的 IP:Port 。

ZooKeeper 会一直保存当前有效的 主从实例 IP:Port 信息。至于主从自动切换过程,使用 redis 自带的 sentinel 实现,现设置为超过 30s 主 server 无响应,则由 sentinel 进行主从实例的切换,切换后就会触发以主、从实例通过以上提到的一系列动作,从而完成最终的切换。

而客户端侧通过给定业务名下的所有 groupName 进行一致性哈希计算,确定 key 落入哪个组。 客户端启动时,会从 ZooKeeper 获取指定业务名下所有 group 的 主从 IP:Port ,并在 ZooKeeper 中设置监视(监视的作用是当 ZooKeeper 的节点发生变化时,会主动通知客户端)。若客户端从 Zookeeper 收到节点变化通知,会重新获取最新的 主从 I:Port ,并重新设置监视( ZooKeeper 监视是一次性的)。通过此方法,客户端可以实时获知当前可访问最新的 主从 IP:Port 信息。

因为我们的所有 redis 实例信息都按照约定保存在 ZooKeeper 上,所以不需要针对每个实例部署监控,我们编写了一个可以自动通过 ZooKeeper 获取所有 redis 实例信息,并且监控 cpu 、 qps 、内存、主从延迟、主从切换、连接数等的工具。

发展:

现在 redis 集群在某些业务内存需求超过预期很多后,无法通过动态扩容进行扩展。所以我们正在做动态扩容的支持。原先的客户端我们是通过一致性哈希进行 key 的

路由策略,但这种方式在动态扩容时会略显复杂,所以我们决定采用实现起来相对简单的预分片方式。一致性哈希的好处是可以无限扩容,而预分片则不是。预分片

时我们会在初始化阶段指定一个集群的所有分片数量,这个数量一旦指定就不能再做改变,这个预分片数量就是后续可以扩容到最大的 redis 实例数。假设预分片 128 个 slot ,每个实例 10G 也可以达到 TB 级别的集群,对于未来数据增长很大的集群我们可以预分片 1024 ,基本可以满足所有大容量内存需求了。

原先我们的 redis 集群有四种角色, Smart Client, redis , sentinel , ZooKeeper 。为了支持动态扩容,我们增加了一个角色, redis_cluster_manager (以下简称 manager ),用于管理 redis 集群。主要工作是初始化集群(即预分片),增加实例后负责修改Z ooKeeper 状态,待客户端做好准备后迁移数据到新增实例上。为了尽量减少数据迁移期间对现性能带来的影响,我们每次只会迁移一个分片的数据,待迁移完成,再进行下一个分片的迁移。

如图2所示

相比原先的方案,多了 slots 、M anager Lock 、 clients 、M igrating Clients 节点。

Slots: 所有分片会把自身信息写入到 slots 节点下面。 Manager 在初始化集群时,根据设置的分片数,以及集群下的 group 数,进行预分片 *** 作,把所有分片均匀分配给已有 group 。分片的信息由一个 json 串组成,记录有分片的状态 (stats) ,当前拥有此分片的 group(src) ,需要迁移到的 group(dst) 。分片的状态一共有三种: online 、 pre_migrate 、 migrating 。

Online 指这个分片处于正常状态,这时 dst 是空值,客户端根据 src 的 group 进行读写。

Pre_migrate 是指这个分片被 manager 标记为需要迁移,此时 dst 仍然为空, manager 在等所有 client 都已经准备就绪,因为 ZooKeeper 回掉所有客户端有时间差,所以如果某些 client 没有准备就绪的时候 manager 进行了数据迁移,那么就会有数据丢失。

Migrating 是 manager 确认了所有客户端都已经做好迁移准备后,在 dst 写入此分片需要迁移的目标 group 。待迁移完成,会在 src 写入目标 group_name , dst 设为空, stats 设为 online 。

Manager Lock: 因为我们是每次只允许迁移一个 slot ,所以不允许超过一个 manager *** 作一个集群。所以 manager 在 *** 作集群前,会在M anager Lock 下注册临时节点,代表这个集群已经有 manager 在 *** 作了,这样其他 manager 想要 *** 作这个集群时就会自动退出。

Clients 和M igrating Clients 是为了让 manager 知道客户端是否已经准备就绪的节点。客户端通过 uid 代表自己,格式是 客户端语言 _ 主机名 _pid 。当集群没有进行迁移,即所有分片都是 online 的时候,客户端会在 clients 下创建 uid 的临时节点。

当某个 slot 从 online 变成 pre_migrate 后,客户端会删除 clients 下的 uid 临时节点,然后在M igrating Clients 创建 uid 临时节点。注意,因为需要保证数据不丢失,从 pre_migrate 到 migrating 期间,这个 slot 是被锁定的,即所有对这个 slot 的读写都会被阻塞。所以 mananger 会最多等待 10s ,确认所有客户端都已经切换到准备就绪状态,如果发现某个客户端一直未准备就绪,那么 mananger 会放弃此次迁移,把 slot 状态由 pre_migrate 改为 online 。如果客户端发现 slot 状态由 pre_migrate 变成 online 了,那么会删除 migrating_clients 下的 uid 节点,在 clients 下重新创建 uid 节点。还需要注意的一点是,有可能一个客户刚启动,并且正在往 clients 下创建 uid 节点,但是因为网络延迟还没创建完成,导致 manager 未确认到这个 client 是否准备就绪,所以 mananger 把 slot 改为 pre_migrate 后会等待 1s 再确认所有客户端是否准备就绪。

如果 Manager 看到 clients 下已经没有客户端的话(都已经准备就绪),会把 slot 状态改为 migrating 。 Slot 变成 migrating 后,锁定也随之解除, manager 会遍历 src group 的数据,把对应 slot 的数据迁移到 dst group 里。客户端在 migrating 期间如果有读写 migrating slot 的 key ,那么客户端会先把这个 key 从 src group 迁移到 dst group ,然后再做读写 *** 作。即这期间客户端性能会有所下降。这也是为什么每次只迁移一个 slot 的原因。这样即使只有 128 个分片的集群,在迁移期间受到性能影响的 key 也只有 1/128 ,是可以接受的。

Manager 发现已经把 slot 已经迁移完毕了,会在 src 写入目标 group_name , dst 设为空, stats 设为 online 。客户端也删除 migrating_clients 下的 uid ,在 clients 下创建 uid 节点。

标签: redis 缓存 主从 哨兵 集群

本文简单的介绍redis三种模式在linux的安装部署和数据存储的总结,希望可以相互交流相互提升。

对于Centos7在安装redis之前需要进行一些常用工具的安装:

关闭防火墙

正式安装redis

在redis进行maketest时候会出现一系列的异常,有如下解决方案:

用redis-server启动一下redis,做一些实验没什么意义。

要把redis作为一个系统的daemon进程去运行的,每次系统启动,redis进程一起启动, *** 作不走如下:

RDB和AOF是redis的一种数据持久化的机制。 持久化 是为了避免系统在发生灾难性的系统故障时导致的系统数据丢失。我们一般会将数据存放在本地磁盘,还会定期的将数据上传到云服务器。

RDB是redis的snapshotting,通过redisconf中的save配置进行设置,如 save 60 1000:

AOF是以appendonly方式进行数据的储存的,开启AOF模式后,所有存进redis内存的数据都会进入os cache中,然后默认1秒执行一次fsync写入追加到appendonlyaof文件中。一般我们配置redisconf中的一下指令:

AOF和RDB模式我们一般在生产环境都会打开,一般而言,redis服务挂掉后进行重启会优先家在aof中的文件。

当启动一个slave node的时候,它会发送一个PSYNC命令给master node,如果这是slave node重新连接master node,那么master node仅仅会复制给slave部分缺少的数据;否则如果是slave node第一次连接master node,那么会触发一次full resynchronization;

开始full resynchronization的时候,master会启动一个后台线程,开始生成一份RDB快照文件,同时还会将从客户端收到的所有写命令缓存在内存中。RDB文件生成完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后再从本地磁盘加载到内存中。然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据。

slave node如果跟master node有网络故障,断开了连接,会自动重连。master如果发现有多个slave node都来重新连接,仅仅会启动一个rdb save *** 作,用一份数据服务所有slave node。

从redis 28开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份。

master node会在内存中常见一个backlog,master和slave都会保存一个replica offset还有一个master id,offset就是保存在backlog中的。如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制,但是如果没有找到对应的offset,那么就会执行一次resynchronization。

master在内存中直接创建rdb,然后发送给slave,不会在自己本地落地磁盘了,可以有如下配置:

slave不会过期key,只会等待master过期key。如果master过期了一个key,或者通过LRU淘汰了一个key,那么会模拟一条del命令发送给slave。

在redisconf配置文件中,上面的参数代表至少需要3个slaves节点与master节点进行连接,并且master和每个slave的数据同步延迟不能超过10秒。一旦上面的设定没有匹配上,则master不在提供相应的服务。

sdown达成的条件很简单,如果一个哨兵ping一个master,超过了 is-master-down-after-milliseconds 指定的毫秒数之后,就主观认为master宕机

sdown到odown转换的条件很简单,如果一个哨兵在指定时间内,收到了 quorum 指定数量的其他哨兵也认为那个master是sdown了,那么就认为是odown了,客观认为master宕机

如果一个slave跟master断开连接已经超过了down-after-milliseconds的10倍,外加master宕机的时长,那么slave就被认为不适合选举为master

(down-after-milliseconds 10) + milliseconds_since_master_is_in_SDOWN_state

每次一个哨兵要做主备切换,首先需要quorum数量的哨兵认为odown,然后选举出一个slave来做切换,这个slave还得得到majority哨兵的授权,才能正式执行切换;

(2)SENTINEL RESET ,在所有sentinal上执行,清理所有的master状态

(3)SENTINEL MASTER mastername,在所有sentinal上执行,查看所有sentinal对数量是否达成了一致

432 slave的永久下线

让master摘除某个已经下线的slave:SENTINEL RESET mastername,在所有的哨兵上面执行

redis的集群模式为了解决系统的横向扩展以及海量数据的存储问题,如果你的数据量很大,那么就可以用redis cluster。

redis cluster可以支撑N个redis master,一个master上面可以挂载多个slave,一般情况我门挂载一个到两个slave,master在挂掉以后会主动切换到slave上面,或者当一个master上面的slave都挂掉后,集群会从其他master上面找到冗余的slave挂载到这个master上面,达到了系统的高可用性。

21 redis cluster的重要配置

22 在三台机器上启动6个redis实例

将上面的配置文件,在/etc/redis下放6个,分别为: 7001conf,7002conf,7003conf,7004conf,7005conf,7006conf

每个启动脚本内,都修改对应的端口号

23 创建集群

解决办法是 先安装rvm,再把ruby版本提升至233

使用redis-tribrb命令创建集群

--replicas: 表示每个master有几个slave

redis-tribrb check 19216831187:7001 查看状体

31 加入新master

以上相同配置完成后,设置启动脚本进行启动;然后用如下命令进行node节点添加:

32 reshard一些数据过去

33 添加node作为slave

34 删除node

应用Redis实现数据的读写,同时利用队列处理器定时将数据写入mysql。

同时要注意避免冲突,在redis启动时去mysql读取所有表键值存入redis中,往redis写数据时,对redis主键自增并进行读取,若mysql更新失败,则需要及时清除缓存及同步redis主键。

这样处理,主要是实时读写redis,而mysql数据则通过队列异步处理,缓解mysql压力,不过这种方法应用场景主要基于高并发,而且redis的高可用集群架构相对更复杂,一般不是很推荐。

相信各位在使用redis集群的时候,对于redis集群中的批量 *** 作都会有一个现象:使用redis集群进行批量获取数据的时候,效率总是不高,取一次数据要达到几百毫秒,当你 *** 作的数据是百万级别的时候,你就会发现redis的读取效率压根就不能接受。接下来告诉大家如何进行了解

### redis集群的哈希槽

redis集群中内置了16384个哈希槽,当一个key值准备存储的时候,是先通过将key进行 crc16 校验,校验后的值对16384取值,得到的值就是该key所在的槽(slot);redis集群中,节点上的槽是连续的一段,因此通过我们计算key得到的slot,就能判断该key是在存储在哪个节点上的。

#### 如何判断redis集群中各个节点上的slot分布?

  使用命令 : cluster nodes  或者  cluster slots

#### 如何知道一个key值对应的槽

使用命令: cluster keyslots {key}

#### 提高效率的解决方案

因此,通过上面我们就可以知道key值存储对应的reids集群的节点,因此我们可以做以下处理:将你所需要的key按照槽的值进行分批,用单点连接的形式连接到某个redis节点上,批量取处于同一个节点上的key。

注意:

- 一定要用单点的形式进行连接,还是使用集群方式连接的话,就算是处于一个节点,效率也是没有提高的;

- redis集群单点连接的话,不能使用mget,因此mget只能取位于同一个 slot 上的,你可以使用pipeline进行事务处理;

### 一次具体的实现

目前我使用的语言的php,借鉴了

[crc16算法计算](>

以上就是关于Redis详解——概述/下载安装全部的内容,包括:Redis详解——概述/下载安装、Redis6.0.9配置redis集群、详解Codis是如何来管理redis分布式集群及涉及原理等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/web/10154496.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-05
下一篇2023-05-05

发表评论

登录后才能评论

评论列表(0条)

    保存