1.概述

原文链接:Clickhouse负载均衡客户端BalancedClickhouseDataSource源码分析

BalancedClickhouseDataSource的完整路径是ru.yandex.clickhouse.BalancedClickhouseDataSource,源码主要包括三部分,构造方法、获取连接、以及生成可用的地址列表。

BalancedClickhouseDataSource实现了javax.sql.DataSource,参数中allUrls是构造方法中传入的地址列表,enabledUrls是可用的地址列表。

public class BalancedClickhouseDataSource implements javax.sql.DataSource {private final ThreadLocal<Random> randomThreadLocal = new ThreadLocal<Random>();private final List<String> allUrls;private volatile List<String> enabledUrls;
}

BalancedClickhouseDataSource的构造方法,有多个,但是最终调用的都是BalancedClickhouseDataSource(final List urls, ClickHouseProperties properties),如果像jdbc:clickhouse://10.170.4.81:8123,10.170.4.82:8123,10.170.4.83:8123,10.170.4.84:8123/datasets这样配置多个地址,则会先进行切分。拆分成像jdbc:clickhouse://10.170.4.81:8123/datasets、jdbc:clickhouse://10.170.4.82:8123/datasets多个地址。

public BalancedClickhouseDataSource(final String url, Properties properties) {this(splitUrl(url), new ClickHouseProperties(properties));}static List<String> splitUrl(final String url) {Matcher m = URL_TEMPLATE.matcher(url);if (!m.matches()) {throw new IllegalArgumentException("Incorrect url");}String database = m.group(2);if (database == null) {database = "";}String[] hosts = m.group(1).split(",");final List<String> result = new ArrayList<String>(hosts.length);for (final String host : hosts) {result.add(JDBC_CLICKHOUSE_PREFIX + "//" + host + database);}return result;}private BalancedClickhouseDataSource(final List<String> urls, ClickHouseProperties properties) {if (urls.isEmpty()) {throw new IllegalArgumentException("Incorrect ClickHouse jdbc url list. It must be not empty");}try {ClickHouseProperties localProperties = ClickhouseJdbcUrlParser.parse(urls.get(0), properties.asProperties());localProperties.setHost(null);localProperties.setPort(-1);this.properties = localProperties;} catch (URISyntaxException e) {throw new IllegalArgumentException(e);}List<String> allUrls = new ArrayList<String>(urls.size());for (final String url : urls) {try {if (driver.acceptsURL(url)) {allUrls.add(url);} else {log.error("that url is has not correct format: {}", url);}} catch (SQLException e) {throw new IllegalArgumentException("error while checking url: " + url, e);}}if (allUrls.isEmpty()) {throw new IllegalArgumentException("there are no correct urls");}this.allUrls = Collections.unmodifiableList(allUrls);this.enabledUrls = this.allUrls;}

初始化完成后,会提供getConnection()方法获取连接,获取连接时会通过getAnyUrl()方法从enabledUrls可用列表中随机获取一个可用的连接。

   @Overridepublic ClickHouseConnection getConnection() throws SQLException {return driver.connect(getAnyUrl(), properties);}private String getAnyUrl() throws SQLException {List<String> localEnabledUrls = enabledUrls;if (localEnabledUrls.isEmpty()) {throw new SQLException("Unable to get connection: there are no enabled urls");}Random random = this.randomThreadLocal.get();if (random == null) {this.randomThreadLocal.set(new Random());random = this.randomThreadLocal.get();}int index = random.nextInt(localEnabledUrls.size());return localEnabledUrls.get(index);}

最后说一下可用地址列表的获取,scheduleActualization()方法会启动一个线程定时去调用actualize()方法检测可用列表。actualize()方法时通过执行SELECT查询SELECT 1去测试节点是否可用。

/*** set time period for checking availability connections** @param delay    value for time unit* @param timeUnit time unit for checking* @return this datasource with changed settings*/public BalancedClickhouseDataSource scheduleActualization(int delay, TimeUnit timeUnit) {ClickHouseDriver.ScheduledConnectionCleaner.INSTANCE.scheduleWithFixedDelay(new Runnable() {@Overridepublic void run() {try {actualize();} catch (Exception e) {log.error("Unable to actualize urls", e);}}}, 0, delay, timeUnit);return this;}/*** Checks if clickhouse on url is alive, if it isn't, disable url, else enable.** @return number of avaliable clickhouse urls*/public synchronized int actualize() {List<String> enabledUrls = new ArrayList<String>(allUrls.size());for (String url : allUrls) {log.debug("Pinging disabled url: {}", url);if (ping(url)) {log.debug("Url is alive now: {}", url);enabledUrls.add(url);} else {log.debug("Url is dead now: {}", url);}}this.enabledUrls = Collections.unmodifiableList(enabledUrls);return enabledUrls.size();}private boolean ping(final String url) {try {driver.connect(url, properties).createStatement().execute("SELECT 1");return true;} catch (Exception e) {return false;}}

2. 结论

Clickhouse-jdbc是使用负载均衡客户端ru.yandex.clickhouse.BalancedClickhouseDataSource来保证的,本质上是通过后台启动一个线程定时去探测clickhouse服务端,生成可用的地址列表。然后获取连接的时候从可用地址列表中随机选择一个节点来建立连接。

