前言

背景:测试环境的redis集群被运维回收,无奈之下只能自己动手,Redis高可用集群架构的搭建。

原理

Redis的哨兵(sentinel)系统用于管理多个redis服务器,该系统执行以下三个任务:

  • 监控(Monitoring):哨兵(sentinel)会不断地检查你的Master和Slave是否运作正常。

  • 提醒(Notification):当被监控的某个Redis出现问题时,哨兵(sentinel)可以通过API向管理员或者其他应用程序发送通知。

  • 自动故障迁移(Automatic failover):当一个Master不能正常工作时,哨兵(sentinel)会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master,并让失效Master的其他Slave改为复制新的Master;当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用Master代替失效Master,客户端实际获取的链接是哨兵返回的。

哨兵(sentinel)是一个分布式系统,你可以在一个架构中运行多个哨兵(sentinel)进程,这些进程使用流言协议(gossipprotocols)来接收关于Master是否下线的信息,并使用投票协议(agreement protocols)来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master。

每个哨兵(sentinel)会向其它哨兵(sentinel)、master、slave定时发送消息,以确认对方是否”活”着,如果发现对方在指定时间(可配置)内未回应,则暂时认为对方已挂(所谓的”主观认为宕机” Subjective Down,简称sdown).

若“哨兵群”中的多数sentinel,都报告某一master没响应,系统才认为该master"彻底死亡"(即:客观上的真正down机,Objective Down,简称odown),通过一定的vote算法,从剩下的slave节点中,选一台提升为master,然后自动修改相关配置.

虽然哨兵(sentinel)释出为一个单独的可执行文件redis-sentinel ,但实际上它只是一个运行在特殊模式下的Redis服务器,你可以在启动一个普通Redis服务器时通过给定--sentinel选项来启动哨兵(sentinel).

哨兵(sentinel)的一些设计思路和zookeeper非常类似。

架构图

下载

首页地址:http://redis.io/

最新稳定版下载地址:http://download.redis.io/releases/redis-3.2.9.tar.gz

# tar -xvf redis-3.2.9.tar.gz

# cd redis-3.2.9

# make install

# make test

命令

redis-server    -h

Usage: ./redis-server [/path/to/redis.conf] [options]

./redis-server - (read config from stdin)

./redis-server -v or --version

./redis-server -h or --help

./redis-server --test-memory

Examples:

./redis-server (run the server with default conf)

./redis-server /etc/redis/6379.conf

./redis-server --port 7777

./redis-server --port 7777 --slaveof 127.0.0.1 8888

./redis-server /etc/myredis.conf --loglevel verbose

Sentinel mode:

./redis-server /etc/sentinel.conf --sentinel

配置

daemonize yes        ###daemon后台运行模式

pidfile /var/run/redis.pid  ###pidfile

port 6379  ###默认6379端口

tcp-backlog 511  ###tcp三次握手等待确认ack最大的队列数

bind 192.168.65.128 127.0.0.1  ###绑定的监听的ip,可同时写多个ip,不写默认监控0.0.0.0

timeout 0  ###关闭空闲客户端,0为disable

tcp-keepalive 0 ###是否开启tcp长连接,定义socket连接timeout时长

loglevel notice  ###定义日志级别为notice(输出必要的日志)

logfile "/var/log/redis/redis.log" ###定义日志输出目录

databases 16  ###允许redis定义的最大的db簇

###开启rdb并应用如下数据保存策略,aof和rdb可同时启用,aof强烈建议开启

save 900 1

save 300 10

save 60 10000

stop-writes-on-bgsave-error yes  ###有任何问题导致的bgsave失败都停止redis的对外服务

rdbcompression yes  ###rdb写压缩

rdbchecksum yes  ###rdb文件正确性检查

dbfilename dump.rdb  ###rdb文件名称(dump.rdb可任意起)

dir /var/lib/redis/    ###rdb文件写目录

# slaveof     ###如果是slave需要写明master

# masterauth     ###master密码验证(因为redis基于内存,作用不大)

slave-serve-stale-data no  ###如果master宕机,slave是否还正常对外服务no->停止服务

