Redis設計與實現-哨兵

哨兵模式

  • 1、啟動并初始化sentinel
    • 1.1 初始化服務器
    • 1.2 使用Sentinel代碼
    • 1.3 初始化sentinel狀態
    • 1.4 初始化sentinel狀態的master屬性
    • 1.5 創建連向主服務器的網絡連接
  • 2、獲取主服務器信息
  • 3、獲取從服務器的信息
  • 4、向主從服務器發送信息
  • 5、接受主從服務器的頻道信息
  • 6、檢測主觀下線狀態
  • 7、檢查客觀下線狀態
  • 8、選擇領頭的sentinel
  • 9、故障轉移
    • 9.1 選擇新主服務器
    • 9.2 修改從服務器復制目標
    • 9.3 將舊的主服務器轉換為從服務器

如有侵權,請聯系~
如有錯誤,也歡迎批評指正~
本篇文章大部分是來自學習《Redis設計與實現》的筆記

哨兵(Sentinel)是Redis的高可用解決方案:由一個或者多個哨兵實例組成的哨兵系統,可以監視任意多個主服務器以及這些主服務器所屬下的所有從服務器,并且在被監視的主服務器下線時自動的將從某個服務器升級為新的主服務器,然后將新的主服務器替換已經下線的主服務器繼續處理命令請求。

1、啟動并初始化sentinel

啟動一個Sentinel可以使用如下命令:

redis-sentinel /path/your/sentinel.conf
redis-server /path/your/sentinel.conf --sentinel

啟動一個sentinel服務器,需要執行如下步驟:

  1. 初始化服務器
  2. 將普通的Redis服務器使用的代碼代替為Sentinel專用代碼
  3. 初始化Sentinel狀態
  4. 根據給定的配置文件,初始化Sentinel的監視主服務器列表
  5. 創建與主服務器的網絡連接

1.1 初始化服務器

因為Sentinel哨兵實例本質上就是一個運行在特殊模式下的Redis服務器,所以這一步初始化服務器就是初始化一個redis實例,參考Redis設計與實現-底層實現。
但是畢竟兩者工作的方式不一樣,所以初始化過程還是有所不一樣,例如哨兵初始化是不需要RDB文件或者AOF文件還原數據庫。

1.2 使用Sentinel代碼

將普通redis使用的代碼替換為sentinel哨兵使用的代碼。例如,redis的服務端端口號為6379,哨兵使用26379.

define REDIS_SERVERPORT 6379
define REDIS_SENTINEL_PORT 26379

哨兵的命令表也和redis服務器的不同,哨兵對客戶端提供的命令PING、SENTINEL、INFO、SUBSCRIBE、UNSUBSCRIBE、PSUBSCRIBE和PUNSUBSCRIBE,不對外提供set get等redis的基礎命令。

1.3 初始化sentinel狀態

接下來會初始化哨兵的狀態sentinelState結構,SentinelState 是 Redis Sentinel 內部用來表示全局狀態的數據結構。它包含了所有監控的主節點、從節點、哨兵實例以及配置信息。

typedef struct sentinelState {uint64_t current_epoch;       // 當前的紀元(epoch),用于故障轉移選舉dict *masters;                // 主節點字典,key 為被監控主節點名稱,value 為 sentinelRedisInstanceint tilt;                     // 是否處于傾斜模式(Tilt Mode)int running_scripts;          // 當前正在運行的腳本數量mstime_t tilt_start_time;     // 傾斜模式開始的時間mstime_t previous_time;       // 上一次時間戳,用于檢測時間跳躍list *scripts_queue;          // 腳本隊列,用于執行用戶定義的腳本
} sentinelState;

1.4 初始化sentinel狀態的master屬性

sentinel狀態會保存所有監控的主服務器的信息master,而這個master的key就是主服務器的名字,value就是sentinelRedisInstance。這一步就是初始化master字典。為什么只保存主服務器信息?因為從服務器是動態的,sentinel會通過主服務器進行獲取。

