关于druid:聊聊druid连接池的参数配置

序本文次要钻研一下druid连接池的参数配置 DruidDataSourceFactorydruid-1.2.11-sources.jar!/com/alibaba/druid/pool/DruidDataSourceFactory.java public class DruidDataSourceFactory implements ObjectFactory { private static final Log LOG = LogFactory.getLog(DruidDataSourceFactory.class); static final int UNKNOWN_TRANSACTIONISOLATION = -1; public static final String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit"; public static final String PROP_DEFAULTREADONLY = "defaultReadOnly"; public static final String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation"; public static final String PROP_DEFAULTCATALOG = "defaultCatalog"; public static final String PROP_DRIVERCLASSNAME = "driverClassName"; public static final String PROP_MAXACTIVE = "maxActive"; public static final String PROP_MAXIDLE = "maxIdle"; public static final String PROP_MINIDLE = "minIdle"; public static final String PROP_INITIALSIZE = "initialSize"; public static final String PROP_MAXWAIT = "maxWait"; public static final String PROP_TESTONBORROW = "testOnBorrow"; public static final String PROP_TESTONRETURN = "testOnReturn"; public static final String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis"; public static final String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun"; public static final String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis"; public static final String PROP_PHY_TIMEOUT_MILLIS = "phyTimeoutMillis"; public static final String PROP_TESTWHILEIDLE = "testWhileIdle"; public static final String PROP_PASSWORD = "password"; public static final String PROP_URL = "url"; public static final String PROP_USERNAME = "username"; public static final String PROP_VALIDATIONQUERY = "validationQuery"; public static final String PROP_VALIDATIONQUERY_TIMEOUT = "validationQueryTimeout"; public static final String PROP_INITCONNECTIONSQLS = "initConnectionSqls"; public static final String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed"; public static final String PROP_REMOVEABANDONED = "removeAbandoned"; public static final String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout"; public static final String PROP_LOGABANDONED = "logAbandoned"; public static final String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements"; public static final String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements"; public static final String PROP_CONNECTIONPROPERTIES = "connectionProperties"; public static final String PROP_FILTERS = "filters"; public static final String PROP_EXCEPTION_SORTER = "exceptionSorter"; public static final String PROP_EXCEPTION_SORTER_CLASS_NAME = "exception-sorter-class-name"; public static final String PROP_NAME = "name"; public static final String PROP_INIT = "init"; private static final String[] ALL_PROPERTIES = { PROP_DEFAULTAUTOCOMMIT, PROP_DEFAULTREADONLY, PROP_DEFAULTTRANSACTIONISOLATION, PROP_DEFAULTCATALOG, PROP_DRIVERCLASSNAME, PROP_MAXACTIVE, PROP_MAXIDLE, PROP_MINIDLE, PROP_INITIALSIZE, PROP_MAXWAIT, PROP_TESTONBORROW, PROP_TESTONRETURN, PROP_TIMEBETWEENEVICTIONRUNSMILLIS, PROP_NUMTESTSPEREVICTIONRUN, PROP_MINEVICTABLEIDLETIMEMILLIS, PROP_TESTWHILEIDLE, PROP_PASSWORD, PROP_FILTERS, PROP_URL, PROP_USERNAME, PROP_VALIDATIONQUERY, PROP_VALIDATIONQUERY_TIMEOUT, PROP_INITCONNECTIONSQLS, PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED, PROP_REMOVEABANDONED, PROP_REMOVEABANDONEDTIMEOUT, PROP_LOGABANDONED, PROP_POOLPREPAREDSTATEMENTS, PROP_MAXOPENPREPAREDSTATEMENTS, PROP_CONNECTIONPROPERTIES, PROP_EXCEPTION_SORTER, PROP_EXCEPTION_SORTER_CLASS_NAME, PROP_INIT, PROP_NAME, "druid.timeBetweenLogStatsMillis", "druid.stat.sql.MaxSize", "druid.clearFiltersEnable", "druid.resetStatEnable", // "druid.notFullTimeoutRetryCount", // "druid.maxWaitThreadCount", // "druid.failFast", // "druid.phyTimeoutMillis", // "druid.wall.tenantColumn", // "druid.wall.updateAllow", // "druid.wall.deleteAllow", // "druid.wall.insertAllow", // "druid.wall.selelctAllow", // "druid.wall.multiStatementAllow", // }; //......} DruidDataSourceFactory的ALL_PROPERTIES常量定义了所有反对的可配置项DruidDataSourceWrappercom/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceWrapper.java ...

September 28, 2023 · 4 min · jiezi

关于druid:聊聊druid的handleException

序本文次要钻研一下druid的handleException prepareStatementcom/alibaba/druid/pool/DruidPooledConnection.java public PreparedStatement prepareStatement(String sql) throws SQLException { checkState(); PreparedStatementHolder stmtHolder = null; PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M1); boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex, sql); } } initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; }DruidPooledConnection的prepareStatement会catch住SQLException而后执行handleExceptionexecuteQuerycom/alibaba/druid/pool/DruidPooledPreparedStatement.java public ResultSet executeQuery() throws SQLException { checkOpen(); incrementExecuteQueryCount(); transactionRecord(sql); oracleSetRowPrefetch(); conn.beforeExecute(); try { ResultSet rs = stmt.executeQuery(); if (rs == null) { return null; } DruidPooledResultSet poolableResultSet = new DruidPooledResultSet(this, rs); addResultSetTrace(poolableResultSet); return poolableResultSet; } catch (Throwable t) { errorCheck(t); throw checkException(t); } finally { conn.afterExecute(); } }executeQuery在catch到Throwable时会执行throw checkException(t)checkExceptioncom/alibaba/druid/pool/DruidPooledStatement.java ...

September 27, 2023 · 4 min · jiezi

关于druid:聊聊druid的return行为

序本文次要钻研一下druid的return行为 closecom/alibaba/druid/pool/DruidPooledConnection.java @Override public void close() throws SQLException { if (this.disable) { return; } DruidConnectionHolder holder = this.holder; if (holder == null) { if (dupCloseLogEnable) { LOG.error("dup close"); } return; } DruidAbstractDataSource dataSource = holder.getDataSource(); boolean isSameThread = this.getOwnerThread() == Thread.currentThread(); if (!isSameThread) { dataSource.setAsyncCloseConnectionEnable(true); } if (dataSource.isAsyncCloseConnectionEnable()) { syncClose(); return; } if (!CLOSING_UPDATER.compareAndSet(this, 0, 1)) { return; } try { for (ConnectionEventListener listener : holder.getConnectionEventListeners()) { listener.connectionClosed(new ConnectionEvent(this)); } List<Filter> filters = dataSource.getProxyFilters(); if (filters.size() > 0) { FilterChainImpl filterChain = new FilterChainImpl(dataSource); filterChain.dataSource_recycle(this); } else { recycle(); } } finally { CLOSING_UPDATER.set(this, 0); } this.disable = true; }close办法先从holder获取以后的dataSource,而后判断ownerThread,若不是同一个线程则设置asyncCloseConnectionEnable为true,若asyncCloseConnectionEnable为true则执行syncClose(这里语义貌似相同),否则执行recycle办法syncClosecom/alibaba/druid/pool/DruidPooledConnection.java ...

September 26, 2023 · 3 min · jiezi

关于druid:聊聊druid的borrow行为

