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;可重入锁允许同一个线程…