redisRedis是单线程的,但是一般用作缓存,redis够用了,读写速度太快了。官方简单测试:测试完成10万个请求50个并发执行。要设置和获取的值是一个256字节的字符串。结果:读取速度为11万次/s,写入速度为81000次/s,但对于访问量特别大的业务还是略显不足。那么,如何提高redis的性能呢?构建集群。Redis主要提供三种集群策略:主从复制clustersentry1、主从复制在主从复制中,数据库分为主库(master)和从库(slave)两种。1.1主从复制具有以下特点:主库可以进行读写操作,当读写操作引起数据变化时,会自动同步数据到从库。master可以有多个slave,但是一个slave只能对应一个master1.2工作机制slave节点服务启动并连接到master后,会主动发送SYNC命令。Master服务主节点收到同步命令后,会启动后台存储进程,收集所有接收到的修改数据集的命令。后台进程执行完毕后,Master会将整个数据库文件传输给Slave,完成一次完整的同步。从节点服务接收到数据库文件数据后,保存并加载到内存中。之后Master主节点继续将收集到的所有修改命令和新的修改命令依次发送给Slave,Slave将执行本次这些数据修改命令,从而实现最终的数据同步。复制初始化后,master收到的每条写命令都会同步发送给slave,保证主从数据的一致性。如果Master和Slave之间的链接断开,Slave可以自动重新连接到Master,但是连接成功后,会自动进行全量同步。1.3主从配置Redis默认是master数据,所以master不需要配置,我们只需要修改slave的配置即可。设置需要连接的master的ip端口:slaveof192.168.0.1076379如果master设置了密码。需要配置:masterauthmaster-password进入命令行成功后,可以通过以下命令行查看连接数据库的其他库的信息:inforeplication1.3优点同一个Master可以同步多个Slave。Slave也可以接受来自其他Slave的连接和同步请求,可以有效分担Master的同步压力。因此,我们可以把Redis的Replication架构看成一个图结构。MasterServer以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步过程中,客户端仍然可以提交查询或者修改请求。SlaveServer也以非阻塞的方式完成数据同步。在同步过程中,如果客户端提交查询请求,Redis会返回同步前的数据。为了减轻Master的读操作压力,Slave服务器可以为客户端提供只读操作服务,而写服务仍然必须由Master来完成。尽管如此,系统的可扩展性还是得到了极大的提高。Master可以将保存数据的操作交给Slave,这样就避免了Master中需要一个独立的进程来完成这个操作。支持主从复制,master会自动同步数据到slave,可以实现读写分离。1.4缺点Redis没有自动容错和恢复功能。master和slave机器宕机会导致前端部分读写请求失败。需要等待机器重启或者手动切换前端IP才能恢复。宿主机宕机,宕机前部分数据无法及时同步到从机,切换IP后会引入数据不一致,降低系统的可用性。Redis的主从复制采用的是全量复制。在复制过程中,主机会fork出一个子进程对内存进行快照,并将子进程的内存快照保存为文件发送给从机。此过程需要确保主机有足够的空闲内存。如果快照文件较大,对集群的服务能力影响很大,复制过程会在从机新加入集群或从机与宿主机网络断开重连时进行,即网络波动会导致主机与主机之间的全量数据复制,给实际的系统运行带来很大的麻烦。Redis很难支持在线扩容,当集群容量达到上限时,在线扩容会变得非常复杂。为了避免这个问题,运维人员必须保证系统上线时有足够的空间,造成资源的极大浪费。其实redis的主从模式很简单,在实际生产环境中很少用到。我不推荐在实际生产环境中使用主从模式来提供系统的高可用。之所以不推荐,是因为主从模式的缺点,在数据量非常大的时候,或者需要系统高可用的时候,也是不稳定的。2、sentinel模式从Redis2.6版本开始提供,但是当时这个版本的模式不稳定。直到Redis2.8版本,sentinel模式才稳定下来。无论是主从模式还是哨兵模式,这两种模式都有一个问题就是不能水平扩展,而且这两种模式的高可用特性都会受到Master主节点内存的限制。2.1哨兵的作用是监控redis系统的运行状态。功能如下,用于监控主从数据库是否正常运行。当master出现故障时,它会自动将其中一个slave转换为master。主从服务器切换后,master的redis.conf,slave的redis.conf,sentinel.conf的配置文件的内容都会发生相应的变化,即多了一行saster配置的master服务器的redis.conf配置文件中的slaveof,sentinel.conf的监控目标会相应改变。当被监控的Redis节点出现问题时,sentinel可以通过API向管理员或其他应用程序发送通知。当配置多个哨兵时,哨兵也会被自动监控。多个Sentinels可以监控同一个redis。2.2Sentinel工作机制sentinel进程启动时,会读取配置文件的内容,通过sentinelmonitormaster-nameipportquorum找到master的ip端口。一个sentinel可以监控多个master数据库,只需要提供多个配置项即可。配置文件中还定义了监控相关的参数,比如master多久没有响应,即判断为下线。Sentinel启动后,会与被监控的master建立两个连接:3.1一个连接用于订阅master的sentinel:hello频道,获取监控master的其他Sentinel节点信息3.2另一个连接周期性发送INFO和其他命令给master获取master自己的信息与master建立连接后,sentinel会进行三个操作,这三个操作的发送频率可以在配置文件中配置:4.1定时向master发送INFO命令andslave4.2定时向master和slave发送sentinel:hello通道发送自己的信息4.3定时向master、slave等sentinel发送PING命令。这三个操作意义重大。发送INFO命令可以获得当前数据库的相关信息,实现新节点的自动发现。所以Sentinel只需要配置主库信息就可以自动发现它的从库信息。Sentinel在获取到slave信息后,也会和slave建立两个连接,进行监控。通过INFO命令,Sentinel可以获取到主从数据库的最新信息,并进行相应的操作,比如角色的改变。接下来sentinel向主从数据库的sentinel:hello通道发送信息,并将自己的信息分享给同样监控这些数据库的sentinel。有master的配置版本。该信息有以下用途:5.1其他Sentinel可以使用该信息判断发送者是否是新发现的Sentinel,如果是,将创建到Sentinel的连接以发送ping命令。5.2其他sentinel可以通过这个信息判断master的版本。如果版本高于直接录制的版本,则会更新。实现slave和其他sentinel节点的自动发现后,sentinel可以定时监控这些数据库和节点是否停止服务。发送频率可以配置,但最长间隔为1s,可以通过sentineldown-after-millisecondsmymaster600设置。如果被ping的数据库或节点在超时时间内没有回复,Sentinel主观认为下线。如果master下线了,sentinel会发命令给其他sentinel,询问他们是否主观上也认为master下线了。如果一个master主服务器被标记为主观下线(SDOWN),所有监控这个master主服务器的Sentinel进程必须每秒确认一次master主服务器确实进入了主观下线状态。如果达到一定的票数(即配置文件中的quorum),sentinel会认为master已经客观下线(ODOWN),选举领先的sentinel节点发起主从系统的failover.上面提到sentinel认为master客观下线后,故障恢复操作需要由选出的leadersentinel进行,选举采用Raft算法:8.1sentinel节点(我们称之为A)发现master下线给各个sentinel发送消息Order,要求对方选举自己为leadersentinel8.2如果目标sentinel节点还没有选择其他人,则同意选举A为leadersentinel8.3如果超过半数sentinel同意选举A为leader,则A将被选举8.4如果有多个哨兵节点同时参与leader选举。这时候可能会出现一轮没有候选人获胜的投票。此时,每个参与节点等待一个随机的时间,然后再次发起选举请求进行下一轮的投票选举,直到选出领导者。Sentinel8.5leadersentinel选出后,leader开始故障恢复,从故障master的数据库slave中选出一个作为新的master。选择规则如下:8.5.1在所有在线的slave中选择优先级最高的是的,可以通过slave-priority配置优先级8.5.2如果有多个slave的优先级最高,则选择优先级最高的那个largestreplicationoffset(即复制越完整)8.5.3如果以上条件都相同,选择id最小的slave选出需要成功的slaver后,leadingsentinel向数据库发送升级命令它给master,然后发送命令给其他slave接受新的master,最后更新数据。将已经停止的旧master更新到新master的slave数据库中,使其恢复服务后可以继续作为slave运行。2.3Sentinel配置sentinel配置文件为sentinel.conf,设置主机名、地址、端口、选举票数,即至少有几个sentinel节点同意恢复。只需要配置需要监控的master,sentinel就会监控连接到master上的slave。sentinelmonitormymaster192.168.0.10763791启动sentinel节点:redis-serversentinel.conf--sentinel&如果出现如下类似信息,则sentinel启动成功。Apr22:40:02.554###+monitormastermymaster192.168.0.1076379quorum13072:X12Apr22:40:03.516*+slaveslave192.168.0.108:6379192.168.0.1086379@mymaster192.1927.19627:1927.1678Apr22:40:03.516*+slaveslave192.168.0.109:6379192.168.0.1096379@mymaster192.168.0.1076379可以在任意服务器上查看指定的sentinel节点信息:bin/redis-cli-h192.168.0.110-p26379infoSentinel控制台输出哨兵信息redis-cli-h192.168.0.110-p26379infoSentinel###Sentinel_masters:1sentinel_tilt:0sentinel_running_scripts:0sentinel_scripts_queue_length:0master0:name=mymaster,status=ok,address=7196.3slaves=2,sentinels=13.Cluster3.1FeaturesRedis3.0之前的版本不支持集群。我们徐子锐老师说,那时候我们的redis如果要集群的话,需要一个中间件,然后这个中间件组件负责对我们需要存入的数据的key通过一套算法计算出一个值雷迪斯。然后根据这个值找到对应的redis节点,将数据存储到这个redis节点中。取值的时候也是先计算key得到对应的值,再到对应的redis节点去对应的节点上取对应的值。这样做有很多缺点。比如我们所有的计算都需要在系统中进行,这样就会增加系统的负担。另外,在这种集群模式下,如果一个节点挂了,其他节点是无法知道的。而且每个节点的负载均衡也不容易。redis-cluster集群从redis3.0版本开始支持。Redis-cluster采用无中心结构。每个节点都存储了集群所有主节点和从节点的信息,以及集群状态。每个节点都连接到其他节点。所以redis-cluster是一种服务端分片技术。每个节点与n-1个节点通信,称为集群总线(clusterbus)。他们使用了一个特殊的端口号,也就是对外服务的端口号加上10000。因此,需要维护这个集群各个节点的信息,否则整个集群不可用,内部使用了特殊的二进制协议以优化传输速度和带宽。redis-cluster将所有物理节点映射到[0,16383]槽(slot),cluster负责维护node--slot--value。集群预先给所有节点分配了16384个桶,每个节点都得到一些桶。当需要向redis集群中插入数据时,它根据CRC16(KEY)mod16384的值决定将key放入哪个桶中。客户端直接连接到redis节点。它不需要连接到集群中的所有节点,只需连接到集群中任何可用的节点即可。整个集群被视为一个整体,客户端可以连接到任意一个节点进行操作。当客户端操作的key没有分配给节点时,redis会返回转向命令指向正确的节点。redis-trib.rb脚本(rub语言)是一个集群管理工具,可以自动添加节点、规划槽位、迁移数据等一系列操作。一个节点的故障只有在集群中超过一半的节点检测到故障时才会生效。集群节点通过相互乒乓判断是否可以连接。如果超过一半的节点在ping一个节点时没有响应,集群就会认为这个节点宕机了,然后连接到它的备节点上。如果某个节点和所有slave节点都挂掉了,集群就进入fail状态,也可以理解为集群的slot映射[0-16383]不完整时进入fail状态。如果超过一半的master节点宕机,那么不管这些节点有没有slave节点,集群也会进入fail状态。这就是redis的投票机制。为了增加集群的可访问性,官方推荐的方案是将节点配置为master-slave结构,即一个master主节点和n个slave从节点。如果master节点出现故障,redis集群会根据选举算法选择其中一个slave节点成为master节点,整个集群继续对外提供服务。3.2配置1.redis集群依赖ruby,需要安装ruby环境。ruby版本必须高于2.2。为6个节点配置不同的路径dir/usr/local/redis-cluster/6380/###启用集群cluster-enabledyes###为节点设置不同的工作目录,为6个节点配置不同的目录cluster-config-filenodes-6380.conf###集群故障时间cluster-node-timeout150003.开启集群所有节点redis-service.../6380/redis.confredis-service.../6381/redis.confredis-service.../6382/redis。confredis-service.../6383/redis.confredis-service.../6384/redis.confredis-service.../6385/redis.conf4。将节点加入集群,输入yes确认创建集群redis-trib.rbcreate--11922.168.168.07:6380192.16888.07:6381192.1688.07:6382,1922.168.07:6383,192.168。07、192.1688.07、192.168.07。P63816.查看查看中的节点节点簇nodes[root@buke107src]###redis-cli-c-h192.168.0.0.0.0.107-p6381192.168.0.0.0.0.107:638197925983连接10923-16383d6d01fd8f1e5b9f8fc0c748e08248a358da3638d192.168.0.107:6385slave868456121fa4e6c8e7abe235a88b51d354a944b5015236097956166connected5cd3ed3a84ead41a765abd3781b98950d452c958192.168.0.107:6380master-015236097946101connected0-5460b8e047aeacb9398c3f58f96d0602efbbea2078e2192.168.0.107:6383slave5cd3ed3a84ead41a765abd3781b98950d452c958015236097976291connected68cf66359318b26df16ebf95ba0c00d9f6b2c63e192.168.0.107:6384slave90b4b326d579f9b5e181e3df95578bceba29b204015236097966225connected90b4b326d579f9b5e181e3df95578bceba29b204192.168.0.107:6381myself,master-002connected5461-10922如上所示,三主三从节点已创建成功7.增加集群节点clustermeetipportotherclusterimplementationsmiddleware1.twemproxytwemproxy,alsoknownasnutcracker,isalightweightproxyRedisproxymiddlewarethatoriginatedfromredisandmemcachedclustersintheTwittersystem.twemproxyisatechnologythatusesmiddlewareforsharding.twemproxyisinthemiddleoftheclientandtheserver.Afterprocessingtherequestsentbytheclient(sharding),itforwardsittotherealredisserveratthebackend.Thatistosay,theclientdoesnotdirectlyaccesstheredisserver,butindirectlythroughthetwemproxyproxymiddleware.Itreducesthenumberofconnectionsdirectlyfromtheclienttotheback-endserver,andsupportshorizontalexpansionoftheservercluster.twemproxy中间件内部处理是无状态的,可以很方便的自己集群,避免了单点压力或故障。从下面的架构图我们可以看出twemproxy是单点的,很容易给它造成很大的压力,所以通常会结合keepalived来实现twemproxy的高可用。这个时候通常只有一个twemproxy在工作,另外一个在备机中。一个挂了,vip自动漂移,备用机接管。关于keepalived的使用,可以上网查资料。2.codiscodis是一个分布式的Redis解决方案,由豌豆荚开源。对于上层应用,连接codisproxy和连接原生redisserver没有明显区别。上层应用可以像单机使用redis、codis,底层会处理请求转发、不间断数据迁移等工作。所有后续的事情对前端客户端都是透明的。可以简单的认为后面的连接是一个无限内存的redis服务。客户端分片和分区的逻辑是在客户端实现的,由客户端选择请求哪个节点。该方案可以参考一致性哈希,通常适用于用户完全控制客户端行为的场景。1.JedisshardingclusterRedisSharding可以说是Rediscluster出来之前业界常用的一种方式。其主要思想是利用哈希算法对存储数据的key进行哈希处理,从而将特定的key分配给特定的上级节点。幸运的是,JavaRedis客户端驱动Jedis已经支持RedisSharding功能,即ShardedJedis和ShardedJedisPoolJedis结合缓冲池的RedisSharding实现具有以下特点:采用一致性哈希算法,对key和nodename处的哈希同时,然后进行映射Match,使用的算法是MURMUR_HASH。使用一致性哈希而不是简单的类似哈希的模映射的主要原因是当添加或删除节点时,不会因为重新匹配而重新哈希。一致性哈希只影响相邻节点的key分布,影响较小。ShardedJedis为了避免一致性哈希只影响相邻节点带来的节点分配压力,ShardedJedis会为每个Redis节点根据其名称(不是,Jedis会分配一个默认名称)虚拟出160个虚拟节点进行哈希。根据weight权重,还可以虚拟出160倍的虚拟节点。使用虚拟节点进行映射匹配,在增加或减少Redis节点时,可以在Redis节点之间更均匀地移动和重新分配键,而不是只影响相邻节点。ShardedJedis支持keyTagPattern模式,即提取一部分keyTag进行sharding,这样通过对key的合理命名,可以将一组相关的key放到同一个Redis节点中,这对于避免跨节点非常重要访问相关数据。当然,RedisSharding这种轻量灵活的方式必然会损害集群的其他能力。比如在扩容的时候,想增加Redis节点的时候,即使使用一致性哈希,毕竟还是会有键匹配不上而丢失。这时候就需要进行键值迁移。Redis作为轻量级的客户端分片,处理Redis的key-value迁移是不现实的,需要应用层允许Redis中的数据丢失或者从后端数据库重新加载数据。但是有时候,突破缓存层,直接访问数据库层,会给系统访问带来很大的压力。
