mirror of
https://github.com/zhwei820/learn.lianglianglee.com.git
synced 2025-09-17 08:46:40 +08:00
1069 lines
34 KiB
HTML
1069 lines
34 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
|
||
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
|
||
<head>
|
||
|
||
<head>
|
||
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
|
||
|
||
<link rel="icon" href="/static/favicon.png">
|
||
|
||
<title>11 编排治理:如何实现分布式环境下的动态配置管理?.md.html</title>
|
||
|
||
<!-- Spectre.css framework -->
|
||
|
||
<link rel="stylesheet" href="/static/index.css">
|
||
|
||
<!-- theme css & js -->
|
||
|
||
<meta name="generator" content="Hexo 4.2.0">
|
||
|
||
</head>
|
||
|
||
|
||
|
||
<body>
|
||
|
||
|
||
|
||
<div class="book-container">
|
||
|
||
<div class="book-sidebar">
|
||
|
||
<div class="book-brand">
|
||
|
||
<a href="/">
|
||
|
||
<img src="/static/favicon.png">
|
||
|
||
<span>技术文章摘抄</span>
|
||
|
||
</a>
|
||
|
||
</div>
|
||
|
||
<div class="book-menu uncollapsible">
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li><a href="/" class="current-tab">首页</a></li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li><a href="../">上一级</a></li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/00 如何正确学习一款分库分表开源框架?.md.html">00 如何正确学习一款分库分表开源框架?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/01 从理论到实践:如何让分库分表真正落地?.md.html">01 从理论到实践:如何让分库分表真正落地?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/02 顶级项目:ShardingSphere 是一款什么样的 Apache 开源软件?.md.html">02 顶级项目:ShardingSphere 是一款什么样的 Apache 开源软件?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/03 规范兼容:JDBC 规范与 ShardingSphere 是什么关系?.md.html">03 规范兼容:JDBC 规范与 ShardingSphere 是什么关系?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/04 应用集成:在业务系统中使用 ShardingSphere 的方式有哪些?.md.html">04 应用集成:在业务系统中使用 ShardingSphere 的方式有哪些?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/05 配置驱动:ShardingSphere 中的配置体系是如何设计的?.md.html">05 配置驱动:ShardingSphere 中的配置体系是如何设计的?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/06 数据分片:如何实现分库、分表、分库+分表以及强制路由?(上).md.html">06 数据分片:如何实现分库、分表、分库+分表以及强制路由?(上).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/07 数据分片:如何实现分库、分表、分库+分表以及强制路由?(下).md.html">07 数据分片:如何实现分库、分表、分库+分表以及强制路由?(下).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/08 读写分离:如何集成分库分表+数据库主从架构?.md.html">08 读写分离:如何集成分库分表+数据库主从架构?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/09 分布式事务:如何使用强一致性事务与柔性事务?.md.html">09 分布式事务:如何使用强一致性事务与柔性事务?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/10 数据脱敏:如何确保敏感数据的安全访问?.md.html">10 数据脱敏:如何确保敏感数据的安全访问?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
<a class="current-tab" href="/专栏/ShardingSphere 核心原理精讲-完/11 编排治理:如何实现分布式环境下的动态配置管理?.md.html">11 编排治理:如何实现分布式环境下的动态配置管理?.md.html</a>
|
||
|
||
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/12 从应用到原理:如何高效阅读 ShardingSphere 源码?.md.html">12 从应用到原理:如何高效阅读 ShardingSphere 源码?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/13 微内核架构:ShardingSphere 如何实现系统的扩展性?.md.html">13 微内核架构:ShardingSphere 如何实现系统的扩展性?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/14 分布式主键:ShardingSphere 中有哪些分布式主键实现方式?.md.html">14 分布式主键:ShardingSphere 中有哪些分布式主键实现方式?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/15 解析引擎:SQL 解析流程应该包括哪些核心阶段?(上).md.html">15 解析引擎:SQL 解析流程应该包括哪些核心阶段?(上).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/16 解析引擎:SQL 解析流程应该包括哪些核心阶段?(下).md.html">16 解析引擎:SQL 解析流程应该包括哪些核心阶段?(下).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/17 路由引擎:如何理解分片路由核心类 ShardingRouter 的运作机制?.md.html">17 路由引擎:如何理解分片路由核心类 ShardingRouter 的运作机制?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/18 路由引擎:如何实现数据访问的分片路由和广播路由?.md.html">18 路由引擎:如何实现数据访问的分片路由和广播路由?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/19 路由引擎:如何在路由过程中集成多种路由策略和路由算法?.md.html">19 路由引擎:如何在路由过程中集成多种路由策略和路由算法?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/20 改写引擎:如何理解装饰器模式下的 SQL 改写实现机制?.md.html">20 改写引擎:如何理解装饰器模式下的 SQL 改写实现机制?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/21 执行引擎:分片环境下 SQL 执行的整体流程应该如何进行抽象?.md.html">21 执行引擎:分片环境下 SQL 执行的整体流程应该如何进行抽象?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/22 执行引擎:如何把握 ShardingSphere 中的 Executor 执行模型?(上).md.html">22 执行引擎:如何把握 ShardingSphere 中的 Executor 执行模型?(上).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/23 执行引擎:如何把握 ShardingSphere 中的 Executor 执行模型?(下).md.html">23 执行引擎:如何把握 ShardingSphere 中的 Executor 执行模型?(下).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/24 归并引擎:如何理解数据归并的类型以及简单归并策略的实现过程?.md.html">24 归并引擎:如何理解数据归并的类型以及简单归并策略的实现过程?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/25 归并引擎:如何理解流式归并和内存归并在复杂归并场景下的应用方式?.md.html">25 归并引擎:如何理解流式归并和内存归并在复杂归并场景下的应用方式?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/26 读写分离:普通主从架构和分片主从架构分别是如何实现的?.md.html">26 读写分离:普通主从架构和分片主从架构分别是如何实现的?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/27 分布式事务:如何理解 ShardingSphere 中对分布式事务的抽象过程?.md.html">27 分布式事务:如何理解 ShardingSphere 中对分布式事务的抽象过程?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/28 分布式事务:ShardingSphere 中如何集成强一致性事务和柔性事务支持?(上).md.html">28 分布式事务:ShardingSphere 中如何集成强一致性事务和柔性事务支持?(上).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/29 分布式事务:ShardingSphere 中如何集成强一致性事务和柔性事务支持?(下).md.html">29 分布式事务:ShardingSphere 中如何集成强一致性事务和柔性事务支持?(下).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/30 数据脱敏:如何基于改写引擎实现低侵入性数据脱敏方案?.md.html">30 数据脱敏:如何基于改写引擎实现低侵入性数据脱敏方案?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/31 配置中心:如何基于配置中心实现配置信息的动态化管理?.md.html">31 配置中心:如何基于配置中心实现配置信息的动态化管理?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/32 注册中心:如何基于注册中心实现数据库访问熔断机制?.md.html">32 注册中心:如何基于注册中心实现数据库访问熔断机制?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/33 链路跟踪:如何基于 Hook 机制以及 OpenTracing 协议实现数据访问链路跟踪?.md.html">33 链路跟踪:如何基于 Hook 机制以及 OpenTracing 协议实现数据访问链路跟踪?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/34 系统集成:如何完成 ShardingSphere 内核与 Spring+SpringBoot 的无缝整合?.md.html">34 系统集成:如何完成 ShardingSphere 内核与 Spring+SpringBoot 的无缝整合?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/35 结语:ShardingSphere 总结及展望.md.html">35 结语:ShardingSphere 总结及展望.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
|
||
|
||
<div class="sidebar-toggle-inner"></div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<script>
|
||
|
||
function add_inner() {
|
||
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
|
||
inner.classList.add('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
function remove_inner() {
|
||
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
|
||
inner.classList.remove('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
function sidebar_toggle() {
|
||
|
||
let sidebar_toggle = document.querySelector('.sidebar-toggle')
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let content = document.querySelector('.off-canvas-content')
|
||
|
||
if (sidebar_toggle.classList.contains('extend')) { // show
|
||
|
||
sidebar_toggle.classList.remove('extend')
|
||
|
||
sidebar.classList.remove('hide')
|
||
|
||
content.classList.remove('extend')
|
||
|
||
} else { // hide
|
||
|
||
sidebar_toggle.classList.add('extend')
|
||
|
||
sidebar.classList.add('hide')
|
||
|
||
content.classList.add('extend')
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
function open_sidebar() {
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
|
||
sidebar.classList.add('show')
|
||
|
||
overlay.classList.add('show')
|
||
|
||
}
|
||
|
||
function hide_canvas() {
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
|
||
sidebar.classList.remove('show')
|
||
|
||
overlay.classList.remove('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
</script>
|
||
|
||
|
||
|
||
<div class="off-canvas-content">
|
||
|
||
<div class="columns">
|
||
|
||
<div class="column col-12 col-lg-12">
|
||
|
||
<div class="book-navbar">
|
||
|
||
<!-- For Responsive Layout -->
|
||
|
||
<header class="navbar">
|
||
|
||
<section class="navbar-section">
|
||
|
||
<a onclick="open_sidebar()">
|
||
|
||
<i class="icon icon-menu"></i>
|
||
|
||
</a>
|
||
|
||
</section>
|
||
|
||
</header>
|
||
|
||
</div>
|
||
|
||
<div class="book-content" style="max-width: 960px; margin: 0 auto;
|
||
|
||
overflow-x: auto;
|
||
|
||
overflow-y: hidden;">
|
||
|
||
<div class="book-post">
|
||
|
||
<p id="tip" align="center"></p>
|
||
|
||
<div><h1>11 编排治理:如何实现分布式环境下的动态配置管理?</h1>
|
||
|
||
<p>随着分布式系统和微服务架构的持续发展,对系统中存在的各种服务和资源进行统一治理已经成为系统架构设计过程中的一个基础要点。ShardingSphere 作为一款分布式数据库中间件,同样集成了编制治理方面的功能。</p>
|
||
|
||
<p>今天的内容围绕如何使用 ShardingSphere 所提供的编排治理功能进行展开,课时思路与上一课时的风格一致,即先讨论 ShardingSphere 对编排治理的抽象过程,然后给出在开发过程中,基于配置中心介绍集成编排治理功能的系统改造方案。</p>
|
||
|
||
<h3>ShardingSphere 如何抽象编排治理?</h3>
|
||
|
||
<p>ShardingSphere 的编排治理功能非常丰富,与日常开发紧密相关的是它的配置中心和注册中心功能。ShardingSphere 对这两个功能提供了自己的抽象和实现方案。</p>
|
||
|
||
<h4>ShardingSphere 中的配置中心</h4>
|
||
|
||
<p>关于配置信息的管理,常见的做法是把它们存放在配置文件中,我们可以基于 YAML 格式或 XML 格式的配置文件完成配置信息的维护,这在 ShardingSphere 中也都得到了支持。在单块系统中,配置文件能够满足需求,围绕配置文件展开的配置管理工作通常不会有太大挑战。但在分布式系统中,越来越多的运行时实例使得散落的配置难于管理,并且,配置不同步导致的问题十分严重。将配置集中于配置中心,可以更加有效地进行管理。</p>
|
||
|
||
<p><strong>采用配置中心也就意味着采用集中式配置管理的设计思想</strong>。在集中式配置中心内,开发、测试和生产等不同的环境配置信息统一保存在配置中心内,这是一个维度。另一个维度就是需要确保分布式集群中同一类服务的所有服务实例保存同一份配置文件并且能够同步更新。配置中心的示意图如下所示:</p>
|
||
|
||
<p><img src="assets/CgqCHl8VVZeAej3eAABEQzB6x7o265.png" alt="1.png" />
|
||
|
||
集中式配置管理的设计思想</p>
|
||
|
||
<p>在 ShardingSphere 中,提供了多种配置中心的实现方案,包括主流的 ZooKeeeper、Etcd、Apollo 和 Nacos。开发人员也可以根据需要实现自己的配置中心并通过 SPI 机制加载到 ShardingSphere 运行时环境中。</p>
|
||
|
||
<p>另一方面,配置信息不是一成不变的。<strong>对修改后的配置信息的统一分发,是配置中心可以提供的另一个重要能力</strong>。配置中心中配置信息的任何变化都可以实时同步到各个服务实例中。在 ShardingSphere 中,通过配置中心可以支持数据源、数据表、分片以及读写分离策略的动态切换。</p>
|
||
|
||
<p>同时,在集中式配置信息管理方案的基础上,ShardingSphere 也支持从本地加载配置信息的实现方案。如果我们希望以本地的配置信息为准,并将本地配置覆盖配置中心的配置,通过一个开关就可以做到这一点。</p>
|
||
|
||
<h4>ShardingSphere 中的注册中心</h4>
|
||
|
||
<p>在实现方式上,注册中心与配置中心非常类似,ShardingSphere 也提供了基于 ZooKeeeper 和 Etcd 这两款第三方工具的注册中心实现方案,而 ZooKeeeper 和 Etcd 同样也可以被用作配置中心。</p>
|
||
|
||
<p>注册中心与配置中心的不同之处在于两者保存的数据类型。配置中心管理的显然是配置数据,但注册中心存放的是 ShardingSphere 运行时的各种动态/临时状态数据,最典型的运行时状态数据就是当前的 Datasource 实例。那么,保存这些动态和临时状态数据有什么用呢?我们来看一下这张图:</p>
|
||
|
||
<p><img src="assets/Ciqc1F8VVaeARWcwAABcQXkFH-E790.png" alt="2.png" />
|
||
|
||
注册中心的数据存储和监听机制示意图</p>
|
||
|
||
<p>注册中心一般都提供了分布式协调机制。在注册中心中,所有 DataSource 在指定路径根目录下创建临时节点,所有访问这些 DataSource 的业务服务都会监听该目录。当有新 DataSource 加入时,注册中心实时通知到所有业务服务,由业务服务做相应路由信息维护;而当某个 DataSource 宕机时,业务服务通过监听机制同样会收到通知。</p>
|
||
|
||
<p>基于这种机制,我们就可以提供针对 DataSource 的治理能力,包括熔断对某一个 DataSource 的数据访问,或禁用对从库 DataSource 的访问等。</p>
|
||
|
||
<p>在 ShardingSphere 中,注册中心更多地面向框架内部使用,普通场景下不需要过多了解注册中心的使用方法。目前,ShardingSphere 针对注册中心所打造的面向开发人员的功能也还比较有限。因此,今天我们重点关注配置中心的使用方式,关于注册中心的讨论,我们放在源码解析部分进行展开。接下来,我将带领你完成集成配置中心的系统改造工作。</p>
|
||
|
||
<h3>系统改造:如何集成配置中心?</h3>
|
||
|
||
<p>由于配置中心的创建需要依赖第三方工具,所以我们需要先完成开发环境的准备工作。</p>
|
||
|
||
<h4>准备开发环境</h4>
|
||
|
||
<p>为了集成配置中心,第一步需要引入 ShardingSphere 中与编排治理相关的依赖包。在 Spring Boot 环境中,这个依赖包是 sharding-jdbc-orchestration-spring-boot-starter:</p>
|
||
|
||
<pre><code><dependency>
|
||
|
||
<groupId>org.apache.shardingsphere</groupId>
|
||
|
||
<artifactId>sharding-jdbc-orchestration-spring-boot-starter</artifactId>
|
||
|
||
</dependency>
|
||
|
||
</code></pre>
|
||
|
||
<p>在接下来的内容中,我们将演示如何基于 ZooKeeeper 这款分布式协调工具来实现配置中心。而在 ShardingSphere 中,集成的 ZooKeeeper 客户端组件是 Curator,所以也需要引入 sharding-orchestration-reg-zookeeper-curator 组件:</p>
|
||
|
||
<pre><code><dependency>
|
||
|
||
<groupId>org.apache.shardingsphere</groupId>
|
||
|
||
<artifactId>sharding-orchestration-reg-zookeeper-curator</artifactId>
|
||
|
||
</dependency>
|
||
|
||
</code></pre>
|
||
|
||
<p>当然,如果我们使用的是 Nacos,那么也需要添加相关的依赖包:</p>
|
||
|
||
<pre><code><dependency>
|
||
|
||
<groupId>org.apache.shardingsphere</groupId>
|
||
|
||
<artifactId>sharding-orchestration-reg-nacos</artifactId>
|
||
|
||
</dependency>
|
||
|
||
<dependency>
|
||
|
||
<groupId>com.alibaba.nacos</groupId>
|
||
|
||
<artifactId>nacos-client</artifactId>
|
||
|
||
</dependency>
|
||
|
||
</code></pre>
|
||
|
||
<p>配置好这些之后,开发环境已经就绪,对于配置中心而言,开发人员主要的工作还是配置,我们一起来看一下有哪些针对配置中心的配置项。</p>
|
||
|
||
<h4>掌握配置项</h4>
|
||
|
||
<p>针对配置中心,ShardingSphere 提供了一系列的 DataSource,包括用于数据分片的 OrchestrationShardingDataSource、用于读写分离的 OrchestrationMasterSlaveDataSource 以及用于数据脱敏的 OrchestrationEncryptDataSource。围绕这些 DataSource,也存在对应的 DataSourceFactory 工厂类。这里以 OrchestrationMasterSlaveDataSourceFactory 为例来看创建 DataSource 所需要的配置类:</p>
|
||
|
||
<pre><code>public final class OrchestrationMasterSlaveDataSourceFactory {
|
||
|
||
|
||
|
||
public static DataSource createDataSource(final Map<String, DataSource> dataSourceMap, final MasterSlaveRuleConfiguration masterSlaveRuleConfig,
|
||
|
||
final Properties props, final OrchestrationConfiguration orchestrationConfig) throws SQLException {
|
||
|
||
if (null == masterSlaveRuleConfig || null == masterSlaveRuleConfig.getMasterDataSourceName()) {
|
||
|
||
return createDataSource(orchestrationConfig);
|
||
|
||
}
|
||
|
||
MasterSlaveDataSource masterSlaveDataSource = new MasterSlaveDataSource(dataSourceMap, new MasterSlaveRule(masterSlaveRuleConfig), props);
|
||
|
||
return new OrchestrationMasterSlaveDataSource(masterSlaveDataSource, orchestrationConfig);
|
||
|
||
}
|
||
|
||
…
|
||
|
||
}
|
||
|
||
</code></pre>
|
||
|
||
<p>可以看到,这里存在一个治理规则配置类 OrchestrationConfiguration,而在其他的 DataSourceFactory 中所使用的也是这个配置类:</p>
|
||
|
||
<pre><code>public final class OrchestrationConfiguration {
|
||
|
||
//治理规则名称
|
||
|
||
private final String name;
|
||
|
||
//注册(配置)中心配置类
|
||
|
||
private final RegistryCenterConfiguration regCenterConfig;
|
||
|
||
//本地配置是否覆写服务器配置标志位
|
||
|
||
private final boolean overwrite;
|
||
|
||
}
|
||
|
||
</code></pre>
|
||
|
||
<p>在 OrchestrationConfiguration 中我们看到了用于指定本地配置是否覆写服务器配置的 overwrite 标志位,也看到了一个注册中心的配置子类 RegistryCenterConfiguration。RegistryCenterConfiguration 包的含内容比较多,我们截取最常见最通用的部分配置项:</p>
|
||
|
||
<pre><code>public final class RegistryCenterConfiguration extends TypeBasedSPIConfiguration {
|
||
|
||
|
||
|
||
//配置中心服务器列表
|
||
|
||
private String serverLists;
|
||
|
||
//命名空间
|
||
|
||
private String namespace;
|
||
|
||
…
|
||
|
||
}
|
||
|
||
</code></pre>
|
||
|
||
<p>这里包含了配置中心服务器列表 serverLists 以及用于标识唯一性的命名空间 namespace。因为 RegistryCenterConfiguration 继承了 TypeBasedSPIConfiguration,所以也就自动带有 type 和 properties 这两个配置项。</p>
|
||
|
||
<h4>实现配置中心</h4>
|
||
|
||
<p>现在,我们来实现基于 ZooKeeper 的配置中心。首先需要下载 ZooKeeper 服务器组件,并确保启动成功。如果采用默认配置,那么 ZooKeeper 会在 2181 端口启动请求监听。</p>
|
||
|
||
<p>然后创建一个配置文件并输入配置项,由于还是以读写分离为例进行演示,因此,在配置文件中,我们设置了一主两从一共三个数据源,这部分配置项在介绍读写分离机制时已经介绍过,这里不再展开:</p>
|
||
|
||
<pre><code>spring.shardingsphere.datasource.names=dsmaster,dsslave0,dsslave1
|
||
|
||
spring.shardingsphere.datasource.dsmaster.type=com.zaxxer.hikari.HikariDataSource
|
||
|
||
spring.shardingsphere.datasource.dsmaster.driver-class-name=com.mysql.jdbc.Driver
|
||
|
||
spring.shardingsphere.datasource.dsmaster.jdbc-url=jdbc:mysql://localhost:3306/dsmaster
|
||
|
||
spring.shardingsphere.datasource.dsmaster.username=root
|
||
|
||
spring.shardingsphere.datasource.dsmaster.password=root
|
||
|
||
spring.shardingsphere.datasource.dsslave0.type=com.zaxxer.hikari.HikariDataSource
|
||
|
||
spring.shardingsphere.datasource.dsslave0.driver-class-name=com.mysql.jdbc.Driver
|
||
|
||
spring.shardingsphere.datasource.dsslave0.jdbc-url=jdbc:mysql://localhost:3306/dsslave0
|
||
|
||
spring.shardingsphere.datasource.dsslave0.username=root
|
||
|
||
spring.shardingsphere.datasource.dsslave0.password=root
|
||
|
||
spring.shardingsphere.datasource.dsslave1.type=com.zaxxer.hikari.HikariDataSource
|
||
|
||
spring.shardingsphere.datasource.dsslave1.driver-class-name=com.mysql.jdbc.Driver
|
||
|
||
spring.shardingsphere.datasource.dsslave1.jdbc-url=jdbc:mysql://localhost:3306/dsslave1
|
||
|
||
spring.shardingsphere.datasource.dsslave1.username=root
|
||
|
||
spring.shardingsphere.datasource.dsslave1.password=root
|
||
|
||
spring.shardingsphere.masterslave.load-balance-algorithm-type=random
|
||
|
||
spring.shardingsphere.masterslave.name=health_ms
|
||
|
||
spring.shardingsphere.masterslave.master-data-source-name=dsmaster
|
||
|
||
spring.shardingsphere.masterslave.slave-data-source-names=dsslave0,dsslave1
|
||
|
||
spring.shardingsphere.props.sql.show=true
|
||
|
||
</code></pre>
|
||
|
||
<p>接下来指定配置中心,我们将 overwrite 设置为 true,<strong>这意味着前面的这些本地配置项会覆盖保存在 ZooKeeper 服务器上的配置项,也就是说我们采用的是本地配置模式</strong>。然后我们设置配置中心类型为 zookeeper,服务器列表为 localhost:2181,并将命名空间设置为 orchestration-health_ms。</p>
|
||
|
||
<pre><code>spring.shardingsphere.orchestration.name=health_ms
|
||
|
||
spring.shardingsphere.orchestration.overwrite=true
|
||
|
||
spring.shardingsphere.orchestration.registry.type=zookeeper
|
||
|
||
spring.shardingsphere.orchestration.registry.server-lists=localhost:2181
|
||
|
||
spring.shardingsphere.orchestration.registry.namespace=orchestration-health_ms
|
||
|
||
</code></pre>
|
||
|
||
<p>现在,让我们启动服务,控制台会出现与 ZooKeeper 进行通信的相关日志信息:</p>
|
||
|
||
<pre><code>2020-05-30 18:13:45.954 INFO 20272 --- [ main] org.apache.zookeeper.ZooKeeper : Initiating client connection, connectString=localhost:2181 sessionTimeout=60000 <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="04736570676c6176396b76632a657465676c612a67717665706b762a476b6a6a6167706d6b6a577065706144313c3165673c3131">[email protected]</a>
|
||
|
||
2020-05-30 18:13:46.011 INFO 20272 --- [0:0:0:0:1:2181)] org.apache.zookeeper.ClientCnxn : Opening socket connection to server 0:0:0:0:0:0:0:1/0:0:0:0:0:0:0:1:2181. Will not attempt to authenticate using SASL (unknown error)
|
||
|
||
2020-05-30 18:13:46.012 INFO 20272 --- [0:0:0:0:1:2181)] org.apache.zookeeper.ClientCnxn : Socket connection established to 0:0:0:0:0:0:0:1/0:0:0:0:0:0:0:1:2181, initiating session
|
||
|
||
2020-05-30 18:13:46.029 INFO 20272 --- [0:0:0:0:1:2181)] org.apache.zookeeper.ClientCnxn : Session establishment complete on server 0:0:0:0:0:0:0:1/0:0:0:0:0:0:0:1:2181, sessionid = 0x10022dd7e680001, negotiated timeout = 40000
|
||
|
||
2020-05-30 18:13:46.034 INFO 20272 --- [ain-EventThread] o.a.c.f.state.ConnectionStateManager : State change: CONNECTED
|
||
|
||
</code></pre>
|
||
|
||
<pre><code>
|
||
|
||
</code></pre>
|
||
|
||
<p>同时,ZooKeeper 服务器端也对来自应用程序的请求作出响应。我们可以使用一些 ZooKeeper 可视化客户端工具来观察目前服务器上的数据。这里,我使用了 ZooInspector 这款工具,由于 ZooKeeper 本质上就是树状结构,~~现在~~所以在根节点中就新增了配置信息:</p>
|
||
|
||
<p><img src="assets/CgqCHl8VVf2AWu6mAAAPpWnlsUo874.png" alt="3.png" />
|
||
|
||
ZooKeeper 中的配置节点图</p>
|
||
|
||
<p>我们关注“config”段内容,其中“rule”节点包含了读写分离的规则设置:</p>
|
||
|
||
<p><img src="assets/CgqCHl8VVgWAXXOKAAAuZGtB8EQ493.png" alt="4.png" />
|
||
|
||
ZooKeeper 中的“rule”配置项</p>
|
||
|
||
<p>而“datasource”节点包含的显然是前面所指定的各个数据源信息。</p>
|
||
|
||
<p>由于我们在本地配置文件中将 spring.shardingsphere.orchestration.overwrite 配置项设置为 true,本地配置的变化就会影响到服务器端配置,进而影响到所有使用这些配置的应用程序。如果不希望产生这种影响,而是统一使用位于配置中心上的配置,应该怎么做呢?</p>
|
||
|
||
<p>很简单,我们只需要将 spring.shardingsphere.orchestration.overwrite 设置为 false 即可。<strong>将这个配置开关进行关闭,意味着我们将只从配置中心读取配置,也就是说,本地不需要保存任何配置信息</strong>,只包含指定配置中心的相关内容了:</p>
|
||
|
||
<pre><code>spring.shardingsphere.orchestration.name=health_ms
|
||
|
||
spring.shardingsphere.orchestration.overwrite=false
|
||
|
||
spring.shardingsphere.orchestration.registry.type=zookeeper
|
||
|
||
spring.shardingsphere.orchestration.registry.server-lists=localhost:2181
|
||
|
||
spring.shardingsphere.orchestration.registry.namespace=orchestration-health_ms
|
||
|
||
</code></pre>
|
||
|
||
<p>执行测试用例后,会发现读写分离规则同样生效。</p>
|
||
|
||
<p>如果你选择使用其他的框架来构建配置中心服务器,比如阿里巴巴的 Nacos,那么也很简单,只需要将 spring.shardingsphere.orchestration.registry.type 设置成 nacos 并提供对应的 server-lists 就可以了:</p>
|
||
|
||
<pre><code>spring.shardingsphere.orchestration.name=health_ms
|
||
|
||
spring.shardingsphere.orchestration.overwrite=true
|
||
|
||
spring.shardingsphere.orchestration.registry.type=nacos
|
||
|
||
spring.shardingsphere.orchestration.registry.server-lists=localhost:8848
|
||
|
||
spring.shardingsphere.orchestration.registry.namespace=
|
||
|
||
</code></pre>
|
||
|
||
<h3>总结</h3>
|
||
|
||
<p>本课时我们讨论了在 ShardingSphere 中与编排治理相关的功能支持。ShardingSphere 提供了配置中心和注册中心两种治理机制,这两种机制采用了类似的底层设计,但面向不同的应用场景。我们结合案例,基于配置中心给出了具体的开发过程。对于配置中心而言,重点是需要理解<strong>如何基于 Zookeeper 这个分布式协调工具来完成本地和远程配置信息之前的动态更新和同步</strong>。</p>
|
||
|
||
<p>这里给你留一道思考题:ShardingSphere 中配置中心和注册中心在设计上有哪些相同点和不同点?</p>
|
||
|
||
<p>本课时是专栏中关于 ShardingSphere 核心功能的最后一个主题,从下一个课时开始,我们将进入 ShardingSphere 源码解析的相关内容,我将为你梳理如何高效地阅读 ShardingSphere 源码,记得按时来听课。</p>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div>
|
||
|
||
<div style="float: left">
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/10 数据脱敏:如何确保敏感数据的安全访问?.md.html">上一页</a>
|
||
|
||
</div>
|
||
|
||
<div style="float: right">
|
||
|
||
<a href="/专栏/ShardingSphere 核心原理精讲-完/12 从应用到原理:如何高效阅读 ShardingSphere 源码?.md.html">下一页</a>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||
|
||
</div>
|
||
|
||
<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"709974b4eb3f3d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
|
||
|
||
</body>
|
||
|
||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||
|
||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
|
||
|
||
<script>
|
||
|
||
window.dataLayer = window.dataLayer || [];
|
||
|
||
|
||
|
||
function gtag() {
|
||
|
||
dataLayer.push(arguments);
|
||
|
||
}
|
||
|
||
|
||
|
||
gtag('js', new Date());
|
||
|
||
gtag('config', 'G-NPSEEVD756');
|
||
|
||
var path = window.location.pathname
|
||
|
||
var cookie = getCookie("lastPath");
|
||
|
||
console.log(path)
|
||
|
||
if (path.replace("/", "") === "") {
|
||
|
||
if (cookie.replace("/", "") !== "") {
|
||
|
||
console.log(cookie)
|
||
|
||
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
setCookie("lastPath", path)
|
||
|
||
}
|
||
|
||
|
||
|
||
function setCookie(cname, cvalue) {
|
||
|
||
var d = new Date();
|
||
|
||
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
|
||
|
||
var expires = "expires=" + d.toGMTString();
|
||
|
||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||
|
||
}
|
||
|
||
|
||
|
||
function getCookie(cname) {
|
||
|
||
var name = cname + "=";
|
||
|
||
var ca = document.cookie.split(';');
|
||
|
||
for (var i = 0; i < ca.length; i++) {
|
||
|
||
var c = ca[i].trim();
|
||
|
||
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
|
||
|
||
}
|
||
|
||
return "";
|
||
|
||
}
|
||
|
||
|
||
|
||
</script>
|
||
|
||
|
||
|
||
</html>
|
||
|