typedef struct sentinelRedisInstance {int flags;                    // 實例標志位(如主節點、從節點、哨兵等)char *name;                   // 實例名稱(僅主節點有名稱)redisAsyncContext *cc;        // 與該實例的命令連接redisAsyncContext *pc;        // 與該實例的發布/訂閱連接mstime_t last_pub_time;       // 上一次發送 PUBLISH 消息的時間mstime_t last_hello_time;     // 上一次收到 HELLO 消息的時間mstime_t last_master_down_time; // 上一次檢測到主節點下線的時間mstime_t down_after_period;   // 判定實例下線的時間閾值mstime_t info_refresh;        // INFO 命令刷新的時間間隔dict *renamed_commands;       // 重命名的 Redis 命令映射int parallel_syncs;           // 故障轉移后允許同時同步的從節點數量int quorum;                   // 判定主節點不可用所需的最小哨兵數量list *sentinels;              // 監控該主節點的所有哨兵實例list *slaves;                 // 主節點的所有從節點struct sentinelRedisInstance *master; // 如果是從節點,指向其主節點...
} sentinelRedisInstance;

1.5 創建連向主服務器的網絡連接

哨兵sentinel會向主服務器建立網絡連接,針對于一個主服務器需要建立兩個網絡連接:

  • 用于命令回復的網絡連接,主要用來向主服務器發送命令請求,接受命令回復
  • 用于訂閱功能的網絡連接,用來訂閱主服務器的_sentinel_:hello頻道

2、獲取主服務器信息

sentinel哨兵會每10秒向監控的主服務器發送INFO命令,并通過主服務器返回的INFO命令回復進行分析更新相應主服務器的sentinelRedisInstance。INFO命令主服務器返回的結果如下:

# server部分
redis_version:6.2.6                  # Redis 版本號
redis_mode:standalone                # Redis 模式 (standalone 或 cluster)
os:Linux 5.4.0-42-generic x86_64     # 操作系統信息
arch_bits:64                         # 架構位數 (3264)
process_id:12345                     # Redis 進程 ID
run_id:abcdef1234567890abcdef1234567890abcdef1234567890abcdef12 # 運行 ID
tcp_port:6379                        # Redis 服務端口
uptime_in_seconds:123456             # Redis 運行時間(秒)
uptime_in_days:1                     # Redis 運行時間(天)
hz:10                                # Redis 內部定時器頻率# client部分
connected_clients:10                 # 當前連接的客戶端數量
client_recent_max_input_buffer:2     # 最大輸入緩沖區大小
client_recent_max_output_buffer:0    # 最大輸出緩沖區大小
blocked_clients:0                    # 被阻塞的客戶端數量# replication部分
role:master                          # 角色:主節點
connected_slaves:2                   # 已連接的從節點數量
slave0:ip=192.168.1.2,port=6379,state=online,offset=12345678,lag=0
slave1:ip=192.168.1.3,port=6379,state=online,offset=12345678,lag=1
master_replid:abcdef1234567890abcdef1234567890abcdef1234567890abcdef12
master_replid2:00000000000000000000000000000000000000000000000000000000
master_repl_offset:12345678          # 主節點的復制偏移量
second_repl_offset:-1                # 第二個復制 ID 的偏移量
repl_backlog_active:1                # 是否啟用了復制積壓緩沖區
repl_backlog_size:1048576            # 復制積壓緩沖區大小
repl_backlog_first_byte_offset:12345 # 積壓緩沖區的第一個字節偏移量
repl_backlog_histlen:12345           # 積壓緩沖區的歷史長度....

通過分析上述命令回復會更新對應主服務器的sentinelRedisInstance,這個命令回復也會返回從服務器的信息。如果有新增的從服務器就會為從服務器創建新的sentinelRedisInstance,添加到主服務的sentinelRedisInstance.slaves屬性中。

3、獲取從服務器的信息

當有新的從服務器出現的時候,sentinel會在該主服務下的slaves中添加一個sentinelRedisInstance實例,并且和從服務器創建命令連接和訂閱連接。
命令創建完成之后,sentinel默認10秒通過命令連接向從服務器發一次info命令,并且返回:

# Replication
role:slave                   # 角色為從節點
master_host:127.0.0.1        # 主節點IP
master_port:6379             # 主節點端口
master_link_status:up        # 與主節點的連接狀態(up/down)
master_last_io_seconds_ago:1 # 上次與主節點通信的秒數(反映復制延遲)
master_sync_in_progress:0    # 是否正在全量同步(0=否,1=是)
slave_repl_offset:123456     # 當前復制偏移量(用于評估數據同步進度)
slave_priority:100           # 從節點優先級(故障轉移時影響選舉)
slave_read_only:1            # 是否只讀模式(默認1# Server
redis_version:6.2.6         # Redis版本
os:Linux 5.4.0-80-generic   # 運行的操作系統
uptime_in_seconds:86400     # 運行時間(秒)
# Clients
connected_clients:3         # 當前客戶端連接數