slave-read-only yes    ###salve是否只读(默认只读)
repl-diskless-sync no ### Disk-backed 启动新进程写rdb到disk,然后增量传输到salves 方式二:Diskless 直接写salve sockers,而不用写disk,当网络好的时候建议使用,但因为用到的是M/S+哨兵的架构,随时可能会进行主从切换,这个方式暂时不用 repl-diskless-sync-delay 5 ##每5s传输一次diskless开启后生效 repl-ping-slave-period 3 ###slave每3s ping测试master是否存活 repl-timeout 10 ###定义replicationtxuq timeout时间,这里的时间要大于repl-ping-slave-period里的时间,不然后一直发生low traffic between the master and the slave问题 repl-disable-tcp-nodelay no ###yes 一条线40milliseconds发送一次数据包,意识着更小的tcp packets和更小的带宽去发送到slave,但在slave会有相应的数据延迟. No,刚相反.一般上我们期望是低延迟,所以最选择no是个不错的选择,但如果在复杂的网络情况或m/s之间有很多中继网络,这里建议修改为yes slave-priority 100 ###slave优先级别,数字越小优先级别越高,当master宕机时优先选取slave # min-slaves-to-write 3 ###当最少有3个slave延迟<= 10s时,master才正常提供服务 # min-slaves-max-lag 10 ###当最少有3个slave延迟<= 10s时,master才正常提供服务 maxmemory 1536000000 #1.5G ###单位 ,redis最大占用内存数,当超过1.5G时redis会根据策略清理内存key #############6种清理策略 # volatile-lru -> remove the key with an expire set using an LRU algorithm ##推荐使用 # allkeys-lru -> remove any key according to the LRU algorithm # volatile-random -> remove a random key with an expire set # allkeys-random -> remove a random key, any key # volatile-ttl -> remove the key with the nearest expire time (minor TTL) # noeviction -> don't expire at all, just return an error on write operations maxmemory-policy volatile-lru ###使用LRU算法清理过期key # maxmemory-samples 3 ###LRU算法和TTL算法均为模糊算法,该精确算法redis会选择3个keys选择最少使用的一个key进行删除, 个人不建议使用 appendonly yes ###aof持久化,增量写disk,比aof慢,但更可靠.企业的默认选择,有的会两者均开启 appendfilename "appendonly.aof" ###aof文件名 # appendfsync always appendfsync everysec ###建议使用该方式 # appendfsync no no-appendfsync-on-rewrite no ##建议no, 主要用来缓和redis调用fsync()写数据时间长的问题.当BGSAVE或BGREWRITEAOF被调用期间,fsync()进程将阻止被调用,即相当于 auto-aof-rewrite-percentage 100 ###当文件大小达到64mb的100%大小时开始rewrite aof文件 auto-aof-rewrite-min-size 64mb ###当文件大小达到64mb的100%大小时开始rewrite aof文件 aof-load-truncated yes ###当aof文件被损坏时,redis将返回错误并退出 lua-time-limit 5000 ###LUA scripts最大执行时间,单位(milliseconds),超出后返回查询错误并写日志 slowlog-log-slower-than 10000 ###单位microseconds(毫秒) 1000000 microseconds=1 s,记录执行时长超过10000 microseconds的执行命令 slowlog-max-len 128 ###最大长度为128 latency-monitor-threshold 0 ###监控相关,关闭就好 notify-keyspace-events "" ###空表示关闭,发布相关key的操作记录到所有 client ######下面是高级设置,个人保持为默认配置 hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-entries 512 list-max-ziplist-value 64 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 activerehashing yes client-output-buffer-limit normal 0 0 0 client-output-buffer-limit slave 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 hz 10 aof-rewrite-incremental-fsync yes

启动

# redis-server /etc/redis/redis.conf

查看

# redis-cli -h Mrds

Mrds:6379> info

# Server

redis_version:2.8.19    ###redis版本号

redis_git_sha1:00000000  ###git SHA1

redis_git_dirty:0  ###git dirty flag

redis_build_id:78796c63e58b72dc

redis_mode:standalone  ###redis运行模式

os:Linux 2.6.32-431.el6.x86_64 x86_64  ###os版本号

arch_bits:64  ###64位架构

multiplexing_api:epoll  ###调用epoll算法

gcc_version:4.4.7  ###gcc版本号

process_id:25899  ###服务器进程PID

