云服务器内容精选

  • 事务介绍 基本概念: 事务将应用程序的多个读、写操作捆绑在一起成为一个逻辑操作单元,是一个执行的整体,整个事务要么成功,要么失败。在一个连接中,当客户端执行multi命令后,redis开始将后续收到的命令缓存在队列中,当客户端发送exec命令时,redis按照顺序依次执行队列中的所有命令。如果有一个命令执行失败则事务回滚,所有命令要么全部成功,要么全部失败。 表1 相关命令 命令 含义 WATCH 用于监视一个或多个key,如果事务执行之前该key被改动,则事务被打断。 UNWATCH 用于取消watch命令对所有key的监视。 MULTI 用于标识一个事务块的开始。 EXEC 用于执行事务块内的所有命令。 DISCARD 用于取消事务块,放弃执行事务块内的所有命令。 注意事项: 使用proxy集群时,为保证事务执行的原子性,需确保事务中的所有key拥有相同的hashtag。若不使用hashtag,事务会被拆分成普通命令执行,则无法保证事务的原子性。 由于整个事务的执行是原子性的,要么全部成功要么全部失败,因此,在编写事务时,需要注意命令的合法性。 由于事务中的命令是按照顺序执行的,所以,在编写事务时,需要注意命令的先后顺序。 使用事务时应遵循轻量化原则,避免单次事务中打包过多命令或复杂度过高的命令,执行的事务中包含命令过多会引起请求阻塞或实例状态异常。
  • Go-redis package main import ( "context" "fmt" "time" "github.com/redis/go-redis/v9" ) var ctx = context.Background() func main() { client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password set DB: 0, // use default DB MaxRetries: 3, // set max retry times MinRetryBackoff: time.Duration(1) * time.Second, // set retry interval MaxRetryBackoff: time.Duration(2) * time.Second, // set retry interval }) // Execute command err := client.Set(ctx, "key", "value", 0).Err() if err != nil { panic(err) } // Test pong, err := client.Ping(ctx).Result() if err != nil { fmt.Println("Failed:", err) return } fmt.Println("Success:", pong) }
  • Redis-py import redis from redis.retry import Retry from redis.exceptions import ConnectionError from redis.backoff import ExponentialBackoff from redis.client import Redis from redis.exceptions import ( BusyLoadingError, ConnectionError, TimeoutError ) # Run 3 retries with exponential backoff strategy retry_strategy = Retry(ExponentialBackoff(), 3) # Redis client with retries client = redis.Redis( host = 'localhost', port = 6379, retry = retry_strategy, # Retry on custom errors retry_on_error = [BusyLoadingError, ConnectionError, TimeoutError], # Retry on timeout retry_on_timeout = True ) try: client.ping() print("Connected to Redis!") except ConnectionError: print("Failed to connect to Redis after retries.") try: client.set('key', 'value') print("Set key and value success!") except ConnectionError: print("Failed to set key after retries.")
  • 注意事项 该功能需升级到特定版本,您可以提工单联系客服咨询实例版本是否支持该功能。 由于APPEND命令对顺序有要求,因此整个流程要避免出现APPEND乱序(并发APPEND的场景)。 可以使⽤PIPELINE模式加速,PIPELINE本⾝也是保证执⾏顺序的,因此不会有乱序的问题。 拆分的粒度可以根据实际情况选择,拆的越细,产⽣的时延⽑刺就越⼩,但是初始化时间就越⻓,通常建议256KB-1MB左右的值。
  • Pipeline 大小选择及注意事项 虽然使用 Pipeline 可以节省网络IO开销,但 Pipeline 并不是越大越好;使用 Pipeline 对程序性能的提升是有上限的,随着 Pipeline 逐渐增加,提高 Pipeline 的收益逐渐降低;如果一次组装的 Pipeline 数据量过大,一方面会导致客户端等待时间增加,另一方面,如果大的 Pipeline 导致 socket buffer 写满,可能会带来网络阻塞,反而引起性能下降; 根据经验,30 - 100 大小的 Pipeline 就已经可以充分发挥数据库的性能,具体最佳值与实际业务有关,建议以实际测试为准。 其它注意事项: Pipeline 不保证原子性,服务端在处理批量命令时,解析出多个单命令并按顺序执行,各个命令相互独立,服务端有可能在该过程中执行其他客户端的命令。某个命令执行失败不会影响其他命令的执行,如需原子性,需要使用事务或lua实现。 单次 Pipeline 的大小需要适当,大Pipeline可能会有OOM风险,也可能会造成网络阻塞;因为Redis 必须在处理完所有命令前,先缓存起所有命令的处理结果。这样会有内存的消耗,过大Pipeline造成内存上涨甚至OOM;对于单个命令数据长度较大的场景,需要适当的减小 Pipeline。 对于时延敏感的场景,不建议使用大 Pipeline,需要结合业务场景选择合适的 Pipeline大小。
  • Pipeline 简介 Redis 是一个请求/响应模型的服务,通常执行一个命令的流程为: 图1 Redis 命令执行流程 客户端发送命令到 Redis 服务器。 Redis 服务器收到命令,排队等待处理。 Redis 服务器执行命令。 Redis 服务器返回结果给客户端。 上述4个步骤中,步骤1和4是IO操作,速度慢并且受网络状况影响,很容易成为瓶颈点。 为了减小网络开销,充分发挥 Redis 高性能的优势,可以使用 Pipeline 流水线执行命令。Pipeline 机制通过将一组 Redis 命令进行组装,一次发送多个命令,并在执行完成后一次性返回结果集,可以减少网络传输带来的开销,流程如下图所示: 图2 使用 Pipeline 访问Redis 上图中的 Pipeline 将3条命令封装成一组,只需要进行一次网络IO就完成了3条命令的执行。 除了网络层面的开销,使用 Pipeline 还可以减少客户端/服务器的 read()/write() 调用,提高程序的执行效率。
  • Lua脚本中禁止执行的命令 Hash:hscan List:blpop、brpop、brpoplpush Set:sscan Sorted Set:bzpopmax、bzpopmin、zscan Stream:xread、xreadgroup Generic:rename、renamenx、restore、scan、client、command、config、dbsize、flushall、flushdb、info、keys Lua:eval、evalsha、script Pub/Sub:psubscribe、publish、punsubscribe、subscribe、unsubscribe Transactions:discard、exec、multi、unwatch、watch
  • 与开源Redis Lua的区别 EVAL/EVALSHA命令 命令格式: EVAL script numkeys key [key …] arg [arg …] EVALSHA sha1 numkeys key [key …] arg [arg …] 上述命令的语法与操作与开源Redis一致。用户需自己保证将脚本中使用到的Redis key显式的通过key参数传入,而不是直接在脚本中编码。 若使用集群版实例,如果带有多个key参数,则要求所有的key参数必须拥有相同的hash tag。 如果不遵循上述约束,则在Lua中执行涉及这些key的Redis操作时,可能会返回错误信息,甚至可能导致数据的一致性被破坏。 SCRIPT命令 SCRIPT命令包含了一组管理Lua脚本的子命令,具体可以通过SCRIPT HELP命令查询具体的操作。 SCRIPT大部分命令都与开源Redis兼容,其中需要特别说明的命令如下: SCRIPT KILL GeminiDB Redis是多线程执行的环境,允许同时执行多个Lua脚本,执行SCRIPT KILL,会终止所有正在运行的Lua脚本。 为了方便使用,GeminiDB Redis扩展了SCRIPT KILL命令,用户可以通过‘SCRIPT KILL SHA1’来终止指定哈希值的脚本。若同一时间存在多个节点在执行哈希值相同的脚本,那么这些脚本都会被终止。 另外,由于用户无法设置Lua超时时间(config set lua-time-limit),因此在任意时刻执行SCRIPT KILL都能直接终止脚本,而不是等待脚本超时后才终止。 SCRIPT DEBUG 目前GeminiDB Redis不支持DEBUG功能,所以该命令执行无效。 SCRIPT GET GeminiDB Redis新增命令, 可用来查询通过 "SCRIPT LOAD" 保存到数据库中的脚本内容。 语法为:SCRIPT GET SHA1。 Lua脚本中执行Redis命令 与开源Redis一致,GeminiDB Redis的Lua环境中也提供了一个全局的“redis”表,用于提供各类和Redis Server交互的函数。 如表1为GeminiDB Redis目前支持和不支持的操作列表。 表1 函数列表 支持的操作 不支持的操作 redis.call() redis.pcall() redis.sha1hex() redis.error_reply() redis.status_reply() redis.log() redis. LOG _DEBUG redis.LOG_VERBOSE redis.LOG_NOTICE redis.LOG_WARNING redis.replicate_commands() redis.set_repl() redis.REPL_NONE redis.REPL_AOF redis.REPL_SLAVE redis.REPL_REPLICA redis.REPL_ALL redis.breakpoint() redis.debug() Lua执行环境限制 开源Redis对Lua脚本的执行有一定的限制,比如限制脚本操作全局变量,限制随机函数的结果,限定能够使用的系统库和第三方库等。 GeminiDB Redis也继承了绝大多数的限制,但是针对如下情况,GeminiDB Redis与开源Redis存在差异: Write Dirty 开源Redis规定,如果某个脚本已经执行了写操作,那么就不能被SCRIPT KILL停止执行,必须使用SHUTDOWN NOSAVE来直接关闭Redis Server。 GeminiDB Redis不支持执行SHUTDOWN命令,因此这条限制不会被执行,用户仍然可以通过SCRIPT KILL来停止脚本的执行。 Random Dirty 由于主从复制的原因,开源Redis规定,若脚本执行了带有随机性质的命令(Time, randomkey),则不允许再执行写语义的命令。 例如,如下Lua脚本: local t = redis.call("time") return redis.call("set", "time", t[1]); 当该脚本的执行传递到从节点时,Time命令获取到的时间一定晚于主节点,因此从节点执行的Set命令的值就会和主节点产生冲突。开源Redis引入了replicate_commands来允许用户决定这种场景下的行为模式。 对于GeminiDB Redis来说,由于没有主从的概念,数据在逻辑上只有一份,因此也就不存在该限制。
  • 参数说明 Jedis连接就是连接池中JedisPool管理的资源,JedisPool保证资源在一个可控范围内,并且保障线程安全。使用合理的GenericObjectPoolConfig配置能够提升Redis的服务性能,降低资源开销。下将对一些重要参数进行说明,并提供设置建议。 表1 Jedis常用参数配置说明 Jedis参数 参数说明 默认值 建议值 maxTotal 当前资源池可并发的最大连接数,单位:个。 Redis连接数要根据具体的业务量进行设置,连接数太大浪费资源,过小无法获取连接,影响业务。 8 客户端节点数*maxTotal不能超过Redis的最大连接数。 假设一个连接的QPS大约是1s/1ms = 1000,而业务期望的单个Redis的QPS是50000,那么理论上需要的资源池大小(即MaxTotal)是50000 / 1000 = 50。 maxIdle 资源池中最大的空闲连接数,单位:个。 达到后资源池会开始回收空闲连接,直到空闲连接数达到minIdle个数。主要避免空连接占用,资源浪费。 8 maxIdle实际上才是业务需要的最大连接数,maxTotal 是为了给出余量,所以maxIdle不要设置得过小,否则会有new Jedis(新连接)开销。 minIdle 资源池中保持最小的空闲可用连接数,单位:个 这部分连接数不会被回收,可防止流量增量时,连接创建不及时。 0 10~20 maxWaitMillis 资源池连接用尽后,调用者的最大等待时间,单位:毫秒。 -1 建议设置一个合理的超时时间,避免出现当连接池用尽后,应用阻塞不响应的情况。 testWhileIdle 是否在空闲资源监测时通过PING命令监测连接有效性,无效连接将被销毁。 false true testOnBorrow 每次向资源池获取连接时是否做连接有效性检测(发送PING请求),无效连接会被释放。 false 建议使用默认值。设为true相当于在每个命令执行完前先发一个PING命令,对高并发请求应用的性能有影响。对于业务可用性要求比较高的场景,可以设为true,可以保证连接有效的。 testOnReturn 每次向连接池归还连接时是否做连接有效性检测(发送PING请求),无效连接会被释放。 false 建议使用默认值。设为true相当于在每个命令执行完后再发一个PING命令,对高并发请求应用的性能有影响。 timeout Jedis的socket timeout值,单位:毫秒。 2000 200~1000
  • 复杂命令、选项详细介绍 EXHSET 表2 EXHSET命令介绍 类别 说明 语法 EXHSET key field value [EX time] [EXAT time] [PX time] [PXAT time] [NX | XX] [VER | ABS version] [KEEPTTL] 命令描述 向Key指定的exHash中插入一个field。如果exHash不存在则自动创建一个,如果field已经存在则覆盖其值。 为Key的field设置了超时时间后,再次执行该命令时如果没有设置超时时间,该field将被设置为永不过期。 选项 Key:exHash的key,用于指定作为命令调用对象的exHash。 field:exHash中的一个元素,一个exHash key可以有多个field。 value:field对应的值,一个field只能有一个value。 EX:指定field的相对过期时间,单位为秒,为0表示马上过期,不传此参数表示不过期。 EXAT:指定field的绝对过期时间,单位为秒,为0表示马上过期,不传此参数表示不过期。 PX:指定field的相对过期时间,单位为毫秒,为0表示马上过期,不传此参数表示不过期。 PXAT:指定field的绝对过期时间,单位为毫秒 ,为0表示马上过期,不传此参数表示不过期。 NX:只在field不存在时插入。 XX:只在field存在时插入。 VER:版本号。如果field存在,和当前版本号做比较:如果相等,继续操作,且版本号加1。如果不相等,返回异常。如果field不存在或者field当前版本为0,忽略传入的版本号并继续操作,成功后版本号变为1。 GT:比当前更大的版本号(Greater Than),设置的版本号如果比当前的版本号小,则返回失败。 ABS:绝对版本号,不论field是否存在,可以在插入field时设置为本参数所指定的版本号。 KEEPTTL:在不指定EX、EXAT、PX或PXAT选项时,使用KEEPTTL选项会保留field当前的过期设置。 返回值 新建field并成功为它设置值:1。 field已经存在,成功覆盖旧值:0。 指定了XX且field不存在:-1。 指定了NX且field已经存在:-1。 指定了VER且版本和当前版本不匹配:"ERR update version is stale"。 其它情况返回相应的异常信息。 示例 field过期示例: field支持version示例: EXHINCRBY 表3 EXHINCRBY命令介绍 类别 说明 语法 EXHINCRBY key field num [EX time] [EXAT time] [PX time] [PXAT time] [VER | ABS version] [MIN minval] [MAX maxval] [KEEPTTL] 命令描述 将Key指定的TairHash中一个field的value增加num,num为一个整数。如果TairHash不存在则自动新创建一个,如果指定的field不存在,则在加之前插入该field并将其值设置为0。 为Key的field设置了超时时间后,再次执行该命令时如果没有设置超时时间,该field将被设置为永不过期。 选项 Key:exHash的key,用于指定作为命令调用对象的exHash。 field:exHash中的一个元素,一个exHash key可以有多个field。 num:需要为field的value增加的整数值。 EX:指定field的相对过期时间,单位为秒,为0表示马上过期,不传此参数表示不过期。 EXAT:指定field的绝对过期时间,单位为秒,为0表示马上过期,不传此参数表示不过期。 PX:指定field的相对过期时间,单位为毫秒,为0表示马上过期,不传此参数表示不过期。 PXAT:指定field的绝对过期时间,单位为毫秒 ,为0表示马上过期,不传此参数表示不过期。 VER:版本号。如果field存在,和当前版本号做比较:如果相等,继续操作,且版本号加1。如果不相等,返回异常。如果field不存在或者field当前版本为0,忽略传入的版本号并继续操作,成功后版本号变为1。 GT:比当前更大的版本号(Greater Than),设置的版本号如果比当前的版本号小,则返回失败。 ABS:绝对版本号,不论field是否存在,可以在插入field时设置为本参数所指定的版本号。 KEEPTTL:在不指定EX、EXAT、PX或PXAT选项时,使用KEEPTTL选项会保留field当前的过期设置。 MIN:value的最小值,小于该值则提示异常。 MAX:value的最大值,大于该值则提示异常。 返回值 成功:与num相加后value的值。 其它情况返回异常。 示例 支持校验设置的最大值最小值范围示例: exHash命令最佳实践请参考广告频控业务exHash方案。