根據從服務器返回的數據,更新sentinelRedisInstance實例。

4、向主從服務器發送信息

sentinel每兩秒就會通過訂閱連接向主從服務器發送信息。當 Sentinel 在 sentinel:hello 頻道上發布消息時,消息內容通常包含以下信息:

publish __sentinel__:hello <sentinel-ip>,<sentinel-port>,<runid>,<current_epoch>,<master-name>,<master-ip>,<master-port>,<master-config-epoch>
  • sentinel-ip 和 sentinel-port:當前 Sentinel 的地址。
  • runid:當前 Sentinel 的運行 ID。
  • current_epoch:當前的配置紀元(用于協調故障轉移)。
  • master-name:被監控的主節點名稱。
  • master-ip 和 master-port:主節點的地址。
  • master-config-epoch:主節點的配置紀元。

5、接受主從服務器的頻道信息

有關頻道的訂閱關系,針對于一個主從服務Redis集群會分配單獨的訂閱頻道,即不同redis主服務器之間的頻道是相互獨立的。針對于同一個頻道,不僅所有的哨兵和redis主從服務器都訂閱這個頻道,而且他們也都可以向這個頻道發布消息。
所以通過這個頻道 redis服務器可以向監聽自己的所有sentinel發送消息。
在這里插入圖片描述
通過上圖可以知道,一個哨兵sentinel發送消息之后除了redis服務器可以接收到數據之外,其他監聽這個redis主服務的sentinel也會收到消息。
一個sentinel發送消息之后,sentinel的處理:

  • 如果發現接收到的sentinel runId和自己的一樣,說明是自己發送的,則丟棄
  • 如果發現不一樣,則根據發送的消息解析出sentinel和主服務器的信息。通過主服務器的信息在自己的sentinelServer的master字典中找到這個主服務器的sentinelRedisInstance實例,然后查看該實例下sentinels【監聽這個主服務器的其他sentinel】是否存在。如果存在則更新數據;否則創建實例,并且與這個sentinel彼此創建命令連接。

sentinel和redis服務器的命令連接和訂閱關系。【本圖沒有畫各個sentinel與redis服務器的命令連接】(sentinel之間只有命令連接,沒有訂閱)
在這里插入圖片描述

6、檢測主觀下線狀態

默認情況下,sentinel會每秒都會向與其建立命令連接的所有實例【主服務器、從服務器以及與其相連的sentinel】發送ping命令,并根據實例返回的命令回復是否有限【有效回復+PONG、- LOADING、- MASTERDOWN】進行判斷是否在線。

sentinel會根據配置文件中down-after-milliseconds參數判斷該實例是否為主觀下線。即一個實例連續down-after-milliseconds毫秒內一直無效回復,則標記為主觀下線,在該實例的sentinelRedisInstance的flags屬性設置為sri_s_down標識。

注意每個sentinel配置文件中的down-after-milliseconds值可能不同,有的可能為1000,有的可能為5000。所以,一個實例下線并不一定所有的sentinel都同時認為下線。

當一個 Sentinel 實例判斷另一個 Sentinel 實例為主觀下線后,它會執行以下操作:

  • 記錄主觀下線狀態:當前 Sentinel 會將目標 Sentinel 標記為 主觀下線,并記錄其狀態。
    這一狀態僅存在于當前 Sentinel 的視角中,并不會立即影響系統的整體行為。
  • 通知其他 Sentinel 實例:通知其他 Sentinel 實例自己對目標 Sentinel 的判斷結果。其他 Sentinel 實例可以接收到這些消息,但它們會根據自己的健康檢查結果獨立判斷目標 Sentinel 是否也處于主觀下線狀態。
  • 不觸發客觀下線

7、檢查客觀下線狀態

當sentinel判斷一個主服務器為主觀下線之后,為了進一步判斷是否真的下線,會問其他sentinel哨兵是否下線。當超過quorum個sentinel認為該主服務器下線,則就會將這個redis主服務器標記為客觀下線。【從服務器不需要進行判斷客觀下線,影響比較小】