run_id:eae356ac1098c13b68f2b00fd7e1c9f93b1c6a2c  ###Redis的随机标识符(用于sentinel和集群)

tcp_port:6379  ###Redis监听的端口号

uptime_in_seconds:6419 ###Redis运行时长(s为单位)

uptime_in_days:0  ###Redis运行时长(天为单位)

hz:10

lru_clock:10737922  ###以分钟为单位的自增时钟,用于LRU管理

config_file:/etc/redis/redis.conf  ###redis配置文件

# Clients

connected_clients:1  ###已连接客户端的数量(不包括通过从属服务器连接的客户端)

client_longest_output_list:0  ###当前连接的客户端中最长的输出列表

client_biggest_input_buf:0  ###当前连接的客户端中最大的输出缓存

blocked_clients:0  ###正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客户端的数量 需监控

# Memory

used_memory:2281560  ###由 Redis 分配器分配的内存总量,以字节(byte)为单位

used_memory_human:2.18M  ###以更友好的格式输出redis占用的内存

used_memory_rss:2699264  ###从操作系统的角度,返回 Redis 已分配的内存总量(俗称常驻集大小)。这个值和 top 、 ps 等命令的输出一致

used_memory_peak:22141272  ### Redis 的内存消耗峰值(以字节为单位)

used_memory_peak_human:21.12M  ###以更友好的格式输出redis峰值内存占用

used_memory_lua:35840  ###LUA引擎所使用的内存大小

mem_fragmentation_ratio:1.18  ###used_memory_rss 和 used_memory 之间的比率

mem_allocator:jemalloc-3.6.0

###在理想情况下, used_memory_rss 的值应该只比 used_memory 稍微高一点儿。当 rss > used ,且两者的值相差较大时,表示存在(内部或外部的)内存碎片。内存碎片的比率可以通过 mem_fragmentation_ratio 的值看出。

当 used > rss 时,表示 Redis 的部分内存被操作系统换出到交换空间了,在这种情况下,操作可能会产生明显的延迟。

# Persistence

loading:0  ###记录服务器是否正在载入持久化文件

rdb_changes_since_last_save:0  ###距离最近一次成功创建持久化文件之后,经过了多少秒

rdb_bgsave_in_progress:0  ###记录了服务器是否正在创建 RDB 文件

rdb_last_save_time:1420023749  ###最近一次成功创建 RDB 文件的 UNIX 时间戳

rdb_last_bgsave_status:ok  ###最近一次创建 RDB 文件的结果是成功还是失败

rdb_last_bgsave_time_sec:0  ###最近一次创建 RDB 文件耗费的秒数

rdb_current_bgsave_time_sec:-1  ###如果服务器正在创建 RDB 文件,那么这个域记录的就是当前的创建操作已经耗费的秒数

aof_enabled:1  ###AOF 是否处于打开状态

aof_rewrite_in_progress:0  ###服务器是否正在创建 AOF 文件

aof_rewrite_scheduled:0  ###RDB 文件创建完毕之后,是否需要执行预约的 AOF 重写操作

aof_last_rewrite_time_sec:-1  ###最近一次创建 AOF 文件耗费的时长

aof_current_rewrite_time_sec:-1  ###如果服务器正在创建 AOF 文件,那么这个域记录的就是当前的创建操作已经耗费的秒数

aof_last_bgrewrite_status:ok  ###最近一次创建 AOF 文件的结果是成功还是失败

aof_last_write_status:ok

aof_current_size:176265  ###AOF 文件目前的大小

aof_base_size:176265  ###服务器启动时或者 AOF 重写最近一次执行之后,AOF 文件的大小

aof_pending_rewrite:0  ###是否有 AOF 重写操作在等待 RDB 文件创建完毕之后执行

aof_buffer_length:0  ###AOF 缓冲区的大小

aof_rewrite_buffer_length:0  ###AOF 重写缓冲区的大小

aof_pending_bio_fsync:0  ###后台 I/O 队列里面,等待执行的 fsync 调用数量

aof_delayed_fsync:0    ###被延迟的 fsync 调用数量

# Stats

total_connections_received:8466  ###服务器已接受的连接请求数量

total_commands_processed:900668  ###服务器已执行的命令数量

instantaneous_ops_per_sec:1  ###服务器每秒钟执行的命令数量

