為緩解熱點Key帶來大量讀請求的影響,您可以啟用讀寫分離功能並增加唯讀節點,系統能夠將讀請求分散至各個節點。這將降低主節點的壓力,並提升系統的整體輸送量和穩定性。
功能概述
讀寫分離架構的所有隻讀節點通過非同步複製主節點的資料(最終一致性),整體資料同步延遲低。這意味著在部分寫入量較大的情況下,可能會發生資料同步延遲,此時應用程式能夠容忍稍舊的資料。例如下述情境:
快取資料:網址首頁的HTML緩衝等,更新頻率低。
遊戲熱門排行榜:小時層級熱門排行榜,其輕微的更新延遲對使用者影響並不顯著。
天氣預報資料:使用者頻繁查詢天氣,資料則按照預定時間進行更新。
增加唯讀節點的直接作用
分擔主節點負載:主節點僅負責100%寫請求、1/N的讀請求(N為總節點數,例如1個主節點、3個唯讀節點,即N為4)。這降低了主節點的CPU壓力、網路壓力,以及串連開銷。
提高系統輸送量:每個唯讀節點可獨立處理讀請求,整體讀效能呈線性擴充。在理想情況下,增加N個唯讀節點可提升N倍讀效能。
降低響應延遲:將讀請求分散到多個節點後,可減少單個請求的排隊等待時間。
不僅支援為標準(主從)架構開啟讀寫分離,也支援為叢集架構開啟讀寫分離,可為叢集的每個資料分區節點增加對應的唯讀節點,具體架構資訊請參見讀寫分離功能。
如何開啟
前提條件:
部署模式為雲原生。
執行個體為Redis開源版或Tair(企業版)記憶體型、持久記憶體型。
執行個體規格為1 GB及以上。
執行個體類型為高可用。
開啟方法:在執行個體詳情頁中,單擊左側導覽列的節點管理,並開啟讀寫分離開關。具體操作請參見開啟讀寫分離。
用戶端串連
單可用性區域執行個體
通常情況下,讀寫分離架構執行個體仍提供一個串連地址,執行個體將通過Proxy組件實現路由分發。您無需修改代碼,開箱即用,更多資訊請參見用戶端程式串連教程。
雙可用性區域執行個體
在雙可用性區域、讀寫分離架構執行個體,執行個體將分別提供主、備可用性區域串連地址。其中備可用性區域串連地址僅用於讀請求,可實現就近訪問,縮短讀請求延遲。
例如執行個體為杭州I(主可用性區域)、杭州J(備可用性區域)。
位於杭州I的用戶端(ECS執行個體)可以串連執行個體的主可用性區域地址,並執行讀寫操作。代碼如下:
import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class MasterReadWrite { public static void main(String[] args) { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxIdle(200); config.setMaxTotal(300); config.setTestOnBorrow(false); config.setTestOnReturn(false); // 配置主可用性區域串連地址、連接埠、帳號密碼資訊。 String host = "r-bp1vtq8tnrquy****pd.redis.rds.aliyuncs.com"; int port = 6379; String password = "default:Passw***2"; JedisPool pool = new JedisPool(config, host, port, 3000, password); Jedis jedis = null; try { jedis = pool.getResource(); // 執行相關操作,樣本如下。 jedis.set("foo", "bar"); System.out.println(jedis.get("foo")); } catch (Exception e) { // 逾時或其他異常處理。 e.printStackTrace(); } finally { if (jedis != null) { jedis.close(); } } pool.destroy(); // 當應用退出,需銷毀資源時,調用此方法。此方法會中斷連線、釋放資源。 } }位於杭州J的用戶端(ECS執行個體)可以串連執行個體的備可用性區域地址,並僅執行讀操作(如需執行寫操作,仍需串連主可用性區域地址)。代碼如下:
import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class ReplicaRead { public static void main(String[] args) { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxIdle(200); config.setMaxTotal(300); config.setTestOnBorrow(false); config.setTestOnReturn(false); // 配置備可用性區域串連地址、連接埠、帳號密碼資訊。 String host = "r-bp1vtq8tnrquy****pd.redis.rds.aliyuncs.com"; int port = 6379; String password = "default:Passw***2"; JedisPool pool = new JedisPool(config, host, port, 3000, password); Jedis jedis = null; try { jedis = pool.getResource(); // 執行相關操作,樣本如下。 System.out.println(jedis.get("foo")); } catch (JedisDataException e) { // 捕獲寫操作異常(如果誤操作執行了寫操作)。 e.getMessage(); } catch (Exception e) { // 逾時或其他異常處理。 e.printStackTrace(); } finally { if (jedis != null) { jedis.close(); } } pool.destroy(); // 當應用退出,需銷毀資源時,調用此方法。此方法會中斷連線、釋放資源。 } }