SENTINEL IS-MASTER-DOWN-BY-ADDR 是 Redis Sentinel 提供的一個命令,用于檢查某個主節點是否被標記為下線(主觀下線或客觀下線),并參與領導者選舉的協商過程。sentinel通過命令連接進行發送的,不是通過hello頻道發送的。

SENTINEL IS-MASTER-DOWN-BY-ADDR命令:

SENTINEL IS-MASTER-DOWN-BY-ADDR <master-ip> <master-port> <current-epoch> <runid>

參數說明:

  • master-ip和 master-port:指定要檢查的主節點的 IP 地址和端口號。
  • current-epoch:當前的配置紀元(configuration epoch)。配置紀元是一個遞增的數字,用于協調多個 Sentinel 實例之間的狀態變更和領導者選舉。
  • runid:如果該參數為 *,表示當前 Sentinel 只是詢問其他 Sentinel 是否認為主節點已下線。
    如果該參數為具體的運行 ID(如當前 Sentinel 的 runid),表示當前 Sentinel 希望競選成為領導者。

目標 Sentinel 返回包含三個參數的響應:

  • down_state:
    • 1 表示目標 Sentinel 認為主節點已下線;
    • 0 表示認為主節點在線。
  • leader_runid:
    • 若為 *,表示回復僅用于主節點狀態檢測;
    • 若為具體 runid,表示目標 Sentinel 同意該 runid 對應的 Sentinel 成為故障轉移的領導者。
  • leader_epoch: 目標 Sentinel 的局部領頭配置紀元(僅當 leader_runid 不為 * 時有效)

sentinel會根據該命令的回復判斷,是否超過quorum個sentinel回復了一下線。客觀下線則會將該redis主服務器實例的sentinelRedisInstance的flags屬性設置為sri_o_down標識。

同樣,不同的sentinel可能配置文件不一樣,從而會出現quorum大小不一樣,可能出現有的sentinel認為主服務器已經下線,有的認為沒有客觀下線。

8、選擇領頭的sentinel

只要判斷主機已經客觀下線之后,監聽這個主機的各個sentinel進行協商,選擇一個領頭的sentinel,由這個領頭的sentinel負責故障轉移。

  • 源哨兵期望成為領頭的sentinel,所以源sentinel向目標sentinel發送sentinel is-master-down-by-addr命令,并且runid為源sentinel的runid。
  • 目標sentinel會根據先到先得,如果沒有在這個記元投遞給其他sentinel,就會投遞給這個sentinel,回復的leader_runid和leader_epoch分別為源sentinel的runid和目標sentinel的epoch。否則就會拒絕
  • 源sentinel接收到命令回復之后,會判斷epoch和自己的epoch是否一樣以及回復的runid是否等于自己的epoch。
  • 如果某個sentinel超過半數以上,則會成為領頭sentinel執行故障轉移。如果都沒有滿足這一條件的,則過一段時間再進行選舉。每次選舉epoch都會加1,無論是否成功。

9、故障轉移

在選擇了領頭sentinel之后,由領頭sentinel負責故障轉移。進行故障轉移主要步驟為:從那些可用的從服務器中選擇主服務器、將其他從服務器復制新的主服務器、將已經下線的主服務器也作為新主服務器的從服務器。

9.1 選擇新主服務器

領頭sentinel從所有從服務器中選擇狀態良好、數據完整的從服務器作為新主服務器,并向這個從服務器發送slave no one命令,將這服務器設置為主服務器。選擇主服務的步驟大致如下:

  1. 從所有的從服務器中刪除處于下線的服務器
  2. 從所有的從服務器中刪除5秒內沒有回復info命令的服務器
  3. 然后從剩余的從服務器根據【 優先級 > 復制偏移量大 > 運行runId最小】的原則選擇作為從服務器作為主服務器
    在這里插入圖片描述
    在這里插入圖片描述

9.2 修改從服務器復制目標

將其他從服務器復制新的主服務器,領頭sentinel會向其他的從服務器發送slave <新主服務器ip> <新主服務器port>。
在這里插入圖片描述

9.3 將舊的主服務器轉換為從服務器

接下來就是將舊的主服務器轉換為從服務器,當舊的主服務器重新啟動之后,sentinel會向它發送slave <新主服務器ip> <新主服務器port>命令。
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/76057.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/76057.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/76057.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