total_net_input_bytes:82724170

total_net_output_bytes:39509080

instantaneous_input_kbps:0.07

instantaneous_output_kbps:0.02

rejected_connections:0  ###因为最大客户端数量限制而被拒绝的连接请求数量

sync_full:2

sync_partial_ok:0

sync_partial_err:0

expired_keys:0  ###因为过期而被自动删除的数据库键数量

evicted_keys:0  ###因为最大内存容量限制而被驱逐(evict)的键数量。

keyspace_hits:0  ###查找数据库键成功的次数。

keyspace_misses:500000  ###查找数据库键失败的次数。

pubsub_channels:0  ###目前被订阅的频道数量

pubsub_patterns:0  ###目前被订阅的模式数量

latest_fork_usec:402  ###最近一次 fork() 操作耗费的毫秒数

# Replication

role:master  ###如果当前服务器没有在复制任何其他服务器,那么这个域的值就是 master ;否则的话,这个域的值就是 slave 。注意,在创建复制链的时候,一个从服务器也可能是另一个服务器的主服务器

connected_slaves:2  ###2个slaves

slave0:ip=192.168.65.130,port=6379,state=online,offset=1639,lag=1

slave1:ip=192.168.65.129,port=6379,state=online,offset=1639,lag=0

master_repl_offset:1639

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:2

repl_backlog_histlen:1638

# CPU

used_cpu_sys:41.87  ###Redis 服务器耗费的系统 CPU

used_cpu_user:17.82  ###Redis 服务器耗费的用户 CPU

used_cpu_sys_children:0.01  ###后台进程耗费的系统 CPU

used_cpu_user_children:0.01  ###后台进程耗费的用户 CPU

# Keyspace

db0:keys=3101,expires=0,avg_ttl=0  ###keyspace 部分记录了数据库相关的统计信息,比如数据库的键数量、数据库已经被删除的过期键数量等。对于每个数据库,这个部分都会添加一行以下格式的信息

Sentinel(哨兵)配置

vi sentinel.conf

启动前:

port 26379

dir "/var/lib/redis/tmp"  ###定义目录存放

sentinel auth-passmymaster vhreal   ##密码

sentinel monitor mymaster 192.168.65.128 6379 2    ###监控mymaster(可自定义-但只能包括A-z 0-9和”._-”)

sentinel down-after-milliseconds mymaster 30000  ###mymaster多久不响应认为SDOWN

sentinel parallel-syncs mymaster 1  ###指定最大同时同步新maser配置的salve数量

sentinel failover-timeout mymaster 180000  ###2次failover切换时间

启动后(redis.con配置文件完全由sentinel控制,请不要再随意手动改动):

port 26379

dir "/var/lib/redis/tmp"

sentinel monitor mymaster 192.168.65.128 6379 2

sentinel config-epoch mymaster 18  ###确认mymater SDOWN时长

sentinel leader-epoch mymaster 18  ###同时一时间最多18个slave可同时更新配置,建议数字不要太大,以免影响正常对外提供服务

sentinel known-slave mymaster 192.168.65.129 6379  ###已知的slave

sentinel known-slave mymaster 192.168.65.130 6379  ###已知的slave

sentinel known-sentinel mymaster 192.168.65.130 26379 be964e6330ee1eaa9a6b5a97417e866448c0ae40    ###已知slave的唯一id

sentinel known-sentinel mymaster 192.168.65.129 26379 3e468037d5dda0bbd86adc3e47b29c04f2afe9e6  ###已知slave的唯一id

sentinel current-epoch 18  ####当前可同时同步的salve数最大同步阀值

开启sentinel

开启sentinel后会后redis.conf会由sentinel进行管理

# redis-server /etc/redis/sentinel.conf --sentinel &> /var/log/redis/sentinel.log &

常用命令

redis-cli

redis-server

auth

set key value

get key

Q&A

Redis主从配置异常解决:Error condition on socket for SYNC: Connection refused

Redis主从集群时,从服务器上的redis日志报错:

32677:S08Feb16:14:38.947*ConnectingtoMASTER172.168.10.70:637932677:S08Feb16:14:38.948*MASTER<->SLAVEsyncstarted32677:S08Feb16:14:38.948#ErrorconditiononsocketforSYNC:Connectionrefused32677:S08Feb16:14:39.950*ConnectingtoMASTER172.168.10.70:637932677:S08Feb16:14:39.950*MASTER<->SLAVEsyncstarted32677:S08Feb16:14:39.950#ErrorconditiononsocketforSYNC:Connectionrefused32677:S08Feb16:14:40.952*ConnectingtoMASTER172.168.10.70:637932677:S08Feb16:14:40.952*MASTER<->SLAVEsyncstarted32677:S08Feb16:14:40.953#ErrorconditiononsocketforSYNC:Connectionrefused
  • 解决方案:

在redis主服务器上的redis.conf中修改bind字段,将

bind 127.0.0.1

修改为

bind 0.0.0.0

又或者直接注释掉bind字段

# bind 127.0.0.1
  • 原因:

如果redis主服务器绑定了127.0.0.1,那么跨服务器IP的访问就会失败,从服务器用IP和端口访问主的时候,主服务器发现本机6379端口绑在了127.0.0.1上,也就是只能本机才能访问,外部请求会被过滤,这是Linux的网络安全策略管理的。如果bind的IP地址是172.168.10.70,那么本机通过localhost和127.0.0.1、或者直接输入命令redis-cli登录本机redis也就会失败了。只能加上本机ip才能访问到。

所以,在研发、测试环境可以考虑bind 0.0.0.0,线上生产环境建议绑定IP地址。

(DENIED Redis is running in protected mode)

Java程序中使用JedisSentinelPool建立redis连接池


Set sentinels = new HashSet(); sentinels.add("172.17.16.7:26379"); sentinels.add("172.17.16.8:26379"); sentinels.add("172.17.16.9:26379"); JedisSentinelPool sentinelPool = new JedisSentinelPool("mymaster", sentinels, "123456");

报错:

DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to    clients.......

使用redis-cli -h 127.0.0.1 -p 26379连接sentinel可以执行命令,而使用redis-cli -h 172.17.16.7 -p 26379连接sentinel执行命令则会报同上的错误。

查遍了网上没有找到相关的问题分析和解决的案例,所以只能自己猜测和排查,初步怀疑是通过172.17.16.7访问sentinel时受限。

由于此错误和redis server的protect-mode为yes的访问错误颇为相似,官方在redis.conf的注释说明中有protected-mode这一配置项,但sentinel.conf的注释中完全没有提到过该配置项,我很疑惑,但还是尝试在sentinel.conf中加入

protected-mode no

之后保存并重新启动sentinel,之后用Java程序建立连接池,没有报错,且可以对redis server进行数据处理,问题解决。

Redis哨兵(sentinel)的更多相关文章

  1. redis单点、redis主从、redis哨兵sentinel,redis集群cluster配置搭建与使用

    目录 redis单点.redis主从.redis哨兵 sentinel,redis集群cluster配置搭建与使用 1 .redis 安装及配置 1.1 redis 单点 1.1.2 在命令窗口操作r ...

  2. redis哨兵(Sentinel)、虚拟槽分区(cluster)和docker入门

    一.Redis-Sentinel(哨兵) 1.介绍 Redis-Sentinel是redis官方推荐的高可用性解决方案,当用redis作master-slave的高可用时,如果master本身宕机,r ...

  3. Redis哨兵(sentinel)模式搭建

    一.Sentinel介绍 之前骚了一波Redis的简介及应用场景,今天试了下他的哨兵模式: Sentinel是Redis的高可用性(HA)解决方案,由一个或多个Sentinel实例组成的Sentine ...

  4. Redis 哨兵 Sentinel

    Redis Sentinel:redis集群应用,分布式系统.   多个Sentinal进程之间通过 gossip 协议来接收主服务器是否下线的信息,通过 Raft 一致性协议来决定故障转移及转移服务 ...

  5. redis哨兵sentinel.conf文件

    关闭保护模式 //17行 protected-mode no 端口号 //21 port 26379 后台启动 //26 daemonize yes //84行 主机的ip加端口号 2 为票数 sen ...

  6. Redis容灾部署(哨兵Sentinel)

    Redis容灾部署(哨兵Sentinel) 哨兵的作用 1. 监控:监控主从是否正常2. 通知:出现问题时,可以通知相关人员3. 故障迁移:自动主从切换4. 统一的配置管理:连接者询问sentinel ...

  7. SpringBoot进阶教程(三十)整合Redis之Sentinel哨兵模式

    Redis-Sentinel是官方推荐的高可用解决方案,当redis在做master-slave的高可用方案时,假如master宕机了,redis本身(以及其很多客户端)都没有实现自动进行主备切换,而 ...

  8. redis cluster + sentinel详细过程和错误处理三主三备三哨兵

    redis cluster + sentinel详细过程和错误处理三主三备三哨兵1.基本架构192.168.70.215 7001 Master + sentinel 27001192.168.70. ...

  9. Redis哨兵模式(sentinel)学习总结及部署记录(主从复制、读写分离、主从切换)

    Redis的集群方案大致有三种:1)redis cluster集群方案:2)master/slave主从方案:3)哨兵模式来进行主从替换以及故障恢复. 一.sentinel哨兵模式介绍Sentinel ...

  10. redis 哨兵(sentinel)

    redis哨兵 哨兵自动故障转移 自动通知应用最新master信息 无需担心,master挂了,程序不需要修改IP啥的,由哨兵自动完成 修改sentinel.conf protected-mode n ...

