• [知识分享] 盘点华为云GaussDB(for Redis)六大秒级能力
    >摘要:盘点高斯Redis的秒级能力,包括扩容、备份、删除、启动等。 本文分享自华为云社区《华为云GaussDB(for Redis)揭秘第20期:六大秒级能力盘点》,作者: 高斯Redis官方博客。 # 引言 大家经常用时间类指标来评估数据库能力,诸如RTO/RPO、扩容耗时、变更操作对业务影响的时长等等,在高可用需求日益迫切的当下,这些都是评价数据库能力的重要参考。在KV数据库领域,华为云GaussDB(for Redis)基于存算分离的基础架构,在很多关键评估维度都具有“秒级”能力,今天便带大家了解一下。 # GaussDB(for Redis)秒级能力盘点 ## 秒启动 社区版Redis在宕机恢复的场景下,需要依赖AOF或RDB文件将数据全量加载到内存中,随着数据量增加,这个耗时经常需要数分钟甚至更久。 GaussDB(for Redis)节点拉起时无需加载全量数据,即可快速提供服务,启动时间受数据量影响极小,**大数据规模下亦可以达到秒级启动**,体验丝滑。 ## 秒删除 社区版Redis在删除/过期数据,尤其是大key的情况下会导致访问严重阻塞。 而GaussDB(for Redis)从根本上解决了大key删除/过期的操作隐患,在底层事先采用了“标记删除,异步回收”的逻辑,对任何数据执行删除/过期,都是立刻执行成功且0阻塞,因此完全不影响业务访问。在实测删除/过期一个大hash key(包含1000w个元素)时,GaussDB(for Redis)仅耗时毫秒。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20227/1/1656639071668891773.png) 图:GaussDB(for Redis)大key秒删 ## 秒备份 社区版Redis打快照时需要将全量数据dump到磁盘上,效率受到磁盘IO性能影响,耗时久。而且有着“fork问题”,造成性能抖动,导致容量利用率只有50%。 GaussDB(for Redis)备份基于底层文件系统的快照技术,记录某一时间点的数据状态,无需进行耗时的数据拷贝操作,真正做到秒级打快照。客户的数据快照文件自动上传到华为云OBS桶内,后续可用来一键恢复到新实例,相当便捷。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20227/1/1656639088751433379.png) 图:GaussDB(for Redis)时间点快照一键恢复 ## 秒扩容 社区版Redis计算、存储强耦合。比如64G规格装满了,当需要升128G规格时,升级过程不仅耗时久,严重影响业务;而且价格翻倍,存在大量算力成本浪费。 GaussDB(for Redis)提供以下3种灵活变更的“扩容”方式: - **1)数据快装满了?一键扩容量,秒级完成,不影响业务** GaussDB(for Redis)底层存储资源按配额形式提供使用,数据快写满场景,只需一键点击扩容,秒级获得更多容量。比如64G扩容到128G,秒级完成,不影响业务。同时无需为不必要的算力买单,扩容价格涨幅小,成本有极大优势。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20227/1/1656639130986819876.png) 图:GaussDB(for Redis)存储扩容 - **2)流量突发高峰?一键加节点,业务只受到秒级影响** GaussDB(for Redis)扩算力的最便捷方式即增加节点,秒级即可完成负载重新均衡,业务短暂受影响。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20227/1/1656639152163701279.png) 图:GaussDB(for Redis)算力扩容-添加节点 - **3)周期性做活动?节点规格按需伸缩,避免算力浪费** 在一些周期性的活动抢券场景,客户往往需要按周期进行规格升降,承载计划内的流量高峰,同时避免平时的浪费。GaussDB(for Redis)支持提升节点规格,比如16U升32U,客户可灵活按需扩容。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20227/1/1656639171808506421.png) 图:GaussDB(for Redis)算力扩容-节点规格变更 ## 故障秒恢复 GaussDB(for Redis)内部有全局的HA管控能力,计算节点故障秒级探测,发现故障后同样采用秒级接管的方式处理,秒级恢复业务侧正常访问。 ## 双活秒级RPO GaussDB(for Redis)支持region内/跨region容灾,即搭建稳定主从实例,提供企业级的高可用。通过高性能数据同步模块实现高性能主从实例同步,在高压力写入的业务压力下测试,有着RPO=10s的超高可靠性表现。 # 总结 经过上面的简单盘点可以看出,GaussDB(for Redis)在启动、大key删除、扩容变更等多种应用场景下均具有秒级能力,最小化业务影响,给用户提供企业级安全、稳定、可靠的使用体验。
  • [新手课堂] [转载]redis内存优化
    ## Redis优化及配置 Redis所有的数据都在内存中,而内存又是非常宝贵的资源。常用的内存优化方案有如下几部分: 一. 配置优化 二. 缩减键值对象 三. 命令处理 四. 缓存淘汰方案 ## 一、配置优化 **Linux 配置优化** ** ** 目前大部分公司都会将 Web 服务器、数据库服务器等部署在 Linux 操作系统上,Redis优化也需要考虑操作系统,所以接下来介绍 Linux 操作系统如何优化Redis。 ①、内存分配 vm.overcommit_memory Redis是内存操作,需要优先使用内存。设置overcommit 为1。是为了让 fork 操作能够在低内存下也执行成功。Linux 操作系统对大部分申请内存的请求都回复 yes,以便能运行更多的程序。因为申请内存后,并不会马上使用内存,这种技术叫做 overcommit。 vm.overcommit_memory 用来设置内存分配策略,有三个可选值: ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/19/1655652174158283205.png) ②、THP Redis 在启动时可能会看到如下日志: ``` WARNING you have Transparent Huge Pages (THP) support enabled ``in` `your kernel. This``will create latency and memory usage issues with Redis. To fix this issue run``the ``command` `'echo never > /sys/kernel/mm/transparent_hugepage/enabled'` `as root,``and add it to your ``/etc/rc``.``local` `in` `order to retain the setting after a reboot.``Redis must be restarted after THP is disabled. ``` Redis建议修改 Transparent Huge Pages(THP)的相关配置,Linux kernel 在2.6.38内核增加了 THP 特性,支持大内存页(2MB)分配,默认开启。当开启时可以降低 fork 子进程的速度,但 fork 操作之后,每个内存页从原来 4KB 变为 2MB,会大幅增加重写期间父进程内存消耗。同时每次写命令引起的复制内存页单位放大了512倍,会拖慢写操作的执行时间,导致大量写操作慢查询,例如简单的 incr 命令也会出现在慢查询中。因此 Redis 日志中建议将此特性进行禁用,禁用方法如下: ``` echo` `never > ``/sys/kernel/mm/transparent_hugepage/enabled ``` 为使机器重启后THP配置依然生效,可以在/etc/rc.local 中追加 echo never>/sys/kernel/mm/transparent_hugepage/enabled ③、swappiness swap对于操作系统来比较重要,当物理内存不足时,可以将一部分内存页进行 swap 操作,已解燃眉之急。swap 空间由硬盘提供,对于需要高并发、高吞吐的应用来说,磁盘 IO 通常会成为系统瓶颈。在 Linux 中,并不是要等到所有物理内存都使用完才会使用到 swap,系统参数 swppiness 会决定操作系统使用 swap 的倾向程度。swappiness 的取值范围是0~100,swappiness 的值越大,说明操作系统可能使用swap的概率越高,swappiness 值越低,表示操作系统更加倾向于使用物理内存。swap 的默认值是60,了解这个值的含义后,有利于 Redis 的性能优化。下图对 swappiness 的重要值进行了说明: 、![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/19/1655652186537720655.png) OOM(Out Of Memory)killer 机制是指 Linux 操作系统发现可用内存不足时,强制杀死一些用户进程(非内核进程),来保证系统有足够的可用内存进行分配。 为使配置在重启 Linux 操作系统后立即生效,只需要在/etc/sysctl.conf 追加 vm.swappiness={bestvalue}即可。 echo vm.swappiness={bestvalue} >> /etc/sysctl.conf 查看 swap 的总体情况可使用 free-m 命令,如下服务器开启了8189M swap,其中使用了 5241MB ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/19/1655652200458282425.png) ④、ulimit设置 可以通过 ulimit 查看和设置系统当前用户进程的资源数。其中 ulimit-a 命令包含的 open files 参数,是单个用户同时打开的最大文件个数: ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/19/1655652208794907632.png) Redis允许同时有多个客户端通过网络进行连接,可以通过配置 maxclients 来限制最大客户端连接数。对 Linux 操作系统来说,这些网络连接都是文件句柄。假设当前 open files 是4096,那么启动 Redis 时会看到如下日志: \#You requested maxclients of 10000 requiring at least 10032 max file descriptors. \#Redis can’t set maximum open files to 10032 because of OS error: Operation not permitted. \#Current maximum open files is 4096. Maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit –n'. **上面日志的内容解释如下:** 第一行:Redis 建议把 open files 至少设置成10032,那么这个10032是如何来的呢?因为 maxclients 默认是10000,这些是用来处理客户端连接的,除此之外,Redis 内部会使用最多32个文件描述符,所以这里的10032=10000+32。** ** 第二行:Redis 不能将 open files 设置成10032,因为它没有权限设置。 第三行:当前系统的 open files 是4096,所以将 maxclients 设置成4096-32=4064个,如果你想设置更高的 maxclients,请使用 ulimit-n 来设置。 从上面的三行日志分析可以看出 open files 的限制优先级比 maxclients 大。 Open files 的设置方法如下: ``` ulimit` `–Sn {max-``open``-files} ``` **Redis配置优化** ①、设置maxmemory。设置Redis使用的最大物理内存,即Redis在占用maxmemory大小的内存之后就开始拒绝后续的写入请求,该参数可以确保Redis因为使用了大量内存严重影响速度或者发生OOM(out-of-memory,发现内存不足时,它会选择杀死一些进程(用户态进程,不是内核线程),以便释放内存)。此外,可以使用info命令查看Redis占用的内存及其它信息。 ②、让键名保持简短。键的长度越长,Redis需要存储的数据也就越多 ③、客户端timeout 设置一个超时时间,防止无用的连接占用资源。设置如下命令: timeout 150 tcp-keepalive 150 (定时向client发送tcp_ack包来探测client是否存活的。默认不探测) ④、检查数据持久化策略 数据落磁盘尽可能减少性能损坏,以空间换时间。设置如下命令: rdbcompression no : 默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的快照会比较大。 rdbchecksum no : 默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。 ⑤、优化AOF和RDB,减少占用CPU时间 主库可以不进行dump操作或者降低dump频率。取消AOF持久化。 命令如下: appendonly no ⑥、监控客户端的连接 因为Redis是单线程模型(只能使用单核),来处理所有客户端的请求, 但由于客户端连接数的增长,处理请求的线程资源开始降低分配给单个客户端连接的处理时间 ⑦、限制客户端连接数 。在Redis-cli工具中输入info clients可以查看到当前实例的所有客户端连接信息 maxclients属性上修改客户端连接的最大数,可以通过在Redis-cli工具上输入 config set maxclients 去设置最大连接数。根据连接数负载的情况。 ## 二、缩减键值对象 降低Redis内存使用最直接的方式就是缩减键(key)和值(value)的长度。 - key长度:如在设计键时,在完整描述业务情况下,键值越短越好。 - value长度:值对象缩减比较复杂,常见需求是把业务对象序列化成二进制数组放入Redis。首先应该在业务上精简业务对象,在存到Redis之前先把你的数据压缩下。 常用压缩方法对比: ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/19/1655652239456342501.png) ## 三、命令处理 Redis基于C/S架构模式,基于Redis操作命令是解决响应延迟问题最关键的部分,因为Redis是个单线程模型,客户端过来的命令是按照顺序执行的。比较常见的延迟是带宽,通过千兆网卡的延迟大约有200μs。倘若明显看到命令的响应时间变慢,延迟高于200μs,那可能是Redis命令队列里等待处理的命令数量比较多。 要分析解决这个性能问题,需要跟踪命令处理数的数量和延迟时间。 比如可以写个脚本,定期记录total_commands_processed的值。当客户端明显发现响应时间过慢时,可以通过记录的total_commands_processed历史数据值来判断命理处理总数是上升趋势还是下降趋势,以便排查问题。 在info信息里的 total_commands_processed 字段显示了Redis服务处理命令的总数 ![1655652398457.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/19/1655652428680504250.png) 解决方案: ①、使用多参数命令:若是客户端在很短的时间内发送大量的命令过来,会发现响应时间明显变慢,这由于后面命令一直在等待队列中前面大量命令执行完毕。有个方法可以改善延迟问题,就是通过单命令多参数的形式取代多命令单参数的形式。 举例来说:循环使用LSET命令去添加1000个元素到list结构中,是性能比较差的一种方式,更好的做法是在客户端创建一个1000元素的列表,用单个命令LPUSH或RPUSH,通过多参数构造形式一次性把1000个元素发送的Redis服务上。下面是Redis的一些操作命令,有单个参数命令和支持多个参数的命令,通过这些命令可尽量减少使用多命令的次数。 ②、管道命令:另一个减少多命令的方法是使用管道(pipeline),把几个命令合并一起执行,从而减少因网络开销引起的延迟问题。因为10个命令单独发送到服务端会引起10次网络延迟开销,使用管道会一次性把执行结果返回,仅需要一次网络延迟开销。Redis本身支持管道命令,大多数客户端也支持,倘若当前实例延迟很明显,那么使用管道去降低延迟是非常有效的。 ## 四、缓存淘汰优化 redis内存数据集大小上升到一定大小的时候,就会进行数据淘汰策略。如果不淘汰经常不用的缓存数据,那么正常的数据将不会存储到缓存当中。 可通过配置redis.conf中的maxmemory这个值来开启内存淘汰功能。 maxmemory 值得注意的是,maxmemory为0的时候表示我们对Redis的内存使用没有限制。 根据应用场景,选择淘汰策略 maxmemory-policy noeviction 内存淘汰的过程如下: ①、首先,客户端发起了需要申请更多内存的命令(如set)。 ②、然后,Redis检查内存使用情况,如果已使用的内存大于maxmemory则开始根据用户配置的不同淘汰策略来淘汰内存(key),从而换取一定的内存。 ③、最后,如果上面都没问题,则这个命令执行成功。 ### 动态改配置命令 此外,redis支持动态改配置,无需重启。 **设置最大内存** config set maxmemory 100000 **设置淘汰策略** config set maxmemory-policy noeviction ### 内存淘汰策略 volatile-lru 从已设置过期时间的数据集(server.db.expires)中挑选最近最少使用的数据淘汰。 allkeys-lru 从数据集(server.db.dict)中挑选最近最少使用的数据淘汰 volatile-lfu 从设置了过期时间的数据集(server.db.expires)中选择某段时间之内使用频次最小的键值对清除掉 allkeys-lfu 从所有的数据集(server.db.dict)中选择某段时间之内使用频次最少的键值对清除 volatile-ttl 从已设置过期时间的数据集(server.db.expires)中挑选将要过期的数据淘汰 volatile-random 从已设置过期时间的数据集(server.db.expires)中任意选择数据淘汰 allkeys-random 从数据集(server.db.dict)中任意选择数据淘汰 no-enviction 当内存达到限制的时候,不淘汰任何数据,不可写入任何数据集,所有引起申请内存的命令会报错。 算法文章:(https://blog.csdn.net/ZYZMZM_/article/details/90546812) ### 如何选择淘汰策略 下面看看几种策略的适用场景 allkeys-lru:如果我们的应用对缓存的访问符合幂律分布,也就是存在相对热点数据,或者我们不太清楚我们应用的缓存访问分布状况,我们可以选择allkeys-lru策略。 allkeys-random:如果我们的应用对于缓存key的访问概率相等,则可以使用这个策略。 volatile-ttl:这种策略使得我们可以向Redis提示哪些key更适合被eviction。 另外,volatile-lru策略和volatile-random策略适合我们将一个Redis实例既应用于缓存和又应用于持久化存储的时候,然而我们也可以通过使用两个Redis实例来达到相同的效果,值得一提的是将key设置过期时间实际上会消耗更多的内存,因此建议使用allkeys-lru策略从而更有效率的使用内存。 原文链接:[https://blog.csdn.net/qq_39399966/article/details/101211939](https://blog.csdn.net/qq_39399966/article/details/101211939)
  • [交流分享] 关于幂等性的学习笔记
    最基础的概念,什么是幂等性?幂等性:提交多次的情况下,结果都一样。比如数据库查询,可称为天然幂等性,即查询多次结果都一样,无需人为去做幂等性操作。但是update table set value=value+1 where id=1,每次执行的结构都会发生变化,不是幂等。inter into table(id,name)values(1,‘name’),如id不是主键或者没有唯一索引,重复操作上面的业务,会插入多条数据,不具备幂等性;所以我们在什么情景下需要确保幂等性呢?用户多次点击保存按钮用户保存成功后,返回上一页再次保存微服务相互调用,由于网络原因,导致请求失败解决方案一、token机制:1、根据业务场景,判断哪些业务存在幂等性问题,在执行业务之前先获取token,将token缓存止redis中2、调用业务接口时,将token携带过去,一般放在请求头,作为Auth认证3、服务器判断token是否存在于redis中,存在表示第一次请求,然后删除token,继续执行业务4、如果不存在,则表示反复操作,不执行业务逻辑,直接返回重复标志!结束风险性:业务执行前删除还是后删除token?如果是执行后删除,在业务执行中,未删除token,用户又点了请求进来,那么则无法保障幂等性。如果是执行前删除,在分布式下,用户快速请求2次,这时2个请求同时到redis去获取token,对比成功,同时删除,同时执行业务,那么也无法保障幂等性。so:使用执行前删除,在分布式情况下,获取,对比,删除必须确保原子性,所以要加分布式锁。二、加锁1、数据库锁select * from table where … for update2、业务层面加分布式锁将获取、对比、删除作为一个原子性的操作加锁,处理完成后释放锁,确保串行操作。三、约束数据库唯一约束:通过主键、唯一索引,确保无法重复新增同一笔数据,这就能确保幂等性
  • [知识分享] 谁说Redis不能存大key
    >摘要:推荐使用GaussDB(for Redis)搞定"大key"存储,从根本上解决社区版Redis使用风险。 本文分享自华为云社区《[华为云GaussDB(for Redis)揭秘第18期:谁说Redis不能存大key](https://bbs.huaweicloud.com/blogs/358513?utm_source=csdn&utm_medium=bbs-ex&utm_campaign=database&utm_content=content)》,作者: 高斯Redis官方博客 。 # 一、社区版Redis的大key痛点 GaussDB(for Redis)专家小强最近有点忙,因为很多客户经理都来找他咨询社区版Redis的大key问题,且一个个都求知欲爆表: ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654831750890201410.png) 小强一拍大腿:你们还真问对人了! 根据现网经验,生产环境因为大key导致的Redis事故屡见不鲜,其中典型的有扩容失败、请求阻塞、OOM宕机等等。早期业务规划不充分、消息队列消费不及时、未及时清理无效数据等原因都可能引入大key隐患。 **社区版Redis大key隐患常见于以下三大场景:** 1. 内存消耗不均衡,大key所在分片有OOM风险 2. 扩容时需要搬迁部分数据,大key耗时久,会导致访问阻塞甚至数据丢失 3. 删除或过期大key时,业务访问被长时间阻塞,甚至导致主从同步中断 社区版Redis架构并不适合可靠存储大key,业界也只能建议预防、拆分或及时清理大key。从客户视角出发,其实有些场景是需要大key的,例如企业ERP系统,海量货币汇率存储等。这时即使适当拆分,也避免不了较大HASH key存在。 # 二、华为云GaussDB(for Redis)的大Key解决方案 小强始终认为,好的产品应当尽量把复杂留给自己,把简单留给用户。因此,小强给每一位来咨询大key问题的客户经理都安利了better解决方案——**使用华为云企业级KV数据库GaussDB(for Redis)**。 大key场景下,GaussDB(for Redis)究竟比社区版Redis优秀在哪?**下面从3个角度深度分析**: ## 1. 高斯Redis支持大key存储,不用担心分片OOM - 社区版Redis存储大key会导致分片内存消耗不均,随着集群整体数据量水位提升,大key所在分片随时有OOM风险。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654831808025261121.png) - 高斯Redis支持大key可靠存储,且不会导致分片OOM。需要注意的是,虽然高斯Redis适合用来可靠存储大key,但从网络链路角度考虑,业务应避免对大key执行诸如hgetall等风险命令。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654831820002773073.png) ## 2. 高斯Redis在大key场景中也支持秒级无损扩容 - 社区版Redis在扩容时,由于要搬迁数据,此时画风是这样的: ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654831839254171355.png) 图:社区版Redis在大key场景扩容,风险高 可以总结为:**有大key,开源Redis请谨慎扩容!** - 高斯Redis支持秒级扩容,并支持升规格、加节点、加存储容量3种手段灵活扩容,运维体验极佳。‍ ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654831894877234967.png) 图:高斯Redis在大key场景可安全扩容 从上图可以看出,高斯Redis采用计算、存储分离架构,扩容时不必搬迁任何数据,因此速度、稳定性都远超社区版Redis。**有大key,高斯Redis可以放心扩容!** ## 3. 高斯Redis删除/过期大key时,业务0阻塞 - 社区版Redis大key的删除/过期都会导致访问严重阻塞。实测删除/过期一个大hash key(包含1000w个元素),社区版Redis访问阻塞长达整整14秒。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654831962213535379.png) 图:社区版Redis在大key删除场景阻塞业务访问 虽然社区版Redis提供了“异步”的unlink命令能够一定程度上缓解大key阻塞问题,但unlink并非严格异步,例如对于zset类型(skiplist编码)以及全部string key都只能阻塞删除,风险不可控。 - 高斯Redis从根本上解决了大key删除/过期操作隐患。在高斯Redis中,对任何数据执行删除/过期,都是立刻执行成功且0阻塞。这是由于底层采用了真正的“标记删除”,因此完全不影响业务访问。实测删除/过期一个大hash key(包含1000w个元素),高斯Redis仅毫秒级。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654831978776157898.png) # 三、总结 根据上述对比评测,可看出相比社区版Redis的实际表现,高斯Redis更适用于大key的可靠存储场景。除了能解决业务大key痛点外,高斯Redis在稳定性、可靠性、安全性等方面也有全面的提升。
  • [交流吐槽] Redis 缓存击穿(失效)、缓存穿透、缓存雪崩怎么解决?
    原始数据存储在 DB 中(如 MySQL、Hbase 等),但 DB 的读写性能低、延迟高。比如 MySQL 在 4 核 8G 上的 TPS = 5000,QPS = 10000 左右,读写平均耗时 10~100 ms。用 Redis 作为缓存系统正好可以弥补 DB 的不足,「码哥」在自己的 MacBook Pro 2019 上执行 Redis 性能测试如下:$ redis-benchmark -t set,get -n 100000 -qSET: 107758.62 requests per second, p50=0.239 msecGET: 108813.92 requests per second, p50=0.239 msecTPS 和 QPS 达到 10 万,于是乎我们就引入缓存架构,在数据库中存储原始数据,同时在缓存总存储一份。当请求进来的时候,先从缓存中取数据,如果有则直接返回缓存中的数据。如果缓存中没数据,就去数据库中读取数据并写到缓存中,再返回结果。这样就天衣无缝了么?缓存的设计不当,将会导致严重后果,本文将介绍缓存使用中常见的三个问题和解决方案:缓存击穿(失效);缓存穿透;缓存雪崩。缓存击穿(失效)高并发流量,访问的这个数据是热点数据,请求的数据在 DB 中存在,但是 Redis 存的那一份已经过期,后端需要从 DB 从加载数据并写到 Redis。关键字:单一热点数据、高并发、数据失效但是由于高并发,可能会把 DB 压垮,导致服务不可用。如下图所示:解决方案过期时间 + 随机值对于热点数据,我们不设置过期时间,这样就可以把请求都放在缓存中处理,充分把 Redis 高吞吐量性能利用起来。或者过期时间再加一个随机值。设计缓存的过期时间时,使用公式:过期时间=baes 时间+随机时间。即相同业务数据写缓存时,在基础过期时间之上,再加一个随机的过期时间,让数据在未来一段时间内慢慢过期,避免瞬时全部过期,对 DB 造成过大压力预热预先把热门数据提前存入 Redis 中,并设热门数据的过期时间超大值。使用锁当发现缓存失效的时候,不是立即从数据库加载数据。而是先获取分布式锁,获取锁成功才执行数据库查询和写数据到缓存的操作,获取锁失败,则说明当前有线程在执行数据库查询操作,当前线程睡眠一段时间在重试。这样只让一个请求去数据库读取数据。伪代码如下:public Object getData(String id) {    String desc = redis.get(id);        // 缓存为空,过期了        if (desc == null) {            // 互斥锁,只有一个请求可以成功            if (redis(lockName)) {                try                    // 从数据库取出数据                    desc = getFromDB(id);                    // 写到 Redis                    redis.set(id, desc, 60 * 60 * 24);                } catch (Exception ex) {                    LogHelper.error(ex);                } finally {                    // 确保最后删除,释放锁                    redis.del(lockName);                    return desc;                }            } else {                // 否则睡眠200ms,接着获取锁                Thread.sleep(200);                return getData(id);            }        }}缓存穿透缓存穿透:意味着有特殊请求在查询一个不存在的数据,即数据不存在 Redis 也不存在于数据库。导致每次请求都会穿透到数据库,缓存成了摆设,对数据库产生很大压力从而影响正常服务。如图所示:解决方案缓存空值:当请求的数据不存在 Redis 也不存在数据库的时候,设置一个缺省值(比如:None)。当后续再次进行查询则直接返回空值或者缺省值。布隆过滤器:在数据写入数据库的同时将这个 ID 同步到到布隆过滤器中,当请求的 id 不存在布隆过滤器中则说明该请求查询的数据一定没有在数据库中保存,就不要去数据库查询了。BloomFilter 要缓存全量的 key,这就要求全量的 key 数量不大,100 亿 条数据以内最佳,因为 100 亿条数据大概要占用 3.5GB 的内存。说下布隆过滤器的原理吧BloomFilter 的算法是,首先分配一块内存空间做 bit 数组,数组的 bit 位初始值全部设为 0。加入元素时,采用 k 个相互独立的 Hash 函数计算,然后将元素 Hash 映射的 K 个位置全部设置为 1。检测 key 是否存在,仍然用这 k 个 Hash 函数计算出 k 个位置,如果位置全部为 1,则表明 key 存在,否则不存在。如下图所示:哈希函数会出现碰撞,所以布隆过滤器会存在误判。这里的误判率是指,BloomFilter 判断某个 key 存在,但它实际不存在的概率,因为它存的是 key 的 Hash 值,而非 key 的值。所以有概率存在这样的 key,它们内容不同,但多次 Hash 后的 Hash 值都相同。对于 BloomFilter 判断不存在的 key ,则是 100% 不存在的,反证法,如果这个 key 存在,那它每次 Hash 后对应的 Hash 值位置肯定是 1,而不会是 0。布隆过滤器判断存在不一定真的存在。缓存雪崩缓存雪崩指的是大量的请求无法在 Redis 缓存系统中处理,请求全部打到数据库,导致数据库压力激增,甚至宕机。出现该原因主要有两种:大量热点数据同时过期,导致大量请求需要查询数据库并写到缓存;Redis 故障宕机,缓存系统异常。缓存大量数据同时过期数据保存在缓存系统并设置了过期时间,但是由于在同时一刻,大量数据同时过期。系统就把请求全部打到数据库获取数据,并发量大的话就会导致数据库压力激增。缓存雪崩是发生在大量数据同时失效的场景,而缓存击穿(失效)是在某个热点数据失效的场景,这是他们最大的区别。如下图:缓存雪崩-大量缓存同时失效解决方案过期时间添加随机值要避免给大量的数据设置一样的过期时间,过期时间 = baes 时间+ 随机时间(较小的随机数,比如随机增加 1~5 分钟)。这样一来,就不会导致同一时刻热点数据全部失效,同时过期时间差别也不会太大,既保证了相近时间失效,又能满足业务需求。接口限流当访问的不是核心数据的时候,在查询的方法上加上接口限流保护。比如设置 10000 req/s。如果访问的是核心数据接口,缓存不存在允许从数据库中查询并设置到缓存中。这样的话,只有部分请求会发送到数据库,减少了压力。限流,就是指,我们在业务系统的请求入口前端控制每秒进入系统的请求数,避免过多的请求被发送到数据库。如下图所示:缓存雪崩-限流Redis 故障宕机一个 Redis 实例能支撑 10 万的 QPS,而一个数据库实例只有 1000 QPS。一旦 Redis 宕机,会导致大量请求打到数据库,从而发生缓存雪崩。解决方案对于缓存系统故障导致的缓存雪崩的解决方案有两种:服务熔断和接口限流;构建高可用缓存集群系统。服务熔断和限流在业务系统中,针对高并发的使用服务熔断来有损提供服务从而保证系统的可用性。服务熔断就是当从缓存获取数据发现异常,则直接返回错误数据给前端,防止所有流量打到数据库导致宕机。服务熔断和限流属于在发生了缓存雪崩,如何降低雪崩对数据库造成的影响的方案。构建高可用的缓存集群所以,缓存系统一定要构建一套 Redis 高可用集群,比如 《Redis 哨兵集群》或者 《Redis Cluster 集群》,如果 Redis 的主节点故障宕机了,从节点还可以切换成为主节点,继续提供缓存服务,避免了由于缓存实例宕机而导致的缓存雪崩问题。总结缓存穿透指的是数据库本就没有这个数据,请求直奔数据库,缓存系统形同虚设。缓存击穿(失效)指的是数据库有数据,缓存本应该也有数据,但是缓存过期了,Redis 这层流量防护屏障被击穿了,请求直奔数据库。缓存雪崩指的是大量的热点数据无法在 Redis 缓存中处理(大面积热点数据缓存失效、Redis 宕机),流量全部打到数据库,导致数据库极大压力。
  • [交流吐槽] Redis消息队列发展历程
    作者 | 丕天Redis是目前最受欢迎的kv类数据库,当然它的功能越来越多,早已不限定在kv场景,消息队列就是Redis中一个重要的功能。Redis从2010年发布1.0版本就具备一个消息队列的雏形,随着10多年的迭代,其消息队列的功能也越来越完善,作为一个全内存的消息队列,适合应用与要求高吞吐、低延时的场景。我们来盘一下Redis消息队列功能的发展历程,历史版本有哪些不足,后续版本是如何来解决这些问题的。一、Redis 1.0 list从广义上来讲消息队列就是一个队列的数据结构,生产者从队列一端放入消息,消费者从另一端读取消息,消息保证先入先出的顺序,一个本地的list数据结构就是一个进程维度的消息队列,它可以让模块A写入消息,模块B消费消息,做到模块A/B的解耦与异步化。但想要做到应用级别的解耦和异步还需要一个消息队列的服务。1.list的特性Redis 1.0发布时就具备了list数据结构,应用A可以通过lpush写入消息,应用B通过rpop从队列中读取消息,每个消息只会被读取一次,而且是按照lpush写入的顺序读到。同时Redis的接口是并发安全的,可以同时有多个生产者向一个list中生产消息,多个消费者从list中读取消息。这里还有个问题,消费者要如何知道list中有消息了,需要不断轮询去查询吗。轮询无法保证消息被及时的处理,会增加延时,而且当list为空时,大部分轮询的请求都是无效请求,这种方式大量浪费了系统资源。好在Redis有brpop接口,该接口有一个参数是超时时间,如果list为空,那么Redis服务端不会立刻返回结果,它会等待list中有新数据后在返回或是等待最多一个超时时间后返回空。通过brpop接口实现了长轮询,该效果等同于服务端推送,消费者能立刻感知到新的消息,而且通过设置合理的超时时间,使系统资源的消耗降到很低。#基于list完成消息的生产和消费 #生产者生产消息msg1 lpush listA msg1 (integer) 1 #消费者读取到消息msg1 rpop listA "msg1" #消费者阻塞式读取listA,如果有数据立刻返回,否则最多等待10秒 brpop listA 10 1) "listA" 2) "msg1"使用rpop或brpop这样接口消费消息会先从队列中删除消息,然后再由应用消费,如果应用应用在处理消息前异常宕机了,消息就丢失了。但如果使用lindex这样的只读命令先读取消息处理完毕后在删除,又需要额外的机制来保证一条消息不会被其他消费者重复读到。好在list有rpoplpush或brpoplpush这样的接口,可以原子性的从一个list中移除一个消息并加入另一个list。应用程序可以通过2个list组和来完成消息的消费和确认功能,使用rpoplpush从list A中消费消息并移入list B,等消息处理完毕后在从list B中删除消息,如果在处理消息过程中应用异常宕机,恢复后应用可以重新从list B中读取未处理的消息并处理。这种方式为消息的消费增加了ack机制。#基于2个list完成消息消费和确认 #从listA中读取消息并写入listB rpoplpush listA listB "msg1" #业务逻辑处理msg1完毕后,从listB中删除msg1,完成消息的确认 lrem listB 1 msg1 (integer) 12.list的不足之处通过Redis 1.0就引入的list结构我们就能实现一个分布式的消息队列,满足一些简单的业务需求。但list结构作为消息队列服务有一个很致命的问题,它没有广播功能,一个消息只能被消费一次。而在大型系统中,通常一个消息会被下游多个应用同时订阅和消费,例如当用户完成一个订单的支付操作时,需要通知商家发货,要更新物流状态,可能还会提高用户的积分和等级,这些都是不同的下游子系统,他们全部会订阅支付完成的操作,而list一个消息只能被消费一次在这样复杂的大型系统面前就捉襟见肘了。可能你会说那弄多个list,生产者向每个list中都投递消息,每个消费者处理自己的list不就行了吗。这样第一是性能不会太好,因为同一个消息需要被重复的投递,第二是这样的设计违反了生产者和消费者解耦的原则,这个设计下生产者需要知道下游有哪些消费者,如果业务发生变化,需要额外增加一个消费者,生产者的代码也需要修改。3.总结优势模型简单,和使用本地list基本相同,适配容易通过brpop做到消息处理的实时性通过rpoplpush来联动2个list,可以做到消息先消费后确认,避免消费者应用异常情况下消息丢失不足消息只能被消费一次,缺乏广播机制二、Redis 2.0 pubsublist作为消息队列应用场景受到限制很重要的原因在于没有广播,所以Redis 2.0中引入了一个新的数据结构pubsub。pubsub虽然不能算作是list的替代品,但它确实能解决一些list不能解决的问题。1.pubsub特性pubsub引入一个概念叫channel,生产者通过publish接口投递消息时会指定channel,消费者通过subscribe接口订阅它关心的channel,调用subscribe后这条连接会进入一个特殊的状态,通常不能在发送其他请求,当有消息投递到这个channel时Redis服务端会立刻通过该连接将消息推送到消费者。这里一个channel可以被多个应用订阅,消息会同时投递到每个订阅者,做到了消息的广播。另一方面,消费者可以会订阅一批channel,例如一个用户订阅了浙江的新闻的推送,但浙江新闻还会进行细分,例如“浙江杭州xx”、“浙江温州xx”,这里订阅者不需要获取浙江的所有子类在挨个订阅,只需要调用psubscribe“浙江*”就能订阅所有以浙江开头的新闻推送了,这里psubscribe传入一个通配符表达的channel,Redis服务端按照规则推送所有匹配channel的消息给对应的客户端。#基于pubsub完成channel的匹配和消息的广播 #消费者1订阅channel1 subscribe channel1 1) "subscribe" 2) "channel1" 3) (integer) 1 #收到消息推送 1) "message" 2) "channel1" 3) "msg1" #消费者2订阅channel* psubscribe channel* 1) "psubscribe" 2) "channel*" 3) (integer) 1 #收到消息推送 1) "pmessage" 2) "channel*" 3) "channel1" 4) "msg1" 1) "pmessage" 2) "channel*" 3) "channel2" 4) "msg2" #生产者发布消息msg1和msg2 publish channel1 msg1 (integer) 2 publish channel2 msg2 (integer) 1在Redfis 2.8时加入了keyspace notifications功能,此时pubsub除了通知用户自定义消息,也可以通知系统内部消息。keyspace notifications引入了2个特殊的channel分别是__keyevent@__:和__keyspace@__:,通过订阅__keyevent客户端可以收到某个具体命令调用的回调通知,通过订阅__keyspace客户端可以收到目标key的增删改操作以及过期事件。使用这个功能还需要开启配置notify-keyspace-events。#通过keyspace notifications功能获取系统事件 #写入请求 set testkey v EX 1 #订阅key级别的事件 psubscribe __keyspace@0__:testkey 1) "psubscribe" 2) "__keyspace@0__:testkey" 3) (integer) 1 #收到通知 1) "pmessage" 2) "__keyspace@0__:testkey" 3) "__keyspace@0__:testkey" 4) "set" 1) "pmessage" 2) "__keyspace@0__:testkey" 3) "__keyspace@0__:testkey" 4) "expire" 1) "pmessage" 2) "__keyspace@0__:testkey" 3) "__keyspace@0__:testkey" 4) "expired" #订阅所有的命令事件 psubscribe __keyevent@0__:* 1) "psubscribe" 2) "__keyevent@0__:*" 3) (integer) 1 #收到通知 1) "pmessage" 2) "__keyevent@0__:*" 3) "__keyevent@0__:set" 4) "testkey" 1) "pmessage" 2) "__keyevent@0__:*" 3) "__keyevent@0__:expire" 4) "testkey" 1) "pmessage" 2) "__keyevent@0__:*" 3) "__keyevent@0__:expired" 4) "testkey"2.pubsub的不足之处pubsub既能单播又能广播,还支持channel的简单正则匹配,功能上已经能满足大部分业务的需求,而且这个接口发布的时间很早,在2011年Redis 2.0发布时就已经具备,用户基础很广泛,所以现在很多业务都有用到这个功能。但你要深入了解pubsub的原理后,是肯定不敢把它作为一个一致性要求较高,数据量较大系统的消息服务的。首先,pubsub的消息数据是瞬时的,它在Redis服务端不做保存,publish发送到Redis的消息会立刻推送到所有当时subscribe连接的客户端,如果当时客户端因为网络问题断连,那么就会错过这条消息,当客户端重连后,它没法重新获取之前那条消息,甚至无法判断是否有消息丢失。其次,pubsub中消费者获取消息是一个推送模型,这意味着Redis会按消息生产的速度给所有的消费者推送消息,不管消费者处理能力如何,如果消费者应用处理能力不足,消息就会在Redis的client buf中堆积,当堆积数据超过一个阈值后会断开这条连接,这意味着这些消息全部丢失了,在也找不回来了。如果同时有多个消费者的client buf堆积数据但又还没达到断开连接的阈值,那么Redis服务端的内存会膨胀,进程可能因为oom而被杀掉,这导致了整个服务中断。3.总结优势消息具备广播能力psubscribe能按字符串通配符匹配,给予了业务逻辑的灵活性能订阅特定key或特定命令的系统消息不足Redis异常、客户端断连都会导致消息丢失消息缺乏堆积能力,不能削峰填谷。推送的方式缺乏背压机制,没有考虑消费者处理能力,推送的消息超过消费者处理能力后可能导致消息丢失或服务异常三、Redis 5.0 stream消息丢失、消息服务不稳定的问题严重限制了pubsub的应用场景,所以Redis需要重新设计一套机制,来解决这些问题,这就有了后来的stream结构。1.stream特性一个稳定的消息服务需要具备几个要点,要保证消息不会丢失,至少被消费一次,要具备削峰填谷的能力,来匹配生产者和消费者吞吐的差异。在2018年Redis 5.0加入了stream结构,这次考虑了list、pubsub在应用场景下的缺陷,对标kafka的模型重新设计全内存消息队列结构,从这时开始Redis消息队列功能算是能和主流消息队列产品pk一把了。stream的改进分为多个方面成本:存储message数据使用了listpack结构,这是一个紧凑型的数据结构,不同于list的双向链表每个节点都要额外占用2个指针的存储空间,这使得小msg情况下stream的空间利用率更高。功能:stream引入了消费者组的概念,一个消费者组内可以有多个消费者,同一个组内的消费者共享一个消息位点(last_delivered_id),这使得消费者能够水平的扩容,可以在一个组内加入多个消费者来线性的提升吞吐,对于一个消费者组,每条msg只会被其中一个消费者获取和处理,这是pubsub的广播模型不具备的。不同消费者组之前是相互隔离的,他们各自维护自己的位点,这使得一条msg能被多个不同的消费者组重复消费,做到了消息广播的能力。stream中消费者采用拉取的方式,并能设置timeout在没有消息时阻塞,通过这种长轮询机制保证了消息的实时性,而且消费速率是和消费者自身吞吐相匹配。消息不丢失:stream的数据会存储在aof和rdb文件中,这使Redis重启后能够恢复stream的数据。而pubsub的数据是瞬时的,Redis重启意味着消息全部丢失。stream中每个消费者组会存储一个last_delivered_id来标识已经读取到的位点,客户端连接断开后重连还是能从该位点继续读取,消息不会丢失。stream引入了ack机制保证消息至少被处理一次。考虑一种场景,如果消费者应用已经读取了消息,但还没来得及处理应用就宕机了,对于这种已经读取但没有ack的消息,stream会标示这条消息的状态为pending,等客户端重连后通过xpending命令可以重新读取到pengind状态的消息,继续处理。如果这个应用永久宕机了,那么该消费者组内的其他消费者应用也能读取到这条消息,并通过xclaim命令将它归属到自己下面继续处理。#基于stream完成消息的生产和消费,并确保异常状态下消息至少被消费一次 #创建mystream,并且创建一个consumergroup为mygroup XGROUP CREATE mystream mygroup $ MKSTREAM OK #写入一条消息,由redis自动生成消息id,消息的内容是一个kv数组,这里包含field1 value1 field2 value2 XADD mystream * field1 value1 field2 value2 "1645517760385-0" #消费者组mygroup中的消费者consumer1从mystream读取一条消息,>表示读取一条该消费者组从未读取过的消息 XREADGROUP GROUP mygroup consumer1 COUNT 1 STREAMS mystream > 1) 1) "mystream" 2) 1) 1) "1645517760385-0" 2) 1) "field1" 2) "value1" 3) "field2" 4) "value2" #消费完成后ack确认消息 xack mystream mygroup 1645517760385-0 (integer) 1 #如果消费者应用在ack前异常宕机,恢复后重新获取未处理的消息id。 XPENDING mystream mygroup - + 10 1) 1) "1645517760385-0" 2) "consumer1" 3) (integer) 305356 4) (integer) 1 #如果consumer1永远宕机,其他消费者可以把pending状态的消息移动到自己名下后继续消费 #将消息id 1645517760385-0移动到consumer2下 XCLAIM mystream mygroup consumer2 0 1645517760385-0 1) 1) "1645517760385-0" 2) 1) "field1" 2) "value1" 3) "field2" 4) "value2"Redis stream保证了消息至少被处理一次,但如果想做到每条消息仅被处理一次还需要应用逻辑的介入。消息被重复处理要么是生产者重复投递,要么是消费者重复消费。对于生产者重复投递问题,Redis stream为每个消息都设置了一个唯一递增的id,通过参数可以让Redis自动生成id或者应用自己指定id,应用可以根据业务逻辑为每个msg生成id,当xadd超时后应用并不能确定消息是否投递成功,可以通过xread查询该id的消息是否存在,存在就说明已经投递成功,不存在则重新投递,而且stream限制了id必须递增,这意味了已经存在的消息重复投递会被拒绝。这套机制保证了每个消息可以仅被投递一次。对于消费者重复消费的问题,考虑一个场景,消费者读取消息后业务处理完毕,但还没来得及ack就发生了异常,应用恢复后对于这条没有ack的消息进行了重复消费。这个问题因为ack和消费消息的业务逻辑发生在2个系统,没法做到事务性,需要业务来改造,保证消息处理的幂等性。2.stream的不足stream的模型做到了消息的高效分发,而且保证了消息至少被处理一次,通过应用逻辑的改造能做到消息仅被处理一次,它的能力对标kafka,但吞吐高于kafka,在高吞吐场景下成本比kafka低,那它又有哪些不足了。首先消息队列很重要的一个功能就是削峰填谷,来匹配生产者和消费者吞吐的差异,生产者和消费者吞吐差异越大,持续时间越长,就意味着steam中需要堆积更多的消息,而Redis作为一个全内存的产品,数据堆积的成本比磁盘高。其次stream通过ack机制保证了消息至少被消费一次,但这有个前提就是存储在Redis中的消息本身不会丢失。Redis数据的持久化依赖aof和rdb文件,aof落盘方式有几种,通过配置appendfsync决定,通常我们不会配置为always来让每条命令执行完后都做一次fsync,线上配置一般为everysec,每秒做一次fsync,而rdb是全量备份时生成,这意味了宕机恢复可能会丢掉最近一秒的数据。另一方面线上生产环境的Redis都是高可用架构,当主节点宕机后通常不会走恢复逻辑,而是直接切换到备节点继续提供服务,而Redis的同步方式是异步同步,这意味着主节点上新写入的数据可能还没同步到备节点,在切换后这部分数据就丢失了。所以在故障恢复中Redis中的数据可能会丢失一部分,在这样的背景下无论stream的接口设计的多么完善,都不能保证消息至少被消费一次。3.总结优势在成本、功能上做了很多改进,支持了紧凑的存储小消息、具备广播能力、消费者能水平扩容、具备背压机制通过ack机制保证了Redis服务端正常情况下消息至少被处理一次的能力不足内存型消息队列,数据堆积成本高Redis本身rpo>0,故障恢复可能会丢数据,所以stream在Redis发生故障恢复后也不能保证消息至少被消费一次。四、Tair持久内存版 streamRedis stream的不足也是内存型数据库特性带来的,它拥有高吞吐、低延时,但大容量下成本会比较高,而应用的场景也不完全是绝对的大容量低吞吐或小容量高吞吐,有时应用的场景会介于二者之间,需要平衡容量和吞吐的关系,所以需要一个产品它的存储成本低于Redis stream,但它的性能又高于磁盘型消息队列。另一方面Redis stream在Redis故障场景下不能保证消息的不丢失,这导致业务需要自己实现一些复杂的机制来回补这段数据,同时也限制了它应用在一些对一致性要求较高的场景。为了让业务逻辑更简单,stream应用范围更广,需要保证故障场景下的消息持久化。兼顾成本、性能、持久化,这就有了Tair持久内存版。1.Tair持久内存版特性更大空间,更低成本Tair持久内存版引入了Intel傲腾持久内存(下面称作AEP),它的性能略低于内存,但相同容量下成本低于内存。Tair持久内存版将主要数据存储在AEP上,使得相同容量下,成本更低,这使同样单价下stream能堆积更多的消息。兼容社区版Tair持久内存版兼容原生Redis绝大部分的数据结构和接口,对于stream相关接口做到了100%兼容,如果你之前使用了社区版stream,那么不需要修改任何代码,只需要换一个连接地址就能切换到持久内存版。并且通过工具完成社区版和持久内存版数据的双向迁移。数据的实时持久化Tair持久内存版并不是简单将Redis中的数据换了一个介质存储,因为这样仅能通过AEP降低成本,但没用到AEP断电数据不丢失的特性,对持久化能力没有任何提升。开源Redis通过在磁盘上记录AppendOnlyLog来持久化数据,AppendOnlyLog记录了所有的写操作,相当于redolog,在宕机恢复时通过回放这些log恢复数据。但受限于磁盘介质的高延时和Redis内存数据库使用场景下对低延时的要求,并不能在每次写操作后fsync持久化log,最新写入的数据可能并没有持久化到磁盘,这也是数据可能丢失的根因。Tair持久内存版的数据恢复没有使用AppendOnlyLog来完成, 而是将将redis数据结构存储在AEP上,这样宕机后这些数据结构并不会丢失,并且对这些数据结构增加了一些额外的描述信息,宕机后在recovery时能够读到这些额外的描述信息,让这些redis数据结构重新被识别和索引,将状态恢复到宕机前的样子。Tair通过将redis数据结构和描述信息实时写入AEP,保证了写入数据的实时持久化。HA数据不丢失Tair持久内存版保证了数据的持久化,但生产环境中都是高可用架构,多数情况下当主节点异常宕机后并不会等主节点重启恢复,而是切换到备节点继续提供服务,然后给新的主节点添加一个新的备节点。所以在故障发生时如果有数据还没从主节点同步到备节点,这部分数据就会丢失。Redis采用的异步同步,当客户端写入数据并返回成功时对Redis的修改可能还没同步到备节点,如果此时主节点宕机数据就会丢失。为了避免在HA过程中数据丢失,Tair持久内存版引入了半同步机制,确保写入请求返回成功前相关的修改已经同步到备节点。可以发现开启半同步功能后写入请求的RT会变高,多出主备同步的耗时,这部分耗时大概在几十微秒。但通过一些异步化的技术,虽然写请求的RT会变高,但对实例的最大写吞吐影响很小。当开启半同步后生成者通过xadd投递消息,如果返回成功,消息一定同步到备节点,此时发生HA,消费者也能在备节点上读到这条消息。如果xadd请求超时,此时消息可能同步到备节点也可能没有,生产者没法确定,此时通过再次投递消息,可以保证该消息至少被消费一次。如果要严格保证消息仅被消费一次,那么生产者可以通过xread接口查询消息是否存在,对于不存在的场景重新投递。2.总结优势引入了AEP作为存储介质,目前Tair持久内存版价格是社区版的70%。保证了数据的实时持久化,并且通过半同步技术保证了HA不丢数据,大多数情况下做到消息不丢失(备库故障或主备网络异常时会降级为异步同步,优先保障可用性),消息至少被消费一次或仅被消费一次。五、未来消息队列主要是为了解决3类问题,应用模块的解耦、消息的异步化、削峰填谷。目前主流的消息队列都能满足这些需求,所以在实际选型时还会考虑一些特殊的功能是否满足,产品的性能如何,具体业务场景下的成本怎么样,开发的复杂度等。Redis的消息队列功能并不是最全面的,它不希望做成一个大而全的产品,而是做一个小而美的产品,服务好一部分用户在某些场景下的需求。目前用户选型Redis作为消息队列服务的原因,主要有Redis在相同成本下吞吐更高、Redis的延时更低、应用需要一个消息服务但又不想额外引入一堆依赖等。未来Tair持久内存版会针对这些述求,把这些优势继续放大。吞吐通过优化持久内存版的持久化流程,让吞吐接近内存版甚至超过内存版吞吐。延时通过rdma在多副本间同步数据,降低半同步下写入数据的延时。
  • [交流吐槽] MySQL 与 Redis 的区别
    MySQL 是持久化存储,存放在磁盘里面,检索的话,会涉及到一定的 IO,为了解决这个瓶颈,于是出现了缓存,比如现在用的最多的 memcached(简称mc)。首先,用户访问mc,如果未命中,就去访问 MySQL,之后像内存和硬盘一样,把数据复制到mc一部分。  Redis 和mc都是缓存,并且都是驻留在内存中运行的,这大大提升了高数据量web访问的访问速度。然而mc只是提供了简单的数据结构,比如 string存储;Redis却提供了大量的数据结构,比如string、list、set、hashset、sorted set这些,这使得用户方便了好多,毕竟封装了一层实用的功能,同时实现了同样的效果,当然用Redis而慢慢舍弃mc。  内存和硬盘的关系,硬盘放置主体数据用于持久化存储,而内存则是当前运行的那部分数据,CPU访问内存而不是磁盘,这大大提升了运行的速度,当然这是基于程序的局部化访问原理。  推理到 Redis + MySQL,它是内存+磁盘关系的一个映射,MySQL 放在磁盘,Redis放在内存,这样的话,web应用每次只访问Redis,如果没有找到的数据,才去访问 MySQL。  然而 Redis + MySQL 和内存+磁盘的用法最好是不同的。前者是内存数据库,数据保存在内存中,当然速度快。后者是关系型数据库,功能强大,数据访问也就慢。像memcache,MongoDB,Redis,都属于No SQL系列。不是一个类型的东西,应用场景也不太一样,还是要看你的需求来决定。
  • [交流吐槽] MongoDB和Redis区别
    MongoDB和Redis都是NoSQL,采用结构型数据存储。二者在使用场景中,存在一定的区别,这也主要由于二者在内存映射的处理过程,持久化的处理方法不同。MongoDB建议集群部署,更多的考虑到集群方案,Redis更偏重于进程顺序写入,虽然支持集群,也仅限于主-从模式。指标 MongoDB(v2.4.9) Redis(v2.4.17) 比较说明实现语言 C++C/C++-协议BSON、自定义二进制类Telnet-性能依赖内存,TPS较高依赖内存,TPS非常高Redis优于MongoDB可操作性丰富的数据表达、索引;最类似于关系数据库,支持丰富的查询语言数据丰富,较少的IOMongoDB优于Redis内存及存储适合大数据量存储,依赖系统虚拟内存管理,采用镜像文件存储;内存占有率比较高,官方建议独立部署在64位系统(32位有最大2.5G文件限制,64位没有改限制)Redis2.0后增加虚拟内存特性,突破物理内存限制;数据可以设置时效性,类似于memcache不同的应用角度看,各有优势可用性支持master-slave,replicaset(内部采用paxos选举算法,自动故障恢复),auto sharding机制,对客户端屏蔽了故障转移和切分机制依赖客户端来实现分布式读写;主从复制时,每次从节点重新连接主节点都要依赖整个快照,无增量复制;不支持自动sharding,需要依赖程序设定一致hash机制MongoDB优于Redis;单点问题上,MongoDB应用简单,相对用户透明,Redis比较复杂,需要客户端主动解决。(MongoDB 一般会使用replica sets和sharding功能结合,replica sets侧重高可用性及高可靠性,而sharding侧重于性能、易扩展)可靠性从1.8版本后,采用binlog方式(MySQL同样采用该方式)支持持久化,增加可靠性依赖快照进行持久化;AOF增强可靠性;增强可靠性的同时,影响访问性能MongoDB优于Redis一致性不支持事物,靠客户端自身保证支持事物,比较弱,仅能保证事物中的操作按顺序执行Redis优于MongoDB数据分析内置数据分析功能(mapreduce)不支持MongoDB优于Redis应用场景海量数据的访问效率提升较小数据量的性能及运算MongoDB优于Redis
  • [技术干货] redis 主从复制
    主从复制:主节点负责写数据,从节点负责读数据,从而实现读写分离,提高redis的高可用性。让一个服务器去复制(replicate)另一个服务器,我们称呼被复制的服务器为主节点(master),而对主服务器进行复制的服务器则被称为从节点(slave)主从复制的特点:1、一个master可以有多个slave2、一个slave只能有一个master3、数据流向是单向的,master到slave 主从复制的作用:1、数据副本:多一份或多份数据拷贝,保证redis高可用2、扩展性能:单机redis的性能是有限的,主从复制能横向扩展 如容量、QPS等主从复制实现方式客户端命令:slaveof全量复制和增量复制全量复制过程:1.  向主节点发送psync,有两个参数,第一个参数是runId,第二个参数是偏移量,第一次发送不知道主节点的runId,也不知道偏移量,因此从节点发送 ?  -12.  主节点收到消息,根据? -1 能判断出来是第一次复制,主节点把runId和offset 发送给Slave节点,3.  从节点保存主节点基本信息4-5-6.  Master节点执行bgsave生成快照,在此期间会记录后续执行的数据更改命令所更改的数据,直到主节点将生成的RDB文件传输到从节点为止,            期间Master节点执行的写操作,主节点会将缓冲区中记录的新更改的数据发送给从节点7-8      从节点清空此前的所有数据,加载RDB文件恢复数据并存入新更改的数据说明: 全量复制的性能开销:1. bgsave生成RDB文件需要的时间,2.  RDB文件在网络间的传输时间,3.  从节点的数据清空时间  ,  4.  加载RDB文件的时间  5. 可能的 AOF   重写时间 数据更改命令缓冲区repl_back_buffer用于:当Redis通过Linux中的fork()函数开辟一个子进程处理其他事务(比如主进程执行bgsave生成一个RDB文件时,或者主进程执行bgrewriteaof生成一个AOF文件时), 而主进程(即处理客户端命令的进程)后续执行的一些数据更改命令会被暂时保存在该区域,而且该区域空间有限(配置文件中repl-backlog-size 1mb即可配置该处空间大小)部分复制部分复制解决的问题:在实际环境中,主节点与从节点之间可能会发生一些网络波动等情况,导致从节点与主节点之间的网络连接断开(主从节点的Redis均未关闭),如果重新连接上后,可以使用全量复制来重新进行一次主从节点数据同步,但是全量复制会带来一个性能开销的问题,而且从节点中可能有大量数据是主节点中没有更该过的,也就是不需要进行再次同步的数据,如果使用全量复制肯定是带来了一些不必要的浪费。所以,部分复制功能就是为了解决该问题的。过程:1.  主从节点直接连接断开,2.  此时主节点继续执行的数据更改命令会被记录在一个缓冲区  repl_back_buffer  中3.  当从节点重新连接主节点时,4.   自动发出一条命令(psync offset run_id),将从节点中存储的主节点的Redis运行时id和从节点中保存的偏移量发送给主节点5.  主节点接收从节点发送的偏移量和id,对比此时主节点的偏移量和接收的偏移量,如果两个偏移量之差大于repl_back_buffer中的数据,那么就表示在断开连接期间从节点已经丢失了超出规定数量的数据,此时就需要进行全量复制了,否则就进行部分复制6.  将主节点缓冲区中的数据同步更新到从节点中,这样就实现了部分数据的复制同步,降低了性能开销主从节点的故障处理故障发生时服务自动转移(自动故障转移):即当某个节点发生故障导致停止服务时,该节点提供的服务会有另一个节点自动代替提供,这样就实现了一个高可用的效果从节点故障:即如果某个从节点发生了故障,导致无法向在该节点上的客户端提供读服务,解决办法就是使该客户端转移到另一个可用从节点上,但是在转移时,应该考虑该从节点能承受几个客户端的压力主节点故障:如果主节点发生故障,在使用主节点进行读写操作的客户端就无法使用了,而使用从节点只进行读操作的客户端还是可以继续使用的,解决办法就是从从节点中选一个节点更改为主节点,并且将原主节点的客户端连接到新的主节点上,然后通过该客户端将其他从节点连接到新的主节点中主从复制确实可以解决故障问题,但是主从复制不能实现自动故障转移,其必须要通过一些手动操作,而且非常麻烦,所以要实现自动故障转移还需要另一个功能,Redis中提供了sentinel功能来实现自动故障转移。主从节点的故障处理 1. 读写分离:即客户端发来的读写命令分开,写命令交给主节点执行,读命令交给从节点执行,不仅减少了主节点的压力,而且增强了读操作的能力;但也会造成一些问题但是主从节点之间数据复制造成的阻塞延迟也可能会导致主从不一致的情况,也就是主节点先进行了写操作,但可能因为数据复制造成的阻塞延迟,导致在从节点上进行的读操作获取的数据与主节点不一致读取过期数据:主从复制会将带有过期时间的数据一并复制到从节点中,但是从节点是没有删除数据的能力的,即使是过期数据,所以主节点中的已经删除了过期数据,但是因为主从复制的阻塞延迟问题导致从节点中的过期数据没有删除,此时客户端就会读到一个过期数据    2. 主从配置不一致:造成的问题有比如配置中的maxmemory参数如果配置不一致,比如主节点2Gb,从节点1Gb,那么就可能会导致数据丢失;以及一些其他配置问题    3. 规避全量复制:全量复制的性能开销较大,所以要尽量避免全量复制,在第一次建立主从节点关系式一定会发生全量复制;可以适当减小Redis的maxmemory参数,这样可以使得RDB更快,或者选择在客户端操作低峰期进行,比如深夜从节点中保存的主节点run_id不一致时也一定会发生全量复制(比如主节点的重启);可以通过故障转移来尽量避免,例如Redis Sentinel 与 Redis Cluster 当主从节点的偏移量之差大于命令缓冲区repl_back_buffer中对应数据的偏移差时,也会发生全量复制,也就是上面的部分复制的复制过程中所说的;可以适当增大配置文件中repl-backlog-size即数据缓冲区可尽量避免    4. 规避复制风暴:单主节点导致的复制风暴,即当主节点重启后,要向其所有的从节点都进行一次全量复制,这非常消耗性能;可以更换主从节点的拓扑结构,更换为类似树形的结构,一个主节点只与少量的从节点建立主从关系,而而这些主节点又与其他从节点构成主从关系单主节点机器复制风暴:即如果过一台机器专门用来部署多个主节点,然后其他机器部署从节点,那么一旦主节点机器宕机重启,就会引起所有的主从节点之间的全量复制,造成非常大的性能开销;可以采用多台机器,分散部署主节点,或者使用自动故障转移来将某个从节点变为主节点实现一个高可用
  • [技术干货] Redis两种持久化方式
    对Redis而言,其数据是保存在内存中的,一旦机器宕机,内存中的数据会丢失,因此需要将数据异步持久化到硬盘中保存。这样,即使机器宕机,数据能从硬盘中恢复。常见的数据持久化方式:1.快照:类似拍照记录时光,快照是某时某刻将数据库的数据做拍照记录下其数据信息。如MYSQL的Dump,Redis的RDB模式2.写日志方式:是将数据的操作全部写到日志当中,需要恢复的时候,按照日志记录的操作记录重新再执行一遍。例如MYSQL的Binlog,Redis的AAOF模式、RDB说明:redis默认开启,将redis在内存中保存的数据,以快照的方式持久化到硬盘中保存。触发机制:1.save命令:阻塞方式,需要等redis执行完save后,才能执行其他get、set等操作。同步方式2.bgsave命令:非阻塞,其原理是调用linux 的  fork()函数,创建redis的子进程,子进程进行创建  rdb 文件的操作。异步方式,3.自动方式:在redis.conf文件中配置,如下  save  <指定时间间隔>  <执行指定次数更新操作>  ,save  60  10000 表示 60秒年内有10000次操作会自动生成rdb文件。4.其他方式4.1  执行flushall命令,清空数据,几乎不用4.2  执行shutdown命令,安全关闭redis不丢失数据,几乎用不到。4.3  主从复制,在主从复制的时候,rdb文件作为媒介来关联主节点和从节点的数据一致。RDB优缺点优点:1 适合大规模的数据恢复。2 如果业务对数据完整性和一致性要求不高,RDB是很好的选择。缺点:1 不可控,容易丢失数据:数据的完整性和一致性不高,因为RDB可能在最后一次备份时宕机了。2 耗时耗性能:备份时占用内存,因为Redis 在备份时会独立创建一个子进程,将数据写入到一个临时文件(此时内存中的数据是原来的两倍哦),最后再将临时文件替换之前的备份文件。所以Redis 的持久化和数据的恢复要选择在夜深人静的时候执行是比较合理的。AOF说明: redis默认不开启,采用日志的形式来记录每个写操作,并追加到 .aof 文件中。Redis 重启的会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作生成AOF的三种策略:1. always : 每条命令都会刷新到缓冲区,把缓冲区fsync到硬盘,对硬盘IO压力大,一般sata盘只有几百TPS,如果redis的写入量非常大,那对硬盘的压力也横刀。2. everysec:  每秒把缓冲区fsync 到硬盘,如果出现故障,会丢失1s(默认配置是1秒)的数据。一般使用这种。3. no : 由操作系统来定什么时候fsync到硬盘中。 缺点:不可控 AOF重写:把过期的,没有用的,重复的,可优化的命令简化为很小的aof文件。实际上是redis内存中的数据回溯成aof文件。如下图所示:作用:1.减少硬盘占用量2.加快恢复速度 AOF重写的实现方式1.bgrewriteaof   命令 : 从redis的主进程fork一个子进程生成包含当前redis内存数据的最小命令集、2.AOF重写配置:# 1. aof文件增长率 auto-aof-rewrite-percentage 100# 2. aof文件重写需要的尺寸 auto-aof-rewrite-min-size 64mb自动触发时机:(需要同时满足)当前的aof文件大小   >   aof文件重写需要的尺寸        (aof当前文件大小 -  上次aof的文件大小)/  上次aof文件大小  >  aof文件增长率 AOF优缺点优点:1.数据的完整性和一致性更高缺点:1.因为AOF记录的内容多,文件会越来越大,数据恢复也会越来越慢。2. AOF每秒fsync一次指令硬盘,如果硬盘IO慢,会阻塞父进程;风险是会丢失1秒多的数据;在Rewrite过程中,主进程把指令存到mem-buffer中,最后写盘时会阻塞主进程。关于Redis持久化方式RDB和AOF的缺点原因是redis持久化方式的痛点,缺点比较明显。1、RDB需要定时持久化,风险是可能会丢两次持久之间的数据,量可能很大。2、AOF每秒fsync一次指令硬盘,如果硬盘IO慢,会阻塞父进程;风险是会丢失1秒多的数据;在Rewrite过程中,主进程把指令存到mem-buffer中,最后写盘时会阻塞主进程。3、这两个缺点是个很大的痛点。为了解决这些痛点,GitHub的两位工程师 Bryana Knight 和 Miguel Fernández 日前写了一篇 文章 ,讲述了将持久数据从Redis迁出的经验: http://www.open-open.com/lib/view/open1487736984424.html如何选择RDB和AOF建议全都要。1、对于我们应该选择RDB还是AOF,官方的建议是两个同时使用。这样可以提供更可靠的持久化方案。在redis 4.0 之后,官方提供了混合持久化模式,具体如下持久化文件结构上半段RDB格式,后半段是AOF模式。
  • [技术干货] GaussDB(for Redis)新特性发布:增强版前缀扫描与多租隔离[转载]
    近期,华为云GaussDB(for Redis)缓存数据库再次推出全新版本,携新特性重磅来袭!GaussDB(for Redis)是华为云推出的企业级分布式KV数据库,它完全兼容Redis协议,提供丰富的数据类型,基于云原生存储计算分离架构,在成本、可靠性等方面为企业带来全新价值。 本次GaussDB(for Redis)推出的全新特性,不仅对基础性能和连接管理等进行了大幅优化,同时突破开源Redis短板,实现增强版前缀搜索和集群版多租隔离功能,前缀搜索时延较开源Redis降低千倍,为助力企业业务发展带来了更多可能。关键特性1:增强版前缀扫描,千倍性能提升GaussDB(for Redis)推出的增强版前缀扫描功能,优化了String、Hash、Set、Zset四种数据类型scan的前缀搜索。GaussDB(for Redis)的SCAN、HSCAN、SSCAN、ZSCAN命令在使用方法上与开源Redis完全兼容,但前缀匹配模式的性能更为优秀,从开源的耗时O(N)优化到O(logN + M)(其中N是整体数据量,M是匹配的数据量)。下面根据某客户实际场景,对比GaussDB(for Redis)和开源Redis的性能:数据:500w个key,均为String,范围为“1”~“5000000”, value大小为100B。命令:Scan 0 Match 499999* Count 100。在500w个key中搜索11个key。结果:开源Redis为7.67s ,GaussDB(for Redis)仅为2.92ms,快了2600倍,且开源Redis在返回搜索结果前返回了4.98w+次的空结果,而GaussDB(for Redis)第一次就返回了搜索结果。开源Redis:GaussDB(for Redis):在互联网业务中,诸如批量查找/删除一批相同前缀的key是很常见的业务场景,在上百万的数据量下,开源Redis的秒级时延显然是不可接受的。GaussDB(for Redis)针对这一场景进行了有效优化,将时延降低上千倍至毫秒级,带来了极致的性能体验。关键特性2:多租隔离,集群版业务数据隔离能力GaussDB(for Redis) 提供的多租隔离功能,允许用户为不同的业务创建不同的DB,实现不同业务数据隔离。使用方法上,GaussDB(for Redis)的多租隔离功能与开源Redis单机版本的多DB用法保持完全兼容(开源Redis集群版本不支持多DB)。用户可以通过SELECT DB来切换/新建不同的DB给不同的业务使用,通过FLUSHDB删除一个DB中的全部数据而不影响其他DB,从而高效地实现多租隔离效果。GaussDB(for Redis)多DB实现业务多租隔离GaussDB(for Redis)的多DB核心价值在于:集群版多DB:GaussDB(for Redis)集群版本可支持多DB;开源Redis的“多DB”只能用于单机,不支持集群。大规模多DB:GaussDB(for Redis)单实例支持65536个DB,搞定多业务多租隔离。高扩展性:开源Redis单机扩容到64G已经是极限,更不用说fork导致的容量利用率只有50%。GaussDB(for Redis)吞吐可水平扩展至百万QPS,容量支持12TB,解决了扩展性问题。低成本:GaussDB(for Redis)相比开源Redis,成本可降20%~70%。多租隔离是数据库的必备功能,在实际业务场景中,不同模块共享同一Redis实例是很常见的需求。GaussDB(for Redis)超越开源Redis,支持集群版本下的多DB,依托现有的秒级弹性扩缩容能力,在海量业务压力下仍能为客户提供灵活便捷的业务数据访问控制服务。目前,GaussDB(for Redis)已经凭借出色的产品实力在游戏系统、电商平台、推荐系统、社交媒体、物联网等众多企业级应用场景中发挥出巨大作用,而新推出的增强版前缀扫描与多租隔离两大功能特性,将以更优异的能力使企业在降本的同时实现增效,助力企业高效数字化!连接:https://bbs.huaweicloud.com/blogs/352808
  • [技术干货] GaussDB(for Redis)新特性发布:增强版前缀扫描与多租隔离[转载]
    近期,华为云GaussDB(for Redis)缓存数据库再次推出全新版本,携新特性重磅来袭!GaussDB(for Redis)是华为云推出的企业级分布式KV数据库,它完全兼容Redis协议,提供丰富的数据类型,基于云原生存储计算分离架构,在成本、可靠性等方面为企业带来全新价值。 本次GaussDB(for Redis)推出的全新特性,不仅对基础性能和连接管理等进行了大幅优化,同时突破开源Redis短板,实现增强版前缀搜索和集群版多租隔离功能,前缀搜索时延较开源Redis降低千倍,为助力企业业务发展带来了更多可能。关键特性1:增强版前缀扫描,千倍性能提升GaussDB(for Redis)推出的增强版前缀扫描功能,优化了String、Hash、Set、Zset四种数据类型scan的前缀搜索。GaussDB(for Redis)的SCAN、HSCAN、SSCAN、ZSCAN命令在使用方法上与开源Redis完全兼容,但前缀匹配模式的性能更为优秀,从开源的耗时O(N)优化到O(logN + M)(其中N是整体数据量,M是匹配的数据量)。下面根据某客户实际场景,对比GaussDB(for Redis)和开源Redis的性能:数据:500w个key,均为String,范围为“1”~“5000000”, value大小为100B。命令:Scan 0 Match 499999* Count 100。在500w个key中搜索11个key。结果:开源Redis为7.67s ,GaussDB(for Redis)仅为2.92ms,快了2600倍,且开源Redis在返回搜索结果前返回了4.98w+次的空结果,而GaussDB(for Redis)第一次就返回了搜索结果。开源Redis:GaussDB(for Redis):在互联网业务中,诸如批量查找/删除一批相同前缀的key是很常见的业务场景,在上百万的数据量下,开源Redis的秒级时延显然是不可接受的。GaussDB(for Redis)针对这一场景进行了有效优化,将时延降低上千倍至毫秒级,带来了极致的性能体验。关键特性2:多租隔离,集群版业务数据隔离能力GaussDB(for Redis) 提供的多租隔离功能,允许用户为不同的业务创建不同的DB,实现不同业务数据隔离。使用方法上,GaussDB(for Redis)的多租隔离功能与开源Redis单机版本的多DB用法保持完全兼容(开源Redis集群版本不支持多DB)。用户可以通过SELECT DB来切换/新建不同的DB给不同的业务使用,通过FLUSHDB删除一个DB中的全部数据而不影响其他DB,从而高效地实现多租隔离效果。GaussDB(for Redis)多DB实现业务多租隔离GaussDB(for Redis)的多DB核心价值在于:集群版多DB:GaussDB(for Redis)集群版本可支持多DB;开源Redis的“多DB”只能用于单机,不支持集群。大规模多DB:GaussDB(for Redis)单实例支持65536个DB,搞定多业务多租隔离。高扩展性:开源Redis单机扩容到64G已经是极限,更不用说fork导致的容量利用率只有50%。GaussDB(for Redis)吞吐可水平扩展至百万QPS,容量支持12TB,解决了扩展性问题。低成本:GaussDB(for Redis)相比开源Redis,成本可降20%~70%。多租隔离是数据库的必备功能,在实际业务场景中,不同模块共享同一Redis实例是很常见的需求。GaussDB(for Redis)超越开源Redis,支持集群版本下的多DB,依托现有的秒级弹性扩缩容能力,在海量业务压力下仍能为客户提供灵活便捷的业务数据访问控制服务。目前,GaussDB(for Redis)已经凭借出色的产品实力在游戏系统、电商平台、推荐系统、社交媒体、物联网等众多企业级应用场景中发挥出巨大作用,而新推出的增强版前缀扫描与多租隔离两大功能特性,将以更优异的能力使企业在降本的同时实现增效,助力企业高效数字化!连接:https://bbs.huaweicloud.com/blogs/352808
  • [问题求助] GaussDB(for Redis) 是闭源的吗 ?
    个人无法免费试用,使用?
  • [技术干货] gaussdb for redis 体验[转载]
    创建1、首先 是找到使用页面 https://activity.huaweicloud.com/free_test/index.html2、全新注册用户,自行解决。(ps:需要邮箱认证,我的邮箱之前 注册过无法重复注册,原账号找回密码需要很多注册信息。。。,最后用guge的邮箱。。)3、点击0元试用 自动跳转到实例控制台,这里体验很流畅。4、点击实例列表名称进入 实例详情,一个月31天。这里开个玩笑,我买12个月 算31x12 不。。。好了进入主页面,咱们开始 详细的了解 华为云的redis实例详情如何了。二  详情页面详解1、基本信息采用arm架构,维护时间窗口默认帮用户设置了。这也是行业惯例。2、拓扑信息基本的主从架构,实例id 也是默认映射主节点的地址,一会可以连接实例看下支持的命令 和主从连接信息。3、连接信息连接信息访问方式免密访问连接地址redis-87f5d492-8b12-4d6f-9d6e-2984bec7e1af.cn-east-3.dcs.myhuaweicloud.com:6379只读地址redis-87f5d492-8b12-4d6f-9d6e-2984bec7e1af-readonly.cn-east-3.dcs.myhuaweicloud.com:6379IP地址172.31.201.38:6379公网访问查看文档我通过电脑自带的redis-cli 无法连接地址【 redis-87f5d492-8b12-4d6f-9d6e-2984bec7e1af.cn-east-3.dcs.myhuaweicloud.com 】,我以为是白名单的问题。然后在实例配置白名单配置里,设置自己的公网地址。(浏览器输入ip.cn,找到自己的公网地址),然后添加我的公网ip地址后 依然不可以访问。仔细 一看如下文字所示,也就是 说这里的配置只是vpc内部的连接白名单。所以,url连接不是用来公网访问的,而是用来内部dns定向访问的。比如不同的子网划分,不同的地址映射吧,这样可以无需修改应用的ip地址配置。您还没有添加任何白名单,所有与VPC互通的IP地址均可访问实例。若需要指定的IP地址才能访问,请将这些IP地址加入白名单。那么如何公网访问呢?连接如下,需要自己开一个云主机用nginx的tcp代理来 映射,6379端口,操作指南详见连接    使用Nginx实现公网访问Redis 4.0/5.0的单机/主备/Proxy集群实例_分布式缓存服务 DCS_最佳实践_华为云 (huaweicloud.com)然后返回体验页面 https://activity.huaweicloud.com/free_test/index.html。 这里开始白嫖一个云主机,发现云主机被体验光了。好吧,下一篇博客在细说 通过云主机的redis-cli连接。这里先小结下体验感受:由于我使用过谷歌 和 redislab的kv服务,国内阿里云的kv服务,体验这里给在国内比较给中上评价吧,如果在国际上就比较差了,连接地址和 只读地址 都是无法通过公网连接的。原因如下:redislabs的使用企业版 url连接自动连上,他是自动化的dbaas服务部署是通过调用aws的接口 创建小实例,并且是可以直接公网访问的。阿里的实例是可以自动开公网访问,并且做到了一个url地址既可以公网也可以内网,并且就在实例的详情主页里实例【公网访问】开通一点击就OK,设置完白名单可以很方便通过url了解访问。4、web console体验直接在概览页面右上角点击 【连接Redis】,跳转到 web的console页面。页面很简洁。页面有db信息,并且自动auth成功,推出当前实例定跳转到 实例列表页面。进行简单操作 set hw hwc,info all。回显如下信息set hw hwcOKinfo all# Server redis_version:5.0.14 patch_version:5.0.14.1 redis_git_sha1:00000000 redis_git_dirty:0 redis_build_id:0 redis_mode:standalone os:Linux arch_bits:64 multiplexing_api:epoll atomicvar_api:atomic-builtin gcc_version:0.0.0 process_id:1 run_id:a7b30d214bf934f5a3254a6596f0bd83dd5c850d tcp_port:2407 uptime_in_seconds:2539 uptime_in_days:0 hz:10 configured_hz:10 lru_clock:8266221 executable:redis-server config_file:redis.conf instance_id:87f5d492-8b12-4d6f-9d6e-2984bec7e1af # Clients connected_clients:7 client_recent_max_input_buffer:2 client_recent_max_output_buffer:0 blocked_clients:0 rx_controlled_clients:0 total_real_rx_controlled:0 total_tx_controlled:0 total_rx_controlled:0 proxy_header_error:0 # Memory used_memory:2341624 used_memory_human:2.23M used_memory_rss:9961472 used_memory_rss_human:9.50M used_memory_peak:2464272 used_memory_peak_human:2.35M used_memory_peak_perc:95.02% used_memory_overhead:2300662 used_memory_startup:1082800 used_memory_dataset:40962 used_memory_dataset_perc:3.25% allocator_allocated:2725304 allocator_active:3088384 allocator_resident:19886080 total_system_memory:1081361883136 total_system_memory_human:1007.10G used_memory_lua:37888 used_memory_lua_human:37.00K used_memory_scripts:0 used_memory_scripts_human:0B number_of_cached_scripts:0 maxmemory:268435456 maxmemory_human:256.00M maxmemory_policy:volatile-lru allocator_frag_ratio:1.13 allocator_frag_bytes:363080 allocator_rss_ratio:6.44 allocator_rss_bytes:16797696 rss_overhead_ratio:0.50 rss_overhead_bytes:-9924608 mem_fragmentation_ratio:4.29 mem_fragmentation_bytes:7641792 mem_not_counted_for_evict:106 mem_replication_backlog:1048576 mem_clients_slaves:17042 mem_clients_normal:152066 mem_aof_buffer:106 mem_allocator:jemalloc-5.1.0 active_defrag_running:0 lazyfree_pending_objects:0 # Persistence loading:0 rdb_changes_since_last_save:1 rdb_bgsave_in_progress:0 rdb_last_save_time:1652430851 rdb_last_bgsave_status:ok rdb_last_bgsave_time_sec:0 rdb_current_bgsave_time_sec:-1 rdb_last_cow_size:299008 aof_enabled:1 aof_rewrite_in_progress:0 aof_rewrite_scheduled:0 aof_last_rewrite_time_sec:-1 aof_current_rewrite_time_sec:-1 aof_last_bgrewrite_status:ok aof_last_write_status:ok aof_last_cow_size:0 aof_current_size:53 max_aof_size:1342177280 aof_base_size:0 aof_pending_rewrite:0 aof_buffer_length:0 aof_rewrite_buffer_length:0 aof_pending_bio_fsync:0 total_aof_write_error:0 aof_delayed_fsync:0 # Stats total_connections_received:717 total_commands_processed:15038 instantaneous_ops_per_sec:5 total_net_input_bytes:889498 total_net_output_bytes:8147140 instantaneous_input_kbps:0.41 instantaneous_output_kbps:1.32 rejected_connections:0 sync_full:1 sync_partial_ok:0 sync_partial_err:0 expired_keys:0 expired_stale_perc:0.00 expired_time_cap_reached_count:0 evicted_keys:0 keyspace_hits:0 keyspace_misses:0 pubsub_channels:1 pubsub_patterns:0 latest_fork_usec:432 migrate_cached_sockets:0 slave_expires_tracked_keys:0 active_defrag_hits:0 active_defrag_misses:0 active_defrag_key_hits:0 active_defrag_key_misses:0 # Replication role:master connected_slaves:1 slave0:ip=192.168.30.31,port=3184,state=online,offset=663452,lag=0 master_replid:c07fd7bb03ad6d1628cde2f017a34d22ea8b36d0 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:663629 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:663629 # CPU used_cpu_sys:1.036002 used_cpu_user:2.197352 used_cpu_sys_children:0.000000 used_cpu_user_children:0.002273 # Commandstats cmdstat_dcs.getBandwidth:calls=2,usec=16,usec_per_call=8.00 cmdstat_publish:calls=3722,usec=21106,usec_per_call=5.67 cmdstat_ping:calls=7298,usec=9439,usec_per_call=1.29 cmdstat_replconf:calls=2536,usec=4751,usec_per_call=1.87 cmdstat_set:calls=1,usec=10,usec_per_call=10.00 cmdstat_command:calls=4,usec=2607,usec_per_call=651.75 cmdstat_client:calls=6,usec=10,usec_per_call=1.67 cmdstat_subscribe:calls=3,usec=11,usec_per_call=3.67 cmdstat_info:calls=1399,usec=109527,usec_per_call=78.29 cmdstat_config:calls=23,usec=428,usec_per_call=18.61 cmdstat_slowlog:calls=43,usec=227,usec_per_call=5.28 cmdstat_psync:calls=1,usec=595,usec_per_call=595.00 # Cluster cluster_enabled:0 # Keyspace db0:keys=1,expires=0,avg_ttl=0在输入 config get * 看看配置信息config get *dbfilename redis.rdb requirepass masterauth cluster-announce-ip unixsocket /opt/redis/redis.sock logfile /var/log/redis.log pidfile /opt/redis/redis.pid slave-announce-ip replica-announce-ip maxmemory 268435456 max-aof-memory-multiplier 5 max-aof-size 1342177280 proto-max-bulk-len 536870912 client-query-buffer-limit 1073741824 maxmemory-samples 5 lfu-log-factor 10 lfu-decay-time 1 timeout 0 active-defrag-threshold-lower 10 active-defrag-threshold-upper 100 active-defrag-ignore-bytes 104857600 active-defrag-cycle-min 5 active-defrag-cycle-max 75 active-defrag-max-scan-fields 1000 auto-aof-rewrite-percentage 0 auto-aof-rewrite-min-size 67108864 hash-max-ziplist-entries 512 hash-max-ziplist-value 64 stream-node-max-bytes 4096 stream-node-max-entries 100 list-max-ziplist-size -2 list-compress-depth 0 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 lua-time-limit 5000 slowlog-log-slower-than 10000 latency-monitor-threshold 0 slowlog-max-len 128 port 2407 cluster-announce-port 0 cluster-announce-bus-port 0 tcp-backlog 10000 databases 256 repl-ping-slave-period 10 repl-ping-replica-period 10 repl-timeout 60 repl-backlog-size 1048576 repl-backlog-ttl 3600 maxclients 10010 watchdog-period 0 slave-priority 100 replica-priority 100 slave-announce-port 0 replica-announce-port 0 min-slaves-to-write 0 min-replicas-to-write 0 min-slaves-max-lag 10 min-replicas-max-lag 10 hz 10 cluster-node-timeout 15000 cluster-migration-barrier 1 cluster-slave-validity-factor 10 cluster-replica-validity-factor 10 repl-diskless-sync-delay 5 tcp-keepalive 30 incremental-eviction-num 65535 active-expire-num 20 active-expire-cycle-slow-time-perc 25 cluster-require-full-coverage yes cluster-slave-no-failover no cluster-replica-no-failover no no-appendfsync-on-rewrite yes slave-serve-stale-data yes replica-serve-stale-data yes slave-read-only yes replica-read-only yes slave-ignore-maxmemory yes replica-ignore-maxmemory yes stop-writes-on-bgsave-error yes daemonize no rdbcompression no rdbchecksum yes activerehashing yes activedefrag no protected-mode no repl-disable-tcp-nodelay no repl-diskless-sync no aof-rewrite-incremental-fsync yes rdb-save-incremental-fsync yes aof-load-truncated yes aof-use-rdb-preamble yes lazyfree-lazy-eviction yes lazyfree-lazy-expire yes lazyfree-lazy-server-del yes slave-lazy-flush yes replica-lazy-flush yes dynamic-hz yes master-read-only no vpc-endpoint-proxy-header no tenant-sync no enable-write-protection no maxmemory-policy volatile-lru loglevel notice supervised no appendfsync no syslog-facility local0 appendonly yes dir /opt/redis save client-output-buffer-limit normal 0 0 0 slave 26843545 26843545 60 pubsub 33554432 8388608 60 unixsocketperm 600 slaveof notify-keyspace-events xE bind 192.168.36.137使用小结:由于带了控制台功能,那么开云主机的需要就不那么紧要了,客户几乎可以执行所有的可配置的 命令。命令支持的也很全面原文连接:https://bbs.huaweicloud.com/blogs/352815
  • [技术干货] 暴露数据库数量创新高,中美占比最多,Redis 排第一
    BleepingComputer 网站消息,威胁情报和研究公司 Group-IB 共享的一份报告中显示,公开暴露在互联网上的数据库数量近期有所增加 ,从 2021 年的 308000 个持续增长,截至 2022 年第一季度,暴露的数据库峰值数量已达 91200 个,创造了历史记录。在大多数情况下,数据库被公开至网络是由于配置错误的原因造成,黑客常常使用可从开放网络访问的搜索引擎索引系统来寻找这些数据库,以窃取内容或进行金融勒索。Group-IB 使用其攻击面管理解决方案扫描整个 IPv4 空间来查找与访问数据库相关的开放端口,并检查索引或表是否可用。Group-IB 的攻击面管理产品负责人 Tim Bobak 告诉 BleepingComputer,该公司的解决方案仅限于检查数据库是否暴露,不会收集或分析数据库内容。以这种方式收集的遥测数据不会显示开放数据库是否容易受到安全漏洞的影响,或者未经授权的一方是否在暴露在网络上时访问了它们。中美数据库占比最多Group-IB 发现,大多数暴露的数据库都位于美国和中国服务器,德国、法国和印度也占很多。在暴露实例中使用的数据库管理系统中,今年一季度的暴露数量最多的是 Redis,是排名第二的 MongoDB 的近两倍, MySQL 则占比较少。目前这些管理系统已采取措施,在管理员将实例配置为无需密码即可公开访问时会对管理员进行提醒,但目前问题仍然存在。专攻数据库安全的安全研究员 Bob Diachenko 告诉 Bleeping Computer:目前一些数据库供应商引入的 dbms (数据库管理系统)越复杂,反而越容易出现配置错误,从而在无意中暴露数据。他认为,数据库的目的不仅是存储数据,而且还允许以即时和便捷的方式共享这些数据,并由其他团队成员对其进行分析,如今,越来越多的人参与到数据库管理过程中,为了试图简化和加快访问速度,甚至对登录措施进行了省略。同时,管理员平均需要 170 天的时间来发现错误配置并修复暴露问题,这足以让恶意行为者找到实例并窃取其内容。预防措施Group-IB 的 Bobak 指出,大多数困扰数据库安全的问题都可以轻松预防。如果管理员在设置和维护数据库时遵循特定关键措施,则可以确保数据库安全。总结为以下几点:如无必要,确保数据库不公开;使数据库管理系统保持最新版本,以减少可利用的缺陷;使用强用户身份验证;为所有存储的信息部署强大的数据加密协议;使用采用数据包过滤器、数据包检查和代理的数据库和 Web 应用程序防火墙;使用实时数据库监控;避免使用将数据库暴露给恶意扫描的默认网络端口;尽可能遵循服务器分段做法;以加密形式对数据进行离线备份。
总条数:384 到第
上滑加载中