序本文次要钻研一下druid的borrow行为 getConnectioncom/alibaba/druid/pool/DruidDataSource.java public DruidPooledConnection getConnection() throws SQLException { return getConnection(maxWait); } public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException { init(); if (filters.size() > 0) { FilterChainImpl filterChain = new FilterChainImpl(this); return filterChain.dataSource_connect(this, maxWaitMillis); } else { return getConnectionDirect(maxWaitMillis); } }DruidDataSource的getConnection办法外部调用的是getConnectionDirect(maxWaitMillis)getConnectionDirectcom/alibaba/druid/pool/DruidDataSource.java public DruidPooledConnection getConnectionDirect(long maxWaitMillis) throws SQLException { int notFullTimeoutRetryCnt = 0; for (; ; ) { // handle notFullTimeoutRetry DruidPooledConnection poolableConnection; try { poolableConnection = getConnectionInternal(maxWaitMillis); } catch (GetConnectionTimeoutException ex) { if (notFullTimeoutRetryCnt <= this.notFullTimeoutRetryCount && !isFull()) { notFullTimeoutRetryCnt++; if (LOG.isWarnEnabled()) { LOG.warn("get connection timeout retry : " + notFullTimeoutRetryCnt); } continue; } throw ex; } if (testOnBorrow) { boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn); if (!validate) { if (LOG.isDebugEnabled()) { LOG.debug("skip not validate connection."); } discardConnection(poolableConnection.holder); continue; } } else { if (poolableConnection.conn.isClosed()) { discardConnection(poolableConnection.holder); // 传入null,防止反复敞开 continue; } if (testWhileIdle) { final DruidConnectionHolder holder = poolableConnection.holder; long currentTimeMillis = System.currentTimeMillis(); long lastActiveTimeMillis = holder.lastActiveTimeMillis; long lastExecTimeMillis = holder.lastExecTimeMillis; long lastKeepTimeMillis = holder.lastKeepTimeMillis; if (checkExecuteTime && lastExecTimeMillis != lastActiveTimeMillis) { lastActiveTimeMillis = lastExecTimeMillis; } if (lastKeepTimeMillis > lastActiveTimeMillis) { lastActiveTimeMillis = lastKeepTimeMillis; } long idleMillis = currentTimeMillis - lastActiveTimeMillis; long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis; if (timeBetweenEvictionRunsMillis <= 0) { timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; } if (idleMillis >= timeBetweenEvictionRunsMillis || idleMillis < 0 // unexcepted branch ) { boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn); if (!validate) { if (LOG.isDebugEnabled()) { LOG.debug("skip not validate connection."); } discardConnection(poolableConnection.holder); continue; } } } } if (removeAbandoned) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); poolableConnection.connectStackTrace = stackTrace; poolableConnection.setConnectedTimeNano(); poolableConnection.traceEnable = true; activeConnectionLock.lock(); try { activeConnections.put(poolableConnection, PRESENT); } finally { activeConnectionLock.unlock(); } } if (!this.defaultAutoCommit) { poolableConnection.setAutoCommit(false); } return poolableConnection; } } public boolean isFull() { lock.lock(); try { return this.poolingCount + this.activeCount >= this.maxActive; } finally { lock.unlock(); } }getConnectionDirect在一个for循环外头进行获取连贯,首先执行getConnectionInternal(maxWaitMillis),若呈现GetConnectionTimeoutException异样,则在notFull且notFullTimeoutRetryCnt小于等于this.notFullTimeoutRetryCount时会递增notFullTimeoutRetryCnt,而后continue持续循环,否则间接抛出GetConnectionTimeoutException跳出循环 ...

September 25, 2023 · 10 min · jiezi

关于druid:搞懂Druid之连接创建和销毁

前言Druid是阿里开源的数据库连接池,是阿里监控零碎Dragoon的副产品,提供了弱小的可监控性和基于Filter-Chain的可扩展性。 本篇文章将对Druid数据库连接池的连贯创立和销毁进行剖析。剖析Druid数据库连接池的源码前,须要明确几个概念。 Druid数据库连接池中可用的连贯寄存在一个数组connections中;Druid数据库连接池做并发管制,次要靠一把可重入锁以及和这把锁关联的两个Condition对象;public DruidAbstractDataSource(boolean lockFair) { lock = new ReentrantLock(lockFair); notEmpty = lock.newCondition(); empty = lock.newCondition();}连接池没有可用连贯时,利用线程会在notEmpty上期待,连接池已满时,生产连贯的线程会在empty上期待;对连贯保活,就是每距离肯定工夫,对达到了保活距离周期的连贯进行有效性校验,能够将有效连贯销毁,也能够避免连贯长时间不与数据库服务端通信。Druid版本:1.2.11 注释一. DruidDataSource连贯创立DruidDataSource连贯的创立由CreateConnectionThread线程实现,其run() 办法如下所示。 public void run() { initedLatch.countDown(); long lastDiscardCount = 0; int errorCount = 0; for (; ; ) { try { lock.lockInterruptibly(); } catch (InterruptedException e2) { break; } long discardCount = DruidDataSource.this.discardCount; boolean discardChanged = discardCount - lastDiscardCount > 0; lastDiscardCount = discardCount; try { // emptyWait为true示意生产连接线程须要期待,无需生产连贯 boolean emptyWait = true; // 产生了创立谬误,且池中已无连贯,且抛弃连贯的统计没有扭转 // 此时生产连接线程须要生产连贯 if (createError != null && poolingCount == 0 && !discardChanged) { emptyWait = false; } if (emptyWait && asyncInit && createCount < initialSize) { emptyWait = false; } if (emptyWait) { // 池中已有连接数大于等于正在期待连贯的利用线程数 // 且以后是非keepAlive场景 // 且以后是非间断失败 // 此时生产连贯的线程在empty上期待 // keepAlive && activeCount + poolingCount < minIdle时会在shrink()办法中触发emptySingal()来增加连贯 // isFailContinuous()返回true示意间断失败,即屡次(默认2次)创立物理连贯失败 if (poolingCount >= notEmptyWaitThreadCount && (!(keepAlive && activeCount + poolingCount < minIdle)) && !isFailContinuous() ) { empty.await(); } // 避免创立超过maxActive数量的连贯 if (activeCount + poolingCount >= maxActive) { empty.await(); continue; } } } catch (InterruptedException e) { // 省略 } finally { lock.unlock(); } PhysicalConnectionInfo connection = null; try { connection = createPhysicalConnection(); } catch (SQLException e) { LOG.error("create connection SQLException, url: " + jdbcUrl + ", errorCode " + e.getErrorCode() + ", state " + e.getSQLState(), e); errorCount++; if (errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0) { // 屡次创立失败 setFailContinuous(true); // 如果配置了疾速失败,就唤醒所有在notEmpty上期待的利用线程 if (failFast) { lock.lock(); try { notEmpty.signalAll(); } finally { lock.unlock(); } } if (breakAfterAcquireFailure) { break; } try { Thread.sleep(timeBetweenConnectErrorMillis); } catch (InterruptedException interruptEx) { break; } } } catch (RuntimeException e) { LOG.error("create connection RuntimeException", e); setFailContinuous(true); continue; } catch (Error e) { LOG.error("create connection Error", e); setFailContinuous(true); break; } if (connection == null) { continue; } // 把连贯增加到连接池 boolean result = put(connection); if (!result) { JdbcUtils.close(connection.getPhysicalConnection()); LOG.info("put physical connection to pool failed."); } errorCount = 0; if (closing || closed) { break; } }}CreateConnectionThread的run() 办法整体就是在一个死循环中一直的期待,被唤醒,而后创立线程。当一个物理连贯被创立进去后,会调用DruidDataSource#put办法将其放到连接池connections中,put() 办法源码如下所示。 ...

February 20, 2023 · 6 min · jiezi

关于druid:数据库连接池Druid数据库连接池源码解析

前言本文将对Druid数据库连接池的源码进行剖析和学习,以理解Druid数据库连接池的工作原理。Druid数据库连接池的根本逻辑简直全副在DruidDataSource类中,所以本文次要是围绕DruidDataSource的各项性能开展阐述。 Druid版本:1.2.11 注释一. DruidDataSource初始化DruidDataSource初始化有两种形式,如下所示。 将DruidDataSource实例创立进去后,被动调用其init()办法实现初始化;首次调用DruidDataSource的getConnection()办法时,会调用到init()办法实现初始化。因为init()办法过长,上面将分点介绍init()办法实现的要害事件。 1. 双重查看inited状态对inited状态进行Double Check,避免DruidDataSource初始化两次。源码示意如下。 public void init() throws SQLException { if (inited) { return; } ...... final ReentrantLock lock = this.lock; try { lock.lockInterruptibly(); } catch (InterruptedException e) { throw new SQLException("interrupt", e); } boolean init = false; try { if (inited) { return; } ...... } catch (SQLException e) { ...... } catch (InterruptedException e) { ...... } catch (RuntimeException e) { ...... } catch (Error e) { ...... } finally { inited = true; lock.unlock(); ...... }}2. 判断数据库类型依据jdbcUrl失去数据库类型dbTypeName。源码如下所示。 ...

January 2, 2023 · 16 min · jiezi

关于druid:mysqlredis-客户端连接池

1.mysql1.1. mysql 参数通过下列命令可查看mysql数据库配置的零碎参数: -- 查问所有零碎参数show variables;--含糊匹配查问零碎参数,如:wait_timeoutshow variables like '%wait_timeout%';这里介绍几个和连接池有关联的参数: 1. wait_timeout非交互连贯的最大存活工夫,单位:秒。即闲暇状态下的连贯,超过规定工夫后,mysql 会主动断开。 可通过下列命令查看具体的连贯的状态: show processlist;如果 sleep 状态的过程,占用总比例过高,就能够思考调小 wait_timeout 值了。 2. max_connections全局最大连接数。 可通过下列命令查看最大应用的连贯数量(Max_used_connections): show status like 'max%connections%';再通过下列命令查看最大连接数(max_connections): show variables like 'max%connections%';通过 Max_used_connections/max_connections 的占比来判断设置的最大连接数是否正当,现实状况下这个比例应该在85%左右。 max_connections 默认值是100,如果服务器的并发连贯申请量比拟大,倡议调高此值,以减少并行连贯数量,当然这建设在机器能撑持的状况下,因为如果连接数越多,介于MySQL会为每个连贯提供连贯缓冲区,就会开销越多的内存,所以要适当调整该值,不能自觉进步设值。 1.2. druid 连接池配置外围参数 1. initial-size初始化时建设物理连贯的个数。 2. max-active连接池同时能维持的最大连接数。 3. min-idle最多维持多少个闲暇连贯,即便客户端没有需要,也要至多维持多少个闲暇连贯,以应答客户端的突发需要。 4. max-idle(已作废) 5. max-wait 连贯最大等待时间,单位毫秒。客户端从连接池获取(借出)一个连贯后,规定工夫内没有偿还,则连接池会抛出 GetConnectionTimeoutException 异样。 场景模仿 假如配置的值如下: spring.datasource.druid.initial-size=5spring.datasource.druid.min-idle=10spring.datasource.druid.max-active=50我的项目启动时,会主动创立5(initial-size)个连贯,就算此时没有数据库拜访,也会创立这5个。并且当客户端查询数据库的并发不大于5时,就始终是这5个。 当客户端查询数据库的并发越来越大,超过5时,连接数也就往上减少,但不会超过最大连接数50(max-active)。当并发数超过50时,超过局部的申请就会在队列中期待。 当峰值过来了,并发数降到50一下,多进去的连贯闲暇后就敞开了,连接数也就随之降落。当连接数最小只会降到10(min-idle),最多维持10个闲暇连贯。 1.3. hikari 连接池配置下列翻译自 HikariCP Github参数阐明: 1. connection-timeout管制客户端期待来自连接池连贯的最大毫秒数。 如果超过此工夫而没有可用的连贯,则会抛出SQLException。可承受的最低连贯超时为250 ms。 默认值:30000(30秒) 2. max-lifetime管制连接池中连贯的最大生存工夫。 正在应用中的连贯永远不会停止使用,只有在连贯敞开后,在达到最大生存周期后才将其删除。值为0示意没有最大生存期(有限生存期),当然这取决于idleTimeout设置。最小允许值是30秒,默认值:30分钟。 倡议:设置的工夫要比数据库中限度的连贯(mysql对应参数 wait_timeout)最大生存工夫小几秒钟。 ...

November 16, 2022 · 2 min · jiezi

关于druid:Apache-Druid聚合函数maxmin的默认值问题

问题形容:需要是对某一个字段取最大值和最小值,并且过滤条件不统一,就想到了druid聚合函数反对携带filter子句这一个性,按想法写进去但后果有点奇怪。 问题剖析:因为须要统计某个字段的最大值和最小值,并且在有Filter条件的状况下,因为Filter条件过滤之后的无后果,所以触发了聚合函数的默认值。这一点在官网中失去了印证。 解决办法:count聚合函数联合case子句对空行数据强制赋0。先用count函数求出过滤条件下的行数。用case子句判断这个行数是否是0,如果是0则强制赋0,如果不是0则认为至多有一条数据,能够应用聚合函数。

September 20, 2022 · 1 min · jiezi

关于druid:Druid-连接池异常statement-is-closed

druid 没有无效的配置主动回收连贯removeAbandoned 及 removeAbandonedTimeout 。导致连贯在在应用之前就被回收了。依据异样显示: statement曾经敞开了,却还想应用 敞开起因手动敞开,调用了close() 办法创立了PreparedStatement 没有及时用。而后数据库连贯发出,主动敞开了 statement解决办法手动敞开找找代码外面有没有敞开的代码。导致敞开之后还在应用数据库连贯发出查看是否配置 removeAbandoned 为true 且 removeAbandonedTimeout 是否小于了业务最大时长参考连贯:druid连接池配置参数 druid回收连贯导致statement is closed 附异样信息: java.sql.SQLException: statement is closed at com.alibaba.druid.pool.DruidPooledStatement.checkOpen(DruidPooledStatement.java:181) at com.alibaba.druid.pool.DruidPooledPreparedStatement.setString(DruidPooledPreparedStatement.java:366) at zm.PreparedStatement.setString(PreparedStatement.java:24) at zm.WinswJava.SwProcSalary.timer_proccess(SwProcSalary.java:121) at zm.base_daemon.proc_statis_salary.timer_run(proc_statis_salary.java:35) at zm.base_daemon.proc_statis_salary$1.run(proc_statis_salary.java:25) at java.util.TimerThread.mainLoop(Timer.java:555) at java.util.TimerThread.run(Timer.java:505)

July 29, 2022 · 1 min · jiezi

关于druid:druid回收连接导致statement-is-closed

相干常识:druid强制回收机制 代码剖析:为什么连贯回收会抛出这个异样首先查看DruidPooledConnection 这个类的close 办法syncClose 最终也会调用 recycle()  所以咱们次要看实现类 DruidDataSource  能够看到,相干的statement都会被敞开而Druid 应用的DruidPooledPreparedStatement 的 colse  如下DruidPooledConnection 的实现类如下:stmt.closeInternal() 最终调用了这个函数,并设置了 closed 而 closed 就是抛出 SQLException: statement is closed 的最大首恶

July 29, 2022 · 1 min · jiezi

关于druid:druid强制回收机制

druid在启动之后,在第一次调用getConnection 获取第一个连贯的时候,会进行 init 操作。init外面会开启几个线程,其中Druid-ConnectionPool-Destroy- 就是本次的配角这个类很简略: 在劳动 一段时间后,开始 销毁 超时的那些连贯 官网说:不论该连贯中是流动还是闲暇, 以避免过程不会进行close而霸占连贯。 然而代码反馈如果是活动状态是不解决的。而闲暇超时的局部,就会进入回收队列了

July 29, 2022 · 1 min · jiezi

关于druid:Apache-Druid-在-Shopee-的工程实践

本文作者 Yuanli,来自 Shopee Data Infra OLAP 团队。 摘要Apache Druid 是一款高性能的开源时序数据库,它实用于交互式体验的低延时查问剖析场景。本文将次要分享 Apache Druid 在撑持 Shopee 相干外围业务 OLAP 实时剖析方面的工程实际。 随着 Shopee 业务一直倒退,越来越多的相干外围业务更加依赖基于 Druid 集群的 OLAP 实时剖析服务,越来越严苛的利用场景使得咱们开始遇到开源我的项目 Apache Druid 的各种性能瓶颈。咱们通过剖析研读外围源码,对呈现性能瓶颈的元数据管理模块和缓存模块做了相干性能优化。 同时,为了满足公司外部外围业务的定制化需要,咱们开发了一些新个性,包含整型准确去重算子和灵便的滑动窗口函数。 1. Druid 集群在 Shopee 的利用以后集群部署计划是保护一个超大集群,基于物理机器部署,集群规模达 100+ 节点。Druid 集群作为相干外围业务数据我的项目的上游,能够通过批工作和流工作写入数据,而后相干业务方能够进行 OLAP 实时查问剖析。 2. 技术优化计划分享2.1 Coordinator 负载平衡算法效率优化2.1.1 问题背景咱们通过实时工作监控报警发现,很多实时工作因为最初一步 segment 公布交出(Coordinate Handoff)期待超时失败,随后陆续有用户跟咱们反映,他们的实时数据查问呈现了抖动。 通过考察发现,随着更多业务开始接入 Druid 集群,接入的 dataSource 越来越多,加上历史数据的累积,整体集群的 segment 数量越来越大。这使得 Coordinator 元数据管理服务的压力加大,逐步呈现性能瓶颈,影响整体服务的稳定性。 2.1.2 问题剖析Coordinator 一系列串行子任务分析首先咱们要剖析这些串行是否能够并行,但剖析发现,这些子工作存在逻辑上的前后依赖关系,因而须要串行执行。通过 Coordinator 的日志信息,咱们发现其中一个负责均衡 segment 在历史节点加载的子工作执行超级慢,耗时超过 10 分钟。正是这个子工作拖慢了整个串行工作的总耗时,使得另一个负责安顿 segment 加载的子工作执行距离太长,导致后面提到的实时工作因为公布阶段超时而失败。 通过应用 JProfiler 工具剖析,咱们发现负载平衡算法中应用的蓄水池采样算法的实现存在性能问题。剖析源码发现,以后的蓄水池采样算法每次调用只能从总量 500 万 segment 中采样一个元素,而每个周期须要均衡 2000 个 segment。也就是说,须要遍历 500 万的列表 2000 次,这显然是不合理的。 ...

February 7, 2022 · 3 min · jiezi

关于druid:leveldb-sstable-min-max区间搜索源码分析1

作者:王东阳 leveldb 中min_max搜寻剖析 前言 leveldb是一个写性能非常优良的存储引擎,是典型的LSM树(Log Structured-Merge Tree)实现。LSM树的核心思想是将随机写转化为间断写,从而晋升写操作的吞吐能力,整体架构如下: 尽管在内存中,所有的数据都是按序排列的,然而当多个memetable数据长久化到磁盘后,对应的不同的sstable之间是存在交加的,在读操作时,须要对所有的sstable文件进行遍历,重大影响了读取效率。因而leveldb后盾会“定期“整合这些sstable文件,该过程也称为compaction。随着compaction的进行,sstable文件在逻辑上被分成若干层,由内存数据间接dump进去的文件称为level0层文件,前期整合而成的文件为level i层文件,这也是leveldb这个名字的由来。 https://www.bookstack.cn/read...在leveldb的压缩过程中, 须要向上层搜寻和相互重叠的sstable进行合并,如下图所示: 下层数据如何疾速的查问下一层中和以后sstable文件重叠的文件列表呢?由上图能够看出每个sstable中都有一个最小值min和最大值max,示意以后文件所蕴含key的最大值和最小值,能够当成一个数据区间,Level0层的key区间相互有重叠,残余其它层中,每一层中的sstable文件,所蕴含的key区间,相互不重叠,所以对它们排序后,无论是最大值还是最小值都是严格递增的。 除了文件压缩,leveldb在执行查问的过程中,也会利用sstable的min,max的属性信息进行疾速查找申请key所在的文件。 本文次要基于leveldb:table.go 和 leveldb_rs:table.rs介绍sstable区间搜寻相干接口代码的实现算法。 tFile Go 文件的构造如下,次要蕴含文件的形容信息fd,文件中数据的大小size,以及文件中蕴含key的最小,最小值 (imin,imax). 在本文中,咱们只须要关注imin,imax就能够了。 // tFile holds basic information about a table.type tFile struct { fd storage.FileDesc seekLeft int32 size int64 imin, imax internalKey}接下来是tFile中的办法,须要留神的是上面的办法中都有一个参数icmp *iComparer ,咱们能够了解为一个比拟器,用于判断key大小时候应用的。 首先是tFile的after办法,判断给定的key是否在这个文件的前面 ,这个办法咱们能够这么了解,在一个程度数轴上,以后tFile的imin,imax对应数轴上的一个区间,判断给定的key是否在这个区间的前面,也就是判断给定ukey是否比以后文件中的最大值imax要大。 after 办法示意图: │ │ │ │ ukey ────────▼──────────▼─────────▲───────► imin imax │ │对应代码如下 // Returns true if given key is after largest key of this table.func (t *tFile) after(icmp *iComparer, ukey []byte) bool { return ukey != nil && icmp.uCompare(ukey, t.imax.ukey()) > 0}同理,tFile的before办法用来判断给定的ukey是否在在以后文件的后面,也就是判断ukey是否比以后文件中的最小值imin要小。 ...

January 15, 2022 · 5 min · jiezi

关于druid:Druid-中的filter

1.动机很多优良的框架都用到filter,之前的意识比拟含糊,心愿本次有所突破。 2.demo先入手写一个简略的demo @Componentpublic class MyFilter extends FilterEventAdapter { @Override protected void statementExecuteBefore(StatementProxy statement, String sql){ System.out.println(sql + "----------MyFilter--------执行开始前!------"); super.statementExecuteBefore(statement,sql); } @Override protected void statementExecuteAfter(StatementProxy statement, String sql, boolean result) { System.out.println(sql + "----------MyFilter--------执行完结后!------"); super.statementExecuteAfter(statement, sql, result); }}继承FilterEventAdapter,复写俩个办法,打两段日志,代码非常简单。执行测试用例: @Testvoid insertTest() { String sql = "insert into t_druid_test (id,firstname) " + "VALUES (1,'JINX')"; jdbcTemplate.execute(sql);}后果如下:一个简略的自定义filter已实现 3.解析3.1 Filter先看filter类图呃,太长了,看不了...总结一下,针对connection_xxx,resultSet_xxx,statement_xxx,preparedStatement_xxx,callableStatement_xxx,另外还有init,destroy等办法,根本参加了JDBC的全生命周期(datasource->connection->(Prepared)Statement->resultSet),果然是为监控而生。 抽象类FilterAdapter实现了filter接口,提供了根本的实现,大大减少了反复编码。 FilterEventAdapter继承FilterAdapter,在filter的根底上新增了xxxx_before,xxxx_after办法,能够用来做更多的事。 3.2 FilterChain看类图,接口办法根本和filter统一,次要承当串联filter和传递调用事件的职责。该接口的实现类FilterChainImpl,轻易找一个办法实现看一下: public ConnectionProxy connection_connect(Properties info) throws SQLException { // 将调用事件一直往下传递,直至this.pos == filterSize if (this.pos < filterSize) { return nextFilter() .connection_connect(this, info); } // 本办法的职责解决 Driver driver = dataSource.getRawDriver(); String url = dataSource.getRawJdbcUrl(); Connection nativeConnection = driver.connect(url, info); if (nativeConnection == null) { return null; } return new ConnectionProxyImpl(dataSource, nativeConnection, info, dataSource.createConnectionId());}此类的办法根本都是这种构造,分为传递调用和本办法的职责解决。 ...

November 22, 2021 · 1 min · jiezi

关于druid:Druid-加载-Kafka-数据后查询和清理数据

查问你的数据 当数据发送到 Kafka 后,Druid 应该可能马上查问到导入的数据的。 请拜访 query tutorial 页面中的内容来理解如何针对新导入的数据运行一些查问。 清理 如果你心愿其余的一些入门教程的话,你须要首先敞开 Druid 集群;删除 var 目录中的所有内容;再重新启动 Druid 集群。这是因为本教程中其余的导入数据形式也会写入雷同的 “wikipedia” 数据源,如果你应用不同的数据源的话就不须要进行清理了。 同时你可能也心愿清理掉 Kafka 中的数据。你能够通过 CTRL-C 来敞开 Kafka 的过程。在敞开 Kafka 过程之前,请不要敞开 ZooKeeper 和 Druid 服务。而后删除 Kafka 的 log 目录/tmp/kafka-logs: rm -rf /tmp/kafka-logs https://www.ossez.com/t/druid...

August 7, 2021 · 1 min · jiezi

关于druid:Druid-加载-Kafka-数据时直接提交一个-supervisor

为了可能间接启动一个服务,咱们须要提交一个 supervisor 配置参数到 Druid overlord 过程中,你能够间接通过 Druid 的包运行上面的命令: curl -XPOST -H'Content-Type: application/json' -d @quickstart/tutorial/wikipedia-kafka-supervisor.json http://localhost:8081/druid/i... 如果提交的 supervisor 被胜利创立的话,在返回的后果中将会有一个创立的 supervisor ID;在咱们以后的示例中,你应该能够看到返回的后果为 {"id":"wikipedia"}。 如果想理解更多无关 Kafka 的数据导入相干的信息,请参考 Druid Kafka indexing service documentation 页面中的内容。 你也能够从 Druid 的控制台中查看以后的 supervisors 和工作。针对本地服务器的拜访地址为: http://localhost:8888/unified... 。 https://www.ossez.com/t/druid...

August 7, 2021 · 1 min · jiezi

关于druid:Druid-集群方式部署-启动服务

启动 Master 服务器 拷贝 Druid 的散发包和你批改过的配置到 Master 服务器上。 如果你曾经在你的本地计算机上批改了配置,你能够应用 rsync 来进行拷贝。 rsync -az apache-druid-apache-druid-0.21.1/ MASTER_SERVER:apache-druid-apache-druid-0.21.1/ Master 没有 Zookeeper 的启动 从散发包的 root 节点中,运行上面的命令来启动 Master 服务器: bin/start-cluster-master-no-zk-server Master 有 Zookeeper 的启动 如果你打算在 Master 服务器上还同时运行 ZK 的话,首先须要更新 conf/zoo.cfg 中的配置来确定你如何运行 ZK。而后你能够抉择在启动 ZK 的同时启动 Master 服务器。 应用上面的命令行来进行启动: bin/start-cluster-master-with-zk-server 在生产环境中,咱们举荐你部署 ZooKeeper 在独立的集群下面。 启动 Data 服务器 拷贝 Druid 的散发包和你批改过的配置到 Data 服务器上。 从散发包的 root 节点中,运行上面的命令来启动 Data 服务器: bin/start-cluster-data-server 如果需要的话,你还能够为你的数据服务器增加更多的节点。 针对集群环境中更加简单的应用环境和需要,你能够将 Historicals 和 MiddleManagers 服务离开部署,而后别离进行扩容。下面的这种离开部署形式,可能给代理 Druid 曾经构建并且实现的 MiddleManager 主动扩容性能。 启动 Query 服务器 ...

August 6, 2021 · 1 min · jiezi

关于druid:Druid-集群方式部署-端口调整

如果你的服务应用了防火墙,或者一些网络配置中限度了端口的拜访的话。那么你须要在你的服务器上凋谢上面的端口,并运行数据进行拜访: Master 服务器1527 (Derby 原数据存储;如果你应用的是其余的数据库,例如 MySQL 或 PostgreSQL 的话就不须要)2181 (ZooKeeper;如果你应用的是分布式 ZooKeeper 集群部署的话就不须要)8081 (Coordinator 服务)8090 (Overlord 服务)Data 服务器8083 (Historical 服务)8091, 8100–8199 (Druid Middle Manager 服务,如果你应用了比拟高的 druid.worker.capacity 配置的话,那么你须要的端口可能会高于 8199)Query 服务器8082 (Broker 服务)8088 (Router 服务,如果应用的话) 在生产环境中,咱们举荐你部署 ZooKeeper 和你的元数据存储到他们本人的硬件上(独立部署)。不要和 Master server 混合部署在一起。 https://www.ossez.com/t/druid...

August 6, 2021 · 1 min · jiezi

关于druid:Druid-集群方式部署-配置调整

从一个独自部署服务器上进行合并到集群的时候,须要对上面的一些配置进行调整。 Master 服务 如果你曾经有一个曾经存在并且独立运行的独立服务器部署的话,例如在页面 single-server deployment examples 中部署的服务器,上面的这个示例将会帮忙你将 Coordinator 和 Overlord 合并到一个过程下面 conf/druid/cluster/master/coordinator-overlord 上面的示例,显示例如如何同时合并 Coordinator 和 Overlord 过程。 你能够从曾经部署的独立服务器上拷贝曾经存在 coordinator-overlord 配置文件,并部署到 conf/druid/cluster/master/coordinator-overlord。 Data 服务 假如咱们将要从一个 32 CPU 和 256GB 内存的独立服务器上进行合并。在老的部署中,上面的配置是针对 Historicals 和 MiddleManagers 过程的: Historical(独立服务器部署) druid.processing.buffer.sizeBytes=500000000druid.processing.numMergeBuffers=8druid.processing.numThreads=31 MiddleManager(独立服务器部署) druid.worker.capacity=8druid.indexer.fork.property.druid.processing.numMergeBuffers=2druid.indexer.fork.property.druid.processing.buffer.sizeBytes=100000000druid.indexer.fork.property.druid.processing.numThreads=1 在集群部署环境中,咱们能够抉择应用 2 个服务器来运行下面的 2 个服务,这 2 个服务器的配置为 16CPU 和 128GB RAM 。咱们将会依照上面的配置形式进行配置: Historical druid.processing.numThreads: 基于配置的新硬件环境,设置为 (num_cores - 1)druid.processing.numMergeBuffers: 针对独立服务器应用的数量应用决裂因子相除druid.processing.buffer.sizeBytes: 放弃不变 MiddleManager: druid.worker.capacity: 针对独立服务器应用的数量应用决裂因子相除druid.indexer.fork.property.druid.processing.numMergeBuffers: 放弃不变druid.indexer.fork.property.druid.processing.buffer.sizeBytes: 放弃不变druid.indexer.fork.property.druid.processing.numThreads: 放弃不变 在实现下面配置后的后果如下: 集群 Historical (应用 2 个数据服务器) druid.processing.buffer.sizeBytes=500000000 druid.processing.numMergeBuffers=8 druid.processing.numThreads=31 集群 MiddleManager (应用 2 个数据服务器) ...

August 6, 2021 · 1 min · jiezi

关于druid:Druid-集群方式部署-配置-Zookeeper-连接

在理论的生产环境中,咱们倡议你应用专用的 ZK 集群来进行部署。ZK 的集群与 Druid 的集群部署是拆散的。 在 conf/druid/cluster/_common/common.runtime.properties 配置文件中,设置druid.zk.service.host 为 connection string。在连贯配置中应用的是逗号分隔符(host:port 对),每一个对应的是一个 ZK 的服务器,(例如, “127.0.0.1:4545” or “127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002”)。 你也能够抉择在 Master 服务器上运行 ZK,而不应用专用的 ZK 集群。 如果这样做的话,咱们倡议部署 3 个 Master 服务服务器,以便具备 ZK 仲裁(因为 Zookeeper 的部署至多须要 3 个服务器,并且服务器的总数量为奇数)。 https://www.ossez.com/t/druid...

August 6, 2021 · 1 min · jiezi

关于druid:Druid-集群方式部署-操作系统和发行版本

抉择操作系统 咱们举荐你应用任何你喜爱的 Linux 操作系统。同时你须要装置: Java 8 或者更新的版本 正告: Druid 目前只能官网的反对 Java 8。如果你应用其余的 JDK 版本,那么很多性能可能是实践性的的。 如果需要的话,你能够在你的零碎环境中定义环境变量 DRUID_JAVA_HOME 或 JAVA_HOME,来通知 Druid 到哪里能够找到须要的 JDK 版本。能够运行 Druid 程序中的 bin/verify-java 脚本来查看以后运行的 Java 版本。 你的操作系统包管理工具应该可能帮忙你在操作系统中装置 Java。如果你应用的是基于 Ubuntu 的操作系统,然而这个操作系统没有提供的最新版本的 Java 的话,请尝试拜访 WebUpd8 页面中的内容: packages for thoseOSes 。 下载发行版本 首先,须要下载并且解压缩相干的归档文件。最好先在单台计算机上进行相干操作。因为随后你须要在解压缩的包内对配置进行批改,而后将批改后的配置公布到所有的其余服务器上。 apache-druid-0.21.1 下载地址 在控制台中应用上面的命令来进行解压: tar -xzf apache-druid-apache-druid-0.21.1-bin.tar.gz cd apache-druid-apache-druid-0.21.1 在解压后的包中,你应该可能看到: LICENSE 和 NOTICE 文件bin/* - 启动或进行的脚本,这是针对独立服务器进行部署的,请参考页面: 独立服务器部署疾速指南conf/druid/cluster/* - 针对集群部署的配置和设置文件extensions/* - Druid 外围扩大hadoop-dependencies/* - Druid Hadoop 依赖lib/* - Druid 外围库和依赖quickstart/* - 独立服务器配置的相干文件,这是针对独立服务器进行部署的,请参考页面: 独立服务器部署疾速指南 如果你须要让你的集群可能启动的话,咱们将会对 conf/druid/cluster/ 中的内容进行编辑。 从独立服务器部署上进行合并 如果须要实现后续页面的部署和配置的话,你须要对 conf/druid/cluster/ 中的内容进行编辑。 如果你曾经有一个正在运行的独立服务器部署的话,请拷贝你曾经存在的配置文件到 conf/druid/cluster 文件夹中,以保障你已有的配置文件不失落。 https://www.ossez.com/t/druid...

August 6, 2021 · 1 min · jiezi

关于druid:Druid-集群方式部署-选择硬件

Apache Druid 被设计部署为可扩大和容错的集群部署形式。 在本文档中,咱们将会设置一个示例集群,并且进行一些探讨,你能够进行那些批改来满足你的需要。 这个简略的集群包含有上面的个性: 主服务器(Master Server)将会运行 Coordinator 和 Overlord 过程2 个可扩大和容错的数据服务器将会运行 Historical 和 MiddleManager 过程一个查问服务器(Query Server)将会运行 Broker 和 Router 过程 在生产环境中,咱们倡议你部署多个 Master 服务器和多个 Query 服务器,服务器的高可用性(fault-tolerant)配置与你的数据个性和容错性要求非亲非故。然而你能够应用一个主服务器(Master Server) 和 一个查问服务器(Query Server)来启动服务,随着需要的减少你能够随时减少更多的服务器节点。 抉择硬件全新部署 如果你没有曾经存在的 Druid 集群,然而你心愿开始在你的环境中应用集群形式部署 Druid,本文档将会应用预配置(pre-made configurations)内容来帮忙你开始部署 Druid 的集群。 主服务器(Master Server) Coordinator 和 Overlord 过程将会负责解决 metadata 数据和在你集群中进行协调。这 2 个过程能够合并在同一个服务器上。 在本示例中,咱们将会在 AWS m5.2xlarge 部署一个评估的服务器和实例。 AWS 下面硬件的配置为: 8 vCPUs31 GB RAM 无关本服务器的配置信息和无关硬件大小的倡议,能够在文件 conf/druid/cluster/master 中找到。 数据服务器(Data server) Historicals 和 MiddleManagers 能够合并到同一个服务器上,这个 2 个过程在你的集群中用于解决理论的数据。通常来说越大 CPU, RAM, SSDs硬盘越好。 在本示例中,咱们将会在 i3.4xlarge 部署一个评估的服务器和实例。 ...

August 6, 2021 · 1 min · jiezi

关于druid:Druid-通过-dsql-的服务器连接参数如何配置

如果间接应用 ./dsql 运行命令行工具的话,将会显示连贯的服务器地址为 http://localhost:8082/ 如果须要连贯到其余的服务器地址,应该如何进行操作。 问题和解决 如果你心愿连贯到其余的服务器地址的话,你须要应用连贯参数 -H 请留神,这里的 H 是大写 H 那么命令的执行为: ./dsql -H http://10.0.0.1:8080/ 来进行服务器的连贯。 https://www.ossez.com/t/druid...

August 3, 2021 · 1 min · jiezi

关于druid:Druid-通过-dsql-进行查询

为了便于应用,Druid 包中还提供了一个 SQL 命令行客户端工具,这个工具位于 bin/dsql 目录中。 如果你间接运行 bin/dsql 的话,你将会看到上面的提醒输入: Welcome to dsql, the command-line client for Druid SQL.Type "\h" for help.dsql> 如果心愿进行查问的话,将你的 SQL 张贴到 dsql 提醒光标前面,而后单击回车: dsql> SELECT page, COUNT(*) AS Edits FROM wikipedia WHERE "__time" BETWEEN TIMESTAMP '2015-09-12 00:00:00' AND TIMESTAMP '2015-09-13 00:00:00' GROUP BY page ORDER BY Edits DESC LIMIT 10;┌──────────────────────────────────────────────────────────┬───────┐│ page │ Edits │├──────────────────────────────────────────────────────────┼───────┤│ Wikipedia:Vandalismusmeldung │ 33 ││ User:Cyde/List of candidates for speedy deletion/Subpage │ 28 ││ Jeremy Corbyn │ 27 ││ Wikipedia:Administrators' noticeboard/Incidents │ 21 ││ Flavia Pennetta │ 20 ││ Total Drama Presents: The Ridonculous Race │ 18 ││ User talk:Dudeperson176123 │ 18 ││ Wikipédia:Le Bistro/12 septembre 2015 │ 18 ││ Wikipedia:In the news/Candidates │ 17 ││ Wikipedia:Requests for page protection │ 17 │└──────────────────────────────────────────────────────────┴───────┘Retrieved 10 rows in 0.06s. ...

August 3, 2021 · 1 min · jiezi

关于druid:Druid-查询返回引擎版本困惑的地方

Druid 在几年前降级了搜寻版本为 V2。 在晚期是能够通过设置查问参数来进行设计的,如果你应用的是 Druid 的新版本的话,默认都会应用引擎 V2。 如果应用 JSON 查问的话,那么应该设置的参数是: "groupByStrategy":"v2" 然而在返回的时候显示返回的版本是 V1。 阐明 在网上考古了下,发现了多年前有这样一个帖子: 0.9.2 groupBy v2 Strategy problem - Google Groups (read only) - Druid Forum 下面官网的解释是这个 V1 定义的是返回的数据集格局为 V1,和应用的查问引擎无关。 这个返回后果还是有点困惑的,心愿提出来供大家参考。 https://www.ossez.com/t/druid...

July 31, 2021 · 1 min · jiezi

关于druid:安装-Druid-安装的时候提示-JAVA-版本的问题

错误信息如下 yhu@YuCheng-Hu:~/apache-druid-0.21.1/bin$ ./start-nano-quickstartDruid only officially supports Java 8. Any Java version later than 8 is still experimental. Your current version is: 11.0.11. If you believe this check is in error or you still want to proceed with Java version other than 8,you can skip this check using an environment variable: export DRUID_SKIP_JAVA_CHECK=1 Otherwise, install Java 8 and try again. This script searches for Java 8 in 3 locations in the followingorder ...

July 29, 2021 · 1 min · jiezi

关于druid:我应该在什么时候使用-Apache-Druid

许多公司都曾经将 Druid 利用于多种不同的利用场景。请拜访 应用 Apache Druid 的公司 页面来理解都有哪些公司应用了 Druid。 如果您的应用场景合乎上面的一些个性,那么Druid 将会是一个十分不错的抉择: 数据的插入频率十分高,然而更新频率非常低。大部分的查问为聚合查问(aggregation)和报表查问(reporting queries),例如咱们常应用的 “group by” 查问。同时还有一些检索和扫描查问。查问的提早被限度在 100ms 到 几秒钟之间。你的数据具备工夫组件(属性)。针对工夫相干的属性,Druid 进行非凡的设计和优化。你可能具备多个数据表,然而查问通常只针对一个大型的散布数据表,然而,查问又可能须要查问多个较小的 lookup 表。如果你的数据中具备高基数(high cardinality)数据字段,例如 URLs、用户 IDs,然而你须要对这些字段进行疾速计数和排序。你须要从 Kafka,HDFS,文本文件,或者对象存储(例如,AWS S3)中载入数据。 如果你的应用场景是上面的一些状况的话,Druid 不是一个较好的抉择: 针对一个曾经存在的记录,应用主键(primary key)进行低提早的更新操作。Druid 反对流式插入(streaming inserts)数据,然而并不很好的反对流式更新(streaming updates)数据。 Druid 的更新操作是通过后盾批处理实现的。你的零碎相似的是一个离线的报表零碎,查问的提早不是零碎设计的重要思考。应用场景中须要对表(Fact Table)进行连贯查问,并且针对这个查问你能够介绍比拟高的提早来期待查问的实现。 https://www.ossez.com/t/apach...

July 24, 2021 · 1 min · jiezi

关于druid:什么是-Druid

Apache Druid 是一个实时剖析型数据库,旨在对大型数据集进行疾速查问和剖析(“OLAP” 查问)。 Druid 最常被当做数据库,用以反对实时摄取、高查问性能和高稳固运行的利用场景。 例如,Druid 通常被用来作为图形剖析工具的数据源来提供数据,或当有须要高聚和高并发的后端 API。 同时 Druid 也非常适合针对面向事件类型的数据。 通常能够应用 Druid 作为数据源的零碎包含有: 点击流量剖析(Web 或者挪动剖析)网络监测剖析(网络性能监控)服务器存储指标供应链剖析(生产数据指标)利用性能指标数字广告剖析商业整合 / OLAP Druid 的外围架构汇合了数据仓库(data warehouses),时序数据库(timeseries databases),日志剖析零碎(logsearch systems)的概念。 如果你对下面的各种数据类型,数据库不是十分理解的话,那么咱们倡议你进行一些搜寻来理解相干的一些定义和提供的性能。 Druid 的一些要害个性包含有: 列示存储格局(Columnar storage format) Druid 应用列式存储,这意味着在一个特定的数据查问中它只须要查问特定的列。 这样的设计极大的进步了局部列查问场景性能。另外,每一列数据都针对特定数据类型做了优化存储,从而可能反对疾速扫描和聚合。可扩大的分布式系统(Scalable distributed system) Druid通常部署在数十到数百台服务器的集群中, 并且能够提供每秒数百万级的数据导入,并且保留有万亿级的数据,同时提供 100ms 到 几秒钟之间的查问提早。高性能并发解决(Massively parallel processing) Druid 能够在整个集群中并行处理查问。实时或者批量数据处理(Realtime or batch ingestion) Druid 能够实时(曾经被导入和摄取的数据可立刻用于查问)导入摄取数据库或批量导入摄取数据。自我修复、自我均衡、易于操作(Self-healing, self-balancing, easy to operate) 为集群运维操作人员,要伸缩集群只需增加或删除服务,集群就会在后盾主动从新均衡本身,而不会造成任何停机。 如果任何一台 Druid 服务器产生故障,零碎将主动绕过损坏的节点而放弃无间断运行。 Druid 被设计为 7*24 运行,无需设计任何起因的打算内停机(例如须要更改配置或者进行软件更新)。原生联合云的容错架构,不失落数据(Cloud-native, fault-tolerant architecture that won’t lose data) 一旦 Druid 取得了数据,那么取得的数据将会平安的保留在 深度存储 (通常是云存储,HDFS 或共享文件系统)中。 即便单个个 Druid 服务产生故障,你的数据也能够从深度存储中进行复原。对于仅影响多数 Druid 服务的无限故障,保留的正本可确保在零碎复原期间依然能够进行查问。针对疾速过滤的索引(Indexes for quick filtering) Druid 应用 Roaring 或 CONCISE 来压缩 bitmap indexes 起初创立索引,以反对疾速过滤和跨多列搜寻。基于工夫的分区(Time-based partitioning) Druid 首先按工夫对数据进行分区,同时也能够依据其余字段进行分区。 这意味着基于工夫的查问将仅拜访与查问工夫范畴匹配的分区,这将大大提高基于工夫的数据处理性能。近似算法(Approximate algorithms) Druid利用了近似 count-distinct,近似排序以及近似直方图和分位数计算的算法。 这些算法占用无限的内存使用量,通常比准确计算要快得多。对于精度要求比速度更重要的场景,Druid 还提供了exact count-distinct 和 exact ranking。在数据摄取的时候主动进行汇总(Automatic summarization at ingest time) Druid 反对在数据摄取阶段可选地进行数据汇总,这种汇总会局部事后聚合您的数据,并能够节俭大量老本并进步性能。 ...

July 24, 2021 · 1 min · jiezi

关于druid:技术分享-探究-Druid-连接池探活方式的实现

作者:刘开洋 爱可生交付服务团队北京 DBA,对数据库及周边技术有浓重的学习趣味,喜爱看书,谋求技术。 本文起源:原创投稿 *爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。 最近有钻研到 Druid 的问题,在进行探活检测时无奈失常输入 select x,解决问题后就跑来跟大家分享下 Druid 探活机制的实现。 一、Druid 是什么?Druid 对连贯的探活又是怎么实现的呢?Druid 是阿里巴巴开源的一款 JDBC 组件,是一款数据库连接池,对MySQL的适配性和性能很弱小,包含监控数据库拜访性能、 数据库明码加密、SQL执行日志、以及拓展监控的实现等等,利用到MySQL还是很香的。 通过对官网源码(详见参考)进行一些简略剖析理解到,应用 Druid 在对连贯进行探活时,波及到以下两个参数的调整: | 参数 | 阐明 | | :--------- | :--: | |druid.validationQuery = select 1 | 用来检测连贯是否无效的sql,要求是一个查问语句,罕用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。 | | druid.mysql.usePingMethod = false | 敞开 mysql com_ping 探活机制,需启用 validationQuery = select x,开启 validationQuery 探活机制 | 对其余参数的阐明参考配置属性列表:https://github.com/alibaba/dr... 在源码中失去的信息是 Druid 顺次初始化加载 initValidConnectionChecker(); 和 validationQueryCheck(); 在 ValidConnectionChecker 中 默认 com_ping 是开启的,就选用了 com_ping 作为默认探活,上面咱们来别离观测一下 com_ping 和 validationquery 的输入。 ...

June 1, 2021 · 4 min · jiezi

关于druid:Druid-015-版本启动错误

Druid 启动的时候提醒谬误如下: [Fri May 28 00:17:16 2021] Command[zk] exited (pid = 3835, exited = 1)[Fri May 28 00:17:16 2021] Command[zk] failed, see logfile for more details: /var/druid/var/sv/zk.log 通过下面的提醒到日志中进行查看后发现的错误信息是: Error: Could not find or load main class org.apache.zookeeper.server.quorum.QuorumPeerMainError: Could not find or load main class org.apache.zookeeper.server.quorum.QuorumPeerMainError: Could not find or load main class org.apache.zookeeper.server.quorum.QuorumPeerMainError: Could not find or load main class org.apache.zookeeper.server.quorum.QuorumPeerMain 下面的内容是你在控制台中看到的内容。 起因和解决 简略来说呈现下面的谬误的起因就是在你的 Druid 服务器上没有装置 Zookeeper。 进入以后的 Druid 目录后,顺次执行上面的命令: ...

May 28, 2021 · 1 min · jiezi

关于druid:解决druid在OpenJDK11Gradle中的依赖问题

1 问题形容环境OpenJDK 11+Gradle,间接在build.gradle中引入druid的依赖,报错如下: 'dependencies.dependency.systemPath' for com.sun:tools:jar must specify an absolute path but is ${project.basedir}/lib/openjdk-1.8-tools.jar in com.alibaba:druid:1.2.6'dependencies.dependency.systemPath' for com.sun:jconsole:jar must specify an absolute path but is ${project.basedir}/lib/openjdk-1.8-jconsole.jar in com.alibaba:druid:1.2.62 起因剖析具体起因的话在issue中能够晓得,其实就是没有兼容JDK11: 既然运行没有问题,那么就手动解决编译问题好了。 3 问题解决依据IDEA的谬误提醒(具体因druid版本而异): ~/.gradle/caches/modules-2/files-2.1/com.alibaba/druid/1.2.6/c57198d77a31adf5bd36d35f9b12dc936b732587/druid-1.2.6.pom批改提醒中的pom文件: 把下面的两个包正文掉就能够了,在1.2.6版本的druid中,批改pom文件的第703行,增加正文即可: 再次从新导入依赖能够看到没有问题了:

May 8, 2021 · 1 min · jiezi

关于druid:数据库连接池监控

连接池数量到底该配置成多少?加了数据库连接池监控之后,就能够验证连接池数量是否配置的太大,因为之前都是乱配的,配了好几百,前面发现理论的沉闷连贯数量只有几个,所以配置数量个别只有几十个就能够了,因为 1.并发申请没有那么高,可能就是个位数,高的时候是十位数,所以几十个就足够了。2.如果不思考并发数量,也只须要配置几十个,就是cpu的数量*2,20来个就能够了。所以最终的后果是,如果没有并发,配置cpu数量*2就能够了,20个就足够了。如果有一点并发(几十个),就30到50个就够了。如果并发达到50个,就还能够再往上加到100,然而最好不要超过100,超过100就应该加机器了,因为并发太多,机器也解决不过去,会导致处理速度变慢,所以就要加机器,好比每个人要做的事件变少了,速度就变快了。 数据库连接池的连贯跟线程池有关系吗?数据库连接池的连贯跟线程池有关系吗?没关系。 切换连贯,是切换线程吗?不是。 一个是切换线程上下文耗资源,因为要用户态和内核态切换,一个是创立数据库连贯耗资源,因为要三次握手。 所以,这两个货色没有任何关系,惟一的共同点就是复用对象,一个是线程对象,一个是数据库连贯对象。 为什么要复用对象?因为这两种对象,一个是创立代价太高,一个是切换代价太高(线程数量少,切换次数就少)。 数据库连接池满了怎么办?数据库连接池满了怎么办?阻塞。默认就是阻塞,直到连接池有新的连贯能够用。举个例子,比方配置的是30,当初满了,第31个申请来了,这个时候就阻塞,直到30个连贯里有一个连贯曾经执行实现了,当初闲暇进去了,这个时候这个闲暇的连贯就去执行方才的第31个申请。 数据库连接池获取连贯的耗时?个别失常状况就是几ms,然而如果是新创建的连贯,就要耗时几百ms,大略是200ms左右。如果是启动的时候,即连接池初始化的时候,获取连贯须要1s,即差不多1000ms。这些都是实在的监控数据,而且是生产环境的,测试环境也一样也差不多。

November 20, 2020 · 1 min · jiezi

关于druid:sql-injection-violation-syntax-errortoken-LPAREN

应用druid在查问MySql with as 报如下错:Error querying database. Cause: java.sql.SQLException: sql injection violation, syntax error: TODO. pos 782, line 25, column 5, token LPAREN : with g as ( 。。。uncategorized SQLException; SQL state [null]; error code [0]; sql injection violation, syntax error: TODO. pos 782, line 25, column 5, token LPAREN : with g as (。。。Caused by: com.alibaba.druid.sql.parser.ParserException: TODO. pos 782, line 25, column 5, token LPAREN at com.alibaba.druid.sql.parser.SQLStatementParser.parseWith(SQLStatementParser.java:3336)at com.alibaba.druid.sql.parser.SQLStatementParser.parseStatementList(SQLStatementParser.java:242)at com.alibaba.druid.sql.parser.SQLStatementParser.parseStatementList(SQLStatementParser.java:182)at com.alibaba.druid.wall.WallProvider.checkInternal(WallProvider.java:624)at com.alibaba.druid.wall.WallProvider.check(WallProvider.java:578)at com.alibaba.druid.wall.WallFilter.checkInternal(WallFilter.java:793)... 114 common frames omitted从下面的Caused by:局部异样信息来看,是druid解析SQL报的错,残缺的SQL如下:with g as ( ...

August 30, 2020 · 2 min · jiezi

SQLTimeoutException-ORA01013-user-requested-cancel-of-current

问题具体的场景是,cat监控到查询报错。 报错信息 Cause: java.sql.SQLTimeoutException: ORA-01013: user requested cancel of current operation字面意思是,客户端取消数据库连接,于是报错。 这个报错分两个部分: 1.数据库服务器 ORA-01013: user requested cancel of current operation //这个是数据库服务器返回的错误 2.客户端 Cause: java.sql.SQLTimeoutException //这个是java里的异常调用栈 原因原因1-数据库锁 网上搜了一下,说是锁的原因,所以开始以为是锁的原因,但是后面分析发现不是锁的原因,因为查询是普通的查询,普通的查询没有锁的问题,也就是说,任何锁,都不影响读。所以,报错应该不是因为这个原因。 原因2-客户端取消连接 根据报错信息字面的信息,就是因为客户端取消数据库连接。实际上,应该也是这个原因。但是,客户端为什么会取消数据库连接?根据报错信息的第一个部分,是超时。可是,为什么会超时?这个报错是间隔性的,一般情况都是正常的,在生产执行sql耗时不到1s,而且有的报错sql数据量比较小但是也会报错,所以也应该不是sql本身的问题。 到目前为止,没有找到本质的原因,只是知道字面的原因。所以,也没有办法解决。 其他信息 1.数据库连接池用了阿里的druid 这次上线更新了数据库连接池的配置,因为最近几天都在报错:连接重置,reset connection,recover connection,之类的报错信息。 原因是因为连接失效,解决方法是,开启连接池的空闲连接检查配置项testWhileIdle。然后,这次上线就更新了数据库连接池的配置,连接重置的错误没了,但是上线之后,却又报错客户端取消连接。所以,也有可能是和这次更新了数据库连接池配置有关。但是其他的项目,配置也一样,却又没有报错。 2.执行了sql,也没有问题,耗时正常 虽然不是锁的原因,但是也找dba看了锁,也是正常的,即都是短暂的锁(多次执行查询锁的sql,锁记录一直在变),没有长期持有锁不释放的情况。 3.cat监控到每个报错信息,也有对应的慢sql(也有报错信息,即异常调用栈) 这个也和报错信息的第一部分也对的上,就是执行sql的时间超时了。但是不知道为什么超时。 4.数据库锁 其他部门也有同样的错误,而且是读写分离,所以更应该不是数据库锁的原因。 总结 1.不是同一笔订单报错,其他的订单号也有报错 2.应该不是锁的原因 1)没有长期没有释放的锁,我和dba一起确认,锁的占用都是短暂的,所以应该不是锁的原因 2)数据库的锁,不会影响查询,现在的查询只是普通的查询,所以应该不是锁的原因 3)问了其他部门,他们读写分离,查询的时候也有这个问题,所以应该不是锁的原因 3.应该是偶尔查询数据库时间太久导致异常的时候,cat里的error和慢sql,都有异常,而且是同一笔订单。 具体分析是,由于数据库查询太久,应用超时,断开数据库连接,然后报错:ORA-01013: user requested cancel of current operation,即客户端取消了数据库连接。 本地模拟两个客户端的查询for update,后面的for update就会一直阻塞——停止后面的查询,也会报错提示:ORA-01013: user requested cancel of current operation。所以,客户端取消了连接,就会报错提示这个信息,在应用里比较可能的原因就是因为查询数据库太久导致应用超时,然后应用就取消了连接,从而报错这个提示信息。 解决方法经过分析,不太可能是慢sql的问题,所以还是连接的问题。目前的连接失效检测,是大于最小数量的连接,才检测。所以还是存在连接失效的问题,如果连接失效,客户端和服务器都不知道,然后客户端超时,然后取消数据库连接,就可能会导致这个问题。 ...

July 2, 2020 · 1 min · jiezi

SQLTimeoutException-ORA01013-user-requested-cancel-of-current

问题具体的场景是,cat监控到查询报错。 报错信息 Cause: java.sql.SQLTimeoutException: ORA-01013: user requested cancel of current operation字面意思是,客户端取消数据库连接,于是报错。 这个报错分两个部分: 1.数据库服务器 ORA-01013: user requested cancel of current operation //这个是数据库服务器返回的错误 2.客户端 Cause: java.sql.SQLTimeoutException //这个是java里的异常调用栈 原因原因1-数据库锁 网上搜了一下,说是锁的原因,所以开始以为是锁的原因,但是后面分析发现不是锁的原因,因为查询是普通的查询,普通的查询没有锁的问题,也就是说,任何锁,都不影响读。所以,报错应该不是因为这个原因。 原因2-客户端取消连接 根据报错信息字面的信息,就是因为客户端取消数据库连接。实际上,应该也是这个原因。但是,客户端为什么会取消数据库连接?根据报错信息的第一个部分,是超时。可是,为什么会超时?这个报错是间隔性的,一般情况都是正常的,在生产执行sql耗时不到1s,而且有的报错sql数据量比较小但是也会报错,所以也应该不是sql本身的问题。 到目前为止,没有找到本质的原因,只是知道字面的原因。所以,也没有办法解决。 其他信息 1.数据库连接池用了阿里的druid 这次上线更新了数据库连接池的配置,因为最近几天都在报错:连接重置,reset connection,recover connection,之类的报错信息。 原因是因为连接失效,解决方法是,开启连接池的空闲连接检查配置项。然后,这次上线就更新了数据库连接池的配置,连接重置的错误没了,但是上线之后,却又报错客户端取消连接。所以,也有可能是和这次更新了数据库连接池配置有关。但是其他的项目,配置也一样,却又没有报错。 2.执行了sql,也没有问题,耗时正常 虽然不是锁的原因,但是也找dba看了锁,也是正常的,即都是短暂的锁(多次执行查询锁的sql,锁记录一直在变),没有长期持有锁不释放的情况。 3.cat监控到每个报错信息,也有对应的慢sql(也有报错信息,即异常调用栈) 这个也和报错信息的第一部分也对的上,就是执行sql的时间超时了。但是不知道为什么超时。 4.数据库锁 其他部门也有同样的错误,而且是读写分离,所以更应该不是数据库锁的原因。 总结 1.不是同一笔订单报错,其他的订单号也有报错 2.应该不是锁的原因 1)没有长期没有释放的锁,我和dba一起确认,锁的占用都是短暂的,所以应该不是锁的原因 2)数据库的锁,不会影响查询,现在的查询只是普通的查询,所以应该不是锁的原因 3)问了其他部门,他们读写分离,查询的时候也有这个问题,所以应该不是锁的原因 3.应该是偶尔查询数据库时间太久导致异常的时候,cat里的error和慢sql,都有异常,而且是同一笔订单。 具体分析是,由于数据库查询太久,应用超时,断开数据库连接,然后报错:ORA-01013: user requested cancel of current operation,即客户端取消了数据库连接。 本地模拟两个客户端的查询for update,后面的for update就会一直阻塞——停止后面的查询,也会报错提示:ORA-01013: user requested cancel of current operation。所以,客户端取消了连接,就会报错提示这个信息,在应用里比较可能的原因就是因为查询数据库太久导致应用超时,然后应用就取消了连接,从而报错这个提示信息。 解决方法经过分析,不太可能是慢sql的问题,所以还是连接的问题。目前的连接失效检测,是大于最小数量的连接,才检测。所以还是存在连接失效的问题,如果连接失效,客户端和服务器都不知道,然后客户端超时,然后取消数据库连接,就可能会导致这个问题。 ...

June 27, 2020 · 1 min · jiezi