但是,坑爹的是,scheduleActualization方法没有地方调用,也就是说必须手动调用,否则,即使你配置了多个地址,如果某个节点宕机,仍然后很大的概率建立连接失败。

最后,BalancedClickhouseDataSource仅仅保证大部分情况下连接可用,根据ping的频率和超时时间的不同,总有一小段时间不能保证可用地址列表中所有地址都可用。因此想实现故障转移,保证高可用,还必须有客户端的配合,最好增加重试机制。

M.参考

参考:ClickHouse系列–BalancedClickhouseDataSource实现

【clickhouse】yandex 官方 BalancedClickhouseDataSource 源码分析相关推荐

  1. 【源码分析】极验验证官方SDK源码分析和实现思路

    前言 2016年就这么来了,新的一年,继续努力~ 最近,除了12306的验证码火起来以后,还有一个在界面上拖拽的验证码,也火了起来,就是这次要说的极验验证,在这个万众创新的时代,工具类产品能做到这样, ...

  2. vitamio官方demo源码分析(1)——MediaPlayerDemo_Video.java分析

    最近在做一个视频监控项目的android客户端,要求用rtsp协议完成视频流的传输,但苦于找到不合适的库.之前考虑过用live555或ffmpeg,但涉及到jni调用,加之不熟悉函数调用顺序,开发难度 ...

  3. 人人网官方Android客户端源码分析(1)

    ContentProvider是不同应用程序之间进行数据交换的标准API,ContentProvider以某种Uri的形式对外提供数据,允许其他应用访问或修改数据;其他应用程序使用ContentRes ...

  4. AI作曲基础-Python编程作曲软件篇-FoxDot文档及源码分析-官方教程01

    AI作曲基础-Python编程作曲软件篇-FoxDot文档及源码分析-官方教程01 前言 本系列系列目录放在文尾: 本系列是AI作曲的基础,暂时和AI关系不大,但尤为重要: 借助FoxDot,从文档分 ...

  5. 【Android CameraX】CameraXBasic —— 官方CameraX实例源码分析

    一.简介 二.源码分析 2.1 build.gradle 2.2 代码结构 2.3 变量 2.3.1 lensFacing 2.3.2 preview 2.3.3 Image capture 2.3. ...

  6. VTK之MPR重建源码分析(VTK官方例子)

    VTK之MPR重建源码分析(VTK官方例子) 一,核心的控制十字轴旋转的代码 //----------------------------------------------------------- ...

  7. openmp官方源码_MNN推理过程源码分析笔记(一)主流程

    在正式开始推理代码分析之前, 回顾下 MNN整体结构 推理分为三个大部分 Engine Backends Runtime Optimize 那么问题来了,从哪里开始,怎么入手呢? 我的心得是源码分析不 ...

  8. 【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析

    目录[阅读时间:约10分钟] 一.概述 二.对比: gorilla/mux与net/http DefaultServeMux 三.简单使用 四.源码简析 1.NewRouter函数 2.HandleF ...

  9. Django源码分析2:本地运行runserver分析

    django源码分析 本文环境python3.5.2,django1.10.x系列1.根据上一篇文章分析了,django-admin startproject与startapp的分析流程后,根据dja ...

最新文章

  1. 刘若英《爱情限量版》摘录
  2. python牛客网编程题_【面经】小米软件开发一面(python)面经 2020 2020
  3. [react] React16废弃了哪些生命周期?为什么?
  4. mybatis学习(31):修改部分字段(有外键,先查询,再修改)
  5. Linux 系统的运行级别(Run Level)
  6. java8 stream 多个_java8 stream两个集体交集、差集、并集操作
  7. 多线程编程(1): python对多线程的支持
  8. 10W+字C语言从入门到精通保姆级教程(2021版下)
  9. 改变iOS searchBar中textField的背景颜色
  10. Matlab设置黑色背景
  11. 如何通过SQL Server语句查询三个月内的信息代码的教程方法
  12. 运用KDJ交叉形态把握短期买卖点
  13. JSONP及Axios
  14. MONTHS_BETWEEN函数使用
  15. 3dsmax2015 64位中文版 安装
  16. 线性稳压器ME6209A33M3G应用电路
  17. 腾讯云短信接口报错1014
  18. wak切割功能和cut的区别
  19. 使用MapBox自定义地图
  20. 2022春 计算机系统大作业 程序人生-Hello’s P2P

热门文章

  1. 小米旗下电商平台「有品有鱼」宣布于3月终止运营
  2. 从武汉模式走向中国模式,打造人工智能产业发展的“中国样板”
  3. 学历全靠编,融资靠忽悠?网传“包养7个女主持”的金融大佬被揭穿了
  4. 法定节假日违规组织培训,51talk被通报批评整改不到位
  5. 爆料称配备更大屏幕尺寸的Apple Silicon版iMac仍在研发中
  6. 为了进大厂,我所经历的奇葩面试
  7. 新希望:拟参与设立总规模40亿元的广西新希望生猪保供专项产业基金
  8. 京东健康暗盘涨幅超27% 成交额超1.6亿港元
  9. 微信号都可以改了,那淘宝号呢?官方硬核回应遭网友吐槽:你没有心!
  10. 除了速度与激情 领克01带给我另一种有关生活方式的想象