ClickHouse系列--BalancedClickhouseDataSource實現

clickhouse-jdbc中負載均衡數據源的實現。
基本邏輯如下:
1.通過配置的url串,來切分構造url列表;
2.通過一個定時線程任務,來不斷的去ping url列表,來更新可用的url列表;
3.在可用列表中隨機返回一個可用url;

/*** 提供負載均衡能力的datasource實現*/
public class BalancedClickhouseDataSource implements DataSource {private static final Logger log = LoggerFactory.getLogger(BalancedClickhouseDataSource.class);private static final Pattern URL_TEMPLATE = Pattern.compile("jdbc:clickhouse://([a-zA-Z0-9_:,.-]+)(/[a-zA-Z0-9_]+([?][a-zA-Z0-9_]+[=][a-zA-Z0-9_]+([&][a-zA-Z0-9_]+[=][a-zA-Z0-9_]+)*)?)?");private PrintWriter printWriter;private int loginTimeoutSeconds;//隨機數private final ThreadLocal<Random> randomThreadLocal;//所有的urlprivate final List<String> allUrls;//可用的urlprivate volatile List<String> enabledUrls;private final ClickHouseProperties properties;private final ClickHouseDriver driver;public BalancedClickhouseDataSource(String url) {this(splitUrl(url), getFromUrl(url));}public BalancedClickhouseDataSource(String url, Properties properties) {this(splitUrl(url), new ClickHouseProperties(properties));}public BalancedClickhouseDataSource(String url, ClickHouseProperties properties) {this(splitUrl(url), properties.merge(getFromUrlWithoutDefault(url)));}private BalancedClickhouseDataSource(List<String> urls) {this(urls, new ClickHouseProperties());}private BalancedClickhouseDataSource(List<String> urls, Properties info) {this(urls, new ClickHouseProperties(info));}private BalancedClickhouseDataSource(List<String> urls, ClickHouseProperties properties) {this.loginTimeoutSeconds = 0;this.randomThreadLocal = new ThreadLocal();this.driver = new ClickHouseDriver();if (urls.isEmpty()) {throw new IllegalArgumentException("Incorrect ClickHouse jdbc url list. It must be not empty");} else {try {//解析配置文件ClickHouseProperties localProperties = ClickhouseJdbcUrlParser.parse((String)urls.get(0), properties.asProperties());localProperties.setHost((String)null);localProperties.setPort(-1);this.properties = localProperties;} catch (URISyntaxException var8) {throw new IllegalArgumentException(var8);}List<String> allUrls = new ArrayList(urls.size());Iterator var4 = urls.iterator();while(var4.hasNext()) {String url = (String)var4.next();try {//如果合法urlif (this.driver.acceptsURL(url)) {//添加到所有的url列表allUrls.add(url);} else {log.error("that url is has not correct format: {}", url);}} catch (SQLException var7) {throw new IllegalArgumentException("error while checking url: " + url, var7);}}if (allUrls.isEmpty()) {throw new IllegalArgumentException("there are no correct urls");} else {//所有urlthis.allUrls = Collections.unmodifiableList(allUrls);//可用urlthis.enabledUrls = this.allUrls;}}}/*** 切割url* @param url* @return*/static List<String> splitUrl(String url) {//校驗url合法性Matcher m = URL_TEMPLATE.matcher(url);if (!m.matches()) {throw new IllegalArgumentException("Incorrect url");} else {String database = m.group(2);if (database == null) {database = "";}//切割url串String[] hosts = m.group(1).split(",");List<String> result = new ArrayList(hosts.length);String[] var5 = hosts;int var6 = hosts.length;//遍歷,添加切割后的urlfor(int var7 = 0; var7 < var6; ++var7) {String host = var5[var7];result.add("jdbc:clickhouse://" + host + database);}return result;}}/*** ping url看是否可用* @param url* @return*/private boolean ping(String url) {try {//執行簡單sql測試url鏈接可用性this.driver.connect(url, this.properties).createStatement().execute("SELECT 1");return true;} catch (Exception var3) {return false;}}/*** 遍歷所有url,通過ping的方式,選擇出可用的url* @return*/public synchronized int actualize() {//新建可用url列表List<String> enabledUrls = new ArrayList(this.allUrls.size());Iterator var2 = this.allUrls.iterator();while(var2.hasNext()) {String url = (String)var2.next();log.debug("Pinging disabled url: {}", url);if (this.ping(url)) {log.debug("Url is alive now: {}", url);//ping通的才添加進可用的enabledUrls.add(url);} else {log.debug("Url is dead now: {}", url);}}//重置可用url列表this.enabledUrls = Collections.unmodifiableList(enabledUrls);return enabledUrls.size();}/*** 隨機獲取可用url返回* @return* @throws SQLException*/private String getAnyUrl() throws SQLException {//可用url列表List<String> localEnabledUrls = this.enabledUrls;if (localEnabledUrls.isEmpty()) {throw new SQLException("Unable to get connection: there are no enabled urls");} else {Random random = (Random)this.randomThreadLocal.get();if (random == null) {this.randomThreadLocal.set(new Random());//產生一個隨機數random = (Random)this.randomThreadLocal.get();}int index = random.nextInt(localEnabledUrls.size());//用隨機數選擇一個可用的url返回return (String)localEnabledUrls.get(index);}}public ClickHouseConnection getConnection() throws SQLException {return this.driver.connect(this.getAnyUrl(), this.properties);}public ClickHouseConnection getConnection(String username, String password) throws SQLException {return this.driver.connect(this.getAnyUrl(), this.properties.withCredentials(username, password));}public <T> T unwrap(Class<T> iface) throws SQLException {if (iface.isAssignableFrom(this.getClass())) {return iface.cast(this);} else {throw new SQLException("Cannot unwrap to " + iface.getName());}}public boolean isWrapperFor(Class<?> iface) throws SQLException {return iface.isAssignableFrom(this.getClass());}public PrintWriter getLogWriter() throws SQLException {return this.printWriter;}public void setLogWriter(PrintWriter printWriter) throws SQLException {this.printWriter = printWriter;}public void setLoginTimeout(int seconds) throws SQLException {this.loginTimeoutSeconds = seconds;}public int getLoginTimeout() throws SQLException {return this.loginTimeoutSeconds;}public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {throw new SQLFeatureNotSupportedException();}/*** 定期清理無用url鏈接* @param rate* @param timeUnit* @return*/public BalancedClickhouseDataSource withConnectionsCleaning(int rate, TimeUnit timeUnit) {this.driver.scheduleConnectionsCleaning(rate, timeUnit);return this;}/*** 定期確認url,通過定時任務實現,以定時更新可用url列表* @param delay* @param timeUnit* @return*/public BalancedClickhouseDataSource scheduleActualization(int delay, TimeUnit timeUnit) {ScheduledConnectionCleaner.INSTANCE.scheduleWithFixedDelay(new Runnable() {public void run() {try {BalancedClickhouseDataSource.this.actualize();} catch (Exception var2) {BalancedClickhouseDataSource.log.error("Unable to actualize urls", var2);}}}, 0L, (long)delay, timeUnit);return this;}public List<String> getAllClickhouseUrls() {return this.allUrls;}public List<String> getEnabledClickHouseUrls() {return this.enabledUrls;}/*** 返回不可用url集合* 通過all 和 enable的差值來找* * @return*/public List<String> getDisabledUrls() {List<String> enabledUrls = this.enabledUrls;if (!this.hasDisabledUrls()) {return Collections.emptyList();} else {List<String> disabledUrls = new ArrayList(this.allUrls);disabledUrls.removeAll(enabledUrls);return disabledUrls;}}public boolean hasDisabledUrls() {return this.allUrls.size() != this.enabledUrls.size();}public ClickHouseProperties getProperties() {return this.properties;}private static ClickHouseProperties getFromUrl(String url) {return new ClickHouseProperties(getFromUrlWithoutDefault(url));}private static Properties getFromUrlWithoutDefault(String url) {if (StringUtils.isBlank(url)) {return new Properties();} else {int index = url.indexOf("?");return index == -1 ? new Properties() : ClickhouseJdbcUrlParser.parseUriQueryPart(url.substring(index + 1), new Properties());}}
}

