关于redis:redis学习之集群

每个节点都会保留集群的数据信息,具体对象是clusterNode,这个对象里记录了每个节点创立工夫、节点名、节点标识、节点IP、节点端口、负责的槽点等。 typedef struct clusterNode{ //创立工夫 mstime_t ctime; //节点名 char name[REDIS_CLUSTER_NAMELEN]; //节点标识,能够示意节点主从角色及节点高低线状态 int flags; //节点配置,用于故障转移 uint64_t configEpoch; //节点ip地址 char ip[REDIS_IP_STR_LEN]; //节点端口 int port; //节点相干信息 clusterLink *link; //槽位 unsigned char slots[16384/8]; int numslots;}clusterNode;在集群中执行命令 客户端向节点发送命令时,节点会依据命令里的key先进行槽位的查看: def CLUSTER_KEYSLOT(key): //计算槽位 slot = slot_number(key) //返回计算的槽位 reply_client(slot)def slot_number(key): return CRC16(key) & 16383这里的CRC16用于计算key的CRC_16校验和(可参考CRC 校验的原理及功能),& 16383用于计算0到16383之间的整数(也就是槽位),计算出槽位后,节点会查看本人在clusterState.slots数组中的值,发现是本人负责的槽位后则执行客户端命令,如果发现不是本人负责解决的槽位则返回‘MOVED’谬误,指引客户端正确节点。 故障检测 集群中的每个节点都会定期向其它节点发送PING音讯,以此来检测对方是否在线,如果某节点没在规定工夫内响应PONG音讯,那么发送检测信息的节点会将对方标记为疑似下线(PFAIL)状态并记录在clusterNode的flag里。一旦半数以上的节点将某个节点都标记为了疑似下线状态,那其它节点会将这个节点由疑似下线标记为下线(FAIL)。 故障转移 当一个从节点发现正在复制的主节点是下线状态后,从节点会进行故障转移: 在之前主节点的所有从节点里选举出新的主节点。新的主节点会撤销所有对收己下线主节点的槽指派,将这些槽全副指派给本人。新的主节点向集群播送一条PONG音讯,让其它从节点晓得本人已成了主节点。新的主节点开始接管和本人负责解决的槽无关的命令申请,实现故障转移。选举主节点 当某个主节点呈现故障下线的时候,等提早一段时间后(上面进行阐明),它上面的从节点会向集群里播送一条要求其它主节点进行投票的音讯。在同一轮投票中,每个主节点都有一次投票的机会,在它收到投票要求且本人还没进行投票时,它就会发动一次投票。当一个从节点收集到大于等于2N+1的投票时,那这个从节点就成为了新的主节点;如果一轮投票里未能产生过半的投票则会进入下一轮的投票,直到主节点选举出。为什么要进行一段时间的提早以及怎么做到提早呢?节点之间相互进行通信是会一个先后,某个节点呈现了故障下线并不是所有节点都会在同一时间晓得,假如某个主节点下线了它上面的一个从节点马上发动投票,其它主节点可能并不知道这个主节点已下线而不进行投票。同时进行一个提早还能够免得所有从节点同时发动投票而导致平票。做到提早是通过上面公式来的: DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms其中的SLAVE_RANK指的是此slave曾经从master复制数据的总量的rank。rank越小代表已复制的数据越新。一般来说,持有最新数据的slave将会首先发动选举。

October 1, 2021 · 1 min · jiezi

关于redis:redis5-主从同步哨兵高可用

环境10.132.128.23 master 6379 10.132.128.24 slave 6379 6380master redis install10.132.128.23 master:6379 sentinel:26379[redis@p0-tkhihec-redis3-cache01 redis]$ pwd/home/redis/redis[redis@p0-tkhihec-redis3-cache01 redis]$ lsadmin bin conf data init.d log logs[redis@p0-tkhihec-redis3-cache01 redis]$ cat conf/redis_6379.confdaemonize yesbind 0.0.0.0pidfile "/home/redis/redis/logs/redis_6379.pid"port 6379tcp-backlog 511timeout 300tcp-keepalive 60loglevel warninglogfile "/home/redis/redis/logs/redis_6379.log"databases 16stop-writes-on-bgsave-error yesrdbcompression yesrdbchecksum yesdbfilename "dump_6379.rdb"dir "/home/redis/redis-5.0.5/data"replica-serve-stale-data yesreplica-read-only yesrepl-diskless-sync norepl-diskless-sync-delay 5repl-disable-tcp-nodelay noreplica-priority 100maxclients 10000maxmemory 3gbmaxmemory-policy volatile-lrumaxmemory-samples 3appendonly yesappendfilename "appendonly_6379.aof"appendfsync everysecno-appendfsync-on-rewrite noauto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mbaof-load-truncated yeslua-time-limit 5000slowlog-log-slower-than 10000slowlog-max-len 1024latency-monitor-threshold 0notify-keyspace-events ""hash-max-ziplist-entries 512hash-max-ziplist-value 64list-max-ziplist-entries 512list-max-ziplist-value 64set-max-intset-entries 512zset-max-ziplist-entries 128zset-max-ziplist-value 64hll-sparse-max-bytes 3000activerehashing yesclient-output-buffer-limit normal 0 0 0client-output-buffer-limit replica 256mb 64mb 60client-output-buffer-limit pubsub 32mb 8mb 60hz 10aof-rewrite-incremental-fsync yesprotected-mode norequirepass "Redis_xxxx"masterauth "Redis_xxxx"#rename-command FLUSHALL ''#rename-command CONFIG ''#rename-command EVAL ''# Generated by CONFIG REWRITEreplicaof 10.132.128.24 6380[redis@p0-tkhihec-redis3-cache01 redis]$ [redis@p0-tkhihec-redis3-cache01 redis]$ cat conf/sentinel.confport 26379daemonize yesbind 0.0.0.0protected-mode nologfile "/home/redis/redis/log/sentinel.log"dir "/home/redis/redis-5.0.5/conf"sentinel myid 35d16b608e98ac4aa9f298dc122752df0235981bsentinel deny-scripts-reconfig yessentinel monitor mymaster 10.132.128.24 6380 2sentinel failover-timeout mymaster 10000# Generated by CONFIG REWRITEsentinel parallel-syncs mymaster 2sentinel auth-pass mymaster Redis_xxxxsentinel config-epoch mymaster 36240sentinel leader-epoch mymaster 36240sentinel known-replica mymaster 10.132.128.23 6379sentinel known-replica mymaster 10.132.128.24 6379sentinel known-sentinel mymaster 10.132.128.24 26379 ba8e97799c0f58c0c5b028e83adf12aa254832fesentinel known-sentinel mymaster 10.132.128.24 26380 abec83027be224b97f2c1e6001acb695543df584sentinel current-epoch 36240master redis install10.132.128.24 slave:6379 sentinel:26379 slave:6380 sentinel:26380[redis@p0-tkhihec-redis3-cache02 ~]$ netstat -tnlp(Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.)Active Internet connections (only servers)Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 13133/../bin/redis- tcp 0 0 0.0.0.0:26379 0.0.0.0:* LISTEN 8804/./bin/redis-se tcp 0 0 0.0.0.0:6380 0.0.0.0:* LISTEN 13081/../bin/redis- tcp 0 0 0.0.0.0:26380 0.0.0.0:* LISTEN 9740/./bin/redis-se tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN - tcp 0 0 0.0.0.0:10050 0.0.0.0:* LISTEN - tcp6 0 0 :::22 :::* LISTEN - tcp6 0 0 :::19100 :::* LISTEN - [redis@p0-tkhihec-redis3-cache02 ~]$ lsredis redis-5.0.5 redis6380[redis@p0-tkhihec-redis3-cache02 ~]$ cd redis[redis@p0-tkhihec-redis3-cache02 redis]$ cat conf/redis_6379.confdaemonize yesbind 0.0.0.0pidfile "/home/redis/redis/logs/redis_6379.pid"port 6379tcp-backlog 511timeout 300tcp-keepalive 60loglevel warninglogfile "/home/redis/redis/logs/redis_6379.log"databases 16stop-writes-on-bgsave-error yesrdbcompression yesrdbchecksum yesdbfilename "dump_6379.rdb"dir "/home/redis/redis-5.0.5/data"replica-serve-stale-data yesreplica-read-only yesrepl-diskless-sync norepl-diskless-sync-delay 5repl-disable-tcp-nodelay noreplica-priority 100maxclients 10000maxmemory 3gbmaxmemory-policy volatile-lrumaxmemory-samples 3appendonly yesappendfilename "appendonly_6379.aof"appendfsync everysecno-appendfsync-on-rewrite noauto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mbaof-load-truncated yeslua-time-limit 5000slowlog-log-slower-than 10000slowlog-max-len 1024latency-monitor-threshold 0notify-keyspace-events ""hash-max-ziplist-entries 512hash-max-ziplist-value 64list-max-ziplist-entries 512list-max-ziplist-value 64set-max-intset-entries 512zset-max-ziplist-entries 128zset-max-ziplist-value 64hll-sparse-max-bytes 3000activerehashing yesclient-output-buffer-limit normal 0 0 0client-output-buffer-limit replica 256mb 64mb 60client-output-buffer-limit pubsub 32mb 8mb 60hz 10aof-rewrite-incremental-fsync yesprotected-mode norequirepass "Redis_xxxx"replicaof 10.132.128.24 6380masterauth "Redis_xxxx"#rename-command FLUSHALL ''#rename-command CONFIG ''#rename-command EVAL ''[redis@p0-tkhihec-redis3-cache02 redis]$ cat conf/sentinel.confport 26379daemonize yesbind 0.0.0.0protected-mode nologfile "/home/redis/redis/log/sentinel.log"dir "/home/redis/redis-5.0.5/conf"sentinel myid ba8e97799c0f58c0c5b028e83adf12aa254832fesentinel deny-scripts-reconfig yessentinel monitor mymaster 10.132.128.24 6380 2sentinel failover-timeout mymaster 10000# Generated by CONFIG REWRITEsentinel parallel-syncs mymaster 2sentinel auth-pass mymaster Redis_NOPwd_2020_Tksentinel config-epoch mymaster 36240sentinel leader-epoch mymaster 36240sentinel known-replica mymaster 10.132.128.23 6379sentinel known-replica mymaster 10.132.128.24 6379sentinel known-sentinel mymaster 10.132.128.23 0 5caf62e09e8dbf647d797e9b741f4c02a4454ed0sentinel known-sentinel mymaster 10.132.128.24 0 787829a9585c4c45e0fcf088a4c12b98a3a4b6ecsentinel known-sentinel mymaster 10.132.128.24 26380 abec83027be224b97f2c1e6001acb695543df584sentinel known-sentinel mymaster 10.132.128.23 26379 35d16b608e98ac4aa9f298dc122752df0235981bsentinel current-epoch 36240[redis@p0-tkhihec-redis3-cache02 redis]$ cd ../redis6380/[redis@p0-tkhihec-redis3-cache02 redis6380]$ cat conf/redis_6379.confcat: conf/redis_6379.conf: No such file or directory[redis@p0-tkhihec-redis3-cache02 redis6380]$ cat conf/redis_6380.confdaemonize yesbind 0.0.0.0pidfile "/home/redis/redis/logs/redis_6380.pid"port 6380tcp-backlog 511timeout 300tcp-keepalive 60loglevel warninglogfile "/home/redis/redis/logs/redis_6380.log"databases 16stop-writes-on-bgsave-error yesrdbcompression yesrdbchecksum yesdbfilename "dump_6380.rdb"dir "/home/redis/redis6380/data"replica-serve-stale-data yesreplica-read-only yesrepl-diskless-sync norepl-diskless-sync-delay 5repl-disable-tcp-nodelay noreplica-priority 100maxclients 10000maxmemory 3gbmaxmemory-policy volatile-lrumaxmemory-samples 3appendonly yesappendfilename "appendonly_6380.aof"appendfsync everysecno-appendfsync-on-rewrite noauto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mbaof-load-truncated yeslua-time-limit 5000slowlog-log-slower-than 10000slowlog-max-len 1024latency-monitor-threshold 0notify-keyspace-events ""hash-max-ziplist-entries 512hash-max-ziplist-value 64list-max-ziplist-entries 512list-max-ziplist-value 64set-max-intset-entries 512zset-max-ziplist-entries 128zset-max-ziplist-value 64hll-sparse-max-bytes 3000activerehashing yesclient-output-buffer-limit normal 0 0 0client-output-buffer-limit replica 256mb 64mb 60client-output-buffer-limit pubsub 32mb 8mb 60hz 10aof-rewrite-incremental-fsync yesprotected-mode norequirepass "Redis_xxxx"masterauth "Redis_xxxx"#rename-command FLUSHALL ''#rename-command CONFIG ''#rename-command EVAL ''[redis@p0-tkhihec-redis3-cache02 redis6380]$ cat conf/sentinel.confport 26380daemonize yesbind 0.0.0.0protected-mode nologfile "/home/redis/redis6380/log/sentinel.log"dir "/home/redis/redis6380/conf"sentinel myid abec83027be224b97f2c1e6001acb695543df584sentinel deny-scripts-reconfig yessentinel monitor mymaster 10.132.128.24 6380 2sentinel failover-timeout mymaster 10000# Generated by CONFIG REWRITEsentinel parallel-syncs mymaster 2sentinel auth-pass mymaster Redis_xxxxsentinel config-epoch mymaster 36240sentinel leader-epoch mymaster 36240sentinel known-replica mymaster 10.132.128.23 6379sentinel known-replica mymaster 10.132.128.24 6379sentinel known-sentinel mymaster 10.132.128.24 26379 ba8e97799c0f58c0c5b028e83adf12aa254832fesentinel known-sentinel mymaster 10.132.128.23 0 5caf62e09e8dbf647d797e9b741f4c02a4454ed0sentinel known-sentinel mymaster 10.132.128.23 26379 35d16b608e98ac4aa9f298dc122752df0235981bsentinel current-epoch 36240启动[redis@p0-tkhihec-redis3-cache01 redis]$ bin/redis-server conf/redis_6379.conf[redis@p0-tkhihec-redis3-cache01 redis]$ bin/redis-sentinel conf/sentinel.conf[redis@p0-tkhihec-redis3-cache01 redis]$ bin/redis-cli -c -p 6379 -a Redis_xxxxWarning: Using a password with '-a' or '-u' option on the command line interface may not be safe.127.0.0.1:6379> info Replication# Replicationrole:slavemaster_host:10.132.128.24master_port:6380master_link_status:upmaster_last_io_seconds_ago:1master_sync_in_progress:0slave_repl_offset:36184101slave_priority:100slave_read_only:1connected_slaves:0master_replid:595f00174f932a7e121148f151579607ba8820c6master_replid2:0000000000000000000000000000000000000000master_repl_offset:36184101second_repl_offset:-1repl_backlog_active:1repl_backlog_size:1048576repl_backlog_first_byte_offset:35135526repl_backlog_histlen:1048576[redis@p0-tkhihec-redis3-cache01 redis]$ bin/redis-cli -c -p 26379 127.0.0.1:26379> info sentinel# Sentinelsentinel_masters:1sentinel_tilt:0sentinel_running_scripts:0sentinel_scripts_queue_length:0sentinel_simulate_failure_flags:0master0:name=mymaster,status=ok,address=10.132.128.24:6380,slaves=2,sentinels=3test测试主从##master127.0.0.1:6379> set test hellokugou##slave127.0.0.1:6379> get test"hellokugou"测试哨兵故障转移1.kill 掉 master redis过程2.察看master sentinel日志[redis@p0-tkhihec-redis3-cache01 redis]$ tail -20f /home/redis/redis/log/sentinel.log8248:X 28 Sep 2021 13:01:06.959 * +reboot master mymaster 10.132.128.23 63798248:X 28 Sep 2021 13:01:07.017 # -sdown master mymaster 10.132.128.23 63798248:X 28 Sep 2021 13:01:07.017 # -odown master mymaster 10.132.128.23 63798248:X 28 Sep 2021 13:01:45.998 # +sdown master mymaster 10.132.128.23 63798248:X 28 Sep 2021 13:01:46.033 # +new-epoch 362408248:X 28 Sep 2021 13:01:46.034 # +vote-for-leader abec83027be224b97f2c1e6001acb695543df584 362408248:X 28 Sep 2021 13:01:46.081 # +odown master mymaster 10.132.128.23 6379 #quorum 3/28248:X 28 Sep 2021 13:01:46.081 # Next failover delay: I will not start a failover before Tue Sep 28 13:02:06 20218248:X 28 Sep 2021 13:01:46.960 # +config-update-from sentinel abec83027be224b97f2c1e6001acb695543df584 10.132.128.24 26380 @ mymaster 10.132.128.23 63798248:X 28 Sep 2021 13:01:46.960 # +switch-master mymaster 10.132.128.23 6379 10.132.128.24 63808248:X 28 Sep 2021 13:01:46.960 * +slave slave 10.132.128.24:6379 10.132.128.24 6379 @ mymaster 10.132.128.24 63808248:X 28 Sep 2021 13:01:46.961 * +slave slave 10.132.128.23:6379 10.132.128.23 6379 @ mymaster 10.132.128.24 63808248:X 28 Sep 2021 13:02:16.982 # +sdown slave 10.132.128.23:6379 10.132.128.23 6379 @ mymaster 10.132.128.24 63808248:X 28 Sep 2021 13:02:38.076 # -sdown slave 10.132.128.23:6379 10.132.128.23 6379 @ mymaster 10.132.128.24 6380##察看日志得悉 master转移到了24的6380上了[redis@p0-tkhihec-redis3-cache02 redis6380]$ bin/redis-cli -c -p 6380 -a Redis_xxxx127.0.0.1:6380> info replication# Replicationrole:mastermaster_host:10.132.128.24master_port:6380master_link_status:upmaster_last_io_seconds_ago:1master_sync_in_progress:0slave_repl_offset:36200699slave_priority:100slave_read_only:1connected_slaves:0master_replid:595f00174f932a7e121148f151579607ba8820c6master_replid2:2d68ce9becb5f8b3949d5b01a9bcfe6030844bd0master_repl_offset:36200699second_repl_offset:2274repl_backlog_active:1repl_backlog_size:1048576repl_backlog_first_byte_offset:35152124repl_backlog_histlen:1048576

September 30, 2021 · 4 min · jiezi

关于redis:redis学习之复制

Redis从2.8版本开始,应用PSYNC代替SYNC命令来执行复制时的同步操作,PSYNC有残缺重同步与局部重同步两种模式: 残缺同步模式用于解决首次复制状况:通过让主服务器创立并发送RDB文件,及向从服务器发送保留在缓冲区外面的写命令来进行同步(也叫命令流传)。局部重同步用于解决断线后反复制状况:主服务器从主从服务器连贯断开期间执行的写命令发送给从服务器,让从服务器能够更新至主服务器以后所处的状态。其中,局部重同步性能由上面三局部形成: 主从服务器的复制偏移量。通过复制偏移量能够晓得主从服务器是否处于统一状态。主服务器的复制积压缓冲区。主服务器在进行命令流传时会将命令写入复制积压缓冲区,且缓冲区里的命令都有对应的复制偏移量。当主从重连上时会依据偏移量比对来确定重传的地位。主从服务器的运行ID。主从服务器都会有本人的运行ID,在每次同步过程中都会将本人的运行ID发送给对方,以此来判断对方的身份。最初,再简略列一下复制的实现过程: 从服务器记录主服务器的地址与端口。从服务器收到客户端的SLAVEOF命令后会先记录主服务器的地址与端口。建设连贯。从服务器向主服务器发送PING命令。如果主服务失常收到命令会响应PONG命令。从服务器进行身份验证。从服务器发送端口命令。同步。命令流传。

September 30, 2021 · 1 min · jiezi

关于redis:redis导致redis慢的原因

redis慢了如何排查?能够思考从上面几方面动手: 查看剖析redis慢日志。看是否存在特地耗时的命令,如果存在能够进一步剖析下命令的工夫复杂度,看是否应用正当,有没有其它命令(数据结构)能够代替。是否存在大key的情景。如果存入或批改的数据对象很大,也是有可能造成响应很慢,比方对ziplist这种数据结构进行批改时是有可能须要从新分配内存。个别redis运维团队是有扫描大key的工具的,能够通过工具进行查看地。长久化策略配置的是否正当。rdb与aof如果配置不合理也会影响性能。rdb fork子过程会对CPU有影响,而aof是通过命令追加会间接影响响应,另外aof重写也是须要fork子过程。因而长久化策略须要依据应用的状况进行正当的配置与修改。是否存在少量key同时过期的状况。少量key同时过期一方面redis须要在极短时间里清理少量过期key对象的内存,另外还会将用户申请打到底层数据库,这样甚至会引发其它更重大的问题。针对这个问题能够思考在过期里加上随机数避免少量数据同时过期。参考文章:Redis变慢了,如何疾速排查?

September 28, 2021 · 1 min · jiezi

关于redis:redis学习之持久化

这篇文章简略聊下redis里的RDB与AOF两种长久化。 RDB(redis database)长久化的特点,它能够手动执行也能够通过配置定期执行,手动执行的命令是SAVE与BGSAVE,其中SAVE会阻塞redis服务器过程,直到RDB文件创建实现,在创立过程中,服务器不解决其它命令;BGSAVE则会派生出一个出过程,由子过程创立RDB文件,服务器过程持续解决其它命令。如果是通过配置,那配置的办法是: save 900 1save 300 10save 60 10000只有满足三个中的一个,BGSAVE就会执行: 服务器在900S之内,对数据库进行了至多1次批改。服务器在300S之内,对数据库进行了至多10次批改。服务器在60S之内,对数据库进行了至多10000次批改。再说下RDB的文件保留的是所有的键值对数据,是通过压缩后的二进制文件,如果键值带有过期工夫,那么过期工夫也会被保存起来。 AOF(append only file)所存的内容是写命令,且是以纯文本模式保留。服务器在执行完一个写命令之后,会将这个写命令追加到aof_buf缓冲区开端。AOF能够通过配置appendfsync的值来管制将缓冲区写入和保留到AOF文件的频率,可配置的值有:always/everysec/no。 AOF数据不同步的问题因为是将写命令先写到aof_buf缓存区而后距离一段时间后再写入到AOF文件里,如果在写入文件之前数据进行了批改,则会造成内存里的数据与AOF文件里的数据不统一。针对这个问题,redis会在后盾fork一个子过程进行AOF重写:学生成一个新的AOF文件,而后应用新生成的文件替换旧的AOF文件。 AOF文件多条反复命令问题在AOF重写过程中,会去数据库里读取键现有的值(而不是去剖析已生成的旧的AOF文件),如果能够应用一条命令进行记录则只记一条。比方: redis> RPUSH list "a" "b"2redis> RPUSH list "c"3学生成的旧的AOF文件会别离对应两条命令,而重写的AOF通过剖析了当初数据库里存的数据后会将下面两条命令合成一条进行记录。 这里再对rdb与aof进行一下比照: rdb长处:体积小(存的是数据)、复原快、性能影响小(fork子过程)rdb毛病:数据失落可能性大(不能频繁执行)、影响cpu(fork工夫长后会有影响)aof长处:数据失落可能性小aof毛病:体积大(存的是命令)、性能影响大(先写aof再执行用户操作)、复原慢(须要解析命令)抉择哪种须要依据业务场景来定: 对性能要求高、须要疾速复原倡议应用rdb对数据完整性要求高,倡议应用aof须要两者兼容,可应用二者混合(redis4.0后)

September 28, 2021 · 1 min · jiezi

关于redis:刘建Linux安装部署Redis超级详细

Linux装置部署Redis(超级具体)Author: 刘建(Abbott.liu) Date: 前言网上搜寻了一筐如何在Linux下装置部署Redis的文章,各种文章混搭在一起勉强装置胜利了。本人也记录下,不便后续装置时候有个借鉴之处。 Redis版本 redis-5.0.7服务器版本 Linux CentOS 7.6 64位下载Redis进入官网找到下载地址https://redis.io/download 右键Download按钮,抉择复制链接。 登录服务器,进入ssh root@2.140.189.129文件夹 进入到Xshell控制台(默认以后是root根目录),输出wget将下面复制的下载链接粘贴上,如下命令: wget http://download.redis.io/releases/redis-5.0.7.tar.gz解压并装置Redis解压 下载实现后须要将压缩文件解压,输出以下命令解压到当前目录 tar -zvxf redis-5.0.7.tar.gz解压后在根目录上输出ls 列出所有目录会发现与下载redis之前多了一个redis-5.0.7.tar.gz文件和 redis-5.0.7的目录。 挪动redis目录 个别都会将redis目录搁置到 /usr/local/redis目录,所以这里输出上面命令将目前在/root目录下的redis-5.0.7文件夹更改目录,同时更改文件夹名称为redis。 mv ./redis-5.0.7 /usr/local/rediscd 到/usr/local目录下输出ls命令能够查问到当前目录曾经多了一个redis子目录,同时/root目录下曾经没有redis-5.0.7文件夹 cd /usr/local 编译 cd /usr/local/redis输出命令make执行编译命令,接下来控制台会输入各种编译过程中输入的内容。 make最终运行后果如下: make test You need tcl 8.5 or newer in order to run the Redis test yum install tcl 而后 make test 装置 输出以下命令 make PREFIX=/usr/local/redis install这里多了一个关键字 PREFIX= 这个关键字的作用是编译的时候用于指定程序寄存的门路。比方咱们当初就是指定了redis必须寄存在/usr/local/redis目录。假如不增加该关键字Linux会将可执行文件寄存在/usr/local/bin目录, 库文件会寄存在/usr/local/lib目录。配置文件会寄存在/usr/local/etc目录。其余的资源文件会寄存在usr/local/share目录。这里指定号目录也不便后续的卸载,后续间接rm -rf /usr/local/redis即可删除redis。 ...

September 28, 2021 · 2 min · jiezi

关于redis:高并发场景下的会话服务数据读写设计思路附具体实施方案

关上聊天软件,跟重要的人说个早安,扫一眼敞开了揭示的群音讯。置信这是很多人开始一天的“固定动作”。 随着挪动互联网和通信技术的高速倒退,线上交换已成为人们工作、生存的最重要形式。没带手机出门就像失去了全世界,电量低于 50% 就开始焦虑,因为好友列表里保留着咱们跟这个世界的联结。而通过会话列表关上一个会话,是咱们每天最频繁的动作之一。 IM 会话列表里会话的准确性、实时性会间接影响用户的应用体验与感触。本文分享融云 IM 即时通讯的会话服务数据读写设计思路。(关注 融云寰球互联网通信云,理解更多IM & RTC技术、场景话题) 海量音讯会话的技术挑战以单聊为例,用户 A 给用户 B 发送音讯,会产生两条会话记录:一条发送者的会话,一条接受者的会话。服务端会把这两条会话记录保留到数据库中,便于后续服务重启、更新、查问应用。 为了缩小服务端与客户端的交互,通常状况下,咱们会在会话记录中保留最初一条音讯。之后每次 A 给 B 发消息,或 B 给 A 发消息都会相应地更新这两条会话的音讯记录以及会话的最初工夫等。 如果某一时刻有 10 万个单聊用户发送音讯,便会产生 20 万条会话的增加(第一次聊天)或更新(后续聊天)操作。 在高频次读写的场景下,要提供精确疾速的查问,以及牢靠的存储就很考验服务在高并发场景下的解决能力了。 高并发下会话的查问操作为了提供疾速的查问能力,咱们个别会把被频繁拜访的热点数据存储在缓存中,比方 Redis 等,以不便零碎疾速做出响应,而不是每次查问到数据库造成数据库压力。 为了缩小网络交互,升高服务器压力和晋升用户体验,咱们能够将热点数据放到服务内存中。当下次用户查问时,先去内存中查找是否存在。若存在则间接返回给用户;若不存在则去数据库中查问进去再放到内存中缓存起来,便于下次查问间接从内存中获取而后返回给用户。 (图 1 会话查问流程) 在分布式系统架构中,为了进步内存中缓存数据的命中率,咱们个别会采纳一致性 Hash 的形式,将一个用户的所有会话的操作都落到同一个服务实例上。这样做,不仅利于性能晋升,还有助于升高解决分布式读写带来的数据一致性问题的难度。 (图 2 一致性 Hash 算法计算服务落点) 高并发下会话的插入更新操作解决完查问操作,咱们再来看看如何优化写操作,蕴含插入、更新以及删除等。 当有大量数据要增加到数据库中时,势必进步数据库查问的延时。该如何解决呢? 首先,内存大小是无限的,把所有的会话都放在内存中是不事实的。咱们会把新增加的会话放到 LRU 缓存中供查问应用,而后把要增加的会话写入到队列中,通过异步形式增加到数据库。此时你可能会想:这也并没有缩小插入数据库的次数呀,只是放到前面异步解决了而已。是的,到这一步的确达不到缩小操作数据库次数的成果,且往下看。 (图 3 异步化数据落地解决) 如果要增加会话 A,首先会更新到 LRU 中,而后把会话退出到队列中期待增加到数据库中。此时队列中若没有积压,则会间接更新到数据库中;若有积压,更新到此条会话时先比照 LRU 中的会话,把最新的会话更新到数据库中,并记录最新的会话工夫。 (图 4 会话数据存取策略) 如图 4,从队列中取出会话 1 进行存储,此刻队列中的会话 1 的音讯工夫是 1,LRU 中的会话 1 的音讯工夫是 4。相比拟 LRU 中的会话是最新的,则把 LRU 中的会话入库,并记录这条会话的更新工夫。当队列中更新到 time 为 3 这条旧的会话 1 时,因为这条会话的工夫比记录的工夫小,则抛弃不入库。这样,就能够无效缩小高并发积压的状况下,雷同会话频繁更新导致频繁入库的状况,从而达到减小数据库压力的目标。 ...

September 28, 2021 · 1 min · jiezi

关于redis:redis过期删除策略与淘汰策略

redis是将数据寄存在内存里的,内存是无限的且有的业务场景也须要将数据设置为过期,所以就有了过期删除策略与淘汰策略。过期删除策略分了定时删除、惰性删除与定期删除三种:这里说一下定时与定期的次要差异:定时会扫描全副的键如果过期进行删除;而定期并不会扫描全副键,而是有肯定的算法只是对其中一部分键进行删除。 通过三种删除策略的比拟,惰性删除+定期删除联合能够肯定水平上防止内存的有效占用,但也不可能完全避免,假如一下:如果某些键始终没被扫描到也没被应用,那它就会逃脱定期与惰性删除使得内存还是得不到开释,这样,咱们就须要设置淘汰策略了。 当redis内存应用达到咱们设置的maxmemory后,会依据淘汰策略清理内存,淘汰策略一有上面六种: noeviction 当内存不足以包容写入数据时,新写入操作会报错。allkeys-lru 当内存不足以包容写入数据时,移除最近起码应用的key。allkeys-random 当内存不足以包容写入数据时,随机移除某个key。volatile-lru 当内存不足以包容写入数据时,移除设置了过期工夫里最近起码应用的key。volatile-random 当内存不足以包容写入数据时,随机移除设置了过期工夫的key。volatile-ttl 当内存不足以包容写入数据时,优先移除更早过期工夫的key。有两点须要阐明下: 个别不举荐应用random相干的淘汰策略,一些数据莫名其妙的不见给人造成困惑。不过也没有相对,须要联合业务场景。如果没设置过期工夫,那volatile-lru/volatile-random/volatile-ttl的行为与noeviction差不多。

September 28, 2021 · 1 min · jiezi

关于redis:Redis核心原理与实践散列类型与字典结构实现原理

Redis散列类型能够存储一组无序的键值对,它特地实用于存储一个对象数据。 > HSET fruit name apple price 7.6 origin china3> HGET fruit price"7.6"本文剖析Redis中散列类型以及其底层数据结构--字典的实现原理。 字典Redis通常应用字典构造存储用户散列数据。 字典是Redis的重要数据结构。除了散列类型,Redis数据库也应用了字典构造。 Redis应用Hash表实现字典构造。剖析Hash表,咱们通常关注以下几个问题: (1)应用什么Hash算法? (2)Hash抵触如何解决? (3)Hash表如何扩容? 提醒:本章代码如无特地阐明,均在dict.h、dict.c中。定义字典中键值对的定义如下: typedef struct dictEntry { void *key; union { void *val; uint64_t u64; int64_t s64; double d; } v; struct dictEntry *next;} dictEntry;key、v:键、值。next:下一个键值对指针。可见Redis字典应用链表法解决Hash抵触的问题。 提醒:C语言union关键字用于申明共用体,共用体的所有属性共用同一空间,同一时间只能贮存其中一个属性值。也就是说,dictEntry.v能够寄存val、u64、s64、d中的一个属性值。应用sizeof函数计算共用体大小,后果不会小于共用体中最大的成员属性大小。字典中Hash表的定义如下: typedef struct dictht { dictEntry **table; unsigned long size; unsigned long sizemask; unsigned long used;} dictht;table:Hash表数组,负责存储数据。used:记录存储键值对的数量。size:Hash表数组长度。dictht的构造如图3-1所示。 字典的定义如下: typedef struct dict { dictType *type; void *privdata; dictht ht[2]; long rehashidx; unsigned long iterators;} dict;type:指定操作数据的函数指针。ht[2]:定义两个Hash表用于实现字典扩容机制。通常场景下只应用ht[0],而在扩容时,会创立ht[1],并在操作数据时中逐渐将ht[0]的数据移到ht[1]中。rehashidx:下一次执行扩容单步操作要迁徙的ht[0]Hash表数组索引,-1代表以后没有进行扩容操作。iterators:以后运行的迭代器数量,迭代器用于遍历字典键值对。 dictType定义了字典中用于操作数据的函数指针,这些函数负责实现数据复制、比拟等操作。typedef struct dictType { uint64_t (*hashFunction)(const void *key); void *(*keyDup)(void *privdata, const void *key); void *(*valDup)(void *privdata, const void *obj); int (*keyCompare)(void *privdata, const void *key1, const void *key2); void (*keyDestructor)(void *privdata, void *key); void (*valDestructor)(void *privdata, void *obj);} dictType;通过dictType指定操作数据的函数指针,字典就能够寄存不同类型的数据了。但在一个字典中,键、值能够是不同的类型,但键必须类型雷同,值也必须类型雷同。 Redis为不同的字典定义了不同的dictType,如数据库应用的server.c/dbDictType,散列类型应用的server.c/setDictType等。 ...

September 27, 2021 · 3 min · jiezi

关于redis:redis学习之十一有序集合对象

之前相关联的文章:redis学习之一SDSredis学习之二双端链表redis学习之三字典redis学习之四skiplistredis学习之五ziplistredis学习之六对象redis学习之七字符串对象redis学习之八列表对象redis学习之九哈希对象redis学习之十汇合对象 先再看一下redisObject的定义: typedef struct redisObject{ //类型 unsigned type:4; //编码 unsigned encoding:4; //lru缓存淘汰机制信息 unsigned lru:LRU_BITS; //援用计数器 int refcount; //指向底层实现数据结构的指针 void *ptr;}robj;有序汇合的编码能够是ziplist或skiplist,当同时满足上面两个条件时应用ziplist编码,不满足的话会应用skiplist编码: 保留的元素不超过128个。保留的元素成员长度不超过64字节。这两个值也是能够通过zset-max-ziplist-value配置进行调整的。 先来说下ziplist编码无关的状况:每个元素应用两个紧挨在一起的压缩列表来保留数据,第一个节点保留元素的成员(member),第二个节点保留的是分值(score),分值从小到大排列,也就是分值较小的排在表头后面,较大的排在凑近表尾一侧。看下上面的命令: redis> ZADD price 8.5 apple 5.0 banana 6.0 cherry(integer) 3存储示意图为: 能够看的进去元素是按分值递增排序的。上面来看下应用skiplist编码是如何存储的,先看下示意图:skiplist编码的有序汇合对象应用zset构造作为底层实现,一个zset蕴含一个字典和一个跳表: typedef struct zset{ zskipliset *zsl; dict *dict;}zset;咱们分两局部别离说下dict与zsl,先看zsl:zsl跳表按分值从小到大保留了所有汇合元素,跳表节点里的object保留了元素成员,跳表里的score属性保留的是元素的分值。再来看看dict里的内容:dict存的是元素成员到分值的映射关系:dict的健保留了元素的成员,dict的值则保留了元素分值,通过这个关系,能够用O(1)的复杂度找到给定的分值。须要阐明下,只管zset同时应用dict与zskiplist两种数据结构保留元素,但这两种数据结构会通过指针来共享雷同元素的成员和分值,所以不会产生同一元素屡次存储,也就不会造成内存的节约。 最初,咱们来聊几个问题: 为什么有序汇合会同时应用dict与ziplist两种数据结构呢?依据下面提到的两种数据结构的存储原理是很好答复的:应用dict是为了利用hash算法,以O(1)的工夫复杂度查问成员的分值,这就是命令ZSCORE实现的根底。应用skiplist让咱们能够以O(logN)的工夫复杂度进行依据分值查问成员、查问成员的排名操作,这就是命令ZRANK/ZRANGE实现的根底。剖析下命令ZRANGE key start stop命令的工夫复杂度咱们晓得这命令会返回有序汇合中指定区间内的成员,工夫复杂度为O(logN + M),其中 N 为有序集的基数,而 M 为后果集的基数。是这样的:通过skiplist能够以O(logN)的工夫复杂度定位到范畴start开始的元素,而后再以M的工夫复杂度定位到stop完结的元素。有个阐明:zrange工夫复杂度的阐明剖析下ZRANK key member的工夫复杂度从文档上看这个命令是返回有序集 key 中成员 member 的排名,工夫复杂度为O(logN),进行工夫复杂度的剖析咱们须要看下ziplist里跨度(redis学习之四skiplist)的含意:跨度是用于记录两个节点之间的间隔的,它是用来计算排位(rank)的,在查找某个节点过程中,将沿途拜访过的所有层的跨度累计起来,失去的后果就是指标结点在ziplist里的排位,计算排位其实就相当于依据分值进行元素的查找,在查找的过程中累加跨度的常量计算能够疏忽,这样整体工夫复杂度就是O(logN)了。本文参考的有:黄健宏的《Redis设计与实现》一书

September 27, 2021 · 1 min · jiezi

关于redis:Redis-知识点总结

Redis1.根本的数据结构字符串 SDS哈希 哈希 压缩链表链表 链表 压缩链表汇合 整数汇合 哈希有序汇合 跳跃表 压缩链表geohyperloglogbitmap 2.长久化AOFRDB 3.高可用单机模式主从模式哨兵模式集群模式 CRC16(key)%16383 4.Redis缓存篇缓存穿透缓存击穿缓存雪崩缓存一致性问题 5.Redis数据过期策略定期删除惰性删除LRU

September 27, 2021 · 1 min · jiezi

关于redis:12306抢票算法居然被曝光了居然是redis实现的

导读置信大家应该都有抢火车票的教训,每年年底,这都是一场盛宴。然而你有没有想过抢火车票这个算法是怎么实现的呢? 应该没有吧,咱们明天就来一一探讨。其实并没有你想的那么难 bitmap与位运算redis的bitmap根本应用咱们之前曾经介绍过了,如果不是很相熟的敌人能够看看这里redis bitmap的基本操作和利用 明天在这里咱们次要是先回顾一下位运算 12306抢票算法详解咱们以北京到西安这趟高铁为例,比方我的路线就是从北京到西安,车上如果只剩最初一张票了,那么如果有其他人,在北京到西安这条路线之间买任何一站,那么我都是买不了票的,换句话说,对于单个座位来说,必须是终点到目的地之间的所有站,都没有人买的话,那么能力被算是有票状态。 所以咱们能够尝试用bitmap联合上位操作来实现这种场景,以上述北京到西安为例,咱们把问题简化 比方一个火车上只有4个座位北京到西安,一共是4站,其实是三个区间的,别离为北京->石家庄,石家庄->郑州,郑州->西安首先咱们给每个区间构建一个空位图(0为有票,1为无票) 接下来,比方有人买了一张从北京到西安的票买票这个动作,比方被调配到的座位是编号为1的座位,那么咱们间接把北京到西安的所有站,1号座位全副设置为1,如下图 接下来又有人买了一张从石家庄到西安的票比方这次调配的是座位2,那么咱们把石家庄到西安的所有票全副设置为1就行了,如下图 如何晓得还剩几张票?其实解决这个问题很简略,咱们间接把上述位图做一个或操作就能够了 或操作后果有几个0,则阐明还剩几张票。 总结其实解决这个问题次要在于位图的构建,因为火车票对于某一个座位来说,只有终点到起点两头某一个区间被占用了(置为1),那么整个座位都是有效的这个特点,很容易想到用或操作的后果来判断买票后果,咱们这里只用了4位是为了不便阐明问题,理论中应该是火车上有多少座位,位图的长度就应该是多少。好了,对于抢票算法咱们就介绍到这里,你有没有Get到呢?或者你有没有更好的实现办法呢?

September 27, 2021 · 1 min · jiezi

关于redis:redis学习之十集合对象

之前相关联的文章:redis学习之一SDSredis学习之二双端链表redis学习之三字典redis学习之四skiplistredis学习之五ziplistredis学习之六对象redis学习之七字符串对象redis学习之八列表对象redis学习之九哈希对象 先再看一下redisObject的定义: typedef struct redisObject{ //类型 unsigned type:4; //编码 unsigned encoding:4; //lru缓存淘汰机制信息 unsigned lru:LRU_BITS; //援用计数器 int refcount; //指向底层实现数据结构的指针 void *ptr;}robj;汇合对象的编码能够是intset或hashtable。当同时满足上面两个条件时会应用intset,不满足时应用hashtable: 保留的所有元素都是整数。只在的元素数量不超过512个(能够通过set-max-intset-entries配置进行调整)当执行了上面命令后: redis> SADD numbers 1 3 5 (integer) 3上面是intset编码存储的格局: 当执行了上面命令后: redis> SADD test "apple" "cherry" "yes"(integer) 3上面是hashtable编码存储的格局: 参考的文章有:黄健宏的《Redis设计与实现》一书

September 26, 2021 · 1 min · jiezi

关于redis:教你如何让Redis更持久

大家好,我是小菜。一个心愿可能成为 吹着牛X谈架构 的男人!如果你也想成为我想成为的人,不然点个关注做个伴,让小菜不再孤独! 本文次要介绍 Redis 的长久化 如有须要,能够参考 如有帮忙,不忘 点赞 ❥ 微信公众号已开启,小菜良记,没关注的同学们记得关注哦! 最近在面试的路上愈走愈远了,Redis必定是一个热门面试方向。像有几种数据结构?如何实现提早队列?淘汰机制是怎么样的?都快问到麻痹,这些问题还常绕脑梁。那咱们这篇就举一个比拟常见且难度适中的面试题来聊聊。Redis 的长久化策略是怎么样的? 开局问个问题,置信被问到 Redis 长久化 的同学必定不在少数,答对的同学必定也不在少数,有些小伙伴说到 Redis长久化 必定张口就来,毕竟也就 AOF 和 RDB 两个概念,只有你筹备了面试,就不会被问的太惨。然而你是真的懂还是只是为了应酬面试而去应酬记忆?你晓得 AOF 和 RDB 两个词是什么单词的缩写吗?你落地施行过吗?你真认为面试官听不出来你是背题还是实操吗?如果 4 个问题你中了一半,那无妨往下看看,兴许会有些播种,起码答面试题的时候心中有小菜~! Redis 长久化什么是Redis长久化?咱们先别记得往解决方向前行,先明确这道题的意思。 长久化 就是要让数据永恒的保留上来。那什么是 Redis 长久化 ?那就是把Redis保留在内存的数据写到磁盘中,避免服务宕机了内存数据失落问题。那有些小伙伴就说了,那磁盘损坏了,数据怎么长久化?就算多点备份能解决磁盘损坏问题,那如果来个多点失落怎么整?停住停住,咱们这篇讲的是Redis内存数据->磁盘的长久化问题,可别指望靠这个问题跟面试官扯半个小时~! 咱们这篇从几个点来阐明 Redis长久化 问题。 也就三点大的方向,三步走策略解决你的长久化问题。 一、RDB先来解决开局的问题之一,RDB 是什么单词的全称。 RDB(Redis Database Backup file)--- Redis 数据备份文件,也称为 Redis 数据快照。 这个玩意就是用来将内存中的所有数据都记录到磁盘中,当 Redis 实例故障重启后,从磁盘读取快照文件,从而复原数据。心田狂喜,看来学的第一个概念就能够解决 Redis 长久化问题~ 在学 RDB 之前,咱们先明确两个外围概念 fork 和 cow,上面咱们会解释,这里先卖个关子。 RDB 是 Redis 中默认的长久化机制,依照肯定的工夫将内存中的数据以快照的形式保留到磁盘中,它会产生一个非凡类型的文件 .rdb 数据文件,同时能够通过配置文件中的 save 参数来定义快照的周期. ...

September 26, 2021 · 2 min · jiezi

关于redis:redis学习之九哈希对象

之前相关联的文章:redis学习之一SDSredis学习之二双端链表redis学习之三字典redis学习之四skiplistredis学习之五ziplistredis学习之六对象redis学习之七字符串对象redis学习之八列表对象 哈希对象的编码能够是ziplist或hashtable。当同时满足上面两个条件时应用ziplist编码,不满足时则应用hashtable。 保留的键和值的字符串长度都小于64字节。保留的键值对数量小于512个。下面两个条件能够通过hash-max-ziplist-value和hash-ziplist-entries两个值进行调整。 当应用ziplist编码时有上面两个特点: 健值对作为两个节点是紧挨在一起的,健节点在前值节点紧随其后。健节点放在ziplist表头方向,值节点放在ziplist表尾方向。看下执行了上面命令后: redis> HSET profile Name "Tom"(integer) 1redis> HSET profile Age 18(integer) 1存储如下图: 当应用hashtable编码时有上面两特点: hashtable里的每个键都是一个stringObject对象,对象里保留了键的内容。hashtable里的每个值都是一个stringObject对象,对象里保留了值的内容。下面执行的命令如果应用的是hashtable,则存储如下:(存储的格局是下面展现的,疏忽外面具体的内容。。。) 参考的文章有:黄健宏的《Redis设计与实现》一书

September 26, 2021 · 1 min · jiezi

关于redis:redis学习之八列表对象

之前相关联的文章:redis学习之一SDSredis学习之二双端链表redis学习之三字典redis学习之四skiplistredis学习之五ziplistredis学习之六对象redis学习之七字符串对象 先再看一下redisObject的定义: typedef struct redisObject{ //类型unsigned type:4;//编码unsigned encoding:4;//lru缓存淘汰机制信息unsigned lru:LRU_BITS;//援用计数器int refcount;//指向底层实现数据结构的指针void *ptr;}robj;字符串对象的编码能够是zilist或linkedlist。编码的转换规则,当列表同时满足上面两个条件时应用ziplist编码,不满足则应用linkedlist。 列表对象保留的所有字符串元素长度都小于64字节。列表对象保留的元素数量小于512个。当执行了如此命令时: redis> RPUSH numbers 1 "three" 5(integer) 3应用ziplist编码的示意图:应用linkedlist编码的示意图: 参考的文章有:黄健宏的《Redis设计与实现》一书须要阐明下的是这里的stringObject作了简化,格局能够参看redis学习之七字符串对象里的内容。

September 26, 2021 · 1 min · jiezi

关于redis:用阿里云redis加速ESC上行速度

因为阿里云流动,19.9买了一年redis,给了100M的公网宽带。 我的阿里云学生机只有1M的上行宽带,redis和ESC又在一个区域,我就有了让ESC服务器上行通过内网走redis,redis再把数据收回来。达到上行减速的作用。阿里云服务器公网上行带宽很高,内网带宽也很高,只有公网上行低。 目前试过的两个场景,ESC当socks代理服务器,客户端和ESC直连,用来阐明代理那些申请,ESC取回数据后,传给redis,客户端从redis取数据,目前看提早还能够。 另一个场景就是阿里云上装了个aria2用来下一些没啥网速的资源,等下完了再通过redis直达,取回本地。 目前试过redis的,阻塞链表和公布订阅模式,链表尽管能够实现,然而要被动去取数据,整体提早上比公布订阅形式高。目前做法是,客户端和服务端提前沟通好key,之后通过公布订阅形式传输数据。

September 26, 2021 · 1 min · jiezi

关于redis:Redis可观测最佳实践5大关键指标最全解析

什么是RedisRedis是一种风行的内存键/值数据存储。 Redis以其杰出的性能和简略的入门而闻名,已在各个行业中找到了用处,包含: 数据库:只管能够应用异步磁盘持久性,但Redis能够用持久性来换取速度,而不是传统的基于磁盘的数据库。 Redis提供了丰盛的数据原语集和异样丰盛的命令列表。邮件队列:Redis的阻止列表命令和低提早使其成为邮件代理服务的良好后端。内存缓存:可配置的密钥发出策略,包含风行的“最近起码应用”策略以及从Redis 4.0开始的“起码常常应用”策略,使Redis成为缓存服务器的绝佳抉择。 与传统的缓存不同,Redis还容许长久化磁盘以进步可靠性。Redis是收费的凋谢源代码产品。 提供商业反对,以及齐全托管的Redis即服务。Redis被许多高流量的网站和应用程序所采纳,例如Twitter,GitHub,Docker,Pinterest,Datadog和Stack Overflow。 要害Redis指标监督Redis能够帮忙您在两个方面发现问题:Redis自身的资源问题以及反对基础架构中其余中央呈现的问题。 在本文中,咱们具体介绍了以下每个类别中最重要的Redis指标: 性能指标内存指标根本流动指标持续性指标谬误指标性能指标除低错误率外,良好的性能是零碎运行状况的最佳顶级指标之一。 如内存局部中所述,性能不佳通常是由内存问题引起的。 告警指标:latency提早是对客户端申请和理论服务器响应之间的工夫的度量。 跟踪提早是检测Redis性能变动的最间接办法。 因为Redis具备单线程个性,因而提早散布中的异样值可能会导致重大的瓶颈。 一个申请的响应工夫过长会减少所有后续申请的等待时间。一旦确定提早是一个问题,就能够采取多种措施来诊断和解决性能问题。 观测指标:Instantaneous_ops_per_sec跟踪已解决命令的吞吐量对于诊断Redis实例中高提早的起因至关重要。 高提早可能是由许多问题引起的,从积压的命令队列到速度慢的命令,再到网络链路适度应用。 您能够通过测量每秒解决的命令数来进行考察-如果该命令简直放弃不变,则起因不是计算密集型命令。 如果一个或多个慢速命令引起提早问题,您将看到每秒的命令数量降落或齐全进行。与历史标准相比,每秒解决的命令数量降落可能是低命令量或阻塞零碎的慢命令的迹象。 低命令量可能是失常景象,或者可能表明上游呈现问题。 指标:hit rate将Redis用作缓存时,监督缓存命中率能够告诉您缓存是否失去无效应用。命中率低意味着客户端正在寻找不再存在的密钥。Redis不间接提供命中率指标。咱们依然能够这样计算: hit rate = keyspace_hits / (keyspace_hits + keyspace_misses)高速缓存命中率低可能是由多种因素引起的,包含数据到期和调配给Redis的内存不足(这可能会导致键退出)。 低命中率可能会导致应用程序提早减少,因为它们必须从较慢的备用资源中获取数据。 内存指标 观测指标:used_memory内存使用率是Redis性能的要害组成部分。 如果used_memory超出了可用的零碎总内存,则操作系统将开始替换内存的旧/未应用局部。 每个替换的局部都写入磁盘,从而重大影响性能。 从磁盘写入或读取比从内存写入或读取要慢5个数量级(100,000x!)(内存为0.1 µs,磁盘为10 ms)。 您能够将Redis配置为限度在指定的内存量内。 在redis.conf文件中设置maxmemory指令能够间接管制Redis的内存应用状况。 启用maxmemory要求您为Redis配置驱赶策略,以确定开释内存的形式。 在evicted_keys局部中理解无关配置maxmemory-policy指令的更多信息。 警报指标:mem_fragmentation_ratiomem_fragmentation_ratio度量规范提供了操作系统(used_memory_rss)所应用的内存与Redis调配的内存(used_memory)的比率。 mem_fragmentation_ratio = used_memory_rss / used_memory操作系统负责为每个过程调配物理内存。操作系统的虚拟内存管理器解决由内存分配器介导的理论映射。 这是什么意思?如果您的Redis实例的内存占用为1GB,则内存分配器将首先尝试查找间断的内存段来存储数据。如果找不到间断的段,则分配器必须将过程的数据划分为多个段,从而减少内存开销。 跟踪碎片率对于理解Redis实例的性能十分重要。碎片率大于1示意正在产生碎片。比率超过1.5示意碎片过多,您的Redis实例耗费了其申请的物理内存的150%。小于1的碎片率告诉您Redis须要的内存多于零碎上可用的内存,这导致替换。替换到磁盘将导致提早显着减少(请参阅已用内存)。现实状况下,操作系统将在物理内存中调配一个间断的段,其碎片率等于1或更大。 如果服务器的碎片率超过1.5,重新启动Redis实例将容许操作系统复原以前因为碎片而无奈应用的内存。在这种状况下,将警报作为告诉可能就足够了。 然而,如果您的Redis服务器的碎片率低于1,则可能须要作为页面收回警报,以便您能够疾速减少可用内存或缩小内存使用量。 从Redis 4开始,将Redis配置为应用随附的jemalloc正本时,能够应用新的被动碎片整顿性能。能够将该工具配置为在碎片达到肯定级别时启动,并开始将值复制到间断的内存区域中并开释旧正本,从而缩小服务器运行时的碎片。 警报指标:evicted_keys(仅高速缓存)如果您将Redis用作缓存,则可能须要将其配置为在达到最大内存限度时主动革除密钥。 如果您将Redis用作数据库或队列,则最好将其替换为逐出,在这种状况下,您能够跳过此指标。 跟踪密钥移出很重要,因为Redis会程序解决每个操作,这意味着逐出大量密钥会导致较低的命中率,从而导致更长的延迟时间。 如果您应用的是TTL,则可能不会心愿退出按键。 在这种状况下,如果该指标始终大于零,则您的实例中的提早可能会减少。 其余大多数不应用TTL的配置最终都会耗尽内存,并开始逐出密钥。 只有您的响应工夫是能够承受的,稳固的驱赶率是能够承受的。 您能够应用以下命令配置密钥到期策略: redis-cli CONFIG SET maxmemory-policy <policy>其中policy是下列之一: noeviction:当达到内存限度并且用户尝试增加其余键时,返回一个谬误volatile-lru:删除具备到期集的密钥中最近起码应用的密钥volatile-ttl:从具备到期集的密钥中删除残余生存工夫最短的密钥volatile-random:从具备到期集的密钥中删除一个随机密钥allkeys-lru:从所有密钥集中删除最近起码应用的密钥allkeys-random:从所有密钥集中删除一个随机密钥volatile-lfu:在Redis 4中增加、删除具备到期集的密钥中最不罕用的密钥allkeys-lfu:在Redis 4中增加、从所有密钥集中删除最不罕用的密钥留神:因为性能起因,在应用LRU,TTL或Redis 4(从LUF开始)策略时,Redis实际上不会从整个键空间中进行采样。 Redis首先对密钥空间的一个随机子集进行采样,而后将逐出策略利用于该样本。 通常,较新的(> = 3)版本的Redis采纳LRU采样策略,该策略更靠近于实在LRU。 LFU策略能够通过设置例如以下内容来调整:设置我的项目必须通过多少工夫能力拜访级别升高的我的项目。 无关更多详细信息,请参见Redis的文档。观测指标:blocked_clientsRedis提供了许多对列表进行操作的阻止命令。 BLPOP,BRPOP和BRPOPLPUSH别离是命令LPOP,RPOP和RPOPLPUSH的阻塞变体。 当源列表为非空时,命令将按预期执行。 然而,当源列表为空时,阻止命令将期待,直到源被填充或达到超时为止。 ...

September 26, 2021 · 1 min · jiezi

关于redis:redis学习之七字符串对象

之前相关联的文章:redis学习之一SDSredis学习之二双端链表redis学习之三字典redis学习之四skiplistredis学习之五ziplistredis学习之六对象 先再看一下redisObject的定义: typedef struct redisObject{ //类型 unsigned type:4; //编码 unsigned encoding:4; //lru缓存淘汰机制信息 unsigned lru:LRU_BITS; //援用计数器 int refcount; //指向底层实现数据结构的指针 void *ptr;}robj;字符串对象的编码能够是int、raw或embstr。 如果一个字符串对象保留的是整数值,并且这个值能够应用long类型示意,那么,字符串对象会将整数值保留在字符串对象构造的ptr属性里,并将字符串编码设置为int。如果字符串对象保留的是一个字符串,且这个字符串值的长度大于39(redis 3.2版本后为44)字节,那么,字符串对象将应用一个SDS保留这个字符串值,且将编码设置为raw;否则编码设置为embstr。embstr与raw两种编码的不同点: embstr编码raw编码字符串对象所有数据所存内存是间断的字符串对象数据所存内存非间断内存申请一次,开释一次内存申请两次,开释也是两次最初,字符串最长可存512M: StringsStrings are the most basic kind of Redis value. Redis Strings are binary safe, this means that a Redis string can contain any kind of data, for instance a JPEG image or a serialized Ruby object.A String value can be at max 512 Megabytes in length.参考的文章有:黄健宏的《Redis设计与实现》一书Redis开发与运维:SDS与embstr、raw 深刻了解 ...

September 26, 2021 · 1 min · jiezi

关于redis:Redis系列之SDS

Redis没有间接应用C语言的字符串,而是本人构建了一个名为简略动静字符串(simple synamic string)的形象类型,并将SDS作为Redis默认的字符串示意。当Redis存储的不仅仅是一个字符串面量,而逝一个能够被批改的字符串的时候,就会用到SDS。例如:应用SET msg "hello world"存储,底层是通过SDS实现的。 一、SDS的定义SDS构造体: struct sdshdr { int len; int free; char buf[];}上边的构造体是SDS的定义,蕴含三个属性信息,len示意的是字符串的长度,在存储的时候间接计算好的,free示意SDS除了存储的字符串之外,额定预留的空间,buf[]用于存储字符串的值,须要留神的是:在存储的时候除了存储字符串自身的值之外,还会在值的结尾存储一个空字符'\O',这一点遵循了C字符串以空字符结尾的常规,这么做的益处是,SDS能够间接重用C字符串函数库中的函数。 SDS与C字符串的区别(一)、查问长度的复杂度C字符串应用长度为N+1的字符数组来示意长度为N的字符串,在字符串的结尾应用一个空字符完结。因为C语言在存储字符串的时候并不间接计算字符串的长度,所以获取字符串长度须要应用遍从来实现,工夫复杂度为O(n);SDS在存储字符串值的时候间接计算并写入len,要获取字符串长度间接查问len即可,实现复杂度为O(1),Redis通过应用SDS,将查问字符串的长度的工夫复杂度从O(n)升高到了O(1)。 (二)、杜绝缓冲区溢出因为C字符串在存储的时候不计算字符串长度,所以strcat假如用户执行这个函数时曾经为dest调配了足够多的内存空间,能够存储所有的字符串值,然而如果strcat的字符串长度大于调配的缓存空间,就会造成一部分字符串存进去了,另一部分因为没有空间存储不了,造成缓冲区的溢出、数据不平安。在Redis中应用SDS,SDS构造中有一个属性free,该属性为SDS存储字符串后又额定预留了一部分存储的空间。在须要会已存入的字符串追加值的时候会先查看free的大小,如果free大于要追加的字符串长度,则间接执行追加操作。反之,API会先将SDS的free批改至追加值的长度后,再执行追加操作。扩大free的操作不须要手动,Redis会主动实现。 (三)、缩小批改字符串时的内存重调配次数在C字符串操作的时候,如果是拼接操作,须要先执行内存重调配来扩大底层数组空间的大小,而后执行拼接操作,如果遗记了内存充沛配会造成内存溢出。如果执行截断操作,须要在执行截断后,执行内存重调配来开释掉不在应用的内存空间,如果遗记了后一步操作就会造成内存透露。在Redis中,SDS通过未应用空间解除了字符串长度和底层数组长度的关联:buf的长度不肯定是存储的字符串长度加1,数组里蕴含着未应用的字节,这些字节的数量由free来记录。SDS解决C字符串问题提供了如下两个策略: 空间预调配空间预调配用于优化字符串增长的操作,当SDS的API须要对一个SDS批改,并且须要进行空间扩大的时候,程序不仅会为SDS调配须要应用的空间,还会为SDS调配额定的未应用的空间。如果批改之后SDS的长度len小于1M,程序会为SDS调配与len属性等值的额定空间;如果SDS批改之后长度len大于1M,程序会为SDS调配1M的额定内存空间。 通过空间预调配策略,Redis缩小了间断执行字符串增长带来的内存重调配次数,将C的N次升高到最多N次。惰性空间开释惰性空间开释用于优化字符串的缩短操作:当SDS的API须要缩短保留的字符串时,在执行缩短操作之后并不会间接开释因为缩短操作带来的多余空间,而是将这些空间长度记录到free中,留待未来应用,这样既缩小了内存重调配的次数,也为未来有可能增长的操作提供了优化。SDS还提供了API,在有须要的时候真正的开释SDS未应用的空间,这样就不会造成内存的节约。(四)、二进制平安C字符串中的字符必须合乎某种编码,并且除了字符串开端的空字符之外,字符串里不能蕴含空字符,否则会被程序误读为结尾,这些限度造成C字符串只能保留文本数据,而不能保留图片、音频、视频等二进制数据。在Redis中为了适应各种存储的场景,SDS的API都是二进制平安的(binary-safe),所有须要存储的数据都会被API以二进制的形式解决后在存储到buf中,不会对存储的数据类型做限度,所以是二进制平安的。

September 26, 2021 · 1 min · jiezi

关于redis:redis学习之六对象

这段时间打算梳理下redis相干的知识点,先从redis底层的数据结构与redisObject对象开始吧。在开展之前咱们须要先对redis的设计准则有一个大略的意识: 存储效率(memory efficiency),在谋求存储效率这一准则的前提下,redis才会有下面这些数据结构,并且会在某些场景下会交替应用这些数据结构,能够设想的到redis会在数据压缩、防止内存碎片方面下功夫。疾速响应(fast response),一般来说,单台redis可达到4W左右的QPS。因为数据是存在内存所以不会呈现磁盘IO(这也是redis不用应用多线程的一个起因),而redis的性能瓶颈次要是内存大小与网络带宽。正是有了底层这些非凡的数据结构撑持,才会有极快的贵响应。咱们都晓得redis里咱们常常应用的数据类型有: stringlisthashsetsorted set这五种(其它数据类型能够参看:redis文档),那底层的数据结构是如何撑持这五种数据类型的呢?从源码里能够看出,底层别离是: dictsdsziplistquicklistskiplist这些构造数据,不过,redis并没有间接应用这些数据结构来实现键值对,而是基于这些数据结构创立了一个对象零碎,这个零碎蕴含字符串对象、列表对象、哈希对象、汇合对象、和有序汇合对象,每种对象都会应用到至多一种下面提到的数据结构,具体是这样的: list:在同时满足上面两种状况下会应用ziplist:一是所有字符串长度小于64字节;二是元素数量小于512,不满足任一条件就会应用linkedlist(双端链表)。hash:在同时满足上面两种状况下会应用ziplist:一是所有键值对的键和值的字符串长度都小于64字节;二是键值对数量小于512个;不满足任意一个都应用hashtable编码。set:在同时满足上面两种状况下会应用intset:一是所有元素都是整数值;二是元素个数小于等于512个;不满足任意一条都将应用hashtable编码。zset:在同时满足上面两种状况下会应用ziplist:一是所有元素长度小于64字节;二是元素个数小于128个;不满足任意一条件将应用skiplist编码。这样做的目标有: 能够在执行命令之前,依据对象的类型来判断一个对象是否能够执行给定命令。能够针对不同的应用场景切换应用适合的数据结构。redisObject对象实现了基于援用计数的内存回收机制方便管理内存,同时在援用计数的根底上实现的对象共享机制也利于节约内存。每次咱们应用redis创立一个新的键值对时,至多会创立两个对象:一个是键对象一个是值对象。redisObject有三个属性别离为type属性、encoding属性、ptr属性: typedef struct redisObject { //类型 unsigned type:4; //编码 unsigned encoding:4; //指向底层实现数据结构的指针 void *ptr; //...} robj;type属性记录了对象的类型,其对应的值如下: 类型常量对象的名称REDIS_STRING字符串对象REDIS_LIST列表对象REDIS_HASH哈希对象REDIS_SET汇合对象REDIS_ZSET有序汇合对象咱们能够应用TYPE命令来查看值对象的类型。对于redis保留的键值来说,键总是一个字符串对象,而值则是下面提到的五种类型对象。 对象的ptr属性指针指向对象的底层实现数据结构,而这些数据结构由对象的encoding属性决定,encoding记录着对象所应用的编码,能够是上面的值: 编码常量编码对应底层的数据结构REDIS_ENCODING_INTlong类型的整数REDIS_ENCODING_EMBSTRembstr编码的简略动静字符串REDIS_ENCODING_RAW简略动静字符串REDIS_ENCODING_HT字典REDIS_ENCODING_LINKEDLIST双端链表REDIS_ENCODING_ZIPLIST压缩列表REDIS_ENCODING_INTSET整数汇合REDIS_ENCODING_SKIPLIST跳跃表值对象的编码咱们能够应用OBJECT命令进行查看。 总结:通过encoding属性来设定对象所应用的编码,而不是为特定类型的对象关联一种固定的编码,极大的晋升了灵活性与效率,redis能够依据不同的应用场景来抉择特定对象不同的的编码,从而晋升对应场景下的应用效率。 参考的文章有:黄健宏的《Redis设计与实现》一书张铁蕾对于redis的文章

September 25, 2021 · 1 min · jiezi

关于redis:redis学习之五ziplist

ziplist是redis为了进步内存使用率而结构的一种数据结构,它占用一整块间断的内存块,一般的链表在内存中是非间断的通过指针连贯,不过它的毛病是会产生内存碎片;而对于数组来说它也是占用一整块间断的内存空间,但所存的数据类型却只能是雷同的,ziplist的每个节点保留一个字节数组或者一个整数值。 咱们先来看下ziplist的组成部分:zlbytes:记录整个ziplist占用的内存字节数,在进行内存重新分配时或计算zllen地位是应用。zltail:记录ziplist尾节点到头节点的字节数,告诉它能够疾速定位到尾节点。zllen:记录ziplist蕴含的节点数量。entry:ziplist各节点,节点tayc由节点保留的内容决定。zlend:非凡值0xFF(十进制255),用于标识ziplist的末端。 再来看下entry的组成部分: previous_entry:记录前一个节点的长度,能够通过指针运算,依据以后节点起始地址计算出前一个节点的起始地址。encoding:保留数据的类型及长度。content:节点值能够是一个字节数组或整数,值的类型和长度由节点的encoding属性决定。看个示例:previous_entry_length值为0x05,阐明前一个节点长度为5。encoding值为00001011,高两位00阐明节点保留的是一个字节数组(11为整数类型);后六位为001011阐明字节数组长度是11。content:节点保留的内容。

September 25, 2021 · 1 min · jiezi

关于redis:redis学习之四skiplist

之前相关联文章:redis学习之一SDSredis学习之二链表redis学习之三字典 一 经典的skiplist 咱们先来看看skiplist的一张示意图:这是在一个有序列表{3,7,11,19,22,26,37}里查找23这个值的一个过程,它是从头节点的最上层开始,通过每个层的比拟判断来进行节点的定位。skiplist个性: 由多层组成。每一层都是有序的链表。最底层(Level 1)的链表蕴含所有元素。如果一个元素呈现在 Level i 的链表中,则它在 Level i 之下的链表也都会呈现。每个节点蕴含两个指针,一个指向同一链表中的下一个元素,一个指向上面一层的元素。skiplist是一种有序数据结构,反对均匀O(logN)、最坏O(n)复杂度的节点查找,其效率不低于均衡树,且skiplist的实现较于均衡树实现要更简略。redis应用skiplist次要是在有序汇合里。 skiplist定义 typedef struct zskiplist{ //表头节点和表尾节点 struct zskiplistNode *header,*tail; //表中节点数量 unsigned long length; //最大节点层数 int level;}zskiplist;二 redis里skiplist redis里skiplist定义: typeof struct zskiplistNode{ //后退节点,以后节点指向的前一个节点,从后向前遍历时应用 struct zskiplistNode *backward; //分值 double score; //成员对象 robj *obj; //层 strcut zskiplistLevle{ //后退指针 struct zskiplistNode *forward; //跨度 unsigned int span; }level[];}zskiplistNode; 阐明:图中是redis里应用通过革新过的skiplist,BW是后退指针;1.0/2.0/3.0是分值;o1/o2/o3是对象。redis里的skiplist与经典的skiplist之间的比拟,有如下特点: 分数(score)容许反复,也就是skiplist的key是充许反复的。大比拟过程中,须要比拟score也须要比拟数据自身。score雷同时,数据自身是按字典有序的。第一层是一个双向链表,不便由后向前遍历。跨度span是用来计算排位(rank)的:在查找某个节点的过程中,将沿途拜访过的所有层的跨度累计起来,失去的后果就是指标节点在skiplist中的排位。三 redis里的sorted set Redis中的sorted set,是在skiplist, dict和ziplist根底上构建起来的: 当数据较少时,sorted set是由一个ziplist来实现的。当数据多的时候,sorted set是由一个叫zset的数据结构来实现的,这个zset蕴含一个dict + 一个skiplist。dict用来查问数据到分数(score)的对应关系,而skiplist用来依据分数查问数据(可能是范畴查找)。本文参考的有:黄健宏的《Redis设计与实现》一书张铁蕾对于skiplist的文章其它文章

September 25, 2021 · 1 min · jiezi

关于redis:redis学习之三字典

之前相关联文章:redis学习之一SDSredis学习之二链表 一 字典相干的数据结构 哈希表定义: typedef struct dictht{ //哈希表数组 dictEntry **table; //哈希表大小 unsigned long size; //哈希表大小掩码,用于计算索引值,总是等于size -1 unsigned long sizemask; //该哈希表已有节点的数量 unsigned long used;}dictht;哈希表节点定义: typedef struct dictEntry{ //键 void *key; //值 union{ void *val; uint64_t u64; int64_t s64; }v; //指向下个哈希表节点,造成链表 struct dictEntry *next;}dictEntry;字典定义: typedef struct dict{ //类型函数 dictType *type; //公有数据 void *private; //哈希表 dictht ht[2]; //rehash索引,当rehash不再进行时值为-1, //每次进行rehash时,rehashidx的值就是对应ht[0]里dictht中dictEntry数组的索引 int rehashidx;}dict;上面是没有进行rehash的字典意识图: redis应用MurmurHash2算法来计算键的哈希值,应用链地址法解决键抵触。 rehash与渐进式rehash 二 扩容与缩容过程当哈希表保留的键值对数量太多或太少的时候,哈希表会进行扩大或膨胀。rehash的步骤如下: 为字典ht[1]调配空间。扩容:ht[1]的大小为第一个大于等于ht[0].used*2的2的n次幂;缩容:ht[1]的大小为第一个大于等于ht[0].used的2的n次幂。将保留在ht[0]中的所有键值对rehash到ht[1]下面,在这个过程中会从新计算键的哈希值与索引值。当ht[0]所有键值都迁徙到了ht[1]之后,开释ht[0],将ht[1]设置为ht[0],并在ht[1]新创建一个空白哈希表,为下次rehash做筹备。三 扩容与缩容的机会 服务器没有执行BGSAVE或BGREWRITEAOF命令,且哈希表的负载因子大于等于1。服务器正在执行BGSAVE或BGREWRITEAOF命令,且哈希表的负载因子大于等于5。哈希表的负载因子小于0.1。四 渐进式rehash 思考到redis服务性能,rehash并不是一次性集中进行而是分屡次渐进式进行的,步骤如下: 为ht[1]调配空间,让字典同时持有ht[0] ht[1]两个哈希表。将下面定义的dict构造里的rehashidx值设置为0,示意rehash开始进行。每次对字典进行增加、删除、查找或更新时,除了进行这些操作外,还会将ht[0]在rehashidx索引上的所有键值对rehash到ht[1],rehash的过程上中rehashidx值为增1。ht[0]里所有键值对rehash到ht[1]后,将rehashidx值置为-1,rehash完结。上面是两rehash的过程图:这个还没进行rehash,所以这里的rehashidx值为-1,留神ht[0]里dictEntry里的值。这里rehashidx值为3,这是在对ht[0]里dictEntry里第3个键值对(k1,v1)进行rehash。 ...

September 24, 2021 · 1 min · jiezi

关于redis:redis学习之二链表

之前相关联文章:redis学习之一SDS 链表数据结构 链表节点构造: typedef struct listNode{ //前置节点 struct listNode *prev; //后置节点 struct listNode *next; //节点的值 void *value;}listNode;链表构造: typedef struct list{ //表头节点 listNode *head; //表尾节点 listNode *tail; //链表所蕴含的节点数 unsigned long len; //节点值复制函数 void *(*dup)(void *ptr); //节点值开释函数 void *(*free)(void *ptr); //节点值比照函数 int (*match)(void *ptr,void *key);}list;链表提供了表头指针head、表尾指针tail,还有链表长度属性len,dup/free/match则是链表为实现特定性能的函数。 链表意识图: 链表的一些个性: 每个节点有指向前与后的节点指针,因而获取某节点的前后节点工夫复杂度为O(1)。表头的prev指针与表尾的next指针都指向NULL。有指向表头与表尾的指针,因而获取头尾节点时工夫复杂度为O(1)。链表有属性len记录链表长度,因而获取链表长度为O(1)。此文大部分内容都来自于黄健宏《Redis设计与实现》一书

September 24, 2021 · 1 min · jiezi

关于redis:redis学习之一SDS

redis里的SDS数据类型redis没有间接应用C语言里的字符串示意,而是本人构建名为简略动静字符串(simple dynamic string,SDS)的类型。在应用redis存储键值对时,不论值是什么类型,键的类型都是SDS,如果值是字符串类型时应用的就是SDS。 SDS的定义: struct sdshdr { //记录buf数组中已应用字节的数量,也就是SDS字符串所保留字符串的长度 int len; //记录buf数组中未应用字节的数量 int free; //字节数组,用于保留字符串 char buf[];};这个是在网上找的图,这里buf是char数组,我感觉应该是'R'|'e'|'d'|'i'|'s'|'\0'|才对,因为改不了在这里阐明一下。 free属性值为0,示意这个SDS没有调配任何未应用空间。如果这个值不为0,则在'\0'前面则会调配有空的区域,其长度为free的值。len属性值为5,示意这个SDS保留了一个五字节长的字符串。buf属性一个char数组,前五个字节别离保留了'R'/'e'/'d'/'i'/'s',最初一个字节则保留了示意空字符的'\0'。SDS遵循C字符串以空字符结尾的常规,保留空字符的1字节不计算在SDS的len属性里。SDS较C语言字符串的长处 常数复杂度获取字符串长度。因为有len属性记录着属性已应用字符串长度,所以在应用STRLEN命令获取长度的时候复杂度为O(1);而C语言字符串获取的工夫复杂度为O(n)。防止缓冲区溢出。SDS在进行批改或拼接前会查看空间是否满足批改所需长度,如果不够会进行扩容;而C语言没有长度查看会有溢出的可能。缩小内存重调配次数。C语言在在进行字符串的增长或缩短操作时,须要对应的进行内存申请与开释,不然会有溢出或透露的可能;而内存的重调配是一个较耗时的操作,SDS采纳了空间预调配与惰性空间开释这两种优化策略。二进制平安。C语言如果遇到空字符串时会被认为是字符串的完结,这使得其只能保留文本数据而像图片、视频文件等是没方法存储的;而SDS会以解决二进制的形式来解决寄存在buf数组里的数据用表格总结下: C字符串SDS获取字符串长度工夫复杂度为O(n)获取字符串长度工夫复杂度为O(1)有缓冲区溢出危险无溢出危险批改字符串N次时肯定须要执行屡次内存生调配批改字符串N次时最多须要执行屡次内存生调配只能存文本文本、图片、视频文件都能够存储

September 23, 2021 · 1 min · jiezi

关于redis:redis这几个常用的场景你都知道吗

1、缓存String类型 例如:热点数据缓存(例如报表、明星出轨),对象缓存、全页缓存、能够晋升热点数据的拜访数据。 2、数据共享分布式String 类型,因为 Redis 是分布式的独立服务,能够在多个利用之间共享 例如:分布式Session <dependency>  <groupId>org.springframework.session</groupId>  <artifactId>spring-session-data-redis</artifactId> </dependency>3、分布式锁String 类型setnx办法,只有不存在时能力增加胜利,返回true public static boolean getLock(String key) {    Long flag = jedis.setnx(key, "1");    if (flag == 1) {        jedis.expire(key, 10);    }    return flag == 1;}public static void releaseLock(String key) {    jedis.del(key);}4、全局IDint类型,incrby,利用原子性 incrby userid 1000 分库分表的场景,一次性拿一段 5、计数器int类型,incr办法 例如:文章的浏览量、微博点赞数、容许肯定的提早,先写入Redis再定时同步到数据库 6、限流int类型,incr办法 以访问者的ip和其余信息作为key,拜访一次减少一次计数,超过次数则返回false 7、位统计String类型的bitcount(1.6.6的bitmap数据结构介绍) 字符是以8位二进制存储的 set k1 asetbit k1 6 1setbit k1 7 0get k1 /* 6 7 代表的a的二进制位的批改a 对应的ASCII码是97,转换为二进制数据是01100001b 对应的ASCII码是98,转换为二进制数据是01100010因为bit十分节俭空间(1 MB=8388608 bit),能够用来做大数据量的统计。*/例如:在线用户统计,留存用户统计 setbit onlineusers 01 setbit onlineusers 11 setbit onlineusers 20反对按位与、按位或等等操作 BITOPANDdestkeykey[key...] ,对一个或多个 key 求逻辑并,并将后果保留到 destkey 。       BITOPORdestkeykey[key...] ,对一个或多个 key 求逻辑或,并将后果保留到 destkey 。 BITOPXORdestkeykey[key...] ,对一个或多个 key 求逻辑异或,并将后果保留到 destkey 。 BITOPNOTdestkeykey ,对给定 key 求逻辑非,并将后果保留到 destkey 。计算出7天都在线的用户 BITOP "AND" "7_days_both_online_users" "day_1_online_users" "day_2_online_users" ...  "day_7_online_users"8、购物车String 或hash。所有String能够做的hash都能够做 图片 key:用户id;field:商品id;value:商品数量。+1:hincr。-1:hdecr。删除:hdel。全选:hgetall。商品数:hlen。9、用户音讯工夫线timelinelist,双向链表,间接作为timeline就好了。插入有序 10、音讯队列List提供了两个阻塞的弹出操作:blpop/brpop,能够设置超时工夫 blpop:blpop key1 timeout 移除并获取列表的第一个元素,如果列表没有元素会阻塞列表直到期待超时或发现可弹出元素为止。brpop:brpop key1 timeout 移除并获取列表的最初一个元素,如果列表没有元素会阻塞列表直到期待超时或发现可弹出元素为止。下面的操作。其实就是java的阻塞队列。学习的货色越多。学习老本越低 队列:先进先除:rpush blpop,左头右尾,左边进入队列,右边出队列栈:先进后出:rpush brpop11、抽奖自带一个随机取得值 spop myset12、点赞、签到、打卡 图片 如果下面的微博ID是t1001,用户ID是u3001 用 like:t1001 来保护 t1001 这条微博的所有点赞用户 点赞了这条微博:sadd like:t1001 u3001勾销点赞:srem like:t1001 u3001是否点赞:sismember like:t1001 u3001点赞的所有用户:smembers like:t1001点赞数:scard like:t1001是不是比数据库简略多了。 ...

September 22, 2021 · 1 min · jiezi

关于redis:Redis之常用的十几种使用场景

起源:https://blog.csdn.net/qq\_39938758/article/details/105577370 1、缓存String类型例如:热点数据缓存(例如报表、明星爆料)、对象缓存、全页缓存等 2、数据共享分布式String 类型,因为 Redis 是分布式的独立服务,能够在多个利用之间共享例如:分布式Session <dependency>   <groupId>org.springframework.sessiongroupId>   <artifactId>spring-session-data-redisartifactId> </dependency>  3、分布式锁String 类型 setnx办法,只有不存在时能力增加胜利,返回truepublic static boolean getLock(String key) {    Long flag = jedis.setnx(key, "1");    if (flag == 1) {        jedis.expire(key, 10);    }    return flag == 1;}public static void releaseLock(String key) {    jedis.del(key);}4、全局IDint类型,incrby,利用原子性incrby userid 1000分库分表的场景,一次性拿一段 5、计数器int类型,incr办法例如:文章的浏览量、微博点赞数、容许肯定的提早,先写入Redis再定时同步到数据库 Redis相干电子书,在公众号后盾回复“书单”即可获取。 6、限流int类型,incr办法以访问者的ip和其余信息作为key,拜访一次减少一次计数,超过次数则返回false 7、位统计String类型的bitcount,字符是以8位二进制存储的set k1 asetbit k1 6 1setbit k1 7 0get k1 /* 6 7 代表的a的二进制位的批改a 对应的ASCII码是97,转换为二进制数据是01100001b 对应的ASCII码是98,转换为二进制数据是01100010因为bit十分节俭空间(1 MB=8388608 bit),能够用来做大数据量的统计。*/例如:在线用户统计,留存用户统计 setbit onlineusers 0 1 setbit onlineusers 1 1 setbit onlineusers 2 0反对按位与、按位或等等操作 BITOP AND destkey key[key...] ,对一个或多个 key 求逻辑并,并将后果保留到 destkey 。       BITOP OR destkey key[key...] ,对一个或多个 key 求逻辑或,并将后果保留到 destkey 。 BITOP XOR destkey key[key...] ,对一个或多个 key 求逻辑异或,并将后果保留到 destkey 。 BITOP NOT destkey key ,对给定 key 求逻辑非,并将后果保留到 destkey 。计算出7天都在线的用户 BITOP AND "7_days_both_online_users" "day_1_online_users" "day_2_online_users" ...  "day_7_online_users"8、购物车String 或 hash。所有String能够做的hash都能够做 key:用户id;field:商品id;value:商品数量。+1:hincr。-1:hdecr。删除:hdel。全选:hgetall。商品数:hlen。9、用户音讯工夫线timelinelist,双向链表,间接作为timeline就好了。插入有序10、音讯队列List提供了两个阻塞的弹出操作:blpop/brpop,能够设置超时工夫blpop:blpop key1 timeout 移除并获取列表的第一个元素,如果列表没有元素会阻塞列表直到期待超时或发现可弹出元素为止。 brpop:brpop key1 timeout 移除并获取列表的最初一个元素,如果列表没有元素会阻塞列表直到期待超时或发现可弹出元素为止。 PS:下面的操作,其实就是java的阻塞队列。到前面你会发现,学习的货色越多,学习老本越低队列:先进先出:rpush blpop,左头右尾,左边进入队列,右边出队列 栈:先进后出:rpush brpop 11、抽奖自带一个随机取得值spop myset12、点赞、签到、打卡 如果下面的微博ID是t1001,用户ID是u3001 用 like:t1001 来保护 t1001 这条微博的所有点赞用户 ...

September 19, 2021 · 1 min · jiezi

关于redis:Redis核心原理与实践列表实现原理之quicklist结构

在上一篇文章《Redis列表实现原理之ziplist构造》,咱们剖析了ziplist构造如何应用一块残缺的内存存储列表数据。同时也提出了一个问题:如果链表很长,ziplist中每次插入或删除节点时都须要进行大量的内存拷贝,这个性能是无奈承受的。本文剖析quicklist构造如何解决这个问题,并实现Redis的列表类型。 quicklist的设计思维很简略,将一个长ziplist拆分为多个短ziplist,防止插入或删除元素时导致大量的内存拷贝。 ziplist存储数据的模式更相似于数组,而quicklist是真正意义上的链表构造,它由quicklistNode节点链接而成,在quicklistNode中应用ziplist存储数据。 提醒:本文以下代码如无非凡阐明,均位于quicklist.h/quicklist.c中。本文以下说的“节点”,如无非凡阐明,都指quicklistNode节点,而不是ziplist中的节点。定义quicklistNode的定义如下: typedef struct quicklistNode { struct quicklistNode *prev; struct quicklistNode *next; unsigned char *zl; unsigned int sz; unsigned int count : 16; unsigned int encoding : 2; unsigned int container : 2; unsigned int recompress : 1; unsigned int attempted_compress : 1; unsigned int extra : 10; } quicklistNode;prev、next:指向前驱节点,后驱节点。zl:ziplist,负责存储数据。sz:ziplist占用的字节数。count:ziplist的元素数量。encoding:2代表节点已压缩,1代表没有压缩。container:目前固定为2,代表应用ziplist存储数据。recompress:1代表临时解压(用于读取数据等),后续须要时再将其压缩。extra:预留属性,暂未应用。当链表很长时,两头节点数据拜访频率较低。这时Redis会将两头节点数据进行压缩,进一步节俭内存空间。Redis采纳是无损压缩算法—LZF算法。 压缩后的节点定义如下: typedef struct quicklistLZF { unsigned int sz; char compressed[];} quicklistLZF;sz:压缩后的ziplist大小。compressed:寄存压缩后的ziplist字节数组。quicklist的定义如下: typedef struct quicklist { quicklistNode *head; quicklistNode *tail; unsigned long count; unsigned long len; int fill : QL_FILL_BITS; unsigned int compress : QL_COMP_BITS; unsigned int bookmark_count: QL_BM_BITS; quicklistBookmark bookmarks[];} quicklist;head、tail:指向头节点、尾节点。count:所有节点的ziplist的元素数量总和。len:节点数量。fill:16bit,用于判断节点ziplist是否已满。compress:16bit,寄存节点压缩配置。quicklist的构造如图2-5所示。 ...

September 19, 2021 · 2 min · jiezi

关于redis:redis-七redis之Hash

redis系列文章: https://liudongdong.top/categ... 本篇起源: https://liudongdong.top/archi... 公众号:雨中散步撒哈拉 备注:欢送关注公众号,一起学习,共同进步! 一、基本概念Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特地适宜用于存储对象。 Redis 中每个 hash 能够存储 232 - 1 键值对(40多亿)。 hash类型能够了解为map汇合,{key1:value1,key2:value2} 实例 127.0.0.1:6379> hmset map name liudd age 2 sex manOK127.0.0.1:6379> hgetall map1) "name"2) "liudd"3) "age"4) "2"5) "sex"6) "man"127.0.0.1:6379> Hash 的利用场景: 将一个用户作为一个 hash ,而后其属性和值就作为外部的 k-v 汇合进行存储 例如 hmset user:1 name 张 age 18 job stuuser:1 代表第 1 个用户,而后这个用户具备 name,age,job 这些字段,因为 redis 效率很高,因而适宜将属性值常常变动的对象作为 hash 存储 二、命令分类集体了解和便于学习,进行了简略分类! 分为以下几类: 减少映射删除映射查问映射特有命令1. 减少命令hset:设置一个key中的属性映射hsetnx:属性映射不存在,则创立胜利hmset:批量设置属性映射2. 删除映射hdel:删除一个或多个属性字段3. 查问映射hget:查问一个key的属性映射hmget:查问多个key对应的属性映射hgetall:查问指定的key中所有的属性映射和值hexists:判断属性值是否存在hlen:统计汇合有多少个属性hkeys:列出所有的key的属性hvals:列出所有的属性对应的value4. 特有命令incrby:指定属性减少整数增量incrbyfloat:指定属性减少浮点型增量三、命令实际1. 减少映射127.0.0.1:6379> keys *(empty list or set)# 设置属性name127.0.0.1:6379> hset map name liudd(integer) 1127.0.0.1:6379> hgetall map1) "name"2) "liudd"# 批量设置属性127.0.0.1:6379> hmset map age 2 sex manOK127.0.0.1:6379> hgetall map1) "name"2) "liudd"3) "age"4) "2"5) "sex"6) "man"# 属性ff不存在,则创立胜利,反之存在则失败127.0.0.1:6379> hsetnx map ff vv(integer) 1127.0.0.1:6379> hgetall map1) "name"2) "liudd"3) "age"4) "2"5) "sex"6) "man"7) "ff"8) "vv"127.0.0.1:6379> hsetnx map ff xx(integer) 0127.0.0.1:6379> hgetall map1) "name"2) "liudd"3) "age"4) "2"5) "sex"6) "man"7) "ff"8) "vv"127.0.0.1:6379>2. 删除映射127.0.0.1:6379> hgetall map1) "name"2) "liudd"3) "age"4) "2"5) "sex"6) "man"7) "ff"8) "vv"# 删除属性ff127.0.0.1:6379> hdel map ff(integer) 1127.0.0.1:6379> hgetall map1) "name"2) "liudd"3) "age"4) "2"5) "sex"6) "man"127.0.0.1:6379> 3. 查问映射# 查问所有属性和值127.0.0.1:6379> hgetall map1) "name"2) "liudd"3) "age"4) "2"5) "sex"6) "man"# 查问map汇合key-value有多少对127.0.0.1:6379> hlen map(integer) 3# 查问属性name值127.0.0.1:6379> hget map name"liudd"# 批量查问属性值127.0.0.1:6379> hmget map name age sex1) "liudd"2) "2"3) "man"# 查问key的列表127.0.0.1:6379> hkeys map1) "name"2) "age"3) "sex"# 查问value的列表127.0.0.1:6379> hvals map1) "liudd"2) "2"3) "man"# 查问ff属性是否存在127.0.0.1:6379> hexists map ff(integer) 0127.0.0.1:6379> hexists map name(integer) 1127.0.0.1:6379>4. 特有命令127.0.0.1:6379> hgetall map1) "name"2) "liudd"3) "age"4) "2"5) "sex"6) "man"# age属性减少整数7127.0.0.1:6379> hincrby map age 7(integer) 9127.0.0.1:6379> hgetall map1) "name"2) "liudd"3) "age"4) "9"5) "sex"6) "man"# age属性减少浮点型1.5127.0.0.1:6379> hincrbyfloat map age 1.5"10.5"127.0.0.1:6379> hgetall map1) "name"2) "liudd"3) "age"4) "10.5"5) "sex"6) "man"127.0.0.1:6379>附录下表列出了 redis hash 根本的相干命令: 序号命令及形容1[HDEL key field1 field2] 删除一个或多个哈希表字段2HEXISTS key field 查看哈希表 key 中,指定的字段是否存在。3HGET key field 获取存储在哈希表中指定字段的值。4HGETALL key 获取在哈希表中指定 key 的所有字段和值5HINCRBY key field increment 为哈希表 key 中的指定字段的整数值加上增量 increment 。6HINCRBYFLOAT key field increment 为哈希表 key 中的指定字段的浮点数值加上增量 increment 。7HKEYS key 获取所有哈希表中的字段8HLEN key 获取哈希表中字段的数量9[HMGET key field1 field2] 获取所有给定字段的值10[HMSET key field1 value1 field2 value2 ] 同时将多个 field-value (域-值)对设置到哈希表 key 中。11HSET key field value 将哈希表 key 中的字段 field 的值设为 value 。12HSETNX key field value 只有在字段 field 不存在时,设置哈希表字段的值。13HVALS key 获取哈希表中所有值。14HSCAN key cursor [MATCH pattern] [COUNT count] 迭代哈希表中的键值对。更多命令请参考:https://redis.io/commands ...

September 16, 2021 · 1 min · jiezi

关于redis:Redis的Keyspace-notifications功能

Redis的Keyspace notifications性能1. 引入背景公司外部有一套通信零碎,用于做内网和和外网的微服务网络买通(通过建设socket连贯);为了保护通信的稳固在通信终端中断时候疾速持续报警或者重连,所以打算客户端引入了心跳包机制,定期向服务端推送心跳包。 开始的时候咱们通过定时器轮询轮询服务最初的心跳工夫,进行判断连贯是否断开: 然而前面咱们发现这样的做法还是有点不好的中央: 当保留Map的连贯对象(即保护的连接数变大后),遍历一次的工夫开始缓缓变长,从而导致实时性变差定时器的工夫不好设置,设置太快了性能就义太大了,太慢了实时性也升高了所以咱们尝试寻找一个第三方服务,能够实现到过期后主动触发一个事件。 这个咱们想到了2个方向:通过mq做延时队列;redis 的事件推送性能;咱们抉择了后者。 2. Redis的Keyspace notifications性能介绍在Redis 2.8.0版本起,退出了“Keyspace notifications”(即“键空间告诉”)的性能。官网形容: 键空间告诉,容许Redis客户端从“公布/订阅”通道中建设订阅关系,以便客户端可能在Redis中的数据因某种形式受到影响时收到相应事件。 其实依据形容咱们并不难理解: 当redis中某个key产生了某种变动(某个事件),零碎会将这个事件推送到咱们指定的事件监听的过程中; 回归上述背景: 如果咱们把心跳放到redis中缓存起来,通过订阅关系,当key 过期时候,redis会推送一条信息到事件监听的客户端;而后通过剖析音讯能够得悉何种音讯,剖析音讯内容能够晓得是哪个key生效了。这样就能够间接实现结尾所形容的性能。 3. Redis的Keyspace notifications性能应用Keyspace notifications 性能默认是敞开的(默认地,Keyspace 工夫告诉性能是禁用的,因为它或多或少会应用一些CPU的资源),咱们须要关上它。关上的办法也很简略,配置属性:notify-keyspace-events redis.conf notify-keyspace-events Ex批改配置后,重启redis服务 增加过期事件订阅 开启一个终端,redis-cli 进入 redis 。开始订阅所有操作,期待接管音讯。 vagrant@homestead  ~  redis-cli127.0.0.1:6379> psubscribe __keyevent@0__:expiredReading messages... (press Ctrl-C to quit)1) "psubscribe"2) "__keyevent@0__:expired"3) (integer) 1再开启一个终端,redis-cli 进入 redis,新增一个 20秒过期的键: 127.0.0.1:6379> SETEX test 123 20OK另外一边执行了阻塞订阅操作后的终端,20秒过期后有如下信息输入: 1) "pmessage"2) "__keyevent@0__:expired"3) "__keyevent@0__:expired"4) "test"阐明:阐明对过期Key信息的订阅是胜利的。 4. 用golang写了个简略监听Demopackage mainimport ( "fmt" "github.com/gomodule/redigo/redis" "strconv" "time" "unsafe")type PSubscribeCallback func (pattern, channel, message string)type PSubscriber struct { client redis.PubSubConn cbMap map[string]PSubscribeCallback}func PConnect(ip, password string, port uint16) redis.Conn { conn, err := redis.Dial("tcp", ip + ":" + strconv.Itoa(int(port))) if err != nil { print("redis dial failed.") } conn.Do("AUTH",password) return conn}func (c *PSubscriber) ReceiveKeySpace(conn redis.Conn) { c.client = redis.PubSubConn{conn} c.cbMap = make(map[string]PSubscribeCallback) go func() { for { switch res := c.client.Receive().(type) { case redis.Message: pattern := &res.Pattern channel := &res.Channel message := (*string)(unsafe.Pointer(&res.Data)) c.cbMap[*channel](*pattern, *channel, *message) case redis.Subscription: fmt.Printf("%s: %s %d\n", res.Channel, res.Kind, res.Count) case error: print("error handle...") continue } } }()}const expired = "__keyevent@0__:expired"func (c *PSubscriber)Psubscribe() { err := c.client.PSubscribe(expired) if err != nil{ print("redis Subscribe error.") } c.cbMap[expired] = PubCallback}func PubCallback(patter , channel, msg string){ print( "PubCallback patter : " + patter + " channel : ", channel, " message : ", msg) // TODO:拿到msg后进行后续的业务代码}func main() { var sub PSubscriber conn := PConnect("192.168.11.213","", 6379) sub.ReceiveKeySpace(conn) sub.Psubscribe() for{ time.Sleep(time.Second) }}5. Redis的Keyspace notifications性能注意事项1. 过期事件:当某个命令拜访该密钥并发现该密钥已过期时。通过后盾零碎,在后盾逐渐查找过期密钥,以便可能收集从未拜访过的密钥。官网文档可知 ...

September 14, 2021 · 2 min · jiezi

关于redis:Linux环境下安装redis

一、筹备工作下载 redis 安装包, 放到 root 目录外面下载地址在 /usr/local/ 下创立 redis ⽂件夹并进⼊ cd /usr/local/mkdir rediscd redis将 redis 安装包解压到 /usr/local/redis tar -zxvf /root/redis-6.2.5.tar.gz -C ./解压完之后, /usr/local/redis ⽬录中会呈现⼀个 redis-6.2.5 的⽬录 二、编译装置编译并装置 cd redis-6.2.5make && make install三、将redis服务装置零碎服务并后盾启动进⼊ utils ⽬录,并执⾏上面命令 cd utils/./install_server.sh这步可能会报错 Welcome to the redis service installerThis script will help you easily set up a running redis serverThis systems seems to use systemd.Please take a look at the provided example service unit files in this directory, and adapt and install them. Sorry!正文上面的代码 vim install_server.sh ...

September 14, 2021 · 2 min · jiezi

关于redis:redis-六redis之Set

redis系列文章: https://liudongdong.top/categ... 本篇起源: https://liudongdong.top/archi... 公众号:雨中散步撒哈拉 备注:欢送关注公众号,一起学习,共同进步! 一、基本概念Redis 的 Set 是 String 类型的无序汇合。汇合成员是惟一的,这就意味着汇合中不能呈现反复的数据。 汇合对象的编码能够是 intset 或者 hashtable。 Redis 中汇合是通过哈希表实现的,所以增加,删除,查找的复杂度都是 O(1)。 汇合中最大的成员数为 232 - 1 (4294967295, 每个汇合可存储40多亿个成员)。 实例: 127.0.0.1:6379> sadd sets one two three(integer) 3127.0.0.1:6379> smembers sets1) "three"2) "one"3) "two"127.0.0.1:6379>二、Set分类依据集体了解和便于学习,进行了简略的分类! 大抵分为以下几类: 减少成员删除成员批改成员查问成员汇合操作1. 减少成员sadd:减少成员2. 删除成员spop:移除随机成员srem:移除指定成员3. 批改成员命令smove:挪动成员到另一个汇合中4. 查问成员scard:查问成员总数sismember:查问该成员是否存在smembers:查问所有成员srandmember:返回汇合一个或多个随机数5. 汇合操作sdiff:俩个汇合之间的差集sdiffstore:俩个汇合之间的差集,后果放到新的set中sinter:俩个汇合之间的交加sinterstore:俩个汇合之间的交加,后果放到新的set中sunion:俩个汇合之间的并集sunionstore:俩个汇合之间的并集,后果放到新的set中三、命令实际1. 减少成员127.0.0.1:6379> sadd sets one two three(integer) 3127.0.0.1:6379> smembers sets1) "three"2) "one"3) "two"127.0.0.1:6379>2. 删除成员127.0.0.1:6379> smembers sets1) "three"2) "one"3) "two"# 删除一个或多个随机值127.0.0.1:6379> spop sets 11) "three"127.0.0.1:6379> smembers sets1) "one"2) "two"# 移除指定成员127.0.0.1:6379> srem sets one(integer) 1127.0.0.1:6379> smembers sets1) "two"127.0.0.1:6379>3. 批改成员127.0.0.1:6379> smembers sets1) "two"127.0.0.1:6379> sadd sets2 a(integer) 1127.0.0.1:6379> smembers sets21) "a"# 批改成员,到新的汇合中127.0.0.1:6379> smove sets sets2 two(integer) 1127.0.0.1:6379> smembers sets21) "a"2) "two"127.0.0.1:6379> smembers sets(empty list or set)127.0.0.1:6379> 4. 查问成员# 查问成员总数127.0.0.1:6379> scard sets2(integer) 2# 查问汇合所有成员127.0.0.1:6379> smembers sets21) "a"2) "two"# 判断成员是否存在汇合中127.0.0.1:6379> sismember sets2 one(integer) 0127.0.0.1:6379> sismember sets2 two(integer) 1# 返回汇合中的一个或多个值127.0.0.1:6379> srandmember sets2 11) "two"127.0.0.1:6379> srandmember sets2 11) "two"127.0.0.1:6379> srandmember sets2 21) "a"2) "two"127.0.0.1:6379>5. 汇合操作1. 差集Redis Sdiff 命令返回第一个汇合与其余汇合之间的差别,也能够认为说第一个汇合中独有的元素。不存在的汇合 key 将视为空集。 差集的后果来自后面的 FIRST\_KEY ,而不是前面的 OTHER\_KEY1,也不是整个 FIRST\_KEY OTHER\_KEY1..OTHER\_KEYN 的差集。 127.0.0.1:6379> smembers sets1) "c"2) "a"3) "b"127.0.0.1:6379> smembers sets21) "a"2) "two"127.0.0.1:6379> sdiff sets sets21) "c"2) "b"127.0.0.1:6379> sadd sets3 1(integer) 1127.0.0.1:6379> sdiffstore sets3 sets sets2(integer) 2127.0.0.1:6379> smembers sets31) "c"2) "b"127.0.0.1:6379>2. 交加Redis Sinter 命令返回给定所有给定汇合的交加。不存在的汇合 key 被视为空集。当给定汇合当中有一个空集时,后果也为空集(依据汇合运算定律)。 127.0.0.1:6379> smembers sets1) "c"2) "a"3) "b"127.0.0.1:6379> smembers sets21) "a"2) "two"127.0.0.1:6379> smembers sets31) "c"2) "b"127.0.0.1:6379> sinter sets sets21) "a"127.0.0.1:6379> sinterstore sets3 sets sets2(integer) 1127.0.0.1:6379> smembers sets31) "a"127.0.0.1:6379>3. 并集Redis Sunion 命令返回给定汇合的并集。不存在的汇合 key 被视为空集。 127.0.0.1:6379> smembers sets1) "c"2) "a"3) "b"127.0.0.1:6379> smembers sets21) "a"2) "two"127.0.0.1:6379> smembers sets31) "a"127.0.0.1:6379> sunion sets sets21) "a"2) "c"3) "two"4) "b"127.0.0.1:6379> sunionstore sets3 sets sets2(integer) 4127.0.0.1:6379> smembers sets31) "a"2) "c"3) "two"4) "b"127.0.0.1:6379>附录下表列出了 Redis 汇合根本命令: 序号命令及形容1[SADD key member1 member2] 向汇合增加一个或多个成员2SCARD key 获取汇合的成员数3[SDIFF key1 key2] 返回第一个汇合与其余汇合之间的差别。4[SDIFFSTORE destination key1 key2] 返回给定所有汇合的差集并存储在 destination 中5[SINTER key1 key2] 返回给定所有汇合的交加6[SINTERSTORE destination key1 key2] 返回给定所有汇合的交加并存储在 destination 中7SISMEMBER key member 判断 member 元素是否是汇合 key 的成员8SMEMBERS key 返回汇合中的所有成员9SMOVE source destination member 将 member 元素从 source 汇合挪动到 destination 汇合10SPOP key 移除并返回汇合中的一个随机元素11[SRANDMEMBER key count] 返回汇合中一个或多个随机数12[SREM key member1 member2] 移除汇合中一个或多个成员13[SUNION key1 key2] 返回所有给定汇合的并集14[SUNIONSTORE destination key1 key2] 所有给定汇合的并集存储在 destination 汇合中15SSCAN key cursor [MATCH pattern] [COUNT count] 迭代汇合中的元素

September 14, 2021 · 1 min · jiezi

关于redis:redis-九redis之Geospatial

redis系列文章: https://liudongdong.top/categ... 本篇起源: https://liudongdong.top/archi... 公众号:雨中散步撒哈拉 备注:欢送关注公众号,一起学习,共同进步! 一、基本概念Geospatial类型,底层实现原理实现为zset类型!1. 应用什么样的地球模型(Earth model)?这只是假如地球是一个球体,因为应用的间隔公式是Haversine公式。这个公式仅实用于地球,而不是一个完满的球体。当在社交网站和其余大多数须要查问半径的利用中应用时,这些偏差都不算问题。然而,在最坏的状况下的偏差可能是0.5%,所以一些地理位置很要害的利用还是须要审慎思考。 2. 它是如何工作的?sorted set应用一种称为Geohash的技术进行填充。经度和纬度的位是交织的,以造成一个独特的52位整数. 咱们晓得,一个sorted set 的double score能够代表一个52位的整数,而不会失去精度。 这种格局容许半径查问查看的1 + 8个畛域须要笼罩整个半径,并抛弃元素以外的半径。通过计算该区域的范畴,通过计算所涵盖的范畴,从不太重要的局部的排序集的得分,并计算得分范畴为每个区域的sorted set中的查问。 GeoHash是一种地址编码方法。他可能把二维的空间经纬度数据编码成一个字符串 3. 能够做什么?查问某个坐标左近的坐标(左近的人性能)查问两点间的间隔……二、命令实际因为geo命令过少,不进行了分类,残缺命令请看官网,本篇命令请看附录! 中国诚恳坐标经纬度查问,进行查问中国城市具体坐标! 1. geoadd 增加经纬元素将指定的天文空间地位(纬度、经度、名称)增加到指定的key中。这些数据将会存储到sorted set这样的目标是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查问等操作。 该命令以采纳规范格局的参数x,y,所以经度必须在纬度之前。这些坐标的限度是能够被编入索引的,区域面积能够很靠近极点然而不能索引。具体的限度,由EPSG:900913 / EPSG:3785 / OSGEO:41001 规定如下: 无效的经度从-180度到180度。 无效的纬度从-85.05112878度到85.05112878度。 当坐标地位超出上述指定范畴时,该命令将会返回一个谬误。 返回值 增加到sorted set元素的数目,但不包含已更新score的元素。 127.0.0.1:6379> geoadd china 116.408 39.904 beijing(integer) 1127.0.0.1:6379> geoadd china 121.445 31.213 shanghai 117.246 39.117 tianjing(integer) 2127.0.0.1:6379> zrange china 0 -11) "shanghai"2) "tianjing"3) "beijing"127.0.0.1:6379>2. geodist获取俩个元素之间直线间隔如果两个地位之间的其中一个不存在, 那么命令返回空值。 指定单位的参数 unit 必须是以下单位的其中一个: m 示意单位为米。km 示意单位为千米。mi 示意单位为英里。ft 示意单位为英尺。 如果用户没有显式地指定单位参数, 那么 GEODIST 默认应用米作为单位。GEODIST 命令在计算间隔时会假如地球为完满的球形, 在极限状况下, 这一假如最大会造成 0.5% 的误差。 返回值 计算出的间隔会以双精度浮点数的模式被返回。如果给定的地位元素不存在, 那么命令返回空值。 127.0.0.1:6379> zrange china 0 -11) "shanghai"2) "tianjing"3) "beijing"127.0.0.1:6379> geodist china beijing shanghai m"1068232.0171"127.0.0.1:6379> geodist china beijing shanghai km"1068.2320"127.0.0.1:6379>3. geopos获取指定元素经纬度从key里返回所有给定地位元素的地位(经度和纬度)。 给定一个sorted set示意的空间索引,密集应用 geoadd 命令,它以取得指定成员的坐标往往是无益的。当空间索引填充通过 geoadd 的坐标转换成一个52位Geohash,所以返回的坐标可能不齐全以增加元素的,但小的谬误可能会出台。 ...

September 14, 2021 · 2 min · jiezi

关于redis:redis-系列高可用

前言Redis 作为最罕用的 key-value 服务,始终为咱们带来了高性能的保障。但程序嘛,总不可能始终运行上来,而咱们所要做的就是将这些危险降到最低。 所以,高可用也是 Redis 必然要思考的了,而随着 Redis 的宽泛应用,市面上也呈现了有很多高可用计划。明天,就来好好意识下这些计划,或者也能够为咱们本人的程序带来灵感。 高可用机制Redis 的高可用从总体上来讲是通过 冗余 + 故障转移 来实现的,而对于冗余和故障转移又能够细化为:全副冗余或局部冗余;手动转移或主动转移。 全副冗余+手动转移的计划就是咱们最相熟的主从模式了;当手动转移变为主动转移时即哨兵模式。最初局部冗余 + 主动转移则是集群模式。 因为 Redis 不像 mysql,在数据的完整性、一致性上是没有比拟好的保障的,所以当咱们在应用高可用计划时,对数据的一致性就冀望不了那么高了,这是须要提前留神的。 主从模式主从模式在高可用计划中是最罕用的一种。往往咱们会在不同的机器上部署着同一 Redis 程序。在这多台机器里,咱们会抉择一个节点作为主节点,它负责数据的写入。其余节点作为从节点,定时的和主节点同步数据。一旦主节点不能应用了,那么就能够在从节点中筛选一个作为主节点,从新上岗服务。 主从模式往往还能进行读写拆散,将读取数据的压力扩散到多个从节点上。 在 Redis 进行主从数据同步时,会执行 bgsave 命令以生成 RDB 文件,同时会在缓冲区记录增量的命令。 当 Redis 将 RDB 文件同步给 Slave 后,会再次的将缓冲区的增量命令发送给从节点,从节点接管到这些数据后,就能够复原到内存里了。 从节点除了复原数据外,它还保护了一个复制偏移量,示意主节点向从节点传递命令的字节总数。这个复制偏移量会定时同步给主节点。 而主节点也有属于本人的一个写入偏移量,有了这 2 个参数后,主节点就晓得要进行局部复制还是要全量复制了。 主从模式在呈现故障时,须要人为进行干涉,而且从节点一多,主节点的同步压力就会很大了。 哨兵模式下面的主从模式须要人工的进行故障节点切换,这种形式对于谋求完满的程序员来说,必定是不够的。所以有了主动切换的哨兵模式。 哨兵模式次要实现了上面几个性能: 监控:一直的检测主从节点是否能失常工作。主动转移故障:当某个 master 不能失常工作时,Sentinel 会启动一个故障转移过程,将其中的一个正本晋升为 master,并告诉其余从节点对应新的 master 相干信息。告诉:当某个节点出问题时,会告知所有节点。如果是新的主节点被选举进去,还会告知已连贯过去的客户端程序对于主节点新的地址。在哨兵模式中,会有一个或多个哨兵程序,对以后的 Redis 集群进行监控。哨兵服务之间通过 gossip 协定进行通信。当须要进行故障转移时,会通过选举算法,选出一个 leader 来主导过程。 而这也意味着,Sentinel 程序不能选举出 leader 的话,则不能继续执行后续动作了。包含客户端的申请,也会被阻塞住。 集群主从模式和哨兵模式都会在多台机器中存储着同一份数据,这样对于内存的利用率并不高。如果可能将数据扩散到各个节点上,同时配上主从模式,那么就能高效应用内存了。集群就是这么个机制。 Redis 的集群采纳了哈希槽的概念,总共会有 16384 个哈希槽。这些哈希槽会被调配到各个节点上,比方: ...

September 13, 2021 · 1 min · jiezi

关于redis:redis-系列持久化机制

长久化机制只管 Redis 是基于内存的 key-value 服务,但也能够进行数据的长久化,以便服务重启,数据能从新加载进来。 为了尽可能的保证数据不失落,Redis 为咱们提供了好几种长久化机制: RDB:即 Redis Database,在指定的工夫距离里将 Redis 内存数据镜像下来,保留到文件里。AOF:将服务器对数据的写操作追加到文件里,相当于将所有的逻辑操作都记录了下来。无持久性:不进行长久化,性能最好。RDB + AOF:将 RDB 和 AOF 联合起来,组合它们各自的长处。上面,咱们来看看这些机制吧。 RDB 配置在 redis.conf 文件里咱们能够针对 RDB 长久化形式进行设置: ### 快照设置 #### save "" 空示意不进行长久化save 900 1 # 900 秒内如果有1个 key 值扭转,则进行长久化动作save 300 10 # 300 秒内如果有10个 key 值扭转,则进行长久化动作save 60 10000 # 60 秒内如果有10000个 key 值扭转,则进行长久化动作# 如果长久化失败,则 Redis 不会再进行数据更新操作,直到恢复正常stop-writes-on-bgsave-error yes# 是否对长久化的 rdb 文件进行压缩保留rdbcompression yes# 是否对长久化的 rdb 文件进行校验rdbchecksum yes# 要长久化的 rdb 文件名dbfilename example.rdb# 导出目录dir /opt/redisdataRDB 劣势当 Redis 进行长久化动作时,它会先 fork 一个子过程,将数据的写入交给子过程,而父过程不会波及到磁盘的 IO 操作,所以 RDB 的性能十分好。如果是在 Unix 零碎上,还能充分利用写时复制机制。也就是子过程和父过程共用雷同的内存页面,只有当子过程或父过程进行批改才会进行复制。这样节俭了对物理内存的应用。因为 RDB 文件只存储了某个时刻的内存数据,并没有什么逻辑命令,所以在进行重启复原时,能很快的加载进来。RDB 毛病尽管 RDB 的 fork 能使得 Redis 的长久化独立进行,然而一旦数据量比拟大的,就会始终占用 CPU,可能会影响到父过程的进行。后面的 RDB 配置里咱们提到是按肯定的工夫距离内去触发长久化的,但也正是因为这个工夫距离起因,导致咱们将会有肯定概率在这段时间内失落数据。AOF 配置同样的,咱们能够在 redis.conf 文件里对 AOF 长久化进行配置: ...

September 12, 2021 · 1 min · jiezi

关于redis:Redis核心原理与实践列表实现原理之ziplist

Redis列表类型能够存储一组按插入程序排序的字符串,它非常灵活,反对在两端插入、弹出数据,能够充当栈和队列的角色。 > LPUSH fruit apple(integer) 1> RPUSH fruit banana(integer) 2> RPOP fruit"banana"> LPOP fruit"apple"本文探讨Redis中列表类型的实现。 ziplist应用数组和链表构造都能够实现列表类型。Redis中应用的是链表构造。上面是一种常见的链表实现形式adlist.h: typedef struct listNode { struct listNode *prev; struct listNode *next; void *value;} listNode;typedef struct list { listNode *head; listNode *tail; void *(*dup)(void *ptr); void (*free)(void *ptr); int (*match)(void *ptr, void *key); unsigned long len;} list;Redis外部应用该链表保留运行数据,如主服务下所有的从服务器信息。 但Redis并不应用该链表保留用户列表数据,因为它对内存治理不够敌对: (1)链表中每一个节点都占用独立的一块内存,导致内存碎片过多。 (2)链表节点中前后节点指针占用过多的额定内存。 读者能够思考一下,用什么构造能够比拟好地解决下面的两个问题?没错,数组。ziplist是一种相似数组的紧凑型链表格局。它会申请一整块内存,在这个内存上寄存该链表所有数据,这就是ziplist的设计思维。 定义ziplist总体布局如下: <zlbytes> <zltail> <zllen> <entry> <entry> ... <entry> <zlend>zlbytes:uint32_t,记录整个ziplist占用的字节数,包含zlbytes占用的4字节。zltail:uint32_t,记录从ziplist起始地位到最初一个节点的偏移量,用于反对链表从尾部弹出或反向(从尾到头)遍历链表。zllen:uint16_t,记录节点数量,如果存在超过216-2个节点,则这个值设置为216-1,这时须要遍历整个ziplist获取真正的节点数量。zlend:uint8_t,一个非凡的标记节点,等于255,标记ziplist结尾。其余节点数据不会以255结尾。entry就是ziplist中保留的节点。entry的格局如下: <prevlen> <encoding> <entry-data>entry-data:该节点元素,即节点存储的数据。prevlen:记录前驱节点长度,单位为字节,该属性长度为1字节或5字节。 ① 如果前驱节点长度小于254,则应用1字节存储前驱节点长度。 ② 否则,应用5字节,并且第一个字节固定为254,剩下4个字节存储前驱节点长度。encoding:代表以后节点元素的编码格局,蕴含编码类型和节点长度。一个ziplist中,不同节点元素的编码格局能够不同。编码格局标准如下: ① 00pppppp(pppppp代表encoding的低6位,下同):字符串编码,长度小于或等于63(26-1),长度寄存在encoding的低6位中。 ② 01pppppp:字符串编码, 长度小于或等于16383(214-1),长度寄存在encoding的后6位和encoding后1字节中。 ③ 10000000:字符串编码,长度大于16383(214-1),长度寄存在encoding后4字节中。 ④ 11000000:数值编码, 类型为int16_t,占用2字节。 ⑤ 11010000:数值编码,类型为int32_t,占用4字节。 ⑥ 11100000:数值编码,类型为int64_t,占用8字节。 ⑦ 11110000:数值编码,应用3字节保留一个整数。 ⑧ 11111110:数值编码,应用1字节保留一个整数。 ⑨ 1111xxxx:应用encoding低4位存储一个整数,存储数值范畴为0~12。该编码下encoding低4位的可用范畴为0001~1101,encoding低4位减1为理论存储的值。 ⑩ 11111111:255,ziplist完结节点。 留神第②、③种编码格局,除了encoding属性,还须要额定的空间存储节点元素长度。第⑨种格局也比拟非凡,节点元素间接寄存在encoding属性上。该编码是针对小数字的优化。这时entry-data为空。字节序encoding属性应用多个字节存储节点元素长度,这种多字节数据存储在计算机内存中或者进行网络传输时的字节程序称为字节序,字节序有两种类型:大端字节序和小端字节序。 ...

September 12, 2021 · 4 min · jiezi

关于redis:高级Redis应用进阶课-一站式Redis解决方案

download:高级Redis利用进阶课 一站式Redis解决方案<configurationFile>D:/GitFile/ka-product/ka-product-soa/src/main/resources/generatorConfig.xml</configurationFile> <verbose>true</verbose> <overwrite>true</overwrite> </configuration> </plugin> generatorConfig.xml <?xmlversion="1.0"encoding="UTF-8"?> generatorConfigurationPUBLIC"-//mybatis.org//DTDMyBatisGeneratorConfiguration1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> me="suppressDate"value="true"/> <propertyname="suppressAllComments"value="true"/> </commentGenerator> <jdbcConnectiondriverClass="com.mysql.jdbc.Driver"connectionURL="jdbc:mysql://192.168.147.35:3306/ka_product"userId="root"password="123456"/> <javaTypeResolver> <propertyname="forceBigDecimals"value="false"/> </javaTypeResolver> <javaModelGeneratortargetPackage="site.muhu.cmp.ucenter.model"targetProject="src/main/java"> <propertyname="enableSubPackages"value="true"/> <propertyname="trimStrings"value="true"/> </javaModelGenerator> <sqlMapGeneratortargetPackage="mapping"targetProject="src/main/resources"> <propertyname="enableSubPackages"value="true"/> </sqlMapGenerator> <javaClientGeneratortype="XMLMAPPER"targetPackage="site.muhu.cmp.ucenter.mapper"targetProject="src/main/java"> <propertyname="enableSubPackages"value="true"/>

September 10, 2021 · 1 min · jiezi

关于redis:Rdies基础-安装常用命令持久化

一、NoSQL Redis概述NoSQL概述RDBMS (Relational Database Management System)关系数据库管理系统 依照事后设置的组织构造,将数据存储在物理介质上数据之间能够做关联操作RDBMS软件支流的RDBMS软件MySQLMariaDBOracleDB2SQL ServerNoSQL (NoSQL = Not Only SQL)意思是“不仅仅是SQL”泛指非关系型数据库不须要事后定义数据存储构造每条记录能够有不同的数据类型和字段个数NoSQL软件支流软件MemcachedRedisMongoDBCouchDB-Neo4jFlockDBRedis介绍Remote Dictionary Server (近程字典服务器)是一款高性能的(Key/Values)分布式内存数据库反对数据长久化(定期把内存里数据存储到硬盘)反对多种数据类型string.list、hash .....反对 master-salve模式数据备份中文网站www.redis.cn初始配置配置服务运行参数]# ./utils/install_server.sh //初始化默认端口 6379主配置文件 /etc/redis/6379.conf日志文件 /var/log/redis_6379.log数据库目录 /var/lib/redis/6379服务启动程序 /usr/local/bin/redis-server命令行连贯命令 /usr/local/bin/redis-cli治理服务]# /etc/init.d/redis_6379 stop //进行服务]# /etc/init.d/redis_6379 start //启动服务]# ps -C redis-server //查看过程]# netstat -utnlp | grep :6379 //查看端口连贯服务拜访redis服务redis-cli 默认连贯本机的redis服务Redis Desktop Manager(RDM)罕用可视化管理工具二、Redis装置部署案例1:搭建Redis服务器具体要求如下∶-在主机192.168.4.155上装置并启动redis服务-设置变量school,值为tarena-查看变量school值 软件装置1)装置源码redis软件 [root@redis ~]# yum -y install gcc[root@redis ~]# tar -xf redis-5.0.10.tar.gz //先从官网下载redis安装包[root@redis ~]# cd redis-5.0.10/[root@redis redis-5.0.10]# ls00-RELEASENOTES COPYING Makefile redis.conf runtest-moduleapi srcBUGS deps MANIFESTO runtest runtest-sentinel testsCONTRIBUTING INSTALL README.md runtest-cluster sentinel.conf utils[root@redis redis-5.0.10]# make[root@redis redis-5.0.10]# make install[root@redis redis-5.0.10]# cd utils/[root@redis utils]# ./install_server.sh Welcome to the redis service installerThis script will help you easily set up a running redis serverPlease select the redis port for this instance: [6379] Selecting default: 6379Please select the redis config file name [/etc/redis/6379.conf] Selected default - /etc/redis/6379.confPlease select the redis log file name [/var/log/redis_6379.log] Selected default - /var/log/redis_6379.logPlease select the data directory for this instance [/var/lib/redis/6379] Selected default - /var/lib/redis/6379Please select the redis executable path [/usr/local/bin/redis-server] Selected config:Port : 6379 //端口号Config file : /etc/redis/6379.conf //配置文件目录Log file : /var/log/redis_6379.log //日志目录Data dir : /var/lib/redis/6379 //数据库目录Executable : /usr/local/bin/redis-server //启动程序的目录Cli Executable : /usr/local/bin/redis-cli //命令行的连贯工具Is this ok? Then press ENTER to go on or Ctrl-C to abort. //回车实现配置Copied /tmp/6379.conf => /etc/init.d/redis_6379 //服务启动脚本Installing service...Successfully added to chkconfig!Successfully added to runlevels 345!Starting Redis server... //提醒服务曾经启动Installation successful! //提醒装置胜利2)查看服务状态 监听的端口 ...

September 9, 2021 · 6 min · jiezi

关于redis:redis-系列总结篇

Redis 总体介绍Redis 是 key-value 型的 memory 缓存中间件,置信大部分程序员都在我的项目中应用过它。咱们也能够利用 memory 来实现缓存,只是应用 redis 的话,能够将缓存性能对立到一个组件里,不便后续重用拓展。 在底层上, redis 应用了 IO 多路复用技术,像 select、epoll 等。能较好的保障吞吐量。而且 redis 采纳了单线程解决申请,防止了线程切换和锁竞争锁带来的额定耗费。 加上 redis 自身也对一些数据结构进行了优化设计,所以 redis 的性能十分好,官网给出的测试报告是单机能够反对约 10w/s 的 QPS。 Redis 通信协议redis 是基于 tcp 长连贯的 C/S 架构,采纳的是文本序列化协定,并且和 http 一样,也是一个申请一个响应,客户端接到响应后再持续申请。 当然,也能够将屡次申请发送过来,而后一次响应回所有执行后果,这就是所谓的管道 pipeline 技术。 redis 的文本序列化协定比较简单,通过一些标准格局去解析文本,大略如下: \r\n 示意解析完结简略字符串,以“+”结尾谬误 Errors,以“-”结尾整数类型,以“:”结尾大字符串类型,以“&dollar;”结尾数组类型,以“*”结尾例如,客户端向服务器发送命令: SET key value 将被解析为: *3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n 下面的命令能够看成: *<参数数量> CR LF$<参数 1 的字节数量> CR LF<参数 1 的数据> CR LF...$<参数 N 的字节数量> CR LF<参数 N 的数据> CR LF而服务器的回复则有很多类型,个别由响应数据的第一个字节决定: ...

September 7, 2021 · 2 min · jiezi

关于redis:redis进阶5缓存雪崩击穿穿透

缓存雪崩+击穿+穿透缓存雪崩目前电商首页以及热点数据都会去做缓存 ,个别缓存都是定时工作去刷新,或者是查不到之后去更新的,定时工作刷新就有一个问题:缓存雪崩。 缓存雪崩是指在大QPS时,缓存刚好生效或更新,大量申请打到DB上,导致DB扛不住挂掉。 解决方案 错开KEY的生效工夫setRedis(Key,value,time + Math.random() * 10000); 热点数据永不过期,放弃和数据库一致性更新缓存穿透指缓存和数据库中都没有的数据,但却产生了数据库的查问。比方数据库的 id 都是1开始自增下来的,如果发动为id值为 -1 的数据或 id 为特地大不存在的数据。 解决方案 接口层减少校验,比方用户鉴权校验,参数做校验,不非法的参数间接代码Return,比方:id 做根底校验,id <=0的间接拦挡等。从缓存取不到的数据,在数据库中也没有取到,这时也能够将对应Key的Value对写为null、地位谬误、稍后重试这样的值具体取啥问产品,或者看具体的场景,缓存无效工夫能够设置短点,如30秒(设置太长会导致失常状况也没法应用)。能够依据场景联合uri和申请参数做缓存。nginx代理层限度同IP高频率拜访缓存击穿缓存击穿和缓存雪崩一样,不过前者是点,后者是面。缓存击穿是指一个Key十分热点,在不停的扛着大并发,大并发集中对这一个点进行拜访,当这个Key在生效的霎时,继续的大并发就穿破缓存,间接申请数据库,就像在一个完整无缺的桶上凿开了一个洞。 解决方案 热点数据永不过期,放弃和数据库一致性更新。加上互斥锁。缓存更新时上锁,此时进来的申请能够先sleep梗塞起。

September 7, 2021 · 1 min · jiezi

关于redis:redis-五redis之List

redis系列文章: https://liudongdong.top/categ... 本篇起源: https://liudongdong.top/archi... 公众号:雨中散步撒哈拉 备注:欢送关注公众号,一起学习,共同进步!一、List概述Redis列表是简略的字符串列表,依照插入程序排序。你能够增加一个元素到列表的头部(右边)或者尾部(左边) 一个列表最多能够蕴含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。 list能够了解为一个通道,能够右边进,也能够左边进。 16293521471.png 依据上边的通道,也能够变体为俩种形式: 左进右出:队列左进左出:桶二、List分类依据集体了解和便于学习,集体进行了list命令的分类! 依据命令性质分为: 增:减少list数据删:删除list数据改:批改list数据查:查问list数据1. List中的增lpush:右边推动一个或多个值lpushx右边推动一个值,列表不存在时,有效rpush:左边推动一个或多个值rpushx:左边推动一个值,列表不存在时,有效linsert:在某一个值的前边或者后边插入一个值2. List中的删lrem:移除指定值,反复值依据指定数量进行移除lpop:头部弹出一个值rpop:右部弹出一个值blpop:阻塞弹出头部一个值,如果没有值,则期待有值或超时brpop:阻塞弹出尾部一个值,如果没有值,则期待有值或超时rpoplpush:尾部弹出一个值,并把该值压入到新的列表头部brpoppush:阻塞弹出一个值,并把该值压入到新的列表头部,如果没有值,则期待有值或超时3. List中的改lset:依据下标,进行批改值ltrim:截取列表值(区间范畴内,定位值)4. List中的查llen:查问列表长度lindex:依据下标进行获取某一个值lrange:依据下标范畴获取list列表三、命令实际依据分类,进行命令操作 1. List中的增127.0.0.1:6379> keys *(empty list or set)# 右边推动俩个值127.0.0.1:6379> lpush lists one two(integer) 2127.0.0.1:6379> lrange lists 0 -11) "two"2) "one"# 左边推动俩个值127.0.0.1:6379> rpush lists three four(integer) 4127.0.0.1:6379> lrange lists 0 -11) "two"2) "one"3) "three"4) "four"# 右边推动一个值,仅反对一个127.0.0.1:6379> lpushx lists five(integer) 5127.0.0.1:6379> lrange lists 0 -11) "five"2) "two"3) "one"4) "three"5) "four"# 左边推动一个值,仅反对一个127.0.0.1:6379> rpushx lists sex(integer) 6127.0.0.1:6379> lrange lists 0 -11) "five"2) "two"3) "one"4) "three"5) "four"6) "sex"# 在某一个值的前边或后边进行插入值127.0.0.1:6379> linsert lists after three zero(integer) 7127.0.0.1:6379> lrange lists 0 -11) "five"2) "two"3) "one"4) "three"5) "zero"6) "four"7) "sex"127.0.0.1:6379> 2. List中的删127.0.0.1:6379> keys *1) "lists"127.0.0.1:6379> lrange lists 0 -11) "five"2) "two"3) "one"4) "three"5) "zero"6) "four"7) "sex"# 头部弹出一个值127.0.0.1:6379> lpop lists"five"127.0.0.1:6379> lrange lists 0 -11) "two"2) "one"3) "three"4) "zero"5) "four"6) "sex"# 尾部弹出一个值127.0.0.1:6379> rpop lists"sex"127.0.0.1:6379> lrange lists 0 -11) "two"2) "one"3) "three"4) "zero"5) "four"# 头部阻塞弹出two值,没有two则取第一个值,如列表没值则返回nil127.0.0.1:6379> blpop lists two 31) "lists"2) "two"127.0.0.1:6379> lrange lists 0 -11) "one"2) "three"3) "zero"4) "four"127.0.0.1:6379> blpop lists two 31) "lists"2) "one"127.0.0.1:6379> lrange lists 0 -11) "three"2) "zero"3) "four"# 创立一个新的列表127.0.0.1:6379> lpush lists2 aa(integer) 1# 头部阻塞弹出two值,没有aa则取第一个值,如列表没值则返回nil127.0.0.1:6379> blpop lists2 aa 31) "lists2"2) "aa"127.0.0.1:6379> blpop lists2 aa 3(nil)(3.10s)127.0.0.1:6379> lrange lists 0 -11) "zero"2) "four"127.0.0.1:6379> lrange lists2 0 -1(empty list or set)# 尾部弹出,并压入新的列表头部127.0.0.1:6379> rpoplpush lists lists2"four"127.0.0.1:6379> lrange lists 0 -11) "zero"127.0.0.1:6379> lrange lists2 0 -11) "four"# 阻塞,尾部弹出,并压入新的列表头部127.0.0.1:6379> brpoplpush lists lists2 3"zero"127.0.0.1:6379> lrange lists 0 -1(empty list or set)127.0.0.1:6379> lrange lists2 0 -11) "zero"2) "four"127.0.0.1:6379> brpoplpush lists lists2 3(nil)(3.04s)# 移除指定值127.0.0.1:6379> lrem lists2 1 zero(integer) 1127.0.0.1:6379> lrange lists2 0 -11) "four"127.0.0.1:6379> 3. List中的改# 创立lists,并赋予值127.0.0.1:6379> lpush lists one two three four five sex(integer) 6127.0.0.1:6379> lrange lists 0 -11) "sex"2) "five"3) "four"4) "three"5) "two"6) "one"# 截取list,范畴位[1,4]127.0.0.1:6379> ltrim lists 1 4OK127.0.0.1:6379> lrange lists 0 -11) "five"2) "four"3) "three"4) "two"# 依据下标进行设置值127.0.0.1:6379> lset lists 0 "hello world"OK127.0.0.1:6379> lrange lists 0 -11) "hello world"2) "four"3) "three"4) "two"127.0.0.1:6379>4. List中的查127.0.0.1:6379> lrange lists2 0 -11) "four"127.0.0.1:6379> llen lists2(integer) 1127.0.0.1:6379> lindex lists2 0"four"127.0.0.1:6379> lrange lists2 0 -11) "four"127.0.0.1:6379> 附录下表列出了列表相干的根本命令: 序号命令及形容1[BLPOP key1 key2 ] timeout 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到期待超时或发现可弹出元素为止。2[BRPOP key1 key2 ] timeout 移出并获取列表的最初一个元素, 如果列表没有元素会阻塞列表直到期待超时或发现可弹出元素为止。3BRPOPLPUSH source destination timeout 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它;如果列表没有元素会阻塞列表直到期待超时或发现可弹出元素为止。4LINDEX key index 通过索引获取列表中的元素5LINSERT key BEFOREAFTER pivot value 在列表的元素前或者后插入元素6LLEN key 获取列表长度7LPOP key 移出并获取列表的第一个元素8[LPUSH key value1 value2] 将一个或多个值插入到列表头部9LPUSHX key value 将一个值插入到已存在的列表头部10LRANGE key start stop 获取列表指定范畴内的元素11LREM key count value 移除列表元素12LSET key index value 通过索引设置列表元素的值13LTRIM key start stop 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。14RPOP key 移除列表的最初一个元素,返回值为移除的元素。15RPOPLPUSH source destination 移除列表的最初一个元素,并将该元素增加到另一个列表并返回16[RPUSH key value1 value2] 在列表中增加一个或多个值17RPUSHX key value 为已存在的列表增加值

September 7, 2021 · 1 min · jiezi

关于redis:redis-四redis之String

edis系列文章: https://liudongdong.top/categ... 本篇起源: https://liudongdong.top/archi... 公众号:雨中散步撒哈拉 备注:欢送关注公众号,一起学习,共同进步! 一、根本语法Redis 字符串(String) Redis 字符串数据类型的相干命令用于治理 redis 字符串值,根本语法如下: 语法 redis 127.0.0.1:6379> COMMAND KEY_NAME实例 127.0.0.1:6379> set learn_redis liuddOK127.0.0.1:6379> get learn_redis"liudd"127.0.0.1:6379> 实用场景: 计数器统计多单位的数量粉丝数对象缓存存储二、命令划分集体感觉string类型,命令比拟多些,便于集体了解和学习,进行了简略分类! 分为以下几类: 赋值命令取值命令特有命令额定命令对象格局操作以上为集体了解,进行简略划分。具体对命令的了解,期待你的了解办法! 1. 赋值命令set:设置值setnx:如果值不存在则进行赋值mset:批量设值msetnx:批量设值,且key不存在getset:返回旧值,设值新值2. 取值命令get:获取key的值mget:批量获取key的值3. 特有命令exists:判断key是否存在append:依据key进行追加strlen:获取key的长度setrange:依据起终下标,进行设值(集体了解为字符串替换replace)getrange:依据起终下标,进行取值(集体了解为字符串截取substring)4. 额定命令setex:设值key,并设置过期工夫(单位:s/秒))psetex:设值key,并设置过期工夫(单位:ms/毫秒))incr:int类型,进行key的自增(i++)decr:int类型,进行key的自减(i--)incrby:int类型,依据步长进行key的减少(i+n)decrby:int类型,依据步长进行key的增减(i-n)incrbyfloat:float类型,依据float值,进行增减(正负)5. 对象格局操作依据id和属性进行对象的存取值 三、分类命令实际1. 赋值命令# 查看以后库所有key127.0.0.1:6379> keys *(empty list or set)# 设值k1127.0.0.1:6379> set k1 v1OK# 测试setnx对k1,如果k1存在是否存储127.0.0.1:6379> setnx k1 kk(integer) 0# 上步返回0,后果为存储失败,进行查看k1值127.0.0.1:6379> get k1"v1"# k2不存在,进行存储127.0.0.1:6379> setnx k2 v2(integer) 1# 上步返回1,存储胜利,进行查看127.0.0.1:6379> get k2"v2"# 批量设值127.0.0.1:6379> mset k3 v3 k4 v4OK# 批量取值127.0.0.1:6379> mget k3 k41) "v3"2) "v4"# 返回旧值,设值新值127.0.0.1:6379> getset k4 v5"v4"# 查看后果127.0.0.1:6379> get k4"v5"127.0.0.1:6379>2. 取值命令前一步,曾经依据设值进行了设值和取值,本步独自进行取值 127.0.0.1:6379> get k1"v1"127.0.0.1:6379> mget k2 k3 k41) "v2"2) "v3"3) "v5"127.0.0.1:6379> 3. 特有命令# 查看以后库,127.0.0.1:6379> keys *1) "k3"2) "k1"3) "k4"4) "k2"# 判断是否存储k4127.0.0.1:6379> exists k4(integer) 1# 判断是否存在k5127.0.0.1:6379> exists k5(integer) 0# k4进行追加值127.0.0.1:6379> append k4 aaa(integer) 5127.0.0.1:6379> get k4"v5aaa"# 获取k4值得长度127.0.0.1:6379> strlen k4(integer) 5# 依据起始下标进行替换k4,起始下标为1127.0.0.1:6379> setrange k4 1 kk(integer) 5127.0.0.1:6379> get k4"vkkaa"# 截取获取值,截取下标范畴[2,4]127.0.0.1:6379> getrange k4 2 4"kaa"# 如果呈现负值,则下标为从右向左,开始为-1127.0.0.1:6379> getrange k4 0 -1"vkkaa"127.0.0.1:6379>题外话: getrange取值下标规定 image.png 4. 额定命令# 设值过期工夫为3秒127.0.0.1:6379> setex k 3 kkOK127.0.0.1:6379> get k"kk"127.0.0.1:6379> get k(nil)# 设值过期工夫为3000毫秒(3秒)127.0.0.1:6379> psetex kk 3000 kkOK127.0.0.1:6379> get kk"kk"127.0.0.1:6379> get kk(nil)# 对i自增127.0.0.1:6379> incr i(integer) 1127.0.0.1:6379> incr i(integer) 2127.0.0.1:6379> get i"2"# 对i自减127.0.0.1:6379> decr i(integer) 1127.0.0.1:6379> decr i(integer) 0127.0.0.1:6379> get i"0"# 依据步长减少127.0.0.1:6379> incrby i 3(integer) 3# 依据步长缩小127.0.0.1:6379> decrby i 4(integer) -1127.0.0.1:6379> get i"-1"# 对i进行float浮点数操作127.0.0.1:6379> incrbyfloat i 2.1"1.1"127.0.0.1:6379> get i"1.1"127.0.0.1:6379> 5. 对象格局操作对象命令格局 mset key:{id}:{属性} # id为1的user,进行设值127.0.0.1:6379> mset user:1:name liudd user:1:age 2OK# 获取user,id为1的值127.0.0.1:6379> mget user:1:name user:1:age1) "liudd"2) "2"# 设值id为2的user对象127.0.0.1:6379> mset user:2:name liudd2 user:2:age 3OK127.0.0.1:6379> mget user:2:name user:2:age1) "liudd2"2) "3"127.0.0.1:6379> keys *1) "k1"2) "user:2:name"3) "k2"4) "user:1:age"5) "user:2:age"6) "k3"7) "user:1:name"8) "k4"9) "i"127.0.0.1:6379>附录:命令列表下表列出了罕用的 redis 字符串命令: 序号命令及形容1SET key value 设置指定 key 的值2GET key 获取指定 key 的值。3GETRANGE key start end 返回 key 中字符串值的子字符4GETSET key value 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。5GETBIT key offset 对 key 所贮存的字符串值,获取指定偏移量上的位(bit)。6[MGET key1 key2..] 获取所有(一个或多个)给定 key 的值。7SETBIT key offset value 对 key 所贮存的字符串值,设置或革除指定偏移量上的位(bit)。8SETEX key seconds value 将值 value 关联到 key ,并将 key 的过期工夫设为 seconds (以秒为单位)。9SETNX key value 只有在 key 不存在时设置 key 的值。10SETRANGE key offset value 用 value 参数覆写给定 key 所贮存的字符串值,从偏移量 offset 开始。11STRLEN key 返回 key 所贮存的字符串值的长度。12[MSET key value key value …] 同时设置一个或多个 key-value 对。13[MSETNX key value key value …] 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。14PSETEX key milliseconds value 这个命令和 SETEX 命令类似,但它以毫秒为单位设置 key 的生存工夫,而不是像 SETEX 命令那样,以秒为单位。15INCR key 将 key 中贮存的数字值增一。16INCRBY key increment 将 key 所贮存的值加上给定的增量值(increment) 。17INCRBYFLOAT key increment 将 key 所贮存的值加上给定的浮点增量值(increment) 。18DECR key 将 key 中贮存的数字值减一。19DECRBY key decrement key 所贮存的值减去给定的减量值(decrement) 。20APPEND key value 如果 key 曾经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的开端。更多命令请参考:https://redis.io/commands ...

September 6, 2021 · 1 min · jiezi

关于redis:redis进阶4限流策略

限流简述限流算法在分布式畛域是一个常常被提起的话题,当零碎的解决能力无限时,如何阻止计划外的申请持续对系统施压,这是一个须要器重的问题。 除了管制流量,限流还有一个利用目标是用于管制用户行为,防止垃圾申请。比方在 UGC 社区,用户的发帖、回复、点赞等行为都要严格受控,个别要严格限定某行为在规定工夫内容许的次数,超过了次数那就是非法行为。对非法行为,业务必须规定适当的表彰策略。 # 指定用户 user_id 的某个行为 action_key 在特定的工夫内 period 只容许产生肯定的次数 max_countdef is_action_allowed(user_id, action_key, period, max_count): return True# 调用这个接口 , 一分钟内只容许最多回复 5 个帖子can_reply = is_action_allowed("110", "reply", 60, 5)if can_reply: do_reply()else: raise ActionThresholdOverflow()计数限流pipe 与 zset 如图所示,用一个 zset 构造记录用户的行为历史,每一个行为都会作为 zset 中的一个 key 保留下来。同一个用户同一种行为用一个 zset 记录。 为节俭内存,咱们只须要保留工夫窗口内的行为记录,同时如果用户是冷用户,滑动工夫窗口内的行为是空记录,那么这个 zset 就能够从内存中移除,不再占用空间。 通过统计滑动窗口内的行为数量与阈值 max\_count 进行比拟就能够得出以后的行为是否容许。用代码示意如下: function isActionAllowed($userId, $action, $period, $maxCount){ $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $key = sprintf('hist:%s:%s', $userId, $action); $now = msectime(); # 毫秒工夫戳 $pipe=$redis->multi(Redis::PIPELINE); //应用管道晋升性能 $pipe->zadd($key, $now, $now); //value 和 score 都应用毫秒工夫戳 $pipe->zremrangebyscore($key, 0, $now - $period); //移除工夫窗口之前的行为记录,剩下的都是工夫窗口内的 $pipe->zcard($key); //获取窗口内的行为数量 $pipe->expire($key, $period + 1); //多加一秒过期工夫 $replies = $pipe->exec(); return $replies[2] <= $maxCount;}for ($i=0; $i<20; $i++){ var_dump(isActionAllowed("110", "reply", 60*1000, 5)); //执行能够发现只有前5次是通过的}//返回以后的毫秒工夫戳function msectime() { list($msec, $sec) = explode(' ', microtime()); $msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000); return $msectime; }应用lua脚本10秒内只能拜访3次。 后续该脚本能够在nginx或者程序运行脚本中间接应用,判断返回是否为0,就0就不让其持续拜访。 ...

September 6, 2021 · 3 min · jiezi

关于redis:如何使用-Redis-实现后台房间的数据管理

摘要:利用 Redis 实现房间业务管理的实际与思考。 文|即构业务后盾开发团队 在一些互动场景中,比方语音聊天室、电商直播等,成员管制、连麦、献花、发弹幕等互动性能,通常要求后盾服务器可能贮存治理房间及房间内成员的数据。 那么如何组织、存储、操作这些数据以实现既定的业务,并且还要同时保障服务器和客户端之间的数据一致性,是实现这类音视频互动场景的业务后盾须要思考的问题之一。 RoomKit 作为即构科技推出的一款全新状态 LCEP(Low-code Engagement Platform)产品,高度形象了音视频通话、白板涂鸦、文件演示、实时音讯等通用能力,模块性能能够任意组装,让用户用低/零码的形式可实现多个业务场景搭建。所以在 Roomkit 这款产品的后盾逻辑中,房间数据管理作为业务的外围局部,贯通了整个开发过程。 Redis 作为一款高性能 kv 数据库,在后盾开发中利用非常宽泛,Roomkit 后盾咱们也应用了 Redis 进行房间数据管理。 那么本文咱们就来看下,即构后盾开发团队在利用 Redis 实现业务时遇到的技术难点和解决方案,读者在应用即构 aPaaS 层实现本人的业务遇到类似的问题时,也能够参考本文进行解决。 一、Roomkit 后盾整体介绍1、功能模块划分依据业务逻辑,RoomKit 将代码划分为房间管制模块和性能插件模块两大模块。上面为大家具体介绍这些模块的性能。 房间管制模块 房间管制模块次要用于治理房间列表、房间状态、房间内成员的状态交互。 RoomKit 实用的场景多种多样,大班课、直播、小班课、视频会议、1v1,但理论这些场景能够划分为类视频会议场景和类直播场景。 这两个场景的逻辑偏重各不相同,类视频会议场景参加成员绝对较少,然而成员之间交互很频繁;而类直播场景参加人数个别较多,然而主播与听众交互绝对较少。基于这个规范 RoomKit 后盾又将房间管制模块又划分为两个子模块。因为与本文主题无关,这里不再开展形容。 性能插件模块 性能插件模块指的是与 RoomKit 反对的插件性能,如共享、教学插件、IM 等,其逻辑与场景无关,均可作为独立模块进行开发,与房间管制模块的交互通过互相提供 handler 实现。 2、后盾服务架构RoomKit 后盾基于 Redis 治理房间数据,并利用即构信令后盾提供的即时推送能力,向客户端实时推送房间状态变动告诉。下图是后盾与其余服务和客户端之间的架构关系。 二、利用 Redis 治理房间数据的关键技术上面咱们次要以【房间管制模块】为例,介绍 Roomkit 后盾在利用 Redis 实现房间业务时的一些关键点。 1、利用 Redis 贮存房间数据为了实现房间内的交互性能,Roomkit 后盾须要记录房间、成员等状态信息。为了在业务服务器程序之间共享这些数据,咱们抉择将数据贮存在 Redis 中。 Redis 的 hash 构造人造的能够用于记录房间状态等数据,对房间的设置,如开始上课操作,只须要更改对应的 field 即可。 而为了可能跟踪到以后处于关上状态的房间,Roomkit 后盾将房间 ID 和创立工夫记录到一个全局的 ZSET 中,后盾会定时遍历这些房间以解决统计数据、查看离线成员等。 ...

September 6, 2021 · 2 min · jiezi

关于redis:redis-三redis基本知识

redis系列文章: https://liudongdong.top/categ... 本篇起源: https://liudongdong.top/archi... 公众号:雨中散步撒哈拉 备注:欢送关注公众号,一起学习,共同进步!一、近程连贯1. 下载关注公众号雨中散步撒哈拉,回复关键词020,进行下载 举荐俩个工具rdm或者another-redis image.png 2. 连贯填写近程信息,进行连贯 image.png another-redis界面 image.png rmd界面 image.png 二、测试性能Redis 自带一个压测工具 redis-benchmark,有以下可选参数 image.png 1. 进入容器docker exec -it docker_redis /bin/bash# 进入容器执行redis-benchmark -p 6379 -c 100 -n 100000 image.png 2. 查看终端输入 image.png 上半局部代表 100 个并发写入 10w 条数据,每次写入 3 个字节,keep-alive:1 代表服务器数量只有 1 台,并且在没有开启多线程的状况下只花了 2.86s ( tips:多线程是 redis 6.0 新增的 ) 下半局部代表在 42.815ms 内解决实现全副申请 3. 查看检测设施 image.png 三、Redis 基本知识redis官网:http://redis.cn/ Redis 是一个基于 C 语言编写的,是可基于内存也可长久化的日志型 K-V 数据库,并提供多种语言的 API。可用作数据库,缓存和消息中间件 Redis 会周期性的把更新的数据写入磁盘或是把批改操作写入到追加的记录文件,并在此基础上实现主从复制 1. Redis 无能啥?反对内存存储和长久化 ( EDB / AOF )效率高,反对高并发,能够用做高速缓存能够用于公布-订阅模式地图信息剖析计数器,计时器数据类型多样反对集群和事务…2. Redis根本命令1. redis数据库Redis 默认有 16 个数据库,起始数据库为 0 号,能够应用命令 ...

September 5, 2021 · 1 min · jiezi

关于redis:Redis核心原理与实践字符串实现原理

Redis是一个键值对数据库(key-value DB),上面是一个简略的Redis的命令: > SET msg "hello wolrd"该命令将键“msg”、值“hello wolrd”这两个字符串保留到Redis数据库中。 本章剖析Redis如何在内存中保留这些字符串。 redisObjectRedis中的数据对象server.h/redisObject是Redis对外部存储的数据定义的形象类型,在深入分析Redis数据类型前,咱们先理解redisObject,它的定义如下: typedef struct redisObject { unsigned type:4; unsigned encoding:4; unsigned lru:LRU_BITS; int refcount; void *ptr;} robj;type:数据类型。encoding:编码格局,即存储数据应用的数据结构。同一个类型的数据,Redis会依据数据量、占用内存等状况应用不同的编码,最大限度地节俭内存。refcount,援用计数,为了节俭内存,Redis会在多处援用同一个redisObject。ptr:指向理论的数据结构,如sds,真正的数据存储在该数据结构中。lru:24位,LRU工夫戳或LFU计数。redisObject负责装载Redis中的所有键和值。redisObject.ptr指向真正存储数据的数据结构,redisObject .refcount、redisObject.lru等属性则用于治理数据(数据共享、数据过期等)。 提醒:type、encoding、lru应用了C语言中的位段定义,这3个属性应用同一个unsigned int的不同bit位。这样能够最大限度地节俭内存。Redis定义了以下数据类型和编码,如表1-1所示。本书第1局部会对表1-1中前五种数据类型进行剖析,最初两种数据类型会在第5局部进行剖析。如果读者当初对表1-1中内容感到纳闷,则能够先带着疑难持续浏览本书。 sds咱们晓得,C语言中将空字符结尾的字符数组作为字符串,而Redis对此做了扩大,定义了字符串类型sds(Simple Dynamic String)。 Redis键都是字符串类型,Redis中最简略的值类型也是字符串类型, 字符串类型的Redis值可用于很多场景,如缓存HTML片段、记录用户登录信息等。 定义提醒:本节代码如无非凡阐明,均在sds.h/sds.c中。对于不同长度的字符串,Redis定义了不同的sds构造体:typedef char *sds;struct __attribute__ ((__packed__)) sdshdr5 { unsigned char flags; char buf[];};struct __attribute__ ((__packed__)) sdshdr8 { uint8_t len; uint8_t alloc; unsigned char flags; char buf[];};...Redis还定义了sdshdr16、sdshdr32、sdshdr64构造体。为了版面整洁,这里不展现sdshdr16、sdshdr32、sdshdr64 构造体的代码,它们与sdshdr8构造体基本相同,只是len、alloc属性应用了 uint16_t、uint32、uint64_t类型。Redis定义不同sdshdr构造体是为了针对不同长度的字符串,应用适合的len、alloc属性类型,最大限度地节俭内存。 len:已应用字节长度,即字符串长度。sdshdr5可寄存的字符串长度小于32(25),sdshdr8可寄存的字符串长度小于256(28),以此类推。因为该属性记录了字符串长度,所以sds能够在常数工夫内获取字符串长度。Redis限度了字符串的最大长度不能超过512MB。alloc:已申请字节长度,即sds总长度。alloc-len为sds中的可用(闲暇)空间。flag:低3位代表sdshdr的类型,高5位只在sdshdr5中应用,示意字符串的长度,所以sdshdr5中没有len属性。另外,因为Redis对sdshdr5的定义是常量字符串,不反对扩容,所以不存在alloc属性。buf:字符串内容,sds遵循C语言字符串的标准,保留一个空字符作为buf的结尾,并且不计入len、alloc属性。这样能够间接应用C语言strcmp、strcpy等函数间接操作sds。提醒:sdshdr构造体中的buf数组并没有指定数组长度,它是C99标准定义的柔性数组—构造体中最初一个属性能够被定义为一个大小可变的数组(该属性前必须有其余属性)。应用sizeof函数计算蕴含柔性数组的构造体大小,返回后果不包含柔性数组占用的内存。 另外,__attribute__((__packed__))关键字能够勾销构造体内的字节对齐以节俭内存。操作剖析接下来看一下sds构建函数: sds sdsnewlen(const void *init, size_t initlen) { void *sh; sds s; // [1] char type = sdsReqType(initlen); // [2] if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8; // [3] int hdrlen = sdsHdrSize(type); unsigned char *fp; /* flags pointer. */ sh = s_malloc(hdrlen+initlen+1); ... // [4] s = (char*)sh+hdrlen; fp = ((unsigned char*)s)-1; switch(type) { case SDS_TYPE_5: { *fp = type | (initlen << SDS_TYPE_BITS); break; } case SDS_TYPE_8: { SDS_HDR_VAR(8,s); sh->len = initlen; sh->alloc = initlen; *fp = type; break; } ... } if (initlen && init) memcpy(s, init, initlen); s[initlen] = '\0'; // [5] return s;}参数阐明: ...

September 5, 2021 · 3 min · jiezi

关于redis:redis-二redis安装

redis系列文章: https://liudongdong.top/categ... 本篇起源: https://liudongdong.top/archi... 公众号:雨中散步撒哈拉 备注:欢送关注公众号,一起学习,共同进步! 一、window装置1. 下载依据GitHub进行下载 https://github.com/microsofta...依据公众号下载 如果GitHub网速太慢,也能够关注公众号雨中散步撒哈拉,回复关键词020,进行下载。2. 解压如下 image.png redis-server.exe:redis服务redis-cli.exe:redis客户端redis-check-aof.exe:aof长久化查看redis-benchmark.exe:benchmark压力测试工具3. 启动启动服务端(双击) image.png 启动客户端(双击) image.png 4. 测试客户端操作 输出ping命令输出set存值输出get取值 image.png 二、Linux装置(centos6.5)0. 装置gcc因为redis是由C语言编写的,它的运行须要C环境,因而咱们须要先装置gcc。装置命令如下: yum install gcc-c++1. 下载wget http://download.redis.io/rele... image.png 也能够间接下载 https://redis.io/download image.png 2. 解压 tar -zxf redis-6.2.5.tar.gz image.png 3. 编译在解压后的redis包中,进行编译 cd redis-6.2.5/make image.png image.png 4. 装置rediscd src/make install image.png 5. 文件分类管理redis目录下创立bin和etc文件,把redis.conf挪动到etc目录下;把mkreleasehdr.sh、redis-benchmark、redis-check-aof、redis-cli、redis-server挪动到bin文件下 [root@node2 redis-6.2.5]# mkdir etc[root@node2 redis-6.2.5]# mkdir bin[root@node2 redis-6.2.5]# mv redis.conf ./etc/[root@node2 redis-6.2.5]# mv src/mkreleasehdr.sh src/redis-benchmark src/redis-check-aof src/redis-cli src/redis-server ./bin[root@node2 redis-6.2.5]# 6. 批改redis配置文件[root@node2 redis-6.2.5]# vim etc/redis.conf1. 开启近程拜访redis把 redis.conf配置文件中的 bind 127.0.0.1 这一行给正文掉,这里的bind指的是只有指定的网段能力近程拜访这个redis,正文掉后,就没有这个限度了。 image.png 把 redis.conf配置文件中的 protected-mode 设置成no(默认是设置成yes的, 避免了近程拜访,在redis3.2.3版本后) image.png 2. 开启后盾启动把文件中的daemonize属性改为yes(表明须要在后盾运行) image.png 3. 批改默认明码esc模式下,/requirepass 搜寻(n为向下检索,大N为向上检索)解除正文,批改本人的明码 ...

September 4, 2021 · 1 min · jiezi

关于redis:redis-一NoSql演进史

redis系列文章: https://liudongdong.top/categ... 本篇起源: https://liudongdong.top/archi... 公众号:雨中散步撒哈拉 备注:欢送关注公众号,一起学习,共同进步! 一、数据库演进史1. 单机 MySQL 时代在 web 初现峥嵘的那段时间 ,大部分网站都是应用的单机 MySQL 来存储用户数据,因为网站的用户与访问量不会太大,甚至大部分都应用额动态网页,与后端没有过多的交互,所以单机 MySQL 足矣 然而随着 web 的倒退带来的用户群体激增,瓶颈也就随之而来了,在单机 MySQL 时代,造成瓶颈的起因次要有 数据量太大,一个服务器硬盘存不下读写混合,一个服务器性能有余数据库索引太大,内存不足2. 垂直拆分与缓存时代起初,随着网站访问量的回升,应用单机 MySQL 的网站开始呈现了性能问题,因而程序员们将眼光从性能转移到了性能上 为了解决单机 MySQL 时代的有余,又对 MySQL 引入了 Memcached ( 缓存 ) 和垂直拆分 (读写拆散) 等计划 一个运行中的网站其大部分工夫都是在被用户进行查问操作,如果将读写拆分到不同的数据库中,就能够进步查问效率,所以数据库有了垂直拆分的计划,也就是数据库依据作用拆分为读服务器和写服务器,并利用主从复制保证数据正确,同时利用缓存加快速度 3. 程度拆分与集群时代读写拆散与分库分表也满足不了用户数据的存储了,这时就呈现了对服务器的程度拆分,多个主从节点组成一个集群节点,而多个集群节点就组成了集群 4.  数据爆炸时代 在现在这个信息爆炸的时代,人们对于信息的实时性要求越来越高,互联网用户同样也越来越多,因而 MySQL 等关系型数据库就不够用了,因为数据量很大,数据变动也很快 通过对第三方平台的拜访和数据抓取,能够很容易的取得用户个人信息,社交网络,用户生成的数据和用户的操作日志曾经成倍的减少,对于这些构造并不确定的数据如果想要对这些数据进行深度的开掘,那关系型数据库就曾经不再实用了 二、什么是 NoSQLNoSQL = Not Only SQL,即泛指非关系型数据库因为 web2.0 时代的到来,互联网用户和数据量呈几何式回升,传统的非关系型数据库很难应酬大型网站的超大数据量和高并发,这就裸露进去了很多关系型数据库难以克服的问题 因为关系型数据库从实质上来说就是一张表格,是有固定构造的,并且所有的数据都必须遵循雷同的形式进行存储 而非关系型数据库是非结构化的,数据能够以多种形式存储,即能够面向文档存储,面向图像存储,甚至面向 K-V 存储等。Java 中的 Map就是一种经典的 "NoSQL",因为 Object 类型能够面向任何类型的对象 1. NoSQL 的特点不便扩大,数据之间没有关系大数据量存储,高性能 (  redis 1s 能写 8w 次,读取 11w 条)数据类型多样,不须要当时设计数据库2. RDBMS 和 NoSQL 的区别RDBMS ...

September 3, 2021 · 1 min · jiezi

关于redis:Redis-新特性篇100-掌握多线程模型

Redis 官网在 2020 年 5 月正式推出 6.0 版本,提供很多振奋人心的新个性,所以备受关注。 码老湿,提供了啥个性呀?晓得了我能加薪么?次要个性如下: 多线程解决网络 IO;客户端缓存;细粒度权限管制(ACL);RESP3 协定的应用;用于复制的 RDB 文件不在有用,将立即被删除;RDB 文件加载速度更快;其中备受关注的就是「多线程模型 + 客户端缓存」,咱们只有把握了新个性原理,能力判断什么时候应用 6.0 版本,如何用的更好更快,不踩坑。 本篇先从 Redis 多线程模型开始,至于客户端缓存、等且听下回分解。 最初,点击下方卡片关注「码哥字节」能加薪。 码老湿,Redis 6.0 之前为什么不应用多线程?官网回答: 应用 Redis 时,简直不存在 CPU 成为瓶颈的状况, Redis 次要受限于内存和网络。在一个一般的 Linux 零碎上,Redis 通过应用pipelining 每秒能够解决 100 万个申请,所以如果应用程序次要应用 O(N) 或O(log(N)) 的命令,它简直不会占用太多 CPU。应用了单线程后,可维护性高。多线程模型尽管在某些方面体现优异,然而它却引入了程序执行程序的不确定性,带来了并发读写的一系列问题,减少了零碎复杂度、同时可能存在线程切换、甚至加锁解锁、死锁造成的性能损耗。Redis 通过 AE 事件模型以及 IO 多路复用等技术,解决性能十分高,因而没有必要应用多线程。 单线程机制让 Redis 外部实现的复杂度大大降低,Hash 的惰性 Rehash、Lpush 等等『线程不平安』的命令都能够无锁进行。 在《Redis 为什么这么快?》码哥有具体介绍快的原理。 Redis 6.0 之前单线程指的是 Redis 只有一个线程干活么?非也,Redis 在解决客户端的申请时,包含获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个程序串行的主线程解决,这就是所谓的「单线程」。 其中执行命令阶段,因为 Redis 是单线程来解决命令的,所有每一条达到服务端的命令不会立即执行,所有的命令都会进入一个 Socket 队列中,当 socket 可读则交给单线程事件散发器一一被执行。 ...

September 2, 2021 · 1 min · jiezi

关于redis:redis进阶3大数据量精度去重

简述通过布隆过滤器实现大数据量的精度去重。 布隆过滤器能够了解为一个不怎么准确的 set 构造,当你应用它的 contains 办法判断某个对象是否存在时,它可能会误判。然而布隆过滤器也不是特地不准确,只有参数设置的正当,它的精确度能够管制的绝对足够准确,只会有小小的误判概率。个别用于大数据量的去重。 当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就必定不存在 。 打个比方,当它说不意识你时,必定就不意识;当它说见过你时,可能基本就没见过面,不过因为你的脸跟它意识的人中某脸比拟类似 (某些熟脸的系数组合),所以误判以前见过你。 Redis 官网提供的布隆过滤器到了 Redis 4.0 提供了插件性能之后才正式退场。布隆过滤器作为一个插件加载到 Redis Server 中,给 Redis 提供了弱小的布隆去重性能。 利用场景在爬虫零碎中,咱们须要对 URL 进行去重,曾经爬过的网页就能够不必爬了。然而 URL 太多了,几千万几个亿,如果用一个汇合装下这些 URL 地址那是十分节约空间的。这时候就能够思考应用布隆过滤器。它能够大幅升高去重存储耗费,只不过也会使得爬虫零碎错过大量的页面。 布隆过滤器在 NoSQL 数据库畛域应用十分宽泛,咱们平时用到的 HBase、Cassandra 还有 LevelDB、RocksDB 外部都有布隆过滤器构造,布隆过滤器能够显著升高数据库的 IO 申请数量。当用户来查问某个 row 时,能够先通过内存中的布隆过滤器过滤掉大量不存在的 row 申请,而后再去磁盘进行查问。 邮箱零碎的垃圾邮件过滤性能也广泛用到了布隆过滤器,因为用了这个过滤器,所以平时也会遇到某些失常的邮件被放进了垃圾邮件目录中,这个就是误判所致,概率很低。 装置docker间接应用> docker pull redislabs/rebloom # 拉取镜像> docker run -p6379:6379 redislabs/rebloom # 运行容器> redis-cli # 连贯容器中的 redis 服务插件装置# 下载编译装置Rebloom插件wget https://github.com/RedisLabsModules/rebloom/archive/v1.1.1.tar.gz# 解压 tar zxvf v1.1.1.tar.gzcd rebloom-1.1.1make# redis服启动增加对应参数rebloom_module="/usr/local/rebloom/rebloom.so"daemon --user ${REDIS_USER-redis} "$exec $REDIS_CONFIG --loadmodule $rebloom_module --daemonize yes --pidfile $pidfile"# 重启redis服务测试命令bf.add test testValue命令胜利阐明开启胜利应用布隆过滤器有二个根本指令,bf.add增加元素,bf.exists查问元素是否存在,它的用法和 set 汇合的 sadd 和 sismember 差不多。留神bf.add只能一次增加一个元素,如果想要一次增加多个,就须要用到bf.madd指令。同样如果须要一次查问多个元素是否存在,就须要用到bf.mexists指令。 ...

September 2, 2021 · 1 min · jiezi

关于redis:工具库系列之Redis-Golang分布式锁

Redis Golang分布式锁 English README 为什么要应用分布式锁? 多个过程或服务竞争资源,而这些过程或服务又部署在多台机器,此时须要应用分布式锁,确保资源被正确地应用,否则可能呈现副作用。防止反复执行某一个动作,多台机器部署的同一个服务上都有雷同定时工作,而定时工作只需执行一次,此时须要应用分布式锁,确保效率。具体业务:电商业务防止反复领取,微服务上多正本服务的夜间定时统计。 分布式锁反对: 单机模式的 Redis。哨兵模式的 Redis。阐明:该模式也是属于单机,Redis 是一主(Master)多从(Slave),只不过有哨兵机制,主挂掉后哨兵发现后能够将从晋升到主。单机和哨兵模式的 Redis 无奈做到锁的高可用,比方 Redis 挂掉了可能导致服务不可用(单机),锁凌乱(哨兵),但对可靠性要求没那么高的,咱们还是能够应用单机 Redis,毕竟大多数状况都比较稳定。 对可靠性要求较高,要求高可用,官网给出了 Redlock 算法,利用多台主(Redis Master)来逐个加锁,半数加锁胜利就认为胜利,因为要保护多套 Redis,略显繁琐。真真须要高可用,我倡议应用 etcd 官网实现的分布式锁 。 如何应用很简略,执行: go get -v github.com/hunterhug/gorlock本库反对无感知锁续命,你只有开启 KeepAlive,能够解决业务解决工夫过长,导致锁超时,而被其他人抢占重入的问题: // LockFactory is main interfacetype LockFactory interface { SetRetryCount(c int64) LockFactory GetRetryCount() int64 SetUnLockRetryCount(c int64) LockFactory GetUnLockRetryCount() int64 SetKeepAlive(isKeepAlive bool) LockFactory IsKeepAlive() bool SetRetryMillSecondDelay(c int64) LockFactory GetRetryMillSecondDelay() int64 SetUnLockRetryMillSecondDelay(c int64) LockFactory GetUnLockRetryMillSecondDelay() int64 LockFactoryCore}// LockFactoryCore is core interfacetype LockFactoryCore interface { // Lock lock resource default keepAlive depend on LockFactory Lock(ctx context.Context, resourceName string, lockMillSecond int) (lock *Lock, err error) // LockForceKeepAlive lock resource force keepAlive LockForceKeepAlive(ctx context.Context, resourceName string, lockMillSecond int) (lock *Lock, err error) // LockForceNotKeepAlive lock resource force not keepAlive LockForceNotKeepAlive(ctx context.Context, resourceName string, lockMillSecond int) (lock *Lock, err error) // UnLock unlock resource UnLock(ctx context.Context, lock *Lock) (isUnLock bool, err error) // Done asynchronous see lock whether is release Done(lock *Lock) chan struct{}}外围操作,就是建一个锁工厂,而后应用接口契约中的办法来生成锁,并操作这把锁。 ...

September 1, 2021 · 3 min · jiezi

关于redis:redis进阶2大数据量模糊计数

简述HyperLogLog 提供不准确的去重计数计划,用于记录大数据量的计数(如,网站的uv),尽管不准确然而也不是十分不准确,标准误差是 0.81%。 应用办法HyperLogLog 提供了两个指令 pfadd 和 pfcount,依据字面意义很好了解,一个是减少计数,一个是获取计数。pfadd 用法和 set 汇合的 sadd 是一样的,来一个用户 ID,就将用户 ID 塞进去就是。pfcount 和 scard 用法是一样的,间接获取计数值。 127.0.0.1:6379> pfadd codehole user1 user2 user3(integer) 3127.0.0.1:6379> pfcount codehole(integer) 3接下来咱们应用脚本,往里面灌更多的数据,看看它是否还能够持续准确上来,如果不能准确,差距有多大。 import redisclient = redis.StrictRedis()for i in range(100000): client.pfadd("codehole", "user%d" % i)print 100000, client.pfcount("codehole")> python pftest.py 100000 99723pfmergeHyperLogLog 除了下面的 pfadd 和 pfcount 之外,还提供了第三个指令 pfmerge,用于将多个 pf 计数值累加在一起造成一个新的 pf 值。 比方在网站中咱们有两个内容差不多的页面,经营说须要这两个页面的数据进行合并。其中页面的 UV 访问量也须要合并,那这个时候 pfmerge 就能够派上用场了。 # 合并三个key到第一个key:test_uv127.0.0.1:6379> PFMERGE test_uv test_uv2 test_uv3OK127.0.0.1:6379> pfcount test_uv5

September 1, 2021 · 1 min · jiezi

关于redis:springdataredis-连接泄漏我-TM-人傻了

本系列是 我TM人傻了 系列第四期[捂脸],往期精彩回顾: 降级到Spring 5.3.x之后,GC次数急剧减少,我TM人傻了这个大表走索引字段查问的 SQL 怎么就成全扫描了,我TM人傻了获取异样信息里再出异样就找不到日志了,我TM人傻了 本文基于 Spring Data Redis 2.4.9最近线上又出事儿了,新上线了一个微服务零碎,上线之后就开始报各种发往这个零碎的申请超时,这是咋回事呢? 还是经典的通过 JFR 去定位(能够参考我的其余系列文章,常常用到 JFR),对于历史某些申请响应慢,我个别依照如下流程去看: 是否有 STW(Stop-the-world,参考我的另一篇文章:JVM相干 - SafePoint 与 Stop The World 全解): 是否有 GC 导致的长时间 STW是否有其余起因导致过程所有线程进入 safepoint 导致 STW是否 IO 花了太长时间,例如调用其余微服务,拜访各种存储(硬盘,数据库,缓存等等)是否在某些锁下面阻塞太长时间?是否 CPU 占用过高,哪些线程导致的?通过 JFR 发现是很多 HTTP 线程在一个锁下面阻塞了,这个锁是从 Redis 连接池获取连贯的锁。咱们的我的项目应用的 spring-data-redis,底层客户端应用 lettuce。为何会阻塞在这里呢?通过剖析,我发现 spring-data-redis 存在连贯透露的问题。 咱们先来简略介绍下 Lettuce,简略来说 Lettuce 就是应用 Project Reactor + Netty 实现的 Redis 非阻塞响应式客户端。spring-data-redis 是针对 Redis 操作的对立封装。咱们我的项目应用的是 spring-data-redis + Lettuce 的组合。 为了和大家尽量说明确问题的起因,这里先将 spring-data-redis + lettuce API 构造简略介绍下。 ...

August 30, 2021 · 4 min · jiezi

关于redis:Redis原码阅读Object101

对象Redis基于后面的那些数据结构,创立了一个对象零碎用来实现键值对数据库。 那么就造成了五大根底对象 字符串对象 String列表对象 List哈希对象 Hash汇合对象 Set有序汇合对象 ZSet因为引入了对象,所有Redis实现了基于援用计数技术的内存回收机制,当程序不在应用某个对象的时候,对象所占用的内存就会被主动开释,另外还实现了对象共享机制,在某些条件下多个数据库能够共享一个对象来节约内存。 类型与编码Redis应用对象示意数据库中的键值,那么咱们创立一个键值对,咱们至多会创立两个对象 /* * Redis 对象 */#define REDIS_LRU_BITS 24#define REDIS_LRU_CLOCK_MAX ((1<<REDIS_LRU_BITS)-1) /* Max value of obj->lru */#define REDIS_LRU_CLOCK_RESOLUTION 1000 /* LRU clock resolution in ms */typedef struct redisObject { // 类型 unsigned type:4; // 编码 unsigned encoding:4; // 对象最初一次被拜访的工夫 unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */ // 援用计数 int refcount; // 指向理论值的指针 void *ptr;} robj;对象的ptr指针指向对象的底层实现数据结构,它是由encoding决定的 TYPE 键名 能够查看键对应的值对象类型set msg "hello"type msg stringrpush numbers 1 3 5type numbers list ...

August 29, 2021 · 1 min · jiezi

关于redis:新书介绍-Redis核心原理与实践

大家好,明天给大家介绍一下我的新书 —— 《Redis外围原理与实际》。 后端开发的同学应该对Redis都不生疏,Redis因为性能极高、功能强大,已成为业界十分风行的内存数据库。 《Redis外围原理与实际》这本书深刻地剖析了Redis罕用个性的外部机制与实现形式,大部分内容源自对Redis源码的剖析,并从中总结出实现原理。通过浏览本书,读者能够疾速、轻松地理解Redis的外部运行机制。 为什么写这本书?我始终心愿从源码层面深入分析一个C语言实现的分布式系统程序。起因如下:(1)C语言能够说是最靠近低级语言的开发语言,剖析C语言程序,能够让咱们更深刻了解操作系统底层常识。(2)随着互联网行业倒退,对后端系统高可用,高性能的要求越来越高,分布式系统也越来越风行。剖析一个分布式系统的设计与实现,对咱们的工作、学习都有很大帮忙。 于是,我便浏览学习了Redis源码,并编写了《Redis外围原理与实际》这本书。 为什么抉择Redis呢?因为Redis是一个典型的“小而美”的程序。 Redis实现简略,源码十分优雅简洁,浏览起来并不吃力,而且Redis功能齐全,涵盖了数据存储,分布式,音讯流等泛滥个性,十分值得深刻学习。 通过写作这本书,我对Redis,Unix编程,分布式系统、存储系统都有了更进一层的了解,再学习其余相干的零碎(如Mysql、Nginx,Kafka),也能够触类旁通,举一反三。心愿这本书也能够帮忙读者百尺竿头,更进一步。 本书构造第一局部次要剖析了Redis中字符串、散列、列表、汇合,有序汇合这五种数据类型的编码格局。 编码格局,即数据的存储格局,对于数据库,数据的存储格局至关重要,如关系型数据库的行式存储和列式存储。而Redis作为内存数据库,对于数据编码的总体设计思维是:最大限度的“以工夫换空间”,从而最大限度地节俭内存。 这一部分内容详细分析了Redis对内存的应用如何达到“斤斤计较”的水平。 第二局部剖析了Redis的外围流程,包含Redis事件机制与命令执行过程。 Redis利用IO复用模型,实现了本人的事件循环机制,而Redis正在由该事件机制驱动运行(很多近程服务程序都是应用相似的架构,如Nginx,Mysql等)。 Redis事件机制设计优雅,实现简略,并且性能卓越,能够说是“化繁为简”。 第三局部剖析了Redis长久化与复制机制。尽管Redis是内存数据库,但依然最大限度保障的数据的可靠性。 不论是文件长久化,还是从节点复制,核心思想都是一样的,通过将数据复制到多个正本中,从而放弃数据安全。 这部分内容分析了RDB、AOF长久化机制,主从节点复制流程等内容,向读者展现了Redis数据是如何“不翼而飞”的。 第四局部剖析了Redis分布式架构。这部分内容从风行的分布式算法Raft算法登程,剖析Sentient如何监控节点,Cluster集群如何实现数据分片,反对动静新增、删除集群节点,以及它们的“拿手好戏"——故障转移。 分布式系统经常让我联想到一个乏味的词,铁索连舟(将集群节点设想为”舟“,节点之间的网络连接设想为”索“)。 第五局部剖析了Redis中的高级个性,包含Redis事务、非阻塞删除、ACL权限管制列表、Tracking机制、Lua脚本、Module模块、Stream音讯流等内容,并且提供了具体的应用案例,帮忙读者循序渐进,由浅到深地进行学习了解。 Redis为各种高性能,高可用场景提供了十分全面的反对,能够说是”无所不包“。 本书特点本书深入分析Redis实现原理,并不是Redis入门书。为了尽量升高本书浏览难度,本书总结了Redis各外围性能的实现机制,提取Redis外围代码(本书会尽量避免沉积代码),并以适量图文,对Redis源码以及实现原理进行详细分析,向读者展现Redis外围性能的设计思维,实现流程。 本书尽管大部分内容基于Redis源码剖析,然而并不简单,即便你只是简略理解C语言的根底语法,也能够轻松读懂。 举荐理由新版本:基于Redis 6.0.9,并剖析了Redis新个性,如Redis 6的ACL、Tracking、IO线程等机制。重实际:本书在对应知识点的根底上提供了具体的利用示例,帮忙读者由浅到深地学习和了解Redis新个性。易把握:本书总结了Redis各个外围性能的实现原理,并以适量图文、丰盛示例,对Redis源码及其实现原理进行详细分析,循序渐进地向读者展现Redis外围性能的设计思维和实现流程。读者也能够联合本书,自行浏览Redis源码。内容丰盛:本书不仅剖析了Redis的性能,还由Redis源码延展了如下两方面内容: (1)具体介绍Redis中应用到的Unix机制,包含Unix网络编程、过程(线程)的利用等内容,并通过源码展现Redis如何应用这些Unix机制。 (2)深入分析Redis如何实现一个分布式系统,次要是Sentinel、Cluster机制如何实现一个高可用的分布式系统。因为我能力无限,书中不免有脱漏或谬误,若您在浏览本书的过程中有任何问题或者倡议,欢送大家沟通交流。我会对您提出的问题、倡议进行梳理与反馈,并在本书后续版本中及时做出勘误与更新。 通过本书编辑批准,我后续会在集体技术公众号(binecy)公布书中局部章节内容,作为书的预览内容,欢送大家查阅,谢谢。 京东链接 豆瓣链接

August 29, 2021 · 1 min · jiezi

关于redis:Redis原码阅读intset100

整数(intset)整数汇合是汇合键的底层实现之一,当一个汇合只蕴含整数元素,并且元素数量不多时,就会用它 整数汇合时Redis用于保留数值的,它能够保留int16_t、int32_t、nt64_t 别离对应short int long insert.h typedef struct intset { // 编码方式 uint32_t encoding; // 汇合蕴含的元素数量 uint32_t length; // 保留元素的数组 int8_t contents[];} intset;/* * intset 的编码方式 */#define INTSET_ENC_INT16 (sizeof(int16_t))#define INTSET_ENC_INT32 (sizeof(int32_t))#define INTSET_ENC_INT64 (sizeof(int64_t)整数汇合的每个元素都是contents数组的一个数组项,它是从小到大排列的,并且不蕴含反复。 你会发现这里的contents是int8_t也就是char、然而实际上contents不保留任何的char、contents数组真正类型却决与encoding属性的值。 如果encoding 为INTSET_ENC_INT16、那么contents就是一个int16_t类型的数组,short(最小值-32768、最大值32767)如果encoding 为INTSET_ENC_INT32、那么contents就是一个int32_t类型的数组,int(最小值-2147483648、最大值2147483647)如果encoding 为INTSET_ENC_INT64、那么contents就是一个int64_t类型的数组,long(太多了)降级如果你向一个int类型的数组中,插入了一个long怎么解决? 降级!!! 1、更具新类型的元素,扩大底层数组空间 2、将底层数组现有所有元素都转换为与新元素雷同的类型,而后进行一个排序,因为contents是有序不反复的 3、最初才是将新元素增加进去 原数组 【1】,【2】,【3】 int16_t 16*3=48插入 65535 int32_t1、重新分配空间大小 32*4=128 但此时之前的数据地位不变,而是在前面增加空间 2、上面就是将转换后元素放到正确的地位,并且要放弃有序性不变先挪动3到 32*2 ~~~ 32*3-1 64 ~~ 95 因为3的地位换了,所有会有肯定的空间空进去 48-63之后同样的情理挪动1和2最初剩下的地位就是留给新元素的将encoding从int16_t变为int32_t每次向整数汇合增加元素都可能引起降级,所有增加时O(N) 元素如果很小比方-12145641会呈现在头部,元素很大1231564会呈现在尾部。 这样的作法就时节约内存,有须要才会降级 整数的汇合是不反对降级操作的,一旦降级,encoding就不可能变小了所有这里就呈现一个问题,如果一个数组100个元素,有99个int16,一个int32,那么数组类型就会降级为int32这也时一种节约,这能不能想方法解决呢?

August 26, 2021 · 1 min · jiezi

关于redis:Redis

定义与根本信息Redis官网:https://redis.io NoSQL型数据库,以key,value的模式存储数据 Redis可实现一秒写8万次,读11万次,将所有数据都放在内存中,读写都在一个CPU上,是单线程的 共16个数据库,默认应用第0个 默认端口:6379 数据类型五种根本数据类型: String, List, Set, Hash, ZSet 三种非凡数据类型: Geospatial, Hyperloglog, Bitmap 作用数据库,缓存,MQ 根本数据类型常用命令连贯redisredis-cli -h host -p port -a passwordString类型命令# 设置键值对SET key value# 获取键值对GET key value# set if not existsSETNX key value# set with expireSETEX key time valueList类型命令list相当于一个双端队列 # 将一个值或多个值,插入到列表头部LPUSH key valueLPUSH key value1LPUSH key value2# 获取list,蕴含指定区间的值LRANGE key start end# 将一个值插入到列表尾部RPUSH key value3# 获取列表长度LLEN key# 移除列表中指定个数的值, 以下例子移除了key中count个valueLREM key count value# 将列表中指定下表值替换成另一个值LSET key index value# 将值插入到列表当中,位于值pivot之前或之后LINSERT key BEFORE|AFTER pivot valueset类型命令此类型中不能呈现反复的value ...

August 21, 2021 · 1 min · jiezi

关于redis:浅谈Redis集群下mget的性能问题

redis问题最近优惠服务的redis常常会间歇性的抖动,具体表现为在短时间内redis rt上涨显著,RedisCommandTimeoutException异样陡增,如下图: 监控面板是依照分钟级别进行统计,所以rt上涨看起来不是很显著。 这种状况必定不太失常,并且在近期呈现的频率有回升趋势。 定位起因遇到这种问题,首先会想到是不是redis自身抖动造成的,看表象其实很像,无规律,间歇性,影响工夫很短,所以第一工夫找了DBA确认过后是不是redis实例产生了问题,或者网络呈现了抖动,同时也去dms redis的监控面板上看下运行指标是否失常。很遗憾,失去的复原是服务抖动这段时间内,redis运行状况失常,网络情况也无任何异样,而且从监控面板上看,redis 运行状况十分好,cpu负载不高,io负载也不高,内核运行rt也都失常,无显著稳定。(下图抉择了redis集群中的一个节点实例,16个节点的情况基本一致) redis cpu: redis io: redis maxRT 到此,中间件自身的起因基本上是能够排除的了。那么,只能是应用姿态的问题了。应用姿态这块可能造成的影响,首先要定位是不是有hot key 还有big key,如果一个big key 又同时是hot key,那么极有可能在流量尖刺的同时造成这种景象。 先去阿里云redis监控面板上看hot key统计 发现一周内并无热点key,也没有大key,显然,缓存内容自身还是比拟正当的。这就有点头疼了,redis自身,以及缓存内容都没什么问题,那只能把眼光放到代码中了,由代码异样来逆推起因。 天眼监控上,发现很多RedisCommandTimeoutException异样,那么先采样看下产生异样的申请上下文 异样接口是:会场商品流批量算价服务 这个申请中用到了redis mget 同时获取多个keys,大略有几十个key,居然超时了,500ms的工夫都不够。 换个存在异样接口 能够这两个接口都用到了mget批量拉取keys ,从key的命名看来,还是依赖同样的数据,当然这不影响。下面咱们看到了redis 缓存的数据是没问题的,无大key 热点key,redis自身运行状态也衰弱,网络也失常,那么,只有一种可能,是不是这个mget有问题,mget是如何一次获取多个key的,带着疑难,咱们追一下mget的源码(零碎用的是Lettuce pool) public RedisFuture<List<KeyValue<K, V>>> mget(Iterable<K> keys) { //获取分区slot和key的映射关系 Map<Integer, List<K>> partitioned = SlotHash.partition(codec, keys); //如果分区数小于2也就是只有一个分区即所有key都落在一个分区就间接获取 if (partitioned.size() < 2) { return super.mget(keys); } //每个key与slot映射关系 Map<K, Integer> slots = SlotHash.getSlots(partitioned); Map<Integer, RedisFuture<List<KeyValue<K, V>>>> executions = new HashMap<>(); //遍历分片信息,一一发送 for (Map.Entry<Integer, List<K>> entry : partitioned.entrySet()) { RedisFuture<List<KeyValue<K, V>>> mget = super.mget(entry.getValue()); executions.put(entry.getKey(), mget); } // restore order of key 复原key的程序 return new PipelinedRedisFuture<>(executions, objectPipelinedRedisFuture -> { List<KeyValue<K, V>> result = new ArrayList<>(); for (K opKey : keys) { int slot = slots.get(opKey); int position = partitioned.get(slot).indexOf(opKey); RedisFuture<List<KeyValue<K, V>>> listRedisFuture = executions.get(slot); result.add(MultiNodeExecution.execute(() -> listRedisFuture.get().get(position))); } return result; });}整个mget操作其实分为了以下几步: ...

August 20, 2021 · 1 min · jiezi

关于redis:缓存-Redis-缓存避坑指南

作者:马功伟 青云科技软件开发工程师 目前从事青云数据库治理平台开发工作,始终从事 Server 端开发工作。 高并发业务场景下,常应用缓存技术缓解数据库压力,可极大的晋升用户体验和零碎稳定性。因为 Redis 本身的诸多个性,很适宜用来做缓存。上面是一个常见的缓存查问流程。 <center>缓存查问流程</center> 尽管缓存带来了较多数据库使用性能方面的晋升,也会带来一些缓存应用问题。 本文将为大家介绍并辨别 缓存穿透,缓存击穿,缓存雪崩 三个常见缓存问题,并针对不同问题提供相应解决思路。 | 缓存击穿查问申请下发后,缓存层中没有查问内容,数据库中有。在高并发场景下,某热点 Key 忽然生效,所有申请都打到数据库上,导致数据库压力过大。<center>查问击穿</center> 解决思路永不生效 这里分两种状况: 对缓存数据的 Redis Key 不设置过期工夫,在数据库写入后进行刷新缓存;另起异步工作在 Redis Key 将要过期的时候来更新缓存。应用互斥锁 业界常应用 mutex 。简略说,就是只容许一个线程重建缓存,其余线程期待重建缓存实现,再从缓存获取数据即可。 | 缓存穿透查问下发后,缓存层和数据库层都没有数据的状况。因为存储层查不到,导致无数据缓存。不存在的数据申请每次都要到存储层去查问,在高并发场景下,导致数据库压力过大。 <center>查问穿透</center> 解决思路缓存空值 对于缓存中没有并在数据库中查问不到的数据,能够缓存空值,并设置较短的有效期。 接口层进行校验 相似 ID=-1 这样的申请,能够在接口层减少参数和发性校验,对于校验不通过的申请间接 Return。 通过 IP 限流 对繁多 IP 进行限流,比方 10 次/ 2 秒。虚构货币交易所应用该解决方案。 布隆过滤器 当要查问一个数据时,应用 K 个哈希函数对元素值进行 K 次计算,失去 K 个哈希值,依据失去的哈希值,查看对应的 K 个比特值。 | 缓存雪崩高并发场景下,同一时间大面积的缓存生效,所有的申请打到数据库上,导致数据库压力过大。与缓存击穿不同的是,缓存击穿是并发查问同一条数据,缓存雪崩是大量的缓存生效。 <center>查问雪崩</center> 解决思路随机生成 Redis Key 的过期工夫 在写入缓存时随机生成 Key 的过期工夫,比方随机在 1-10 之间生成秒数。 ...

August 18, 2021 · 1 min · jiezi

关于redis:这个-Redis-连接池的新监控方式针不戳我再加一点佐料

Lettuce 是一个 Redis 连接池,和 Jedis 不一样的是,Lettuce 是次要基于 Netty 以及 ProjectReactor 实现的异步连接池。因为基于 ProjectReactor,所以能够间接用于 spring-webflux 的异步我的项目,当然,也提供了同步接口。 在咱们的微服务项目中,应用了 Spring Boot 以及 Spring Cloud。并且应用了 spring-data-redis 作为连贯 Redis 的库。并且连接池应用的是 Lettuce。同时,咱们线上的 JDK 是 OpenJDK 11 LTS 版本,并且每个过程都关上了 JFR 记录。对于 JFR,能够参考这个系列:[JFR 全解]() 在 Lettuce 6.1 之后,Lettuce 也引入了基于 JFR 的监控事件。参考:events.flight-recorder 1. Redis 连贯相干事件: ConnectEvent:当尝试与 Redis 建设连贯之前,就会收回这个事件。ConnectedEvent:连贯建设的时候会收回的事件,蕴含建设连贯的近程 IP 与端口以及应用的 Redis URI 等信息,对应 Netty 其实就是 ChannelHandler 中的 channelActive 回调一开始就会收回的事件。ConnectionActivatedEvent:在实现 Redis 连贯一系列初始化操作之后(例如 SSL 握手,发送 PING 心跳命令等等),这个连贯能够用于执行 Redis 命令时收回的事件。ConnectionDeactivatedEvent:在没有任何正在解决的命令并且 isOpen() 是 false 的状况下,连贯就不是沉闷的了,筹备要被敞开。这个时候就会收回这个事件。DisconnectedEvent:连贯真正敞开或者重置时,会收回这个事件。ReconnectAttemptEvent:Lettuce 中的 Redis 连贯会被保护为长连贯,当连贯失落,会主动重连,须要重连的时候,会收回这个事件。ReconnectFailedEvent:当重连并且失败的时候的时候,会收回这个事件。2. Redis 集群相干事件: ...

August 12, 2021 · 4 min · jiezi

关于redis:换一种存储方式居然能节约这么多内存

前言 提到缓存,就会想到redis,提到 Redis,咱们的脑子里马上就会呈现一个词:快。那么咱们也晓得,redis 之所以这么快,因为数据是放在内存中的,然而内存是十分低廉的,怎么来设计咱们的利用的存储构造,让利用满足失常的业务的前提下来节约内存呢?首先咱们从Redis的数据类型开始看起。 Redis 的数据类型及底层实现 说到redis的数据类型,大家必定会说:不就是 String(字符串)、List(列表)、Hash(哈希)、Set(汇合)和 Sorted Set(有序汇合)吗?” 其实,这些只是 Redis 键值对中值的数据类型,也就是数据的保留模式。 而这里,咱们说的数据结构,是要去看看它们的底层实现。简略说底层数据结构一共有 6 种: 简略动静字符串双向链表压缩列表哈希表跳表和整数数组。Redis 存储构造总览 其实在Redis中,并不是单纯将key 与value保留到内存中就能够的。它须要依赖下面讲的数据结构对其进行治理。 因为这个哈希表保留了所有的键值对,所以,我也把它称为全局哈希表。哈希表的最大益处很显著,就是让咱们能够用 O(1) 的工夫复杂度来疾速查找到键值对——咱们只须要计算键的哈希值,就能够晓得它所对应的哈希桶地位,而后就能够拜访相应的 entry 元素。每个entry 都会有一个数据类型。 Redis 不同数据类型的编码 而且每个类型又对应了多种编码格局,不同的编码格局对应的底层数据结构是不同的。能够先做个理解,前面会具体用到。 编码编码对应的底层数据结构INTlong 类型的整数EMBSTRembstr 编码的简略动静字符串RAW简略动静字符串HT字典 HASH\_TABLELINKEDLIST双端链表ZIPLIST压缩列表INTSET整数汇合SKIPLIST跳跃表和字典类型与编码映射类型编码编码对应的底层数据结构STRINGINTlong 类型的整数STRINGEMBSTRembstr 编码的简略动静字符串STRINGRAW简略动静字符串LISTZIPLIST压缩列表LISTQUICKLIST疾速列表LISTLINKEDLIST双端链表HASHZIPLIST压缩列表HASHHT字典SETINTSET整数汇合SETHT字典ZSETZIPLIST压缩列表ZSETSKIPLIST跳跃表和字典具体的映射关系1. 字符串类型(STRING)对象编码方式阐明编码方式阐明OBJ\_ENCODING\_RAW长度超过 44 个字节的字符串以这种形式编码OBJ\_ENCODING\_INT能够被转化为 long 类型整数的字符串以这种形式编码OBJ\_ENCODING\_EMBSTR不能被转化为 long 类型整数且长度不超过 44 个字节的字符串| 2. 汇合类型(SET)对象编码方式阐明编码方式阐明OBJ\_ENCODING\_INTSET增加的元素是整数,且保留的整数个数不超过配置项 set\_max\_intset\_entries (默认512)OBJ\_ENCODING\_HT增加的元素不是整数或者整数的个数超过配置项 set\_max\_intset\_entries (默认512)| 3. 有序汇合类型(ZSET)对象有序汇合类型的对象有两种编码方式:OBJ\_ENCODING\_SKIPLIST、OBJ\_ENCODING\_ZIPLIST。Redis 对于有序汇合类型的编码有两个配置项: zset\_max\_ziplist\_entries,默认值为 128,示意有序汇合中压缩列表节点的最大数量。zset\_max\_ziplist\_value,默认值为 64,示意有序汇合中压缩列表节点的最大长度。编码方式阐明OBJ\_ENCODING\_ZIPLIST增加的元素长度不超过 zset\_max\_ziplist\_value,且压缩列表节点数量不超过zset\_max\_ziplist\_entriesOBJ\_ENCODING\_SKIPLISTOBJ\_ENCODING\_SKIPLIST增加的元素长度超过 zset\_max\_ziplist\_value,或压缩列表节点数量超过zset\_max\_ziplist\_entries,会将压缩列表转化为跳表注:当删除或更新元素,使得满足以上两个配置项时,编码方式是不会主动从 OBJ\_ENCODING\_SKIPLIST 转化为 OBJ\_ENCODING\_ZIPLIST 的,但 Redis 提供了函数 zsetConvertToZiplistIfNeeded 反对。 4. 哈希类型(HASH)对象哈希类型对象有两种编码方式:OBJ\_ENCODING\_ZIPLIST、OBJ\_ENCODING\_HT。Redis 对于哈希类型对象的编码有两个配置项:hash\_max\_ziplist\_entries,默认值 512, 示意哈希类型对象中压缩列表节点的最大数量。hash\_max\_ziplist\_value,默认值 64,示意哈希类型对象中压缩列表节点的最大长度。编码方式阐明OBJ\_ENCODING\_ZIPLIST增加的元素长度不超过 hash\_max\_ziplist\_value,且压缩列表节点数量不超过hash\_max\_ziplist\_entriesOBJ\_ENCODING\_HT增加的元素长度超过 hash\_max\_ziplist\_value,或压缩列表节点数量超过hash\_max\_ziplist\_entries,会将压缩列表转化为字典注:当删除或更新元素,使得满足以上两个配置项时,编码方式是不会主动从 OBJ\_ENCODING\_HT 向 OBJ\_ENCODING\_ZIPLIST 转化。 ...

August 9, 2021 · 2 min · jiezi

关于redis:Redis总结篇下

主从复制主从复制是指将一台Redis服务器的数据,复制到其余的Redis服务器,前者称为主节点,后者称为从节点。 数据的复制是单向的,只能从主节点到从节点。主节点以写为主,从节点以读为主。 默认状况下,每台Redis服务器都是主节点。一个主节点能够有多个从节点一个从节点只能有一个主节点为什么要主从复制主从复制实现了数据的热备份故障复原,当主节点呈现问题,服务能够由从节点提供负载平衡,尤其是在写少读多的场景下,通过多个节点分担读负载主从复制是高可用的基石主从复制的外围机制Redis采纳异步形式复制数据到slave节点,Redis2.8开始,slave node会周期性地确认本人每次复制的数据量一个master node能够配置多个slave nodeslave能够连贯其余的slaveslave在复制的时候,不会阻塞master失常工作slave在复制的时候,不会阻塞本人的查问操作,复制实现后加载数据时会暂停对外服务全量复制|增量复制残缺同步: 当一个Redis服务器接管到replicaof命令,开始对另一个服务器进行复制的时候,主服务器会进行如下操作:主服务器bgsave生成一个RDB,缓存区存储bgsave命令之后的写命令主通过套接字传RDB给从从接管载入RDB文件主再把缓存区的写命令发送给从主机中的所有信息和数据,都会主动被从机备份保留。 全量复制:slave服务在接管到数据库文件数据后,将其存盘并加载到内存中增量复制:master持续将新的所有收集到的批改命令顺次传给slave,实现同步 外围原理Slave启动胜利后,会发送一个psync同步命令给master。 如果这是slave首次连贯到master,会触发一次full resynchronization 全量复制。master启动一个后盾线程,生成RDB快照,并且将新收到的写命令缓存在内存中。 master会将RDB发送给slave,slave会先写入本地磁盘,而后再从磁盘加载到内存中,接着master会将内存中的缓存的写命令发送到slave,slave也会同步这些数据。 如果slave和master断开连接会主动重连,连贯之后master仅会复制给slave局部短少的数据。 断点续传从Redis2.8开始,就反对主从复制的断点续传,如果主从复制过程中,断开了连贯,能够接着上次复制的中央持续复制上来。master会在内存中保护一个backlog,master和slave都会保留一个replica offset还有一个master run id, offset就是保留在backlog中的,如果master和slave网络连接断掉了,slave会让master从上次replica offset开始持续复制,如果没有找到对应的offset,那么就会执行一次 resynchronization。 无磁盘化复制master在内存中创立RDB,而后发送给slave,不会在本人本地落地磁盘了。只须要在配置文件中开启repl-diskless-sync yes 如果主机宕机了主机宕机,群龙无首,如果本台服务器想当老大,能够执行如下命令: redis> slaveof no one应用整个命令让本人变成主机,其余从机还是要手动抉择它作为老大。但如果这个时候,老大又好了,,,,老大也不是老大了,还得手动改回去 哨兵模式哨兵模式就是主动抉择老大的模式。Redis从2.8开始正式提供了Sentinel(哨兵)架构来解决这个问题。 哨兵模式是一种非凡的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的过程,作为过程,它会独立运行,其原理是哨兵通过发送命令,期待Redis服务器响应,从而监控运行的多个Redis实例。 Redis哨兵主备切换的数据失落问题导致数据失落的两种状况主备切换的过程,可能导致数据失落: 异步复制导致的数据失落因为master-slave的复制是异步的,所以可能有局部数据还没复制到slave,master就宕机了,此时这部分数据就失落了脑裂导致的数据失落脑裂,也就是说,某个master所在机器忽然脱离了失常的网络,跟其余slave机器不能连贯,但实际上master还运行着。哨兵认为master宕机,从新选了一个,集群中有两个master。尽管某slave变成master,但可能客户端还没来得及切换到新的master,还持续向旧master写数据。旧master复原的时候,会作为slave,本人的数据被清空,新master没有前面客户端写入的数据,所以这部分数据失落了。数据失落的解决方案进行如下配置: min-slaves-to-write 1min-slaves-max-lag 10 示意要求至多有1个slave,数据复制和同步的提早不能超过10秒一旦所有的slave,数据复制和同步的提早都超过了10秒钟,master就不会再接管任何申请了 缩小异步复制数据的失落:有了min-slaves-max-lag配置,就能够确保说,一旦slave复制数据和ack延时过长,就认为可能master宕机后损失的数据太多了,那么就回绝写申请,这样能够把master宕机时因为数据未同步到slave导致的数据失落升高的可控范畴内。 缩小脑裂的数据失落:如果一个master呈现了脑裂,跟其余slave丢了连贯,那么下面两个配置能够确保说,如果不能持续给指定数量的slave发送数据,而且slave超过10秒没有给本人ack音讯,那么就间接回绝客户端的写申请。因而在脑裂场景下,最多失落10秒数据。 启动Sentinel用户须要在配置文件中指定想要被Sentinel监督的主服务器,并且Sentinel也须要在配置文件中写入信息以记录主从服务器的状态。 $> redis-sentinel sentinel.conf //配置文件门路看具体的,也可能是/etc/sentinel.confSentinel配置文件须要蕴含以下选项: sentinel monitor <master-name> <ip> <port> <quorum>master-name: 指定主服务器的名字quorum: 判断这个主服务器下线所需的Sentinel数量当Sentinel开始监督一个主服务器之后,就会去获取被监督主服务器的从服务器名单,并依据名单对各个从服务器施行监督,整个过程是齐全主动的,所以用户只需输出待监督主服务器的地址就能够了。 Sentinel会对每个被监督的主从服务器施行心跳检测,记录各个服务器的在线状态、响应速度等信息,当Sentinel发现被监督的主服务器进入下线状态时,就会开始故障转移。 redis-sentinel是一个运行在非凡模式下的Redis服务器,也能够应用:redis-server sentinel.conf --sentinel去启动一个sentinel 一个Sentinel能够监督多个主服务器,在配置文中指定多个 sentinel monitor选项,给不同的主机设置不同的名字 新主机筛选规定设置从服务器优先级:配置文件里的replica-priority 默认值100,值越小优先级越高。0示意永远不会被选为主服务器。新主机的筛选规定: 先剔除不符合条件的从服务器 否决曾经下线、长时间没用回复心跳检测疑似下线的服务器否决长时间没有与主机通信,数据状态过期的服务器否决优先级为0的服务器依据以下规定,在残余的当中选 优先级最高的从服务器等同优先级复制偏移量最大的服务器以上都雷同选运行ID最小的Sentinel网络只抉择一个哨兵对Redis服务进行监控,可能会呈现问题,能够应用多个哨兵进行监控,各个哨兵之间还能够相互监控,这样就造成了多哨兵模式。 假如主服务器宕机,哨兵1查看到了这个后果,但他不会马上进行failover(故障转移)过程,仅仅只是哨兵1主观的认为主服务器不可用,这个景象称为主观下线。当前面的哨兵也检测到主服务器不可用,并且数量达到肯定值时,哨兵之间就会进行一次投票,投票的后果由一个哨兵发动,进行failover(故障转移)操作。切换胜利后,就会告诉公布订阅模式,让各个哨兵把本人监控的从服务器实现切换主机,这个过程称为主观下线。 当Sentinel网络中的其中一个Sentinel认为某个主服务器曾经下线时,它会将这个主服务器标记为主观下线,而后询问其余的Sentinel是否也将这个主服务器标记成了主观下线(sdown)。当这个批准主机下线的数量达到配置中设置的quorum指定的数量时,将主服务器标记为主观下线(odown)。 哨兵集群的主动发现机制哨兵相互之间的发现,是通过Redis的pub/sub零碎实现的。每个哨兵都会往__sentinel__:hello这个channel里发送一个音讯,这时候所有其余哨兵都能够生产到这个音讯,并感知到其余哨兵的存在。 每隔两秒钟,每个哨兵都会往本人监控的某个master+slaves对应的__sentinel__:hello channel里发送一个音讯,内容是本人的host、ip、runid还有对这个master的监控配置。 每个哨兵也会去监听本人监控的每个master+slaves对应的__sentinel__hello channel,而后去感知到同样在监听这个master+slaves的哨兵的存在。 ...

August 8, 2021 · 1 min · jiezi

关于redis:面试官怎么实现Redis分布式锁

本文曾经收录到github/gitee仓库,欢送大家围观、star github仓库: https://github.com/Tyson0314/... 如果github拜访不了,能够拜访gitee仓库。 gitee仓库:https://gitee.com/tysondai/Ja... 在单机环境下,当存在多个线程能够同时扭转某个变量(可变共享变量)时,就会呈现线程平安问题。这个问题能够通过 JAVA 提供的 volatile、ReentrantLock、synchronized 以及 concurrent 并发包下一些线程平安的类等来防止。 而在多机部署环境,须要在多过程下保障线程的安全性,Java提供的这些API仅能保障在单个JVM过程内对多线程访问共享资源的线程平安,曾经不满足需要了。这时候就须要应用分布式锁来保障线程平安。通过分布式锁,能够保障在分布式部署的利用集群中,同一个办法在同一时间只能被一台机器上的一个线程执行。 分布式锁须要满足四个条件: 互斥性。在任意时刻,只有一个客户端能持有锁。不会死锁。即便有客户端在持有锁的期间解体而没有被动解锁,也要保障后续其余客户端能加锁。加锁和解锁必须是同一个客户端。客户端a不能将客户端b的锁解开,即不能误会锁。容错性。只有大多数Redis节点失常运行,客户端就可能获取和开释锁。Redis分布式锁常见的实现分布式锁的形式有:数据库、Redis、Zookeeper。上面次要介绍应用Redis实现分布式锁。 Redis 2.6.12 之前的版本中采纳 setnx + expire 形式实现分布式锁,在 Redis 2.6.12 版本后 setnx 减少了过期工夫参数: SET lockKey value NX PX expire-time所以在Redis 2.6.12 版本后,只须要应用setnx就能够实现分布式锁了。 加锁逻辑: setnx争抢key的锁,如果已有key存在,则不作操作,过段时间持续重试,保障只有一个客户端能持有锁。value设置为 requestId(能够应用机器ip拼接以后线程名称),示意这把锁是哪个申请加的,在解锁的时候须要判断以后申请是否持有锁,避免误会锁。比方客户端A加锁,在执行解锁之前,锁过期了,此时客户端B尝试加锁胜利,而后客户端A再执行del()办法,则将客户端B的锁给解除了。再用expire给锁加一个过期工夫,避免异样导致锁没有开释。解锁逻辑: 首先获取锁对应的value值,查看是否与requestId相等,如果相等则删除锁。应用lua脚本实现原子操作,保障线程平安。 上面咱们通过Jedis(基于java语言的redis客户端)来演示分布式锁的实现。 Jedis实现分布式锁引入Jedis jar包,在pom.xml文件减少代码: <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version></dependency>加锁调用jedis的set()实现加锁,加锁代码如下: /** * @description: * @author: 程序员大彬 * @time: 2021-08-01 17:13 */public class RedisTest { private static final String LOCK_SUCCESS = "OK"; private static final String SET_IF_NOT_EXIST = "NX"; private static final String SET_EXPIRE_TIME = "PX"; @Autowired private JedisPool jedisPool; public boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) { Jedis jedis = jedisPool.getResource(); String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_EXPIRE_TIME, expireTime); if (LOCK_SUCCESS.equals(result)) { return true; } return false; }}各参数阐明: ...

August 8, 2021 · 2 min · jiezi

关于redis:Redis-实战篇巧用数据类型实现亿级数据统计

在挪动利用的业务场景中,咱们须要保留这样的信息:一个 key 关联了一个数据汇合,同时还要对汇合中的数据进行统计排序。 常见的场景如下: 给一个 userId ,判断用户登陆状态;两亿用户最近 7 天的签到状况,统计 7 天内间断签到的用户总数;统计每天的新增与第二天的留存用户数;统计网站的对访客(Unique Visitor,UV)量最新评论列表依据播放量音乐榜单通常状况下,咱们面临的用户数量以及访问量都是微小的,比方百万、千万级别的用户数量,或者千万级别、甚至亿级别的访问信息。 所以,咱们必须要抉择可能十分高效地统计大量数据(例如亿级)的汇合类型。 如何抉择适合的数据汇合,咱们首先要理解罕用的统计模式,并使用正当的数据了性来解决理论问题。 四种统计类型: 二值状态统计;聚合统计;排序统计;基数统计。本文将用到 String、Set、Zset、List、hash 以外的拓展数据类型 Bitmap、HyperLogLog 来实现。 文章波及到的指令能够通过在线 Redis 客户端运行调试,地址:https://try.redis.io/,超不便的说。 寄语多分享多付出,后期多给他人发明价值并且不计回报,从久远来看,这些付出都会成倍的回报你。 特地是刚开始跟他人单干的时候,不要去计较短期的回报,没有太大意义,更多的是锤炼本人的视线、视角以及解决问题的能力。 二值状态统计码哥,什么是二值状态统计呀?也就是汇合中的元素的值只有 0 和 1 两种,在签到打卡和用户是否登陆的场景中,只需记录签到(1)或 未签到(0),已登录(1)或未登陆(0)。 如果咱们在判断用户是否登陆的场景中应用 Redis 的 String 类型实现(key -> userId,value -> 0 示意下线,1 - 登陆),如果存储 100 万个用户的登陆状态,如果以字符串的模式存储,就须要存储 100 万个字符串了,内存开销太大。 对于二值状态场景,咱们就能够利用 Bitmap 来实现。比方登陆状态咱们用一个 bit 位示意,一亿个用户也只占用 一亿 个 bit 位内存 ≈ (100000000 / 8/ 1024/1024)12 MB。 大略的空间占用计算公式是:($offset/8/1024/1024) MB什么是 Bitmap 呢?Bitmap 的底层数据结构用的是 String 类型的 SDS 数据结构来保留位数组,Redis 把每个字节数组的 8 个 bit 位利用起来,每个 bit 位 示意一个元素的二值状态(不是 0 就是 1)。 ...

August 8, 2021 · 5 min · jiezi

关于redis:带你彻底搞懂-Redis-16大应用场景

1、缓存String类型 例如:热点数据缓存(例如报表、明星出轨),对象缓存、全页缓存、能够晋升热点数据的拜访数据。 2、数据共享分布式String 类型,因为 Redis 是分布式的独立服务,能够在多个利用之间共享 例如:分布式Session <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency>3、分布式锁String 类型setnx办法,只有不存在时能力增加胜利,返回true public static boolean getLock(String key) { Long flag = jedis.setnx(key, "1"); if (flag == 1) { jedis.expire(key, 10); } return flag == 1;}public static void releaseLock(String key) { jedis.del(key);}4、全局IDint类型,incrby,利用原子性 incrby userid 1000分库分表的场景,一次性拿一段 5、计数器int类型,incr办法 例如:文章的浏览量、微博点赞数、容许肯定的提早,先写入Redis再定时同步到数据库 6、限流int类型,incr办法 以访问者的ip和其余信息作为key,拜访一次减少一次计数,超过次数则返回false 7、位统计String类型的bitcount(1.6.6的bitmap数据结构介绍) 字符是以8位二进制存储的 set k1 asetbit k1 6 1setbit k1 7 0get k1 /* 6 7 代表的a的二进制位的批改a 对应的ASCII码是97,转换为二进制数据是01100001b 对应的ASCII码是98,转换为二进制数据是01100010因为bit十分节俭空间(1 MB=8388608 bit),能够用来做大数据量的统计。*/例如:在线用户统计,留存用户统计 setbit onlineusers 01 setbit onlineusers 11 setbit onlineusers 20反对按位与、按位或等等操作 ...

August 6, 2021 · 1 min · jiezi

关于redis:你遇到过缓存雪崩缓存穿透缓存击穿么

封面图 嗨~大家好啊,我是阿壮,一个后端程序员。Redis 当初成了缓存“专业户”,很多零碎的缓存都在应用 Redis,Redis 中缓存雪崩、击穿、穿透也成了陈词滥调的问题,明天带大家梳理一下,呈现这些问题的起因和解决方案。 缓存雪崩呈现的起因缓存雪崩呈现的起因是当某一时刻产生大规模的缓存生效的状况,比方你的缓存服务宕机了,会有大量的申请进来间接打到 DB 上,这样可能导致整个零碎的解体。 解决方案设置不同的过期工夫比较简单且好了解的计划是咱们在缓存的过期工夫上设置一个 1-5min 的随机值,这样每个缓存的过期工夫反复率就会升高,就能够防止缓存在某一时刻大规模到期的状况。 针对热 key 设置永不过期设置热 key 永不过期或者针对行将过期的热 key 应用异步线程一直的刷新过期工夫。 限流,应用锁或者队列,防止同时刻大量申请打崩 DB加锁或者队列的形式保障缓存的单线程写,这样能够防止缓存大量生效后,申请短时间内都打到 DB 上。毛病是零碎的吞吐率升高。 分级缓存缓存击穿呈现的起因缓存击穿和缓存雪崩比拟类似,缓存雪崩是 key 大部分生效,而缓存击穿式热点 key 生效。一个设置了过期工夫的 key 在某个工夫大并发间接申请,并且此时正好过期的状况下,申请在缓存中没有读取到数据就会间接打到 DB 上,导致服务解体。 解决方案加锁更新比方申请查问 A,发现缓存中没有,对 A 这个 key 加锁,同时去数据库查问数据,写入缓存,再返回给用户,这样前面的申请就能够从缓存中拿到数据了。 针对热 key 设置永不过期限流,应用锁或者队列,防止同时刻大量申请打崩 DB缓存穿透呈现的起因根本原因是申请了缓存中不存在的 key,导致每次申请都打到 DB 上。通常处于零碎容错思考,咱们会在查问后如果有后果则写入到缓存,这样下一次申请时就能够间接从缓存中读取数据。而后当申请的 id 在数据库中存在时,比方数据库中主键应用的自增 id,而申请的是-1,那么这将导致缓存中不存在这个数据而每次申请都会从数据库中查,这就失去了缓存的意义,当并发量很大时会导致系统宕机。 解决方案尽管从 DB 中查到的空,然而依然把数据写到缓存这是最简略粗犷的办法,不论从 DB 中查到的是什么都会写入到缓存,缓存有效期设置短些即可,比方 <=5min。 应用布隆过滤器布隆过滤器的原理是在你存入数据的时候,会通过散列函数将它映射为一个位数组中的 K 个点,同时把他们置为 1。当用户来查问 A,而 A 在布隆过滤器值为 0,间接返回,就不会打到 DB 了。应用布隆过滤器之后会有一个问题就是误判,因为它自身是一个数组,可能会有多个值落到同一个地位,那么实践上来说只有咱们的数组长度够长,误判的概率就会越低。 做好参数校验拦挡非法的参数就能够缩小 DB 中查不到数据的状况。 我是阿壮,一个后端程序员,微信搜一搜:科技猫,获取第一工夫更新,咱们下期见

August 4, 2021 · 1 min · jiezi

关于redis:redis-Cluster

本文次要讲Redis集群相干的机制 哨兵机制请参阅专栏:https://segmentfault.com/a/11... 本文参考: redis官网文档-Redis集群标准《redis设计与实现》Redis集群定义Redis集群是以高性能、平安和高可用为指标而设计的一套分布式实现。 高性能:高吞吐,同时具备高达1000个节点的线性扩大能力。没有代理、应用异步复制,同时也不会做值执行合并操作。 平安: 保障肯定水平的写平安,尽最大致力保留连贯大多数主节点的客户端的所有写操作。 高可用:在网络分区的状况,redis可能在领有大多数主节数的分区下失常提供服务,并且保障每个主节点至多领有一个从节点,当没有从节点的主节点产生故障须要转移时,能够从领有多个从节点的其余主节点接管一个从节点来进行转移。 对于写平安redis集群在主从节点间应用异步复制,而最初博得选举的主节点的数据将会替换所有其余从节点的正本。那么,在分区期间总有可能失落写入的工夫窗口。而这个工夫窗口在客户端连贯的是大多数主节点和多数主节点这两种不状况的状况下有很大的不同。而Redis集群则是进最大致力来保障连贯到大多数主节点的客户端执行的写入。 以下可能产生数据失落的场景 1、redis主节点宕机:redis主节点在解决完写入后将音讯返回给客户,再通过异步复制把写入操作同步到从节点,如果在写入音讯还没有同步到从节点之前主节点宕机了,因为主节点长时间无法访问Redis集群将会把其从节点降级为主节点,而从节点又没有同步宕机前在主节点执行的写入操作,那么这时候这个写入操作就失落了。 2、redis主节点所在的网络产生分区: 呈现以下事件时可能产生写入失落: 因为分区导致主节点不可达;产生故障转移,从节点降级为主节点;一段时间后主节点又可达;在Redis集群把这个旧主节点转换为新主节点的从节点之前,客户端通过过期的路由表把写操作发送到旧主节点。第1种状况产生可能写抛弃的工夫窗口实际上十分小,因为把响应写回客户端跟把写入操作流传给从节点,这简直是同时产生的。 第2种状况其实不太可能产生,因为故障的主节点在长时间(NODE_TIMEOUT)无奈与大多数主节点通信时,将会故障转移并且不再承受写入操作,而当分区复原时,在其余节点同步配置给它之前,会有一段时间回绝写入操作。同时,它还须要客户端有一个过期的路由表。 另外,在网络分区的状况下,如果客户端连贯的主节点在在具备多数主节点的分区中,在大数节点主节点分区中Redis集群检测到并产生故障转移之前,会有一个比拟大的失落写入的工夫容器。具体的来说,如果产生分区,在NODE_TIMEOUT达到之前复原了网络,那么不会产生数据库,因为工夫没有故障转移;而如果在NODE_TIMEOUT达到之前网络还没有复原,那么将触发故障转移,在NODE_TIMEOUT这段时间的所有写入操作都将失落了。 对于高性能在Redis Redis集群中,不会通过代理将申请转发到解决该key集的节点上,而是可能依据槽位的散布状况,间接地将向解决该key汇合的节点发送申请命令。节点之间通过异步复制,节点不须要期待其余节点的对写入的确认(前提是没有应用wait命令)防止值合并。容许多键操作,前提是波及多键操作的单个命令(或者事务、lua脚本)的所有键都是指向同一个hash槽。不存在值合并操作值合并操作通过产生在查问的键值对在不同节点上有不同的版本,须要获取多个节点的数据后对数据进行一次合并后再返回。 Redis的设计防止在不同节点上雷同的键值存在版本抵触,并且redis的数据模型也不容许这种行为。因为在Redis,值通常十分大,通过会看到蕴含数百万个元素的列表和排序集,另外redis的数据类型也比较复杂。如果须要传输并且合并不同节点上不同版本的值,这可能会是一个性能瓶颈,并且十分十分严格的程序来管制,同时也须要额定调配一些内存来治理它们。 对于高可用假如在大多数主节点的网络分区,有多个主节点,并且每个不可达主节点都有对应的从节点,在NODE_TIMEOUT后的几秒内就可能主动产生故障,而如果在领有多数节点的网络分区,Redis将是不可用的。实际上Redis集群的高可用须要有一个前提,即只是产生多数节点的故障。如果产生大规模的节点故障,那么Redis集群将不是一个适合的解决方案。 Redis集群部署及相干配置详见另一个链接: Redis集群相干机制key分布式Reids集群的key散布不同于单机,单机上所有key都散布在一个主节点上,而在Redis集群中,key会通过一致性哈希算法散布到不同槽位上,再把这些槽位调配给各个主节点。在Redis集群中,键空间(key space)会被划分为16384个槽位,实际上是redis设计了一致性哈希算法,通过这一算法可能将不同的key散列到这13684个槽位上。对于集群中的每一个主节点,它将解决这16384个槽位的一个子集,并且不同主节点的子集之间的元素没有交加,也就是说,一个槽位只会调配到一个主节点上,而一个主节点容许同时负责多个槽位的解决。 HASH_SLOT = CRC16(key) mod 16384key散列标签 除了通过一致性哈希来确认key所属的槽位,还能够通过哈希标签将一些雷同标签的key强制散列到同一个槽位上。比方,key的名字组成为aaa.{xxx}.ccc,那么将仅对{}内的xxx做哈希散列来计算出槽位。 散列标签的规定为,取第一呈现的{和第一次进去}两头的非空字符来做散列,以下列举几种取散列key的例子 key理论进行哈希散列的字符{user1}.nameUser1{{user1}}.name{user1{}.{user1}.name{}.{user1}.name (第一呈现的{和第一次进去}两头的字符为空字符串){class}.{user1}.nameclass集群拓朴redis集群由多个节点组成,每个节点与其它节点都会建设一个TCP连贯,整个redis集群的网络拓朴出现一个网状结构。redis集群中节间之间的连贯为长连贯,节点之间通过ping-pong的心跳来检测节点之间的状态,ping-pong的报文其中蕴含了gossip协定的报文,这能够用来做配置更新以及节点发现。 尽管节点之间有心跳,但通过gossip协定和配置更新机制能够防止失常运行状况下指数级的音讯替换。这个具体下文进行阐明。 节点间的握手一个集群通常由多个节点组成,在刚开始的时候,每个节点都是独立的,它们都只处于一个蕴含本人的集群中。那么如何将多个节点组成成一个大的集群? 实际上redis除了数据同步端口(比例默认状况下是6379)外,还须要监听一个集群总线端口(syncPort+10000,默认即16379)。集群间的握手通过总线端口来连贯,如果发送方与接受方同属一个集群,那么通过集群总线端口连贯后,接受方会立刻返回ping命令,否则将抛弃所有其余的数据包。 在redis集群,只有两种形式可能承受节点作为集群中的一部分: 第一种状况是通过Meet命令。节点node1向指定ip和port的节点node2发送meet命令,如CLUSTER MEET ip port,那么node2将被纳入到node1所在的集群,作为集群的一部分。第二种状况下,redis集群节点间的心跳蕴含gossip协定的报文,这里边蕴含除其本身节点外,多数随机的其余节点的信息。如果一个被信赖的节点通过gossip协定把其余节点的信息流传过去,那么以后节点也会认为它是可信赖的,最终也会建设到该节点的连贯。即A->B,B->C,那么A->C。槽位分派Redis集群反对通过CLUSTER的子命令去批改槽位的分派,具体的命令如下所示 CLUSTER ADDSLOTS slot1 [slot2] ... [slotN]CLUSTER DELSLOTS slot1 [slot2] ... [slotN]CLUSTER SETSLOT slot NODE nodeCLUSTER SETSLOT slot MIGRATING nodeCLUSTER SETSLOT slot IMPORTING nodeADDSLOTS和DELSLOTS仅用于节点调配槽,调配槽位意味着通知给定的主节点它将负责为指定的哈希槽提供存储和服务。ADDSLOTS通常用于从头创立集群,为每个主节点调配所有16384个可用你哈希槽的子集;DELSLOTS用于被动批改集群配置或者调试,实际上很有实在场景须要应用到。CLUSTER SETSLOT slot NODE node用于将槽调配给特定ID的节点。与ADDSLOTS的区别,集体认为,ADDSLOTS须要将命令发送到指定的主节点,而CLUSTER SETSLOT slot NODE node能够发送到集群中任一个主节点。MIGRATING和IMPORTING用来示意节点以后槽位的状态,MIGRATING示意以后槽位正在迁徙,IMPORTING示意以后槽位正在导入。 ...

August 4, 2021 · 1 min · jiezi

关于redis:一文读懂Redis的哨兵机制

大家好,我是memo,这几天正在看<<Redis设计与实现>>这本书籍,看到了哨兵机制这块知识点,置信大家在面试中或多或少都会遇到。为此,我做了小笔记,坚固常识。什么是哨兵机制哨兵机制(sentinel) 是Redis解决高可用的一种解决方案:它是由一个或者多个sentinel 实例组成的一个sentinel 零碎。如图所示: 上图显示sentinel系统监控着master节点和slave节点,并且slave节点与master节点存在数据复制性能。那么问题来了: sentinel零碎如何监控master节点和slave节点?master节点和slave节点复制原理?如果master节点呈现故障,sentinel零碎进行故障转移?sentinel零碎中多个sentinel节点如何进行通信?sentinel零碎如何把master节点和slave节点告诉给客户端?sentinel零碎如何判断master库是真的挂了?sentinel零碎到底选举哪个从库为新主库?......这些问题都会在后续文章中一一解答,心愿能够带着问题来阅读文章,带着本人的思考在文章中寻求解答,心愿能给你们一点帮忙。 sentinel根本流程sentinel其实就是一个运行在非凡模式下的Redis服务器。 在服务器初始化时,一般Redis服务器初始化时会通过载入RDB文件或者AOF文件来复原数据库状态,而sentinel服务器因为不应用数据库,所以它在初始化时无需载入RDB文件或者AOF文件。 哨兵机制提供三个性能:监控、故障转移、告诉。 监控:sentinel 零碎能够监控任意多个主服务,以及主服务所属的所有从服务器,监控着他们的生命状态。故障转移:当Redis主服务挂掉之后,sentinel零碎会从其所属的从服务器中选取一台从服务器作为master服务器保障服务的高可用。告诉:sentinel零碎会将主服务节点和从服务器节点相干信息告诉到客户端,让客户端的数据始终为最新状态。接下来,咱们先看监控。监控指的就是哨兵过程运行时,它会周期性地心跳检测,检测所有主从服务器是否失常运行。心跳检测形式为周期性向主从服务器发送PING命令,若主从服务器在规定工夫内响应哨兵过程,则判断该服务器处于存活状态;若主从服务器在规定工夫内没有响应哨兵过程,则哨兵过程会断定其下线。 如下图所示,主服务器server2在规定工夫内未响应sentinel过程,则sentinel过程判断主服务器server2主观下线,进行选举操作。 若主服务器处于下线状态时,哨兵过程会进行故障转移,也就是从新选主。选主就是会从其所属的多个从服务器中选举一个服务器作为新的主服务器,来提供服务。选举胜利后,哨兵过程让已下线主服务器属下的所有从服务器去复制新的主服务器,这一动作会通过向从服务器发送SLAVEOF命令来实现。 如下图,则展现了在故障转移操作中,sentinel节点向已下线主服务器server1的两个从服务器server3发送SLAVEOF命令,进行复制新的主服务器数据信息。 若旧的主服务器重新启动后,会成为新的主服务器的从服务器。 如下图所示,旧主服务器server1重新启动后,会默认成为新主服务器server2的从服务器,进行运行。 哨兵选举出新的主服务器后,会将新主服务器信息发送给客户端,让它和新的主服务器建设连贯就行,并不波及决策的逻辑。然而,在监控和选举过程中,哨兵须要做出两个决策:一个是判断主库是否下线;第二个是在选举过程中,选举哪个从服务器作为新的主服务器,提供服务。 sentinel获取主从服务器信息sentinel过程默认会以每隔10秒一次的频率,通过命令连贯向被连贯的主服务器发送INFO命令,并通过剖析INFO命令返回的数据来获取主服务器的以后信息以及所属从服务器信息。 如下图所示,主服务器server2和其三个从服务器server1、server3、server4。sentinel过程会向主服务器server2发送INFO命令,主服务器会返回对应的主服务器和从服务器的信息。 同理,sentinel过程也会向从服务器发送INFO命令,获取从服务器对应的节点信息。频率默认10秒一次。 多个sentinel进行通信在哨兵集群下,哨兵实例进行通信,是基于Redis提供的pub/sub机制的,也就是公布/订阅模式。 在主从集群中,哨兵节点不会间接与其余哨兵节点建设连贯,而是首先会和主库建设起连贯,而后向一个名为"_sentinel_:hello"频道发送本人的信息(IP+port),其余订阅了该频道的哨兵节点就会获取到该哨兵节点信息,从而哨兵节点之间互知。 艰深讲,Redis哨兵模式中,哨兵节点的互通是通过订阅指定的频道来进行的,而不是间接与其余sentinel节点建设起连贯。 举个例子,如果当初有sentinel1、sentinel2、sentinel3三个sentinel在监控同一个服务器,那么当sentinel1向主服务器的_sentinel_:hello频道发送一条信息时,所有订阅了_sentinel_:hello频道的sentinel(蕴含sentinel本人在内)都会收到这条音讯。如下图所示: 当一个sentinel从_sentinel_:hello频道收到一条音讯后,sentinel会对这条信息进行剖析,提取出信息中的sentinel IP地址、sentinel端口号、sentinel运行ID等八个参数,并进行查看: 如果信息中记录的sentinel运行ID和接管信息的sentinel的运行ID雷同,那么阐明这条音讯是sentinel本人发送的,sentinel将失落这条信息,不做进一步解决。相同地,如果信息记录的sentinel运行ID和接管信息的sentinel的运行ID不雷同,那么阐明这条信息是监控同一个服务器的其余sentinel发来的,接管信息的sentinel将依据信息中的各个参数,对相应主服务器的实例构造进行更新。主观下线和主观下线首先先解释一下什么是"主观下线"。 哨兵过程会应用PING命令的形式来检测各个主库和从库的网络连接状况,用来判断实例状态。如果哨兵发现主库或者从库响应超时,那么哨兵会断定其为"主观下线"。 如果哨兵检测从库,发现从库在规定工夫内未响应,那么哨兵就会把它标记为"主观在线",因为从库的下线影响个别不太大,集群的对外服务不会间断。然而,如果检测主库,哨兵不会简略把它标记为"主观在线",开启主从切换。 因为很有可能会有一种非凡状况:哨兵误判。也就是说主库自身没有故障,但因为哨兵的误判,判断它为下线状态。一旦启动主从切换,后续的选举和告诉操作都会带来额定的计算和通信开销。因而,为了不必要开销,咱们要严格留神误判的状况。 在哨兵集群中,断定主库是否处于下线状态,不是由一个哨兵来决定的,而是只有大多数哨兵认为主库曾经"主观下线",主库才会标记为"主观下线"。这种判断机制为:多数遵从少数。同时会触发主从切换模式。 举个例子,当初有sentinel1、sentinel2、sentinel3三个哨兵和master1一个主库和slave1、slave2、slave3三个从服务器。但sentinel1和sentinel2 判断master1处于上线状态,而sentinel3判断master1处于"主观下线",那么最终master1依然为上线状态。 简略的来说,"主观下线"的规范为,当有N个实例,最好要有N/2+1个哨兵实例认为其"主观下线",那么主库才是"主观下线"。 这样的益处缩小了误判的概率,防止了不必要的开销。(当然,有多个实例做出"主线下线"的判断才能够,也能够由Redis管理员自行设定) 选举新库当哨兵开始进行主从切换时,哨兵如何进行选举新的主库呢?它到底遵循什么样的机制? 一般来说,我把哨兵选举新主的过程总结为"筛选+排序"。首先,哨兵会依照肯定的筛选机制筛选掉不符合要求的从库,而后从符合条件的从库中进行排序,从而诞生出新库。 上述我把哨兵选举的过程称为"筛选+排序",那么接下来说一下筛选机制和排序机制。 首先先说筛选机制。 筛除掉所有处于下线或者断线状态的从服务器,这能够保障残余的从服务器都是失常在线的。筛除掉所有在规定工夫内没有响应哨兵的INFO命令的从服务器,这能够保障残余的从服务器都是最近胜利进行通信的。筛除掉所有与已下线主服务器连贯断开超过down-after-milliseconds*10毫秒的从服务器,这样能够保障残余的从服务器都没有过早地与主服务器断开连接,换句话来说,列表中的从服务器保留的数据都是比拟新的。上述的为筛选机制,接下来排序机制。 哨兵会依据从服务器的优先级,对列表中残余的从服务器进行排序,选出优先级最好的从服务器。若有多个雷同最好优先级的从服务器,那么哨兵会依照复制偏移量对具备雷同优先级的所有从服务器进行排序,并选出其中偏移量最大的从服务器。若有多个优先级最高、复制偏移量最大的从服务器,那么哨兵将依照运行ID对这些从服务器进行排序,并选出其中运行ID最小的从服务器。到这里,新主库就被选出来了,"选举"过程实现。咱们来回顾一下选举过程。首先哨兵会筛选掉已下线、断线状态、网络状态不好的从服务器,其次,会依据从服务器优先级、复制偏移量、运行ID方面进行排序,最终失去一个从服务器,那么该从服务器为新的主服务器。 基于pub/sub机制的客户端事件告诉从实质上说,哨兵就是一个运行在特定模式的Redis,只不过它并不服务于申请操作,只是实现监控、故障转移、告诉的工作。每个哨兵提供pub/sub机制,客户端能够从哨兵订阅音讯。 客户端能够从哨兵订阅所有事件,这样客户端不仅能够在主从切换后失去新主库的连贯信息,还能够监控主从库切换过程中产生的各个重要事件。 有了pub/sub机制,哨兵和哨兵之间、哨兵与从库之间、哨兵与客户端之间就能连接起来了, 再加上上述将的主库判断根据和选举根据,哨兵集群的监控、选举、告诉三个工作就能够失常运行了。 总结sentinel只是一个运行在非凡环境下的Redis,不提供数据存储服务。sentinel会通过向主服务器发送INFO命令获取主服务器所属的从服务器的地址信息,并为这些从服务器创立相应的实例构造,以及向这些从服务器发送命令连贯和订阅连贯。在个别状况下,sentinel会以每10s一次的频率向被监督的主库和从库发送INFO命令,获取主库和从库的相干信息。当主库处于下线状态,或者sentinel正对主服务器进行故障转移操作时,sentinel向从服务发送INFO命令的频率批改为每秒一次。对于监控同一个主服务器的哨兵来说,他们通过向主服务器的_sentinel_:hello发送音讯来向其余sentinel告知本人的存在。其余订阅了该频道的sentinel都能够接管到,从而各个sentinel互知。sentinel只会与主服务器和从服务器之间建设命令连贯和订阅连贯,而sentinel之间只会建设命令建设,进行通信。sentinel会以每秒一次的频率向实例(从服务器、主服务器、其余sentinel)发送PING命令,并依据实例对PING命令的回复来判断实例是否在线,当一个实例在指定工夫内未响应PING命令,则断定其为主观下线。在哨兵集群下,当sentinel收到足够多的主观下线投票之后,他会将主服务器判断为主观下线,并发动一个针对主服务器的故障转移操作。到这里,Redis哨兵机制内容也完结了,咱们下期再见!!! 我是memo,一个IT界的小学生。

August 1, 2021 · 1 min · jiezi

关于redis:redis过期策略复习

之前其实写过redis的过期的一些原理,这次次要是记录下,一些应用上的概念,次要是redis应用的过期策略是懒过期和定时革除,懒过期的其实比较简单,即是在key被拜访的时候会顺带着判断下这个key是否已过期了,如果曾经过期了,就不返回了,然而这种策略有个破绽是如果有些key之后始终不会被拜访了,就等于沉在池底了,所以须要有一个定时的清理机制,去从设置了过期的key池子(expires)里随机地捞key,具体的策略咱们看下官网的解释 Test 20 random keys from the set of keys with an associated expire.Delete all the keys found expired.If more than 25% of keys were expired, start again from step 1.从池子里随机获取20个key,将其中过期的key删掉,如果这其中有超过25%的key曾经过期了,那就再来一次,以此放弃过期的key不超过25%(左右),并且这个定时策略能够在redis的配置文件 # Redis calls an internal function to perform many background tasks, like# closing connections of clients in timeout, purging expired keys that are# never requested, and so forth.## Not all tasks are performed with the same frequency, but Redis checks for# tasks to perform according to the specified "hz" value.## By default "hz" is set to 10. Raising the value will use more CPU when# Redis is idle, but at the same time will make Redis more responsive when# there are many keys expiring at the same time, and timeouts may be# handled with more precision.## The range is between 1 and 500, however a value over 100 is usually not# a good idea. Most users should use the default of 10 and raise this up to# 100 only in environments where very low latency is required.hz 10能够配置这个hz的值,代表的含意是每秒的执行次数,默认是10,其实也用了hz的广泛含意。有趣味能够看看之前写的一篇文章redis系列介绍七-过期策略 ...

July 27, 2021 · 1 min · jiezi

关于redis:Redis总结篇上

@TOC Redis概述 ✍什么是RedisRedis是Remote Dictionary Server(近程字典服务器)的缩写,能够作为高效的缓存。Redis应用C语言开发,将数据保留在内存中,能够看成是一款纯内存的数据库,所以它的数据存取速度十分快。 Redis通过键值对的模式来存储数据。Redis的Key只能是String类型,Value值则能够是String类型,Map类型、List(列表)类型、Set(汇合)类型、SortedSet(有序汇合)等类型。 为什么用Redis做缓存相比于其余的键值对内存数据库,Redis有如下特点: 速度快。不须要期待磁盘IO,而是在内存之间进行数据存储和查问,速度十分快。缓存的数据总量不能太大,因为受到物理内存空间大小的限度丰盛的数据结构单线程,防止了线程切换和锁机制的性能耗费 ,不过6.0后是多线程了可长久化,反对RDB与AOF两种形式,将内存中的数据写入内部的物理存储设备反对公布、订阅反对Lua脚本反对分布式锁反对原子操作和事务反对主从复制和高可用集群反对管道,Redis管道是指客户端能够将多个命令一次性发送到服务器,而后由服务器一次性返回所有后果。管道技术的长处是,在批量执行命令的利用场景中,能够大大减少网络传输开销,进步性能Redis装置启动下载配置一下Redis Linux服务器上: 下载: wget http://download.redis.io/releases/redis-4.0.10.tar.gz 解压 tar -zxvf redis-4.0.10.tar.gz cd redis-4.0.10 make MALLOC=libc (要求已装置gcc) make install批改redis.conf文件 > redis-server redis.conf 启动> redis-cli -a password 连贯 也能够在命令行敞开:redis-cli -p 6379 -a your_password shutdown压测工具:redis-benchmark -h localhost -p 6379 -c 50 -n 10000具体可用参数翻文档Redis配置文件解读 ⚙ Redis数据类型 ✍String字符串Redis本人构建了简略的动静字符串SDS(相似ArrayList,预调配冗余空间),没有用c语言原生的。String类型既能够存储文字,又能够存储数数字,还能够存储二进制数据。 127.0.0.1:6379> set foo nameOK127.0.0.1:6379> mset f1 str f2 strr f3 strrrOK127.0.0.1:6379> get foo"name"127.0.0.1:6379> get f1"str"127.0.0.1:6379> mget f1 f2 f31) "str"2) "strr"3) "strrr"127.0.0.1:6379> strlen f1(integer) 3127.0.0.1:6379> set n1 1.0OK127.0.0.1:6379> get n1"1.0"127.0.0.1:6379> set n2 1OK127.0.0.1:6379> incr n2(integer) 2127.0.0.1:6379> set bina1 101110OK127.0.0.1:6379> get bina1"101110"利用场景缓存,String是很多语言都有的类型计数器,应用Redis做零碎的实时计数器共享用户Session,用户刷新一次页面,可能须要拜访一下数据进行从新登录,或者拜访页面缓存Cookie,能够利用Redis将用户的Session集中管理,只须要保障Redis的高可用,每次用户Session的更新和获取都能够疾速实现。List列表Redis的List类型是基于双向链表实现的,能够反对正向、反向查找和遍历。List列表是简略的字符串列表,字符串依照增加的程序排列。能够增加一个元素到List列表的头部或尾部。一个List列表最多能够蕴含2^32^-1个元素。 ...

July 25, 2021 · 3 min · jiezi

关于redis:redis4客户端连接信息

1: redis.config中连贯相干配置timeout 客户端连贯超时工夫 单位为秒tcp-keepalive 默认300maxclients 客户端最大连贯数量 默认100002: info clients127.0.0.1:6379[2]> info clients# Clientsconnected_clients:3client_longest_output_list:0client_biggest_input_buf:0blocked_clients:0名称含意connected_clients已连贯的客户端数量client_longest_output_list以后连贯的客户端当中,最长的输入列表client_longest_input_buf以后连贯的客户端当中,最大输出缓存blocked_clients正在期待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客户端的数量3:client list127.0.0.1:6379[2]> client listid=121 addr=192.168.199.1:51010 fd=9 name= age=158972 idle=73961 flags=N db=2 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=getid=151 addr=127.0.0.1:48072 fd=10 name= age=156536 idle=156536 flags=N db=1 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=selectid=215 addr=127.0.0.1:48079 fd=8 name= age=888 idle=0 flags=N db=2 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=clientaddr 客户端地址和端口fd 文件描述符age 以秒计算的已连贯时长idle 以秒计算的闲暇时长flags 客户端flagdb 该客户端正在应用的数据库 IDsub 已订阅频道的数量psub 已订阅模式的数量multi 在事务中被执行的命令数量qbuf 查问缓存的长度( 0 示意没有查问在期待)qbuf-free 查问缓存的残余空间( 0 示意没有残余空间)obl 输入缓存的长度oll 输入列表的长度(当输入缓存没有残余空间时,回复被入队到这个队列里)omem 输入缓存的内存占用量events 文件描述符事件cmd 最近一次执行的命令参考:https://redis.io/commands/cli... ...

July 22, 2021 · 1 min · jiezi

关于redis:REDIS缓存穿透缓存击穿缓存雪崩原因解决方案

一、前言在咱们日常的开发中,无不都是应用数据库来进行数据的存储,因为个别的零碎工作中通常不会存在高并发的状况,所以这样看起来并没有什么问题,可是一旦波及大数据量的需要,比方一些商品抢购的情景,或者是主页访问量霎时较大的时候,繁多应用数据库来保留数据的零碎会因为面向磁盘,磁盘读/写速度比较慢的问题而存在重大的性能弊病,一瞬间成千上万的申请到来,须要零碎在极短的工夫内实现成千上万次的读/写操作,这个时候往往不是数据库可能接受的,极其容易造成数据库系统瘫痪,最终导致服务宕机的重大生产问题。 为了克服上述的问题,我的项目通常会引入NoSQL技术,这是一种基于内存的数据库,并且提供肯定的长久化性能。 redis技术就是NoSQL技术中的一种,然而引入redis又有可能呈现缓存穿透,缓存击穿,缓存雪崩等问题。本文就对这三种问题进行较深刻分析。 二、初意识缓存穿透:key对应的数据在数据源并不存在,每次针对此key的申请从缓存获取不到,申请都会到数据源,从而可能压垮数据源。比方用一个不存在的用户id获取用户信息,不管缓存还是数据库都没有,若黑客利用此破绽进行攻打可能压垮数据库。缓存击穿:key对应的数据存在,但在redis中过期,此时若有大量并发申请过去,这些申请发现缓存过期个别都会从后端DB加载数据并回设到缓存,这个时候大并发的申请可能会霎时把后端DB压垮。缓存雪崩:当缓存服务器重启或者大量缓存集中在某一个时间段生效,这样在生效的时候,也会给后端系统(比方DB)带来很大压力。三、缓存穿透解决方案一个肯定不存在缓存及查问不到的数据,因为缓存是不命中时被动写的,并且出于容错思考,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次申请都要到存储层去查问,失去了缓存的意义。 有很多种办法能够无效地解决缓存穿透问题,最常见的则是采纳布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个肯定不存在的数据会被 这个bitmap拦挡掉,从而防止了对底层存储系统的查问压力。另外也有一个更为简略粗犷的办法(咱们采纳的就是这种),如果一个查问返回的数据为空(不论是数据不存在,还是系统故障),咱们依然把这个空后果进行缓存,但它的过期工夫会很短,最长不超过五分钟。 粗犷形式伪代码: //伪代码public object GetProductListNew() { int cacheTime = 30;String cacheKey = "product_list";String cacheValue = CacheHelper.Get(cacheKey);if (cacheValue != null) { return cacheValue;}cacheValue = CacheHelper.Get(cacheKey);if (cacheValue != null) { return cacheValue;} else { //数据库查问不到,为空 cacheValue = GetProductListFromDB(); if (cacheValue == null) { //如果发现为空,设置个默认值,也缓存起来 cacheValue = string.Empty; } CacheHelper.Add(cacheKey, cacheValue, cacheTime); return cacheValue;}}四、缓存击穿解决方案key可能会在某些工夫点被超高并发地拜访,是一种十分“热点”的数据。这个时候,须要思考一个问题:缓存被“击穿”的问题。 应用互斥锁(mutex key) 业界比拟罕用的做法,是应用mutex。简略地来说,就是在缓存生效的时候(判断拿进去的值为空),不是立刻去load db,而是先应用缓存工具的某些带胜利操作返回值的操作(比方Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回胜利时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的办法。 SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,能够利用它来实现锁的成果。 public String get(key) { String value = redis.get(key); if (value == null) { //代表缓存值过期 //设置3min的超时,避免del操作失败的时候,下次缓存过期始终不能load db if (redis.setnx(key_mutex, 1, 3 * 60) == 1) { //代表设置胜利 value = db.get(key); redis.set(key, value, expire_secs); redis.del(key_mutex); } else { //这个时候代表同时候的其余线程曾经load db并回设到缓存了,这时候重试获取缓存值即可 sleep(50); get(key); //重试 } } else { return value; }}memcache代码: ...

July 22, 2021 · 2 min · jiezi

关于redis:Redisconf

Redis.conf单位配置文件对大小写不敏感# 1k => 1000 bytes# 1kb => 1024 bytes# 1m => 1000000 bytes# 1mb => 1024*1024 bytes# 1g => 1000000000 bytes# 1gb => 1024*1024*1024 bytes…………蕴含# include /path/to/local.conf# include /path/to/other.conf…………bind 127.0.0.1 绑定的ipprotected-mode yes 保护模式port 6379 端口################################# GENERAL #####################################daemonize yes 守护过程形式运行,默认nopidfile /www/server/redis/redis.pid 如果当前台形式运行,要指定pid# Specify the server verbosity level.# This can be one of:# debug (a lot of information, useful for development/testing)# verbose (many rarely useful info, but not a mess like the debug level)# notice (moderately verbose, what you want in production probably)默认,生产环境# warning (only very important / critical messages are logged)loglevel noticelogfile "/www/server/redis/redis.log" 地位# dbid is a number between 0 and 'databases'-1databases 16 默认16个数据库长久化,redis是内存数据库,断电即失save 900 1 如果900s内至多有一个key批改,进行长久化操作save 300 10save 60 10000 stop-writes-on-bgsave-error yes 长久化出错,是否持续工作 rdbcompression yes 是否压缩 rdb 文件,要耗费肯定的cpu资源 rdbchecksum yes 保留 rdb 文件 是否要校验 dbfilename dump.rdb rdb 文件保留目录 ################################# REPLICATION ################################# ################################# SECURITY ################################## requirepass foobared 设置明码 ################################### CLIENTS ##################################### maxclients 10000 最大的连接数############################## MEMORY MANAGEMENT################################# maxmemory <bytes> 最大的容量 # maxmemory-policy noeviction 内存满了怎么解决 ############################## APPEND ONLY MODE ###############################aof的配置 appendonly no 默认不开启,默认rdb够用了appendfilename "appendonly.aof" 长久化的文件的名字# appendfsync always 每次都要 syncappendfsync everysec 每秒执行一次 sync 可能会失落一秒的数据# appendfsync no 不执行,操作系统本人同步数据

July 20, 2021 · 1 min · jiezi

关于redis:Redis高级数据类型HyperloglogBitmap快速带你上手

前言很多小伙伴在面试中都会被问道 Redis的罕用数据结构有哪些? 可能很大一部分答复都是 string、hash、list、set、zset。当然啦,这个答案必定是没有错的,然而置信这个答案,面试官曾经听的耳朵都起茧了。 自身咱们抉择的这个行业竞争就极强,学历拼不过难道还要常识都拼不过吗??? 心愿进来的小伙伴能好好看完这篇文章,也心愿你当前的答复能是 罕用的数据结构有string、hash、list、set、zset,但我平时可能还会用到 Hyperloglog和Bitmap。置信面试官听到你的答复,会有眼前一亮的感觉! 话不多说,开始吧,⬇ Hyperloglog Hyperloglog简介HyperLogLog是一种概率数据结构,用来估算数据的基数。 <font size="3">**基数:可简略了解为汇合中不同元素的个数,也能够了解为Set对于一个汇合 1、2、3、4,那么它的基数为 4对于一个汇合 1、2、3、4、1,那么它的基数也是 4** Hyperloglog作用咱们能够应用它来统计 UV。 <font size="3">UV即:UniqueVisitor,UV指的是==独立访客的数量==,一台电脑被视为一个独立访客。一台电脑早上拜访了一次,下午又拜访了一次,两次拜访的都是同一个网站,只能被计算一次。 那可能有小伙伴问了,及方才都说了能够了解为一个Set,那我为什么要用它来统计UV? **Redis 的 HyperLogLog 通过就义准确率来缩小内存空间的耗费,只须要12K内存,在标准误差0.81%的前提下,可能统计2^64个数据。而Set就须要耗费大量空间所以 HyperLogLog 是否适宜在比方统计区间活跃度这样对精度要求不高的场景。** 为什么能这么存储,次要依赖于伯努利试验,各位小伙伴能够去百度理解理解。 命令行中的应用pfadd \<key> [element]:增加数据pfcount \<key>:统计数量 SpringBoot中的应用@Testpublic void testHyperloglog() { String key = "language"; for (int i = 1; i <= 10000; i++) { redisTemplate.opsForHyperLogLog().add(key,i); } for (int i = 5000; i <= 15000; i++) { redisTemplate.opsForHyperLogLog().add(key,i); } for (int i = 10000; i <= 20000; i++) { redisTemplate.opsForHyperLogLog().add(key,i); } long size = redisTemplate.opsForHyperLogLog().size(key); System.out.println(size);}能够看到后果值为:19891与实在值:20000相差不了多少,虽说有误差,但相比于set曾经是很好了! ...

July 12, 2021 · 1 min · jiezi

关于redis:redis-读写分离架构技术解析

背景Redis 不论主从版还是集群规格,replica作为备库不对外提供服务,只有在产生HA的时候,replica晋升为master后才承当读写流量。这种架构读写申请都在master上实现,一致性较高,但性能受到master数量的限度。常常有用户数据较少,但因为流量或者并发太高而不得不降级到更大的集群规格。 为满足读多写少的业务场景,最大化节约用户老本,云数据库Redis版推出了读写拆散规格,为用户提供通明、高可用、高性能、高灵便的读写拆散服务 架构Redis集群模式有redis-proxy、master、replica、HA等几个角色。在读写拆散实例中,新增read-only replica角色来承当读流量,replica作为热备不提供服务,架构上放弃对现有集群规格的兼容性。redis-proxy按权重将读写申请转发到master或者某个read-only replica上;HA负责监控DB节点的衰弱状态,异样时发动主从切换或重搭read-only replica,并更新路由。 一般来说,依据master和read-only replica的数据同步形式,能够分为两种架构:星型复制和链式复制。 星型复制星型复制就是将所有的read-only replica间接和master放弃同步,每个read-only replica之间互相独立,任何一个节点异样不影响到其余节点,同时因为复制链比拟短,read-only replica上的复制提早比拟小。 Redis是单过程单线程模型,主从之间的数据复制也在主线程中解决,read-only replica数量越多,数据同步对master的CPU耗费就越重大,集群的写入性能会随着read-only replica的减少而升高。此外,星型架构会让master的进口带宽随着read-only replica的减少而成倍增长。Master上较高的CPU和网络负载会对消掉星型复制提早较低的劣势,因而,星型复制架构会带来比较严重的扩大问题,整个集群的性能会受限于master。 链式复制链式复制将所有的read-only replica组织成一个复制链,如下图所示,master只须要将数据同步给replica和复制链上的第一个read-only replica。 链式复制解决了星型复制的扩大问题,实践上能够有限减少read-only replica的数量,随着节点的减少整个集群的性能也能够基本上呈线性增长。 链式复制的架构下,复制链越长,复制链末端的read-only replica和master之间的同步提早就越大,思考到读写拆散次要应用在对一致性要求不高的场景下,这个毛病个别能够承受。然而如果复制链中的某个节点异样,会导致上游的所有节点数据都会大幅滞后。更加重大的是这可能带来全量同步,并且全量同步将始终传递到复制链的末端,这会对服务带来肯定的影响。为了解决这个问题,读写拆散的Redis都应用阿里云优化后的binlog复制版本,最大水平的升高全量同步的概率。 更多对于Redis技术栈的学习,能够关注民工哥技术之路公众号,在 Redis专栏 中查看相干的技术文章、面试题及答案,十分具体,继续更新中。 Redis读写拆散劣势通明兼容读写拆散和一般集群规格一样,都应用了redis-proxy做申请转发,多分片令应用存在肯定的限度,但从主从降级单分片读写拆散,或者从集群降级到多分片的读写拆散集群能够做到齐全兼容。 用户和redis-proxy建设连贯,redis-proxy会辨认出客户端连贯发送过去的申请是读还是写,而后依照权重作负载平衡,将申请转发到后端不同的DB节点中,写申请转发给master,读操作转发给read-only replica(master默认也提供读,能够通过权重管制)。 用户只须要购买读写拆散规格的实例,间接应用任何客户端即可间接应用,业务不必做任何批改就能够开始享受读写拆散服务带来的微小性能晋升,接入老本简直为0。 高可用高可用模块(HA)监控所有DB节点的衰弱状态,为整个实例的可用性保驾护航。master宕机时主动切换到新主。如果某个read-only replica宕机,HA也能及时感知,而后重搭一个新的read-only replica,下线宕机节点。 除HA之外,redis-proxy也能实时感知每个read-only replica的状态。在某个read-only replica异样期间,redis-proxy会主动升高这个节点的权重,如果发现某个read-only replica间断失败超过肯定次数当前,会临时屏蔽异样节点,直到异样隐没当前才会复原其失常权重。 redis-proxy和HA一起做到尽量减少业务对后端异样的感知,进步服务可用性。能够参考:Redis低成本高可用计划 高性能对于读多写少的业务场景,间接应用集群版本往往不是最合适的计划,当初读写拆散提供了更多的抉择,业务能够依据场景抉择最适宜的规格,充分利用每一个read-only replica的资源。 目前单shard对外售卖1 master + 1/3/5 read-only replica多种规格(如果有更大的需要能够提工单反馈),提供60万QPS和192 MB/s的服务能力,在齐全兼容所有命令的状况下冲破单机的资源限度。后续将去掉规格限度,让用户依据业务流量随时自在的减少或缩小read-only replica数量。 Redis主从异步复制,从read-only replica中可能读到旧的数据,应用读写拆散须要业务能够容忍肯定水平的数据不统一,后续将会给客户更灵便的配置和更大的自在,例如配置能够容忍的最大延迟时间。 作者:小酷爱起源:juejin.cn/post/6955355686108659726

July 9, 2021 · 1 min · jiezi

关于redis:Redisson-分布式锁源码-07公平锁释放

前言看门狗机制是在 RedissonBaseLock#scheduleExpirationRenewal 办法中,这块偏心锁和非偏心锁并无区别。 前文曾经理解到,偏心锁加锁失败之后,会将以后放到期待队列中,通过 Java 代码中的循环不断尝试取得锁。 锁开释被动开释源码:RedissonFairLock#unlockInnerAsync KEYS[1]:加锁的名字,anyLock;KEYS[2]:加锁期待队列,redisson_lock_queue:{anyLock};KEYS[3]:期待队列中线程锁工夫的 set 汇合,redisson_lock_timeout:{anyLock},是依照锁的工夫戳寄存到汇合中的;KEYS[4]:redisson_lock__channel:{anyLock};ARGV[1]:LockPubSub.UNLOCK_MESSAGE;ARGV[2]:锁超时工夫 30000;ARGV[3]:UUID:ThreadId 组合 58f6c4a2-9908-4957-b229-283a45359c4b:47;ARGV[4]:currentTime 以后工夫戳。 这块逻辑突出局部曾经标出,重点就是开释锁。 锁在队列中,超时了则间接从队列中移除;锁缩小重入次数,缩小后,如果重入次数大于 0,重置超时工夫,如果不大于 0,则间接移除锁。这样的话后续就其余线程从期待队列中开始取得锁。 超时删除 在加锁和开释锁的 lua 脚本中,第一段永远是一个 while true do xxx,作用就是用来移除队列中超时的锁。 而持锁线程的开释,则和非偏心锁没有任何区别,当锁超时或者服务宕机,锁就会被主动开释。(这个是指 anyLock)。 总结偏心锁的开释同样分为被动开释和超时开释。 被动开释,即本人调用开释锁。超时删除,则分为两种,一种是持锁线程超时删除,这种和非偏心锁没有任何区别,因为这个锁也是含有超时工夫+看门狗续租的。另一种则是期待队列中的超时删除,是在每次获取锁之前,判断第一个期待线程的工夫戳是否超时,从而移除锁。相干举荐Redisson 分布式锁源码 06:偏心锁排队加锁Redisson 分布式锁源码 05:偏心锁加锁Redisson 分布式锁源码 04:可重入锁开释

July 9, 2021 · 1 min · jiezi

关于redis:hyperloglog原理

1. 需要当初有个需要,须要对立段时间内登陆的用户数量。这一段时间里可能先后登陆了用户a、b、c、b、c、a、d这么多人,可能有人反复登陆,咱们在解决时就须要去重而后返回用户数量。 下面的状况就是基数统计:获取一个汇合S去重之后的汇合大小。 一种办法就是应用hashmap,hashmap的key是用户名,value是它登陆的次数。在64位机器中,golang在一条记录上应用24个字节。当用户成千上万乃至上亿的时候,须要的内存空间就十分大了。 为了节俭内存空间,还有其余办法:$B^+$树、Bitmap等,Redis中应用HyperLogLog来进行粗略的统计,12k内存能够统计$2^{64}$个数据。 2. 伯努利试验HyperLogLog的原理和伯努利试验无关。 投掷硬币,侧面和背面呈现的概率都是50%。那始终投掷硬币直到第t次投掷呈现侧面,这个过程就是一次伯努利试验。 如果进行n次伯努利试验,第1次试验,n=1,对应的投掷次数为$t_1$;第n次试验,对应的投掷次数为$t_n$。 进行完这么屡次试验之后,必定有一个最大的投掷次数$t_{max}$ n次伯努利试验的投掷次数都不大于 $t_{max}$n次伯努利试验中,至多有一次投掷次数等于 $ t_{max}$n和$ t_{max}$存在如下估算关系: $$n=2^{t_{max}}$$ 具体的推导我就不说了,概率论的相干内容。 通过屡次伯努利试验的 $ t_{max}$能够推导失去进行的伯努利试验的次数n。那么如果把HyperLogLog的一次ADD当做一次伯努利试验,那么通过计算每次伯努利试验的最大投掷次数$ t_{max}$应该就能够求出HyperLogLog统计的元素数量n了。这就是HyperLogLog的基本原理。 HyperLogLog的第i次ADD的投掷次数$t_i$怎么计算呢?每次ADD的元素的hash值是一系列0和1组合的字节码,那么就能够通过统计从某个地位、某个方向开始第一个1所在的地位来计算$ t_i$。例如,0b1010 1000,从最低位向最高位计算失去$t=4$。 3. HyperLogLogHyperLogLog基于LogLogCounting等算法,它应用一个简直平均的hash函数获取须要统计的元素的hash值,而后通过分桶均匀打消误差。HLL(之后均代表HyperLogLog)把hash值分成一个一个的桶,并且用hash值的前k个位来寻找它的桶地位,桶的数量示意成: $$m=2^k$$ 如下图,LSB示意最低位,MSB示意最高位,这个hash值示意为大端字节序。k=6,阐明一共有64个桶。而下图的hash值示意的桶地位是0b00 1101=13。 接下来计算上图hash值中后L-k的序列中第一个1呈现的地位:6。因而在索引号为13的桶中进行后续操作,如果桶中的数字比6小就设置为6,否则就不变。 统计每个桶中贮存的值的平均数,就能够计算失去估算的基数值。 HLL中应用和谐平均数进行计算: $$H=\frac{n}{\frac{1}{x_1}+\frac{1}{x_2}+...+\frac{1}{x_n}}=\frac{n}{\sum_{i=1}^n\frac{1}{x_i}}$$ 它的基数估算公式就是: $$\hat{n}=\frac{\alpha_mm^2}{\sum_{i=0}^m2^{-M[i]}}$$ 其中,M[i]示意第i个桶中的数值,示意为该hash值下第一个1对应的最大地位。 还有: $$\alpha_m=(m\int_0^\infty(log_2(\frac{2+u}{1+u}))^mdu)^{-1}$$ HLL的执行步骤能够通过这个HLL模仿网站进行理解,建设大抵的印象为后续的内容铺垫。 http://content.research.neust...能够看出,HLL占用很少的内存来实现十分大的基数统计,相应的实现也必然很简单,下一节就是剖析其在redis中的实现。 4. redis HLL实现4.1. HLL介绍redis HLL代码: https://github.com/crazyStrom...redis应用register(寄存器)来示意hash定位的桶,其中的内容就是统计的hash值的L-k那一部分中第一个1的最大地位。上面是redis代码中的HLL介绍。 redis应用[1]中提出的64位hash函数,通过在每个寄存器或桶中减少1bit,将基数统计的下限进步到$10^9$以上。 [1] Heule, Nunkesser, Hall: HyperLogLog in Practice: Algorithmic Engineering of a State of The Art Cardinality Estimation Algorithm.*redis应用它的sds来贮存HLL,并不创立新的数据类型。 redis不对[1]中的数据结构进行额定的压缩。redis应用[2]中的HyperLogLog的算法,惟一不同的是redis应用64位hash函数。 [2] P. Flajolet, Éric Fusy, O. Gandouet, and F. Meunier. Hyperloglog: The analysis of a near-optimal cardinality estimation algorithm.*redis在HLL中应用两种不同的数据贮存模式: ...

July 8, 2021 · 6 min · jiezi

关于redis:Redisson-分布式锁源码-05公平锁加锁

前言默认的加锁逻辑是非偏心的。 在加锁失败时,线程会进入 while 循环,始终尝试取得锁,这时候是多线程进行竞争。就是说谁抢到就是谁的。 Redisson 提供了 偏心锁 机制,应用形式如下: RLock fairLock = redisson.getFairLock("anyLock");// 最常见的应用办法fairLock.lock();上面一起看下偏心锁是如何实现的? 偏心锁置信小伙伴们看过后面的文章,曾经驾轻就熟了,间接定位到源码办法:RedissonFairLock#tryLockInnerAsync。 好家伙,这一大块代码,我截图也截不完,咱们间接剖析 lua 脚本。 PS:尽管咱不懂 lua,然而这一堆堆的 if else 咱们大略还是能看懂的。因为 debug 发现 command == RedisCommands.EVAL_LONG,所以间接看上面一部分。 这么长,连呼好几声好家伙! 先来看看参数都有啥? KEYS[1]:加锁的名字,anyLock;KEYS[2]:加锁期待队列,redisson_lock_queue:{anyLock};KEYS[3]:期待队列中线程锁工夫的 set 汇合,redisson_lock_timeout:{anyLock},是依照锁的工夫戳寄存到汇合中的;ARGV[1]:锁超时工夫 30000;ARGV[2]:UUID:ThreadId 组合 a3da2c83-b084-425c-a70f-5d9a08b37f31:1;ARGV[3]:threadWaitTime 默认 300000;ARGV[4]:currentTime 以后工夫戳。 加锁队列和汇合是含有大括号的字符串。{XXXX} 是指这个 key 仅应用 XXXX 用来计算 slot 的地位。Lua 脚本剖析下面的 lua 脚本是分为几块的,咱们别离从不同的角度看下下面代码的执行。 首次加锁(Thread1) 第一局部,因为是首次加锁,所以期待队列为空,间接 跳出循环。这一部分执行完结。 第二局部: 当锁不存在,期待队列为空或队首是以后线程,两个条件都满足时,进入外部逻辑;从期待队列和超时汇合中删除以后线程,这时候期待队列和超时汇合都是空的,不须要任何操作;缩小队列中所有期待线程的超时工夫,也不须要任何操作;加锁并设置超时工夫。执行完这里就 return 了。所以前面几局部就临时不看了。 相当于上面两个命令(整个 lua 脚本都是原子的!): > hset anyLock a3da2c83-b084-425c-a70f-5d9a08b37f31:1 1> pexpire anyLock 30000 ...

July 7, 2021 · 1 min · jiezi

关于redis:Redis-Lua-教程

lua-redis简介在Redis中应用Lua脚本在业务开发中是比拟常见的事件,应用Lua的长处有以下几点。 对于与屡次redis指令的发送,应用Lua脚本能够缩小网络的开销。当网络传输慢或者响应要求高的场景中尤为要害。Lua脚本能够将多个申请通过脚本模式一次进行解决,缩小网络的相干时延。Redis还提供了Pipeline来解决这个问题,然而在后面指令会影响前面指令逻辑的场景下,Pipeline并不能满足。原子操作。在Lua脚本中会将整个脚本作为一个整体来执行,两头不会被其余指令而打断,因而保障了原子性。因而在咱们写Lua脚本时,无需思考竞争而导致的整体数据状态不统一的问题,并且无需应用事务。并且因为此个性,需确保脚本尽可能不要运行工夫过长,要确保脚本执行的粒度最小化。复用和封装。针对于一些通用能力的性能,把这些放到redis脚本中去实现。其余客户端调用雷同的脚本代码,从而达到逻辑的复用。比照Lua脚本与事务:Lua脚本自身也能够看作为一种事务,而且应用脚本起来更简略,并且可管制的流程更灵便。 在应用Redis事务的时候会遇到两种问题: 事务在调用EXEC之前,产生了语法错误(如参数数量,参数名等问题)或者服务器内存等问题。遇到这一类问题是,会在服务器运行这些指令前发现这些问题(2.6.5之后),并且终止此次的事务。事务执行EXEC调用之后的失败,如事务中某个键的类型谬误的问题。两头指令的谬误并不会终止前面的流程,也不会导致后面指令的回滚。然而在Lua脚本中,你能够齐全管制这些。Lua-Redis指令教程注入和应用脚本:运行脚本时把脚本发送到Redis(网络开销较大) EVAL script numkeys [key ...] [arg ...]# 运行脚本redis> EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second# 运行只读脚本,脚本须要不蕴含任何批改内容的操作。这个指令能够随便被kill掉,# 而且不会影响到正本的stream。这个指令能够在master和replica上执行。redis> EVAL_RO "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second上传脚本,之后应用SHA1校验和来调用脚本。(潜在碰撞问题,在应用时个别会漠视) SCRIPT LOAD scriptEVALSHA sha1 numkeys key [key ...] arg [arg ...]redis> SCRIPT LOAD "return 'hello moto'""232fd51614574cf0867b83d384a5e898cfd24e5a"# 运行脚本redis> EVALSHA 232fd51614574cf0867b83d384a5e898cfd24e5a 0"hello moto"# 运行只读脚本,脚本须要不蕴含任何批改内容的操作。这个指令能够随便被kill掉,# 而且不会影响到正本的stream。这个指令能够在master和replica上执行。redis> EVALSHA 232fd51614574cf0867b83d384a5e898cfd24e5a 0其余一些指令SCRIPT DEBUG 用来调试脚本 DocumentSCRIPT EXISTS 通过校验值用来查看脚本是否存在 DocumentSCRIPT FLUSH 革除脚本 DocumentSCRIPT KILL 停到当初执行中的脚本,默认脚本没有写操作 Document留神点运行脚本须要严格依照Keys和Args的要求来进行传参。 所有操作到的redis key应放到Keys对象中,否则可能会影响到在redis集群中谬误体现。 ...

July 6, 2021 · 2 min · jiezi

关于redis:Redisson-分布式锁源码-04可重入锁释放

前言后面曾经理解到了,可重入锁加锁,看门狗以及锁的互斥阻塞。 当锁加锁胜利之后,锁是如何开释的? 被动开释源码入口:RedissonLock#unlock 在解锁时会获取以后线程的id。 一路往里跟,间接来到 RedissonLock#unlockInnerAsync: 剖析一下 lua 脚本的内容: 如果锁不存在,间接返回 null;如果锁存在,则对锁的重入次数 -1; 残余重入次数大于 0,从新设置过期工夫,返回 0;残余重入次数不大于 0,删除 redis key 并公布音讯,返回 1;被动开释锁这块思考的不仅仅是对 key 进行解决,因为可能存在重入锁,所以会先对 redis key 对应的 hash value 进行递加,相当于减去重入次数。 主动开释相比拟被动开释,主动开释就比拟容易了解了。 当服务宕机时,看门狗不再看门,那么最多 30s 之后锁被主动开释;当设置锁的工夫时,锁到了工夫,主动开释。总结 Redisson 锁的开释分为两种: 被动开释:本人调用 API unlock 即可;宕机/到期主动开释:Redis key 指定工夫主动过期。相干举荐Redisson 分布式锁源码 03:可重入锁互斥Redisson 分布式锁源码 02:看门狗Redisson 分布式锁源码 01:可重入锁加锁

July 6, 2021 · 1 min · jiezi

关于redis:10款Redis容器化技术选型对比K8S并非万金油

本文依据我在〖deeplus直播第247期〗线上分享演讲内容整顿而成。 明天将分享的内容分为以下4个方面: 一、缘起二、介绍多样的容器化技术三、Redis介绍四、Redis容器化计划的比照一、缘起 首先咱们先聊一下为什么明天我会分享这个主题。我和敌人一起组织了一个 Redis技术交换群,到当初曾经经营了6年左右的工夫,其中某一天在群里有一个小伙伴就抛出来一个问题: 他问大家线上的Redis有没有应用Docker装置?Docker应用Host的网络模式、磁盘应用本地挂载模式这种计划怎么样?这里的话咱们临时先不说这个计划如何,因为在明天的分享之后,我置信大家对于这个计划应该会有一个更清晰的意识和评估。 二、介绍多样的容器化技术 1、chroot和jails 在容器化技术方面,其实历史很长远了。尽管咱们当初用的容器化技术,或者说 k8s,还有云原生的概念是近几年才火起来的,然而实际上就容器化技术的倒退来说,其实是很早的了。比如说最早的时候来自chroot,chroot大家可能都用过,或者都有理解过,在1979年的时候它是来自Unix,它次要的性能是能够批改过程和子过程的/。 通过应用chroot达到什么样成果呢?应用chroot加某一个目录,而后再启动一个过程,那么这个过程本人所看到的 / ,就是咱们平时所说的 / 目录,这个 / 就会是咱们方才指定的文件夹,或者说方才指定的门路。这样子的话能够无效的爱护咱们操作系统下面的一些文件,或者说权限和平安相干的货色。 在2000年的时候,呈现了一个新的技术,叫做jails,其实它曾经具备了sandbox,就是沙箱环境的雏形。应用jails的话,能够让一个过程或者说创立的环境领有独立的网络接口和IP地址,而当咱们提到应用jails的话,咱们必定会想到一个问题,就是如果你有了独立的网络接口和IP地址,这样的话就不能发原始的套接字,通常跟原始的套接字接触得比拟多的就是咱们应用的Ping命令。默认的状况下,这样子是不容许应用原始的套接字的,而有本人的网络接口和IP地址,这个感觉上就像是咱们罕用的虚拟机。 2、Linux VServer和OpenVZ 接下来在2001年的时候,在Linux社区当中就呈现了一个新的技术叫做Linux VServer。Linux VServer有时候能够简写成lvs,然而和咱们平时用到的4层的代理lvs其实是不一样的。它其实是对Linux内核的一种Patch,它是须要批改Linux内核,批改实现之后,咱们能够让它支持系统级的虚拟化,同时应用Linux VServer的话,它能够共享零碎调用,它是没有仿真开销的,也就是说咱们罕用的一些零碎调用、零碎调用的一些函数都是能够共享的。 在2005年的时候,呈现的一个新的技术—OpenVZ。OpenVZ其实和Linux VServer有很大的类似点,它也是对内核的一种Patch,这两种技术最大的变动就是它对Linux打了很多的Patch,加了很多新的性能,然而在2005年的时候,没有把这些全副都合并到Linux的骨干当中,而且在应用OpenVZ的时候,它能够容许每个过程能够有本人的/proc或者说本人的/sys。 其实咱们大家都晓得在Linux当中,比如说启动一个过程,你在他的/proc/self上面,你就能够看到过程相干的信息。如果你有了本人独立的/proc,其实你就能够达到和其余的过程隔离开的成果。 接下来另外一个显著的特点就是它有独立的users和groups,也就是说你能够有独立的用户或者独立的组,而且这个是能够和零碎当中其余的用户或者组独立开的。 其次的话OpenVZ是有商业应用的,就是有很多国外的主机和各种VPS都是用OpenVZ这种技术计划。 3、namespace 和 cgroups 到了2002年的时候,新的技术是namespace。在Linux当中咱们有了新的技术叫做namespace,namespace能够达到过程组内的特定资源的隔离。因为咱们平时用到的namespace其实有很多种,比如说有PID、net等,而且如果你不在雷同的namespace上面的话,是看不到其余过程特定的资源的。 到了2013年的时候,产生了一个新的namespace的个性,就是user namespace。其实当有了user namespace,就和上文提到的OpenVZ实现的独立用户和组的性能是比拟像的。 对于namespace的操作当中,通常会有三种。 1)Clone 能够指定子过程在什么namespace上面。 2)Unshare 它是与其余过程不共享的,unshare再加一个-net,就能够与其余的过程独立开,不共享本人的net,不共享本人的网络的namespace。 3)Setns 就是为过程设置 namespace。 到了2008年,cgroups开始被引入到Linux内核当中,它能够用于隔离过程组的资源应用,比如说能够隔离CPU、内存、磁盘,还有网络,尤其是他在2013年和user namespace进行了一次组合之后,并且进行了从新的设计,这个时候,就变得更现代化了,就像咱们当初常常应用到的Docker的相干个性,其实都来自于这个时候。所以说cgroups和namespace形成古代容器技术的根底。 4、LXC 和 CloudFoundry 在2008年的时候,新的一项技术叫做LXC, 咱们也会叫他Linux Container(以下均简称LXC)。上文咱们提到了很多容器化的技术,比方Linux VServer、OpenVZ,然而这些都是通过打Patch来实现的,而LXC是首个能够间接和上游的Linux内核独特工作的。 LXC是能够反对特权容器的,意思就是说能够在机器下面去做uid map、gid map,去做映射,而且不须要都拿root用户去启动,这样子就具备了很大的便利性。而且这种形式能够让你的被攻击面大大放大。LXC反对的这几种比拟惯例的操作,就是LXC-start,能够用来启动container,LXC-attach就能够进入container当中。 到2011年的时候,CloudFoundry开始呈现了,他实际上是应用了LXC和 Warden这两项技术的组合,在这个时候不得不提到的,就是他的技术架构是CS的模式,也就是说还有一个客户端和server端,而 Warden容器,它通常是有两层,一层是只读os的,就是只读的操作系统的文件系统,另外一层是用于应用程序和其依赖的非长久化的读写层,就是这两层的组合。 咱们之前提到的技术,大多数都是针对于某一台机器的,就是对于单机的。CloudFoundry它最大的不同就是它能够治理跨计算机的容器集群,这其实就曾经有了古代容器技术的相干个性了。 5、LMCTFY和systemd-nspawn 在2013年的时候, Google开源了本人的容器化的解决方案,叫做LMCTFY。这个计划是能够反对CPU、内存还有设施的隔离。而且它是反对子容器的,能够让应用程序去感知到本人以后是处在容器当中的。另外还能够再为本人创立一个子容器,然而随着2013年倒退之后,它逐步发现只依附本人不停的做这些技术,就相当于单打独斗,倒退始终是无限的,所以它逐渐的将本人的次要精力放在形象和移植上,把本人的外围个性都移植到了libcontainer。而libcontainer之后就是Docker的运行时的一个外围,再之后就是被Docker捐到了OCI,再而后就倒退到了runC。这部分内容咱们稍后再具体解说。 大家都晓得服务器它必定是有一个 PID为1的过程。就是它的初始过程、守护过程,而古代的操作系统的话,大多数大家都应用的是systemd,同样systemd它也提供了一种容器化的解决方案,叫做 systemd-nspawn。这个技术的话,它是能够和systemd相干的工具链进行联合的。 ...

July 5, 2021 · 2 min · jiezi

关于redis:Redis进阶缓存设计

缓存的收益和老本收益减速读写:因为缓存通常都是全内存的(例如Redis、Memcache),而存储层通常读写性能不够强悍(例如MySQL),通过缓存的应用能够无效地减速读写,优化用户体验。升高后端负载:帮忙后端缩小访问量和简单计算(例如很简单的SQL语句),在很大水平升高了后端的负载。老本数据不一致性:缓存层和存储层的数据存在着肯定工夫窗口的不一致性,工夫窗口跟更新策略无关。代码保护老本:退出缓存后,须要同时解决缓存层和存储层的逻辑,增大了开发者保护代码的老本。运维老本:以Redis Cluster为例,退出后无形中减少了运维老本。缓存的应用场景根本蕴含如下两种: 开销大的简单计算:以MySQL为例,一些简单的操作或者计算(例如大量联表操作、一些分组计算),如果不加缓存,岂但无奈满足高并发量,同时也会给MySQL带来微小的累赘。减速申请响应:即便查问单条后端数据足够快,那么仍然能够应用缓存,以Redis为例,每秒能够实现数万次读写,并且提供的批量操作能够优化整个IO链的响应工夫。缓存更新策略LRU/LFU/FIFO算法剔除应用场景:通常用于缓存使用量超过了预设的最大值时候,如何对现有的数据进行剔除。例如Redis应用maxmemory-policy这个配置作为内存最大值后对于数据的剔除策略。 一致性:要清理哪些数据是由具体算法决定,开发人员只能决定应用哪种算法,所以数据的一致性是最差的。 保护老本:算法不须要开发人员本人来实现,通常只须要配置最大maxmemory和对应的策略即可。开发人员只须要晓得每种算法的含意,抉择适宜本人的算法即可。 超时剔除应用场景:超时剔除通过给缓存数据设置过期工夫,让其在过期工夫后主动删除,例如Redis提供的expire命令。如果业务能够容忍一段时间内,缓存层数据和存储层数据不统一,那么能够为其设置过期工夫。在数据过期后,再从实在数据源获取数据,从新放到缓存并设置过期工夫。 一致性:一段时间窗口内存在一致性问题,即缓存数据非和实在数据源的数据不统一。 保护老本:保护老本不是很高,只需设置expire过期工夫即可,当然前提是利用方容许这段时间可能产生的数据不统一。 被动更新应用场景:利用方对于数据的一致性要求高,须要在实在数据更新后,立刻更新缓存数据。例如能够利用音讯零碎或者其余形式告诉缓存更新。 一致性:一致性最高,但如果被动更新产生了问题,那么这条数据很可能很长时间不会更新,所以倡议联合超时剔除一起应用成果会更好。 保护老本:保护老本会比拟高,开发者须要本人来实现更新,并保障更新操作的正确性。 最佳实际低一致性业务倡议配置最大内存和淘汰策略的形式应用。高一致性业务能够联合应用超时剔除和被动更新,这样即便被动更新出了问题,也能保证数据过期工夫后删除脏数据。 缓存粒度管制例如当初须要将MySQL的用户信息应用Redis缓存,假如用户表有100个列,须要缓存到什么维度呢?这个问题就是缓存粒度问题,到底是缓存全副属性还是只缓存局部重要属性?上面将从通用性、空间占用、代码保护三个角度进行阐明。 通用性:缓存全副数据比局部数据更加通用,但从理论教训看,很长时间内利用只须要几个重要的属性。 空间占用:缓存全副数据要比局部数据占用更多的空间,可能存在以下问题: 全副数据会造成内存的节约。全副数据可能每次传输产生的网络流量会比拟大,耗时绝对较大,在极其状况下会阻塞网络。全副数据的序列化和反序列化的CPU开销更大。代码保护:全副数据的劣势更加显著,而局部数据一旦要加新字段须要批改业务代码,而且批改后通常还须要刷新缓存数据。 缓存粒度问题是一个容易被忽视的问题,如果使用不当,可能会造成很多无用空间的节约,网络带宽的节约,代码通用性较差等状况,须要综合数据通用性、空间占用比、代码维护性三点进行取舍。 缓存穿透缓存穿透是指查问一个基本不存在的数据,缓存层和存储层都不会命中,通常出于容错的思考,如果从存储层查不到数据则不写入缓存层。缓存穿透将导致不存在的数据每次申请都要到存储层去查问,失去了缓存爱护后端存储的意义。 缓存穿透问题可能会使后端存储负载加大,因为很多后端存储不具备高并发性,甚至可能造成后端存储宕掉。通常能够在程序中别离统计总调用数、缓存层命中数、存储层命中数,如果发现大量存储层空命中,可能就是呈现了缓存穿透问题。 造成缓存穿透的根本起因有两个。第一,本身业务代码或者数据呈现问题,第二,一些歹意攻打、爬虫等造成大量空命中。上面咱们来看一下如何解决缓存穿透问题。 缓存空对象当存储层不命中后,依然将空对象保留到缓存层中,之后再拜访这个数据将会从缓存中获取,这样就爱护了后端数据源。 缓存空对象会有两个问题: 空值做了缓存,意味着缓存层中存了更多的键,须要更多的内存空间(如果是攻打,问题更重大),比拟无效的办法是针对这类数据设置一个较短的过期工夫,让其主动剔除。缓存层和存储层的数据会有一段时间窗口的不统一,可能会对业务有肯定影响。例如过期工夫设置为5分钟,如果此时存储层增加了这个数据,那此段时间就会呈现缓存层和存储层数据的不统一,此时能够利用音讯零碎或者其余形式革除掉缓存层中的空对象。布隆过滤器拦挡在拜访缓存层和存储层之前,将存在的key用布隆过滤器提前保存起来,做第一层拦挡。例如:一个举荐零碎有4亿个用户id,每个小时算法工程师会依据每个用户之前历史行为计算出举荐数据放到存储层中,然而最新的用户因为没有历史行为,就会产生缓存穿透的行为,为此能够将所有举荐数据的用户做成布隆过滤器。如果布隆过滤器认为该用户id不存在,那么就不会拜访存储层,在肯定水平爱护了存储层。 这种办法实用于数据命中不高、数据绝对固定、实时性低(通常是数据集较大)的利用场景,代码保护较为简单,然而缓存空间占用少。 缓存空对象和布隆过滤器计划比照 缓存无底洞2010年,Facebook的Memcache节点曾经达到了3000个,承载着TB级别的缓存数据。但开发和运维人员发现了一个问题,为了满足业务要求增加了大量新Memcache节点,然而发现性能岂但没有恶化反而降落了,过后将这种景象称为缓存的“无底洞”景象。 那么为什么会产生这种景象呢,通常来说增加节点使得Memcache集群性能应该更强了,但事实并非如此。键值数据库因为通常采纳哈希函数将key映射到各个节点上,造成key的散布与业务无关,然而因为数据量和访问量的持续增长,造成须要增加大量节点做程度扩容,导致键值散布到更多的节点上,所以无论是Memcache还是Redis的分布式,批量操作(例如mget)通常须要从不同节点上获取,相比于单机批量操作只波及一次网络操作,分布式批量操作会波及屡次网络工夫。 无底洞问题剖析: 客户端一次批量操作会波及屡次网络操作,也就意味着批量操作会随着节点的增多,耗时会一直增大。网络连接数变多,对节点的性能也有肯定影响。用一句艰深的话总结就是,更多的节点不代表更高的性能,所谓“无底洞”就是说投入越多不肯定产出越多。然而分布式又是不能够防止的,因为访问量和数据量越来越大,一个节点基本抗不住,所以如何高效地在分布式缓存中批量操作是一个难点。 上面介绍如何在分布式条件下优化批量操作。在介绍具体的办法之前,咱们来看一下常见的单机IO优化思路: 命令自身的优化,例如优化SQL语句等。缩小网络通信次数。升高接入老本,例如客户端应用长连/连接池、NIO等。这里咱们假如命令、客户端连贯曾经为最优,重点探讨缩小网络操作次数。以Redis批量获取n个字符串为例,咱们将联合Redis Cluster的一些个性对四种分布式的批量操作形式进行阐明。 串行命令因为n个key一般来说都散布在Redis Cluster的各个节点上,因而无奈应用mget命令一次性获取,所以通常来讲要获取n个key的值,最简略的办法就是逐次执行n个get命令,这种操作工夫复杂度较高,它的操作工夫=n次网络工夫+n次命令工夫,网络次数是n。很显然这种计划不是最优的,然而实现起来比较简单。 串行IORedis Cluster应用CRC16算法计算出散列值,再取对16383的余数就能够算出slot值,同时Smart客户端会保留slot和节点的对应关系,有了这两个数据就能够将属于同一个节点的key进行归档,失去每个节点的key子列表,之后对每个节点执行mget或者Pipeline操作,它的操作工夫=node次网络工夫+n次命令工夫,网络次数是node的个数,很显著这种计划比第一种要好很多,然而如果节点数太多,还是有肯定的性能问题。 并行IO此计划是将计划2中的最初一步改为多线程执行,网络次数尽管还是节点个数,但因为应用多线程网络工夫变为O(1),这种计划会减少编程的复杂度。它的操作工夫为:max_slow(node次网络工夫 )+n次命令工夫。 hash_tag实现应用Redis Cluster的hash_tag性能,它能够将多个key强制调配到一个节点上,它的操作工夫=1次网络工夫+n次命令工夫。 计划比照 缓存雪崩因为缓存层承载着大量申请,无效地爱护了存储层,然而如果缓存层因为某些起因不能提供服务,于是所有的申请都会达到存储层,存储层的调用量会暴增,造成存储层也会级联宕机的状况。 预防和解决缓存雪崩问题,能够从以下三个方面进行着手。 保障缓存层服务高可用性如果缓存层设计成高可用的,即便个别节点、个别机器、甚至是机房宕掉,仍然能够提供服务,例如Redis Sentinel和Redis Cluster都实现了高可用。 依赖隔离组件为后端限流并降级无论是缓存层还是存储层都会有出错的概率,能够将它们视同为资源。作为并发量较大的零碎,如果有一个资源不可用,可能会造成线程全副阻塞在这个资源上,造成整个零碎不可用。 降级机制在高并发零碎中是十分广泛的:比方举荐服务中,如果个性化举荐服务不可用,能够降级补充热点数据。在理论我的项目中,咱们须要对重要的资源(例如Redis、MySQL、HBase、内部接口)都进行隔离,让每种资源都独自运行在本人的线程池中,即便个别资源呈现了问题,对其余服务没有影响。然而线程池如何治理,比方如何敞开资源池、开启资源池、资源池阀值治理,这些做起来还是相当简单的。 提前演练在我的项目上线前,演练缓存层宕掉后,利用以及后端的负载状况以及可能呈现的问题,在此基础上做一些预案设定。 热点key重建开发人员应用“缓存+过期工夫”的策略既能够减速数据读写,又保证数据的定期更新,这种模式根本可能满足绝大部分需要。然而有两个问题如果同时呈现,可能就会对利用造成致命的危害: 以后key是一个热点key,并发量十分大。重建缓存不能在短时间实现,可能是一个简单计算,例如简单的SQL、屡次IO、多个依赖等。在缓存生效的霎时,有大量线程来重建缓存,造成后端负载加大,甚至可能会让利用解体。要解决这个问题也不是很简单,然而不能为了解决这个问题给零碎带来更多的麻烦,所以须要制订如下指标: 缩小重建缓存的次数。数据尽可能统一。较少的潜在危险。互斥锁此办法只容许一个线程重建缓存,其余线程期待重建缓存的线程执行完,从新从缓存获取数据即可。例如能够应用Redis的setnx命令来实现一个简略的分布式互斥锁来实现。 永远不过期“永远不过期”蕴含两层意思: 从缓存层面来看,的确没有设置过期工夫,所以不会呈现热点key过期后产生的问题,也就是“物理”不过期。从性能层面来看,为每个value设置一个逻辑过期工夫,当发现超过逻辑过期工夫后,会应用独自的线程去构建缓存。此办法无效杜绝了热点key产生的问题,但惟一有余的就是重构缓存期间,会呈现数据不统一的状况,这取决于利用方是否容忍这种不统一。 总结作为一个并发量较大的利用,在应用缓存时有三个指标:第一,放慢用户访问速度,进步用户体验。第二,升高后端负载,缩小潜在的危险,保证系统安稳。第三,保证数据“尽可能”及时更新。下表是依照这三个维度对上述两种解决方案所进行的比照。

July 3, 2021 · 1 min · jiezi

关于redis:Redisson-分布式锁源码-02看门狗

前言说起 Redisson,比拟耳熟能详的就是这个看门狗(Watchdog)机制。 本文就一起看看加锁胜利之后的看门狗(Watchdog)是如何实现的? 加锁胜利在前一篇文章中介绍了可重入锁加锁的逻辑,其中 RedissonLock#tryAcquireAsync 办法是进行异步加锁的逻辑。 回顾一下这个办法的入参: waitTime:-1;leaseTime:-1,加锁时未指定锁工夫,则为 -1,如果指定,则是指定的工夫;unit:null;threadId:以后线程 id。其中的 tryLockInnerAsync 在之前曾经介绍过了。 当加锁胜利时,会返回 null,加锁失败,会返回以后锁的剩余时间。 所以这块会进入到红框标记的局部。 leaseTime 为加锁工夫,默认不指定,所以会进入到 scheduleExpirationRenewal 办法,也就是明天的主题:看门狗。 至此能够得出一个论断: Redisson 看门狗(Watchdog)在指定加锁工夫时,是不会对锁工夫主动续租的。 看门狗 看门狗的一部分重点逻辑就在 renewExpiration 办法这里: 提早调度,延迟时间为:internalLockLeaseTime / 3,就是 10s 左右后会调度这个 TimerTask;异步续租:逻辑都在 renewExpirationAsync 外面;递归调用:当续租胜利之后,从新调用 renewExpiration 本人,从而达到继续续租的目标;当然也不能始终有限续租,所以两头有一些判断逻辑,就是用来中断续租的。续租逻辑 这块也是一个 lua 脚本,就是将之前的 redis key 间接从新设置工夫。 这样一通续租下来,就是在过了 10s 左右将锁的工夫从新设置为 30s。 总结至此,看门狗介绍结束,简要总结一下内容。 只有在未指定锁超时工夫时才会应用看门狗;看门狗默认续租工夫是 10s 左右,internalLockLeaseTime / 3;能够通过 Config 对立设置看门狗的工夫,设置 lockWatchdogTimeout 参数即可。最初,同样应用一张图,进行下总结: 相干举荐Redisson 分布式锁源码 01:可重入锁加锁Spring 是如何解决循环依赖的?Spring 自调用事务生效,你是怎么解决的?

July 3, 2021 · 1 min · jiezi

关于redis:命令行搞一切之如何使用命令行为-redis-做健康检测

如何应用命令行查看 redis 是否按预期工作?redis-cli 基础知识应用 redis-cli 查看数据库健康状况听起来很简略,实际上,它是:Redis 主机上的简略redis-cli PING返回PONG。这看起来不太行的样子,但的确如此。返回PONG 的redis性能失常、身体健康,吃嘛嘛香。 更具体一点:这意味着数据集已齐全加载,Redis 已筹备好连贯。如果某些货色不能失常工作,它会显示谬误音讯,例如“(error) LOADING Redis is loading the dataset in memory”。这将在加载 rdb/aof 文件或期待复制实现时返回。 通过应用 redis-cli,您能够轻松应用info命令和子命令来获取更多统计信息和信息。 命令列表要反复命令,您能够轻松应用两个选项进行监控:redis - cli - r 5 - i 2 <command> 将执行<command> 5 次,距离为 2 秒。 应用这些命令,您能够轻松地将 redis 集成到您的监控中。只需将 redis-cli 命令增加为自定义参数,例如增加到 Zabbix 或 Nagios。您还能够应用 prometheus 导出器从 redis 中获取指标。 集成提早监控、报告、慢日志兴许你们中的一些人会问本人,为什么咱们首先须要监控,因为 redis 的速度十分快。答案是:您说得对,redis 旨在为每个实例每秒解决大量查问。但可怜的是,在大多数应用程序中,对均匀响应工夫和最坏状况的提早都有严格的要求。 尽管如此,因为 redis 有大量的命令,多且杂,也分为三六九等。有些命令运行速度很快,而且运行速度为常数或对数工夫,而其余命令则较慢,可能会导致提早峰值。采纳这种监控形式的其余起因是与操作系统的交互(例如磁盘持久性)和 redis 的单线程架构无关。 自2.8.13版本起,redis 引入提早监控,该命令有助于解决可能的提早问题。以下机制是该框架的一部分: 用提早钩子来采样不同提早敏感代码的门路由其余事件宰割的提早峰值的工夫序列记录报告引擎从工夫序列中获取原始数据剖析引擎依据测量提供人类可读的报告和给出相应提醒如何启用提早监控?在 redis 运行时,提早监控能够很容易地通过 CONFIG SET latency-monitor-threshold 100启用。尾数以毫秒为单位定义工夫。在咱们的示例中,每个须要超过 100ms 的事件都将被记录为提早峰值。 ...

June 30, 2021 · 1 min · jiezi

关于redis:Redis高频面试题之缓存穿透缓存击穿和缓存雪崩

一、概述Redis是什么?what?Redis(Remote Dictionary Server ),即近程字典服务 ! 是一个开源的应用ANSI C语言编写、反对网络、可基于内存亦可长久化的日志型、Key-Value数据库,并提供多种语言的API。 redis会周期性的把更新的数据写入磁盘或者把批改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。 收费和开源!是当下最热门的 NoSQL 技术之一!也被人们称之为结构化数据库! Redis能干嘛?1、内存存储、长久化,内存中是断电即失、所以说长久化很重要(rdb、aof) 2、效率高,能够用于高速缓存 3、公布订阅零碎 4、地图信息剖析 5、计时器、计数器(浏览量!) 6、........ 二、Redis的根本理解首先咱们能够看下官网文档是如何介绍Redis的:①、英文文档 点击跳转. ②、中文文档 点击跳转. 2. Redis-Key 简略介绍一下Redis中队Key的操作命令。心愿大家能够跟着正文敲一遍,简略记一下,都是最罕用的命令! 127.0.0.1:6379> ping #查看以后连贯是否失常,失常返回PONGPONG127.0.0.1:6379> clear #分明以后控制台(为了更好的看到上面输出的命令)127.0.0.1:6379> keys * #查看以后库里所有的key1) "db"127.0.0.1:6379> FLUSHALL #清空所有库的内容OK127.0.0.1:6379> keys * (empty array)127.0.0.1:6379> set name dingdada #增加一个key为‘name’ value为‘dingdada’的数据OK127.0.0.1:6379> get name #查问key为‘name’的value值"dingdada"127.0.0.1:6379> keys *1) "name"127.0.0.1:6379> set name1 dingdada2OK127.0.0.1:6379> get name1"dingdada2"127.0.0.1:6379> keys * #查看以后库里所有的key1) "name1"2) "name"127.0.0.1:6379> EXISTS name #判断以后key是否存在(integer) 1127.0.0.1:6379> move name 1 #移除以后库1的key为‘name‘的数据(integer) 1127.0.0.1:6379> keys *1) "name1"127.0.0.1:6379> FLUSHALL #再次清空所有库的内容OK## 多加几条数据 上面测试设置key的过期工夫127.0.0.1:6379> set name dingdadaOK127.0.0.1:6379> set name1 dingdada1OK127.0.0.1:6379> set name2 dingdada2OK127.0.0.1:6379> EXPIRE name 15 #设置key为’name‘的数据过期工夫为15秒 单位seconds(integer) 1127.0.0.1:6379> ttl name #查看以后key为’name‘的残余生命周期工夫(integer) 13127.0.0.1:6379> ttl name(integer) 12127.0.0.1:6379> ttl name(integer) 11127.0.0.1:6379> ttl name(integer) 8127.0.0.1:6379> ttl name(integer) 6127.0.0.1:6379> ttl name(integer) 3127.0.0.1:6379> ttl name(integer) 2127.0.0.1:6379> ttl name(integer) 1127.0.0.1:6379> ttl name(integer) 0127.0.0.1:6379> ttl name #如若返回-2,证实key已过期(integer) -2127.0.0.1:6379> get name #再次查问即为空(nil)127.0.0.1:6379> type name1string127.0.0.1:6379> 如若遇到不会的命令!记得查看Redis中武官网,下面有官网文档!链接下面有,能够点击跳转~ ...

June 25, 2021 · 3 min · jiezi

关于redis:redis主从环境搭建

筹备零碎环境:Linux ubuntu 4.15.0-62-generic下载 redis-6.2.4.tar.gz (官网下载即可) 解压编译redistar -xvf redis-6.2.4.tar.gzcd redis-6.2.4make环境筹备三个redis服务,一主二从(装置在本地所以用127.0.0.1,此版本从服务器用replica):127.0.0.1:6379 master127.0.0.1:6380 replica1127.0.0.1 6381 replica2 redis-mastercd ~/appscp -r redis-6.2.4 ./redis-6379/mkdir run #pid文件、日志寄存目录mkdir -p dbfile/redis_6379 #数据库文件寄存目录vim redis-6379/redis.conf批改配置文件: #设置端口 port 6379 #配置以守护过程运行 daemonize yes #以守护常常运行必须配置pid文件地址 pidfile /home/bing/apps/redis-6379/run/redis_6379.pid #配置日志地址 logfile "/home/bing/apps/redis-6379/run/redis6379.log" #配置数据库文件寄存目录, Append Only File也放在这里 dir ./dbfile/redis_6379/ #配置最大内存 maxmemory 512m 启动master: ./redis-6379/src/redis-server ./redis-6379/redis.conf #启动redis ps -ef|grep redis #查看是否启动胜利 查看启动胜利: 目前master启动胜利了! redis-replica1cd ~/appscp -r redis-6.2.4 ./redis-6380/mkdir run #pid文件、日志寄存目录mkdir -p dbfile/redis_6380 #数据库文件寄存目录vim redis-6380/redis.conf批改配置文件: #设置端口 port 6380 #配置以守护过程运行 daemonize yes #以守护常常运行必须配置pid文件地址 pidfile /home/bing/apps/redis-6380/run/redis_6380.pid #配置日志地址 logfile "/home/bing/apps/redis-6380/run/redis6380.log" #配置数据库文件寄存目录, Append Only File也放在这里 dir ./dbfile/redis_6380/ #配置所属的主库(从库都须要的配置) replicaof 127.0.0.1 6379 #配置最大内存 maxmemory 512m ...

June 24, 2021 · 1 min · jiezi

关于redis:Redis应用实战-秒杀场景Nodejs版本

写在后面公司随着业务量的减少,最近用时几个月工夫在我的项目中全面接入Redis,开发过程中发现市面上短少具体的实战材料,尤其是在Node.js环境下,能找到的材料要么过于简略入门,要么徒有虚名,大部分都是属于高级。因而决定把公司这段时间的成绩进行分享,会用几篇文章具体介绍Redis的几个应用场景,冀望大家一起学习、提高。 上面就开始第一篇,秒杀场景。 业务剖析理论业务中,秒杀蕴含了许多场景,具体能够分为秒杀前、秒杀中和秒杀后三个阶段,从开发角度具体分析如下: 秒杀前:次要是做好缓存工作,以应答用户频繁的拜访,因为数据是固定的,能够把商品详情页的元素动态化,而后用CDN或者是浏览器进行缓存。秒杀中:次要是库存查验,库存扣减和订单解决,这一步的特点是 短时间内大量用户同时进行抢购,零碎的流量忽然激增,服务器压力霎时增大(刹时并发拜访高)申请数量大于商品库存,比方10000个用户抢购,然而库存只有100限定用户只能在肯定时间段内购买限度单个用户购买数量,防止刷单抢购是跟数据库打交道,外围性能是下单,库存不能扣成正数对数据库的操作读多写少,而且读操作绝对简略秒杀后:次要是一些用户查看已购订单、解决退款和解决物流等等操作,这时候用户申请量曾经降落,操作也绝对简略,服务器压力不大。根据上述剖析,本文把重点放在秒杀中的开发解说,其余局部感兴趣的小伙伴能够本人搜寻材料,进行尝试。 开发环境数据库:Redis 3.2.9 + Mysql 5.7.18服务器:Node.js v10.15.0测试工具:Jmeter-5.4.1 实战数据库筹备如图所示,Mysql中须要创立三张表,别离是 产品表,用于记录产品信息,字段别离为Id、名称、缩略图、价格和状态等等秒杀流动表,用于记录秒杀流动的详细信息,字段别离为Id、参加秒杀的产品Id、库存量、秒杀开始工夫、秒杀完结工夫和秒杀流动是否无效等等订单表,用于记录下单后的数据,字段别离为Id、订单号、产品Id、购买用户Id、订单状态、订单类型和秒杀流动Id等等上面是创立sql语句,以供参考 CREATE TABLE `scekill_goods` ( `id` INTEGER NOT NULL auto_increment, `fk_good_id` INTEGER, `amount` INTEGER, `start_time` DATETIME, `end_time` DATETIME, `is_valid` TINYINT ( 1 ), `comment` VARCHAR ( 255 ), `created_at` DATETIME NOT NULL, `updated_at` DATETIME NOT NULL,PRIMARY KEY ( `id` ) ) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;CREATE TABLE `orders` ( `id` INTEGER NOT NULL auto_increment, `order_no` VARCHAR ( 255 ), `good_id` INTEGER, `user_id` INTEGER, `status` ENUM ( '-1', '0', '1', '2' ), `order_type` ENUM ( '1', '2' ), `scekill_id` INTEGER, `comment` VARCHAR ( 255 ), `created_at` DATETIME NOT NULL, `updated_at` DATETIME NOT NULL,PRIMARY KEY ( `id` ) ) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;CREATE TABLE `goods` ( `id` INTEGER NOT NULL auto_increment, `name` VARCHAR ( 255 ), `thumbnail` VARCHAR ( 255 ), `price` INTEGER, `status` TINYINT ( 1 ), `stock` INTEGER, `stock_left` INTEGER, `description` VARCHAR ( 255 ), `comment` VARCHAR ( 255 ), `created_at` DATETIME NOT NULL, `updated_at` DATETIME NOT NULL,PRIMARY KEY ( `id` ) ) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;产品表在此次业务中不是重点,以下逻辑都以id=1的产品为示例,请悉知。 秒杀流动表中创立一条库存为200的记录,作为秒杀测试数据,参考上面语句: ...

June 24, 2021 · 5 min · jiezi

关于redis:Redis我是如何与客户端进行通信的

江湖上说,天下文治,无坚不摧,唯快不破,这句话几乎是为我量身定制。 我是一个Redis服务,最引以为傲的就是我的速度,我的 QPS 能达到10万级别。 在我的手下有数不清的小弟,他们会时不时到我这来寄存或者取走一些数据,我管他们叫做客户端,还给他们起了英文名叫 Redis-client。 有时候一个小弟会来的十分频繁,有时候一堆小弟会同时过去,然而,即便再多的小弟我也能治理的东倒西歪。 有一天,小弟们问我。 想当年,为了不让小弟们拖垮我傲人的速度,在设计和他们的通信协议时,我搜索枯肠,制订了上面的三条准则: 实现简略针对计算机来说,解析速度快针对人类来说,可读性强为什么这么设计呢?先来看看一条指令收回的过程,首先在客户端须要对指令操作进行封装,应用网络进行传输,最初在服务端进行相应的解析、执行。 这一过程如果设计成一种非常复杂的协定,那么封装、解析、传输的过程都将十分耗时,无疑会升高我的速度。什么,你问我为什么要遵循最初一条规定?算是对于程序员们的馈赠吧,我真是太凶恶了。 我把发明进去的这种协定称为 RESP (REdis Serialization Protocol)协定,它工作在 TCP 协定的下层,作为我和客户端之间进行通信的规范模式。 说到这,我曾经有点急不可待想让你们看看我设计进去的杰作了,但我好歹也是个大哥,得摆点架子,不能我被动拿来给你们看。 所以我倡议你间接应用客户端收回一条向服务器的命令,而后取出这条命令对应的报文来直观的看一下。话虽如此,不过我曾经被封装的很严实了,失常状况下你是看不到我外部进行通信的具体报文的,所以,你能够假装成一个Redis的服务端,来截获小弟们发给我的音讯。 实现起来也很简略,我和小弟之间是基于 Socket 进行通信,所以在本地先启动一个ServerSocket,用来监听Redis服务的6379端口: public static void server() throws IOException { ServerSocket serverSocket = new ServerSocket(6379); Socket socket = serverSocket.accept(); byte[] bytes = new byte[1024]; InputStream input = socket.getInputStream(); while(input.read(bytes)!=0){ System.out.println(new String(bytes)); }}而后启动redis-cli客户端,发送一条命令: set key1 value1这时,假装的服务端就会收到报文了,在控制台打印了: *3$3set$4key1$6value1看到这里,模摸糊糊看到了方才输出的几个关键字,然而还有一些其余的字符,要怎么解释呢,是时候让我对协定报文中的格局进行一下揭秘了。 我对小弟们说了,对大哥谈话的时候得按规矩来,这样吧,你们在申请的时候要遵循上面的规定: *<参数数量> CRLF$<参数1的字节长度> CRLF<参数1的数据> CRLF$<参数2的字节长度> CRLF<参数2的数据> CRLF...$<参数N的字节长度> CRLF<参数N的数据> CRLF首先解释一下每行开端的CRLF,转换成程序语言就是\r\n,也就是回车加换行。看到这里,你也就可能明确为什么控制台打印出的指令是竖向排列了吧。 在命令的解析过程中,set、key1、value1会被认为是3个参数,因而参数数量为3,对应第一行的*3。 第一个参数set,长度为3对应$3;第二个参数key1,长度为4对应$4;第三个参数value1,长度为6对应$6。在每个参数长度的下一行对应真正的参数数据。 ...

June 23, 2021 · 1 min · jiezi

关于redis:NoClassDefFoundErrorGenericObjectPoolConfig-问题

本文集体博客地址:https://www.leafage.top/posts/detail/21622MARQ 记录一个redis的异样,明天更新测试环境的服务,该服务中应用了 spring-boot-starter-data-redis 的依赖,在公布测试的时候报错了,很难堪。为啥呢,我本地运行的好好的呀。。。(是不是你的日常?)。 这个错的具体信息如下: 6 2021-06-22 09:23:17,291 [application-name] [main] WARN o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisConnectionFactory' defined in class path resource [org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory]: Factory method 'redisConnectionFactory' threw exception; nested exception is java.lang.NoClassDefFoundError: org/apache/commons/pool2/impl/GenericObjectPoolConfig 7 2021-06-22 09:23:17,343 [application-name] [main] ERROR o.s.b.SpringApplication - Application run failed 8 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisConnectionFactory' defined in class path resource [org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory]: Factory method 'redisConnectionFactory' threw exception; nested exception is java.lang.NoClassDefFoundError: org/apache/commons/pool2/impl/GenericObjectPoolConfig 9 at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:657) 10 at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:637) 11 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1341) 12 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1181) 13 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:556) 14 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516) 15 at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324) 16 at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) 17 at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) 18 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) 19 at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:897) 20 at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879) 21 at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551) 22 at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) 23 at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) 24 at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) 25 at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:405) 26 at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) 27 at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) 28 at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) 29 at com.ichinae.imis.MgrApplication.main(MgrApplication.java:20) 30 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 31 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 32 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 33 at java.lang.reflect.Method.invoke(Method.java:498) 34 at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) 35 at org.springframework.boot.loader.Launcher.launch(Launcher.java:107) 36 at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) 37 at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) 38 Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory]: Factory method 'redisConnectionFactory' threw exception; nested exception is java.lang.NoClassDefFoundError: org/apache/commons/pool2/impl/GenericObjectPoolConfig 39 at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) 40 at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:652) 41 ... 28 common frames omitted 42 Caused by: java.lang.NoClassDefFoundError: org/apache/commons/pool2/impl/GenericObjectPoolConfig 43 at org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration$LettucePoolingClientConfigurationBuilder.<init>(LettucePoolingClientConfiguration.java:94) 44 at org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration.builder(LettucePoolingClientConfiguration.java:51) 45 at org.springframework.boot.autoconfigure.data.redis.LettuceConnectionConfiguration$PoolBuilderFactory.createBuilder(LettuceConnectionConfiguration.java:159) 46 at org.springframework.boot.autoconfigure.data.redis.LettuceConnectionConfiguration.createBuilder(LettuceConnectionConfiguration.java:107) 47 at org.springframework.boot.autoconfigure.data.redis.LettuceConnectionConfiguration.getLettuceClientConfiguration(LettuceConnectionConfiguration.java:92) 48 at org.springframework.boot.autoconfigure.data.redis.LettuceConnectionConfiguration.redisConnectionFactory(LettuceConnectionConfiguration.java:74) 49 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 50 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 51 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 52 at java.lang.reflect.Method.invoke(Method.java:498) 53 at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) 54 ... 29 common frames omitted 55 Caused by: java.lang.ClassNotFoundException: org.apache.commons.pool2.impl.GenericObjectPoolConfig 56 at java.net.URLClassLoader.findClass(URLClassLoader.java:381) 57 at java.lang.ClassLoader.loadClass(ClassLoader.java:424) 58 at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151) 59 at java.lang.ClassLoader.loadClass(ClassLoader.java:357) 60 ... 40 common frames omitted像平常一样,copy 异样信息,粘贴的google搜一下,而后介绍的都是价格以apache common pool2 的依赖,而后还有居然说重建一个我的项目到。。。(兄弟你搞笑的吧)。来说下这个异样的起因,报这个错的去看下你的配置文件中是不是配置了 lettuce.pool 的配置信息,如果有那就对了,解决的办法有两个: ...

June 22, 2021 · 2 min · jiezi

关于redis:十亿级流量下我与Redis时延小突刺的战斗史

一、背景某一日收到上游调用方的反馈,提供的某一个Dubbo接口,每天在固定的工夫点被短时间熔断,抛出的异样信息为提供方dubbo线程池被耗尽。以后dubbo接口日申请量18亿次,报错申请94W/天,至此开始了优化之旅。 二、疾速应急2.1 疾速定位首先进行惯例的零碎信息监控(机器、JVM内存、GC、线程),发现虽稍有突刺,但都在正当范畴内,且跟报错工夫点对不上,先临时疏忽。 其次进行流量剖析,发现每天固定工夫点会有流量突增的状况,流量突增的点跟报错的工夫点也吻合,初步判断为短时大流量导致。 流量趋势 被降级量 接口99线 三、寻找性能瓶颈点3.1 接口流程剖析3.1.1 流程图 3.1.2 流程剖析收到申请后调用上游接口,应用hystrix熔断器,熔断工夫为500MS; 依据上游接口返回的数据,进行详情数据的封装,第一步先到本地缓存中获取,如果本地缓存没有,则从Redis进行回源,Redis中无则间接返回,异步线程从数据库进行回源。 如果第一步调用上游接口异样,则进行数据兜底,兜底流程为先到本地缓存中获取,如果本地缓存没有,则从Redis进行回源,Redis中无则间接返回,异步线程从数据库进行回源。 3.2 性能瓶颈点排查3.2.1 上游接口服务耗时比拟长调用链显示,尽管上游接口的P99线在峰值流量时存在突刺,超出1S,但因为熔断超时的设置(熔断工夫500MS,coreSize&masSize=50,上游接口均匀耗时10MS以下),判断上游接口不是问题的关键点,为进一步排除烦扰,在上游服务存在突刺时能疾速失败,调整熔断工夫为100MS,dubbo超时工夫100MS。 3.2.2 获取详情本地缓存无数据,Redis回源借助调用链平台,第一步剖析Redis申请流量,以此来判断本地缓存的命中率,发现Redis的流量是接口流量的2倍,从设计上来说不应该呈现这个景象。开始代码Review,发现在有一处逻辑呈现了问题。 没有从本地缓存读取,而是间接从Redis中获取了数据,Redis最大响应工夫也的确发现了不合理的突刺,持续剖析发现Redis响应工夫和Dubbo99线突刺状况基本一致,感觉此时曾经找到了问题的起因,心中暗喜。 Redis申请流量 服务接口申请流量 Dubbo99线 Redis最大响应工夫 3.2.3 获取兜底数据本地缓存无数据,Redis回源失常 3.2.4 记录申请后果入Redis因为以后Redis做了资源隔离,且未在DB后盾查问到慢日志,此时剖析导致Redis变慢的起因有很多,不过其余的都被主观疏忽了,注意力都在申请Redis流量翻倍的问题上了,故优先解决3.2.2中的问题。 四、解决方案4.1 3.3.2中定位的问题上线上线前Redis申请量 上线后Redis申请量 上线后Redis流量翻倍问题失去解决,Redis最大响应工夫突刺有所缓解,但仍旧没能彻底解决,阐明大流量查问不是最基本的起因。 redis最大响应工夫(上线前) redis最大响应工夫(上线后) 4.2 Redis扩容在Redis异样流量问题解决后,问题并未失去彻底解决,此时能做的就是静下心来,认真去梳理导致Redis慢的起因,思路次要从以下三个方面: 呈现了慢查问Redis服务呈现性能瓶颈客户端配置不合理基于以上思路,一个个的进行排查;查问Redis慢查问日志,未发现慢查问。 借用调用链平台详细分析慢的Redis命令,没有了大流量导致的慢查问的烦扰,问题定位流程很快,大量的耗时申请在setex办法上,偶然呈现查问的慢申请也都是在setex办法之后,依据Redis单线程的个性判断setex是Redis99线突刺的首恶。找到具体语句,定位到具体业务后,首先申请扩容Redis,由6个master扩到8个master。 Redis扩容前 Redis扩容后 从后果上看,扩容基本上没有成果,阐明redis服务自身不是性能瓶颈点,此时剩下的一个就是客户端相干配置了。 4.3 客户端参数优化4.3.1 连接池优化Redis扩容没有成果,针对客户端可能呈现的问题,此时狐疑的点有两个方向。 第一个是客户端在解决Redis集群模式时,对连贯的治理上存在BUG,第二个是连接池参数设置不合理,此时源码剖析和连接池参数调整同步进行。 4.3.1.1 判断客户端连贯治理上是否有BUG在剖析完,客户端解决连接池的源码后,没有问题,跟料想统一,依照槽位缓存连接池,第一个假如被排除,源码如下。 1、setEx public String setex(final byte[] key, final int seconds, final byte[] value) { return new JedisClusterCommand<String>(connectionHandler, maxAttempts) { @Override public String execute(Jedis connection) { return connection.setex(key, seconds, value); } }.runBinary(key); } 2、runBinary public T runBinary(byte[] key) { if (key == null) { throw new JedisClusterException("No way to dispatch this command to Redis Cluster."); } return runWithRetries(key, this.maxAttempts, false, false); }3、runWithRetries private T runWithRetries(byte[] key, int attempts, boolean tryRandomNode, boolean asking) { if (attempts <= 0) { throw new JedisClusterMaxRedirectionsException("Too many Cluster redirections?"); } Jedis connection = null; try { if (asking) { // TODO: Pipeline asking with the original command to make it // faster.... connection = askConnection.get(); connection.asking(); // if asking success, reset asking flag asking = false; } else { if (tryRandomNode) { connection = connectionHandler.getConnection(); } else { connection = connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key)); } } return execute(connection); } 4、getConnectionFromSlot public Jedis getConnectionFromSlot(int slot) { JedisPool connectionPool = cache.getSlotPool(slot); if (connectionPool != null) { // It can't guaranteed to get valid connection because of node // assignment return connectionPool.getResource(); } else { renewSlotCache(); //It's abnormal situation for cluster mode, that we have just nothing for slot, try to rediscover state connectionPool = cache.getSlotPool(slot); if (connectionPool != null) { return connectionPool.getResource(); } else { //no choice, fallback to new connection to random node return getConnection(); } } }4.3.1.2 剖析连接池参数 ...

June 22, 2021 · 5 min · jiezi

关于redis:Redis-面霸篇高频问题横扫核心知识点

「码哥字节」从高频面试问题跟大家一起横扫 Redis 外围知识点,从根本上了解 Redis ,不做八股文的工具人,做扭转乾坤的大神。 码哥到现在曾经写了 9 篇 Redis 连载,后盾有小伙伴也让我写一些对于面试的文章,于是“面霸”系列便出道了。 如果大家用心读完《Redis 系列》并了解,吊打面试官基本不是事。 Redis 外围篇:唯快不破的机密Redis 日志篇:AOF 和 RDB 实现宕机疾速复原,数据不失落Redis 高可用篇:主从架构数据一致性同步原理Redis 实战篇:6.x 版本 Sentinel 哨兵集群搭建Redis 高可用篇:Sentinel 哨兵集群原理Redis 实战篇:6.x 版本 Cluster 集群搭建Redis 高可用篇:Cluster 集群能有限拓展么?原理是什么?Redis 实战篇:巧用 Bitmap 实现亿级海量数据统计Redis 实战篇:巧用数据结构实现亿级数据统计Redis 为什么这么快?很多人只晓得是 K/V NoSQl 内存数据库,单线程……这都是没有全面了解 Redis 导致无奈持续深问上来。 这个问题是根底摸底,咱们能够从 Redis 不同数据类型底层的数据结构实现、齐全基于内存、IO 多路复用网络模型、线程模型、渐进式 rehash…... 到底有多快?咱们能够先说到底有多快,依据官网数据,Redis 的 QPS 能够达到约 100000(每秒申请数),有趣味的能够参考官网的基准程序测试《How fast is Redis?》,地址:https://redis.io/topics/bench... 横轴是连接数,纵轴是 QPS。 这张图反映了一个数量级,通过量化让面试官感觉你有看过官网文档,很谨严。基于内存实现Redis 是基于内存的数据库,跟磁盘数据库相比,齐全吊打磁盘的速度。 不管读写操作都是在内存上实现的,咱们别离比照下内存操作与磁盘操作的差别。 磁盘调用 内存操作 内存间接由 CPU 管制,也就是 CPU 外部集成的内存控制器,所以说内存是间接与 CPU 对接,享受与 CPU 通信的最优带宽。 ...

June 22, 2021 · 4 min · jiezi

关于redis:CSSE1001-7030-统计详细解释

CSSE1001 / 7030 Semester 1, 2019Assignment 1 (15 Marks)Due: Friday 29 March 2019 at 20:30IntroductionWelcome to Travel Inspiration!We are going to be building a travel recommendation program. Out of ideas where to travel? TravelInspiration has got you covered.The program will ask the user questions about their preferences in a travel destination. It will usethese to recommend the best match in a database of potential travel destinations.You are provided with a file travel.py, which serves as a template for the assignment. This file iswhere you should write the code for your solution. The file also provides an example of how to readthe data from the database, one destination at a time. You need to implement the functionality toquestion the user and perform the matching. The database is in the form of a text file,destinations.csv. You may edit this text file to add more destinations for testing.OverviewTasksThis assignment is broken down into six main tasks, grouped into two categories: Core ...

June 18, 2021 · 13 min · jiezi

关于redis:Redis分布式锁

1. SETNX一般加锁形式,示意SET if Not eXists,当key不存在时才会去设置它的值,否则什么也不做 //客户端1申请加锁,加锁胜利127.0.0.1:6379> SETNX lock 1(integer) 1 // 客户端1,加锁胜利//客户端2申请加锁,加锁失败127.0.0.1:6379> SETNX lock 1(integer) 0 // 客户端2,加锁失败操作实现后再去开释锁 127.0.0.1:6379> DEL lock // 开释锁(integer) 1 存在缺点:程序处理业务逻辑异样,没及时开释锁过程挂了,没机会开释锁如何防止死锁设置过期工夫 127.0.0.1:6379> SETNX lock 1 // 加锁(integer) 1127.0.0.1:6379> EXPIRE lock 10 // 10s后主动过期(integer) 1//这种状况不是原子操作,任然会产生死锁问题// 一条命令保障原子性执行127.0.0.1:6379> SET lock 1 EX 10 NXOK这种状况仍会产生问题: 锁过期:客户端 1 操作共享资源耗时太久,导致锁被主动开释,之后被客户端 2 持有开释他人的锁:客户端 1 操作共享资源实现后,却又开释了客户端 2 的锁解决方案// 锁的VALUE设置为UUID127.0.0.1:6379> SET lock $uuid EX 20 NXOK开释锁时,应用lua脚本判断lock键的值是否是本人的uuid,如果是则开释Redis 解决每一个申请是「单线程」执行,在执行lua脚本时,其余申请必须期待 综上所述,基于redis的分布式锁,流程应该如下: 加锁:SET lock_key $unique_id EX $expire_time NX操作共享资源开释锁:Lua 脚本,先 GET 判断锁是否归属本人,再 DEL 开释锁解决锁过期问题:应用redisson,加锁时先设置一个过期工夫,而后开启一个守护线程,定时去检测锁的生效工夫,如果锁快过期,操作共享资源还未完结,则进行续期,从新设置过期工夫.默认过期工夫为30s,检测时间为20s ...

June 18, 2021 · 1 min · jiezi

关于redis:技术分享-主从和集群架构下-redis-client-连接实例的实现方式

作者:王悦 Copyright (C) 2021 wingYue 本文起源:原创投稿 *爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。 redis 作为一个高性能的内存数据库被广泛应用于各类零碎中,比方排行榜、评分服务等等。咱们在抉择 redis 时除了思考其提供的数据类型和性能是否满足业务需要之外,十分重要的一点是思考高可用性。redis 提供了 redis sentinel 来实现高可用机制,sentinel 会监控 redis 主从实例,提供主动故障切换性能。 然而随之而来一个问题是 client 在故障切换后如何得悉以后的 master 实例地址? 主从架构办法一: 应用 redis sentinel 的服务发现redis sentinel 提供了一个服务发现机制,连贯 sentinel 执行“SENTINEL get-master-addr-by-name”,会返回以后 master 实例地址,故障切换后,返回后果也会更新为新的master实例地址: 有很多“聪慧”的 redis client 库都实现了基于该服务发现机制的主动连贯,只有将 sentinel 的地址列表传入,clinet 会通过 sentinel 获取以后最新的 master 地址,而后应用获取的地址连贯。比方 jedis: sentinels.add(new HostAndPort("192.168.0.31",26379).toString()); sentinels.add(new HostAndPort("192.168.0.32",26379).toString()); sentinels.add(new HostAndPort("192.168.0.33",26379).toString()); pool = new JedisSentinelPool(masterName, sentinels, config, TIMEOUT,password); ... // 获取连贯: Jedis jedis = pool.getResource(); try { jedis.set("hello", "jedis"); } finally { jedis.close(); }jedis 作为一个优良的 redis 客户端,其应用的订阅 sentinel的形式是时刻在内存中保护最新的 master 地址。而一些其余的 client 则是在每次获取连贯时,先询问 sentinel 最新 master 地址,而后再执行 redis 连贯,这样每次操作都须要发送两次申请,并不是十分高效。另一种形式是应用 VIP : ...

June 16, 2021 · 2 min · jiezi

关于redis:在-SAP-Kyma-上使用-Redis-服务

链接:https://developers.sap.com/tu... 本地文件:C:\Code\referenceCode\SAP Kyma教程例子\redis-function 蕴含一个 deployment 和两个 function: 函数1:cache-order定义了三个依赖: axiosredishandy-redis 环境变量 这些环境变量的用法,在代码里应用 process.env 加上中括号援用。 cache-order 函数的三大次要逻辑: (1)从 Kyma 传入的 event 构造里,取得 Commerce 创立订单的 ID. (2) 依据订单 ID,调用函数 getOrderDetails,取得订单明细。 (3) 从订单明细里取得含税的价格,调用函数 cacheOrder,将价格存储到 Redis 里: getOrderDetails 的实现: async function getOrderDetails(orderCode) { const ordersUrl = `${COMM_GATEWAY_URL}/${process.env.SITE}/orders/${orderCode}`; console.log("Getting ordering details via: %s", ordersUrl, " for orderCode: ", orderCode); const response = await axios.get(ordersUrl); console.log(JSON.stringify(response.data, null, 2)); return response.data;}代码里的 COMM_GATEWAY_URL 环境变量,在 Kyma 控制台里可能找到: ...

June 16, 2021 · 1 min · jiezi

关于redis:Redis的安装

筹备redis安装包进入redis官网,找到redis安装包下载地址,这里咱们抉择文本版本6.2.4 https://download.redis.io/releases/redis-6.2.4.tar.gz?_ga=2.148749810.415473691.1623143846-237276233.1597318421linux零碎中(centos7),通过wget下载安装包,如果没有装置wget工具,先进行装置 yum install wget创立redis包寄存目录(如/opt/redis)并进入,执行wget下载redis安装包 wget https://download.redis.io/releases/redis-6.2.4.tar.gz?_ga=2.148749810.415473691.1623143846-237276233.1597318421下载实现后进行解压 tar xf redis-6.2.4.tar.gz解压完的文件中蕴含redis源码、工具和装置阐明等文件 编译咱们首先要将redis源码编译成可执行文件能力运行。在上述解压的readme.md文件中有具体的编译及装置步骤。最简略间接的形式是间接运行make命令,进入redis-6.2.4目录,执行 make也能够依据须要加一些编译参数,如make BUILD_TLS=yes 编译反对tls,make 32bit编译成32位 等,在readme.md中有具体阐明。make过程中可能会呈现谬误而终止,而后再从新执行make编译时须要革除一下编译缓存,保障从新开始 make distclean编译实现后,会在src目录下生成可执行文件redis-server,执行就能够启动了 ./redis-serverredis是C语言开发的,make编译时应该确保零碎装置c语音编译器,如下装置 yum install gccmake命令是linux下的一个编译调用工具,他会找到当前目录下的Makefile文件,依据其内容进行编译。因而make之前要先保障生成Makefile文件,如果没有须要应用configure命令进行生成后再进行编译。 装置将redis装置成零碎服务,后盾运行,缩小人工启动。装置的过程其实是将编译实现的程序copy到装置目录下,默认是装置到/usr/local/bin目录下,能够指定其余装置目录。进入redis源码编译目录,执行 make install PREFIX=/opt/jia/redis6.2.4装置命令会将redis的编译文件copy到/opt/jia/redis6.2.4/bin目录下。咱们看一下具体的文件列表 这时能够应用redis-server脚步启动redis服务 ./redis-server应用make install命令只会进行二进制文件的装置,不会进行一些脚本初始化及配置之类的操作。在生产环境中咱们个别会将redis装置成服务,后盾运行。redis提供了utils工具来实现服务的装置配置。执行前咱们先配置一下Redis环境变量,指定redis-server执行文件门路。 vi /etc/profile#在最初一行退出redis环境变量export REDIS_HOME=/opt/jia/redis6.2.4export PATH=$PATH:$REDIS_HOME/bin#保留文件而后失效配置文件source /etc/profile进入src/utils目录,执行install_server.sh脚本 cd utils./install_server.sh图片中咱们看到,装置过程中会为redis调配 配置文件6379.conf放到/etc/redis/目录下;日志文件/var/log/redis_6379.log数据文件/var/lib/redis/6379redis的执行程序指向咱们配置的环境变量目录设置零碎服务治理redis。 在/etc/init.d目录下生成redis_6379执行文件,并执行chkconfig命令设置服务启动装置实现后,安装程序会将redis服务启动起来,当初咱们能够应用service redis命令查看redis服务状态。 # 服务名字要和init.d下的文件名统一service redis_6379 status单机多实例装置在一台主机上反对多个redis服务装置运行,各实例之间共享同一份安装文件(上文中装置目录/opt/jia/6.2.4/bin),应用端口号辨别配置文件及数据文件。运行install_server.sh脚本进行装置 Please select the redis port for this instance:[6379] 6380输出6380回车,安装程序主动为新装置实例生成新的6380配置文件/日志文件/数据文件,实现后在/etc/init.d目录下会生成一个redis_6380可执行文件,应用service redis_6380 start启动新实例。 装置过程中呈现的谬误装置中如果呈现以下谬误 This systems seems to use systemd.Please take a look at the provided example service unit files in this directory, and adapt and install them. Sorry!批改install_server.sh脚本 ...

June 15, 2021 · 1 min · jiezi

关于redis:Redis-实战篇巧用-Bitmap-实现亿级数据统计

在挪动利用的业务场景中,咱们须要保留这样的信息:一个 key 关联了一个数据汇合。 常见的场景如下: 给一个 userId ,判断用户登陆状态;显示用户某个月的签到次数和首次签到工夫;两亿用户最近 7 天的签到状况,统计 7 天内间断签到的用户总数;通常状况下,咱们面临的用户数量以及访问量都是微小的,比方百万、千万级别的用户数量,或者千万级别、甚至亿级别的访问信息。 所以,咱们必须要抉择可能十分高效地统计大量数据(例如亿级)的汇合类型。 如何抉择适合的数据汇合,咱们首先要理解罕用的统计模式,并使用正当的数据了性来解决理论问题。 四种统计类型: 二值状态统计;聚合统计;排序统计;基数统计。本文将由二值状态统计类型作为实战篇系列的开篇,文中将用到 String、Set、Zset、List、hash 以外的拓展数据类型 Bitmap 来实现。 文章波及到的指令能够通过在线 Redis 客户端运行调试,地址:https://try.redis.io/,超不便的说。 寄语多分享多付出,后期多给他人发明价值并且不计回报,从久远来看,这些付出都会成倍的回报你。 特地是刚开始跟他人单干的时候,不要去计较短期的回报,没有太大意义,更多的是锤炼本人的视线、视角以及解决问题的能力。 二值状态统计码哥,什么是二值状态统计呀?也就是汇合中的元素的值只有 0 和 1 两种,在签到打卡和用户是否登陆的场景中,只需记录签到(1)或 未签到(0),已登录(1)或未登陆(0)。 如果咱们在判断用户是否登陆的场景中应用 Redis 的 String 类型实现(key -> userId,value -> 0 示意下线,1 - 登陆),如果存储 100 万个用户的登陆状态,如果以字符串的模式存储,就须要存储 100 万个字符串了,内存开销太大。 码哥,为什么 String 类型内存开销大?String 类型除了记录理论数据以外,还须要额定的内存记录数据长度、空间应用等信息。 当保留的数据蕴含字符串,String 类型就应用简略动静字符串(SDS)构造体来保留,如下图所示: len:占 4 个字节,示意 buf 的已用长度。alloc:占 4 个字节,示意 buf 理论调配的长度,通常 > len。buf:字节数组,保留理论的数据,Redis 主动在数组最初加上一个 “\0”,额定占用一个字节的开销。所以,在 SDS 中除了 buf 保留理论的数据, len 与 alloc 就是额定的开销。 ...

June 15, 2021 · 3 min · jiezi

关于redis:技术干货-高负载压测下接口异常问题定位排查Redis

背景: xx业务接口次要为获取全国范畴地区信息,实在生产场景是调用频繁数据量大,因而须要对该业务接口做性能测试,确认接口性能及高负载下承受能力。 接口解决逻辑:获取全国范畴地区信息,第一次从mysql获取信息,获取到信息后hset到redis,前面的获取信息都走redis获取并返回接口数据。 问题: 20并发对该接口进行继续加压,压力负载一直晋升,压力机端监控到返回错误信息,连贯失败(10并发失常), 应用服务抛出异样:getList:merchant:area:list error redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool 定位排查: 从利用抛出异样信息看出,无奈获取更多的redis线程池资源,但20并发还未造成高强度的压力,进一步排查: 硬件资源:服务器资源利用率失常,cpu、内存,磁盘等比拟短缺,排查资源影响 Redis配置及性能:查看redis连接池配置redis.pool.maxIdle=300,redis.pool.maxTotal=600,设置足够大,在20并发继续压测下,该最大连接数已足够大,但依然抛出redis连接池异样,应存在其余方面因素影响,持续排查 redis连接数失常,netstat -nap |grep redis |wc -l,100多个流动连贯。 redis -info查看redis信息连贯失常,失常连贯100多个。 redis -monitor获取数据失常,get和hget数据均失常。 查看redis日志,找到问题如下问题: WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect. ...

June 10, 2021 · 2 min · jiezi

关于redis:Redis-的线程模型

Redis 外部应用文件事件处理器 file event handler,这个文件事件处理器是单线程的,所以 Redis 才叫做单线程的模型。它采纳 IO 多路复用机制同时监听多个 Socket,依据 Socket 上的事件来抉择对应的事件处理器进行解决。 文件事件处理器的构造蕴含 4 个局部: 多个 Socket IO 多路复用程序 文件事件分派器 事件处理器(连贯应答处理器、命令申请处理器、命令回复处理器) 多个 Socket 可能会并发产生不同的操作,每个操作对应不同的文件事件,然而 IO 多路复用程序会监听多个 Socket,会将 Socket 产生的事件放入队列中排队,事件分派器每次从队列中取出一个事件,把该事件交给对应的事件处理器进行解决。

June 8, 2021 · 1 min · jiezi