mirror of
https://github.com/hellobike/tunnel.git
synced 2025-12-08 18:02:31 +00:00
feat:PG同步工具
This commit is contained in:
parent
39e2f57029
commit
5aff34c653
41
.circleci/config.yml
Normal file
41
.circleci/config.yml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# Java Maven CircleCI 2.0 configuration file
|
||||||
|
#
|
||||||
|
# Check https://circleci.com/docs/2.0/language-java/ for more details
|
||||||
|
#
|
||||||
|
version: 2
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
docker:
|
||||||
|
# specify the version you desire here
|
||||||
|
- image: circleci/openjdk:8-jdk
|
||||||
|
|
||||||
|
# Specify service dependencies here if necessary
|
||||||
|
# CircleCI maintains a library of pre-built images
|
||||||
|
# documented at https://circleci.com/docs/2.0/circleci-images/
|
||||||
|
# - image: circleci/postgres:9.4
|
||||||
|
|
||||||
|
working_directory: ~/repo
|
||||||
|
|
||||||
|
environment:
|
||||||
|
# Customize the JVM maximum heap limit
|
||||||
|
MAVEN_OPTS: -Xmx3200m
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
|
||||||
|
# Download and cache dependencies
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- v1-dependencies-{{ checksum "pom.xml" }}
|
||||||
|
# fallback to using the latest cache if no exact match is found
|
||||||
|
- v1-dependencies-
|
||||||
|
|
||||||
|
- run: mvn dependency:go-offline
|
||||||
|
|
||||||
|
- save_cache:
|
||||||
|
paths:
|
||||||
|
- ~/.m2
|
||||||
|
key: v1-dependencies-{{ checksum "pom.xml" }}
|
||||||
|
|
||||||
|
# run tests!
|
||||||
|
- run: mvn integration-test
|
||||||
40
.gitignore
vendored
Normal file
40
.gitignore
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Compiled class file
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Log file
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# BlueJ files
|
||||||
|
*.ctxt
|
||||||
|
|
||||||
|
# Mobile Tools for Java (J2ME)
|
||||||
|
.mtj.tmp/
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
# idea
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
**/target/**
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
out
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# eclipse
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.settings/
|
||||||
|
*.imp
|
||||||
|
|
||||||
|
logs
|
||||||
288
pom.xml
Normal file
288
pom.xml
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-all</artifactId>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-clean-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<filesets>
|
||||||
|
<fileset>
|
||||||
|
<directory>${basedir}/logs</directory>
|
||||||
|
</fileset>
|
||||||
|
</filesets>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-clean-plugin</artifactId>
|
||||||
|
<version>3.1.0</version>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<version>3.1.1</version>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.0</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
<encoding>utf-8</encoding>
|
||||||
|
</configuration>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ow2.asm</groupId>
|
||||||
|
<artifactId>asm</artifactId>
|
||||||
|
<version>${asm.version}</version> <!-- Use newer version of ASM -->
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>3.1.0</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>2.22.1</version>
|
||||||
|
<configuration>
|
||||||
|
<skipTests>true</skipTests>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>3.1.0</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>tunnel-server</module>
|
||||||
|
<module>tunnel-spi</module>
|
||||||
|
<module>tunnel-monitor</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<asm.version>6.1.1</asm.version>
|
||||||
|
<postgresql.version>42.2.5</postgresql.version>
|
||||||
|
<log4j2.version>2.11.1</log4j2.version>
|
||||||
|
<disruptor.version>3.4.2</disruptor.version>
|
||||||
|
<es.version>6.4.2</es.version>
|
||||||
|
<apollo.version>1.2.0</apollo.version>
|
||||||
|
<junit.version>4.12</junit.version>
|
||||||
|
<fastjson.version>1.2.51</fastjson.version>
|
||||||
|
<commons-lang3.version>3.8.1</commons-lang3.version>
|
||||||
|
<curator.version>2.12.0</curator.version>
|
||||||
|
<slf4j.version>1.7.25</slf4j.version>
|
||||||
|
<jackson.version>2.9.8</jackson.version>
|
||||||
|
<snappy.version>1.1.7.2</snappy.version>
|
||||||
|
<druid.version>1.1.12</druid.version>
|
||||||
|
<guava.version>23.0</guava.version>
|
||||||
|
|
||||||
|
|
||||||
|
<hadoop.version>2.5.1</hadoop.version>
|
||||||
|
<hbase.version>1.3.0</hbase.version>
|
||||||
|
<hive.version>2.1.1</hive.version>
|
||||||
|
|
||||||
|
|
||||||
|
<lombok.version>1.18.4</lombok.version>
|
||||||
|
|
||||||
|
|
||||||
|
<tunnel.version>1.0.0-SNAPSHOT</tunnel.version>
|
||||||
|
|
||||||
|
<powermock.version>1.7.4</powermock.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>dev</id>
|
||||||
|
<properties>
|
||||||
|
<env>dev</env>
|
||||||
|
</properties>
|
||||||
|
<activation>
|
||||||
|
<activeByDefault>true</activeByDefault>
|
||||||
|
</activation>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>${lombok.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-monitor</artifactId>
|
||||||
|
<version>${tunnel.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-api</artifactId>
|
||||||
|
<version>${tunnel.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-es</artifactId>
|
||||||
|
<version>${tunnel.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-hbase</artifactId>
|
||||||
|
<version>${tunnel.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-hdfs</artifactId>
|
||||||
|
<version>${tunnel.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-hive</artifactId>
|
||||||
|
<version>${tunnel.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-kafka</artifactId>
|
||||||
|
<version>${tunnel.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>${slf4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>log4j-over-slf4j</artifactId>
|
||||||
|
<version>${slf4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>jcl-over-slf4j</artifactId>
|
||||||
|
<version>${slf4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>druid</artifactId>
|
||||||
|
<version>${druid.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<version>4.5.6</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpcore</artifactId>
|
||||||
|
<version>4.4.10</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-codec</groupId>
|
||||||
|
<artifactId>commons-codec</artifactId>
|
||||||
|
<version>1.11</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-beanutils</groupId>
|
||||||
|
<artifactId>commons-beanutils</artifactId>
|
||||||
|
<version>1.9.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-collections</groupId>
|
||||||
|
<artifactId>commons-collections</artifactId>
|
||||||
|
<version>3.2.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-logging</groupId>
|
||||||
|
<artifactId>commons-logging</artifactId>
|
||||||
|
<version>1.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>2.6</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xerial.snappy</groupId>
|
||||||
|
<artifactId>snappy-java</artifactId>
|
||||||
|
<version>${snappy.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>${commons-lang3.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>${jackson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-core</artifactId>
|
||||||
|
<version>${jackson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-annotations</artifactId>
|
||||||
|
<version>${jackson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>${guava.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.lmax</groupId>
|
||||||
|
<artifactId>disruptor</artifactId>
|
||||||
|
<version>${disruptor.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>fastjson</artifactId>
|
||||||
|
<version>${fastjson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
</project>
|
||||||
80
tunnel-monitor/pom.xml
Normal file
80
tunnel-monitor/pom.xml
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>tunnel-all</artifactId>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>tunnel-monitor</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<opentracing.version>0.31.0</opentracing.version>
|
||||||
|
<prometheus.version>0.6.0</prometheus.version>
|
||||||
|
<opencensus.version>0.18.0</opencensus.version>
|
||||||
|
<yukon.version>1.0.1</yukon.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.opentracing</groupId>
|
||||||
|
<artifactId>opentracing-api</artifactId>
|
||||||
|
<version>${opentracing.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- The client -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.prometheus</groupId>
|
||||||
|
<artifactId>simpleclient</artifactId>
|
||||||
|
<version>${prometheus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Hotspot JVM metrics-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.prometheus</groupId>
|
||||||
|
<artifactId>simpleclient_hotspot</artifactId>
|
||||||
|
<version>${prometheus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Exposition HTTPServer-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.prometheus</groupId>
|
||||||
|
<artifactId>simpleclient_httpserver</artifactId>
|
||||||
|
<version>${prometheus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Pushgateway exposition-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.prometheus</groupId>
|
||||||
|
<artifactId>simpleclient_pushgateway</artifactId>
|
||||||
|
<version>${prometheus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>fastjson</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.lmax</groupId>
|
||||||
|
<artifactId>disruptor</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.opencensus</groupId>
|
||||||
|
<artifactId>opencensus-api</artifactId>
|
||||||
|
<version>${opencensus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.opencensus</groupId>
|
||||||
|
<artifactId>opencensus-impl</artifactId>
|
||||||
|
<version>${opencensus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.opencensus</groupId>
|
||||||
|
<artifactId>opencensus-exporter-stats-prometheus</artifactId>
|
||||||
|
<version>${opencensus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.monitor;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-27
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ExporterConfig {
|
||||||
|
|
||||||
|
private int exportPort = 7788;
|
||||||
|
private String metricName = "TunnelMetric";
|
||||||
|
private String[] labelName = labelNames();
|
||||||
|
private String loggerName = "TunnelLogger";
|
||||||
|
|
||||||
|
|
||||||
|
private static String[] labelNames() {
|
||||||
|
return new String[]{
|
||||||
|
"slotName", "appId",
|
||||||
|
"database", "table",
|
||||||
|
"target", "total",
|
||||||
|
"currentTime", "error"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.monitor;
|
||||||
|
|
||||||
|
import io.opencensus.exporter.stats.prometheus.PrometheusStatsCollector;
|
||||||
|
import io.prometheus.client.exporter.HTTPServer;
|
||||||
|
import io.prometheus.client.hotspot.DefaultExports;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-27
|
||||||
|
*/
|
||||||
|
public class PrometheusExporter implements TunnelExporter {
|
||||||
|
|
||||||
|
private ExporterConfig exporterConfig;
|
||||||
|
private PrometheusMonitor monitor;
|
||||||
|
private HTTPServer server;
|
||||||
|
|
||||||
|
public PrometheusExporter(ExporterConfig exporterConfig) {
|
||||||
|
this.exporterConfig = exporterConfig;
|
||||||
|
this.monitor = new PrometheusMonitor(this.exporterConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startup() {
|
||||||
|
PrometheusStatsCollector.createAndRegister();
|
||||||
|
DefaultExports.initialize();
|
||||||
|
try {
|
||||||
|
this.server = new HTTPServer(this.exporterConfig.getExportPort());
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
if (this.server != null) {
|
||||||
|
this.server.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TunnelMonitor getTunnelMonitor() {
|
||||||
|
return monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.monitor;
|
||||||
|
|
||||||
|
import io.prometheus.client.Gauge;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-25
|
||||||
|
*/
|
||||||
|
public class PrometheusMonitor implements TunnelMonitor {
|
||||||
|
|
||||||
|
private final Gauge gauge;
|
||||||
|
|
||||||
|
public PrometheusMonitor(ExporterConfig config) {
|
||||||
|
this.gauge = Gauge.build().name(config.getMetricName()).labelNames(config.getMetricName()).help("Tunnel Requests.").register();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void collect(Statics statics) {
|
||||||
|
this.gauge.labels(statics.getSlotName(), statics.getAppId(),
|
||||||
|
statics.getDatabase(), statics.getTable(),
|
||||||
|
statics.getTarget(), String.valueOf(statics.getTotal()),
|
||||||
|
String.valueOf(statics.getCurrentTime()), statics.getError()).inc();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.monitor;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-13
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class Statics {
|
||||||
|
|
||||||
|
private String appId;
|
||||||
|
private String database;
|
||||||
|
private String slotName;
|
||||||
|
private String table;
|
||||||
|
private int total;
|
||||||
|
private String target;
|
||||||
|
private String error;
|
||||||
|
private long currentTime;
|
||||||
|
|
||||||
|
public static Statics createStatics(String appId, String database, String slotName, String table, int total, String target, String error) {
|
||||||
|
return Statics.builder()
|
||||||
|
.appId(appId)
|
||||||
|
.database(database)
|
||||||
|
.slotName(slotName)
|
||||||
|
.table(table)
|
||||||
|
.total(total)
|
||||||
|
.target(target)
|
||||||
|
.error(error)
|
||||||
|
.currentTime(System.currentTimeMillis())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> toMap() {
|
||||||
|
Map<String, Object> map = new HashMap<>(8, 1f);
|
||||||
|
map.put("appId", getAppId());
|
||||||
|
map.put("database", getDatabase());
|
||||||
|
map.put("slotName", getSlotName());
|
||||||
|
map.put("table", getTable());
|
||||||
|
map.put("total", getTotal() + "");
|
||||||
|
map.put("target", getTarget());
|
||||||
|
map.put("error", getError());
|
||||||
|
map.put("currentTime", getCurrentTime() == 0 ? System.currentTimeMillis() : getCurrentTime());
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.monitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-27
|
||||||
|
*/
|
||||||
|
public interface TunnelExporter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动 exporter 容器,以便于外界查询
|
||||||
|
*/
|
||||||
|
void startup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭 exporter 容器
|
||||||
|
*/
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取监视器
|
||||||
|
*
|
||||||
|
* @return 监视器
|
||||||
|
*/
|
||||||
|
TunnelMonitor getTunnelMonitor();
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.monitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-25
|
||||||
|
*/
|
||||||
|
public interface TunnelMonitor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收集统计数据
|
||||||
|
*
|
||||||
|
* @param statics 统计数据
|
||||||
|
*/
|
||||||
|
void collect(final Statics statics);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.monitor;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-27
|
||||||
|
*/
|
||||||
|
public class PrometheusMain {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ExporterConfig config = new ExporterConfig();
|
||||||
|
TunnelExporter exporter = new PrometheusExporter(config);
|
||||||
|
TunnelMonitor monitor = exporter.getTunnelMonitor();
|
||||||
|
exporter.startup();
|
||||||
|
int total = 10;
|
||||||
|
CountDownLatch latch = new CountDownLatch(total);
|
||||||
|
Thread[] threads = new Thread[total];
|
||||||
|
IntStream.range(0, total).forEach(i -> {
|
||||||
|
threads[i] = new Thread(() -> {
|
||||||
|
monitor.collect(Statics.createStatics("testApp" + i, "testDb" + i, "sn" + i, "table" + i, i, "target" + i, "error" + i));
|
||||||
|
latch.countDown();
|
||||||
|
});
|
||||||
|
threads[i].start();
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
latch.await();
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
exporter.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
223
tunnel-server/pom.xml
Normal file
223
tunnel-server/pom.xml
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>tunnel-all</artifactId>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>tunnel-server</artifactId>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
<plugins>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
<encoding>utf-8</encoding>
|
||||||
|
</configuration>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ow2.asm</groupId>
|
||||||
|
<artifactId>asm</artifactId>
|
||||||
|
<version>${asm.version}</version> <!-- Use newer version of ASM -->
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<addClasspath>true</addClasspath>
|
||||||
|
<mainClass>com.hellobike.base.tunnel.TunnelLauncher</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
<excludes>
|
||||||
|
<exclude>conf/**</exclude>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skipTests>true</skipTests>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<appendAssemblyId>false</appendAssemblyId>
|
||||||
|
<finalName>AppTunnelService</finalName>
|
||||||
|
<descriptors>
|
||||||
|
<descriptor>src/main/assembly/assembly.xml</descriptor>
|
||||||
|
</descriptors>
|
||||||
|
<outputDirectory>${project.parent.basedir}/target</outputDirectory>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>make-assembly</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-monitor</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-es</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-hbase</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-hdfs</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-hive</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-kafka</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<version>${postgresql.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-slf4j-impl</artifactId>
|
||||||
|
<version>${log4j2.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.ctrip.framework.apollo</groupId>
|
||||||
|
<artifactId>apollo-client</artifactId>
|
||||||
|
<version>${apollo.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.curator</groupId>
|
||||||
|
<artifactId>curator-framework</artifactId>
|
||||||
|
<version>${curator.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.curator</groupId>
|
||||||
|
<artifactId>curator-recipes</artifactId>
|
||||||
|
<version>${curator.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-pool2</artifactId>
|
||||||
|
<version>2.6.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>${junit.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.powermock</groupId>
|
||||||
|
<artifactId>powermock-module-junit4</artifactId>
|
||||||
|
<version>${powermock.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.powermock</groupId>
|
||||||
|
<artifactId>powermock-api-mockito</artifactId>
|
||||||
|
<version>${powermock.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.manub</groupId>
|
||||||
|
<artifactId>scalatest-embedded-kafka_2.12</artifactId>
|
||||||
|
<version>2.0.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>snappy-java</artifactId>
|
||||||
|
<groupId>org.xerial.snappy</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>pl.allegro.tech</groupId>
|
||||||
|
<artifactId>embedded-elasticsearch</artifactId>
|
||||||
|
<version>2.7.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>jackson-core</artifactId>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
48
tunnel-server/src/main/assembly/assembly.xml
Normal file
48
tunnel-server/src/main/assembly/assembly.xml
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3
|
||||||
|
http://maven.apache.org/xsd/assembly-1.1.3.xsd">
|
||||||
|
|
||||||
|
<id>package</id>
|
||||||
|
<formats>
|
||||||
|
<format>zip</format>
|
||||||
|
</formats>
|
||||||
|
<fileSets>
|
||||||
|
<fileSet>
|
||||||
|
<directory>src/main/resources/configs/${env}/</directory>
|
||||||
|
<outputDirectory>conf</outputDirectory>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>src/main/resources/</directory>
|
||||||
|
<outputDirectory>conf/</outputDirectory>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/configs/**</exclude>
|
||||||
|
<exclude>**/conf/**</exclude>
|
||||||
|
</excludes>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>bin/${env}</directory>
|
||||||
|
<outputDirectory>/</outputDirectory>
|
||||||
|
<fileMode>755</fileMode>
|
||||||
|
</fileSet>
|
||||||
|
</fileSets>
|
||||||
|
|
||||||
|
<files>
|
||||||
|
<file>
|
||||||
|
<source>conf/logrotate</source>
|
||||||
|
<outputDirectory>/</outputDirectory>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<source>bin/check.sh</source>
|
||||||
|
<outputDirectory>/</outputDirectory>
|
||||||
|
<fileMode>755</fileMode>
|
||||||
|
</file>
|
||||||
|
</files>
|
||||||
|
|
||||||
|
<dependencySets>
|
||||||
|
<dependencySet>
|
||||||
|
<outputDirectory>/lib</outputDirectory>
|
||||||
|
<fileMode>0444</fileMode>
|
||||||
|
</dependencySet>
|
||||||
|
</dependencySets>
|
||||||
|
</assembly>
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-04
|
||||||
|
*/
|
||||||
|
public class TunnelContext {
|
||||||
|
|
||||||
|
private static final Map<String, TunnelServer> /**/ SERVERS /**/ = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private TunnelContext() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TunnelServer findServer(String serverId) {
|
||||||
|
return SERVERS.get(serverId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void putServer(TunnelServer server) {
|
||||||
|
SERVERS.put(server.getServerId(), server);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void remove(String serverId) {
|
||||||
|
SERVERS.remove(serverId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void close() {
|
||||||
|
SERVERS.values()
|
||||||
|
.forEach(TunnelServer::shutdown);
|
||||||
|
SERVERS.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,379 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.hellobike.base.tunnel.apollo.ApolloConfig;
|
||||||
|
import com.hellobike.base.tunnel.config.*;
|
||||||
|
import com.hellobike.base.tunnel.filter.TableNameFilter;
|
||||||
|
import com.hellobike.base.tunnel.monitor.ExporterConfig;
|
||||||
|
import com.hellobike.base.tunnel.monitor.TunnelExporter;
|
||||||
|
import com.hellobike.base.tunnel.monitor.TunnelMonitorFactory;
|
||||||
|
import com.hellobike.base.tunnel.publisher.PublisherManager;
|
||||||
|
import com.hellobike.base.tunnel.publisher.es.EsPublisher;
|
||||||
|
import com.hellobike.base.tunnel.publisher.hbase.HBasePublisher;
|
||||||
|
import com.hellobike.base.tunnel.publisher.kafka.KafkaPublisher;
|
||||||
|
import com.hellobike.base.tunnel.utils.FileUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.log4j.LogManager;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-11-07
|
||||||
|
*/
|
||||||
|
public class TunnelLauncher {
|
||||||
|
|
||||||
|
private static final Logger /**/ LOGGER /**/ = LoggerFactory.getLogger(TunnelLauncher.class);
|
||||||
|
private static final String /**/ TUNNEL_KEY /**/ = "tunnel_subscribe_config";
|
||||||
|
private static final String /**/ TUNNEL_ZK_KEY /**/ = "tunnel_zookeeper_address";
|
||||||
|
private static final String /**/ CONFIG_PATH /**/ = "conf/tunnel.properties";
|
||||||
|
private static final String /**/ APP_ID /**/ = "AppTunnelService";
|
||||||
|
|
||||||
|
private static final TunnelConfig /**/ TUNNEL_CONFIG /**/ = new TunnelConfig();
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
Map<String, String> cmdArgs = toMap(args);
|
||||||
|
initTunnelConfig(cmdArgs);
|
||||||
|
initTunnelMonitor(cmdArgs);
|
||||||
|
|
||||||
|
ConfigLoader config = ConfigLoaderFactory.getConfigLoader(TUNNEL_CONFIG);
|
||||||
|
|
||||||
|
String configValue = config.getProperty(TUNNEL_KEY, "");
|
||||||
|
if ("".equals(configValue)) {
|
||||||
|
LOGGER.warn("config is null at first setup");
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.info("config value:{}", configValue);
|
||||||
|
String zkAddress = config.getProperty(TUNNEL_ZK_KEY, "");
|
||||||
|
if ("".equals(zkAddress)) {
|
||||||
|
LOGGER.warn("zk address is null");
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
ZkConfig zkConfig = new ZkConfig();
|
||||||
|
zkConfig.setAddress(zkAddress);
|
||||||
|
LOGGER.info("zk address:{}", zkAddress);
|
||||||
|
|
||||||
|
startSubscribe(zkConfig, configValue);
|
||||||
|
config.addChangeListener(((key, oldValue, newValue) -> {
|
||||||
|
if (!TUNNEL_KEY.equals(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
startSubscribe(zkConfig, newValue);
|
||||||
|
}));
|
||||||
|
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
|
TunnelContext.close();
|
||||||
|
LogManager.shutdown();
|
||||||
|
LOGGER.info("TunnelServer Stopped");
|
||||||
|
}));
|
||||||
|
|
||||||
|
LOGGER.info("TunnelServer Started at:{}", TUNNEL_CONFIG.getProcessId());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TunnelConfig getTunnelConfig() {
|
||||||
|
return TUNNEL_CONFIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化Tunnel 配置
|
||||||
|
* <pre>
|
||||||
|
* -d domain
|
||||||
|
* -a app id
|
||||||
|
* -u use apollo
|
||||||
|
* -c config file
|
||||||
|
* -y use yukon
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param cfg 参数
|
||||||
|
*/
|
||||||
|
private static void initTunnelConfig(Map<String, String> cfg) {
|
||||||
|
TUNNEL_CONFIG.setProcessId(getPid());
|
||||||
|
TUNNEL_CONFIG.setAppId(cfg.getOrDefault("-a", APP_ID));
|
||||||
|
TUNNEL_CONFIG.setMetaDomain(cfg.getOrDefault("-d", getMetaDomain()));
|
||||||
|
TUNNEL_CONFIG.setUseApollo("true".equalsIgnoreCase(cfg.getOrDefault("-u", "true")));
|
||||||
|
TUNNEL_CONFIG.setUseYukon("true".equalsIgnoreCase(cfg.getOrDefault("-y", "false")));
|
||||||
|
TUNNEL_CONFIG.setConfigFile(cfg.get("-c"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* -p port
|
||||||
|
* -m metric name
|
||||||
|
* -n logger name
|
||||||
|
* -l labels
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param cfg 参数
|
||||||
|
*/
|
||||||
|
private static void initTunnelMonitor(Map<String, String> cfg) {
|
||||||
|
ExporterConfig config = new ExporterConfig();
|
||||||
|
String port = cfg.get("-p");
|
||||||
|
String metricName = cfg.get("-m");
|
||||||
|
String loggerName = cfg.get("-n");
|
||||||
|
String labelNames = cfg.get("-l");
|
||||||
|
if (StringUtils.isNotBlank(port)) {
|
||||||
|
try {
|
||||||
|
config.setExportPort(Integer.parseInt(port));
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(metricName)) {
|
||||||
|
config.setMetricName(metricName);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(loggerName)) {
|
||||||
|
config.setLoggerName(loggerName);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(labelNames)) {
|
||||||
|
config.setLabelName(labelNames.split(","));
|
||||||
|
}
|
||||||
|
boolean useYukon = "true".equalsIgnoreCase(cfg.getOrDefault("-y", "true"));
|
||||||
|
TunnelExporter exporter = TunnelMonitorFactory.initializeExporter(useYukon, config);
|
||||||
|
|
||||||
|
exporter.startup();
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(exporter::destroy));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, String> toMap(String[] args) {
|
||||||
|
Map<String, String> cfg = new LinkedHashMap<>();
|
||||||
|
if (args == null || args.length == 0) {
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < args.length; i += 2) {
|
||||||
|
try {
|
||||||
|
cfg.put(args[i], args[i + 1]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getPid() {
|
||||||
|
String name = ManagementFactory.getRuntimeMXBean().getName();
|
||||||
|
return Integer.parseInt(name.split("@")[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void startSubscribe(ZkConfig zkConfig, String value) {
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ApolloConfig apolloConfig = JSON.parseObject(value, ApolloConfig.class);
|
||||||
|
|
||||||
|
List<ApolloConfig.Subscribe> subscribes = apolloConfig.getSubscribes();
|
||||||
|
for (ApolloConfig.Subscribe subscribe : subscribes) {
|
||||||
|
TunnelServer newServer = null;
|
||||||
|
TunnelServer oldServer = null;
|
||||||
|
try {
|
||||||
|
SubscribeConfig subscribeConfig = toTunnelConfig(subscribe);
|
||||||
|
subscribeConfig.setZkConfig(zkConfig);
|
||||||
|
newServer = new TunnelServer(subscribeConfig);
|
||||||
|
oldServer = TunnelContext.findServer(newServer.getServerId());
|
||||||
|
if (oldServer != null) {
|
||||||
|
oldServer.shutdown();
|
||||||
|
}
|
||||||
|
TunnelContext.putServer(newServer);
|
||||||
|
newServer.start();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.warn("setup :'" + subscribe.getSlotName() + "' failure", e);
|
||||||
|
//
|
||||||
|
if (oldServer != null) {
|
||||||
|
oldServer.shutdown();
|
||||||
|
TunnelContext.remove(oldServer.getServerId());
|
||||||
|
}
|
||||||
|
if (newServer != null) {
|
||||||
|
newServer.shutdown();
|
||||||
|
TunnelContext.remove(newServer.getServerId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SubscribeConfig toTunnelConfig(ApolloConfig.Subscribe subscribe) {
|
||||||
|
|
||||||
|
String slotName = subscribe.getSlotName();
|
||||||
|
ApolloConfig.EsConf esConf = subscribe.getEsConf();
|
||||||
|
ApolloConfig.KafkaConf kafkaConf = subscribe.getKafkaConf();
|
||||||
|
ApolloConfig.HBaseConf hbaseConf = subscribe.getHbaseConf();
|
||||||
|
ApolloConfig.HiveConf hiveConf = subscribe.getHiveConf();
|
||||||
|
ApolloConfig.HdfsConf hdfsConf = subscribe.getHdfsConf();
|
||||||
|
|
||||||
|
ApolloConfig.PgConnConf pgConnConf = subscribe.getPgConnConf();
|
||||||
|
List<ApolloConfig.Rule> rules = subscribe.getRules();
|
||||||
|
|
||||||
|
parseEsConfig(slotName, esConf, rules);
|
||||||
|
parseKafkaConfig(slotName, kafkaConf, rules);
|
||||||
|
parseHBaseConfig(slotName, hbaseConf, rules);
|
||||||
|
parseHiveConfig(slotName, hiveConf, rules);
|
||||||
|
parseHdfsConfig(slotName, hdfsConf, rules);
|
||||||
|
|
||||||
|
JdbcConfig jdbcConfig = getJdbcConfig(slotName, pgConnConf);
|
||||||
|
SubscribeConfig subscribeConfig = new SubscribeConfig();
|
||||||
|
subscribeConfig.setJdbcConfig(jdbcConfig);
|
||||||
|
subscribeConfig.setServerId(generateServerId(pgConnConf.getHost(), pgConnConf.getPort(), jdbcConfig.getSlotName()));
|
||||||
|
return subscribeConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generate a new serverId
|
||||||
|
*
|
||||||
|
* @param host host
|
||||||
|
* @param port port
|
||||||
|
* @param slot slot
|
||||||
|
* @return serverId
|
||||||
|
*/
|
||||||
|
private static String generateServerId(String host, int port, String slot) {
|
||||||
|
return slot + "@" + host + ":" + port;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parseKafkaConfig(String slotName, ApolloConfig.KafkaConf kafkaConf, List<ApolloConfig.Rule> rules) {
|
||||||
|
if (kafkaConf == null || kafkaConf.getAddrs() == null || kafkaConf.getAddrs().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<KafkaConfig> kafkaConfigs = rules.stream()
|
||||||
|
.map(TunnelLauncher::toKafkaConfig)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.peek(cfg -> cfg.setServer(StringUtils.join(kafkaConf.getAddrs(), ",")))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
PublisherManager.getInstance().putPublisher(slotName, new KafkaPublisher(kafkaConfigs));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parseEsConfig(String slotName, ApolloConfig.EsConf esConf, List<ApolloConfig.Rule> rules) {
|
||||||
|
if (esConf == null || esConf.getAddrs() == null || esConf.getAddrs().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<EsConfig> esConfigs = rules.stream()
|
||||||
|
.map(TunnelLauncher::toEsConfig)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.peek(esConfig -> esConfig.setServer(esConf.getAddrs()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
PublisherManager.getInstance().putPublisher(slotName, new EsPublisher(esConfigs));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parseHBaseConfig(String slotName, ApolloConfig.HBaseConf hbaseConf, List<ApolloConfig.Rule> rules) {
|
||||||
|
|
||||||
|
if (hbaseConf == null || StringUtils.isBlank(hbaseConf.getZkquorum())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<HBaseConfig> configs = rules.stream()
|
||||||
|
.map(TunnelLauncher::toHBaseConfig)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.peek(config -> config.setQuorum(hbaseConf.getZkquorum()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
PublisherManager.getInstance().putPublisher(slotName, new HBasePublisher(configs));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parseHiveConfig(String slotName, ApolloConfig.HiveConf hiveConf, List<ApolloConfig.Rule> rules) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parseHdfsConfig(String slotName, ApolloConfig.HdfsConf hdfsConf, List<ApolloConfig.Rule> rules) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static KafkaConfig toKafkaConfig(ApolloConfig.Rule rule) {
|
||||||
|
if (StringUtils.isBlank(rule.getTopic())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
KafkaConfig kafkaConfig = new KafkaConfig();
|
||||||
|
kafkaConfig.setTopic(rule.getTopic());
|
||||||
|
kafkaConfig.setPartition(rule.getPartition());
|
||||||
|
kafkaConfig.setFilters(Collections.singletonList(new TableNameFilter(rule.getTable())));
|
||||||
|
kafkaConfig.setPkNames(new ArrayList<>(rule.getPks()));
|
||||||
|
|
||||||
|
return kafkaConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EsConfig toEsConfig(ApolloConfig.Rule rule) {
|
||||||
|
if (StringUtils.isBlank(rule.getTable())
|
||||||
|
|| StringUtils.isBlank(rule.getIndex())
|
||||||
|
|| StringUtils.isBlank(rule.getType())
|
||||||
|
|| rule.getPks() == null
|
||||||
|
|| rule.getEsid() == null
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
EsConfig esConfig = new EsConfig();
|
||||||
|
esConfig.setTable(rule.getTable());
|
||||||
|
esConfig.setIndex(rule.getIndex());
|
||||||
|
esConfig.setType(rule.getType());
|
||||||
|
esConfig.setPkFieldNames(new ArrayList<>(rule.getPks()));
|
||||||
|
esConfig.setEsIdFieldNames(new ArrayList<>(rule.getEsid()));
|
||||||
|
esConfig.setFieldMappings(rule.getFields() == null ? new HashMap<>() : new HashMap<>(rule.getFields()));
|
||||||
|
esConfig.setFilters(Collections.singletonList(new TableNameFilter(esConfig.getTable())));
|
||||||
|
|
||||||
|
esConfig.setSql(rule.getSql());
|
||||||
|
esConfig.setParameters(rule.getParameters());
|
||||||
|
|
||||||
|
return esConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HBaseConfig toHBaseConfig(ApolloConfig.Rule rule) {
|
||||||
|
HBaseConfig config = new HBaseConfig();
|
||||||
|
config.setPks(rule.getPks());
|
||||||
|
config.setHbaseKey(rule.getHbaseKey());
|
||||||
|
config.setHbaseTable(rule.getHbaseTable());
|
||||||
|
config.setTable(rule.getTable());
|
||||||
|
config.setFamily(StringUtils.isBlank(rule.getFamily()) ? "data" : rule.getFamily());
|
||||||
|
config.setQualifier(StringUtils.isBlank(rule.getQualifier()) ? "bytes" : rule.getQualifier());
|
||||||
|
config.setFilters(Collections.singletonList(new TableNameFilter(rule.getTable())));
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JdbcConfig getJdbcConfig(String slotName, ApolloConfig.PgConnConf pgConnConf) {
|
||||||
|
String jdbcUrl = "jdbc:postgresql://" + pgConnConf.getHost() + ":" + pgConnConf.getPort() + "/" + pgConnConf.getDatabase();
|
||||||
|
JdbcConfig jdbcConfig = new JdbcConfig();
|
||||||
|
jdbcConfig.setSlotName(slotName);
|
||||||
|
jdbcConfig.setUrl(jdbcUrl);
|
||||||
|
jdbcConfig.setUsername(pgConnConf.getUser());
|
||||||
|
jdbcConfig.setPassword(pgConnConf.getPassword());
|
||||||
|
jdbcConfig.setHost(pgConnConf.getHost());
|
||||||
|
jdbcConfig.setPort(pgConnConf.getPort());
|
||||||
|
jdbcConfig.setSchema(pgConnConf.getDatabase());
|
||||||
|
return jdbcConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getMetaDomain() {
|
||||||
|
InputStream is = FileUtils.load(CONFIG_PATH);
|
||||||
|
if (is == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
Properties prop = new Properties();
|
||||||
|
try {
|
||||||
|
prop.load(is);
|
||||||
|
} catch (IOException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
return prop.getProperty("tunnel.apollo.meta.domain", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,246 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.config.JdbcConfig;
|
||||||
|
import com.hellobike.base.tunnel.config.SubscribeConfig;
|
||||||
|
import com.hellobike.base.tunnel.ha.ZkLock;
|
||||||
|
import com.hellobike.base.tunnel.model.InvokeContext;
|
||||||
|
import com.hellobike.base.tunnel.parse.EventParser;
|
||||||
|
import com.hellobike.base.tunnel.parse.IEventParser;
|
||||||
|
import com.hellobike.base.tunnel.utils.TimeUtils;
|
||||||
|
import org.postgresql.PGConnection;
|
||||||
|
import org.postgresql.PGProperty;
|
||||||
|
import org.postgresql.replication.LogSequenceNumber;
|
||||||
|
import org.postgresql.replication.PGReplicationStream;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-11-23
|
||||||
|
*/
|
||||||
|
public class TunnelServer {
|
||||||
|
|
||||||
|
private static final Logger /**/ log = LoggerFactory.getLogger(TunnelServer.class);
|
||||||
|
|
||||||
|
private final String /**/ serverId;
|
||||||
|
private final SubscribeConfig /**/ config;
|
||||||
|
private final JdbcConfig /**/ jdbcConfig;
|
||||||
|
private final IEventParser /**/ eventParser = new EventParser();
|
||||||
|
private final ZkLock /**/ zkLock;
|
||||||
|
private final String /**/ slotName;
|
||||||
|
private final ReentrantLock /**/ lock = new ReentrantLock();
|
||||||
|
|
||||||
|
private final Thread /**/ startThread;
|
||||||
|
private final Thread /**/ receiveThread;
|
||||||
|
|
||||||
|
private volatile boolean /**/ started = false;
|
||||||
|
private Connection /**/ connection;
|
||||||
|
private PGConnection /**/ rplConnection;
|
||||||
|
private PGReplicationStream /**/ stream;
|
||||||
|
|
||||||
|
public TunnelServer(SubscribeConfig config) {
|
||||||
|
this.serverId = config.getServerId();
|
||||||
|
this.config = config;
|
||||||
|
this.jdbcConfig = config.getJdbcConfig();
|
||||||
|
this.slotName = this.jdbcConfig.getSlotName();
|
||||||
|
this.zkLock = new ZkLock(this.config.getZkConfig().getAddress(), generateLockKey(config.getJdbcConfig()));
|
||||||
|
this.startThread = new Thread(new StartTask(), "TunnelStartThread-" + this.slotName);
|
||||||
|
this.receiveThread = new Thread(new ReceiveTask(), "TunnelReceiveThread-" + this.slotName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String generateLockKey(JdbcConfig config) {
|
||||||
|
return "/com/hellobike/base/tunnel/lock/" + config.getHost() + ":" + config.getPort() + "/" + config.getSchema() + "/" + config.getSlotName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void closeClosable(AutoCloseable closeable) {
|
||||||
|
if (closeable != null) {
|
||||||
|
try {
|
||||||
|
closeable.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
this.startThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
started = false;
|
||||||
|
closeClosable(this.stream);
|
||||||
|
closeClosable(this.connection);
|
||||||
|
zkLock.unlock();
|
||||||
|
zkLock.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerId() {
|
||||||
|
return serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createRplConn() throws SQLException {
|
||||||
|
String url = this.jdbcConfig.getUrl();
|
||||||
|
Properties props = new Properties();
|
||||||
|
PGProperty.USER.set(props, this.jdbcConfig.getUsername());
|
||||||
|
PGProperty.PASSWORD.set(props, this.jdbcConfig.getPassword());
|
||||||
|
PGProperty.ASSUME_MIN_SERVER_VERSION.set(props, this.jdbcConfig.getMinVersion());
|
||||||
|
PGProperty.REPLICATION.set(props, this.jdbcConfig.getRplLevel());
|
||||||
|
PGProperty.PREFER_QUERY_MODE.set(props, "simple");
|
||||||
|
|
||||||
|
this.connection = DriverManager.getConnection(url, props);
|
||||||
|
this.rplConnection = this.connection.unwrap(PGConnection.class);
|
||||||
|
log.info("GetRplConnection success,slot:{}", this.slotName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createRplSlot() throws SQLException {
|
||||||
|
try {
|
||||||
|
this.rplConnection.getReplicationAPI()
|
||||||
|
.createReplicationSlot()
|
||||||
|
.logical()
|
||||||
|
.withSlotName(this.jdbcConfig.getSlotName())
|
||||||
|
.withOutputPlugin("test_decoding")
|
||||||
|
.make();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
String msg = "ERROR: replication slot \"" + this.jdbcConfig.getSlotName() + "\" already exists";
|
||||||
|
if (msg.equals(e.getMessage())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
log.info("GetRplSlot success,slot:{}", this.slotName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createRplStream() throws SQLException {
|
||||||
|
this.stream = this.rplConnection.getReplicationAPI()
|
||||||
|
.replicationStream()
|
||||||
|
.logical()
|
||||||
|
.withSlotName(this.jdbcConfig.getSlotName())
|
||||||
|
.withSlotOption("include-xids", true)
|
||||||
|
.withSlotOption("skip-empty-xacts", true)
|
||||||
|
.withStatusInterval(5, TimeUnit.SECONDS)
|
||||||
|
.start();
|
||||||
|
log.info("GetRplStream success,slot:{}", this.slotName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void receiveStream() throws SQLException {
|
||||||
|
|
||||||
|
assert !stream.isClosed();
|
||||||
|
assert !connection.isClosed();
|
||||||
|
|
||||||
|
//non blocking receive message
|
||||||
|
ByteBuffer msg = stream.readPending();
|
||||||
|
|
||||||
|
if (msg == null) {
|
||||||
|
TimeUtils.sleepInMills(10L);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int offset = msg.arrayOffset();
|
||||||
|
byte[] source = msg.array();
|
||||||
|
int length = source.length - offset;
|
||||||
|
LogSequenceNumber lsn = stream.getLastReceiveLSN();
|
||||||
|
|
||||||
|
InvokeContext ctx = new InvokeContext();
|
||||||
|
ctx.setMessage(new String(source, offset, length));
|
||||||
|
ctx.setJdbcUrl(this.jdbcConfig.getUrl());
|
||||||
|
ctx.setJdbcUser(this.jdbcConfig.getUsername());
|
||||||
|
ctx.setJdbcPass(this.jdbcConfig.getPassword());
|
||||||
|
ctx.setSlotName(this.slotName);
|
||||||
|
ctx.setServerId(this.serverId);
|
||||||
|
ctx.setLsn(lsn.asLong());
|
||||||
|
|
||||||
|
eventParser.parse(ctx);
|
||||||
|
|
||||||
|
|
||||||
|
//feedback
|
||||||
|
stream.setAppliedLSN(lsn);
|
||||||
|
stream.setFlushedLSN(lsn);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recover() {
|
||||||
|
this.lock.lock();
|
||||||
|
try {
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
closeClosable(stream);
|
||||||
|
closeClosable(connection);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
createRplConn();
|
||||||
|
createRplSlot();
|
||||||
|
createRplStream();
|
||||||
|
break;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Recover Streaming Occurred Error", e);
|
||||||
|
closeClosable(stream);
|
||||||
|
closeClosable(connection);
|
||||||
|
TimeUtils.sleepInMills(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long e = System.currentTimeMillis();
|
||||||
|
log.info("recover logical replication success,slot:{},cost:{}ms", slotName, e - s);
|
||||||
|
} finally {
|
||||||
|
this.lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class StartTask implements Runnable {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (zkLock.tryLock()) {
|
||||||
|
try {
|
||||||
|
createRplConn();
|
||||||
|
createRplSlot();
|
||||||
|
createRplStream();
|
||||||
|
started = true;
|
||||||
|
receiveThread.start();
|
||||||
|
log.warn("Startup RplStream Success");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Startup RplStream Failure", e);
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ReceiveTask implements Runnable {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (started) {
|
||||||
|
try {
|
||||||
|
receiveStream();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("receive msg failure,try to recover.", e);
|
||||||
|
recover();
|
||||||
|
TimeUtils.sleepInMills(2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,418 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.apollo;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 这个是兼容代码
|
||||||
|
*
|
||||||
|
* @author machunxiao 2018-11-01
|
||||||
|
*/
|
||||||
|
public class ApolloConfig {
|
||||||
|
|
||||||
|
@JSONField(name = "pg_dump_path")
|
||||||
|
private String pgDumpPath;
|
||||||
|
private List<Subscribe> subscribes;
|
||||||
|
|
||||||
|
public String getPgDumpPath() {
|
||||||
|
return pgDumpPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPgDumpPath(String pgDumpPath) {
|
||||||
|
this.pgDumpPath = pgDumpPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Subscribe> getSubscribes() {
|
||||||
|
return subscribes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubscribes(List<Subscribe> subscribes) {
|
||||||
|
this.subscribes = subscribes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Subscribe {
|
||||||
|
|
||||||
|
private String slotName;
|
||||||
|
private PgConnConf pgConnConf;
|
||||||
|
private List<Rule> rules;
|
||||||
|
private KafkaConf kafkaConf;
|
||||||
|
private EsConf esConf;
|
||||||
|
private HBaseConf hbaseConf;
|
||||||
|
private HiveConf hiveConf;
|
||||||
|
private HdfsConf hdfsConf;
|
||||||
|
|
||||||
|
|
||||||
|
public String getSlotName() {
|
||||||
|
return slotName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSlotName(String slotName) {
|
||||||
|
this.slotName = slotName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgConnConf getPgConnConf() {
|
||||||
|
return pgConnConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPgConnConf(PgConnConf pgConnConf) {
|
||||||
|
this.pgConnConf = pgConnConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Rule> getRules() {
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRules(List<Rule> rules) {
|
||||||
|
this.rules = rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KafkaConf getKafkaConf() {
|
||||||
|
return kafkaConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKafkaConf(KafkaConf kafkaConf) {
|
||||||
|
this.kafkaConf = kafkaConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EsConf getEsConf() {
|
||||||
|
return esConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEsConf(EsConf esConf) {
|
||||||
|
this.esConf = esConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HBaseConf getHbaseConf() {
|
||||||
|
return hbaseConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHbaseConf(HBaseConf hbaseConf) {
|
||||||
|
this.hbaseConf = hbaseConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HiveConf getHiveConf() {
|
||||||
|
return hiveConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHiveConf(HiveConf hiveConf) {
|
||||||
|
this.hiveConf = hiveConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HdfsConf getHdfsConf() {
|
||||||
|
return hdfsConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHdfsConf(HdfsConf hdfsConf) {
|
||||||
|
this.hdfsConf = hdfsConf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PgConnConf {
|
||||||
|
private String host;
|
||||||
|
private int port;
|
||||||
|
private String database;
|
||||||
|
private String schema;
|
||||||
|
private String user;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDatabase() {
|
||||||
|
return database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDatabase(String database) {
|
||||||
|
this.database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSchema() {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchema(String schema) {
|
||||||
|
this.schema = schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(String user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class KafkaConf {
|
||||||
|
private List<String> addrs;
|
||||||
|
|
||||||
|
public List<String> getAddrs() {
|
||||||
|
return addrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddrs(List<String> addrs) {
|
||||||
|
this.addrs = addrs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EsConf {
|
||||||
|
private String addrs;
|
||||||
|
|
||||||
|
public String getAddrs() {
|
||||||
|
return addrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddrs(String addrs) {
|
||||||
|
this.addrs = addrs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HBaseConf {
|
||||||
|
private String zkquorum;
|
||||||
|
|
||||||
|
public String getZkquorum() {
|
||||||
|
return zkquorum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZkquorum(String zkquorum) {
|
||||||
|
this.zkquorum = zkquorum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HiveConf {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HdfsConf {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Rule {
|
||||||
|
|
||||||
|
private String table;
|
||||||
|
|
||||||
|
private String topic;
|
||||||
|
private int partition;
|
||||||
|
|
||||||
|
private List<String> pks;
|
||||||
|
private List<String> esid;
|
||||||
|
private String index;
|
||||||
|
private String type;
|
||||||
|
private Map<String, String> fields;
|
||||||
|
|
||||||
|
|
||||||
|
private String sql;
|
||||||
|
private List<String> parameters;
|
||||||
|
|
||||||
|
private String family;
|
||||||
|
private String qualifier;
|
||||||
|
private List<String> rowKeys;
|
||||||
|
|
||||||
|
private String hbaseTable;
|
||||||
|
private List<String> hbaseKey;
|
||||||
|
|
||||||
|
public String getTable() {
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTable(String table) {
|
||||||
|
this.table = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTopic() {
|
||||||
|
return topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopic(String topic) {
|
||||||
|
this.topic = topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPartition() {
|
||||||
|
return partition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPartition(int partition) {
|
||||||
|
this.partition = partition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPks() {
|
||||||
|
return pks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPks(List<String> pks) {
|
||||||
|
this.pks = pks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getEsid() {
|
||||||
|
return esid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEsid(List<String> esid) {
|
||||||
|
this.esid = esid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndex(String index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getFields() {
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFields(Map<String, String> fields) {
|
||||||
|
this.fields = fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSql() {
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSql(String sql) {
|
||||||
|
this.sql = sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getParameters() {
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParameters(List<String> parameters) {
|
||||||
|
this.parameters = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFamily() {
|
||||||
|
return family;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFamily(String family) {
|
||||||
|
this.family = family;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQualifier() {
|
||||||
|
return qualifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQualifier(String qualifier) {
|
||||||
|
this.qualifier = qualifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getRowKeys() {
|
||||||
|
return rowKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRowKeys(List<String> rowKeys) {
|
||||||
|
this.rowKeys = rowKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHbaseTable() {
|
||||||
|
return hbaseTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHbaseTable(String hbaseTable) {
|
||||||
|
this.hbaseTable = hbaseTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getHbaseKey() {
|
||||||
|
return hbaseKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHbaseKey(List<String> hbaseKey) {
|
||||||
|
this.hbaseKey = hbaseKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 例如在es索引中,一个复合索引 es_idx_t1包含10个字段,其中5个来自tb1,5个来自tb2,
|
||||||
|
* 当tb1或者tb2有新增或删除的时候,查询另外一个表的内容,添加到索引中
|
||||||
|
*
|
||||||
|
* val: insert into tb1(id1,name1,age1) values('id1','name1','age1');
|
||||||
|
*
|
||||||
|
* sql: select id2,name2,age2 from tb2 where id = @id and name= @name
|
||||||
|
*
|
||||||
|
* idx: append into es1(id1,id2,name1,name2,age1,age2) values()
|
||||||
|
*
|
||||||
|
* 假设目前只支持根据主键的join
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public static class Join {
|
||||||
|
|
||||||
|
private String table;
|
||||||
|
private String sql;
|
||||||
|
private List<String> parameters;
|
||||||
|
|
||||||
|
public String getTable() {
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTable(String table) {
|
||||||
|
this.table = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSql() {
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSql(String sql) {
|
||||||
|
this.sql = sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getParameters() {
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParameters(List<String> parameters) {
|
||||||
|
this.parameters = parameters;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.apollo;
|
||||||
|
|
||||||
|
import com.ctrip.framework.apollo.Config;
|
||||||
|
import com.ctrip.framework.apollo.ConfigChangeListener;
|
||||||
|
import com.ctrip.framework.apollo.ConfigService;
|
||||||
|
import com.ctrip.framework.apollo.model.ConfigChange;
|
||||||
|
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
|
||||||
|
import com.hellobike.base.tunnel.config.ConfigListener;
|
||||||
|
import com.hellobike.base.tunnel.config.ConfigLoader;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-26
|
||||||
|
*/
|
||||||
|
public class ApolloConfigLoader implements ConfigLoader {
|
||||||
|
|
||||||
|
private final Config config;
|
||||||
|
|
||||||
|
public ApolloConfigLoader(String appId, String metaDomain) {
|
||||||
|
this.config = ConfigService.getAppConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProperty(String key, String defaultValue) {
|
||||||
|
return this.config.getProperty(key, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addChangeListener(ConfigListener configListener) {
|
||||||
|
this.config.addChangeListener(new ApolloInnerConfigListener(configListener));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ApolloInnerConfigListener implements ConfigChangeListener {
|
||||||
|
|
||||||
|
private final ConfigListener configListener;
|
||||||
|
|
||||||
|
public ApolloInnerConfigListener(ConfigListener configListener) {
|
||||||
|
this.configListener = configListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChange(ConfigChangeEvent changeEvent) {
|
||||||
|
Set<String> keys = changeEvent.changedKeys();
|
||||||
|
for (String key : keys) {
|
||||||
|
ConfigChange change = changeEvent.getChange(key);
|
||||||
|
if (change == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String oldValue = change.getOldValue();
|
||||||
|
String newValue = change.getNewValue();
|
||||||
|
configListener.onChange(key, oldValue, newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-26
|
||||||
|
*/
|
||||||
|
public interface ConfigListener {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听值变化
|
||||||
|
*
|
||||||
|
* @param key 键值
|
||||||
|
* @param oldValue 旧值
|
||||||
|
* @param newValue 新值
|
||||||
|
*/
|
||||||
|
void onChange(String key, String oldValue, String newValue);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-26
|
||||||
|
*/
|
||||||
|
public interface ConfigLoader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置
|
||||||
|
*
|
||||||
|
* @param key key
|
||||||
|
* @param defaultValue 默认值
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String getProperty(String key, String defaultValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加事件监听器
|
||||||
|
*
|
||||||
|
* @param configListener 监听器
|
||||||
|
*/
|
||||||
|
void addChangeListener(ConfigListener configListener);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.config;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.apollo.ApolloConfigLoader;
|
||||||
|
import com.hellobike.base.tunnel.config.file.FileConfigLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-27
|
||||||
|
*/
|
||||||
|
public class ConfigLoaderFactory {
|
||||||
|
|
||||||
|
private ConfigLoaderFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConfigLoader getConfigLoader(TunnelConfig tunnelConfig) {
|
||||||
|
if (tunnelConfig.isUseApollo()) {
|
||||||
|
return new ApolloConfigLoader(tunnelConfig.getAppId(), tunnelConfig.getMetaDomain());
|
||||||
|
}
|
||||||
|
return new FileConfigLoader(tunnelConfig.getConfigFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,151 @@
|
|||||||
|
package com.hellobike.base.tunnel.config;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.filter.IEventFilter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-11-01
|
||||||
|
*/
|
||||||
|
public class EsConfig {
|
||||||
|
|
||||||
|
private String server;
|
||||||
|
private String schema;
|
||||||
|
private String table;
|
||||||
|
|
||||||
|
private String index;
|
||||||
|
private String type;
|
||||||
|
private Map<String, String> fieldMappings;
|
||||||
|
private List<String> pkFieldNames;
|
||||||
|
private List<String> esIdFieldNames;
|
||||||
|
|
||||||
|
private String separator = ";";
|
||||||
|
|
||||||
|
private String dstTable;
|
||||||
|
private String sql;
|
||||||
|
private List<String> parameters;
|
||||||
|
|
||||||
|
private List<IEventFilter> filters = new ArrayList<>();
|
||||||
|
|
||||||
|
public String getServer() {
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServer(String server) {
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSchema() {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchema(String schema) {
|
||||||
|
this.schema = schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTable() {
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTable(String table) {
|
||||||
|
this.table = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndex(String index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getFieldMappings() {
|
||||||
|
return fieldMappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldMappings(Map<String, String> fieldMappings) {
|
||||||
|
this.fieldMappings = fieldMappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPkFieldNames() {
|
||||||
|
return pkFieldNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPkFieldNames(List<String> pkFieldNames) {
|
||||||
|
this.pkFieldNames = pkFieldNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getEsIdFieldNames() {
|
||||||
|
return esIdFieldNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEsIdFieldNames(List<String> esIdFieldNames) {
|
||||||
|
this.esIdFieldNames = esIdFieldNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSeparator() {
|
||||||
|
return separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeparator(String separator) {
|
||||||
|
this.separator = separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IEventFilter> getFilters() {
|
||||||
|
return filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilters(List<IEventFilter> filters) {
|
||||||
|
this.filters = filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDstTable() {
|
||||||
|
return dstTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDstTable(String dstTable) {
|
||||||
|
this.dstTable = dstTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSql() {
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSql(String sql) {
|
||||||
|
this.sql = sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getParameters() {
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParameters(List<String> parameters) {
|
||||||
|
this.parameters = parameters;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,103 @@
|
|||||||
|
package com.hellobike.base.tunnel.config;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.filter.IEventFilter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-10
|
||||||
|
*/
|
||||||
|
public class HBaseConfig {
|
||||||
|
|
||||||
|
private String table;
|
||||||
|
private List<String> pks;
|
||||||
|
private String hbaseTable;
|
||||||
|
private List<String> hbaseKey;
|
||||||
|
|
||||||
|
private String family;
|
||||||
|
private String qualifier;
|
||||||
|
|
||||||
|
private String quorum;
|
||||||
|
|
||||||
|
private List<IEventFilter> filters;
|
||||||
|
|
||||||
|
public String getTable() {
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTable(String table) {
|
||||||
|
this.table = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPks() {
|
||||||
|
return pks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPks(List<String> pks) {
|
||||||
|
this.pks = pks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHbaseTable() {
|
||||||
|
return hbaseTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHbaseTable(String hbaseTable) {
|
||||||
|
this.hbaseTable = hbaseTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getHbaseKey() {
|
||||||
|
return hbaseKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHbaseKey(List<String> hbaseKey) {
|
||||||
|
this.hbaseKey = hbaseKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFamily() {
|
||||||
|
return family;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFamily(String family) {
|
||||||
|
this.family = family;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQualifier() {
|
||||||
|
return qualifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQualifier(String qualifier) {
|
||||||
|
this.qualifier = qualifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQuorum() {
|
||||||
|
return quorum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQuorum(String quorum) {
|
||||||
|
this.quorum = quorum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IEventFilter> getFilters() {
|
||||||
|
return filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilters(List<IEventFilter> filters) {
|
||||||
|
this.filters = filters;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package com.hellobike.base.tunnel.config;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-10
|
||||||
|
*/
|
||||||
|
public class HdfsConfig {
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package com.hellobike.base.tunnel.config;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-10
|
||||||
|
*/
|
||||||
|
public class HiveConfig {
|
||||||
|
}
|
||||||
@ -0,0 +1,113 @@
|
|||||||
|
package com.hellobike.base.tunnel.config;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-11-01
|
||||||
|
*/
|
||||||
|
public class JdbcConfig {
|
||||||
|
private String url;
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private String slotName;
|
||||||
|
private String lastLsn = "";
|
||||||
|
private String minVersion = "9.4";
|
||||||
|
private String rplLevel = "database";
|
||||||
|
private String host;
|
||||||
|
private int port;
|
||||||
|
private String schema;
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSlotName() {
|
||||||
|
return slotName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSlotName(String slotName) {
|
||||||
|
this.slotName = slotName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastLsn() {
|
||||||
|
return lastLsn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastLsn(String lastLsn) {
|
||||||
|
this.lastLsn = lastLsn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMinVersion() {
|
||||||
|
return minVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinVersion(String minVersion) {
|
||||||
|
this.minVersion = minVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRplLevel() {
|
||||||
|
return rplLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRplLevel(String rplLevel) {
|
||||||
|
this.rplLevel = rplLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSchema() {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchema(String schema) {
|
||||||
|
this.schema = schema;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,110 @@
|
|||||||
|
package com.hellobike.base.tunnel.config;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.filter.IEventFilter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-11-01
|
||||||
|
*/
|
||||||
|
public class KafkaConfig {
|
||||||
|
|
||||||
|
private String topic;
|
||||||
|
private String server;
|
||||||
|
private String ackConfig = "all";
|
||||||
|
private int retryTimes;
|
||||||
|
private String keySerializer = "org.apache.kafka.common.serialization.StringSerializer";
|
||||||
|
private String valSerializer = "org.apache.kafka.common.serialization.StringSerializer";
|
||||||
|
private int partition = 0;
|
||||||
|
private List<IEventFilter> filters;
|
||||||
|
|
||||||
|
private List<String> pkNames;
|
||||||
|
|
||||||
|
public String getTopic() {
|
||||||
|
return topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopic(String topic) {
|
||||||
|
this.topic = topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServer() {
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServer(String server) {
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAckConfig() {
|
||||||
|
return ackConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAckConfig(String ackConfig) {
|
||||||
|
this.ackConfig = ackConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRetryTimes() {
|
||||||
|
return retryTimes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRetryTimes(int retryTimes) {
|
||||||
|
this.retryTimes = retryTimes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeySerializer() {
|
||||||
|
return keySerializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeySerializer(String keySerializer) {
|
||||||
|
this.keySerializer = keySerializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValSerializer() {
|
||||||
|
return valSerializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValSerializer(String valSerializer) {
|
||||||
|
this.valSerializer = valSerializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPartition() {
|
||||||
|
return partition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPartition(int partition) {
|
||||||
|
this.partition = partition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IEventFilter> getFilters() {
|
||||||
|
return filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilters(List<IEventFilter> filters) {
|
||||||
|
this.filters = filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPkNames() {
|
||||||
|
return pkNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPkNames(List<String> pkNames) {
|
||||||
|
this.pkNames = pkNames;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-26
|
||||||
|
*/
|
||||||
|
public class SubscribeConfig {
|
||||||
|
|
||||||
|
private String serverId;
|
||||||
|
private JdbcConfig jdbcConfig;
|
||||||
|
private ZkConfig zkConfig;
|
||||||
|
|
||||||
|
public String getServerId() {
|
||||||
|
return serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerId(String serverId) {
|
||||||
|
this.serverId = serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JdbcConfig getJdbcConfig() {
|
||||||
|
return jdbcConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJdbcConfig(JdbcConfig jdbcConfig) {
|
||||||
|
this.jdbcConfig = jdbcConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZkConfig getZkConfig() {
|
||||||
|
return zkConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZkConfig(ZkConfig zkConfig) {
|
||||||
|
this.zkConfig = zkConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-27
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TunnelConfig {
|
||||||
|
|
||||||
|
private String appId;
|
||||||
|
private String metaDomain;
|
||||||
|
private String configFile;
|
||||||
|
|
||||||
|
private boolean useApollo;
|
||||||
|
private boolean useYukon;
|
||||||
|
|
||||||
|
private int processId;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-11-07
|
||||||
|
*/
|
||||||
|
public class ZkConfig {
|
||||||
|
|
||||||
|
private String address = "localhost:2181";
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.config.file;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.config.ConfigListener;
|
||||||
|
import com.hellobike.base.tunnel.config.ConfigLoader;
|
||||||
|
import com.hellobike.base.tunnel.utils.NamedThreadFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-26
|
||||||
|
*/
|
||||||
|
public class FileConfigLoader implements ConfigLoader, AutoCloseable {
|
||||||
|
|
||||||
|
private File file;
|
||||||
|
|
||||||
|
private Map<String, String> properties = new ConcurrentHashMap<>();
|
||||||
|
private List<ConfigListener> listeners = new CopyOnWriteArrayList<>();
|
||||||
|
private ExecutorService executor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1), new NamedThreadFactory("FileWatcherThread"));
|
||||||
|
private AtomicBoolean started = new AtomicBoolean(Boolean.FALSE);
|
||||||
|
|
||||||
|
public FileConfigLoader(String fileName) {
|
||||||
|
this.file = new File(fileName);
|
||||||
|
this.properties.putAll(load(this.file));
|
||||||
|
addFileWatcher(this.file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, String> load(File file) {
|
||||||
|
Map<String, String> data = new LinkedHashMap<>();
|
||||||
|
try {
|
||||||
|
Properties prop = new Properties();
|
||||||
|
prop.load(new FileInputStream(file));
|
||||||
|
for (Map.Entry<Object, Object> e : prop.entrySet()) {
|
||||||
|
Object key = e.getKey();
|
||||||
|
Object value = e.getValue();
|
||||||
|
if (key != null) {
|
||||||
|
data.put((String) key, (String) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProperty(String key, String defaultValue) {
|
||||||
|
return properties.getOrDefault(key, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addChangeListener(ConfigListener configListener) {
|
||||||
|
if (!this.listeners.contains(configListener)) {
|
||||||
|
this.listeners.add(configListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
this.started.compareAndSet(Boolean.TRUE, Boolean.FALSE);
|
||||||
|
this.executor.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFileWatcher(File file) {
|
||||||
|
FileWatchTask fileWatchTask = new FileWatchTask(file);
|
||||||
|
|
||||||
|
this.started.compareAndSet(Boolean.FALSE, Boolean.TRUE);
|
||||||
|
this.executor.submit(fileWatchTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ThreeTuple<O1, O2, O3> {
|
||||||
|
|
||||||
|
private O1 k1;
|
||||||
|
private O2 v1;
|
||||||
|
private O3 v2;
|
||||||
|
|
||||||
|
private ThreeTuple(O1 k1, O2 v1, O3 v2) {
|
||||||
|
this.k1 = k1;
|
||||||
|
this.v1 = v1;
|
||||||
|
this.v2 = v2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean valueEquals() {
|
||||||
|
if (v1 == null) {
|
||||||
|
return v2 == null;
|
||||||
|
}
|
||||||
|
return v1.equals(v2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FileWatchTask implements Runnable {
|
||||||
|
|
||||||
|
private File file;
|
||||||
|
|
||||||
|
private FileWatchTask(File file) {
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
|
||||||
|
Path dir = Paths.get(this.file.getParent());
|
||||||
|
dir.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
|
||||||
|
|
||||||
|
while (started.get()) {
|
||||||
|
try {
|
||||||
|
WatchKey key = watchService.poll(50, TimeUnit.MILLISECONDS);
|
||||||
|
if (key == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (WatchEvent<?> event : key.pollEvents()) {
|
||||||
|
WatchEvent.Kind<?> kind = event.kind();
|
||||||
|
List<ThreeTuple<String, String, String>> data = new ArrayList<>();
|
||||||
|
Path path = (Path) event.context();
|
||||||
|
if (!path.toFile().getName().equals(this.file.getName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (kind == StandardWatchEventKinds.ENTRY_MODIFY) {
|
||||||
|
Map<String, String> newData = load(this.file);
|
||||||
|
mergeData(properties, newData, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDataChange(data);
|
||||||
|
}
|
||||||
|
key.reset();
|
||||||
|
|
||||||
|
} catch (Throwable e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Throwable t) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void mergeData(Map<String, String> oldProp, Map<String, String> newProp, List<ThreeTuple<String, String, String>> data) {
|
||||||
|
Map<String, ThreeTuple<String, String, String>> tmp = new LinkedHashMap<>();
|
||||||
|
for (Map.Entry<String, String> e : oldProp.entrySet()) {
|
||||||
|
String key = e.getKey();
|
||||||
|
String oldVal = e.getValue();
|
||||||
|
String newVal = newProp.get(key);
|
||||||
|
|
||||||
|
if (newVal == null) {
|
||||||
|
oldProp.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp.put(key, new ThreeTuple<>(key, oldVal, newVal));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<String, String> e : newProp.entrySet()) {
|
||||||
|
String key = e.getKey();
|
||||||
|
String newVal = e.getValue();
|
||||||
|
|
||||||
|
String oldVal = oldProp.putIfAbsent(key, newVal);
|
||||||
|
|
||||||
|
tmp.putIfAbsent(key, new ThreeTuple<>(key, oldVal, newVal));
|
||||||
|
}
|
||||||
|
|
||||||
|
data.addAll(new ArrayList<>(tmp.values()));
|
||||||
|
oldProp.clear();
|
||||||
|
oldProp.putAll(newProp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDataChange(List<ThreeTuple<String, String, String>> data) {
|
||||||
|
for (ThreeTuple<String, String, String> tuple : data) {
|
||||||
|
for (ConfigListener listener : listeners) {
|
||||||
|
if (!tuple.valueEquals()) {
|
||||||
|
listener.onChange(tuple.k1, tuple.v1, tuple.v2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
package com.hellobike.base.tunnel.filter;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.ColumnData;
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-30
|
||||||
|
*/
|
||||||
|
public class ColumnFilter implements IEventFilter {
|
||||||
|
|
||||||
|
private final List<String> columnNames;
|
||||||
|
|
||||||
|
public ColumnFilter(List<String> columnNames) {
|
||||||
|
this.columnNames = columnNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean filter(Event event) {
|
||||||
|
|
||||||
|
if (columnNames == null || columnNames.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ColumnData> dataList = event.getDataList()
|
||||||
|
.stream()
|
||||||
|
.filter(cd -> {
|
||||||
|
String name = cd.getName();
|
||||||
|
return columnNames
|
||||||
|
.stream()
|
||||||
|
.anyMatch(s -> s.contains(name));
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (dataList.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
package com.hellobike.base.tunnel.filter;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.model.EventType;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-30
|
||||||
|
*/
|
||||||
|
public class EventTypeFilter implements IEventFilter {
|
||||||
|
|
||||||
|
private final EventType eventType;
|
||||||
|
|
||||||
|
public EventTypeFilter(EventType eventType) {
|
||||||
|
this.eventType = eventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean filter(Event event) {
|
||||||
|
if (event == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return getEventType() == null || event.getEventType() == getEventType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public EventType getEventType() {
|
||||||
|
return eventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package com.hellobike.base.tunnel.filter;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-25
|
||||||
|
*/
|
||||||
|
public interface IEventFilter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param event msg event
|
||||||
|
* @return whether test success
|
||||||
|
*/
|
||||||
|
boolean filter(Event event);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.hellobike.base.tunnel.filter;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-30
|
||||||
|
*/
|
||||||
|
public class SchemaFilter implements IEventFilter {
|
||||||
|
|
||||||
|
private final String schemaName;
|
||||||
|
|
||||||
|
public SchemaFilter(String schemaName) {
|
||||||
|
this.schemaName = schemaName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean filter(Event event) {
|
||||||
|
if (event == null || event.getSchema() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return getSchemaName() == null || getSchemaName().contains(event.getSchema());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSchemaName() {
|
||||||
|
return schemaName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package com.hellobike.base.tunnel.filter;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-30
|
||||||
|
*/
|
||||||
|
public class TableNameFilter implements IEventFilter {
|
||||||
|
|
||||||
|
private final String tableNameExp;
|
||||||
|
private final Pattern pattern;
|
||||||
|
|
||||||
|
public TableNameFilter(String tableNameExp) {
|
||||||
|
this.tableNameExp = StringUtils.isBlank(tableNameExp) ? ".*" : tableNameExp;
|
||||||
|
this.pattern = Pattern.compile(this.tableNameExp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean filter(Event event) {
|
||||||
|
if (event == null || event.getTable() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Matcher matcher = pattern.matcher(event.getTable());
|
||||||
|
return matcher.matches();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.ha;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-26
|
||||||
|
*/
|
||||||
|
public interface DistributedLock {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取锁
|
||||||
|
*
|
||||||
|
* @throws LockingException
|
||||||
|
*/
|
||||||
|
void lock() throws LockingException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试获取锁
|
||||||
|
*
|
||||||
|
* @param timeout 超时时间
|
||||||
|
* @param unit 时间刻度
|
||||||
|
* @return lock success:true else:false
|
||||||
|
*/
|
||||||
|
boolean tryLock(long timeout, TimeUnit unit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放锁
|
||||||
|
*
|
||||||
|
* @throws LockingException
|
||||||
|
*/
|
||||||
|
void unlock() throws LockingException;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.ha;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-26
|
||||||
|
*/
|
||||||
|
public class LockingException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 2256598708734964597L;
|
||||||
|
|
||||||
|
public LockingException(String msg, Throwable e) {
|
||||||
|
super(msg, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LockingException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.ha;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
|
import org.apache.zookeeper.CreateMode;
|
||||||
|
import org.apache.zookeeper.data.ACL;
|
||||||
|
import org.apache.zookeeper.data.Stat;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-26
|
||||||
|
*/
|
||||||
|
public class ZkDistributedLock implements DistributedLock {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ZkDistributedLock.class.getName());
|
||||||
|
|
||||||
|
private final CuratorFramework zkClient;
|
||||||
|
private final String lockPath;
|
||||||
|
|
||||||
|
private final AtomicBoolean aborted = new AtomicBoolean(false);
|
||||||
|
private CountDownLatch syncPoint;
|
||||||
|
private boolean holdsLock = false;
|
||||||
|
private String currentId;
|
||||||
|
private String currentNode;
|
||||||
|
private String watchedNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a distributed lock using the given {@code zkClient} to coordinate locking.
|
||||||
|
*
|
||||||
|
* @param zkClient The ZooKeeper client to use.
|
||||||
|
* @param lockPath The path used to manage the lock under.
|
||||||
|
* @param acl The acl to apply to newly created lock nodes.
|
||||||
|
*/
|
||||||
|
public ZkDistributedLock(CuratorFramework zkClient, String lockPath, Iterable<ACL> acl) {
|
||||||
|
this.zkClient = zkClient;
|
||||||
|
this.lockPath = lockPath;
|
||||||
|
this.syncPoint = new CountDownLatch(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void lock() throws LockingException {
|
||||||
|
if (holdsLock) {
|
||||||
|
throw new LockingException("Error, already holding a lock. Call unlock first!");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
prepare();
|
||||||
|
syncPoint.await();
|
||||||
|
if (!holdsLock) {
|
||||||
|
throw new LockingException("Error, couldn't acquire the lock!");
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
cancelAttempt();
|
||||||
|
throw new LockingException("InterruptedException while trying to acquire lock!", e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// No need to clean up since the node wasn't created yet.
|
||||||
|
throw new LockingException("ZkException while trying to acquire lock!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized boolean tryLock(long timeout, TimeUnit unit) {
|
||||||
|
if (holdsLock) {
|
||||||
|
throw new LockingException("Error, already holding a lock. Call unlock first!");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
prepare();
|
||||||
|
boolean success = syncPoint.await(timeout, unit);
|
||||||
|
if (!success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!holdsLock) {
|
||||||
|
throw new LockingException("Error, couldn't acquire the lock!");
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
cancelAttempt();
|
||||||
|
return false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// No need to clean up since the node wasn't created yet.
|
||||||
|
throw new LockingException("ZkException while trying to acquire lock!", e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void unlock() throws LockingException {
|
||||||
|
if (currentId == null) {
|
||||||
|
throw new LockingException("Error, neither attempting to lock nor holding a lock!");
|
||||||
|
}
|
||||||
|
Preconditions.checkNotNull(currentId);
|
||||||
|
// Try aborting!
|
||||||
|
if (!holdsLock) {
|
||||||
|
aborted.set(true);
|
||||||
|
} else {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void prepare() throws Exception {
|
||||||
|
this.zkClient.checkExists().forPath(lockPath);
|
||||||
|
|
||||||
|
// Create an EPHEMERAL_SEQUENTIAL node.
|
||||||
|
this.currentNode = this.zkClient.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(lockPath + "/member_");
|
||||||
|
|
||||||
|
// We only care about our actual id since we want to compare ourselves to siblings.
|
||||||
|
if (currentNode.contains("/")) {
|
||||||
|
currentId = currentNode.substring(currentNode.lastIndexOf("/") + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void cancelAttempt() {
|
||||||
|
cleanup();
|
||||||
|
// Bubble up failure...
|
||||||
|
holdsLock = false;
|
||||||
|
syncPoint.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanup() {
|
||||||
|
LOG.info("Cleaning up!");
|
||||||
|
Preconditions.checkNotNull(currentId);
|
||||||
|
try {
|
||||||
|
Stat stat = zkClient.checkExists().forPath(currentNode);
|
||||||
|
if (stat != null) {
|
||||||
|
zkClient.delete().forPath(currentNode);
|
||||||
|
} else {
|
||||||
|
LOG.info("Called cleanup but nothing to cleanup!");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
holdsLock = false;
|
||||||
|
aborted.set(false);
|
||||||
|
currentId = null;
|
||||||
|
currentNode = null;
|
||||||
|
syncPoint = new CountDownLatch(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.ha;
|
||||||
|
|
||||||
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
|
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||||
|
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
|
||||||
|
import org.apache.curator.retry.RetryNTimes;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-11-07
|
||||||
|
*/
|
||||||
|
public class ZkLock implements DistributedLock, AutoCloseable {
|
||||||
|
|
||||||
|
private static final Logger /**/ log = LoggerFactory.getLogger(ZkLock.class);
|
||||||
|
private final CuratorFramework /**/ zkClient;
|
||||||
|
private final InterProcessMutex /**/ lock;
|
||||||
|
private final String /**/ path;
|
||||||
|
|
||||||
|
public ZkLock(String address, String path) {
|
||||||
|
this.zkClient = startZkClient(address);
|
||||||
|
this.path = path;
|
||||||
|
this.lock = new InterProcessMutex(this.zkClient, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CuratorFramework startZkClient(String address) {
|
||||||
|
CuratorFramework zkClient = CuratorFrameworkFactory.builder()
|
||||||
|
.connectString(address)
|
||||||
|
.connectionTimeoutMs(Integer.MAX_VALUE)
|
||||||
|
.sessionTimeoutMs(Integer.MAX_VALUE)
|
||||||
|
.retryPolicy(new RetryNTimes(5, 1000))
|
||||||
|
.build();
|
||||||
|
zkClient.start();
|
||||||
|
log.info("ZkLog ---- ZkClient Started");
|
||||||
|
return zkClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean tryLock() {
|
||||||
|
return tryLock(1000, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lock() throws LockingException {
|
||||||
|
try {
|
||||||
|
lock.acquire();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new LockingException("lock", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tryLock(long timeout, TimeUnit unit) {
|
||||||
|
try {
|
||||||
|
log.info("ZkLog ---- Acquiring Lock On:{}", path);
|
||||||
|
while (true) {
|
||||||
|
if (lock.acquire(timeout, unit)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("ZkLog ---- Acquired Lock On:{}", path);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlock() {
|
||||||
|
try {
|
||||||
|
lock.release();
|
||||||
|
log.info("ZkLog ---- Release Lock Done");
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
try {
|
||||||
|
unlock();
|
||||||
|
this.zkClient.close();
|
||||||
|
log.info("ZkLog ---- ZkClient Closed");
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
package com.hellobike.base.tunnel.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-25
|
||||||
|
*/
|
||||||
|
public class ColumnData implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 4767055418095657107L;
|
||||||
|
private String name;
|
||||||
|
private String dataType;
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
public ColumnData() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColumnData(String name, String dataType, String value) {
|
||||||
|
this.name = name;
|
||||||
|
this.dataType = dataType;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataType() {
|
||||||
|
return dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataType(String dataType) {
|
||||||
|
this.dataType = dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ColumnData data = (ColumnData) o;
|
||||||
|
return Objects.equals(name, data.name) &&
|
||||||
|
Objects.equals(dataType, data.dataType) &&
|
||||||
|
Objects.equals(value, data.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(name, dataType, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ColumnData{" +
|
||||||
|
"name='" + name + '\'' +
|
||||||
|
", dataType='" + dataType + '\'' +
|
||||||
|
", value=" + value +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,126 @@
|
|||||||
|
package com.hellobike.base.tunnel.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-25
|
||||||
|
*/
|
||||||
|
public class Event implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 3414755790085772526L;
|
||||||
|
|
||||||
|
private long lsn;
|
||||||
|
|
||||||
|
private transient String slotName;
|
||||||
|
private transient String serverId;
|
||||||
|
private String schema;
|
||||||
|
private String table;
|
||||||
|
private EventType eventType;
|
||||||
|
private List<ColumnData> dataList = new ArrayList<>();
|
||||||
|
|
||||||
|
public String getSlotName() {
|
||||||
|
return slotName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSlotName(String slotName) {
|
||||||
|
this.slotName = slotName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerId() {
|
||||||
|
return serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerId(String serverId) {
|
||||||
|
this.serverId = serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSchema() {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchema(String schema) {
|
||||||
|
this.schema = schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTable() {
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTable(String table) {
|
||||||
|
this.table = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EventType getEventType() {
|
||||||
|
return eventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEventType(EventType eventType) {
|
||||||
|
this.eventType = eventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ColumnData> getDataList() {
|
||||||
|
return dataList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataList(List<ColumnData> dataList) {
|
||||||
|
this.dataList = dataList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLsn() {
|
||||||
|
return lsn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLsn(long lsn) {
|
||||||
|
this.lsn = lsn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Event event = (Event) o;
|
||||||
|
return Objects.equals(schema, event.schema) &&
|
||||||
|
Objects.equals(table, event.table) &&
|
||||||
|
eventType == event.eventType &&
|
||||||
|
Objects.equals(dataList, event.dataList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(schema, table, eventType, dataList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Event{" +
|
||||||
|
"schema='" + schema + '\'' +
|
||||||
|
", table='" + table + '\'' +
|
||||||
|
", eventType=" + eventType +
|
||||||
|
", dataList=" + dataList +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
package com.hellobike.base.tunnel.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-25
|
||||||
|
*/
|
||||||
|
public enum EventType implements Serializable {
|
||||||
|
// sql 语句类型
|
||||||
|
BEGIN,
|
||||||
|
COMMIT,
|
||||||
|
INSERT,
|
||||||
|
UPDATE,
|
||||||
|
DELETE;
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public static EventType getEventType(String message) {
|
||||||
|
if (EventType.INSERT.name().equalsIgnoreCase(message)) {
|
||||||
|
return EventType.INSERT;
|
||||||
|
} else if (EventType.DELETE.name().equalsIgnoreCase(message)) {
|
||||||
|
return EventType.DELETE;
|
||||||
|
} else if (EventType.UPDATE.name().equalsIgnoreCase(message)) {
|
||||||
|
return EventType.UPDATE;
|
||||||
|
} else if (EventType.BEGIN.name().equalsIgnoreCase(message)) {
|
||||||
|
return EventType.BEGIN;
|
||||||
|
} else if (EventType.COMMIT.name().equalsIgnoreCase(message)) {
|
||||||
|
return EventType.COMMIT;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("unsupported event:" + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,122 @@
|
|||||||
|
package com.hellobike.base.tunnel.model;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.publisher.IPublisher;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-14
|
||||||
|
*/
|
||||||
|
public class InvokeContext {
|
||||||
|
|
||||||
|
private String serverId;
|
||||||
|
private String slotName;
|
||||||
|
|
||||||
|
private String jdbcUrl;
|
||||||
|
private String jdbcUser;
|
||||||
|
private String jdbcPass;
|
||||||
|
|
||||||
|
private long lsn;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
|
||||||
|
private String xid;
|
||||||
|
private Event event;
|
||||||
|
|
||||||
|
private IPublisher.Callback callback;
|
||||||
|
|
||||||
|
public String getServerId() {
|
||||||
|
return serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerId(String serverId) {
|
||||||
|
this.serverId = serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSlotName() {
|
||||||
|
return slotName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSlotName(String slotName) {
|
||||||
|
this.slotName = slotName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJdbcUrl() {
|
||||||
|
return jdbcUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJdbcUrl(String jdbcUrl) {
|
||||||
|
this.jdbcUrl = jdbcUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJdbcUser() {
|
||||||
|
return jdbcUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJdbcUser(String jdbcUser) {
|
||||||
|
this.jdbcUser = jdbcUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJdbcPass() {
|
||||||
|
return jdbcPass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJdbcPass(String jdbcPass) {
|
||||||
|
this.jdbcPass = jdbcPass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLsn() {
|
||||||
|
return lsn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLsn(long lsn) {
|
||||||
|
this.lsn = lsn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getXid() {
|
||||||
|
return xid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXid(String xid) {
|
||||||
|
this.xid = xid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Event getEvent() {
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvent(Event event) {
|
||||||
|
this.event = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPublisher.Callback getCallback() {
|
||||||
|
return callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCallback(IPublisher.Callback callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.monitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-27
|
||||||
|
*/
|
||||||
|
public class TunnelMonitorFactory {
|
||||||
|
|
||||||
|
private static volatile TunnelExporter exporter;
|
||||||
|
|
||||||
|
private TunnelMonitorFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TunnelMonitor getTunnelMonitor() {
|
||||||
|
return exporter.getTunnelMonitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized TunnelExporter initializeExporter(boolean useYukon, ExporterConfig config) {
|
||||||
|
if (exporter == null) {
|
||||||
|
synchronized (TunnelMonitorFactory.class) {
|
||||||
|
exporter = new PrometheusExporter(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exporter;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,186 @@
|
|||||||
|
package com.hellobike.base.tunnel.parse;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.ColumnData;
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.model.EventType;
|
||||||
|
import com.hellobike.base.tunnel.model.InvokeContext;
|
||||||
|
import com.hellobike.base.tunnel.store.MemStore;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-25
|
||||||
|
*/
|
||||||
|
public class EventParser implements IEventParser {
|
||||||
|
|
||||||
|
private MemStore memStore;
|
||||||
|
|
||||||
|
public EventParser() {
|
||||||
|
this.memStore = new MemStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isBegin(String msg) {
|
||||||
|
return msg != null
|
||||||
|
&& msg.length() > 5
|
||||||
|
&& (msg.charAt(0) == 'B' || msg.charAt(0) == 'b')
|
||||||
|
&& (msg.charAt(1) == 'E' || msg.charAt(1) == 'e')
|
||||||
|
&& (msg.charAt(2) == 'G' || msg.charAt(2) == 'g')
|
||||||
|
&& (msg.charAt(3) == 'I' || msg.charAt(3) == 'i')
|
||||||
|
&& (msg.charAt(4) == 'N' || msg.charAt(4) == 'n');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isCommit(String msg) {
|
||||||
|
return msg != null
|
||||||
|
&& msg.length() > 6
|
||||||
|
&& (msg.charAt(0) == 'C' || msg.charAt(0) == 'c')
|
||||||
|
&& (msg.charAt(1) == 'O' || msg.charAt(1) == 'o')
|
||||||
|
&& (msg.charAt(2) == 'M' || msg.charAt(2) == 'm')
|
||||||
|
&& (msg.charAt(3) == 'M' || msg.charAt(3) == 'm')
|
||||||
|
&& (msg.charAt(4) == 'I' || msg.charAt(4) == 'i')
|
||||||
|
&& (msg.charAt(5) == 'T' || msg.charAt(5) == 't');
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parse(InvokeContext context) {
|
||||||
|
if (isBegin(context.getMessage()) || isCommit(context.getMessage())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Event event = parseEvent(context.getMessage());
|
||||||
|
if (event == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context.setEvent(event);
|
||||||
|
|
||||||
|
memStore.store(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Event parseEvent(String message) {
|
||||||
|
Event event = new Event();
|
||||||
|
Lexer lexer = new Lexer(message);
|
||||||
|
|
||||||
|
// "table"
|
||||||
|
lexer.nextToken(' ');
|
||||||
|
// schema_name
|
||||||
|
lexer.nextToken('.');
|
||||||
|
String schema = lexer.token();
|
||||||
|
// table_name
|
||||||
|
String table = lexer.nextToken(':');
|
||||||
|
lexer.skip(1);
|
||||||
|
// event_type
|
||||||
|
String eventType = lexer.nextToken(':');
|
||||||
|
|
||||||
|
event.setSchema(schema);
|
||||||
|
event.setTable(table);
|
||||||
|
event.setEventType(EventType.getEventType(eventType));
|
||||||
|
lexer.skip(1);
|
||||||
|
|
||||||
|
while (lexer.hasNext()) {
|
||||||
|
ColumnData data = new ColumnData();
|
||||||
|
String name = parseName(lexer);
|
||||||
|
if ("(no-tuple-data)".equals(name)) {
|
||||||
|
// 删除时,无主键,不能同步
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String type = parseType(lexer);
|
||||||
|
lexer.skip(1);
|
||||||
|
String value = parseValue(lexer);
|
||||||
|
|
||||||
|
|
||||||
|
// 去除多余的符号 "'"
|
||||||
|
if (value.length() > 0 && value.charAt(0) == '\'' && value.charAt(value.length() - 1) == '\'') {
|
||||||
|
value = value.substring(1, value.length() - 1);
|
||||||
|
}
|
||||||
|
data.setName(name);
|
||||||
|
data.setDataType(type);
|
||||||
|
data.setValue(value);
|
||||||
|
event.getDataList().add(data);
|
||||||
|
}
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseName(Lexer lexer) {
|
||||||
|
if (lexer.current() == ' ') {
|
||||||
|
lexer.skip(1);
|
||||||
|
}
|
||||||
|
lexer.nextToken('[');
|
||||||
|
return lexer.token();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseType(Lexer lexer) {
|
||||||
|
lexer.nextToken(']');
|
||||||
|
return lexer.token();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseValue(Lexer lexer) {
|
||||||
|
if (lexer.current() == '\'') {
|
||||||
|
lexer.skip(1);
|
||||||
|
lexer.nextToken('\'');
|
||||||
|
return lexer.token();
|
||||||
|
}
|
||||||
|
lexer.nextToken(' ');
|
||||||
|
return lexer.token();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setMemStore(MemStore memStore) {
|
||||||
|
this.memStore = memStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Lexer {
|
||||||
|
private final String input;
|
||||||
|
private final char[] array;
|
||||||
|
private final int length;
|
||||||
|
private int pos = 0;
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
public Lexer(String input) {
|
||||||
|
this.input = input;
|
||||||
|
this.array = input.toCharArray();
|
||||||
|
this.length = this.array.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String token() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String nextToken(char comma) {
|
||||||
|
if (pos < length) {
|
||||||
|
StringBuilder out = new StringBuilder(16);
|
||||||
|
while (pos < length && array[pos] != comma) {
|
||||||
|
out.append(array[pos]);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
return token = out.toString();
|
||||||
|
}
|
||||||
|
return token = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void skip(int skip) {
|
||||||
|
this.pos += skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char current() {
|
||||||
|
return array[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
return pos < length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.parse;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.InvokeContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-25
|
||||||
|
*/
|
||||||
|
public interface IEventParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析消息
|
||||||
|
*
|
||||||
|
* @param context 上下文信息
|
||||||
|
*/
|
||||||
|
void parse(InvokeContext context);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.publisher;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.monitor.Statics;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-11-15
|
||||||
|
*/
|
||||||
|
public abstract class BasePublisher {
|
||||||
|
|
||||||
|
public static List<Statics> mapToStatics(Map<String, Long> data) {
|
||||||
|
List<Statics> staticsList = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, Long> entry : data.entrySet()) {
|
||||||
|
String k = entry.getKey();
|
||||||
|
Long c = entry.getValue();
|
||||||
|
String[] dst = k.split("@@");
|
||||||
|
|
||||||
|
Statics statics = Statics.createStatics(
|
||||||
|
"AppTunnelService",
|
||||||
|
dst[0],
|
||||||
|
dst[1],
|
||||||
|
dst[2],
|
||||||
|
c.intValue(),
|
||||||
|
dst[3],
|
||||||
|
""
|
||||||
|
);
|
||||||
|
staticsList.add(statics);
|
||||||
|
|
||||||
|
}
|
||||||
|
return staticsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onSuccess(IPublisher.Callback callback) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onFailure(IPublisher.Callback callback, Exception e) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onFailure(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.publisher;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.model.InvokeContext;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-25
|
||||||
|
*/
|
||||||
|
public interface IPublisher extends AutoCloseable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费消息
|
||||||
|
*
|
||||||
|
* @param event 事件
|
||||||
|
* @param callback 回调
|
||||||
|
*/
|
||||||
|
void publish(Event event, Callback callback);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费消息
|
||||||
|
*
|
||||||
|
* @param context 上下文
|
||||||
|
* @param callback 回调
|
||||||
|
*/
|
||||||
|
default void publish(InvokeContext context, Callback callback) {
|
||||||
|
context.getEvent().setLsn(context.getLsn());
|
||||||
|
context.getEvent().setServerId(context.getServerId());
|
||||||
|
context.getEvent().setSlotName(context.getSlotName());
|
||||||
|
this.publish(context.getEvent(), callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭发布器
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
default void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量发布
|
||||||
|
*
|
||||||
|
* @param contexts 上下文
|
||||||
|
*/
|
||||||
|
default void publish(List<InvokeContext> contexts) {
|
||||||
|
if (contexts == null || contexts.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
contexts.forEach(ctx -> publish(ctx, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
|
||||||
|
void onSuccess();
|
||||||
|
|
||||||
|
void onFailure(Throwable t);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.publisher;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.model.InvokeContext;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-25
|
||||||
|
*/
|
||||||
|
public class PublisherManager implements IPublisher {
|
||||||
|
|
||||||
|
private static final PublisherManager INSTANCE = new PublisherManager();
|
||||||
|
|
||||||
|
private Map<String, IPublisher> publishers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private PublisherManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PublisherManager getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(Event event, Callback callback) {
|
||||||
|
this.publishers.get(event.getSlotName()).publish(event, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(InvokeContext context, Callback callback) {
|
||||||
|
this.publishers.get(context.getSlotName()).publish(context, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
this.publishers.values().forEach(IPublisher::close);
|
||||||
|
this.publishers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(List<InvokeContext> contexts) {
|
||||||
|
if (contexts.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putPublisher(String slotName, IPublisher publisher) {
|
||||||
|
this.publishers.put(slotName, publisher);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,403 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.publisher.es;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.config.EsConfig;
|
||||||
|
import com.hellobike.base.tunnel.model.ColumnData;
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.model.InvokeContext;
|
||||||
|
import com.hellobike.base.tunnel.monitor.TunnelMonitorFactory;
|
||||||
|
import com.hellobike.base.tunnel.publisher.BasePublisher;
|
||||||
|
import com.hellobike.base.tunnel.publisher.IPublisher;
|
||||||
|
import com.hellobike.base.tunnel.utils.NamedThreadFactory;
|
||||||
|
import org.apache.commons.dbutils.QueryRunner;
|
||||||
|
import org.apache.commons.dbutils.handlers.MapHandler;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.http.HttpHost;
|
||||||
|
import org.elasticsearch.action.ActionListener;
|
||||||
|
import org.elasticsearch.action.DocWriteRequest;
|
||||||
|
import org.elasticsearch.action.bulk.BulkRequest;
|
||||||
|
import org.elasticsearch.action.bulk.BulkResponse;
|
||||||
|
import org.elasticsearch.action.delete.DeleteRequest;
|
||||||
|
import org.elasticsearch.action.index.IndexRequest;
|
||||||
|
import org.elasticsearch.action.support.ActiveShardCount;
|
||||||
|
import org.elasticsearch.action.support.WriteRequest;
|
||||||
|
import org.elasticsearch.action.update.UpdateRequest;
|
||||||
|
import org.elasticsearch.client.RequestOptions;
|
||||||
|
import org.elasticsearch.client.RestClient;
|
||||||
|
import org.elasticsearch.client.RestHighLevelClient;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static com.hellobike.base.tunnel.utils.TimeUtils.sleepOneSecond;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-25
|
||||||
|
*/
|
||||||
|
public class EsPublisher extends BasePublisher implements IPublisher {
|
||||||
|
|
||||||
|
private static final Logger /**/ LOG = LoggerFactory.getLogger(EsPublisher.class);
|
||||||
|
private static final int /**/ MAX_CACHED = 10240;
|
||||||
|
|
||||||
|
private final List<EsConfig> /**/ esConfigs;
|
||||||
|
private final ThreadPoolExecutor /**/ executor;
|
||||||
|
|
||||||
|
private final LinkedBlockingQueue<Helper> /**/ requestHelperQueue;
|
||||||
|
private final RestHighLevelClient[] /**/ restClients;
|
||||||
|
|
||||||
|
|
||||||
|
private volatile boolean /**/ started;
|
||||||
|
|
||||||
|
public EsPublisher(List<EsConfig> esConfigs) {
|
||||||
|
this.esConfigs = esConfigs;
|
||||||
|
int total = 8;
|
||||||
|
this.executor = new ThreadPoolExecutor(total, total, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5000), new NamedThreadFactory("EsSendThread"));
|
||||||
|
|
||||||
|
this.restClients = new RestHighLevelClient[total];
|
||||||
|
for (int i = 0; i < total; i++) {
|
||||||
|
this.restClients[i] = newRestEsHighLevelClient();
|
||||||
|
}
|
||||||
|
this.requestHelperQueue = new LinkedBlockingQueue<>(81920);
|
||||||
|
|
||||||
|
started = true;
|
||||||
|
for (int i = 0; i < total; i++) {
|
||||||
|
this.executor.submit(new Sender(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(Event event, Callback callback) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(InvokeContext context, Callback callback) {
|
||||||
|
this.esConfigs.forEach(
|
||||||
|
esConfig -> internalPublish(context, callback, esConfig)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
started = false;
|
||||||
|
this.executor.shutdown();
|
||||||
|
Arrays.stream(this.restClients).forEach(this::closeClosable);
|
||||||
|
LOG.info("EsPublisher Closed");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeClosable(AutoCloseable closeable) {
|
||||||
|
if (closeable != null) {
|
||||||
|
try {
|
||||||
|
closeable.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void internalPublish(InvokeContext context, Callback callback, EsConfig esConfig) {
|
||||||
|
if (esConfig.getFilters() == null
|
||||||
|
|| esConfig.getFilters().isEmpty()
|
||||||
|
|| esConfig.getFilters().stream().allMatch(filter -> filter.filter(context.getEvent()))) {
|
||||||
|
sendToEs(esConfig, context, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendToEs(EsConfig esConfig, InvokeContext context, Callback callback) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
requestHelperQueue.put(new Helper(context, esConfig, callback));
|
||||||
|
|
||||||
|
onSuccess(callback);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
LOG.error("Put Data To MemQueue Failure", e);
|
||||||
|
onFailure(callback, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestHelperQueue.size() >= MAX_CACHED) {
|
||||||
|
forceFlushMemQueue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private DocWriteRequest eventToRequest(EsConfig esConfig, InvokeContext context) {
|
||||||
|
|
||||||
|
DocWriteRequest req = null;
|
||||||
|
|
||||||
|
Map<String, String> values = context.getEvent().getDataList()
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(ColumnData::getName, ColumnData::getValue));
|
||||||
|
|
||||||
|
// column_name,column_name
|
||||||
|
String id = esConfig.getEsIdFieldNames()
|
||||||
|
.stream()
|
||||||
|
.map(esId -> String.valueOf(values.get(esId)))
|
||||||
|
.reduce((s1, s2) -> s1 + esConfig.getSeparator() + s2)
|
||||||
|
.orElse("");
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(id)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String type = esConfig.getType();
|
||||||
|
String index = esConfig.getIndex();
|
||||||
|
|
||||||
|
|
||||||
|
switch (context.getEvent().getEventType()) {
|
||||||
|
case INSERT:
|
||||||
|
IndexRequest ir = new IndexRequest(index, type, id);
|
||||||
|
ir.opType(DocWriteRequest.OpType.CREATE);
|
||||||
|
|
||||||
|
execSQL(esConfig, context, values);
|
||||||
|
|
||||||
|
ir.source(values);
|
||||||
|
req = ir;
|
||||||
|
break;
|
||||||
|
case UPDATE:
|
||||||
|
UpdateRequest ur = new UpdateRequest(index, type, id);
|
||||||
|
|
||||||
|
execSQL(esConfig, context, values);
|
||||||
|
|
||||||
|
ur.doc(values);
|
||||||
|
req = ur;
|
||||||
|
break;
|
||||||
|
case DELETE:
|
||||||
|
DeleteRequest dr = new DeleteRequest(index, type, id);
|
||||||
|
dr.id(id);
|
||||||
|
req = dr;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void execSQL(EsConfig esConfig, InvokeContext context, Map<String, String> values) {
|
||||||
|
String sql = esConfig.getSql();
|
||||||
|
List<String> parameters = esConfig.getParameters();
|
||||||
|
if (sql != null && parameters != null) {
|
||||||
|
// select * from tb1 where id=@id,name=@name
|
||||||
|
for (String k : parameters) {
|
||||||
|
sql = sql.replace("?", getValue(values.get(k)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行sql,获得结果集
|
||||||
|
Map<String, Object> result = executeQuery(sql, context);
|
||||||
|
Map<String, String> newValues = new LinkedHashMap<>();
|
||||||
|
result.entrySet().stream()
|
||||||
|
.filter(e -> e.getValue() != null)
|
||||||
|
.forEach(e -> newValues.put(e.getKey(), String.valueOf(e.getValue())));
|
||||||
|
if (!newValues.isEmpty()) {
|
||||||
|
values.clear();
|
||||||
|
values.putAll(newValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getValue(Object val) {
|
||||||
|
if (val instanceof Number) {
|
||||||
|
return val.toString();
|
||||||
|
}
|
||||||
|
return '\'' + val.toString() + '\'';
|
||||||
|
}
|
||||||
|
|
||||||
|
private void syncSend(RestHighLevelClient restClient, List<DocWriteRequest> doc) {
|
||||||
|
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
BulkRequest br = createBulkRequest(doc);
|
||||||
|
RequestOptions requestOptions = createRequestOptions();
|
||||||
|
int retry = 10;
|
||||||
|
|
||||||
|
while (retry > 0) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
BulkResponse response = restClient.bulk(br, requestOptions);
|
||||||
|
|
||||||
|
long e = System.currentTimeMillis();
|
||||||
|
LOG.info("indexed doc:{},cost:{}ms,result:{}", doc.size(), e - s, response.hasFailures());
|
||||||
|
return;
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
retry--;
|
||||||
|
LOG.error("Send Data To Es Occurred Error,retry:" + (10 - retry), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void asyncSend(RestHighLevelClient restClient, List<DocWriteRequest> doc) {
|
||||||
|
BulkRequest br = createBulkRequest(doc);
|
||||||
|
RequestOptions requestOptions = createRequestOptions();
|
||||||
|
restClient.bulkAsync(br, requestOptions, new ActionListener<BulkResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(BulkResponse responses) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Exception e) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private BulkRequest createBulkRequest(List<DocWriteRequest> doc) {
|
||||||
|
BulkRequest br = new BulkRequest();
|
||||||
|
br.add(doc);
|
||||||
|
br.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||||
|
br.waitForActiveShards(ActiveShardCount.ONE);
|
||||||
|
return br;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RequestOptions createRequestOptions() {
|
||||||
|
RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
|
||||||
|
builder.addHeader("Connection", "Keep-Alive");
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Helper> pollHelperFromQueue(BlockingQueue<Helper> queue) {
|
||||||
|
int len = queue.size();
|
||||||
|
int capacity = Math.min(MAX_CACHED / 2, len);
|
||||||
|
List<Helper> helpers = new ArrayList<>(capacity);
|
||||||
|
queue.drainTo(helpers, capacity);
|
||||||
|
return helpers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Event findMaxEvent(List<Helper> helpers) {
|
||||||
|
if (helpers == null || helpers.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return helpers.stream()
|
||||||
|
.max(Comparator.comparingLong(h1 -> h1.context.getLsn()))
|
||||||
|
.map(helper -> helper.context.getEvent())
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<DocWriteRequest> transferToReq(List<Helper> helpers) {
|
||||||
|
|
||||||
|
return helpers.stream()
|
||||||
|
.map(helper -> eventToRequest(helper.config, helper.context))
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private RestHighLevelClient newRestEsHighLevelClient() {
|
||||||
|
return new RestHighLevelClient(RestClient.builder(
|
||||||
|
this.esConfigs
|
||||||
|
.stream()
|
||||||
|
.map(esConfig -> HttpHost.create(esConfig.getServer()))
|
||||||
|
.toArray(HttpHost[]::new)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forceFlushMemQueue(int idx) {
|
||||||
|
List<Helper> helpers = pollHelperFromQueue(requestHelperQueue);
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (helpers.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
syncSend(restClients[idx], transferToReq(helpers));
|
||||||
|
|
||||||
|
Event maxEvent = findMaxEvent(helpers);
|
||||||
|
if (maxEvent != null) {
|
||||||
|
LOG.info("flush queue success,lsn:{}", maxEvent.getLsn());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (!helpers.isEmpty()) {
|
||||||
|
Map<String, Long> data = getMonitorData(helpers);
|
||||||
|
mapToStatics(data).forEach(statics ->
|
||||||
|
TunnelMonitorFactory.getTunnelMonitor().collect(statics)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Long> getMonitorData(List<Helper> helpers) {
|
||||||
|
return helpers.stream()
|
||||||
|
.map(helper -> {
|
||||||
|
helper.context.getEvent().setSlotName(helper.context.getSlotName());
|
||||||
|
return helper.context.getEvent();
|
||||||
|
})
|
||||||
|
.collect(Collectors.groupingBy(event ->
|
||||||
|
event.getSchema() + "@@" + event.getSlotName() + "@@" + event.getTable() + "@@es", Collectors.counting()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> executeQuery(String sql, InvokeContext context) {
|
||||||
|
Connection connection = null;
|
||||||
|
try {
|
||||||
|
connection = DriverManager.getConnection(context.getJdbcUrl(), context.getJdbcUser(), context.getJdbcPass());
|
||||||
|
QueryRunner qr = new QueryRunner();
|
||||||
|
Map<String, Object> query = qr.query(connection, sql, new MapHandler());
|
||||||
|
if (query == null || query.isEmpty()) {
|
||||||
|
query = new LinkedHashMap<>();
|
||||||
|
LOG.warn("Select Nothing By SQL:{}", sql);
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
} finally {
|
||||||
|
closeClosable(connection);
|
||||||
|
}
|
||||||
|
return new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Helper {
|
||||||
|
|
||||||
|
final InvokeContext context;
|
||||||
|
final EsConfig config;
|
||||||
|
final Callback callback;
|
||||||
|
|
||||||
|
private Helper(InvokeContext context, EsConfig config, Callback callback) {
|
||||||
|
this.context = context;
|
||||||
|
this.config = config;
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Sender implements Runnable {
|
||||||
|
|
||||||
|
private final int idx;
|
||||||
|
|
||||||
|
public Sender(int idx) {
|
||||||
|
this.idx = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (started) {
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
forceFlushMemQueue(this.idx);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warn("flush data to es failure", e);
|
||||||
|
} finally {
|
||||||
|
sleepOneSecond(s, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,358 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.publisher.hbase;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.config.HBaseConfig;
|
||||||
|
import com.hellobike.base.tunnel.model.ColumnData;
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.monitor.TunnelMonitorFactory;
|
||||||
|
import com.hellobike.base.tunnel.publisher.BasePublisher;
|
||||||
|
import com.hellobike.base.tunnel.utils.DefaultObjectPoolFactory;
|
||||||
|
import com.hellobike.base.tunnel.utils.NamedThreadFactory;
|
||||||
|
import com.hellobike.base.tunnel.utils.ObjectManager;
|
||||||
|
import com.hellobike.base.tunnel.utils.ObjectPool;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.hbase.HBaseConfiguration;
|
||||||
|
import org.apache.hadoop.hbase.TableName;
|
||||||
|
import org.apache.hadoop.hbase.client.*;
|
||||||
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static com.hellobike.base.tunnel.utils.TimeUtils.sleepOneSecond;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-11-27
|
||||||
|
*/
|
||||||
|
public class HBaseClient {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(HBaseClient.class);
|
||||||
|
private static final int MAX_CACHE = 10240;
|
||||||
|
private static final int THREAD_NUM = 4;
|
||||||
|
|
||||||
|
private static volatile HBaseClient instance = null;
|
||||||
|
private final Configuration cfg;
|
||||||
|
private final ObjectPool<Connection> pool;
|
||||||
|
private final ArrayBlockingQueue<InsertHelper> insertQueue = new ArrayBlockingQueue<>(40960);
|
||||||
|
private final ArrayBlockingQueue<DeleteHelper> deleteQueue = new ArrayBlockingQueue<>(40960);
|
||||||
|
private final ThreadPoolExecutor insertExecutor;
|
||||||
|
private final ThreadPoolExecutor deleteExecutor;
|
||||||
|
private Map<String, Table> tables = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private volatile boolean started;
|
||||||
|
|
||||||
|
private HBaseClient() {
|
||||||
|
this.cfg = HBaseConfiguration.create();
|
||||||
|
this.pool = new DefaultObjectPoolFactory().createObjectPool(new ConnManager());
|
||||||
|
this.insertExecutor = new ThreadPoolExecutor(THREAD_NUM, THREAD_NUM, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(20480), new NamedThreadFactory("HBaseInsertThread"));
|
||||||
|
this.deleteExecutor = new ThreadPoolExecutor(THREAD_NUM, THREAD_NUM, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(20480), new NamedThreadFactory("HBaseDeleteThread"));
|
||||||
|
started = true;
|
||||||
|
for (int i = 0; i < THREAD_NUM; i++) {
|
||||||
|
this.insertExecutor.submit(new InsertTask());
|
||||||
|
this.deleteExecutor.submit(new DeleteTask());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HBaseClient(String quorum) {
|
||||||
|
this.cfg = HBaseConfiguration.create();
|
||||||
|
this.cfg.set("hbase.zookeeper.quorum", quorum);
|
||||||
|
this.pool = new DefaultObjectPoolFactory().createObjectPool(new ConnManager());
|
||||||
|
this.insertExecutor = new ThreadPoolExecutor(THREAD_NUM, THREAD_NUM, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(20480), new NamedThreadFactory("HBaseInsertThread"));
|
||||||
|
this.deleteExecutor = new ThreadPoolExecutor(THREAD_NUM, THREAD_NUM, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(20480), new NamedThreadFactory("HBaseDeleteThread"));
|
||||||
|
started = true;
|
||||||
|
for (int i = 0; i < THREAD_NUM; i++) {
|
||||||
|
this.insertExecutor.submit(new InsertTask());
|
||||||
|
this.deleteExecutor.submit(new DeleteTask());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HBaseClient getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
synchronized (HBaseClient.class) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new HBaseClient();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HBaseClient getInstance(String quorum) {
|
||||||
|
if (instance == null) {
|
||||||
|
synchronized (HBaseClient.class) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new HBaseClient(quorum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insert(HBaseConfig config, Event event) {
|
||||||
|
String rowKey = generateRowKey(config, event.getDataList());
|
||||||
|
if (StringUtils.isBlank(rowKey)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Put put = new Put(Bytes.toBytes(rowKey));
|
||||||
|
for (ColumnData cd : event.getDataList()) {
|
||||||
|
put.addColumn(Bytes.toBytes(config.getFamily()), Bytes.toBytes(cd.getName()), Bytes.toBytes(cd.getValue()));
|
||||||
|
}
|
||||||
|
InsertHelper ih = createInsertHelper(config, event, put);
|
||||||
|
try {
|
||||||
|
insertQueue.put(ih);
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
if (insertQueue.size() >= MAX_CACHE) {
|
||||||
|
doInsert();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(HBaseConfig config, Event event) {
|
||||||
|
insert(config, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(HBaseConfig config, Event event) {
|
||||||
|
|
||||||
|
String rowKey = generateRowKey(config, event.getDataList());
|
||||||
|
if (StringUtils.isBlank(rowKey)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DeleteHelper dh = createDeleteHelper(config, event, rowKey);
|
||||||
|
try {
|
||||||
|
deleteQueue.put(dh);
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
if (deleteQueue.size() >= MAX_CACHE) {
|
||||||
|
doDelete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
this.started = true;
|
||||||
|
this.doDelete();
|
||||||
|
this.doInsert();
|
||||||
|
this.insertExecutor.shutdown();
|
||||||
|
this.deleteExecutor.shutdown();
|
||||||
|
this.pool.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeleteHelper createDeleteHelper(HBaseConfig config, Event event, String rowKey) {
|
||||||
|
DeleteHelper dh = new DeleteHelper();
|
||||||
|
dh.table = config.getHbaseTable();
|
||||||
|
dh.schema = event.getSchema();
|
||||||
|
dh.slotName = event.getSlotName();
|
||||||
|
dh.delete = new Delete(Bytes.toBytes(rowKey));
|
||||||
|
return dh;
|
||||||
|
}
|
||||||
|
|
||||||
|
private InsertHelper createInsertHelper(HBaseConfig config, Event event, Put put) {
|
||||||
|
InsertHelper ih = new InsertHelper();
|
||||||
|
ih.table = config.getHbaseTable();
|
||||||
|
ih.schema = event.getSchema();
|
||||||
|
ih.slotName = event.getSlotName();
|
||||||
|
ih.put = put;
|
||||||
|
return ih;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doDelete() {
|
||||||
|
List<DeleteHelper> deletes = pollFromQueue(deleteQueue);
|
||||||
|
if (deletes.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
Map<String, List<Delete>> data = deletes.stream()
|
||||||
|
.collect(Collectors.groupingBy(dh -> dh.table, Collectors.mapping(dh -> dh.delete, Collectors.toList())));
|
||||||
|
|
||||||
|
Connection conn = pool.borrowObject();
|
||||||
|
|
||||||
|
try {
|
||||||
|
data.forEach((tableName, deleteList) -> {
|
||||||
|
try {
|
||||||
|
Table table = getTable(tableName, conn);
|
||||||
|
table.delete(deleteList);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logError(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
long e = System.currentTimeMillis();
|
||||||
|
LOGGER.info("delete msg success.queue:{},data:{},thread:{},cost:{}ms", deleteQueue.size(), deletes.size(), Thread.currentThread().getName(), (e - s));
|
||||||
|
} finally {
|
||||||
|
pool.returnObject(conn);
|
||||||
|
monitor(deletes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doInsert() {
|
||||||
|
List<InsertHelper> inserts = pollFromQueue(insertQueue);
|
||||||
|
if (inserts.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
|
||||||
|
Map<String, List<Put>> data = inserts.stream()
|
||||||
|
.collect(Collectors.groupingBy(ih -> ih.table, Collectors.mapping(ih -> ih.put, Collectors.toList())));
|
||||||
|
|
||||||
|
Connection conn = pool.borrowObject();
|
||||||
|
|
||||||
|
try {
|
||||||
|
data.forEach((tableName, insertList) -> {
|
||||||
|
try {
|
||||||
|
Table table = getTable(tableName, conn);
|
||||||
|
table.put(insertList);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logError(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
long e = System.currentTimeMillis();
|
||||||
|
LOGGER.info("insert msg success.queue:{},data:{},thread:{},cost:{}ms", insertQueue.size(), inserts.size(), Thread.currentThread().getName(), (e - s));
|
||||||
|
} finally {
|
||||||
|
pool.returnObject(conn);
|
||||||
|
monitor(inserts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void monitor(List<? extends BaseHelper> helpers) {
|
||||||
|
Map<String, Long> map = helpers.stream().collect(Collectors.groupingBy(helper -> helper.schema + "@@" + helper.slotName + "@@" + helper.table + "@@hbase", Collectors.counting()));
|
||||||
|
BasePublisher.mapToStatics(map).forEach(statics ->
|
||||||
|
TunnelMonitorFactory.getTunnelMonitor().collect(statics)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> List<T> pollFromQueue(ArrayBlockingQueue<T> queue) {
|
||||||
|
int capacity = Math.min(MAX_CACHE, queue.size());
|
||||||
|
List<T> list = new ArrayList<>(capacity);
|
||||||
|
queue.drainTo(list, capacity);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Table getTable(String tableName, Connection conn) throws IOException {
|
||||||
|
Table table = tables.get(tableName);
|
||||||
|
if (table == null) {
|
||||||
|
tables.putIfAbsent(tableName, getOrCreateTable(tableName, conn));
|
||||||
|
table = tables.get(tableName);
|
||||||
|
}
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateRowKey(HBaseConfig config, List<ColumnData> data) {
|
||||||
|
Map<String, String> columnKeyVal = data.stream().collect(Collectors.toMap(ColumnData::getName, ColumnData::getValue));
|
||||||
|
return config.getHbaseKey().stream()
|
||||||
|
.map(columnKeyVal::get)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.reduce(((s1, s2) -> s1 + "_" + s2))
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized Table getOrCreateTable(String tableName, Connection conn) throws IOException {
|
||||||
|
TableName tb = TableName.valueOf(tableName);
|
||||||
|
return conn.getTable(tb);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logError(String msg, Throwable t) {
|
||||||
|
LOGGER.error(msg, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Connection getConnection() throws IOException {
|
||||||
|
return ConnectionFactory.createConnection(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ConnManager implements ObjectManager<Connection> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Connection newInstance() throws Exception {
|
||||||
|
return getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void releaseInstance(Connection connection) {
|
||||||
|
try {
|
||||||
|
connection.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validateInstance(Connection connection) {
|
||||||
|
return !connection.isClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private abstract class BaseHelper {
|
||||||
|
String table;
|
||||||
|
String schema;
|
||||||
|
String slotName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class InsertHelper extends BaseHelper {
|
||||||
|
Put put;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DeleteHelper extends BaseHelper {
|
||||||
|
Delete delete;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class InsertTask implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (started) {
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
doInsert();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logError("InsertTask Occurred Error", e);
|
||||||
|
} finally {
|
||||||
|
sleepOneSecond(s, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DeleteTask implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (started) {
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
doDelete();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logError("DeleteTask Occurred Error", e);
|
||||||
|
} finally {
|
||||||
|
sleepOneSecond(s, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.publisher.hbase;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.config.HBaseConfig;
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.publisher.BasePublisher;
|
||||||
|
import com.hellobike.base.tunnel.publisher.IPublisher;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-11-27
|
||||||
|
*/
|
||||||
|
public class HBasePublisher extends BasePublisher implements IPublisher {
|
||||||
|
|
||||||
|
private final HBaseClient hBaseClient;
|
||||||
|
private final List<HBaseConfig> configs;
|
||||||
|
|
||||||
|
public HBasePublisher(List<HBaseConfig> configs) {
|
||||||
|
this.hBaseClient = getHBaseClient(configs);
|
||||||
|
this.configs = configs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(Event event, Callback callback) {
|
||||||
|
|
||||||
|
for (HBaseConfig config : configs) {
|
||||||
|
if (!config.getFilters().stream().allMatch(filter -> filter.filter(event))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (event.getEventType()) {
|
||||||
|
case INSERT:
|
||||||
|
hBaseClient.insert(config, event);
|
||||||
|
break;
|
||||||
|
case UPDATE:
|
||||||
|
hBaseClient.update(config, event);
|
||||||
|
break;
|
||||||
|
case DELETE:
|
||||||
|
hBaseClient.delete(config, event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
this.hBaseClient.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private HBaseClient getHBaseClient(List<HBaseConfig> configs) {
|
||||||
|
String quorum = configs.stream()
|
||||||
|
.map(HBaseConfig::getQuorum)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
return quorum == null ? HBaseClient.getInstance() : HBaseClient.getInstance(quorum);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.publisher.hdfs;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.fs.FSDataOutputStream;
|
||||||
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-11-30
|
||||||
|
*/
|
||||||
|
public class HdfsClient {
|
||||||
|
|
||||||
|
private Configuration configuration;
|
||||||
|
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
public void append(HdfsConfig config, Event event) {
|
||||||
|
try {
|
||||||
|
Configuration hadoopConfig = new Configuration();
|
||||||
|
FileSystem fileSystem = FileSystem.get(hadoopConfig);
|
||||||
|
Path hdfsPath = new Path(fileName);
|
||||||
|
FSDataOutputStream fileOutputStream = null;
|
||||||
|
try {
|
||||||
|
if (fileSystem.exists(hdfsPath)) {
|
||||||
|
fileOutputStream = fileSystem.append(hdfsPath);
|
||||||
|
} else {
|
||||||
|
fileOutputStream = fileSystem.create(hdfsPath);
|
||||||
|
}
|
||||||
|
fileOutputStream.writeUTF(JSON.toJSONString(event));
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (fileSystem != null) {
|
||||||
|
fileSystem.close();
|
||||||
|
}
|
||||||
|
if (fileOutputStream != null) {
|
||||||
|
fileOutputStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(HdfsConfig config, Event event) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(HdfsConfig config, Event event) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package com.hellobike.base.tunnel.publisher.hdfs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-11-30
|
||||||
|
*/
|
||||||
|
public class HdfsConfig {
|
||||||
|
}
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
package com.hellobike.base.tunnel.publisher.hdfs;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.publisher.BasePublisher;
|
||||||
|
import com.hellobike.base.tunnel.publisher.IPublisher;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-11-30
|
||||||
|
*/
|
||||||
|
public class HdfsPublisher extends BasePublisher implements IPublisher {
|
||||||
|
|
||||||
|
private List<HdfsConfig> configs;
|
||||||
|
private HdfsClient hdfsClient;
|
||||||
|
|
||||||
|
public HdfsPublisher(List<HdfsConfig> configs) {
|
||||||
|
this.configs = configs;
|
||||||
|
this.hdfsClient = new HdfsClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(Event event, Callback callback) {
|
||||||
|
for (HdfsConfig config : configs) {
|
||||||
|
switch (event.getEventType()) {
|
||||||
|
case INSERT:
|
||||||
|
this.hdfsClient.append(config, event);
|
||||||
|
break;
|
||||||
|
case DELETE:
|
||||||
|
this.hdfsClient.delete(config, event);
|
||||||
|
break;
|
||||||
|
case UPDATE:
|
||||||
|
this.hdfsClient.update(config, event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.publisher.hive;
|
||||||
|
|
||||||
|
import com.alibaba.druid.pool.DruidDataSource;
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.utils.MsgUtils;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-11-28
|
||||||
|
*/
|
||||||
|
public class HiveClient implements AutoCloseable {
|
||||||
|
|
||||||
|
private final DruidDataSource dataSource;
|
||||||
|
|
||||||
|
private final HiveConfig hiveConfig;
|
||||||
|
|
||||||
|
public HiveClient(HiveConfig hiveConfig) {
|
||||||
|
this.hiveConfig = hiveConfig;
|
||||||
|
this.dataSource = new DruidDataSource();
|
||||||
|
initDataSourceConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insert(Event event) {
|
||||||
|
try (Connection conn = getConnection();
|
||||||
|
Statement stmt = conn.createStatement()) {
|
||||||
|
|
||||||
|
String sql = MsgUtils.toInsert(event);
|
||||||
|
stmt.execute(sql);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(Event event) {
|
||||||
|
try (Connection conn = getConnection();
|
||||||
|
Statement stmt = conn.createStatement()) {
|
||||||
|
String sql = MsgUtils.toUpdate(event, this.hiveConfig.getPks());
|
||||||
|
stmt.execute(sql);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(Event event) {
|
||||||
|
try (Connection conn = getConnection();
|
||||||
|
Statement stmt = conn.createStatement()) {
|
||||||
|
String sql = MsgUtils.toDelete(event, this.hiveConfig.getPks());
|
||||||
|
stmt.execute(sql);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
this.dataSource.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Connection getConnection() throws SQLException {
|
||||||
|
return dataSource.getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initDataSourceConfig() {
|
||||||
|
this.dataSource.setUsername(this.hiveConfig.getUsername());
|
||||||
|
this.dataSource.setPassword(this.hiveConfig.getPassword());
|
||||||
|
this.dataSource.setUrl(this.hiveConfig.getHiveUrl());
|
||||||
|
this.dataSource.setValidationQuery("select 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.publisher.hive;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-11-27
|
||||||
|
*/
|
||||||
|
public class HiveConfig {
|
||||||
|
|
||||||
|
private String hiveUrl;
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
private String table;
|
||||||
|
|
||||||
|
private List<String> pks;
|
||||||
|
|
||||||
|
public String getHiveUrl() {
|
||||||
|
return hiveUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHiveUrl(String hiveUrl) {
|
||||||
|
this.hiveUrl = hiveUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPks() {
|
||||||
|
return pks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPks(List<String> pks) {
|
||||||
|
this.pks = pks;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.publisher.hive;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.publisher.BasePublisher;
|
||||||
|
import com.hellobike.base.tunnel.publisher.IPublisher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-11-27
|
||||||
|
*/
|
||||||
|
public class HivePublisher extends BasePublisher implements IPublisher {
|
||||||
|
|
||||||
|
private final HiveClient hiveClient;
|
||||||
|
|
||||||
|
public HivePublisher(HiveConfig hiveConfig) {
|
||||||
|
this.hiveClient = new HiveClient(hiveConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(Event event, Callback callback) {
|
||||||
|
//
|
||||||
|
switch (event.getEventType()) {
|
||||||
|
case INSERT:
|
||||||
|
hiveClient.insert(event);
|
||||||
|
break;
|
||||||
|
case DELETE:
|
||||||
|
hiveClient.delete(event);
|
||||||
|
break;
|
||||||
|
case UPDATE:
|
||||||
|
hiveClient.update(event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
hiveClient.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.publisher.kafka;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.hellobike.base.tunnel.config.KafkaConfig;
|
||||||
|
import com.hellobike.base.tunnel.model.ColumnData;
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.monitor.Statics;
|
||||||
|
import com.hellobike.base.tunnel.monitor.TunnelMonitorFactory;
|
||||||
|
import com.hellobike.base.tunnel.publisher.BasePublisher;
|
||||||
|
import com.hellobike.base.tunnel.publisher.IPublisher;
|
||||||
|
import org.apache.kafka.clients.producer.KafkaProducer;
|
||||||
|
import org.apache.kafka.clients.producer.ProducerConfig;
|
||||||
|
import org.apache.kafka.clients.producer.ProducerRecord;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-25
|
||||||
|
*/
|
||||||
|
public class KafkaPublisher extends BasePublisher implements IPublisher {
|
||||||
|
|
||||||
|
private static final Logger /**/ log = LoggerFactory.getLogger(KafkaPublisher.class);
|
||||||
|
|
||||||
|
private final List<KafkaConfig> /**/ kafkaConfigs;
|
||||||
|
private final KafkaProducer<String, String> /**/ producer;
|
||||||
|
|
||||||
|
public KafkaPublisher(List<KafkaConfig> kafkaConfigs) {
|
||||||
|
this.kafkaConfigs = kafkaConfigs;
|
||||||
|
this.producer = new KafkaProducer<>(getProperties(kafkaConfigs));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Properties getProperties(List<KafkaConfig> kafkaConfigs) {
|
||||||
|
KafkaConfig kafkaConfig = kafkaConfigs.get(0);
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaConfig.getServer());
|
||||||
|
props.put(ProducerConfig.ACKS_CONFIG, kafkaConfig.getAckConfig());
|
||||||
|
props.put(ProducerConfig.RETRIES_CONFIG, 0);
|
||||||
|
props.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
|
||||||
|
props.put(ProducerConfig.LINGER_MS_CONFIG, 1);
|
||||||
|
props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 33554432);
|
||||||
|
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, kafkaConfig.getKeySerializer());
|
||||||
|
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, kafkaConfig.getValSerializer());
|
||||||
|
props.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, "org.apache.kafka.clients.producer.internals.DefaultPartitioner");
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(Event event, Callback callback) {
|
||||||
|
|
||||||
|
this.kafkaConfigs.forEach(kafkaConfig -> internalPublish(kafkaConfig, event, callback));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
this.producer.close();
|
||||||
|
log.info("KafkaPublisher Closed");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void internalPublish(KafkaConfig kafkaConfig, Event event, Callback callback) {
|
||||||
|
if (kafkaConfig.getFilters() == null
|
||||||
|
|| kafkaConfig.getFilters().isEmpty()
|
||||||
|
|| kafkaConfig.getFilters().stream().allMatch(filter -> filter.filter(event))) {
|
||||||
|
sendToKafka(kafkaConfig, event, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendToKafka(KafkaConfig kafkaConfig, Event event, Callback callback) {
|
||||||
|
String value = JSON.toJSONString(event);
|
||||||
|
ProducerRecord<String, String> record = new ProducerRecord<>(kafkaConfig.getTopic(), getPrimaryKey(kafkaConfig, event), value);
|
||||||
|
String[] errors = new String[1];
|
||||||
|
try {
|
||||||
|
if (callback == null) {
|
||||||
|
producer.send(record);
|
||||||
|
} else {
|
||||||
|
producer.send(record,
|
||||||
|
(metadata, exception) -> {
|
||||||
|
if (exception != null) {
|
||||||
|
errors[0] = exception.getMessage();
|
||||||
|
KafkaPublisher.this.onFailure(callback, exception);
|
||||||
|
} else {
|
||||||
|
KafkaPublisher.this.onSuccess(callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
errors[0] = e.getMessage();
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
Statics statics = Statics.createStatics(
|
||||||
|
"AppTunnelService",
|
||||||
|
event.getSchema(),
|
||||||
|
event.getSlotName(),
|
||||||
|
event.getTable(),
|
||||||
|
1,
|
||||||
|
"kafka",
|
||||||
|
errors[0]
|
||||||
|
);
|
||||||
|
TunnelMonitorFactory.getTunnelMonitor().collect(statics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPrimaryKey(KafkaConfig kafkaConfig, Event event) {
|
||||||
|
List<String> pkNames = kafkaConfig.getPkNames();
|
||||||
|
if (pkNames == null || pkNames.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Map<String, String> data = event.getDataList().stream().collect(Collectors.toMap(ColumnData::getName, ColumnData::getValue));
|
||||||
|
return kafkaConfig.getPkNames().stream().map(data::get).reduce((s1, s2) -> s1 + "_" + s2).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package com.hellobike.base.tunnel.store;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.InvokeContext;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-25
|
||||||
|
*/
|
||||||
|
public interface IStore {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一次sql事件
|
||||||
|
*
|
||||||
|
* @param ctx 上下文
|
||||||
|
*/
|
||||||
|
void store(InvokeContext ctx);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.store;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.model.InvokeContext;
|
||||||
|
import com.hellobike.base.tunnel.publisher.PublisherManager;
|
||||||
|
import com.hellobike.base.tunnel.utils.NamedThreadFactory;
|
||||||
|
import com.hellobike.base.tunnel.utils.TimeUtils;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-10-25
|
||||||
|
*/
|
||||||
|
public class MemStore implements IStore, AutoCloseable {
|
||||||
|
|
||||||
|
private static final int PER_CONTEXTS = 10240;
|
||||||
|
private static final int MAX_CONTEXTS = PER_CONTEXTS * 5;
|
||||||
|
|
||||||
|
private static final int CPU_NUMBERS = Runtime.getRuntime().availableProcessors();
|
||||||
|
private static final int THD_NUMBERS = CPU_NUMBERS << 1;
|
||||||
|
|
||||||
|
private final AtomicBoolean started = new AtomicBoolean(Boolean.FALSE);
|
||||||
|
private final Map<String, BlockingQueue<InvokeContext>> caches;
|
||||||
|
private final ThreadPoolExecutor executor;
|
||||||
|
|
||||||
|
public MemStore() {
|
||||||
|
this.caches = new ConcurrentHashMap<>();
|
||||||
|
this.executor = new ThreadPoolExecutor(
|
||||||
|
THD_NUMBERS, THD_NUMBERS,
|
||||||
|
60, TimeUnit.SECONDS,
|
||||||
|
new LinkedBlockingQueue<>(MAX_CONTEXTS),
|
||||||
|
new NamedThreadFactory("")
|
||||||
|
);
|
||||||
|
|
||||||
|
this.started.compareAndSet(Boolean.FALSE, Boolean.TRUE);
|
||||||
|
for (int i = 0; i < THD_NUMBERS; i++) {
|
||||||
|
this.executor.submit(new ConsumeTask());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean eventIsEmpty(Event event) {
|
||||||
|
return event == null ||
|
||||||
|
(event.getSchema() == null
|
||||||
|
&& event.getTable() == null
|
||||||
|
&& event.getEventType() == null
|
||||||
|
&& (event.getDataList() == null || event.getDataList().isEmpty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean ctxIsEmpty(InvokeContext ctx) {
|
||||||
|
return ctx == null || eventIsEmpty(ctx.getEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void store(InvokeContext ctx) {
|
||||||
|
if (ctxIsEmpty(ctx)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PublisherManager.getInstance().publish(ctx, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
this.started.compareAndSet(Boolean.TRUE, Boolean.FALSE);
|
||||||
|
this.executor.shutdown();
|
||||||
|
this.caches.values().forEach(BlockingQueue::clear);
|
||||||
|
this.caches.values().clear();
|
||||||
|
this.caches.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void asyncPublish(InvokeContext ctx) {
|
||||||
|
if (ctxIsEmpty(ctx)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockingQueue<InvokeContext> queue = putToCache(ctx);
|
||||||
|
if (queue.size() > PER_CONTEXTS) {
|
||||||
|
forceFlushMemory(queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized BlockingQueue<InvokeContext> putToCache(InvokeContext context) {
|
||||||
|
BlockingQueue<InvokeContext> blockingQueue = caches.get(context.getSlotName());
|
||||||
|
if (blockingQueue == null) {
|
||||||
|
caches.put(context.getSlotName(), new LinkedBlockingQueue<>(MAX_CONTEXTS));
|
||||||
|
blockingQueue = caches.get(context.getSlotName());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
blockingQueue.put(context);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
return blockingQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forceFlushMemory(BlockingQueue<InvokeContext> queue) {
|
||||||
|
if (queue.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int capacity = started.get() ? Math.min(PER_CONTEXTS, queue.size()) : queue.size();
|
||||||
|
List<InvokeContext> contexts = new LinkedList<>();
|
||||||
|
queue.drainTo(contexts, capacity);
|
||||||
|
PublisherManager.getInstance().publish(contexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ConsumeTask implements Runnable {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (started.get()) {
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
for (BlockingQueue<InvokeContext> queue : caches.values()) {
|
||||||
|
forceFlushMemory(queue);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
long e = System.currentTimeMillis();
|
||||||
|
TimeUtils.sleepOneSecond(s, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BlockingQueue<InvokeContext> queue : caches.values()) {
|
||||||
|
forceFlushMemory(queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,99 @@
|
|||||||
|
package com.hellobike.base.tunnel.utils;
|
||||||
|
|
||||||
|
import org.apache.commons.pool2.BasePooledObjectFactory;
|
||||||
|
import org.apache.commons.pool2.PooledObject;
|
||||||
|
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||||
|
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||||
|
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-03
|
||||||
|
*/
|
||||||
|
public class CommonPool<T> implements ObjectPool<T> {
|
||||||
|
|
||||||
|
private final ObjectManager<T> manager;
|
||||||
|
private final GenericObjectPool<T> pool;
|
||||||
|
|
||||||
|
public CommonPool(ObjectManager<T> manager) {
|
||||||
|
this.manager = manager;
|
||||||
|
this.pool = newObjectPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T borrowObject() {
|
||||||
|
try {
|
||||||
|
return pool.borrowObject();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new UnsupportedOperationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void returnObject(T obj) {
|
||||||
|
pool.returnObject(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
this.pool.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private GenericObjectPool<T> newObjectPool() {
|
||||||
|
GenericObjectPool<T> pool = new GenericObjectPool<>(new CommonFactory()); // NOSONAR
|
||||||
|
pool.setConfig(newPoolConfig());
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GenericObjectPoolConfig<T> newPoolConfig() {
|
||||||
|
GenericObjectPoolConfig<T> config = new GenericObjectPoolConfig<>();
|
||||||
|
config.setTestWhileIdle(true);
|
||||||
|
config.setTestOnCreate(true);
|
||||||
|
config.setTestOnBorrow(true);
|
||||||
|
config.setTestOnReturn(false);
|
||||||
|
config.setMaxTotal(100);
|
||||||
|
config.setMinIdle(30);
|
||||||
|
config.setMaxIdle(80);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CommonFactory extends BasePooledObjectFactory<T> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T create() throws Exception {
|
||||||
|
return manager.newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PooledObject<T> wrap(T t) {
|
||||||
|
return new DefaultPooledObject<>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validateObject(PooledObject<T> p) {
|
||||||
|
return manager.validateInstance(p.getObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroyObject(PooledObject<T> p) {
|
||||||
|
manager.releaseInstance(p.getObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package com.hellobike.base.tunnel.utils;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-05
|
||||||
|
*/
|
||||||
|
public class DefaultObjectPoolFactory implements ObjectPoolFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> ObjectPool<T> createObjectPool(ObjectManager<T> manager) {
|
||||||
|
return new CommonPool<>(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.utils;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.TunnelLauncher;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-26
|
||||||
|
*/
|
||||||
|
public class FileUtils {
|
||||||
|
|
||||||
|
private FileUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InputStream load(String file) {
|
||||||
|
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(file);
|
||||||
|
if (is == null) {
|
||||||
|
is = TunnelLauncher.class.getResourceAsStream(file);
|
||||||
|
}
|
||||||
|
if (is == null) {
|
||||||
|
is = loadFromFileSystem(file);
|
||||||
|
}
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InputStream loadFromFileSystem(String configPath) {
|
||||||
|
if (Paths.get(configPath).toFile().exists()) {
|
||||||
|
try {
|
||||||
|
return new FileInputStream(Paths.get(configPath).toFile());
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
package com.hellobike.base.tunnel.utils;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-10
|
||||||
|
*/
|
||||||
|
public class MsgUtils {
|
||||||
|
|
||||||
|
|
||||||
|
private MsgUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toUpdate(Event event, List<String> pkNames) {
|
||||||
|
String schema = event.getSchema();
|
||||||
|
String table = event.getTable();
|
||||||
|
|
||||||
|
String kv = event.getDataList().stream().map(cd -> cd.getName() + "=" + cd.getValue()).reduce((s1, s2) -> s1 + "," + s2).orElse("");
|
||||||
|
String pk = getPKValues(event, pkNames);
|
||||||
|
|
||||||
|
return "update " + schema + "." + table + " set " + pk + " where " + kv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toDelete(Event event, List<String> pkNames) {
|
||||||
|
String schema = event.getSchema();
|
||||||
|
String table = event.getTable();
|
||||||
|
String pk = getPKValues(event, pkNames);
|
||||||
|
return "delete from " + schema + "." + table + " where " + pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toInsert(Event event) {
|
||||||
|
String schema = event.getSchema();
|
||||||
|
String table = event.getTable();
|
||||||
|
|
||||||
|
List<String> keys = new ArrayList<>();
|
||||||
|
List<String> vals = new ArrayList<>();
|
||||||
|
event.getDataList().forEach(cd -> {
|
||||||
|
keys.add(cd.getName());
|
||||||
|
vals.add("'" + cd.getValue() + "'");
|
||||||
|
});
|
||||||
|
|
||||||
|
return "insert into " + schema + "." + table + "(" + StringUtils.join(keys, ',') + ") values(" + StringUtils.join(vals, ',') + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getPKValues(Event event, List<String> pkNames) {
|
||||||
|
return event.getDataList().stream()
|
||||||
|
.filter(cd -> pkNames.contains(cd.getName()))
|
||||||
|
.map(cd -> cd.getName() + "=" + cd.getValue())
|
||||||
|
.reduce((s1, s2) -> s1 + "," + s2)
|
||||||
|
.orElse("");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
package com.hellobike.base.tunnel.utils;
|
||||||
|
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-11-23
|
||||||
|
*/
|
||||||
|
public class NamedThreadFactory implements ThreadFactory {
|
||||||
|
private final AtomicInteger index = new AtomicInteger();
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public NamedThreadFactory(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable r) {
|
||||||
|
return new Thread(r, this.name + "-" + index.incrementAndGet());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
package com.hellobike.base.tunnel.utils;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-03
|
||||||
|
*/
|
||||||
|
public interface ObjectManager<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产生一个实例
|
||||||
|
*
|
||||||
|
* @return 实例
|
||||||
|
* @throws Exception 错误信息
|
||||||
|
*/
|
||||||
|
T newInstance() throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放资源
|
||||||
|
*
|
||||||
|
* @param instance 实例
|
||||||
|
*/
|
||||||
|
default void releaseInstance(T instance) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
default boolean validateInstance(T instance) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
package com.hellobike.base.tunnel.utils;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-03
|
||||||
|
*/
|
||||||
|
public interface ObjectPool<T> extends AutoCloseable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a object from pool
|
||||||
|
*
|
||||||
|
* @return instance
|
||||||
|
*/
|
||||||
|
T borrowObject();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return obj to pool
|
||||||
|
*
|
||||||
|
* @param obj object
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
void returnObject(T obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放资源
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void close();
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package com.hellobike.base.tunnel.utils;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-05
|
||||||
|
*/
|
||||||
|
public interface ObjectPoolFactory {
|
||||||
|
|
||||||
|
<T> ObjectPool<T> createObjectPool(ObjectManager<T> manager);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.hellobike.base.tunnel.utils;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao
|
||||||
|
*/
|
||||||
|
public class TimeUtils {
|
||||||
|
|
||||||
|
private TimeUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sleepInMills(long mills) {
|
||||||
|
if (mills <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(mills);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sleepOneSecond(long s, long e) {
|
||||||
|
long cost = 1000 + s - e;
|
||||||
|
TimeUtils.sleepInMills(cost);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
tunnel-server/src/main/resources/META-INF/app.properties
Normal file
1
tunnel-server/src/main/resources/META-INF/app.properties
Normal file
@ -0,0 +1 @@
|
|||||||
|
app.id=AppTunnelService
|
||||||
1
tunnel-server/src/main/resources/conf/.gitignore
vendored
Normal file
1
tunnel-server/src/main/resources/conf/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.properties
|
||||||
30
tunnel-server/src/main/resources/log4j2.xml
Normal file
30
tunnel-server/src/main/resources/log4j2.xml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- copy from sprint boot -->
|
||||||
|
<Configuration status="warn" shutdownHook="disable">
|
||||||
|
<Properties>
|
||||||
|
<Property name="PID">????</Property>
|
||||||
|
<Property name="LOG_LEVEL_PATTERN">%5p</Property>
|
||||||
|
<Property name="CONSOLE_LOG_PATTERN">[%d{yyyy-MM-dd HH:mm:ss.SSS}] [${LOG_LEVEL_PATTERN}] [%20.20t] [%-40.40c{1.}] %m%n</Property>
|
||||||
|
<Property name="LOG_HOME">logs</Property>
|
||||||
|
</Properties>
|
||||||
|
<Appenders>
|
||||||
|
<Console name="Console" target="SYSTEM_OUT" follow="true">
|
||||||
|
<PatternLayout pattern="${sys:CONSOLE_LOG_PATTERN}"/>
|
||||||
|
</Console>
|
||||||
|
<File name="LogFile" fileName="logs/tunnel.log">
|
||||||
|
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||||
|
<PatternLayout>
|
||||||
|
<Pattern>${sys:CONSOLE_LOG_PATTERN}</Pattern>
|
||||||
|
</PatternLayout>
|
||||||
|
</File>
|
||||||
|
<Async name="Async" BufferSize="65536">
|
||||||
|
<AppenderRef ref="LogFile"/>
|
||||||
|
</Async>
|
||||||
|
</Appenders>
|
||||||
|
<Loggers>
|
||||||
|
<AsyncRoot level="info">
|
||||||
|
<AppenderRef ref="Console"/>
|
||||||
|
<AppenderRef ref="Async"/>
|
||||||
|
</AsyncRoot>
|
||||||
|
</Loggers>
|
||||||
|
</Configuration>
|
||||||
7
tunnel-server/src/main/resources/yukon.properties
Normal file
7
tunnel-server/src/main/resources/yukon.properties
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
yukon.appender.a2.name=kafkaAppender
|
||||||
|
yukon.appender.a2.class=com.hellobike.yukon.kafka11.appender.KafkaAppender
|
||||||
|
yukon.appender.a2.topic=pg_transfer_monitor-dev
|
||||||
|
yukon.appender.a2.brokers=10.111.70.58:9092,10.111.70.59:9092,10.111.70.60:9092
|
||||||
|
yukon.logger.l1.name=TunnelLogger
|
||||||
|
yukon.logger.l1.level=info
|
||||||
|
yukon.logger.l1.appenderRef=kafkaAppender
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.utils.TimeUtils;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-05
|
||||||
|
*/
|
||||||
|
public class TunnelServerTest {
|
||||||
|
|
||||||
|
private static volatile boolean stopped = false;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_threadPool() {
|
||||||
|
int total = 4;
|
||||||
|
ThreadPoolExecutor executor = new ThreadPoolExecutor(total, total, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100));
|
||||||
|
|
||||||
|
for (int i = 0; i < total; i++) {
|
||||||
|
executor.submit(new Task(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
executor.awaitTermination(1, TimeUnit.SECONDS);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
stopped = true;
|
||||||
|
executor.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Task implements Runnable {
|
||||||
|
|
||||||
|
private final int idx;
|
||||||
|
|
||||||
|
private Task(int idx) {
|
||||||
|
this.idx = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (!stopped) {
|
||||||
|
TimeUtils.sleepInMills(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Task{" +
|
||||||
|
"idx=" + idx +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.config.file;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-26
|
||||||
|
*/
|
||||||
|
public class FileConfigLoaderTest {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FileConfigLoaderTest.class);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFileConfigLoader() {
|
||||||
|
String file = "test_config.properties";
|
||||||
|
FileConfigLoader loader = new FileConfigLoader(getFilePath(file));
|
||||||
|
loader.addChangeListener((key, oldValue, newValue) -> log.info("key:{},old:{},new:{}", key, oldValue, newValue));
|
||||||
|
try {
|
||||||
|
Thread.currentThread().join(1000 * 60 * 10);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
loader.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFilePath(String file) {
|
||||||
|
URL url = Thread.currentThread().getContextClassLoader().getResource(file);
|
||||||
|
if (url == null) {
|
||||||
|
url = FileConfigLoaderTest.class.getClassLoader().getResource(file);
|
||||||
|
}
|
||||||
|
if (url == null) {
|
||||||
|
File f = Paths.get(file).toFile();
|
||||||
|
if (f.exists()) {
|
||||||
|
return f.getPath();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return url.getPath();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-26
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.config;
|
||||||
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.filter;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.ColumnData;
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.model.EventType;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-11-07
|
||||||
|
*/
|
||||||
|
public class FilterTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_ColumnFilter() {
|
||||||
|
Event event = new Event();
|
||||||
|
|
||||||
|
ColumnFilter filter = new ColumnFilter(null);
|
||||||
|
boolean ret = filter.filter(event);
|
||||||
|
Assert.assertTrue(ret);
|
||||||
|
|
||||||
|
filter = new ColumnFilter(new ArrayList<>());
|
||||||
|
ret = filter.filter(event);
|
||||||
|
Assert.assertTrue(ret);
|
||||||
|
|
||||||
|
filter = new ColumnFilter(new ArrayList<>(Arrays.asList("Tom", "Age")));
|
||||||
|
List<ColumnData> columnDataList = new ArrayList<>();
|
||||||
|
event.setDataList(columnDataList);
|
||||||
|
ret = filter.filter(event);
|
||||||
|
Assert.assertFalse(ret);
|
||||||
|
|
||||||
|
ColumnData data = new ColumnData();
|
||||||
|
data.setName("om");
|
||||||
|
columnDataList.add(data);
|
||||||
|
ret = filter.filter(event);
|
||||||
|
Assert.assertTrue(ret);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_EventTypeFilter() {
|
||||||
|
EventTypeFilter filter = new EventTypeFilter(EventType.DELETE);
|
||||||
|
boolean ret = filter.filter(null);
|
||||||
|
Assert.assertFalse(ret);
|
||||||
|
|
||||||
|
Event event = new Event();
|
||||||
|
event.setEventType(EventType.DELETE);
|
||||||
|
ret = filter.filter(event);
|
||||||
|
Assert.assertTrue(ret);
|
||||||
|
|
||||||
|
event.setEventType(EventType.INSERT);
|
||||||
|
ret = filter.filter(event);
|
||||||
|
Assert.assertFalse(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_SchemaFilter() {
|
||||||
|
SchemaFilter filter = new SchemaFilter(null);
|
||||||
|
boolean ret = filter.filter(null);
|
||||||
|
Assert.assertFalse(ret);
|
||||||
|
|
||||||
|
Event event = new Event();
|
||||||
|
ret = filter.filter(event);
|
||||||
|
Assert.assertFalse(ret);
|
||||||
|
|
||||||
|
filter = new SchemaFilter(null);
|
||||||
|
event.setSchema("Tom");
|
||||||
|
ret = filter.filter(event);
|
||||||
|
Assert.assertTrue(ret);
|
||||||
|
|
||||||
|
filter = new SchemaFilter("Tom");
|
||||||
|
event.setSchema("Tom");
|
||||||
|
ret = filter.filter(event);
|
||||||
|
Assert.assertTrue(ret);
|
||||||
|
|
||||||
|
filter = new SchemaFilter("Tom");
|
||||||
|
event.setSchema("Jack");
|
||||||
|
ret = filter.filter(event);
|
||||||
|
Assert.assertFalse(ret);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_TableNameFilter() {
|
||||||
|
TableNameFilter filter = new TableNameFilter(null);
|
||||||
|
boolean ret = filter.filter(null);
|
||||||
|
Assert.assertFalse(ret);
|
||||||
|
|
||||||
|
Event event = new Event();
|
||||||
|
ret = filter.filter(event);
|
||||||
|
Assert.assertFalse(ret);
|
||||||
|
|
||||||
|
filter = new TableNameFilter("Tom.*");
|
||||||
|
event.setTable("Tom123");
|
||||||
|
ret = filter.filter(event);
|
||||||
|
Assert.assertTrue(ret);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.ha;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-11-07
|
||||||
|
*/
|
||||||
|
public class ZkLockTest {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(ZkLockTest.class);
|
||||||
|
|
||||||
|
private static final ExecutorService EXECUTOR =
|
||||||
|
new ThreadPoolExecutor(
|
||||||
|
10, 10,
|
||||||
|
0, TimeUnit.MICROSECONDS,
|
||||||
|
new ArrayBlockingQueue<>(10),
|
||||||
|
new ThreadFactory() {
|
||||||
|
private final AtomicInteger index = new AtomicInteger();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable r) {
|
||||||
|
Thread t = new Thread(r, "TestLock-" + index.incrementAndGet());
|
||||||
|
t.setDaemon(false);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_lock() {
|
||||||
|
ZkLock lock = new ZkLock("localhost:2181", "/tunnel/test/lock");
|
||||||
|
lock.tryLock();
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
int total = 10;
|
||||||
|
CountDownLatch latch = new CountDownLatch(total);
|
||||||
|
CyclicBarrier barrier = new CyclicBarrier(total);
|
||||||
|
Runnable task = () -> {
|
||||||
|
try {
|
||||||
|
barrier.await();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
LOGGER.info("thread:{} active", Thread.currentThread().getName());
|
||||||
|
if (lock.tryLock()) {
|
||||||
|
try {
|
||||||
|
LOGGER.info("thread:{} lock success", Thread.currentThread().getName());
|
||||||
|
Thread.sleep(10L);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
LOGGER.info("thread:{} release lock success", Thread.currentThread().getName());
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < total; i++) {
|
||||||
|
EXECUTOR.submit(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
latch.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
EXECUTOR.shutdown();
|
||||||
|
lock.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.parse;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.InvokeContext;
|
||||||
|
import com.hellobike.base.tunnel.store.MemStore;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-11-07
|
||||||
|
*/
|
||||||
|
public class EventParserTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_parse() {
|
||||||
|
|
||||||
|
EventParser parser = new EventParser();
|
||||||
|
String serverId = "server-id1";
|
||||||
|
InvokeContext ctx = new InvokeContext();
|
||||||
|
ctx.setSlotName("test_slot");
|
||||||
|
ctx.setServerId(serverId);
|
||||||
|
ctx.setLsn(1000L);
|
||||||
|
|
||||||
|
String msg = "begin 12345";
|
||||||
|
|
||||||
|
ctx.setMessage(msg);
|
||||||
|
parser.parse(ctx);
|
||||||
|
|
||||||
|
msg = "commit 12345";
|
||||||
|
ctx.setMessage(msg);
|
||||||
|
parser.parse(ctx);
|
||||||
|
|
||||||
|
msg = "table public.test_logic_table: INSERT: pk[integer]:1 name[character varying]:'previous value'";
|
||||||
|
ctx.setMessage(msg);
|
||||||
|
MemStore mock = Mockito.mock(MemStore.class);
|
||||||
|
Mockito.doNothing().when(mock).store(Mockito.any());
|
||||||
|
parser.setMemStore(mock);
|
||||||
|
|
||||||
|
parser.parse(ctx);
|
||||||
|
|
||||||
|
msg = "table public.test_logic_table: DELETE: (no-tuple-data)";
|
||||||
|
ctx.setMessage(msg);
|
||||||
|
parser.parse(ctx);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.publisher;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.config.EsConfig;
|
||||||
|
import com.hellobike.base.tunnel.filter.IEventFilter;
|
||||||
|
import com.hellobike.base.tunnel.filter.TableNameFilter;
|
||||||
|
import com.hellobike.base.tunnel.model.ColumnData;
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.model.EventType;
|
||||||
|
import com.hellobike.base.tunnel.model.InvokeContext;
|
||||||
|
import com.hellobike.base.tunnel.publisher.es.EsPublisher;
|
||||||
|
import com.hellobike.base.tunnel.utils.TimeUtils;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import pl.allegro.tech.embeddedelasticsearch.EmbeddedElastic;
|
||||||
|
import pl.allegro.tech.embeddedelasticsearch.PopularProperties;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-11-08
|
||||||
|
*/
|
||||||
|
public class EsPublisherTest {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(EsPublisherTest.class);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_EsPublisher() {
|
||||||
|
EmbeddedElastic elastic = EmbeddedElastic.builder()
|
||||||
|
.withElasticVersion("5.0.0")
|
||||||
|
.withSetting(PopularProperties.HTTP_PORT, 9200)
|
||||||
|
.build();
|
||||||
|
try {
|
||||||
|
elastic.start();
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
// http://localhost:9200
|
||||||
|
String table = "";
|
||||||
|
List<IEventFilter> filters = new ArrayList<>(Collections.singleton(new TableNameFilter(table)));
|
||||||
|
|
||||||
|
EsConfig esConfig = new EsConfig();
|
||||||
|
esConfig.setServer("http://localhost:9200");
|
||||||
|
esConfig.setEsIdFieldNames(Collections.singletonList("id"));
|
||||||
|
esConfig.setPkFieldNames(Collections.singletonList("id"));
|
||||||
|
esConfig.setSchema("test1");
|
||||||
|
esConfig.setTable("t_user");
|
||||||
|
esConfig.setIndex("idx_t_u");
|
||||||
|
esConfig.setType("logs");
|
||||||
|
esConfig.setFilters(filters);
|
||||||
|
|
||||||
|
List<EsConfig> esConfigs = new ArrayList<>(Collections.singleton(esConfig));
|
||||||
|
EsPublisher publisher = new EsPublisher(esConfigs);
|
||||||
|
|
||||||
|
ColumnData cd1 = new ColumnData();
|
||||||
|
cd1.setName("id");
|
||||||
|
cd1.setDataType("integer");
|
||||||
|
cd1.setValue("1001");
|
||||||
|
|
||||||
|
ColumnData cd2 = new ColumnData();
|
||||||
|
cd2.setName("name");
|
||||||
|
cd2.setDataType("varchar");
|
||||||
|
cd2.setValue("tom hanks");
|
||||||
|
|
||||||
|
ColumnData cd3 = new ColumnData();
|
||||||
|
cd3.setName("sex");
|
||||||
|
cd3.setDataType("varchar");
|
||||||
|
cd3.setValue("mail");
|
||||||
|
|
||||||
|
ColumnData cd4 = new ColumnData();
|
||||||
|
cd4.setName("email");
|
||||||
|
cd4.setDataType("varchar");
|
||||||
|
cd4.setValue("xxx@tom.com");
|
||||||
|
List<ColumnData> dataList = new ArrayList<>(Arrays.asList(cd1, cd2, cd3, cd4));
|
||||||
|
|
||||||
|
Event event = new Event();
|
||||||
|
event.setSchema("test1");
|
||||||
|
event.setTable("t_user");
|
||||||
|
event.setEventType(EventType.INSERT);
|
||||||
|
event.setDataList(dataList);
|
||||||
|
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
InvokeContext ctx = new InvokeContext();
|
||||||
|
ctx.setEvent(event);
|
||||||
|
publisher.publish(ctx, new IPublisher.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
LOGGER.info("success");
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t) {
|
||||||
|
LOGGER.info("failure", t);
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
latch.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
event.setEventType(EventType.UPDATE);
|
||||||
|
CountDownLatch latch3 = new CountDownLatch(1);
|
||||||
|
publisher.publish(ctx, new IPublisher.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
LOGGER.info("success3");
|
||||||
|
latch3.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t) {
|
||||||
|
LOGGER.info("failure3", t);
|
||||||
|
latch3.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
event.setEventType(EventType.BEGIN);
|
||||||
|
publisher.publish(ctx, null);
|
||||||
|
|
||||||
|
|
||||||
|
event.setEventType(EventType.DELETE);
|
||||||
|
CountDownLatch latch2 = new CountDownLatch(1);
|
||||||
|
publisher.publish(ctx, new IPublisher.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
LOGGER.info("success2");
|
||||||
|
latch2.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t) {
|
||||||
|
LOGGER.info("failure2", t);
|
||||||
|
latch2.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
latch2.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
elastic.stop();
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
publisher.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_BlockingQueue() {
|
||||||
|
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>(16);
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
queue.add("idx-" + i);
|
||||||
|
}
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
queue.drainTo(list, 8);
|
||||||
|
Assert.assertEquals(queue.size(), list.size());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_cost() {
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (i < 10) {
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
func1();
|
||||||
|
long e = System.currentTimeMillis();
|
||||||
|
|
||||||
|
long cost = 1000 - (e - s);
|
||||||
|
|
||||||
|
TimeUtils.sleepInMills(cost);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void func1() {
|
||||||
|
TimeUtils.sleepInMills(100L);
|
||||||
|
LOGGER.info("called");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.publisher;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.config.KafkaConfig;
|
||||||
|
import com.hellobike.base.tunnel.filter.IEventFilter;
|
||||||
|
import com.hellobike.base.tunnel.filter.TableNameFilter;
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.publisher.kafka.KafkaPublisher;
|
||||||
|
import net.manub.embeddedkafka.EmbeddedKafka;
|
||||||
|
import net.manub.embeddedkafka.EmbeddedKafkaConfig;
|
||||||
|
import net.manub.embeddedkafka.EmbeddedKafkaConfigImpl;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import scala.collection.immutable.HashMap;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-11-08
|
||||||
|
*/
|
||||||
|
public class KafkaPublisherTest {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(KafkaPublisherTest.class);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_KafkaPublisher() {
|
||||||
|
|
||||||
|
EmbeddedKafkaConfig cfg = new EmbeddedKafkaConfigImpl(9093, 2182, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
|
EmbeddedKafka.start(cfg);
|
||||||
|
String address = "localhost:9093";
|
||||||
|
KafkaConfig kafkaConfig = new KafkaConfig();
|
||||||
|
kafkaConfig.setServer(address);
|
||||||
|
kafkaConfig.setTopic("test1");
|
||||||
|
kafkaConfig.setPartition(-1);
|
||||||
|
List<KafkaConfig> kafkaConfigs = new ArrayList<>(Collections.singleton(kafkaConfig));
|
||||||
|
|
||||||
|
String table = "";
|
||||||
|
List<IEventFilter> filters = new ArrayList<>(Collections.singleton(new TableNameFilter(table)));
|
||||||
|
kafkaConfig.setFilters(filters);
|
||||||
|
KafkaPublisher publisher = new KafkaPublisher(kafkaConfigs);
|
||||||
|
|
||||||
|
Event event = new Event();
|
||||||
|
event.setTable("t1");
|
||||||
|
CountDownLatch latch1 = new CountDownLatch(1);
|
||||||
|
IPublisher.Callback callback = new IPublisher.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
LOGGER.info("success");
|
||||||
|
latch1.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t) {
|
||||||
|
LOGGER.info("failure", t);
|
||||||
|
latch1.countDown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
publisher.publish(event, callback);
|
||||||
|
try {
|
||||||
|
latch1.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
publisher.publish(event, null);
|
||||||
|
|
||||||
|
|
||||||
|
table = "abc";
|
||||||
|
filters = new ArrayList<>(Collections.singleton(new TableNameFilter(table)));
|
||||||
|
kafkaConfig.setFilters(filters);
|
||||||
|
publisher = new KafkaPublisher(kafkaConfigs);
|
||||||
|
CountDownLatch latch2 = new CountDownLatch(1);
|
||||||
|
event.setTable("def");
|
||||||
|
|
||||||
|
publisher.publish(event, new IPublisher.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
latch2.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t) {
|
||||||
|
LOGGER.warn("", t);
|
||||||
|
latch2.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
latch2.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
EmbeddedKafka.stop();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.publisher;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-11-12
|
||||||
|
*/
|
||||||
|
public class PublisherManagerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_PublisherManager() {
|
||||||
|
|
||||||
|
PublisherManager.getInstance().putPublisher("test123", (event, callback) -> { /**/ });
|
||||||
|
PublisherManager.getInstance().putPublisher("test456", (event, callback) -> { /**/ });
|
||||||
|
PublisherManager.getInstance().publish((Event) null, null);
|
||||||
|
PublisherManager.getInstance().publish((Event) null, new IPublisher.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
PublisherManager.getInstance().publish(new Event(), null);
|
||||||
|
PublisherManager.getInstance().publish(new Event(), new IPublisher.Callback() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.publisher.hbase;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.config.HBaseConfig;
|
||||||
|
import com.hellobike.base.tunnel.model.ColumnData;
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.model.EventType;
|
||||||
|
import com.hellobike.base.tunnel.utils.TimeUtils;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-11-28
|
||||||
|
*/
|
||||||
|
public class HBaseClientTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_HBaseClient() {
|
||||||
|
HBaseClient client = HBaseClient.getInstance();
|
||||||
|
Assert.assertNotNull(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_HBaseClient_insert() {
|
||||||
|
HBaseClient client = HBaseClient.getInstance();
|
||||||
|
String rowKey = "number";
|
||||||
|
Event event = new Event();
|
||||||
|
event.setSchema("db1");
|
||||||
|
event.setTable("go_hbase_score");
|
||||||
|
event.setEventType(EventType.INSERT);
|
||||||
|
List<ColumnData> dataList = event.getDataList();
|
||||||
|
ColumnData cd1 = new ColumnData();
|
||||||
|
cd1.setName("number");
|
||||||
|
cd1.setValue("1123");
|
||||||
|
cd1.setDataType("integer");
|
||||||
|
dataList.add(cd1);
|
||||||
|
HBaseConfig config = new HBaseConfig();
|
||||||
|
config.setFamily("f1");
|
||||||
|
config.setQualifier("q1");
|
||||||
|
config.setHbaseTable("go_hbase_score");
|
||||||
|
config.setPks(Collections.singletonList("number"));
|
||||||
|
config.setHbaseKey(Collections.singletonList("number"));
|
||||||
|
client.insert(config, event);
|
||||||
|
|
||||||
|
TimeUtils.sleepInMills(5000L);
|
||||||
|
client.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_HBaseClient_update() {
|
||||||
|
HBaseClient client = HBaseClient.getInstance();
|
||||||
|
String rowKey = "pk001";
|
||||||
|
Event event = new Event();
|
||||||
|
HBaseConfig config = new HBaseConfig();
|
||||||
|
client.update(config, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_HBaseClient_delete() {
|
||||||
|
HBaseClient client = HBaseClient.getInstance();
|
||||||
|
String rowKey = "pk001";
|
||||||
|
Event event = new Event();
|
||||||
|
event.setTable("tb1");
|
||||||
|
HBaseConfig config = new HBaseConfig();
|
||||||
|
client.delete(config, event);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_HBaseClient_get() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.publisher.hbase;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.config.HBaseConfig;
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.publisher.IPublisher.Callback;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-05
|
||||||
|
*/
|
||||||
|
public class HBasePublisherTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_publish() {
|
||||||
|
HBaseConfig config = new HBaseConfig();
|
||||||
|
config.setFamily("tb1_family");
|
||||||
|
config.setQualifier("tb1_qualifier");
|
||||||
|
config.setPks(Collections.singletonList("id"));
|
||||||
|
|
||||||
|
HBasePublisher publisher = new HBasePublisher(Collections.singletonList(config));
|
||||||
|
Callback callback = new EmptyCallback();
|
||||||
|
Event event = new Event();
|
||||||
|
publisher.publish(event, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class EmptyCallback implements Callback {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.publisher.hive;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.ColumnData;
|
||||||
|
import com.hellobike.base.tunnel.model.Event;
|
||||||
|
import com.hellobike.base.tunnel.model.EventType;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-03
|
||||||
|
*/
|
||||||
|
public class HiveClientTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_insert() {
|
||||||
|
HiveConfig config = new HiveConfig();
|
||||||
|
config.setHiveUrl("jdbc:hive2://10.111.20.161:10000/default;ssl=false;");
|
||||||
|
HiveClient hiveClient = new HiveClient(config);
|
||||||
|
hiveClient.insert(newEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_find() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private Event newEvent() {
|
||||||
|
Event e = new Event();
|
||||||
|
e.setTable("test1");
|
||||||
|
e.setEventType(EventType.INSERT);
|
||||||
|
e.setSchema("default");
|
||||||
|
e.getDataList().add(new ColumnData("user_id", "string", "1001"));
|
||||||
|
e.getDataList().add(new ColumnData("device_id", "string", "20001"));
|
||||||
|
e.getDataList().add(new ColumnData("price", "double", "20001.0"));
|
||||||
|
e.getDataList().add(new ColumnData("sales", "int", "10"));
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.spi.api.utils;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.utils.TimeUtils;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.powermock.api.mockito.PowerMockito;
|
||||||
|
import org.powermock.modules.junit4.PowerMockRunner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-05
|
||||||
|
*/
|
||||||
|
@RunWith(PowerMockRunner.class)
|
||||||
|
public class TimeUtilsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_sleepInMills() {
|
||||||
|
TimeUtils.sleepInMills(-1L);
|
||||||
|
TimeUtils.sleepInMills(1L);
|
||||||
|
PowerMockito.spy(Thread.class);
|
||||||
|
PowerMockito.doThrow(new InterruptedException()).when(Thread.class);
|
||||||
|
TimeUtils.sleepInMills(2L);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hellobike.base.tunnel.store;
|
||||||
|
|
||||||
|
import com.hellobike.base.tunnel.model.InvokeContext;
|
||||||
|
import com.hellobike.base.tunnel.publisher.PublisherManager;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.powermock.api.mockito.PowerMockito;
|
||||||
|
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||||
|
import org.powermock.modules.junit4.PowerMockRunner;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao 2018-11-08
|
||||||
|
*/
|
||||||
|
@RunWith(PowerMockRunner.class)
|
||||||
|
@PrepareForTest(PublisherManager.class)
|
||||||
|
public class MemStoreTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_store() {
|
||||||
|
|
||||||
|
PublisherManager mgr = Mockito.mock(PublisherManager.class);
|
||||||
|
PowerMockito.mockStatic(PublisherManager.class);
|
||||||
|
Mockito.when(PublisherManager.getInstance()).thenReturn(mgr);
|
||||||
|
|
||||||
|
PublisherManager actual = PublisherManager.getInstance();
|
||||||
|
assertEquals(mgr, actual);
|
||||||
|
|
||||||
|
MemStore memStore = new MemStore();
|
||||||
|
memStore.store(null);
|
||||||
|
InvokeContext ctx = new InvokeContext();
|
||||||
|
ctx.setSlotName("testSlotName");
|
||||||
|
memStore.store(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
35
tunnel-server/src/test/resources/cfg.json
Normal file
35
tunnel-server/src/test/resources/cfg.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"": [
|
||||||
|
{
|
||||||
|
"address": "",
|
||||||
|
"database": "",
|
||||||
|
"username": "",
|
||||||
|
"password": "",
|
||||||
|
"slot": "",
|
||||||
|
"cluster": "",
|
||||||
|
"kafka": {
|
||||||
|
"addr": [],
|
||||||
|
"topic": "",
|
||||||
|
"filter": {
|
||||||
|
"dbName": "",
|
||||||
|
"tbName": "",
|
||||||
|
"fieldName": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"es": {
|
||||||
|
"addr": "",
|
||||||
|
"filter": {
|
||||||
|
"dbName": "",
|
||||||
|
"tbName": "",
|
||||||
|
"fieldName": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filter": {
|
||||||
|
"dbName": "",
|
||||||
|
"tbName": "",
|
||||||
|
"fieldName": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
}
|
||||||
1
tunnel-server/src/test/resources/test_config.properties
Normal file
1
tunnel-server/src/test/resources/test_config.properties
Normal file
@ -0,0 +1 @@
|
|||||||
|
k1=v1
|
||||||
23
tunnel-spi/pom.xml
Normal file
23
tunnel-spi/pom.xml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>tunnel-all</artifactId>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>tunnel-spi</artifactId>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<modules>
|
||||||
|
<module>tunnel-api</module>
|
||||||
|
<module>tunnel-es</module>
|
||||||
|
<module>tunnel-hbase</module>
|
||||||
|
<module>tunnel-hdfs</module>
|
||||||
|
<module>tunnel-hive</module>
|
||||||
|
<module>tunnel-kafka</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
</project>
|
||||||
15
tunnel-spi/tunnel-api/pom.xml
Normal file
15
tunnel-spi/tunnel-api/pom.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>tunnel-spi</artifactId>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>tunnel-api</artifactId>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package com.hellobike.base.tunnel.spi.api;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-07
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CellData implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -3834617680446353654L;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String type;
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
package com.hellobike.base.tunnel.spi.api;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class Invocation implements Cloneable {
|
||||||
|
|
||||||
|
private String serverId;
|
||||||
|
private String slotName;
|
||||||
|
|
||||||
|
private String jdbcUrl;
|
||||||
|
private String jdbcUser;
|
||||||
|
private String jdbcPass;
|
||||||
|
private long lsn;
|
||||||
|
private String message;
|
||||||
|
private String xid;
|
||||||
|
|
||||||
|
private final LinkedHashMap<String, Object> parameters = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
public void addParameter(String key, Object val) {
|
||||||
|
this.parameters.put(key, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeParameter(String key) {
|
||||||
|
this.parameters.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
this.parameters.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
super.finalize();
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Invocation clone() {
|
||||||
|
Invocation that = Invocation.builder()
|
||||||
|
.serverId(serverId)
|
||||||
|
.slotName(slotName)
|
||||||
|
.jdbcUrl(jdbcUrl)
|
||||||
|
.jdbcUser(jdbcUser)
|
||||||
|
.jdbcPass(jdbcPass)
|
||||||
|
.lsn(lsn)
|
||||||
|
.message(message)
|
||||||
|
.xid(xid)
|
||||||
|
.build();
|
||||||
|
that.getParameters().putAll(parameters);
|
||||||
|
return that;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
package com.hellobike.base.tunnel.spi.api;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-07
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class Message implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 6362136769760497527L;
|
||||||
|
|
||||||
|
private String schema;
|
||||||
|
private String table;
|
||||||
|
private List<CellData> data;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package com.hellobike.base.tunnel.spi.api;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-07
|
||||||
|
*/
|
||||||
|
public interface OutputHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输出消息
|
||||||
|
*
|
||||||
|
* @param invocation 消息内容
|
||||||
|
*/
|
||||||
|
void handle(Invocation invocation);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Shanghai Junzheng Network Technology Co.,Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.hellobike.base.tunnel.spi.api;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author machunxiao create at 2018-12-24
|
||||||
|
*/
|
||||||
|
public interface TransportConfig<T extends TransportConfig> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T toRealConfig(String config);
|
||||||
|
|
||||||
|
}
|
||||||
44
tunnel-spi/tunnel-es/pom.xml
Normal file
44
tunnel-spi/tunnel-es/pom.xml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>tunnel-spi</artifactId>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>tunnel-es</artifactId>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.elasticsearch.client</groupId>
|
||||||
|
<artifactId>elasticsearch-rest-client</artifactId>
|
||||||
|
<version>${es.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.elasticsearch.client</groupId>
|
||||||
|
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
||||||
|
<version>${es.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>jackson-core</artifactId>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-dbutils</groupId>
|
||||||
|
<artifactId>commons-dbutils</artifactId>
|
||||||
|
<version>1.7</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
123
tunnel-spi/tunnel-hbase/pom.xml
Normal file
123
tunnel-spi/tunnel-hbase/pom.xml
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>tunnel-spi</artifactId>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>tunnel-hbase</artifactId>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hellobike.base.tunnel</groupId>
|
||||||
|
<artifactId>tunnel-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.hbase</groupId>
|
||||||
|
<artifactId>hbase-client</artifactId>
|
||||||
|
<version>${hbase.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>jdk.tools</artifactId>
|
||||||
|
<groupId>*</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>log4j</artifactId>
|
||||||
|
<groupId>log4j</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>commons-logging</artifactId>
|
||||||
|
<groupId>commons-logging</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>commons-configuration</artifactId>
|
||||||
|
<groupId>commons-configuration</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.hbase</groupId>
|
||||||
|
<artifactId>hbase-hadoop-compat</artifactId>
|
||||||
|
<version>${hbase.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.hbase</groupId>
|
||||||
|
<artifactId>hbase-hadoop2-compat</artifactId>
|
||||||
|
<version>${hbase.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.hbase</groupId>
|
||||||
|
<artifactId>hbase-server</artifactId>
|
||||||
|
<version>${hbase.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>disruptor</artifactId>
|
||||||
|
<groupId>com.lmax</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.hbase</groupId>
|
||||||
|
<artifactId>hbase-prefix-tree</artifactId>
|
||||||
|
<version>${hbase.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.hbase</groupId>
|
||||||
|
<artifactId>hbase-procedure</artifactId>
|
||||||
|
<version>${hbase.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-configuration2</artifactId>
|
||||||
|
<version>2.4</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>log4j-over-slf4j</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>jcl-over-slf4j</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.lmax</groupId>
|
||||||
|
<artifactId>disruptor</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user