新需求,每次獲取連接實例的時候打印出連接的ip
每次獲取連接


```java
BalancedClickhouseDataSource source ;
connection=source.getConnection();
//獲取的連接ip
String url = connection.getMetaData().getURL();

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

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

相關文章

Linux目錄說明

Linux Filesystem Hierarchy Standard&#xff08;FHS&#xff09; 1. /bin 全稱&#xff1a;Binary&#xff08;二進制文件&#xff09;功能&#xff1a;存放系統最基礎的可執行命令&#xff0c;所有用戶&#xff08;包括普通用戶&#xff09;都能使用&#xff0c;用于系統啟…

鴻蒙 Grid 與 GridItem 深度解析:二維網格布局解決方案

一、引言&#xff1a;網格布局 —— 多維度數據展示的黃金方案 在鴻蒙應用開發體系中&#xff0c;網格布局作為處理多元素有序排列的核心方案&#xff0c;廣泛應用于電商商品陳列、圖片畫廊、功能矩陣等場景。鴻蒙提供的 Grid 與 GridItem 組件通過聲明式語法構建靈活的二維布…

??Vue 開發環境配置:使用 devServer.proxy 解決跨域問題?-vue中文件vue.config,js中配置devserver做反向代理到后端

??Vue 開發環境配置&#xff1a;使用 devServer.proxy 解決跨域問題?? ??引言?? 在現代 Web 開發中&#xff0c;前端和后端通常獨立開發&#xff0c;前端運行在 http://localhost:8080&#xff0c;而后端可能運行在 http://localhost:8000 或其他端口。由于瀏覽器的 …

JVM 中的 GC 算法演進之路!(Serial、CMS、G1 到 ZGC)

引言 想象一下&#xff0c;Java 程序運行就像在一個巨大的圖書館里借書還書。這個圖書館&#xff08;JVM 的內存堆區&#xff09;為了高效運轉&#xff0c;需要一個聰明的“圖書管理員”來清理失效的書籍&#xff08;垃圾對象&#xff09;。這&#xff0c;就是垃圾回收器&#…

(9)python+playwright自動化測試-頁面(page)

1.簡介 通過前邊的講解和學習&#xff0c;細心認真地你可能發現在Playwright中&#xff0c;沒有Element這個概念&#xff0c;只有Page的概念&#xff0c;Page不僅僅指的是某個頁面&#xff0c;例如頁面間的跳轉等&#xff0c;還包含了所有元素、事件的概念&#xff0c;所以我們…

《自動控制原理 》- 第 1 章 自動控制的基本原理與方式

1-1 自動控制的基本原理與方式 自動控制是指在沒有人直接參與的情況下&#xff0c;利用外加的設備或裝置&#xff0c;使機器、設備或生產過程的某個工作狀態或參數按照預定的規律運行。自動控制的核心原理是反饋控制&#xff0c;即通過將系統的輸出量回送到輸入端&#xff0c;與…

DL00715-基于YOLOv11的水面漂浮物目標檢測含數據集

【論文必備】基于YOLOv11的水面漂浮物目標檢測——讓你的研究走在科技前沿&#xff01; 在環境監測、海洋保護和水質管理領域&#xff0c;水面漂浮物的檢測一直是一個亟待解決的難題。傳統的人工巡檢方式不僅耗時費力&#xff0c;還無法覆蓋廣泛的水域范圍。如今&#xff0c;基…

權電阻網絡DAC實現電壓輸出型數模轉換Multisim電路仿真——硬件工程師筆記

目錄 1 基礎知識 1.1 運算放大器在DAC中的作用 1.2 常見的基于運算放大器的DAC電路 1.2.1 倒T形電阻網絡DAC 1.2.2 權電阻網絡DAC 1.2.3 開關電容DAC 1.3 運算放大器的選擇 1.4 設計注意事項 2 仿真實驗 2.1 權電阻網絡DAC實現數字0對應電壓輸出 2.2 權電阻網絡DAC實…

Redis主從集群

? 一、什么是 Redis 主從集群&#xff1f; Redis 主從&#xff08;Master-Slave&#xff09;集群是一種最基礎的集群方式&#xff1a; 一臺 Redis 作為主節點&#xff08;Master&#xff09;&#xff0c;負責寫操作&#xff1b; 一到多臺 Redis 作為從節點&#xff08;Slave&…

【水印論文閱讀1】將水印規則的定義域從離散的符號空間轉移到連續的語義空間

【水印論文閱讀1】將水印規則的定義域從離散的符號空間轉移到連續的語義空間 寫在最前面**為什么“token序列空間”有根本缺陷&#xff1f;****為什么“語義向量空間”能破局&#xff1f;****1. 連續性&#xff08;抗攻擊的核心&#xff09;****2. 高維復雜性&#xff08;防破解…

Glide緩存機制

一、緩存層級與設計目標 雙級緩存&#xff1a; 內存緩存&#xff1a;弱引用 LruCache 磁盤緩存&#xff1a;DiskLruCache 設計目標&#xff1a; 減少網絡流量消耗 避免Bitmap頻繁創建/銷毀引發的GC 提升圖片加載速度 二、內存緩存機制 1. 雙緩存結構 緩存類型存儲對象…

BaiduSitemap - Typecho站點地圖生成與多搜索引擎推送插件

文章目錄 ?? BaiduSitemap - Typecho站點地圖生成與多搜索引擎推送插件? 功能特點?? 插件架構核心模塊文件結構?? 安裝方法方法一:手動安裝方法二:Git克隆?? 配置說明站點地圖基本設置搜索引擎配置百度搜索引擎必應(Bing)搜索引擎谷歌(Google)搜索引擎?? 使用…

androidx中<layout>根布局的意義及用法

在 Android 開發中,<layout> 根布局是 Android Jetpack Data Binding 庫的核心組件,用于聲明該 XML 布局文件將使用數據綁定功能。以下是詳細說明: ?? 一、基本作用 1. 啟用數據綁定 <layout> 標簽標志著此布局文件支持數據綁定,編譯器會為其生成對應的綁定類…

QTreeWidget 簡單使用

效果圖&#xff1a; 關鍵代碼&#xff1a; void MainProj::_InitTree() { connect(m_pTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(TreeItemClicked(QTreeWidgetItem*, int))); m_pTreeWidget->header()->setHidden(1); /*QTreeWid…

手勢-handpose的pipeline介紹

手勢-handpose的pipeline包括&#xff1a; 1、手部檢測算法&#xff1a;單幀檢測出左右手的邊界框。 2、手部跟蹤算法&#xff1a;連續幀跟蹤&#xff0c;鎖定左右手跟蹤目標&#xff0c;作為后續的手部ui操作。 3、手部關鍵點檢測算法&#xff1a;基于單幀的檢測框圖像作為輸…

計算機操作系統(十七)內存管理

計算機操作系統&#xff08;十七&#xff09;內存管理 前言一、內存的使用與程序重定位&#xff08;一&#xff09;內存是什么&#xff1f;&#xff08;二&#xff09;程序的重定位過程&#xff08;三&#xff09;總結&#xff1a;內存使用的核心問題 二、連續分區管理&#xf…

【編譯原理】期末

單選題 (4分) 令文法G[E]為&#xff1a;E->ET | T T->T*F | F F-> (E) | i 句型 F*iT 的最左素短語是&#xff08; &#xff09; A.F B.i C.T D.F*i B 短語&#xff1a; F*iT、F*i、F、i 素短語&#xff1a; i 最左素短語&#xff1a; i 單選題 (4分) 若在…

一個簡單測試Deepseek吞吐量的腳本,國內環境可跑

一個簡單測試Deepseek吞吐量的腳本,這里用DeepSeek-R1-Distill-Qwen-32B ,支持單卡4090 24G可跑,具體看你的硬件情況做調整,理論支持所有的模型,看你需要,可以修改模型名稱,重點是pip使用國內的源,模型下載用阿里的ModelScope,無障礙下載,使用. 最后可以生成一個txt與html報表.…

前端基礎知識JavaScript系列 - 19(正則表達式)

一、是什么 正則表達式是一種用來匹配字符串的強有力的武器 它的設計思想是用一種描述性的語言定義一個規則&#xff0c;凡是符合規則的字符串&#xff0c;我們就認為它“匹配”了&#xff0c;否則&#xff0c;該字符串就是不合法的 在 JavaScript中&#xff0c;正則表達式也…

Java鎖機制知識點

一、鎖的基礎概念 1.1 什么是鎖 在并發編程中&#xff0c;鎖是用于控制多個線程對共享資源進行訪問的機制。鎖可以保證在同一時刻最多只有一個線程訪問共享資源&#xff0c;從而保證數據的一致性。 1.2 鎖的分類 可重入鎖 vs 不可重入鎖&#xff1a;可重入鎖允許同一個線程…