藍橋杯省模擬賽 字符串拼接

問題描述 給定四個字符串 a,b,c,d&#xff0c;請將這四個字符串按照任意順序依次連接拼成一個字符串。 請問拼成的字符串字典序最小是多少&#xff1f; 輸入格式 輸入四行&#xff0c;每行包含一個字符串。 輸出格式 輸出一行包含一個字符串&#xff0c;表示答案。 樣例…

【大前端系列20】JavaScript核心:項目實戰從零構建任務管理系統

JavaScript核心&#xff1a;項目實戰從零構建任務管理系統 系列: 「全棧進化&#xff1a;大前端開發完全指南」系列第20篇 核心: 將JavaScript異步編程、事件循環等核心知識應用于實際項目開發 &#x1f4cc; 引言 在前面的文章中&#xff0c;我們深入探討了JavaScript中的異步…

STM32單片機的桌面寵物機器人(基于HAL庫)

效果 基于STM32單片機的桌面寵物機器人 概要 語音模塊&#xff1a;ASR PRO&#xff0c;通過天問block軟件燒錄語音指令 主控芯片&#xff1a;STM32F103C8T6 使用HAL庫 屏幕&#xff1a;0.96寸OLED屏&#xff0c;用來顯示表情 4個舵機&#xff0c;用來當作四只腿 底部一個面…

計算機視覺初步(環境搭建)

1.anaconda 建議安裝在D盤&#xff0c;官網正常安裝即可&#xff0c;一般可以安裝windows版本 安裝成功后&#xff0c;可以在電腦應用里找到&#xff1a; 2.創建虛擬環境 打開anaconda prompt&#xff0c; 可以用conda env list 查看現有的環境&#xff0c;一般打開默認bas…

SQL Server數據庫引擎服務啟動失敗:端口沖突

問題現象&#xff1a; SQL Server 2022 安裝完成后&#xff0c;數據庫引擎服務無法啟動&#xff0c;日志報錯 “TCP 端口 1433 已被占用”&#xff08;ERROR_LOG_SYS_TCP_PORT&#xff09;。 快速診斷 檢測端口占用&#xff1a; # 查看 1433 端口占用情況&#xff08;需管理員權…

全局思維與系統思考

最近接到一些需求&#xff0c;1號位希望每個層級的領導者有眼界&#xff0c;胸懷&#xff0c;格局&#xff0c;全局觀&#xff0c;這些聽起來似乎很抽象&#xff0c;然而它們是每個人、每個團隊成長與成功的核心競爭力。那么&#xff0c;如何才能提升這些能力&#xff1f;就像我…

區間有關的貪心解題記錄435無重疊區間452用最少數量的箭引爆氣球

無重疊區間我的想法是開一個數組a&#xff0c;遍歷給出的區間&#xff0c;在數組a里將對應落在的區間index標記。如果有重復區間就只選擇最小的那個區間標記。但是這道題的區間好像很長-5 * 104 < starti < endi < 5 * 104沒法用數組a表示總的區間范圍。 核心思路是當…

天銳藍盾終端安全防護——企業終端設備安全管控

從辦公室的臺式電腦到員工手中的移動終端&#xff0c;這些設備不僅是工作的得力助手&#xff0c;更是企業數據的重要載體。然而&#xff0c;隨著終端設備的廣泛使用&#xff0c;安全風險也如影隨形。硬件設備使用不當、數據隨意傳輸等問題頻發&#xff0c;使得企業數據面臨著泄…

k8s網絡策略

k8s網絡策略 k8s網絡測試概述查看防火墻策略 k8s網絡策略網絡訪問控制案例&#xff1a;配置k8s網絡策略結果驗證 k8s網絡策略配置示例 k8s網絡測試概述 網絡策略就是設置防火墻 查看防火墻策略 # 獲取當前命名空間下的所有 NetworkPolicy 資源&#xff08;網絡策略&#xff0…

leetcode刷題日記——跳躍游戲 II

[ 題目描述 ]&#xff1a; [ 思路 ]&#xff1a; 題目要求在一個一定能達到數組末尾的跳躍數組中(見55題 跳躍游戲)&#xff0c;找出能夠跳到末尾的最小次數要求次數最少&#xff0c;那肯定是選取能選步數中最大的數。也就是在當前能夠達到的距離中&#xff0c;選擇能夠達到的…