随机推荐

  1. JVM 堆外内存查看方法

    JVM 堆外内存查看方法 JVM 堆外内存查看方法 1.概述 是否曾经想过为什么Java应用程序通过众所周知的*-Xms和-Xmx调整标志消耗的内存比指定的数量大得多 ?由于各种原因和可能的优化,JV ...

  2. 参照DefenseGrid在Unity中实现合理的塔防寻路机制

    前言 在一款TD游戏中,最重要的单位就两大类:防御塔(Tower)和敌人单位(Enemy).在处理敌人单位的AI行为时,最基本也是最重要的就是自动寻路.在各式TD游戏中,防御塔的攻击方式以及敌人单位的 ...

  3. Go 1.21发布!

    原文在这里. 由Eli Bendersky, on behalf of the Go team 发布于 8 August 2023 Go团队今天非常高兴地发布了Go 1.21版本,你可以通过访问下载页 ...

  4. CreateProcess函数源码分析

    CreateProcess函数源码分析 ​ 源码版本:Windows 2003 源码 ​ 源码阅读工具:Source Insight 函数功能分析 函数原型 BOOL CreateProcessA( ...

  5. 在vscode中运行bat文件(执行bat)并解决中文乱码问题

    使用vscode编写bat脚本让工作流得到了极大的改善 以前:在文本编辑器中写完,保存,回到资源管理器双击bat运行,再循环重复 现在:在vscode中编写bat,按下快捷键执行bat 在vscode ...

  6. 机器学习算法(四): 基于支持向量机的分类预测(SVM)

    机器学习算法(四): 基于支持向量机的分类预测 本项目链接:https://www.heywhale.com/home/column/64141d6b1c8c8b518ba97dcc 1.相关流程 支 ...

  7. 2.3 CE修改器:浮点数扫描

    本关需要使用 Cheat Engine 工具对浮点数进行扫描,完成修改任务.浮点数是一种带有小数点的数值,通过"浮点数"扫描方式进行修改.本关中,健康值为单精度浮点数,弹药值为双精 ...

  8. Java注解之获取注解内部数据的原因分析

    我们都知道从JDK1.5开始,注解开始被支持使用,当我们在使用注解的时候感觉比配置文件用起来更加简便和清爽.配置文件是通过解析配置文件的内容获取到数据,那么为什么仅仅在类.方法或者属性上添加注解被注解 ...

  9. P4747 [CERC2017] Intrinsic Interval 题解

    题目链接:Intrinsic Interval 讲讲析合树如何解决这种问题,其实这题很接近析合树的板题的应用. 增量法进行析合树建树时,需要用 ST 表预处理出 \(max\) 和 \(min\) 以 ...

  10. P7167 [eJOI2020 Day1] Fountain 题解

    题目链接:Fountain 很不错的基础算法组合题:单调栈+倍增 首先考虑到一个事实,就是下面第一个比当前半径大的位置会成为移动的第一次落脚点,抽象下就是下面出现的第一次比自身大的半径,这个问题显然可 ...