【Java SE】Java比較器:Comparable、Comparator

目錄 1.前言 2.Comaprable接口 2.1 使用細節 2.2 案例演示 3.Comparator接口 3.1 為什么需要Comparator接口 3.2 使用細節 3.3 案例演示 4.Comparable、Comparator對比 1.前言 Java 中的對象&#xff0c;正常情況下&#xff0c;只能進行比較&#xff1a; 或 ! 。不…

(二)創建實例

在這節中&#xff0c; 創建一個實例初始化Vulkan庫,指定驅動程序需要使用的應用程序信息 1&#xff0c;要有個實例句柄 VkInstance instance; 2&#xff0c;設置創建Vulkan驅動程序需要的信息&#xff0c; VkInstanceCreateInfo createInfo {}; createInfo.sType VK_STRUCTUR…

HCIP之VRRP

1. VRRP是什么 VRRP&#xff08;Virtual Router Redundancy Protocol&#xff0c;虛擬路由冗余協議&#xff09;是一種用于提高網絡可靠性的容錯協議。它通過將多臺路由器虛擬成一臺虛擬路由器&#xff0c;實現網關的冗余備份。當主路由器&#xff08;Master&#xff09;出現故…

高效內存管理:x86-64架構中的分頁機制

在 x86-64 架構的世界里&#xff0c;內存分頁機制扮演著舉足輕重的角色&#xff0c;它就像是一座橋梁&#xff0c;連接著虛擬地址與物理地址。簡單來說&#xff0c;內存分頁機制就是將線性地址&#xff08;也就是虛擬地址&#xff09;切分成一個個固定大小的頁&#xff0c;并把…

【軟件工程】填空題

真題 2024-10 16.數據字典是用來定義_____中各個成分的具體含義的。 17.模塊設計的基本原則是_____。 18.接口是操作的一個集合,其中每個操作描述了類、構件或子系統的一個_____。 19.耦合是指不同模塊之間_____的度量。 20.RUP的突出特點是,它是一種以用況為驅動的、…

第二卷:海鹽城血戰(37-72回)正反人物群像

第二卷&#xff1a;海鹽城血戰&#xff08;37-72回&#xff09;正反人物群像 核心矛盾&#xff1a;寒門軍事崛起 → 內部傾軋 → 制度性腐敗 主題&#xff1a;通過人物群像展現寒門勝利的虛幻性與權力異化的必然性 一、正派陣營&#xff08;寒門抗爭勢力&#xff09; 1. 劉裕…

23_js面向對象

上次我們講運動函數&#xff0c;實際開發不會寫運動函數。只是講一下思想。 現在講一下用原生js去實現輪播圖&#xff0c;引入到對象 首先&#xff0c;要明確 面向對象不是語法&#xff0c;是一個思想&#xff0c;是一種編程模式 面向&#xff1a;朝向 面向對象&#xff1a…

torch不能使用cuda的解決方案

遇到了這樣的報錯&#xff0c;說明 torch不能使用cuda 反思 我頻繁地嘗試安裝不同的 nvdia 驅動&#xff0c;浪費了很多時間。因為我的錯誤地認為nvidia會自帶cuda&#xff0c;其實cuda需要單獨安裝。 還有我的torch是cpu版本的&#xff0c;即使nvidia cuda安裝了&#xff0…

kettle從入門到精通 第九十三課 ETL之kettle kettle 調用web service接口5種方法,一文徹底搞懂

場景&#xff1a;群里有小伙伴向我求助如何調用web service接口&#xff0c;趁著周末時間&#xff0c;給兄弟們搞demo。 1、本次使用的web service服務接口地址是http://ws.webxml.com.cn/WebServices/WeatherWS.asmx?opgetSupportCityDataset&#xff0c; 此接口根據用戶輸入…

藍橋杯 14 天 十五屆藍橋杯 數字詩意

static boolean kkk(long x) {if(x1)return true;else {// 初始化xx為1&#xff0c;用于計算2的冪long xx 1;// 循環60次&#xff0c;檢查2的冪是否等于xfor (int i 1; i < 60; i) {xx * 2; // 每次將xx乘以2if (xx x) { // 如果xx等于x&#xff0c;說明x是2的冪&#xf…