mirror of
https://github.com/NationalSecurityAgency/timely.git
synced 2026-11-10 11:51:29 -10:00
Compare commits
164
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7cafd5c8d3 | ||
|
|
2b38b55718 | ||
|
|
6ad1127989 | ||
|
|
e72ca910dc | ||
|
|
70672972b2 | ||
|
|
276e5e8fb2 | ||
|
|
673ae360e8 | ||
|
|
bb3386925c | ||
|
|
ecf481440c | ||
|
|
7582b62391 | ||
|
|
97edb406bc | ||
|
|
86a5e58683 | ||
|
|
4e8a7dbfb2 | ||
|
|
03f11ca11c | ||
|
|
849e265536 | ||
|
|
6d83aa98cd | ||
|
|
00b36ed7b8 | ||
|
|
f19779ce13 | ||
|
|
fe7daa3faa | ||
|
|
739d3a4726 | ||
|
|
d7b747ef79 | ||
|
|
0f891b28b2 | ||
|
|
ca86bddba1 | ||
|
|
6e9ab8e533 | ||
|
|
6c52ee5715 | ||
|
|
52ebc1856a | ||
|
|
ac390d5bed | ||
|
|
80fd98d304 | ||
|
|
6467283cbb | ||
|
|
cdc277067a | ||
|
|
c27a3d2bb6 | ||
|
|
3498c5e546 | ||
|
|
01ecbce346 | ||
|
|
1e746df912 | ||
|
|
d9214ed406 | ||
|
|
9a1c0e6e2f | ||
|
|
95f3e3d596 | ||
|
|
aaa0d91f11 | ||
|
|
48509e747b | ||
|
|
286bb85cab | ||
|
|
abfebeca60 | ||
|
|
e335eeb3b4 | ||
|
|
12d3695f10 | ||
|
|
61df23e6ba | ||
|
|
2640cbaf80 | ||
|
|
11a417c890 | ||
|
|
780e8f37b8 | ||
|
|
5ce377b15c | ||
|
|
4ed6eb98de | ||
|
|
4d08db3fbc | ||
|
|
16d73a1845 | ||
|
|
42b06cf60c | ||
|
|
e772728159 | ||
|
|
ebce93684a | ||
|
|
ff7a75c7c4 | ||
|
|
ad61f2cc85 | ||
|
|
e8beb77cb9 | ||
|
|
d6839fbc6c | ||
|
|
d53079a996 | ||
|
|
2e7489afef | ||
|
|
ee71a2c74f | ||
|
|
89a374f9a2 | ||
|
|
f145d0d1a4 | ||
|
|
387140722c | ||
|
|
b3617820f7 | ||
|
|
ac2d9463dc | ||
|
|
c32867685f | ||
|
|
08057e7d67 | ||
|
|
a058e5a816 | ||
|
|
99b81986a4 | ||
|
|
d7ecbd345f | ||
|
|
0f9059b6b6 | ||
|
|
fcbdd9296b | ||
|
|
df3ade7929 | ||
|
|
823a6fa08f | ||
|
|
89ab2635fd | ||
|
|
13d8db5ab7 | ||
|
|
8db5358b50 | ||
|
|
3e376e106b | ||
|
|
18eecfd7b0 | ||
|
|
065d8a9a9f | ||
|
|
09c2ef7e11 | ||
|
|
cb875819ff | ||
|
|
fcc5f0f716 | ||
|
|
c87543f7d7 | ||
|
|
d7f5a3b20b | ||
|
|
9601cdc927 | ||
|
|
60c2588c79 | ||
|
|
f3275c6a34 | ||
|
|
7486b6b761 | ||
|
|
b1a968590c | ||
|
|
8f86b20c02 | ||
|
|
a3620a3f24 | ||
|
|
9c99e74958 | ||
|
|
91ec36e819 | ||
|
|
9ad1b18b74 | ||
|
|
82c45d4dd4 | ||
|
|
a0e47d0b48 | ||
|
|
d3dc324d84 | ||
|
|
4871b3a4a9 | ||
|
|
8d5d5eeca8 | ||
|
|
a006a44372 | ||
|
|
6cfcdc1030 | ||
|
|
4eb7ceff8c | ||
|
|
6ad8da2b99 | ||
|
|
7f56a36906 | ||
|
|
1443fdceb9 | ||
|
|
3cff14eb03 | ||
|
|
8fa5b56e62 | ||
|
|
b2f2cef834 | ||
|
|
c6a2988083 | ||
|
|
d54817cc9a | ||
|
|
c4ee035584 | ||
|
|
d4bfc1a3aa | ||
|
|
fb315148a1 | ||
|
|
e8ae575086 | ||
|
|
da0146c741 | ||
|
|
882b4e2587 | ||
|
|
8048862f2c | ||
|
|
c2f00c3d19 | ||
|
|
61b1a245e2 | ||
|
|
a3c33115c4 | ||
|
|
bed1ceb9ee | ||
|
|
06e2699a44 | ||
|
|
d09faaa087 | ||
|
|
088f1a5cab | ||
|
|
cf6d4ada3e | ||
|
|
e464a8c9e0 | ||
|
|
8e4e61c373 | ||
|
|
729dca23ba | ||
|
|
104d20ad1b | ||
|
|
f0f005f8fa | ||
|
|
8593218b89 | ||
|
|
cbfe6a439f | ||
|
|
455616d568 | ||
|
|
9d3172cc75 | ||
|
|
7aa7b0da2a | ||
|
|
6c61861d83 | ||
|
|
91882ba363 | ||
|
|
ed61b5f305 | ||
|
|
a083c2d632 | ||
|
|
2891794174 | ||
|
|
c99b2471cf | ||
|
|
bb479a58d7 | ||
|
|
ff37d40801 | ||
|
|
a7d980975e | ||
|
|
30f5a0c1b2 | ||
|
|
2f9e6ca2d7 | ||
|
|
954528a460 | ||
|
|
0f7b514b30 | ||
|
|
a6ca46e1c1 | ||
|
|
487d1d4a5c | ||
|
|
e3c26f815c | ||
|
|
bbc1946204 | ||
|
|
991412f99b | ||
|
|
5428e93cb5 | ||
|
|
c18aae5a89 | ||
|
|
6972c46a1a | ||
|
|
4d7bee7566 | ||
|
|
4b11b3d50f | ||
|
|
84b9856ec7 | ||
|
|
c9548a9b9a | ||
|
|
aec7bd4c38 | ||
|
|
e2b8b643f2 |
No files matched your search
@@ -7,4 +7,6 @@ target/
|
|||||||
logs/
|
logs/
|
||||||
server/pki/
|
server/pki/
|
||||||
client/src/main/python/setup.py
|
client/src/main/python/setup.py
|
||||||
|
grafana/timely-app/yarn-error.log
|
||||||
|
grafana/timely-app/data/
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Apache License
|
Apache License
|
||||||
Version 2.0, January 2004
|
Version 2.0, January 2004
|
||||||
http://www.apache.org/licenses/
|
httpProperties://www.apache.org/licenses/
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@
|
|||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
httpProperties://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[![Apache License][li]][ll]
|
[![Apache License][li]][ll]
|
||||||
|
|
||||||
Timely is a time series database application that provides secure access to time series data. Timely is written in Java and designed to work with [Apache Accumulo](https://accumulo.apache.org/) and [Grafana](https://www.grafana.com). Documentation is located [here](https://nationalsecurityagency.github.io/timely/).
|
Timely is a time series database application that provides secure access to time series data. Timely is written in Java and designed to work with [Apache Accumulo](https://accumuloProperties.apache.org/) and [Grafana](https://www.grafana.com). Documentation is located [here](https://nationalsecurityagency.github.io/timely/).
|
||||||
|
|
||||||
[li]: https://img.shields.io/badge/license-ASL-blue.svg
|
[li]: https://img.shields.io/badge/license-ASL-blue.svg
|
||||||
[ll]: https://www.apache.org/licenses/LICENSE-2.0
|
[ll]: https://www.apache.org/licenses/LICENSE-2.0
|
||||||
+19
-24
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely</artifactId>
|
<artifactId>timely</artifactId>
|
||||||
<version>1.2.8-SNAPSHOT</version>
|
<version>2.2.6-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>timely-analytics</artifactId>
|
<artifactId>timely-analytics</artifactId>
|
||||||
<!--
|
<!--
|
||||||
@@ -53,36 +53,17 @@
|
|||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>timely</groupId>
|
||||||
|
<artifactId>timely-common</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>timely</groupId>
|
|
||||||
<artifactId>timely-common</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<pluginManagement>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<compilerId>jdt</compilerId>
|
|
||||||
</configuration>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.eclipse.tycho</groupId>
|
|
||||||
<artifactId>tycho-compiler-jdt</artifactId>
|
|
||||||
<version>1.4.0</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</pluginManagement>
|
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.jacoco</groupId>
|
<groupId>org.jacoco</groupId>
|
||||||
@@ -169,6 +150,12 @@
|
|||||||
</excludes>
|
</excludes>
|
||||||
</artifactSet>
|
</artifactSet>
|
||||||
<filters>
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/module-info.class</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
<filter>
|
<filter>
|
||||||
<artifact>org.apache.flink:*</artifact>
|
<artifact>org.apache.flink:*</artifact>
|
||||||
<excludes>
|
<excludes>
|
||||||
@@ -246,6 +233,14 @@
|
|||||||
<artifactSet>
|
<artifactSet>
|
||||||
<excludes combine.self="override" />
|
<excludes combine.self="override" />
|
||||||
</artifactSet>
|
</artifactSet>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/module-info.class</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import java.util.List;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.flink.streaming.util.serialization.SerializationSchema;
|
import org.apache.flink.streaming.util.serialization.SerializationSchema;
|
||||||
|
|
||||||
import timely.model.Tag;
|
import timely.model.Tag;
|
||||||
|
|
||||||
public class MetricHistogram implements Serializable, SerializationSchema<MetricHistogram> {
|
public class MetricHistogram implements Serializable, SerializationSchema<MetricHistogram> {
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package timely.analytics.flink;
|
package timely.analytics.flink;
|
||||||
|
|
||||||
import org.apache.flink.api.java.functions.KeySelector;
|
import org.apache.flink.api.java.functions.KeySelector;
|
||||||
|
|
||||||
import timely.api.response.MetricResponse;
|
import timely.api.response.MetricResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uniquely defines a time series in a Flink stream. A unique time series is the
|
* Uniquely defines a time series in a Flink stream. A unique time series is the metric name and all of its tags, to include visibility if it exists.
|
||||||
* metric name and all of its tags, to include visibility if it exists.
|
|
||||||
*/
|
*/
|
||||||
public class MetricKeySelector implements KeySelector<MetricResponse, String> {
|
public class MetricKeySelector implements KeySelector<MetricResponse,String> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ import org.apache.flink.api.common.accumulators.Accumulator;
|
|||||||
* Custom accumulator that retains a sorted map of strings and their counts
|
* Custom accumulator that retains a sorted map of strings and their counts
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class SortedStringAccumulator implements Accumulator<String, ConcurrentSkipListMap<String, MutableLong>> {
|
public class SortedStringAccumulator implements Accumulator<String,ConcurrentSkipListMap<String,MutableLong>> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private ConcurrentSkipListMap<String, MutableLong> values = new ConcurrentSkipListMap<>();
|
private ConcurrentSkipListMap<String,MutableLong> values = new ConcurrentSkipListMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(String value) {
|
public void add(String value) {
|
||||||
@@ -25,7 +25,7 @@ public class SortedStringAccumulator implements Accumulator<String, ConcurrentSk
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConcurrentSkipListMap<String, MutableLong> getLocalValue() {
|
public ConcurrentSkipListMap<String,MutableLong> getLocalValue() {
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ public class SortedStringAccumulator implements Accumulator<String, ConcurrentSk
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void merge(Accumulator<String, ConcurrentSkipListMap<String, MutableLong>> other) {
|
public void merge(Accumulator<String,ConcurrentSkipListMap<String,MutableLong>> other) {
|
||||||
other.getLocalValue().forEach((k, v) -> {
|
other.getLocalValue().forEach((k, v) -> {
|
||||||
if (values.containsKey(k)) {
|
if (values.containsKey(k)) {
|
||||||
values.get(k).add(v.longValue());
|
values.get(k).add(v.longValue());
|
||||||
@@ -46,7 +46,7 @@ public class SortedStringAccumulator implements Accumulator<String, ConcurrentSk
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Accumulator<String, ConcurrentSkipListMap<String, MutableLong>> clone() {
|
public Accumulator<String,ConcurrentSkipListMap<String,MutableLong>> clone() {
|
||||||
SortedStringAccumulator a = new SortedStringAccumulator();
|
SortedStringAccumulator a = new SortedStringAccumulator();
|
||||||
a.getLocalValue().putAll(this.values);
|
a.getLocalValue().putAll(this.values);
|
||||||
return a;
|
return a;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
|
|||||||
import org.apache.flink.streaming.api.watermark.Watermark;
|
import org.apache.flink.streaming.api.watermark.Watermark;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import timely.api.response.MetricResponse;
|
import timely.api.response.MetricResponse;
|
||||||
import timely.api.response.MetricResponses;
|
import timely.api.response.MetricResponses;
|
||||||
import timely.client.websocket.ClientHandler;
|
import timely.client.websocket.ClientHandler;
|
||||||
@@ -41,7 +42,7 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(SubscriptionSource.class);
|
private static final Logger log = LoggerFactory.getLogger(SubscriptionSource.class);
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private transient WebSocketSubscriptionClient client = null;
|
private transient WebSocketSubscriptionClient client = null;
|
||||||
@@ -63,12 +64,11 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void open(Configuration parameters) throws Exception {
|
public void open(Configuration parameters) throws Exception {
|
||||||
LOG.info("Opening summarization job.");
|
log.info("Opening summarization job.");
|
||||||
super.open(parameters);
|
super.open(parameters);
|
||||||
client = new WebSocketSubscriptionClient(jp.getTimelyHostname(), jp.getTimelyHttpsPort(), jp.getTimelyWssPort(),
|
client = new WebSocketSubscriptionClient(jp.getTimelyHostname(), jp.getTimelyHttpsPort(), jp.getTimelyWssPort(), jp.isClientAuth(), jp.isDoLogin(),
|
||||||
jp.isClientAuth(), jp.isDoLogin(), jp.getTimelyUsername(), jp.getTimelyPassword(), jp.getKeyStoreFile(),
|
jp.getKeyStoreFile(), jp.getKeyStoreType(), jp.getKeyStorePass(), jp.getTrustStoreFile(), jp.getTrustStoreType(),
|
||||||
jp.getKeyStoreType(), jp.getKeyStorePass(), jp.getTrustStoreFile(), jp.getTrustStoreType(),
|
jp.getTrustStorePass(), jp.isHostVerificationEnabled(), jp.getBufferSize());
|
||||||
jp.getTrustStorePass(), jp.isHostVerificationEnabled(), jp.getBufferSize());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -81,7 +81,7 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(SourceContext<MetricResponse> ctx) throws Exception {
|
public void run(SourceContext<MetricResponse> ctx) throws Exception {
|
||||||
LOG.info("Running summarization job");
|
log.info("Running summarization job");
|
||||||
final SortedStringAccumulator dateTimeAccumulator = new SortedStringAccumulator();
|
final SortedStringAccumulator dateTimeAccumulator = new SortedStringAccumulator();
|
||||||
this.getRuntimeContext().addAccumulator("source hourly count", dateTimeAccumulator);
|
this.getRuntimeContext().addAccumulator("source hourly count", dateTimeAccumulator);
|
||||||
final LongCounter sourceInputs = new LongCounter();
|
final LongCounter sourceInputs = new LongCounter();
|
||||||
@@ -103,22 +103,20 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(final String message) {
|
public void onMessage(final String message) {
|
||||||
LOG.info("Message received on Websocket session {}, length: {}", session.getId(),
|
log.info("Message received on Websocket session {}, length: {}", session.getId(), message.length());
|
||||||
message.length());
|
|
||||||
try {
|
try {
|
||||||
// Deserialize in this thread
|
// Deserialize in this thread
|
||||||
final MetricResponses responses = JsonSerializer.getObjectMapper().readValue(message,
|
final MetricResponses responses = JsonSerializer.getObjectMapper().readValue(message, MetricResponses.class);
|
||||||
MetricResponses.class);
|
|
||||||
// Process in the other
|
// Process in the other
|
||||||
final Runnable r = () -> {
|
final Runnable r = () -> {
|
||||||
responses.getResponses().forEach(response -> {
|
responses.getResponses().forEach(response -> {
|
||||||
if (response.isComplete()) {
|
if (response.isComplete()) {
|
||||||
LOG.info("Received last message.");
|
log.info("Received last message.");
|
||||||
ctx.emitWatermark(new Watermark(Long.MAX_VALUE));
|
ctx.emitWatermark(new Watermark(Long.MAX_VALUE));
|
||||||
subscriptionsRemaining.getAndDecrement();
|
subscriptionsRemaining.getAndDecrement();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LOG.trace("Received metric: {}", response);
|
log.trace("Received metric: {}", response);
|
||||||
long time = response.getTimestamp();
|
long time = response.getTimestamp();
|
||||||
ctx.collectWithTimestamp(response, time);
|
ctx.collectWithTimestamp(response, time);
|
||||||
dateTimeAccumulator.add(formatter.format(new Date(response.getTimestamp())));
|
dateTimeAccumulator.add(formatter.format(new Date(response.getTimestamp())));
|
||||||
@@ -141,11 +139,11 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
|
|||||||
inputProcessedInMainThread.add(1);
|
inputProcessedInMainThread.add(1);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.error("Error deserializing metric response, closing", e);
|
log.error("Error deserializing metric response, closing", e);
|
||||||
try {
|
try {
|
||||||
close();
|
close();
|
||||||
} catch (Exception e1) {
|
} catch (Exception e1) {
|
||||||
LOG.error("Error closing client", e1);
|
log.error("Error closing client", e1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,7 +156,7 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
|
|||||||
try {
|
try {
|
||||||
close();
|
close();
|
||||||
} catch (Exception e1) {
|
} catch (Exception e1) {
|
||||||
LOG.error("Error closing client", e1);
|
log.error("Error closing client", e1);
|
||||||
}
|
}
|
||||||
// Signal done sending data
|
// Signal done sending data
|
||||||
ctx.emitWatermark(new Watermark(Long.MAX_VALUE));
|
ctx.emitWatermark(new Watermark(Long.MAX_VALUE));
|
||||||
@@ -170,7 +168,7 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
|
|||||||
try {
|
try {
|
||||||
close();
|
close();
|
||||||
} catch (Exception e1) {
|
} catch (Exception e1) {
|
||||||
LOG.error("Error closing client", e1);
|
log.error("Error closing client", e1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,14 +176,14 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
|
|||||||
try {
|
try {
|
||||||
client.open(handler);
|
client.open(handler);
|
||||||
for (String m : metrics) {
|
for (String m : metrics) {
|
||||||
LOG.info("Adding subscription for {}", m);
|
log.info("Adding subscription for {}", m);
|
||||||
client.addSubscription(m, null, start, end, 5000);
|
client.addSubscription(m, null, start, end, 5000);
|
||||||
}
|
}
|
||||||
while (!client.isClosed() && subscriptionsRemaining.get() > 0) {
|
while (!client.isClosed() && subscriptionsRemaining.get() > 0) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(5000);
|
Thread.sleep(5000);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.error("Sleep interrupted.");
|
log.error("Sleep interrupted.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -195,21 +193,21 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cancel() {
|
public void cancel() {
|
||||||
LOG.info("Cancelling subscription source.");
|
log.info("Cancelling subscription source.");
|
||||||
try {
|
try {
|
||||||
close();
|
close();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error("Error closing web socket client");
|
log.error("Error closing web socket client");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
LOG.info("Stopping subscription source.");
|
log.info("Stopping subscription source.");
|
||||||
try {
|
try {
|
||||||
close();
|
close();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error("Error closing web socket client");
|
log.error("Error closing web socket client");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,12 @@ import org.apache.flink.streaming.api.functions.sink.SocketClientSink;
|
|||||||
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
|
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import timely.api.response.MetricResponse;
|
import timely.api.response.MetricResponse;
|
||||||
|
|
||||||
public class SummarizationJob {
|
public class SummarizationJob {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(SummarizationJob.class);
|
private static final Logger log = LoggerFactory.getLogger(SummarizationJob.class);
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
@@ -26,11 +27,11 @@ public class SummarizationJob {
|
|||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.info("Loading properties from: {}", args[0]);
|
log.info("Loading properties from: {}", args[0]);
|
||||||
ParameterTool params = ParameterTool.fromPropertiesFile(args[0]);
|
ParameterTool params = ParameterTool.fromPropertiesFile(args[0]);
|
||||||
|
|
||||||
final SummarizationJobParameters jp = new SummarizationJobParameters(params);
|
final SummarizationJobParameters jp = new SummarizationJobParameters(params);
|
||||||
LOG.info("Properties: {}", jp);
|
log.info("Properties: {}", jp);
|
||||||
|
|
||||||
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
|
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
@@ -42,7 +43,7 @@ public class SummarizationJob {
|
|||||||
.window(TumblingEventTimeWindows.of(jp.getSummarizationInterval()))
|
.window(TumblingEventTimeWindows.of(jp.getSummarizationInterval()))
|
||||||
.fold(new MetricHistogram(), new FoldFunction<MetricResponse, MetricHistogram>() {
|
.fold(new MetricHistogram(), new FoldFunction<MetricResponse, MetricHistogram>() {
|
||||||
|
|
||||||
private final Logger LOG = LoggerFactory
|
private final Logger log = LoggerFactory
|
||||||
.getLogger("timely.analytics.SummarizationJob.FoldFunction@");
|
.getLogger("timely.analytics.SummarizationJob.FoldFunction@");
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@@ -58,7 +59,7 @@ public class SummarizationJob {
|
|||||||
throw new RuntimeException("Tags don't not match - partitioning problem");
|
throw new RuntimeException("Tags don't not match - partitioning problem");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG.trace("Updating histogram for {} with value {} at {} for metric {}", histo.getMetric()
|
log.trace("Updating histogram for {} with value {} at {} for metric {}", histo.getMetric()
|
||||||
+ histo.getTags(), metric.getValue(), metric.getTimestamp(), metric.getMetric()
|
+ histo.getTags(), metric.getValue(), metric.getTimestamp(), metric.getMetric()
|
||||||
+ metric.getTags());
|
+ metric.getTags());
|
||||||
histo.update(metric.getValue(), metric.getTimestamp());
|
histo.update(metric.getValue(), metric.getTimestamp());
|
||||||
@@ -70,7 +71,7 @@ public class SummarizationJob {
|
|||||||
new SocketClientSink<MetricHistogram>(jp.getTimelyHostname(), jp.getTimelyTcpPort(),
|
new SocketClientSink<MetricHistogram>(jp.getTimelyHostname(), jp.getTimelyTcpPort(),
|
||||||
new MetricHistogram(), 2, true) {
|
new MetricHistogram(), 2, true) {
|
||||||
|
|
||||||
private final Logger LOG = LoggerFactory
|
private final Logger log = LoggerFactory
|
||||||
.getLogger("timely.analytics.SummarizationJob.SocketClientSink");
|
.getLogger("timely.analytics.SummarizationJob.SocketClientSink");
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private final LongCounter sinkCounter = new LongCounter();
|
private final LongCounter sinkCounter = new LongCounter();
|
||||||
@@ -82,7 +83,7 @@ public class SummarizationJob {
|
|||||||
super.open(parameters);
|
super.open(parameters);
|
||||||
this.getRuntimeContext().addAccumulator("sink counter", this.sinkCounter);
|
this.getRuntimeContext().addAccumulator("sink counter", this.sinkCounter);
|
||||||
this.getRuntimeContext().addAccumulator("sink hourly count", dateTimeAccumulator);
|
this.getRuntimeContext().addAccumulator("sink hourly count", dateTimeAccumulator);
|
||||||
LOG.info("Sink opened");
|
log.info("Sink opened");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -96,7 +97,7 @@ public class SummarizationJob {
|
|||||||
@Override
|
@Override
|
||||||
public void close() throws Exception {
|
public void close() throws Exception {
|
||||||
super.close();
|
super.close();
|
||||||
LOG.info("Sink closed");
|
log.info("Sink closed");
|
||||||
}
|
}
|
||||||
|
|
||||||
}).name("Timely Metric Sink");
|
}).name("Timely Metric Sink");
|
||||||
|
|||||||
@@ -184,8 +184,8 @@ public class SummarizationJobParameters extends GlobalJobParameters implements S
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String> toMap() {
|
public Map<String,String> toMap() {
|
||||||
Map<String, String> m = new HashMap<>();
|
Map<String,String> m = new HashMap<>();
|
||||||
m.put("timelyHostname", this.timelyHostname);
|
m.put("timelyHostname", this.timelyHostname);
|
||||||
m.put("timelyHttpsPort", Integer.toString(this.timelyHttpsPort));
|
m.put("timelyHttpsPort", Integer.toString(this.timelyHttpsPort));
|
||||||
m.put("timelyWssPort", Integer.toString(this.timelyWssPort));
|
m.put("timelyWssPort", Integer.toString(this.timelyWssPort));
|
||||||
|
|||||||
@@ -15,4 +15,12 @@
|
|||||||
<Method name="getMetrics" />
|
<Method name="getMetrics" />
|
||||||
<Bug pattern="EI_EXPOSE_REP" />
|
<Bug pattern="EI_EXPOSE_REP" />
|
||||||
</Match>
|
</Match>
|
||||||
|
<Match>
|
||||||
|
<!-- these are probably avoidable, but needs further triage to fix -->
|
||||||
|
<Bug pattern="EI_EXPOSE_REP" />
|
||||||
|
</Match>
|
||||||
|
<Match>
|
||||||
|
<!-- these are probably avoidable, but needs further triage to fix -->
|
||||||
|
<Bug pattern="EI_EXPOSE_REP2" />
|
||||||
|
</Match>
|
||||||
</FindBugsFilter>
|
</FindBugsFilter>
|
||||||
@@ -6,6 +6,7 @@ import java.util.List;
|
|||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import timely.model.Metric;
|
import timely.model.Metric;
|
||||||
import timely.model.Tag;
|
import timely.model.Tag;
|
||||||
import timely.model.parse.MetricParser;
|
import timely.model.parse.MetricParser;
|
||||||
@@ -96,9 +97,8 @@ public class MetricHistogramTest {
|
|||||||
Metric metric = metricParser.parse(put);
|
Metric metric = metricParser.parse(put);
|
||||||
Assert.assertEquals("sys.cpu.user_summarized", metric.getName());
|
Assert.assertEquals("sys.cpu.user_summarized", metric.getName());
|
||||||
metric.getTags().forEach(t -> {
|
metric.getTags().forEach(t -> {
|
||||||
Assert.assertTrue(
|
Assert.assertTrue(t.equals(t1) || t.equals(t2) || t.equals(avg) || t.equals(min) || t.equals(max) || t.equals(sum) || t.equals(count)
|
||||||
t.equals(t1) || t.equals(t2) || t.equals(avg) || t.equals(min) || t.equals(max) || t.equals(sum)
|
|| t.equals(p50) || t.equals(p75) || t.equals(p90) || t.equals(p99));
|
||||||
|| t.equals(count) || t.equals(p50) || t.equals(p75) || t.equals(p90) || t.equals(p99));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [[ `uname` == "Darwin" ]]; then
|
||||||
|
THIS_SCRIPT=`python -c 'import os,sys; print os.path.realpath(sys.argv[1])' $0`
|
||||||
|
else
|
||||||
|
THIS_SCRIPT=`readlink -f $0`
|
||||||
|
fi
|
||||||
|
|
||||||
|
THIS_DIR="${THIS_SCRIPT%/*}"
|
||||||
|
BASE_DIR=$(cd $THIS_DIR/.. && pwd)
|
||||||
|
BIN_DIR=${BASE_DIR}/bin
|
||||||
|
|
||||||
|
. ${BIN_DIR}/timely-balancer-env.sh
|
||||||
|
|
||||||
|
for i in $(seq 1 $NUM_INSTANCES); do
|
||||||
|
echo ${BIN_DIR}/timely-balancer.sh $i
|
||||||
|
${BIN_DIR}/timely-balancer.sh $i
|
||||||
|
done
|
||||||
Executable
+21
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [[ `uname` == "Darwin" ]]; then
|
||||||
|
THIS_SCRIPT=`python -c 'import os,sys; print os.path.realpath(sys.argv[1])' $0`
|
||||||
|
else
|
||||||
|
THIS_SCRIPT=`readlink -f $0`
|
||||||
|
fi
|
||||||
|
|
||||||
|
THIS_DIR="${THIS_SCRIPT%/*}"
|
||||||
|
BASE_DIR=$(cd $THIS_DIR/.. && pwd)
|
||||||
|
BIN_DIR=${BASE_DIR}/bin
|
||||||
|
|
||||||
|
. ${BIN_DIR}/timely-balancer-env.sh
|
||||||
|
|
||||||
|
for i in $(seq 1 $NUM_INSTANCES); do
|
||||||
|
PID=`jps -m | grep -E 'timely-balancer-.*-exec.jar' | grep "instance=${i}" | awk '{print $1}'`
|
||||||
|
if [ "$PID" != "" ]; then
|
||||||
|
echo "stopping timely-balancer instance ${i} [${PID}]"
|
||||||
|
kill -9 $PID
|
||||||
|
fi
|
||||||
|
done
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -1,11 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
export TRUSTSTORE_FILE=
|
|
||||||
export TRUSTSTORE_TYPE="jks";
|
|
||||||
export TRUSTSTORE_PASS=
|
|
||||||
export KEYSTORE_FILE=
|
|
||||||
export KEYSTORE_TYPE="pkcs12";
|
|
||||||
export KEYSTORE_PASS=
|
|
||||||
|
|
||||||
export NUM_QUERY_THREADS=4
|
|
||||||
export NUM_INGEST_THREADS=4
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [[ `uname` == "Darwin" ]]; then
|
|
||||||
THIS_SCRIPT=`python -c 'import os,sys; print os.path.realpath(sys.argv[1])' $0`
|
|
||||||
else
|
|
||||||
THIS_SCRIPT=`readlink -f $0`
|
|
||||||
fi
|
|
||||||
|
|
||||||
THIS_DIR="${THIS_SCRIPT%/*}"
|
|
||||||
BASE_DIR=${THIS_DIR}/../..
|
|
||||||
TMP_DIR="${BASE_DIR}/tmp"
|
|
||||||
CONF_DIR="${BASE_DIR}/conf"
|
|
||||||
LIB_DIR="${BASE_DIR}/lib"
|
|
||||||
|
|
||||||
. ${THIS_DIR}/load-test-env.sh
|
|
||||||
|
|
||||||
export CLASSPATH="${CONF_DIR}:${THIS_DIR}:${LIB_DIR}/*"
|
|
||||||
JVM_ARGS="-Xmx1G -Xms1G"
|
|
||||||
|
|
||||||
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.testing.MetricPutLoadTest $*"
|
|
||||||
$JAVA_HOME/bin/java ${JVM_ARGS} timely.testing.MetricPutLoadTest $*
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [[ `uname` == "Darwin" ]]; then
|
|
||||||
THIS_SCRIPT=`python -c 'import os,sys; print os.path.realpath(sys.argv[1])' $0`
|
|
||||||
else
|
|
||||||
THIS_SCRIPT=`readlink -f $0`
|
|
||||||
fi
|
|
||||||
|
|
||||||
THIS_DIR="${THIS_SCRIPT%/*}"
|
|
||||||
BASE_DIR=${THIS_DIR}/../..
|
|
||||||
TMP_DIR="${BASE_DIR}/tmp"
|
|
||||||
CONF_DIR="${BASE_DIR}/conf"
|
|
||||||
LIB_DIR="${BASE_DIR}/lib"
|
|
||||||
|
|
||||||
. ${THIS_DIR}/load-test-env.sh
|
|
||||||
|
|
||||||
export CLASSPATH="${CONF_DIR}:${THIS_DIR}:${LIB_DIR}/*"
|
|
||||||
JVM_ARGS="-Xmx1G -Xms1G"
|
|
||||||
|
|
||||||
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.testing.MetricQueryLoadTest $*"
|
|
||||||
$JAVA_HOME/bin/java ${JVM_ARGS} timely.testing.MetricQueryLoadTest $*
|
|
||||||
Executable
+27
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
NUM_INSTANCES=1
|
||||||
|
ACCUMULO_ZOOKEEPERS=localhost:2181
|
||||||
|
HADOOP_CONF_DIR=${HADOOP_CONF_DIR}
|
||||||
|
HADOOP_DEFAULT_FS=hdfs://localhost:8020
|
||||||
|
TCP_BASE_PORT=4242
|
||||||
|
HTTP_BASE_PORT=4243
|
||||||
|
WEBSOCKET_BASE_PORT=4244
|
||||||
|
UDP_BASE_PORT=4245
|
||||||
|
|
||||||
|
HOST_IP=0.0.0.0
|
||||||
|
HOST=$(hostname -s)
|
||||||
|
HOST_VERIFICATION_ENABLED=true
|
||||||
|
|
||||||
|
GENERATE_KEYS=true
|
||||||
|
TRUST_STORE_TYPE=
|
||||||
|
TRUST_STORE_FILE=
|
||||||
|
TRUST_STORE_PASSWORD=
|
||||||
|
KEY_STORE_TYPE=
|
||||||
|
KEY_STORE_FILE=
|
||||||
|
KEY_STORE_PASSWORD=
|
||||||
|
AUTHORIZATION_URL=
|
||||||
|
AUTHORIZATION_CERTIFICATE_TYPE=
|
||||||
|
AUTHORIZATION_CERTIFICATE_FILE=
|
||||||
|
ANONYMOUS_HTTP=true
|
||||||
|
ANONYMOUS_WEBSOCKET=true
|
||||||
@@ -1,42 +1,64 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
if [[ `uname` == "Darwin" ]]; then
|
if [[ $(uname) == "Darwin" ]]; then
|
||||||
THIS_SCRIPT=`python -c 'import os,sys; print os.path.realpath(sys.argv[1])' $0`
|
THIS_SCRIPT=$(python -c 'import os,sys; print os.path.realpath(sys.argv[1])' "$0")
|
||||||
TCNATIVE_SUFFIX="jnilib"
|
|
||||||
else
|
else
|
||||||
THIS_SCRIPT=`readlink -f $0`
|
THIS_SCRIPT=$(readlink -f "$0")
|
||||||
TCNATIVE_SUFFIX="so"
|
HW=`uname -m`
|
||||||
|
OS_PATH=linux-${HW}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
THIS_DIR="${THIS_SCRIPT%/*}"
|
if [ -z "$1" ]; then
|
||||||
NATIVE_DIR="${THIS_DIR}/META-INF/native"
|
export INSTANCE="1"
|
||||||
BASE_DIR=${THIS_DIR}/..
|
else
|
||||||
TMP_DIR="${BASE_DIR}/tmp"
|
export INSTANCE="$1"
|
||||||
CONF_DIR="${BASE_DIR}/conf"
|
|
||||||
LIB_DIR="${BASE_DIR}/lib"
|
|
||||||
NUM_SERVER_THREADS=4
|
|
||||||
|
|
||||||
if [[ -e ${TMP_DIR} ]]; then
|
|
||||||
rm -rf ${TMP_DIR}
|
|
||||||
fi
|
fi
|
||||||
mkdir ${TMP_DIR}
|
|
||||||
|
|
||||||
if [[ -e ${NATIVE_DIR} ]]; then
|
PID=$(jps -m | grep -E 'timely-balancer-.*-exec.jar' | grep "instance=${INSTANCE}" | awk '{print $1}')
|
||||||
rm -rf ${NATIVE_DIR}
|
|
||||||
|
if [ "$PID" == "" ]; then
|
||||||
|
THIS_DIR="${THIS_SCRIPT%/*}"
|
||||||
|
BASE_DIR=$(cd "$THIS_DIR"/.. && pwd)
|
||||||
|
LIB_DIR="${BASE_DIR}/lib"
|
||||||
|
BIN_DIR="${BASE_DIR}/bin"
|
||||||
|
export CONF_DIR="${BASE_DIR}/conf"
|
||||||
|
NATIVE_DIR="${BIN_DIR}/META-INF/native"
|
||||||
|
|
||||||
|
set -a
|
||||||
|
. "${BIN_DIR}/timely-balancer-env.sh"
|
||||||
|
set +a
|
||||||
|
|
||||||
|
# use either a value from timely-balancer-env.sh or the default
|
||||||
|
export LOG_DIR="${TIMELY_LOG_DIR:-${BASE_DIR}/logs}"
|
||||||
|
|
||||||
|
if [[ ! -e ${NATIVE_DIR} ]]; then
|
||||||
|
mkdir -p "${NATIVE_DIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -e ${LOG_DIR} ]]; then
|
||||||
|
mkdir "${LOG_DIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
JVM_ARGS="-Xmx2G -Xms2G -XX:NewSize=1G -XX:MaxNewSize=1G"
|
||||||
|
JVM_ARGS="${JVM_ARGS} -Dlogging.config=${CONF_DIR}/log4j2.yml"
|
||||||
|
JVM_ARGS="${JVM_ARGS} -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
|
||||||
|
JVM_ARGS="${JVM_ARGS} -XX:+UseG1GC -XX:+UseStringDeduplication"
|
||||||
|
JVM_ARGS="${JVM_ARGS} -Djava.net.preferIPv4Stack=true"
|
||||||
|
JVM_ARGS="${JVM_ARGS} -XX:+UseNUMA"
|
||||||
|
|
||||||
|
# for linux varieties of OS, extract native libraries if not already present
|
||||||
|
if [[ -n "$OS_PATH" ]]; then
|
||||||
|
if [[ ! -d ${NATIVE_DIR} || -z "$(ls -A ${NATIVE_DIR})" ]]; then
|
||||||
|
pushd "${BASE_DIR}/bin" || exit
|
||||||
|
"${JAVA_HOME}"/bin/jar xf "${LIB_DIR}"/netty-tcnative-boringssl-static-*.Final-"${OS_PATH}".jar META-INF/native/libnetty_tcnative_linux_"${HW}".so
|
||||||
|
"${JAVA_HOME}"/bin/jar xf "${LIB_DIR}"/netty-transport-native-epoll-*-"${OS_PATH}".jar META-INF/native/libnetty_transport_native_epoll_"${HW}".so
|
||||||
|
popd || exit
|
||||||
|
fi
|
||||||
|
JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${JAVA_HOME}/bin/java ${JVM_ARGS} -jar ${BIN_DIR}/timely-balancer-*-exec.jar --instance=${INSTANCE}"
|
||||||
|
nohup "${JAVA_HOME}"/bin/java ${JVM_ARGS} -jar "${BIN_DIR}"/timely-balancer-*-exec.jar --instance="${INSTANCE}" >> "${LOG_DIR}/timely-balancer${INSTANCE}.out" 2>&1 &
|
||||||
|
else
|
||||||
|
echo "timely-balancer --instance=${INSTANCE} already running with pid ${PID}"
|
||||||
fi
|
fi
|
||||||
mkdir -p ${NATIVE_DIR}
|
|
||||||
|
|
||||||
pushd ${BASE_DIR}/bin
|
|
||||||
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-tcnative-boringssl-static*.jar META-INF/native/libnetty_tcnative_linux_x86_64.${TCNATIVE_SUFFIX}
|
|
||||||
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-all*.jar META-INF/native/libnetty_transport_native_epoll_x86_64.${TCNATIVE_SUFFIX}
|
|
||||||
popd
|
|
||||||
|
|
||||||
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*:${HADOOP_CONF_DIR}"
|
|
||||||
JVM_ARGS="-Xmx1G -Xms1G -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS} -Dlog4j.configurationFile=${CONF_DIR}/log4j2-spring.xml"
|
|
||||||
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
|
|
||||||
JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}"
|
|
||||||
|
|
||||||
#JVM_ARGS="${JVM_ARGS} -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
|
|
||||||
|
|
||||||
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.balancer.Balancer --spring.config.name=timely --spring.profiles.active=balancer"
|
|
||||||
$JAVA_HOME/bin/java ${JVM_ARGS} timely.balancer.Balancer --spring.config.name=timely --spring.profiles.active=balancer
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Configuration status="warn" monitorInterval="60">
|
|
||||||
<Appenders>
|
|
||||||
<Console name="Console" target="SYSTEM_OUT">
|
|
||||||
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
|
|
||||||
</Console>
|
|
||||||
</Appenders>
|
|
||||||
<Loggers>
|
|
||||||
<Root level="error" includeLocation="false">
|
|
||||||
<AppenderRef ref="Console" level="error" />
|
|
||||||
</Root>
|
|
||||||
</Loggers>
|
|
||||||
</Configuration>
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Configuration status="warn" monitorInterval="60">
|
|
||||||
<Properties>
|
|
||||||
<Property name="PID">????</Property>
|
|
||||||
<Property name="LOG_PATTERN">%clr{%d{yyyy-MM-dd HH:mm:ss.SSS}}{faint} %clr{%5p} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n%wEx</Property>
|
|
||||||
</Properties>
|
|
||||||
<Appenders>
|
|
||||||
<RollingRandomAccessFile name="Rolling" fileName="/srv/logs/timely/timely-balancer.log"
|
|
||||||
filePattern="/srv/logs/timely/$${date:yyyy-MM}/timely-balancer-%d{MM-dd-yyyy}-%i.log.gz">
|
|
||||||
<PatternLayout pattern="${LOG_PATTERN}"/>
|
|
||||||
<Policies>
|
|
||||||
<SizeBasedTriggeringPolicy size="1024 MB" />
|
|
||||||
</Policies>
|
|
||||||
<DefaultRolloverStrategy max="10" />
|
|
||||||
</RollingRandomAccessFile>
|
|
||||||
<Console name="Console" target="SYSTEM_OUT">
|
|
||||||
<PatternLayout pattern="${LOG_PATTERN}"/>
|
|
||||||
</Console>
|
|
||||||
</Appenders>
|
|
||||||
<Loggers>
|
|
||||||
<Root level="trace" includeLocation="false">
|
|
||||||
<AppenderRef ref="Console" level="warn" />
|
|
||||||
<AppenderRef ref="Rolling" level="trace" />
|
|
||||||
</Root>
|
|
||||||
<Logger name="timely" additivity="false">
|
|
||||||
<AppenderRef ref="Console" level="debug" />
|
|
||||||
</Logger>
|
|
||||||
</Loggers>
|
|
||||||
</Configuration>
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
Configuration:
|
||||||
|
status: warn
|
||||||
|
monitorInterval: 60
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
Property:
|
||||||
|
- name: logDir
|
||||||
|
value: ${env:LOG_DIR}
|
||||||
|
- name: PID
|
||||||
|
value: "????"
|
||||||
|
- name: LOG_PATTERN
|
||||||
|
value: "%d{ISO8601} %-5p [%-40.40t] [%-40.40c{1.}] %m%n%wEx"
|
||||||
|
|
||||||
|
Appenders:
|
||||||
|
RollingFile:
|
||||||
|
- name: File
|
||||||
|
fileName: "${sys:logDir}/timely-balancer${env:INSTANCE}.log"
|
||||||
|
filePattern: "${sys:logDir}/timely-balancer${env:INSTANCE}.log.%d{yyyy-MM-dd}-%i.gz"
|
||||||
|
append: true
|
||||||
|
bufferedIO: true
|
||||||
|
bufferSize: 8192
|
||||||
|
Policies:
|
||||||
|
TimeBasedTriggeringPolicy:
|
||||||
|
interval: 1
|
||||||
|
SizeBasedTriggeringPolicy:
|
||||||
|
size: 250MB
|
||||||
|
DefaultRolloverStrategy:
|
||||||
|
max: 10
|
||||||
|
PatternLayout:
|
||||||
|
pattern: "${LOG_PATTERN}"
|
||||||
|
|
||||||
|
Loggers:
|
||||||
|
Root:
|
||||||
|
level: info
|
||||||
|
AppenderRef:
|
||||||
|
- ref: File
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
<beans:beans xmlns="http://www.springframework.org/schema/security"
|
|
||||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
|
||||||
xmlns:util="http://www.springframework.org/schema/util"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
|
||||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
|
||||||
http://www.springframework.org/schema/security
|
|
||||||
http://www.springframework.org/schema/security/spring-security.xsd
|
|
||||||
http://www.springframework.org/schema/util
|
|
||||||
http://www.springframework.org/schema/util/spring-util.xsd">
|
|
||||||
|
|
||||||
<beans:bean id="x509PrincipalExtractor" class="org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor">
|
|
||||||
<beans:property name="subjectDnRegex" value="CN=(.*?)(?:,|$)"/>
|
|
||||||
</beans:bean>
|
|
||||||
|
|
||||||
<beans:bean id="timelyUserDetailsService" class="timely.auth.UserDetailsService">
|
|
||||||
<beans:property name="users">
|
|
||||||
<util:list>
|
|
||||||
<beans:bean class="timely.auth.TimelyUser">
|
|
||||||
<beans:constructor-arg name="subjectDn">
|
|
||||||
<beans:value>CN=example.com</beans:value>
|
|
||||||
</beans:constructor-arg>
|
|
||||||
<beans:constructor-arg name="auths">
|
|
||||||
<util:list>
|
|
||||||
<beans:value>D</beans:value>
|
|
||||||
<beans:value>E</beans:value>
|
|
||||||
<beans:value>F</beans:value>
|
|
||||||
</util:list>
|
|
||||||
</beans:constructor-arg>
|
|
||||||
<beans:constructor-arg name="roles">
|
|
||||||
<util:list>
|
|
||||||
<beans:value>G</beans:value>
|
|
||||||
<beans:value>H</beans:value>
|
|
||||||
<beans:value>I</beans:value>
|
|
||||||
</util:list>
|
|
||||||
</beans:constructor-arg>
|
|
||||||
</beans:bean>
|
|
||||||
</util:list>
|
|
||||||
</beans:property>
|
|
||||||
</beans:bean>
|
|
||||||
|
|
||||||
<beans:bean id="x509AuthorizationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
|
|
||||||
<beans:property name="preAuthenticatedUserDetailsService" ref="timelyUserDetailsService" />
|
|
||||||
</beans:bean>
|
|
||||||
|
|
||||||
<user-service id="usernamePasswordService">
|
|
||||||
<user name="test" password="test1" authorities="A,B,C" />
|
|
||||||
</user-service>
|
|
||||||
|
|
||||||
<beans:bean id="noOpPasswordEncoder" class="org.springframework.security.crypto.password.NoOpPasswordEncoder"/>
|
|
||||||
|
|
||||||
<beans:bean id="UserNamePasswordAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
|
|
||||||
<beans:property name="userDetailsService" ref="usernamePasswordService"/>
|
|
||||||
<beans:property name="passwordEncoder" ref="noOpPasswordEncoder"/>
|
|
||||||
</beans:bean>
|
|
||||||
|
|
||||||
<authentication-manager alias="authenticationManager">
|
|
||||||
<!-- X509 PreAuthenticated authorization provider -->
|
|
||||||
<authentication-provider ref="x509AuthorizationProvider"/>
|
|
||||||
<!-- Basic authorization provider, validates provided username and password -->
|
|
||||||
<authentication-provider ref="UserNamePasswordAuthenticationProvider" />
|
|
||||||
</authentication-manager>
|
|
||||||
|
|
||||||
<util:list id="requiredRoles" value-type="java.lang.String">
|
|
||||||
<beans:value></beans:value>
|
|
||||||
</util:list>
|
|
||||||
|
|
||||||
<util:list id="requiredAuths" value-type="java.lang.String">
|
|
||||||
<beans:value></beans:value>
|
|
||||||
</util:list>
|
|
||||||
</beans:beans>
|
|
||||||
+159
-122
@@ -1,131 +1,168 @@
|
|||||||
timely-balancer:
|
timely:
|
||||||
zooKeeper:
|
instance: ${INSTANCE}
|
||||||
servers: localhost:2181
|
zookeeper:
|
||||||
|
servers: ${ACCUMULO_ZOOKEEPERS}
|
||||||
timeout: 30s
|
timeout: 30s
|
||||||
checkServerHealthInterval: 10000
|
|
||||||
serverFailuresBeforeDown: 6
|
|
||||||
serverSuccessesBeforeUp: 1
|
|
||||||
assignmentFile: /timely/balancer/assignments.csv
|
|
||||||
security:
|
security:
|
||||||
session-max-age: 86400
|
session-max-age: 86400
|
||||||
cache-expiration-minutes: 60
|
cache-expiration-minutes: 60
|
||||||
cache-refresh-minutes: 5
|
cache-refresh-minutes: 5
|
||||||
allow-anonymous-http-access: true
|
authorization-url: ${AUTHORIZATION_URL}
|
||||||
allow-anonymous-ws-access: true
|
allow-anonymous-http-access: ${ANONYMOUS_HTTP:true}
|
||||||
serverSsl:
|
allow-anonymous-ws-access: ${ANONYMOUS_WEBSOCKET:true}
|
||||||
certificate-file:
|
server-ssl:
|
||||||
key-file:
|
key-store-type: ${KEY_STORE_TYPE}
|
||||||
#key-password:
|
key-store-file: ${KEY_STORE_FILE}
|
||||||
use-generated-keypair: true
|
key-store-password: ${KEY_STORE_PASSWORD}
|
||||||
trust-store-file:
|
use-generated-keypair: ${GENERATE_KEYS}
|
||||||
use-openssl: true
|
ignore-ssl-handshake-errors: true
|
||||||
#use-ciphers:
|
trust-store-type: ${TRUST_STORE_TYPE}
|
||||||
clientSsl:
|
trust-store-file: ${TRUST_STORE_FILE}
|
||||||
keyFile:
|
trust-store-password: ${TRUST_STORE_PASSWORD}
|
||||||
keyType: pkcs12
|
client-ssl:
|
||||||
#keyPassword:
|
key-store-type: ${KEY_STORE_TYPE}
|
||||||
trustStoreFile:
|
key-store-file: ${KEY_STORE_FILE}
|
||||||
trustStoreType: jks
|
key-store-password: ${KEY_STORE_PASSWORD}
|
||||||
#trustStorePassword:
|
trust-store-type: ${TRUST_STORE_TYPE}
|
||||||
|
trust-store-file: ${TRUST_STORE_FILE}
|
||||||
|
trust-store-password: ${TRUST_STORE_PASSWORD}
|
||||||
|
hostVerificationEnabled: ${HOST_VERIFICATION_ENABLED:true}
|
||||||
|
jwt-ssl:
|
||||||
|
key-store-type: ${AUTHORIZATION_CERTIFICATE_TYPE}
|
||||||
|
key-store-file: ${AUTHORIZATION_CERTIFICATE_FILE}
|
||||||
|
key-store-password: ${AUTHORIZATION_CERTIFICATE_PASSWORD}
|
||||||
cache:
|
cache:
|
||||||
enabled: false
|
enabled: false
|
||||||
metric-age-off-hours:
|
metric-age-off-hours:
|
||||||
default: 26
|
default: 26
|
||||||
nonCachedMetrics:
|
non-cached-metrics:
|
||||||
server:
|
balancer:
|
||||||
ip: 127.0.0.1
|
check-server-health-interval: 10000
|
||||||
tcpPort: 4242
|
server-failures-before-down: 6
|
||||||
numTcpPools: 1
|
server-successes-before-up: 1
|
||||||
tcpBufferSize: 100
|
default-fs: ${HADOOP_DEFAULT_FS}
|
||||||
tcpClientPool:
|
fs-config-resources:
|
||||||
minIdlePerKey: 0
|
- ${HADOOP_CONF_DIR}/core-site.xml
|
||||||
maxIdlePerKey: 40
|
- ${HADOOP_CONF_DIR}/hdfs-site.xml
|
||||||
maxTotalPerKey: 40
|
assignment-file: hdfs:///timely/balancer/assignments.csv
|
||||||
maxTotal: -1
|
server:
|
||||||
lifo: true
|
ip: ${HOST_IP}
|
||||||
fairness: false
|
tcp-base-port: ${TCP_BASE_PORT}
|
||||||
maxWaitMillis: -1
|
tcp-buffer-size: 100
|
||||||
minEvictableIdleTimeMillis: 1800000
|
tcp-client-pool:
|
||||||
evictorShutdownTimeoutMillis: 10000
|
min-idle-per-key: 5
|
||||||
softMinEvictableIdleTimeMillis: -1
|
max-idle-per-key: 5
|
||||||
numTestsPerEvictionRun: 3
|
max-total-per-key: 5
|
||||||
timeBetweenEvictionRunsMillis: -1
|
max-total: -1
|
||||||
blockWhenExhausted: true
|
lifo: false
|
||||||
jmxEnabled: true
|
fairness: true
|
||||||
testOnBorrow: false
|
max-wait-millis: 60000
|
||||||
testOnReturn: false
|
min-evictable-idle-time-millis: -1
|
||||||
udpPort: 4245
|
evictor-shutdown-timeout-millis: 10000
|
||||||
udpClientPool:
|
soft-min-evictable-idle-time-millis: 300000
|
||||||
minIdlePerKey: 0
|
num-tests-per-eviction-run: 3
|
||||||
maxIdlePerKey: 40
|
time-between-eviction-runs-millis: 30000
|
||||||
maxTotalPerKey: 40
|
block-when-exhausted: true
|
||||||
maxTotal: -1
|
remove-abandoned-on-borrow: false
|
||||||
lifo: true
|
remove-abandoned-on-maintenance: true
|
||||||
fairness: false
|
remove-abandoned-timeout-millis: 600000
|
||||||
maxWaitMillis: -1
|
remove-abandoned-logging: true
|
||||||
minEvictableIdleTimeMillis: 1800000
|
jmx-enabled: true
|
||||||
evictorShutdownTimeoutMillis: 10000
|
test-on-borrow: false
|
||||||
softMinEvictableIdleTimeMillis: -1
|
test-on-return: false
|
||||||
numTestsPerEvictionRun: 3
|
udp-base-port: ${UDP_BASE_PORT}
|
||||||
timeBetweenEvictionRunsMillis: -1
|
udp-client-pool:
|
||||||
blockWhenExhausted: true
|
min-idle-per-key: 5
|
||||||
jmxEnabled: true
|
max-idle-per-key: 5
|
||||||
testOnBorrow: false
|
max-total-per-key: 5
|
||||||
testOnReturn: false
|
max-total: -1
|
||||||
http:
|
lifo: false
|
||||||
host: localhost
|
fairness: true
|
||||||
ip: 127.0.0.1
|
max-wait-millis: 60000
|
||||||
port: 4243
|
min-evictable-idle-time-millis: -1
|
||||||
redirect-path: /secure-me
|
evictor-shutdown-timeout-millis: 10000
|
||||||
strict-transport-max-age: 608400
|
soft-min-evictable-idle-time-millis: 300000
|
||||||
cors:
|
num-tests-per-eviction-run: 3
|
||||||
allow-any-origin: false
|
time-between-eviction-runs-millis: 30000
|
||||||
allow-null-origin: false
|
block-when-exhausted: true
|
||||||
allow-credentials: true
|
remove-abandoned-on-borrow: false
|
||||||
allowed-origins:
|
remove-abandoned-on-maintenance: true
|
||||||
allowed-methods: DELETE,GET,HEAD,OPTIONS,PUT,POST
|
remove-abandoned-timeout-millis: 600000
|
||||||
allowed-headers: content-type
|
remove-abandoned-logging: true
|
||||||
httpClientPool:
|
jmx-enabled: true
|
||||||
minIdlePerKey: 0
|
test-on-borrow: false
|
||||||
maxIdlePerKey: 40
|
test-on-return: false
|
||||||
maxTotalPerKey: 40
|
http:
|
||||||
maxTotal: -1
|
host: ${HOST}
|
||||||
lifo: true
|
ip: ${HOST_IP}
|
||||||
fairness: false
|
base-port: ${HTTP_BASE_PORT}
|
||||||
maxWaitMillis: -1
|
redirect-path: /secure-me
|
||||||
minEvictableIdleTimeMillis: 1800000
|
strict-transport-max-age: 604800
|
||||||
evictorShutdownTimeoutMillis: 10000
|
connection-request-timeout: 5000
|
||||||
softMinEvictableIdleTimeMillis: -1
|
connect-timeout: 5000
|
||||||
numTestsPerEvictionRun: 3
|
socketTimeout: 300000
|
||||||
timeBetweenEvictionRunsMillis: -1
|
request-timeout: 300000
|
||||||
blockWhenExhausted: true
|
cors:
|
||||||
jmxEnabled: true
|
allow-any-origin: false
|
||||||
testOnBorrow: false
|
allow-null-origin: false
|
||||||
testOnReturn: false
|
allow-credentials: true
|
||||||
websocket:
|
allowed-origins:
|
||||||
ip: 127.0.0.1
|
allowed-methods: DELETE,GET,HEAD,OPTIONS,PUT,POST
|
||||||
port: 5244
|
allowed-headers: content-type
|
||||||
timeout: 60
|
httpClientPool:
|
||||||
subscription-lag: 120
|
min-idle-per-key: 10
|
||||||
scanner-batch-size: 10000
|
max-idle-per-key: 40
|
||||||
flush-interval-seconds: 30
|
max-total-per-key: 40
|
||||||
scanner-read-ahead: 1
|
max-total: -1
|
||||||
subscription-batch-size: 5000
|
lifo: false
|
||||||
incomingBufferSize: 50000000
|
fairness: true
|
||||||
wsClientPool:
|
max-wait-millis: 60000
|
||||||
minIdlePerKey: 0
|
min-evictable-idle-time-millis: -1
|
||||||
maxIdlePerKey: 40
|
evictor-shutdown-timeout-millis: 10000
|
||||||
maxTotalPerKey: 40
|
soft-min-evictable-idle-time-millis: 300000
|
||||||
maxTotal: -1
|
num-tests-per-eviction-run: 3
|
||||||
lifo: true
|
time-between-eviction-runs-millis: 30000
|
||||||
fairness: false
|
block-when-exhausted: true
|
||||||
maxWaitMillis: -1
|
remove-abandoned-on-borrow: false
|
||||||
minEvictableIdleTimeMillis: 1800000
|
remove-abandoned-on-maintenance: true
|
||||||
evictorShutdownTimeoutMillis: 10000
|
remove-abandoned-timeout-millis: 600000
|
||||||
softMinEvictableIdleTimeMillis: -1
|
remove-abandoned-logging: true
|
||||||
numTestsPerEvictionRun: 3
|
jmx-enabled: true
|
||||||
timeBetweenEvictionRunsMillis: -1
|
test-on-borrow: false
|
||||||
blockWhenExhausted: true
|
test-on-return: false
|
||||||
jmxEnabled: true
|
websocket:
|
||||||
testOnBorrow: false
|
ip: ${HOST_IP}
|
||||||
testOnReturn: false
|
base-port: ${WEBSOCKET_BASE_PORT}
|
||||||
|
timeout: 60
|
||||||
|
subscription-lag: 120
|
||||||
|
scanner-batch-size: 10000
|
||||||
|
flush-interval-seconds: 30
|
||||||
|
scanner-read-ahead: 1
|
||||||
|
subscription-batch-size: 5000
|
||||||
|
incoming-buffer-size: 50000000
|
||||||
|
ws-client-pool:
|
||||||
|
min-idle-per-key: 0
|
||||||
|
max-idle-per-key: 40
|
||||||
|
max-total-per-key: 40
|
||||||
|
max-total: -1
|
||||||
|
lifo: false
|
||||||
|
fairness: true
|
||||||
|
max-wait-millis: 60000
|
||||||
|
min-evictable-idle-time-millis: -1
|
||||||
|
evictor-shutdown-timeout-millis: 10000
|
||||||
|
soft-min-evictable-idle-time-millis: 300000
|
||||||
|
num-tests-per-eviction-run: 3
|
||||||
|
time-between-eviction-runs-millis: 30000
|
||||||
|
block-when-exhausted: true
|
||||||
|
remove-abandoned-on-borrow: false
|
||||||
|
remove-abandoned-on-maintenance: true
|
||||||
|
remove-abandoned-timeout-millis: 600000
|
||||||
|
remove-abandoned-logging: true
|
||||||
|
jmx-enabled: true
|
||||||
|
test-on-borrow: false
|
||||||
|
test-on-return: false
|
||||||
|
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
ROOT: info
|
||||||
|
timely: debug
|
||||||
+96
-31
@@ -4,9 +4,13 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely</artifactId>
|
<artifactId>timely</artifactId>
|
||||||
<version>1.2.8-SNAPSHOT</version>
|
<version>2.2.6-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>timely-balancer</artifactId>
|
<artifactId>timely-balancer</artifactId>
|
||||||
|
<description>Timely Balancer</description>
|
||||||
|
<properties>
|
||||||
|
<start-class>timely.balancer.TimelyBalancer</start-class>
|
||||||
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
@@ -37,12 +41,12 @@
|
|||||||
<artifactId>commons-beanutils</artifactId>
|
<artifactId>commons-beanutils</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.lukehutch</groupId>
|
<groupId>io.github.classgraph</groupId>
|
||||||
<artifactId>fast-classpath-scanner</artifactId>
|
<artifactId>classgraph</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-all</artifactId>
|
<artifactId>netty-transport-classes-epoll</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.sourceforge.javacsv</groupId>
|
<groupId>net.sourceforge.javacsv</groupId>
|
||||||
@@ -51,16 +55,6 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.accumulo</groupId>
|
<groupId>org.apache.accumulo</groupId>
|
||||||
<artifactId>accumulo-core</artifactId>
|
<artifactId>accumulo-core</artifactId>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.accumulo</groupId>
|
|
||||||
<artifactId>accumulo-minicluster</artifactId>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
@@ -97,21 +91,19 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.hadoop</groupId>
|
<groupId>org.apache.hadoop</groupId>
|
||||||
<artifactId>hadoop-common</artifactId>
|
<artifactId>hadoop-common</artifactId>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>jdk.tools</groupId>
|
|
||||||
<artifactId>jdk.tools</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.hadoop</groupId>
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
<artifactId>hadoop-minicluster</artifactId>
|
<artifactId>log4j-1.2-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-webflux</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-websocket</artifactId>
|
<artifactId>spring-websocket</artifactId>
|
||||||
@@ -134,6 +126,18 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-context</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-config</artifactId>
|
<artifactId>spring-security-config</artifactId>
|
||||||
@@ -150,10 +154,6 @@
|
|||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely-common</artifactId>
|
<artifactId>timely-common</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>timely</groupId>
|
|
||||||
<artifactId>timely-server</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.lmax</groupId>
|
<groupId>com.lmax</groupId>
|
||||||
<artifactId>disruptor</artifactId>
|
<artifactId>disruptor</artifactId>
|
||||||
@@ -162,6 +162,30 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||||
|
<classifier>linux-aarch_64</classifier>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||||
|
<classifier>linux-x86_64</classifier>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-transport-native-epoll</artifactId>
|
||||||
|
<classifier>linux-aarch_64</classifier>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-transport-native-epoll</artifactId>
|
||||||
|
<classifier>linux-x86_64</classifier>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.activation</groupId>
|
||||||
|
<artifactId>activation</artifactId>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -174,11 +198,6 @@
|
|||||||
<artifactId>log4j-core</artifactId>
|
<artifactId>log4j-core</artifactId>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
|
||||||
<artifactId>log4j-slf4j-impl</artifactId>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.javassist</groupId>
|
<groupId>org.javassist</groupId>
|
||||||
<artifactId>javassist</artifactId>
|
<artifactId>javassist</artifactId>
|
||||||
@@ -189,19 +208,38 @@
|
|||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.hadoop</groupId>
|
||||||
|
<artifactId>hadoop-minicluster</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jsoup</groupId>
|
<groupId>org.jsoup</groupId>
|
||||||
<artifactId>jsoup</artifactId>
|
<artifactId>jsoup</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-test-autoconfigure</artifactId>
|
<artifactId>spring-boot-test-autoconfigure</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>timely</groupId>
|
||||||
|
<artifactId>timely-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-assembly-plugin</artifactId>
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
@@ -261,6 +299,20 @@
|
|||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>3.1.2</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<!--suppress UnresolvedMavenProperty, MavenModelInspection -->
|
||||||
|
<mainClass>${start-class}</mainClass>
|
||||||
|
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>build-helper-maven-plugin</artifactId>
|
<artifactId>build-helper-maven-plugin</artifactId>
|
||||||
@@ -288,4 +340,17 @@
|
|||||||
</extension>
|
</extension>
|
||||||
</extensions>
|
</extensions>
|
||||||
</build>
|
</build>
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>docker</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.spotify</groupId>
|
||||||
|
<artifactId>docker-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
</project>
|
</project>
|
||||||
Vendored
+12
-16
@@ -15,20 +15,23 @@
|
|||||||
<include>NOTICE*</include>
|
<include>NOTICE*</include>
|
||||||
</includes>
|
</includes>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
|
||||||
<directory>${project.build.directory}</directory>
|
|
||||||
<outputDirectory>lib</outputDirectory>
|
|
||||||
<includes>
|
|
||||||
<include>timely*.jar</include>
|
|
||||||
</includes>
|
|
||||||
</fileSet>
|
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<directory>${project.build.directory}/lib</directory>
|
<directory>${project.build.directory}/lib</directory>
|
||||||
<outputDirectory>lib</outputDirectory>
|
<outputDirectory>lib</outputDirectory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>*.jar</include>
|
<include>netty-tcnative-boringssl-static*linux-x86_64.jar</include>
|
||||||
|
<include>netty-tcnative-boringssl-static*linux-aarch_64.jar</include>
|
||||||
|
<include>netty-transport-native-epoll*linux-x86_64.jar</include>
|
||||||
|
<include>netty-transport-native-epoll*linux-aarch_64.jar</include>
|
||||||
</includes>
|
</includes>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.build.directory}</directory>
|
||||||
|
<outputDirectory>bin</outputDirectory>
|
||||||
|
<includes>
|
||||||
|
<include>timely-balancer-*-exec.jar</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<directory>${project.basedir}/bin</directory>
|
<directory>${project.basedir}/bin</directory>
|
||||||
<outputDirectory>bin</outputDirectory>
|
<outputDirectory>bin</outputDirectory>
|
||||||
@@ -43,12 +46,5 @@
|
|||||||
<include>*</include>
|
<include>*</include>
|
||||||
</includes>
|
</includes>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
|
||||||
<directory>${project.basedir}/src/main/resources/webapp</directory>
|
|
||||||
<outputDirectory>bin/webapp</outputDirectory>
|
|
||||||
<includes>
|
|
||||||
<include>*</include>
|
|
||||||
</includes>
|
|
||||||
</fileSet>
|
|
||||||
</fileSets>
|
</fileSets>
|
||||||
</assembly>
|
</assembly>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
FROM azul/zulu-openjdk-alpine:11
|
||||||
|
|
||||||
|
LABEL version=${project.version} \
|
||||||
|
run="docker run ${docker.image.prefix}${project.artifactId}:latest" \
|
||||||
|
description="${project.description}"
|
||||||
|
|
||||||
|
ADD ${project.build.finalName}-exec.jar /app.jar
|
||||||
|
RUN apk add libc6-compat curl
|
||||||
|
|
||||||
|
EXPOSE 54322 54323 54324 54325
|
||||||
|
ENTRYPOINT ["java","-jar","app.jar"]
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package timely.balancer;
|
package timely.balancer;
|
||||||
|
|
||||||
import java.util.Timer;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.TimerTask;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.AtomicDouble;
|
import com.google.common.util.concurrent.AtomicDouble;
|
||||||
@@ -20,38 +20,26 @@ public class ArrivalRate {
|
|||||||
private AtomicDouble longTermRate = new AtomicDouble(0);
|
private AtomicDouble longTermRate = new AtomicDouble(0);
|
||||||
private AtomicLong longTermLastReset = new AtomicLong(0);
|
private AtomicLong longTermLastReset = new AtomicLong(0);
|
||||||
|
|
||||||
public ArrivalRate(Timer timer) {
|
public ArrivalRate(ScheduledExecutorService arrivalRateExecutor) {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
shortTermLastReset.set(now);
|
shortTermLastReset.set(now);
|
||||||
mediumTermLastReset.set(now);
|
mediumTermLastReset.set(now);
|
||||||
longTermLastReset.set(now);
|
longTermLastReset.set(now);
|
||||||
|
|
||||||
// 2 minute
|
// 2 minute
|
||||||
timer.schedule(new TimerTask() {
|
arrivalRateExecutor.scheduleAtFixedRate(() -> {
|
||||||
|
resetShort();
|
||||||
@Override
|
}, 2, 2, TimeUnit.MINUTES);
|
||||||
public void run() {
|
|
||||||
resetShort();
|
|
||||||
}
|
|
||||||
}, 120000, 120000);
|
|
||||||
|
|
||||||
// 5 minute
|
// 5 minute
|
||||||
timer.schedule(new TimerTask() {
|
arrivalRateExecutor.scheduleAtFixedRate(() -> {
|
||||||
|
resetMedium();
|
||||||
@Override
|
}, 5, 5, TimeUnit.MINUTES);
|
||||||
public void run() {
|
|
||||||
resetMedium();
|
|
||||||
}
|
|
||||||
}, 300000, 300000);
|
|
||||||
|
|
||||||
// 15 minute
|
// 15 minute
|
||||||
timer.schedule(new TimerTask() {
|
arrivalRateExecutor.scheduleAtFixedRate(() -> {
|
||||||
|
resetLong();
|
||||||
@Override
|
}, 15, 15, TimeUnit.MINUTES);
|
||||||
public void run() {
|
|
||||||
resetLong();
|
|
||||||
}
|
|
||||||
}, 900000, 900000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetShort() {
|
private void resetShort() {
|
||||||
|
|||||||
@@ -1,21 +1,34 @@
|
|||||||
package timely.balancer;
|
package timely.balancer;
|
||||||
|
|
||||||
import static timely.Server.SERVICE_DISCOVERY_PATH;
|
import static org.apache.accumulo.core.conf.ConfigurationTypeHelper.getTimeInMillis;
|
||||||
import static timely.store.cache.DataStoreCache.NON_CACHED_METRICS;
|
import static timely.Constants.NON_CACHED_METRICS;
|
||||||
import static timely.store.cache.DataStoreCache.NON_CACHED_METRICS_LOCK_PATH;
|
import static timely.Constants.NON_CACHED_METRICS_LOCK_PATH;
|
||||||
|
import static timely.Constants.SERVICE_DISCOVERY_PATH;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.curator.RetryPolicy;
|
||||||
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
|
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||||
|
import org.apache.curator.retry.RetryForever;
|
||||||
|
import org.apache.zookeeper.CreateMode;
|
||||||
|
import org.apache.zookeeper.data.Stat;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
|
import io.netty.bootstrap.AbstractBootstrap;
|
||||||
import io.netty.bootstrap.Bootstrap;
|
import io.netty.bootstrap.Bootstrap;
|
||||||
import io.netty.bootstrap.ServerBootstrap;
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
import io.netty.buffer.PooledByteBufAllocator;
|
import io.netty.buffer.PooledByteBufAllocator;
|
||||||
@@ -25,7 +38,6 @@ import io.netty.channel.ChannelHandler;
|
|||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
import io.netty.channel.ChannelOption;
|
import io.netty.channel.ChannelOption;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.channel.WriteBufferWaterMark;
|
|
||||||
import io.netty.channel.epoll.EpollChannelOption;
|
import io.netty.channel.epoll.EpollChannelOption;
|
||||||
import io.netty.channel.epoll.EpollDatagramChannel;
|
import io.netty.channel.epoll.EpollDatagramChannel;
|
||||||
import io.netty.channel.epoll.EpollEventLoopGroup;
|
import io.netty.channel.epoll.EpollEventLoopGroup;
|
||||||
@@ -46,48 +58,35 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
|
|||||||
import io.netty.handler.codec.http.HttpServerCodec;
|
import io.netty.handler.codec.http.HttpServerCodec;
|
||||||
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
||||||
import io.netty.handler.logging.LoggingHandler;
|
import io.netty.handler.logging.LoggingHandler;
|
||||||
import io.netty.handler.ssl.ClientAuth;
|
|
||||||
import io.netty.handler.ssl.OpenSslServerContext;
|
import io.netty.handler.ssl.OpenSslServerContext;
|
||||||
import io.netty.handler.ssl.OpenSslServerSessionContext;
|
import io.netty.handler.ssl.OpenSslServerSessionContext;
|
||||||
import io.netty.handler.ssl.SslContext;
|
import io.netty.handler.ssl.SslContext;
|
||||||
import io.netty.handler.ssl.SslContextBuilder;
|
|
||||||
import io.netty.handler.ssl.SslProvider;
|
|
||||||
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
|
||||||
import io.netty.handler.stream.ChunkedWriteHandler;
|
import io.netty.handler.stream.ChunkedWriteHandler;
|
||||||
import io.netty.handler.timeout.IdleStateHandler;
|
import io.netty.handler.timeout.IdleStateHandler;
|
||||||
import io.netty.util.NettyRuntime;
|
import io.netty.util.NettyRuntime;
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
import org.apache.accumulo.core.conf.AccumuloConfiguration;
|
import timely.auth.JWTTokenHandler;
|
||||||
import org.apache.curator.RetryPolicy;
|
import timely.balancer.configuration.BalancerHttpProperties;
|
||||||
import org.apache.curator.framework.CuratorFramework;
|
import timely.balancer.configuration.BalancerProperties;
|
||||||
import org.apache.curator.framework.CuratorFrameworkFactory;
|
import timely.balancer.configuration.BalancerServerProperties;
|
||||||
import org.apache.curator.retry.RetryForever;
|
import timely.balancer.configuration.BalancerWebsocketProperties;
|
||||||
import org.apache.zookeeper.CreateMode;
|
|
||||||
import org.apache.zookeeper.data.Stat;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.boot.WebApplicationType;
|
|
||||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
|
||||||
import timely.auth.AuthCache;
|
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
|
||||||
import timely.balancer.configuration.ClientSsl;
|
|
||||||
import timely.balancer.configuration.SpringBootstrap;
|
|
||||||
import timely.balancer.connection.http.HttpClientPool;
|
import timely.balancer.connection.http.HttpClientPool;
|
||||||
import timely.balancer.connection.tcp.TcpClientPool;
|
import timely.balancer.connection.tcp.TcpClientPool;
|
||||||
import timely.balancer.connection.udp.UdpClientPool;
|
import timely.balancer.connection.udp.UdpClientPool;
|
||||||
import timely.balancer.connection.ws.WsClientPool;
|
import timely.balancer.connection.ws.WsClientPool;
|
||||||
import timely.balancer.healthcheck.HealthChecker;
|
|
||||||
import timely.balancer.netty.http.HttpRelayHandler;
|
import timely.balancer.netty.http.HttpRelayHandler;
|
||||||
import timely.balancer.netty.tcp.TcpRelayHandler;
|
import timely.balancer.netty.tcp.TcpRelayHandler;
|
||||||
import timely.balancer.netty.udp.UdpRelayHandler;
|
import timely.balancer.netty.udp.UdpRelayHandler;
|
||||||
import timely.balancer.netty.ws.WsRelayHandler;
|
import timely.balancer.netty.ws.WsRelayHandler;
|
||||||
import timely.balancer.resolver.BalancedMetricResolver;
|
import timely.common.component.AuthenticationService;
|
||||||
import timely.balancer.resolver.MetricResolver;
|
import timely.common.configuration.SecurityProperties;
|
||||||
import timely.client.http.HttpClient;
|
import timely.common.configuration.SslClientProperties;
|
||||||
import timely.configuration.ServerSsl;
|
import timely.common.configuration.SslServerProperties;
|
||||||
import timely.netty.http.HttpStaticFileServerHandler;
|
import timely.common.configuration.ZookeeperProperties;
|
||||||
import timely.netty.http.NonSslRedirectHandler;
|
import timely.netty.http.HttpStrictTransportSecurityHandler;
|
||||||
|
import timely.netty.http.HttpVersionRequestHandler;
|
||||||
|
import timely.netty.http.NonSslForbiddenHandler;
|
||||||
|
import timely.netty.http.NotFoundHandler;
|
||||||
import timely.netty.http.TimelyExceptionHandler;
|
import timely.netty.http.TimelyExceptionHandler;
|
||||||
import timely.netty.http.auth.X509LoginRequestHandler;
|
import timely.netty.http.auth.X509LoginRequestHandler;
|
||||||
import timely.netty.tcp.MetricsBufferDecoder;
|
import timely.netty.tcp.MetricsBufferDecoder;
|
||||||
@@ -105,17 +104,25 @@ public class Balancer {
|
|||||||
final public static String ASSIGNMENTS_LOCK_PATH = "/timely/balancer/assignments/lock";
|
final public static String ASSIGNMENTS_LOCK_PATH = "/timely/balancer/assignments/lock";
|
||||||
final public static String ASSIGNMENTS_LAST_UPDATED_PATH = "/timely/balancer/assignments/lastUpdated";
|
final public static String ASSIGNMENTS_LAST_UPDATED_PATH = "/timely/balancer/assignments/lastUpdated";
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Balancer.class);
|
private static final Logger log = LoggerFactory.getLogger(Balancer.class);
|
||||||
private static final int EPOLL_MIN_MAJOR_VERSION = 2;
|
private static final String EPOLL_MIN_VERSION = "2.7";
|
||||||
private static final int EPOLL_MIN_MINOR_VERSION = 6;
|
|
||||||
private static final int EPOLL_MIN_PATCH_VERSION = 32;
|
|
||||||
private static final String OS_NAME = "os.name";
|
private static final String OS_NAME = "os.name";
|
||||||
private static final String OS_VERSION = "os.version";
|
private static final String OS_VERSION = "os.version";
|
||||||
private static final String WS_PATH = "/websocket";
|
private static final String WS_PATH = "/websocket";
|
||||||
protected static final CountDownLatch LATCH = new CountDownLatch(1);
|
private BalancerProperties balancerProperties;
|
||||||
static ConfigurableApplicationContext applicationContext;
|
private SecurityProperties securityProperties;
|
||||||
|
private SslServerProperties sslServerProperties;
|
||||||
private final BalancerConfiguration balancerConfig;
|
private SslClientProperties sslClientProperties;
|
||||||
|
private ZookeeperProperties zookeeperProperties;
|
||||||
|
private BalancerServerProperties balancerServerProperties;
|
||||||
|
private BalancerHttpProperties balancerHttpProperties;
|
||||||
|
private BalancerWebsocketProperties balancerWebsocketProperties;
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
private AuthenticationService authenticationService;
|
||||||
|
private CuratorFramework curatorFramework;
|
||||||
|
private int quietPeriod;
|
||||||
|
private SslContext serverSslContext;
|
||||||
|
private SSLContext clientSSLContext;
|
||||||
private EventLoopGroup tcpWorkerGroup = null;
|
private EventLoopGroup tcpWorkerGroup = null;
|
||||||
private EventLoopGroup tcpBossGroup = null;
|
private EventLoopGroup tcpBossGroup = null;
|
||||||
private EventLoopGroup httpWorkerGroup = null;
|
private EventLoopGroup httpWorkerGroup = null;
|
||||||
@@ -129,57 +136,196 @@ public class Balancer {
|
|||||||
protected Channel httpChannelHandle = null;
|
protected Channel httpChannelHandle = null;
|
||||||
protected Channel wsChannelHandle = null;
|
protected Channel wsChannelHandle = null;
|
||||||
protected List<Channel> udpChannelHandleList = new ArrayList<>();
|
protected List<Channel> udpChannelHandleList = new ArrayList<>();
|
||||||
private CuratorFramework curatorFramework;
|
protected int DEFAULT_EVENT_LOOP_THREADS;
|
||||||
protected volatile boolean shutdown = false;
|
|
||||||
private static final int DEFAULT_EVENT_LOOP_THREADS;
|
|
||||||
|
|
||||||
private String[] zkPaths = new String[] { LEADER_LATCH_PATH, ASSIGNMENTS_LAST_UPDATED_PATH, ASSIGNMENTS_LOCK_PATH,
|
private String[] zkPaths = new String[] {LEADER_LATCH_PATH, ASSIGNMENTS_LAST_UPDATED_PATH, ASSIGNMENTS_LOCK_PATH, SERVICE_DISCOVERY_PATH,
|
||||||
SERVICE_DISCOVERY_PATH, NON_CACHED_METRICS, NON_CACHED_METRICS_LOCK_PATH };
|
NON_CACHED_METRICS, NON_CACHED_METRICS_LOCK_PATH};
|
||||||
|
|
||||||
static {
|
private static boolean useEpoll() {
|
||||||
DEFAULT_EVENT_LOOP_THREADS = Math.max(1,
|
final String osName = SystemPropertyUtil.get(OS_NAME).toLowerCase().trim();
|
||||||
SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
|
final String osVersion = SystemPropertyUtil.get(OS_VERSION).toLowerCase();
|
||||||
}
|
// split at periods, keep the first two, join with a period
|
||||||
|
final String majMinVers = StringUtils.join(Arrays.stream(osVersion.split("\\.")).limit(2).collect(Collectors.toList()), ".");
|
||||||
public Balancer(BalancerConfiguration balancerConf) throws Exception {
|
if (osName.startsWith("linux")) {
|
||||||
this.balancerConfig = balancerConf;
|
try {
|
||||||
}
|
Runtime.Version currentVersion = Runtime.Version.parse(majMinVers);
|
||||||
|
Runtime.Version epollMinVersion = Runtime.Version.parse(EPOLL_MIN_VERSION);
|
||||||
protected static ConfigurableApplicationContext initializeConfiguration(String[] args) {
|
return currentVersion.compareTo(epollMinVersion) > 0;
|
||||||
return new SpringApplicationBuilder(SpringBootstrap.class).web(WebApplicationType.NONE).run(args);
|
} catch (Exception e) {
|
||||||
}
|
log.error(e.getMessage(), e);
|
||||||
|
|
||||||
private void shutdownHook() {
|
|
||||||
|
|
||||||
final Runnable shutdownRunner = () -> {
|
|
||||||
if (!shutdown) {
|
|
||||||
shutdown();
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
final Thread hook = new Thread(shutdownRunner, "shutdown-hook-thread");
|
return false;
|
||||||
Runtime.getRuntime().addShutdownHook(hook);
|
}
|
||||||
|
|
||||||
|
public Balancer(ApplicationContext applicationContext, SslContext serverSslContext, SSLContext clientSSLContext,
|
||||||
|
AuthenticationService authenticationService, MetricResolver metricResolver, BalancerProperties balancerProperties,
|
||||||
|
ZookeeperProperties zookeeperProperties, SecurityProperties securityProperties, SslServerProperties sslServerProperties,
|
||||||
|
SslClientProperties sslClientProperties, BalancerServerProperties balancerServerProperties, BalancerHttpProperties balancerHttpProperties,
|
||||||
|
BalancerWebsocketProperties balancerWebsocketProperties) {
|
||||||
|
this.serverSslContext = serverSslContext;
|
||||||
|
this.clientSSLContext = clientSSLContext;
|
||||||
|
this.quietPeriod = balancerServerProperties.getShutdownQuietPeriod();
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
this.authenticationService = authenticationService;
|
||||||
|
this.metricResolver = metricResolver;
|
||||||
|
this.balancerProperties = balancerProperties;
|
||||||
|
this.zookeeperProperties = zookeeperProperties;
|
||||||
|
this.securityProperties = securityProperties;
|
||||||
|
this.sslServerProperties = sslServerProperties;
|
||||||
|
this.sslClientProperties = sslClientProperties;
|
||||||
|
this.balancerServerProperties = balancerServerProperties;
|
||||||
|
this.balancerHttpProperties = balancerHttpProperties;
|
||||||
|
this.balancerWebsocketProperties = balancerWebsocketProperties;
|
||||||
|
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
log.info("Starting {}", this.getClass().getSimpleName());
|
||||||
|
try {
|
||||||
|
// start curator framework
|
||||||
|
RetryPolicy retryPolicy = new RetryForever(1000);
|
||||||
|
int timeout = Long.valueOf(getTimeInMillis(zookeeperProperties.getTimeout())).intValue();
|
||||||
|
curatorFramework = CuratorFrameworkFactory.newClient(zookeeperProperties.getServers(), timeout, 10000, retryPolicy);
|
||||||
|
curatorFramework.start();
|
||||||
|
ensureZkPaths(curatorFramework, zkPaths);
|
||||||
|
|
||||||
|
JWTTokenHandler.init(securityProperties, null);
|
||||||
|
final boolean useEpoll = useEpoll();
|
||||||
|
Class<? extends ServerSocketChannel> channelClass;
|
||||||
|
Class<? extends Channel> datagramChannelClass;
|
||||||
|
if (useEpoll) {
|
||||||
|
tcpWorkerGroup = new EpollEventLoopGroup();
|
||||||
|
tcpBossGroup = new EpollEventLoopGroup();
|
||||||
|
httpWorkerGroup = new EpollEventLoopGroup();
|
||||||
|
httpBossGroup = new EpollEventLoopGroup();
|
||||||
|
wsWorkerGroup = new EpollEventLoopGroup();
|
||||||
|
wsBossGroup = new EpollEventLoopGroup();
|
||||||
|
udpWorkerGroup = new EpollEventLoopGroup();
|
||||||
|
udpBossGroup = new EpollEventLoopGroup();
|
||||||
|
channelClass = EpollServerSocketChannel.class;
|
||||||
|
datagramChannelClass = EpollDatagramChannel.class;
|
||||||
|
} else {
|
||||||
|
tcpWorkerGroup = new NioEventLoopGroup();
|
||||||
|
tcpBossGroup = new NioEventLoopGroup();
|
||||||
|
httpWorkerGroup = new NioEventLoopGroup();
|
||||||
|
httpBossGroup = new NioEventLoopGroup();
|
||||||
|
wsWorkerGroup = new NioEventLoopGroup();
|
||||||
|
wsBossGroup = new NioEventLoopGroup();
|
||||||
|
udpWorkerGroup = new NioEventLoopGroup();
|
||||||
|
udpBossGroup = new NioEventLoopGroup();
|
||||||
|
channelClass = NioServerSocketChannel.class;
|
||||||
|
datagramChannelClass = NioDatagramChannel.class;
|
||||||
|
}
|
||||||
|
log.info("Using channel class {}", channelClass.getSimpleName());
|
||||||
|
|
||||||
|
final ServerBootstrap tcpServer = new ServerBootstrap();
|
||||||
|
tcpServer.group(tcpBossGroup, tcpWorkerGroup);
|
||||||
|
tcpServer.channel(channelClass);
|
||||||
|
tcpServer.handler(new LoggingHandler());
|
||||||
|
TcpClientPool tcpClientPool = new TcpClientPool(balancerServerProperties);
|
||||||
|
tcpServer.childHandler(setupTcpChannel(metricResolver, tcpClientPool));
|
||||||
|
tcpServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
||||||
|
tcpServer.option(ChannelOption.SO_BACKLOG, 128);
|
||||||
|
tcpServer.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||||
|
final int tcpPort = balancerServerProperties.getTcpPort();
|
||||||
|
final String tcpIp = balancerServerProperties.getIp();
|
||||||
|
tcpChannelHandle = bind(tcpServer, tcpIp, tcpPort);
|
||||||
|
final String tcpAddress = ((InetSocketAddress) tcpChannelHandle.localAddress()).getAddress().getHostAddress();
|
||||||
|
|
||||||
|
final int httpPort = balancerHttpProperties.getPort();
|
||||||
|
final String httpIp = balancerHttpProperties.getIp();
|
||||||
|
|
||||||
|
if (serverSslContext instanceof OpenSslServerContext) {
|
||||||
|
OpenSslServerContext openssl = (OpenSslServerContext) serverSslContext;
|
||||||
|
String application = "Timely_" + httpPort;
|
||||||
|
OpenSslServerSessionContext opensslCtx = openssl.sessionContext();
|
||||||
|
opensslCtx.setSessionCacheEnabled(true);
|
||||||
|
opensslCtx.setSessionCacheSize(128);
|
||||||
|
opensslCtx.setSessionIdContext(application.getBytes(StandardCharsets.UTF_8));
|
||||||
|
opensslCtx.setSessionTimeout(securityProperties.getSessionMaxAge());
|
||||||
|
}
|
||||||
|
final ServerBootstrap httpServer = new ServerBootstrap();
|
||||||
|
httpServer.group(httpBossGroup, httpWorkerGroup);
|
||||||
|
httpServer.channel(channelClass);
|
||||||
|
httpServer.handler(new LoggingHandler());
|
||||||
|
HttpClientPool httpClientPool = new HttpClientPool(balancerHttpProperties, clientSSLContext, sslClientProperties);
|
||||||
|
httpServer.childHandler(setupHttpChannel(balancerHttpProperties, sslServerProperties, serverSslContext, metricResolver, httpClientPool));
|
||||||
|
httpServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
||||||
|
httpServer.option(ChannelOption.SO_BACKLOG, 128);
|
||||||
|
httpServer.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||||
|
httpChannelHandle = bind(httpServer, httpIp, httpPort);
|
||||||
|
final String httpAddress = ((InetSocketAddress) httpChannelHandle.localAddress()).getAddress().getHostAddress();
|
||||||
|
|
||||||
|
final int wsPort = balancerWebsocketProperties.getPort();
|
||||||
|
final String wsIp = balancerWebsocketProperties.getIp();
|
||||||
|
final ServerBootstrap wsServer = new ServerBootstrap();
|
||||||
|
wsServer.group(wsBossGroup, wsWorkerGroup);
|
||||||
|
wsServer.channel(channelClass);
|
||||||
|
wsServer.handler(new LoggingHandler());
|
||||||
|
WsClientPool wsClientPool = new WsClientPool(balancerProperties, balancerWebsocketProperties, sslClientProperties, clientSSLContext);
|
||||||
|
wsServer.childHandler(setupWSChannel(balancerWebsocketProperties, securityProperties, serverSslContext, metricResolver, wsClientPool));
|
||||||
|
wsServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
||||||
|
wsServer.option(ChannelOption.SO_BACKLOG, 128);
|
||||||
|
wsServer.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||||
|
wsChannelHandle = bind(wsServer, wsIp, wsPort);
|
||||||
|
final String wsAddress = ((InetSocketAddress) wsChannelHandle.localAddress()).getAddress().getHostAddress();
|
||||||
|
|
||||||
|
final int udpPort = balancerServerProperties.getUdpPort();
|
||||||
|
final String udpIp = balancerServerProperties.getIp();
|
||||||
|
UdpClientPool udpClientPool = new UdpClientPool(balancerServerProperties);
|
||||||
|
for (int n = 0; n < DEFAULT_EVENT_LOOP_THREADS; n++) {
|
||||||
|
final Bootstrap udpServer = new Bootstrap();
|
||||||
|
udpServer.group(udpBossGroup);
|
||||||
|
udpServer.channel(datagramChannelClass);
|
||||||
|
udpServer.handler(setupUdpChannel(metricResolver, udpClientPool));
|
||||||
|
udpServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
||||||
|
udpServer.option(EpollChannelOption.SO_REUSEADDR, true);
|
||||||
|
udpServer.option(EpollChannelOption.SO_REUSEPORT, true);
|
||||||
|
udpChannelHandleList.add(bind(udpServer, udpIp, udpPort));
|
||||||
|
}
|
||||||
|
log.info("Balancer started. Listening on {}:{} for TCP traffic, {}:{} for HTTP traffic, {}:{} for WebSocket traffic, and {}:{} for UDP traffic",
|
||||||
|
tcpAddress, tcpPort, httpAddress, httpPort, wsAddress, wsPort, wsAddress, udpPort);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
SpringApplication.exit(applicationContext, () -> 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Channel bind(AbstractBootstrap server, String ip, int port) {
|
||||||
|
Channel channel = null;
|
||||||
|
try {
|
||||||
|
channel = server.bind(ip, port).sync().channel();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error("Failed to bind to {}:{} -- {}", ip, port, e.getMessage());
|
||||||
|
}
|
||||||
|
if (channel == null) {
|
||||||
|
throw new IllegalStateException("Failed to bind to port:" + ip + ":" + port);
|
||||||
|
}
|
||||||
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
List<ChannelFuture> channelFutures = new ArrayList<>();
|
List<ChannelFuture> channelFutures = new ArrayList<>();
|
||||||
|
|
||||||
if (tcpChannelHandle != null) {
|
if (tcpChannelHandle != null) {
|
||||||
LOG.info("Closing tcpChannelHandle");
|
log.info("Closing tcpChannelHandle");
|
||||||
channelFutures.add(tcpChannelHandle.close());
|
channelFutures.add(tcpChannelHandle.close());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (httpChannelHandle != null) {
|
if (httpChannelHandle != null) {
|
||||||
LOG.info("Closing httpChannelHandle");
|
log.info("Closing httpChannelHandle");
|
||||||
channelFutures.add(httpChannelHandle.close());
|
channelFutures.add(httpChannelHandle.close());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wsChannelHandle != null) {
|
if (wsChannelHandle != null) {
|
||||||
LOG.info("Closing wsChannelHandle");
|
log.info("Closing wsChannelHandle");
|
||||||
channelFutures.add(wsChannelHandle.close());
|
channelFutures.add(wsChannelHandle.close());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int udpChannel = 1;
|
||||||
for (Channel c : udpChannelHandleList) {
|
for (Channel c : udpChannelHandleList) {
|
||||||
LOG.info("Closing udpChannelHandle");
|
log.info("Closing udpChannelHandle #" + udpChannel++);
|
||||||
channelFutures.add(c.close());
|
channelFutures.add(c.close());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,51 +334,49 @@ public class Balancer {
|
|||||||
try {
|
try {
|
||||||
f.get();
|
f.get();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
LOG.error("Error while shutting down channel: {}", f.channel().config());
|
log.error("Channel:" + f.channel().config() + " -> " + e.getMessage(), e);
|
||||||
LOG.error("{}", e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Integer quietPeriod = balancerConfig.getServer().getShutdownQuietPeriod();
|
|
||||||
List<Future<?>> groupFutures = new ArrayList<>();
|
List<Future<?>> groupFutures = new ArrayList<>();
|
||||||
|
|
||||||
if (tcpBossGroup != null) {
|
if (tcpBossGroup != null) {
|
||||||
LOG.info("Shutting down tcpBossGroup");
|
log.info("Shutting down tcpBossGroup");
|
||||||
groupFutures.add(tcpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
groupFutures.add(tcpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tcpWorkerGroup != null) {
|
if (tcpWorkerGroup != null) {
|
||||||
LOG.info("Shutting down tcpWorkerGroup");
|
log.info("Shutting down tcpWorkerGroup");
|
||||||
groupFutures.add(tcpWorkerGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
groupFutures.add(tcpWorkerGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (httpBossGroup != null) {
|
if (httpBossGroup != null) {
|
||||||
LOG.info("Shutting down httpBossGroup");
|
log.info("Shutting down httpBossGroup");
|
||||||
groupFutures.add(httpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
groupFutures.add(httpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (httpWorkerGroup != null) {
|
if (httpWorkerGroup != null) {
|
||||||
LOG.info("Shutting down httpWorkerGroup");
|
log.info("Shutting down httpWorkerGroup");
|
||||||
groupFutures.add(httpWorkerGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
groupFutures.add(httpWorkerGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wsBossGroup != null) {
|
if (wsBossGroup != null) {
|
||||||
LOG.info("Shutting down wsBossGroup");
|
log.info("Shutting down wsBossGroup");
|
||||||
groupFutures.add(wsBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
groupFutures.add(wsBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wsWorkerGroup != null) {
|
if (wsWorkerGroup != null) {
|
||||||
LOG.info("Shutting down wsWorkerGroup");
|
log.info("Shutting down wsWorkerGroup");
|
||||||
groupFutures.add(wsWorkerGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
groupFutures.add(wsWorkerGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (udpBossGroup != null) {
|
if (udpBossGroup != null) {
|
||||||
LOG.info("Shutting down udpBossGroup");
|
log.info("Shutting down udpBossGroup");
|
||||||
groupFutures.add(udpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
groupFutures.add(udpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (udpWorkerGroup != null) {
|
if (udpWorkerGroup != null) {
|
||||||
LOG.info("Shutting down udpWorkerGroup");
|
log.info("Shutting down udpWorkerGroup");
|
||||||
groupFutures.add(udpWorkerGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
groupFutures.add(udpWorkerGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,106 +384,17 @@ public class Balancer {
|
|||||||
try {
|
try {
|
||||||
f.get();
|
f.get();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
LOG.error("Error while shutting down group: {}", f.toString());
|
log.error("Group:" + f.toString() + " -> " + e.getMessage(), e);
|
||||||
LOG.error("{}", e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
LOG.info("Closing WebSocketRequestDecoder");
|
log.info("Closing WebSocketRequestDecoder");
|
||||||
WebSocketRequestDecoder.close();
|
WebSocketRequestDecoder.close();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error("Error closing WebSocketRequestDecoder during shutdown", e);
|
log.error("Error closing WebSocketRequestDecoder during shutdown", e);
|
||||||
}
|
}
|
||||||
|
log.info("{} shut down.", this.getClass().getSimpleName());
|
||||||
if (applicationContext != null) {
|
|
||||||
LOG.info("Closing applicationContext");
|
|
||||||
applicationContext.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (curatorFramework != null) {
|
|
||||||
curatorFramework.close();
|
|
||||||
}
|
|
||||||
this.shutdown = true;
|
|
||||||
LOG.info("Server shut down.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean useEpoll() {
|
|
||||||
|
|
||||||
// Should we just return true if this is Linux and if we get an error
|
|
||||||
// during Epoll
|
|
||||||
// setup handle it there?
|
|
||||||
final String os = SystemPropertyUtil.get(OS_NAME).toLowerCase().trim();
|
|
||||||
final String[] version = SystemPropertyUtil.get(OS_VERSION).toLowerCase().trim().split("\\.");
|
|
||||||
if (os.startsWith("linux") && version.length >= 3) {
|
|
||||||
final int major = Integer.parseInt(version[0]);
|
|
||||||
if (major > EPOLL_MIN_MAJOR_VERSION) {
|
|
||||||
return true;
|
|
||||||
} else if (major == EPOLL_MIN_MAJOR_VERSION) {
|
|
||||||
final int minor = Integer.parseInt(version[1]);
|
|
||||||
if (minor > EPOLL_MIN_MINOR_VERSION) {
|
|
||||||
return true;
|
|
||||||
} else if (minor == EPOLL_MIN_MINOR_VERSION) {
|
|
||||||
final int patch = Integer.parseInt(version[2].substring(0, 2));
|
|
||||||
return patch >= EPOLL_MIN_PATCH_VERSION;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected SslContext createSSLContext(BalancerConfiguration config) throws Exception {
|
|
||||||
|
|
||||||
ServerSsl sslCfg = config.getSecurity().getServerSsl();
|
|
||||||
Boolean generate = sslCfg.isUseGeneratedKeypair();
|
|
||||||
SslContextBuilder ssl;
|
|
||||||
if (generate) {
|
|
||||||
LOG.warn("Using generated self signed server certificate");
|
|
||||||
Date begin = new Date();
|
|
||||||
Date end = new Date(begin.getTime() + 86400000);
|
|
||||||
SelfSignedCertificate ssc = new SelfSignedCertificate("localhost", begin, end);
|
|
||||||
ssl = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey());
|
|
||||||
} else {
|
|
||||||
String cert = sslCfg.getCertificateFile();
|
|
||||||
String key = sslCfg.getKeyFile();
|
|
||||||
String keyPass = sslCfg.getKeyPassword();
|
|
||||||
if (null == cert || null == key) {
|
|
||||||
throw new IllegalArgumentException("Check your SSL properties, something is wrong.");
|
|
||||||
}
|
|
||||||
ssl = SslContextBuilder.forServer(new File(cert), new File(key), keyPass);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssl.ciphers(sslCfg.getUseCiphers());
|
|
||||||
|
|
||||||
// Can't set to REQUIRE because the CORS pre-flight requests will fail.
|
|
||||||
ssl.clientAuth(ClientAuth.OPTIONAL);
|
|
||||||
|
|
||||||
Boolean useOpenSSL = sslCfg.isUseOpenssl();
|
|
||||||
if (useOpenSSL) {
|
|
||||||
ssl.sslProvider(SslProvider.OPENSSL);
|
|
||||||
} else {
|
|
||||||
ssl.sslProvider(SslProvider.JDK);
|
|
||||||
}
|
|
||||||
String trustStore = sslCfg.getTrustStoreFile();
|
|
||||||
if (null != trustStore) {
|
|
||||||
if (!trustStore.isEmpty()) {
|
|
||||||
ssl.trustManager(new File(trustStore));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ssl.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected SSLContext createSSLClientContext(BalancerConfiguration config) throws Exception {
|
|
||||||
|
|
||||||
ClientSsl ssl = config.getSecurity().getClientSsl();
|
|
||||||
return HttpClient.getSSLContext(ssl.getTrustStoreFile(), ssl.getTrustStoreType(), ssl.getTrustStorePassword(),
|
|
||||||
ssl.getKeyFile(), ssl.getKeyType(), ssl.getKeyPassword());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureZkPaths(CuratorFramework curatorFramework, String[] paths) {
|
private void ensureZkPaths(CuratorFramework curatorFramework, String[] paths) {
|
||||||
@@ -347,182 +402,38 @@ public class Balancer {
|
|||||||
try {
|
try {
|
||||||
Stat stat = curatorFramework.checkExists().forPath(s);
|
Stat stat = curatorFramework.checkExists().forPath(s);
|
||||||
if (stat == null) {
|
if (stat == null) {
|
||||||
curatorFramework.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT)
|
curatorFramework.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT).forPath(s);
|
||||||
.forPath(s);
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.info(e.getMessage());
|
log.info(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() throws Exception {
|
protected ChannelHandler setupHttpChannel(BalancerHttpProperties balancerHttpProperties, SslServerProperties sslServerProperties, SslContext sslCtx,
|
||||||
|
MetricResolver metricResolver, HttpClientPool httpClientPool) {
|
||||||
// start curator framework
|
|
||||||
RetryPolicy retryPolicy = new RetryForever(1000);
|
|
||||||
int timeout = Long.valueOf(AccumuloConfiguration.getTimeInMillis(balancerConfig.getZooKeeper().getTimeout()))
|
|
||||||
.intValue();
|
|
||||||
curatorFramework = CuratorFrameworkFactory.newClient(balancerConfig.getZooKeeper().getServers(), timeout, 10000,
|
|
||||||
retryPolicy);
|
|
||||||
curatorFramework.start();
|
|
||||||
ensureZkPaths(curatorFramework, zkPaths);
|
|
||||||
|
|
||||||
AuthCache.configure(balancerConfig.getSecurity());
|
|
||||||
final boolean useEpoll = useEpoll();
|
|
||||||
Class<? extends ServerSocketChannel> channelClass;
|
|
||||||
Class<? extends Channel> datagramChannelClass;
|
|
||||||
if (useEpoll) {
|
|
||||||
tcpWorkerGroup = new EpollEventLoopGroup();
|
|
||||||
tcpBossGroup = new EpollEventLoopGroup();
|
|
||||||
httpWorkerGroup = new EpollEventLoopGroup();
|
|
||||||
httpBossGroup = new EpollEventLoopGroup();
|
|
||||||
wsWorkerGroup = new EpollEventLoopGroup();
|
|
||||||
wsBossGroup = new EpollEventLoopGroup();
|
|
||||||
udpWorkerGroup = new EpollEventLoopGroup();
|
|
||||||
udpBossGroup = new EpollEventLoopGroup();
|
|
||||||
channelClass = EpollServerSocketChannel.class;
|
|
||||||
datagramChannelClass = EpollDatagramChannel.class;
|
|
||||||
} else {
|
|
||||||
tcpWorkerGroup = new NioEventLoopGroup();
|
|
||||||
tcpBossGroup = new NioEventLoopGroup();
|
|
||||||
httpWorkerGroup = new NioEventLoopGroup();
|
|
||||||
httpBossGroup = new NioEventLoopGroup();
|
|
||||||
wsWorkerGroup = new NioEventLoopGroup();
|
|
||||||
wsBossGroup = new NioEventLoopGroup();
|
|
||||||
udpWorkerGroup = new NioEventLoopGroup();
|
|
||||||
udpBossGroup = new NioEventLoopGroup();
|
|
||||||
channelClass = NioServerSocketChannel.class;
|
|
||||||
datagramChannelClass = NioDatagramChannel.class;
|
|
||||||
}
|
|
||||||
LOG.info("Using channel class {}", channelClass.getSimpleName());
|
|
||||||
|
|
||||||
List<TcpClientPool> tcpClientPools = new ArrayList<>();
|
|
||||||
for (int x = 0; x < balancerConfig.getServer().getNumTcpPools(); x++) {
|
|
||||||
tcpClientPools.add(new TcpClientPool(this.balancerConfig));
|
|
||||||
}
|
|
||||||
HealthChecker healthChecker = new HealthChecker(this.balancerConfig, tcpClientPools.get(0));
|
|
||||||
this.metricResolver = new BalancedMetricResolver(curatorFramework, this.balancerConfig, healthChecker);
|
|
||||||
|
|
||||||
final ServerBootstrap tcpServer = new ServerBootstrap();
|
|
||||||
tcpServer.group(tcpBossGroup, tcpWorkerGroup);
|
|
||||||
tcpServer.channel(channelClass);
|
|
||||||
tcpServer.handler(new LoggingHandler());
|
|
||||||
tcpServer.childHandler(setupTcpChannel(metricResolver, tcpClientPools));
|
|
||||||
tcpServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
|
||||||
tcpServer.option(ChannelOption.SO_BACKLOG, 128);
|
|
||||||
tcpServer.option(ChannelOption.SO_KEEPALIVE, true);
|
|
||||||
final int tcpPort = balancerConfig.getServer().getTcpPort();
|
|
||||||
final String tcpIp = balancerConfig.getServer().getIp();
|
|
||||||
tcpChannelHandle = tcpServer.bind(tcpIp, tcpPort).sync().channel();
|
|
||||||
final String tcpAddress = ((InetSocketAddress) tcpChannelHandle.localAddress()).getAddress().getHostAddress();
|
|
||||||
|
|
||||||
final int httpPort = balancerConfig.getHttp().getPort();
|
|
||||||
final String httpIp = balancerConfig.getHttp().getIp();
|
|
||||||
SslContext sslCtx = createSSLContext(balancerConfig);
|
|
||||||
if (sslCtx instanceof OpenSslServerContext) {
|
|
||||||
OpenSslServerContext openssl = (OpenSslServerContext) sslCtx;
|
|
||||||
String application = "Timely_" + httpPort;
|
|
||||||
OpenSslServerSessionContext opensslCtx = openssl.sessionContext();
|
|
||||||
opensslCtx.setSessionCacheEnabled(true);
|
|
||||||
opensslCtx.setSessionCacheSize(128);
|
|
||||||
opensslCtx.setSessionIdContext(application.getBytes(StandardCharsets.UTF_8));
|
|
||||||
opensslCtx.setSessionTimeout(balancerConfig.getSecurity().getSessionMaxAge());
|
|
||||||
}
|
|
||||||
SSLContext clientSSLContext = createSSLClientContext(balancerConfig);
|
|
||||||
final ServerBootstrap httpServer = new ServerBootstrap();
|
|
||||||
httpServer.group(httpBossGroup, httpWorkerGroup);
|
|
||||||
httpServer.channel(channelClass);
|
|
||||||
httpServer.handler(new LoggingHandler());
|
|
||||||
HttpClientPool httpClientPool = new HttpClientPool(balancerConfig.getSecurity(), balancerConfig.getHttp(),
|
|
||||||
clientSSLContext);
|
|
||||||
httpServer.childHandler(setupHttpChannel(balancerConfig, sslCtx, metricResolver, httpClientPool));
|
|
||||||
httpServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
|
||||||
httpServer.option(ChannelOption.SO_BACKLOG, 128);
|
|
||||||
httpServer.option(ChannelOption.SO_KEEPALIVE, true);
|
|
||||||
httpChannelHandle = httpServer.bind(httpIp, httpPort).sync().channel();
|
|
||||||
final String httpAddress = ((InetSocketAddress) httpChannelHandle.localAddress()).getAddress().getHostAddress();
|
|
||||||
|
|
||||||
final int wsPort = balancerConfig.getWebsocket().getPort();
|
|
||||||
final String wsIp = balancerConfig.getWebsocket().getIp();
|
|
||||||
final ServerBootstrap wsServer = new ServerBootstrap();
|
|
||||||
wsServer.group(wsBossGroup, wsWorkerGroup);
|
|
||||||
wsServer.channel(channelClass);
|
|
||||||
wsServer.handler(new LoggingHandler());
|
|
||||||
WsClientPool wsClientPool = new WsClientPool(balancerConfig, clientSSLContext);
|
|
||||||
wsServer.childHandler(setupWSChannel(balancerConfig, sslCtx, metricResolver, wsClientPool));
|
|
||||||
wsServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
|
||||||
wsServer.option(ChannelOption.SO_BACKLOG, 128);
|
|
||||||
wsServer.option(ChannelOption.SO_KEEPALIVE, true);
|
|
||||||
/* Not sure if next two lines are necessary */
|
|
||||||
wsServer.option(ChannelOption.SO_SNDBUF, 1048576);
|
|
||||||
wsServer.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(620145, 838860));
|
|
||||||
wsChannelHandle = wsServer.bind(wsIp, wsPort).sync().channel();
|
|
||||||
final String wsAddress = ((InetSocketAddress) wsChannelHandle.localAddress()).getAddress().getHostAddress();
|
|
||||||
|
|
||||||
final int udpPort = balancerConfig.getServer().getUdpPort();
|
|
||||||
final String udpIp = balancerConfig.getServer().getIp();
|
|
||||||
UdpClientPool udpClientPool = new UdpClientPool(balancerConfig);
|
|
||||||
for (int n = 1; n < DEFAULT_EVENT_LOOP_THREADS; n++) {
|
|
||||||
final Bootstrap udpServer = new Bootstrap();
|
|
||||||
udpServer.group(udpBossGroup);
|
|
||||||
udpServer.channel(datagramChannelClass);
|
|
||||||
udpServer.handler(setupUdpChannel(metricResolver, udpClientPool));
|
|
||||||
udpServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
|
||||||
udpServer.option(EpollChannelOption.SO_REUSEADDR, true);
|
|
||||||
udpServer.option(EpollChannelOption.SO_REUSEPORT, true);
|
|
||||||
udpChannelHandleList.add(udpServer.bind(udpIp, udpPort).sync().channel());
|
|
||||||
}
|
|
||||||
shutdownHook();
|
|
||||||
LOG.info(
|
|
||||||
"Server started. Listening on {}:{} for TCP traffic, {}:{} for HTTP traffic, {}:{} for WebSocket traffic, and {}:{} for UDP traffic",
|
|
||||||
tcpAddress, tcpPort, httpAddress, httpPort, wsAddress, wsPort, wsAddress, udpPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
|
|
||||||
Balancer.applicationContext = Balancer.initializeConfiguration(args);
|
|
||||||
BalancerConfiguration balancerConf = applicationContext.getBean(BalancerConfiguration.class);
|
|
||||||
|
|
||||||
Balancer b = new Balancer(balancerConf);
|
|
||||||
try {
|
|
||||||
b.run();
|
|
||||||
LATCH.await();
|
|
||||||
} catch (final InterruptedException e) {
|
|
||||||
LOG.info("Server shutting down.");
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error("Error running server.", e);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
b.shutdown();
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ChannelHandler setupHttpChannel(BalancerConfiguration balancerConfig, SslContext sslCtx,
|
|
||||||
MetricResolver metricResolver, HttpClientPool httpClientPool) {
|
|
||||||
|
|
||||||
return new ChannelInitializer<SocketChannel>() {
|
return new ChannelInitializer<SocketChannel>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initChannel(SocketChannel ch) throws Exception {
|
protected void initChannel(SocketChannel ch) {
|
||||||
|
|
||||||
ch.pipeline().addLast("ssl", new NonSslRedirectHandler(balancerConfig.getHttp(), sslCtx));
|
ch.pipeline().addLast("nonsslforbidden", new NonSslForbiddenHandler(sslCtx));
|
||||||
ch.pipeline().addLast("encoder", new HttpResponseEncoder());
|
ch.pipeline().addLast("encoder", new HttpResponseEncoder());
|
||||||
ch.pipeline().addLast("decoder", new HttpRequestDecoder());
|
ch.pipeline().addLast("strict", new HttpStrictTransportSecurityHandler(balancerHttpProperties));
|
||||||
|
ch.pipeline().addLast("decoder", new HttpRequestDecoder(4096, 32768, 8192, true, 128));
|
||||||
ch.pipeline().addLast("compressor", new HttpContentCompressor());
|
ch.pipeline().addLast("compressor", new HttpContentCompressor());
|
||||||
ch.pipeline().addLast("decompressor", new HttpContentDecompressor());
|
ch.pipeline().addLast("decompressor", new HttpContentDecompressor());
|
||||||
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
|
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
|
||||||
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
|
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
|
||||||
ch.pipeline().addLast("queryDecoder", new timely.netty.http.HttpRequestDecoder(
|
ch.pipeline().addLast("queryDecoder",
|
||||||
balancerConfig.getSecurity(), balancerConfig.getHttp()));
|
new timely.netty.http.HttpRequestDecoder(authenticationService, securityProperties, balancerHttpProperties));
|
||||||
ch.pipeline().addLast("fileServer", new HttpStaticFileServerHandler());
|
ch.pipeline().addLast("notfound", new NotFoundHandler());
|
||||||
ch.pipeline().addLast("login",
|
ch.pipeline().addLast("login", new X509LoginRequestHandler(authenticationService, securityProperties, balancerHttpProperties));
|
||||||
new X509LoginRequestHandler(balancerConfig.getSecurity(), balancerConfig.getHttp()));
|
ch.pipeline().addLast("version", new HttpVersionRequestHandler());
|
||||||
ch.pipeline().addLast("httpRelay", new HttpRelayHandler(metricResolver, httpClientPool));
|
ch.pipeline().addLast("httpRelay", new HttpRelayHandler(balancerHttpProperties, metricResolver, httpClientPool));
|
||||||
ch.pipeline().addLast("error", new TimelyExceptionHandler());
|
ch.pipeline().addLast("error", new TimelyExceptionHandler().setIgnoreSslHandshakeErrors(sslServerProperties.isIgnoreSslHandshakeErrors()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -542,7 +453,7 @@ public class Balancer {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ChannelHandler setupTcpChannel(MetricResolver metricResolver, List<TcpClientPool> tcpClientPools) {
|
protected ChannelHandler setupTcpChannel(MetricResolver metricResolver, TcpClientPool tcpClientPool) {
|
||||||
return new ChannelInitializer<SocketChannel>() {
|
return new ChannelInitializer<SocketChannel>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -550,14 +461,14 @@ public class Balancer {
|
|||||||
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
|
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
|
||||||
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(65536, true, Delimiters.lineDelimiter()));
|
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(65536, true, Delimiters.lineDelimiter()));
|
||||||
ch.pipeline().addLast("putDecoder", new TcpDecoder());
|
ch.pipeline().addLast("putDecoder", new TcpDecoder());
|
||||||
ch.pipeline().addLast("tcpRelayHandler", new TcpRelayHandler(metricResolver, tcpClientPools));
|
ch.pipeline().addLast("tcpRelayHandler", new TcpRelayHandler(metricResolver, tcpClientPool));
|
||||||
ch.pipeline().addLast("versionHandler", new TcpVersionHandler());
|
ch.pipeline().addLast("versionHandler", new TcpVersionHandler());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ChannelHandler setupWSChannel(BalancerConfiguration balancerConfig, SslContext sslCtx,
|
protected ChannelHandler setupWSChannel(BalancerWebsocketProperties balancerWebsocketProperties, SecurityProperties securityProperties, SslContext sslCtx,
|
||||||
MetricResolver metricResolver, WsClientPool wsClientPool) {
|
MetricResolver metricResolver, WsClientPool wsClientPool) {
|
||||||
return new ChannelInitializer<SocketChannel>() {
|
return new ChannelInitializer<SocketChannel>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -565,14 +476,12 @@ public class Balancer {
|
|||||||
ch.pipeline().addLast("ssl", sslCtx.newHandler(ch.alloc()));
|
ch.pipeline().addLast("ssl", sslCtx.newHandler(ch.alloc()));
|
||||||
ch.pipeline().addLast("httpServer", new HttpServerCodec());
|
ch.pipeline().addLast("httpServer", new HttpServerCodec());
|
||||||
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
|
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
|
||||||
ch.pipeline().addLast("sessionExtractor", new WebSocketFullRequestHandler());
|
ch.pipeline().addLast("sessionExtractor", new WebSocketFullRequestHandler(authenticationService));
|
||||||
|
|
||||||
ch.pipeline().addLast("idle-handler",
|
ch.pipeline().addLast("idle-handler", new IdleStateHandler(balancerWebsocketProperties.getTimeout(), 0, 0));
|
||||||
new IdleStateHandler(balancerConfig.getWebsocket().getTimeout(), 0, 0));
|
ch.pipeline().addLast("ws-protocol", new WebSocketServerProtocolHandler(WS_PATH, null, true, 65536, false, true));
|
||||||
ch.pipeline().addLast("ws-protocol",
|
ch.pipeline().addLast("wsDecoder", new WebSocketRequestDecoder(authenticationService, securityProperties));
|
||||||
new WebSocketServerProtocolHandler(WS_PATH, null, true, 65536, false, true));
|
ch.pipeline().addLast("httpRelay", new WsRelayHandler(balancerWebsocketProperties, metricResolver, wsClientPool));
|
||||||
ch.pipeline().addLast("wsDecoder", new WebSocketRequestDecoder(balancerConfig.getSecurity()));
|
|
||||||
ch.pipeline().addLast("httpRelay", new WsRelayHandler(balancerConfig, metricResolver, wsClientPool));
|
|
||||||
ch.pipeline().addLast("error", new WSTimelyExceptionHandler());
|
ch.pipeline().addLast("error", new WSTimelyExceptionHandler());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package timely.balancer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import timely.balancer.configuration.BalancerProperties;
|
||||||
|
import timely.balancer.configuration.BalancerServerProperties;
|
||||||
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
import timely.balancer.connection.tcp.TcpClientPool;
|
||||||
|
import timely.balancer.healthcheck.TCPServerHealthCheck;
|
||||||
|
|
||||||
|
public class HealthChecker {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HealthChecker.class);
|
||||||
|
private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
|
||||||
|
private TCPServerHealthCheck tcpServerHealthCheck;
|
||||||
|
private BalancerProperties balancerProperties;
|
||||||
|
private BalancerServerProperties balancerServerProperties;
|
||||||
|
protected List<TimelyBalancedHost> timelyHosts = new ArrayList<>();
|
||||||
|
|
||||||
|
public HealthChecker(BalancerProperties balancerProperties, BalancerServerProperties balancerServerProperties) {
|
||||||
|
this.balancerProperties = balancerProperties;
|
||||||
|
this.balancerServerProperties = balancerServerProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
TcpClientPool tcpClientPool = new TcpClientPool(balancerServerProperties);
|
||||||
|
this.tcpServerHealthCheck = new TCPServerHealthCheck(tcpClientPool);
|
||||||
|
this.executorService.scheduleAtFixedRate(() -> {
|
||||||
|
synchronized (timelyHosts) {
|
||||||
|
for (TimelyBalancedHost h : timelyHosts) {
|
||||||
|
try {
|
||||||
|
if (tcpServerHealthCheck.isServerHealthy(h)) {
|
||||||
|
h.reportSuccess();
|
||||||
|
} else {
|
||||||
|
h.reportFailure();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
h.reportFailure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 0, balancerProperties.getCheckServerHealthInterval(), TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
this.executorService.shutdown();
|
||||||
|
try {
|
||||||
|
this.executorService.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (!this.executorService.isTerminated()) {
|
||||||
|
this.executorService.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimelyHosts(List<TimelyBalancedHost> timelyHosts) {
|
||||||
|
synchronized (timelyHosts) {
|
||||||
|
this.timelyHosts.clear();
|
||||||
|
this.timelyHosts.addAll(timelyHosts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+307
-227
@@ -1,12 +1,15 @@
|
|||||||
package timely.balancer.resolver;
|
package timely.balancer;
|
||||||
|
|
||||||
import static timely.Server.SERVICE_DISCOVERY_PATH;
|
import static org.apache.hadoop.fs.FileSystem.FS_DEFAULT_NAME_KEY;
|
||||||
|
import static timely.Constants.NON_CACHED_METRICS;
|
||||||
|
import static timely.Constants.NON_CACHED_METRICS_LOCK_PATH;
|
||||||
|
import static timely.Constants.SERVICE_DISCOVERY_PATH;
|
||||||
import static timely.balancer.Balancer.ASSIGNMENTS_LAST_UPDATED_PATH;
|
import static timely.balancer.Balancer.ASSIGNMENTS_LAST_UPDATED_PATH;
|
||||||
import static timely.balancer.Balancer.ASSIGNMENTS_LOCK_PATH;
|
import static timely.balancer.Balancer.ASSIGNMENTS_LOCK_PATH;
|
||||||
import static timely.balancer.Balancer.LEADER_LATCH_PATH;
|
import static timely.balancer.Balancer.LEADER_LATCH_PATH;
|
||||||
import static timely.store.cache.DataStoreCache.NON_CACHED_METRICS;
|
|
||||||
import static timely.store.cache.DataStoreCache.NON_CACHED_METRICS_LOCK_PATH;
|
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -19,19 +22,17 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
import com.csvreader.CsvReader;
|
|
||||||
import com.csvreader.CsvWriter;
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
import org.apache.commons.lang3.SerializationUtils;
|
import org.apache.commons.lang3.SerializationUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.curator.framework.CuratorFramework;
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
import org.apache.curator.framework.recipes.atomic.DistributedAtomicLong;
|
import org.apache.curator.framework.recipes.atomic.DistributedAtomicLong;
|
||||||
import org.apache.curator.framework.recipes.atomic.DistributedAtomicValue;
|
import org.apache.curator.framework.recipes.atomic.DistributedAtomicValue;
|
||||||
@@ -51,65 +52,79 @@ import org.apache.curator.x.discovery.details.ServiceCacheListener;
|
|||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.FSDataInputStream;
|
import org.apache.hadoop.fs.FSDataInputStream;
|
||||||
import org.apache.hadoop.fs.FSDataOutputStream;
|
import org.apache.hadoop.fs.FSDataOutputStream;
|
||||||
|
import org.apache.hadoop.fs.FileStatus;
|
||||||
import org.apache.hadoop.fs.FileSystem;
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
import org.apache.hadoop.fs.Path;
|
import org.apache.hadoop.fs.Path;
|
||||||
import org.apache.zookeeper.CreateMode;
|
import org.apache.zookeeper.CreateMode;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.csvreader.CsvReader;
|
||||||
|
import com.csvreader.CsvWriter;
|
||||||
|
|
||||||
import timely.ServerDetails;
|
import timely.ServerDetails;
|
||||||
import timely.balancer.ArrivalRate;
|
import timely.balancer.configuration.BalancerProperties;
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.balancer.healthcheck.HealthChecker;
|
import timely.common.configuration.CacheProperties;
|
||||||
|
|
||||||
public class BalancedMetricResolver implements MetricResolver {
|
public class MetricResolver {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(BalancedMetricResolver.class);
|
private static final Logger log = LoggerFactory.getLogger(MetricResolver.class);
|
||||||
private Map<String, TimelyBalancedHost> metricToHostMap = new TreeMap<>();
|
|
||||||
private Map<String, ArrivalRate> metricMap = new HashMap<>();
|
|
||||||
private ReentrantReadWriteLock balancerLock = new ReentrantReadWriteLock();
|
private ReentrantReadWriteLock balancerLock = new ReentrantReadWriteLock();
|
||||||
private List<TimelyBalancedHost> serverList = new ArrayList<>();
|
|
||||||
private Random r = new Random();
|
private Random r = new Random();
|
||||||
final private HealthChecker healthChecker;
|
private ScheduledExecutorService assignmentExecutor = Executors.newScheduledThreadPool(2);
|
||||||
private Timer timer = new Timer("RebalanceTimer", true);
|
private ScheduledExecutorService arrivalRateExecutor = Executors.newScheduledThreadPool(2);
|
||||||
private Timer arrivalRateTimer = new Timer("ArrivalRateTimerResolver", true);
|
|
||||||
private int roundRobinCounter = 0;
|
private int roundRobinCounter = 0;
|
||||||
private Set<String> nonCachedMetrics = new HashSet<>();
|
private Set<String> nonCachedMetrics = new HashSet<>();
|
||||||
private DistributedAtomicValue nonCachedMetricsIP;
|
private DistributedAtomicValue nonCachedMetricsIP;
|
||||||
private ReentrantReadWriteLock nonCachedMetricsLocalLock = new ReentrantReadWriteLock();
|
private ReentrantReadWriteLock nonCachedMetricsLocalLock = new ReentrantReadWriteLock();
|
||||||
private InterProcessReadWriteLock nonCachedMetricsIPRWLock;
|
private InterProcessReadWriteLock nonCachedMetricsIPRWLock;
|
||||||
private BalancerConfiguration balancerConfig;
|
|
||||||
private LeaderLatch leaderLatch;
|
private LeaderLatch leaderLatch;
|
||||||
private AtomicBoolean isLeader = new AtomicBoolean(false);
|
private AtomicBoolean isLeader = new AtomicBoolean(false);
|
||||||
private InterProcessReadWriteLock assignmentsIPRWLock;
|
private InterProcessReadWriteLock assignmentsIPRWLock;
|
||||||
private DistributedAtomicLong assignmentsLastUpdatedInHdfs;
|
private DistributedAtomicLong assignmentsLastUpdatedInHdfs;
|
||||||
private AtomicLong assignmentsLastUpdatedLocal = new AtomicLong(0);
|
private AtomicLong assignmentsLastUpdatedLocal = new AtomicLong(0);
|
||||||
|
protected List<TimelyBalancedHost> serverList = new ArrayList<>();
|
||||||
|
protected Map<String,TimelyBalancedHost> metricToHostMap = new TreeMap<>();
|
||||||
|
protected Map<String,ArrivalRate> metricMap = new HashMap<>();
|
||||||
|
final protected CuratorFramework curatorFramework;
|
||||||
|
final protected BalancerProperties balancerProperties;
|
||||||
|
final protected CacheProperties cacheProperties;
|
||||||
|
final protected HealthChecker healthChecker;
|
||||||
|
final protected Path assignmentFile;
|
||||||
|
final protected FileSystem fs;
|
||||||
|
|
||||||
private enum BalanceType {
|
private enum BalanceType {
|
||||||
HIGH_LOW, HIGH_AVG, AVG_LOW
|
HIGH_LOW, HIGH_AVG, AVG_LOW
|
||||||
}
|
}
|
||||||
|
|
||||||
public BalancedMetricResolver(CuratorFramework curatorFramework, BalancerConfiguration balancerConfig,
|
public MetricResolver(CuratorFramework curatorFramework, BalancerProperties balancerProperties, CacheProperties cacheProperties,
|
||||||
HealthChecker healthChecker) {
|
HealthChecker healthChecker) throws Exception {
|
||||||
this.balancerConfig = balancerConfig;
|
this.curatorFramework = curatorFramework;
|
||||||
|
this.balancerProperties = balancerProperties;
|
||||||
|
this.cacheProperties = cacheProperties;
|
||||||
this.healthChecker = healthChecker;
|
this.healthChecker = healthChecker;
|
||||||
|
this.assignmentFile = new Path(balancerProperties.getAssignmentFile());
|
||||||
|
this.fs = getFileSystem(this.assignmentFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
assignmentsIPRWLock = new InterProcessReadWriteLock(curatorFramework, ASSIGNMENTS_LOCK_PATH);
|
assignmentsIPRWLock = new InterProcessReadWriteLock(curatorFramework, ASSIGNMENTS_LOCK_PATH);
|
||||||
testIPRWLock(curatorFramework, assignmentsIPRWLock, ASSIGNMENTS_LOCK_PATH);
|
testIPRWLock(curatorFramework, assignmentsIPRWLock, ASSIGNMENTS_LOCK_PATH);
|
||||||
startLeaderLatch(curatorFramework);
|
startLeaderLatch(curatorFramework);
|
||||||
startServiceListener(curatorFramework);
|
startServiceListener(curatorFramework);
|
||||||
assignmentsLastUpdatedInHdfs = new DistributedAtomicLong(curatorFramework, ASSIGNMENTS_LAST_UPDATED_PATH,
|
assignmentsLastUpdatedInHdfs = new DistributedAtomicLong(curatorFramework, ASSIGNMENTS_LAST_UPDATED_PATH, new RetryForever(1000));
|
||||||
new RetryForever(1000));
|
try {
|
||||||
|
assignmentsLastUpdatedInHdfs.forceSet(getLastWrittenToHdfsTimestamp());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
TreeCacheListener assignmentListener = new TreeCacheListener() {
|
TreeCacheListener assignmentListener = (curframework, event) -> {
|
||||||
|
log.debug("Handling assignments event {}. assignmentsLastUpdatedInHdfs:{}", event.getType().toString(),
|
||||||
@Override
|
new Date(assignmentsLastUpdatedInHdfs.get().postValue()));
|
||||||
public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent event) throws Exception {
|
if (event.getType().equals(TreeCacheEvent.Type.NODE_UPDATED)) {
|
||||||
LOG.debug("Handling assignments event {}. assignmentsLastUpdatedInHdfs:{}", event.getType().toString(),
|
readAssignmentsFromHdfs(true);
|
||||||
new Date(assignmentsLastUpdatedInHdfs.get().postValue()));
|
|
||||||
if (event.getType().equals(TreeCacheEvent.Type.NODE_UPDATED)) {
|
|
||||||
readAssignmentsFromHdfs(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -117,20 +132,16 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
assignmentTreeCache.getListenable().addListener(assignmentListener);
|
assignmentTreeCache.getListenable().addListener(assignmentListener);
|
||||||
assignmentTreeCache.start();
|
assignmentTreeCache.start();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
nonCachedMetricsIPRWLock = new InterProcessReadWriteLock(curatorFramework, NON_CACHED_METRICS_LOCK_PATH);
|
nonCachedMetricsIPRWLock = new InterProcessReadWriteLock(curatorFramework, NON_CACHED_METRICS_LOCK_PATH);
|
||||||
testIPRWLock(curatorFramework, nonCachedMetricsIPRWLock, NON_CACHED_METRICS_LOCK_PATH);
|
testIPRWLock(curatorFramework, nonCachedMetricsIPRWLock, NON_CACHED_METRICS_LOCK_PATH);
|
||||||
nonCachedMetricsIP = new DistributedAtomicValue(curatorFramework, NON_CACHED_METRICS, new RetryForever(1000));
|
nonCachedMetricsIP = new DistributedAtomicValue(curatorFramework, NON_CACHED_METRICS, new RetryForever(1000));
|
||||||
TreeCacheListener nonCachedMetricsListener = new TreeCacheListener() {
|
TreeCacheListener nonCachedMetricsListener = (framework, event) -> {
|
||||||
|
if (event.getType().equals(TreeCacheEvent.Type.NODE_UPDATED)) {
|
||||||
@Override
|
log.debug("Handling nonCachedMetricsIP event {}", event.getType().toString());
|
||||||
public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent event) throws Exception {
|
readNonCachedMetricsIP();
|
||||||
if (event.getType().equals(TreeCacheEvent.Type.NODE_UPDATED)) {
|
|
||||||
LOG.debug("Handling nonCachedMetricsIP event {}", event.getType().toString());
|
|
||||||
readNonCachedMetricsIP();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -138,12 +149,12 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
nonCachedMetricsTreeCache.getListenable().addListener(nonCachedMetricsListener);
|
nonCachedMetricsTreeCache.getListenable().addListener(nonCachedMetricsListener);
|
||||||
nonCachedMetricsTreeCache.start();
|
nonCachedMetricsTreeCache.start();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
nonCachedMetricsLocalLock.writeLock().lock();
|
nonCachedMetricsLocalLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
addNonCachedMetrics(balancerConfig.getCache().getNonCachedMetrics());
|
addNonCachedMetrics(cacheProperties.getNonCachedMetrics());
|
||||||
} finally {
|
} finally {
|
||||||
nonCachedMetricsLocalLock.writeLock().unlock();
|
nonCachedMetricsLocalLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -151,45 +162,61 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
|
|
||||||
readAssignmentsFromHdfs(false);
|
readAssignmentsFromHdfs(false);
|
||||||
|
|
||||||
timer.schedule(new TimerTask() {
|
assignmentExecutor.scheduleAtFixedRate(() -> {
|
||||||
|
if (isLeader.get()) {
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (isLeader.get()) {
|
|
||||||
try {
|
|
||||||
balance();
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 900000, 900000);
|
|
||||||
|
|
||||||
timer.schedule(new TimerTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
try {
|
||||||
if (isLeader.get()) {
|
balance();
|
||||||
long lastLocalUpdate = assignmentsLastUpdatedLocal.get();
|
|
||||||
long lastHdfsUpdate = assignmentsLastUpdatedInHdfs.get().postValue();
|
|
||||||
if (lastLocalUpdate > lastHdfsUpdate) {
|
|
||||||
LOG.debug("Leader writing assignments to hdfs lastLocalUpdate ({}) > lastHdfsUpdate ({})",
|
|
||||||
new Date(lastLocalUpdate), new Date(lastHdfsUpdate));
|
|
||||||
writeAssignmentsToHdfs();
|
|
||||||
} else {
|
|
||||||
LOG.trace(
|
|
||||||
"Leader not writing assignments to hdfs lastLocalUpdate ({}) <= lastHdfsUpdate ({})",
|
|
||||||
new Date(lastLocalUpdate), new Date(lastHdfsUpdate));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
readAssignmentsFromHdfs(true);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 10000, 60000);
|
}, 15, 15, TimeUnit.MINUTES);
|
||||||
|
|
||||||
|
assignmentExecutor.scheduleAtFixedRate(() -> {
|
||||||
|
try {
|
||||||
|
if (isLeader.get()) {
|
||||||
|
long lastLocalUpdate = assignmentsLastUpdatedLocal.get();
|
||||||
|
long lastHdfsUpdate = assignmentsLastUpdatedInHdfs.get().postValue();
|
||||||
|
if (lastLocalUpdate > lastHdfsUpdate) {
|
||||||
|
log.debug("Leader writing assignments to hdfs lastLocalUpdate ({}) > lastHdfsUpdate ({})", new Date(lastLocalUpdate),
|
||||||
|
new Date(lastHdfsUpdate));
|
||||||
|
writeAssignmentsToHdfs();
|
||||||
|
} else {
|
||||||
|
log.trace("Leader not writing assignments to hdfs lastLocalUpdate ({}) <= lastHdfsUpdate ({})", new Date(lastLocalUpdate),
|
||||||
|
new Date(lastHdfsUpdate));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
readAssignmentsFromHdfs(true);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}, 10, 60, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
|
||||||
|
this.assignmentExecutor.shutdown();
|
||||||
|
try {
|
||||||
|
this.assignmentExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (!this.assignmentExecutor.isTerminated()) {
|
||||||
|
this.assignmentExecutor.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.arrivalRateExecutor.shutdown();
|
||||||
|
try {
|
||||||
|
this.arrivalRateExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (!this.arrivalRateExecutor.isTerminated()) {
|
||||||
|
this.arrivalRateExecutor.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readNonCachedMetricsIP() {
|
private void readNonCachedMetricsIP() {
|
||||||
@@ -203,34 +230,33 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
byte[] currentNonCachedMetricsDistributedBytes = nonCachedMetricsIP.get().postValue();
|
byte[] currentNonCachedMetricsDistributedBytes = nonCachedMetricsIP.get().postValue();
|
||||||
if (currentNonCachedMetricsDistributedBytes != null) {
|
if (currentNonCachedMetricsDistributedBytes != null) {
|
||||||
try {
|
try {
|
||||||
currentNonCachedMetricsDistributed = SerializationUtils
|
currentNonCachedMetricsDistributed = SerializationUtils.deserialize(currentNonCachedMetricsDistributedBytes);
|
||||||
.deserialize(currentNonCachedMetricsDistributedBytes);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
currentNonCachedMetricsDistributed = new TreeSet<>();
|
currentNonCachedMetricsDistributed = new TreeSet<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
nonCachedMetricsIPRWLock.readLock().release();
|
nonCachedMetricsIPRWLock.readLock().release();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nonCachedMetricsLocalLock.writeLock().lock();
|
nonCachedMetricsLocalLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
if (nonCachedMetrics.containsAll(currentNonCachedMetricsDistributed)) {
|
if (nonCachedMetrics.containsAll(currentNonCachedMetricsDistributed)) {
|
||||||
LOG.debug("local nonCachedMetrics already contains {}", currentNonCachedMetricsDistributed);
|
log.debug("local nonCachedMetrics already contains {}", currentNonCachedMetricsDistributed);
|
||||||
} else {
|
} else {
|
||||||
currentNonCachedMetricsDistributed.removeAll(nonCachedMetrics);
|
currentNonCachedMetricsDistributed.removeAll(nonCachedMetrics);
|
||||||
LOG.debug("Adding {} to local nonCachedMetrics", currentNonCachedMetricsDistributed);
|
log.debug("Adding {} to local nonCachedMetrics", currentNonCachedMetricsDistributed);
|
||||||
nonCachedMetrics.addAll(currentNonCachedMetricsDistributed);
|
nonCachedMetrics.addAll(currentNonCachedMetricsDistributed);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
} finally {
|
} finally {
|
||||||
nonCachedMetricsLocalLock.writeLock().unlock();
|
nonCachedMetricsLocalLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -245,26 +271,26 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void isLeader() {
|
public void isLeader() {
|
||||||
LOG.info("this balancer is the leader");
|
log.info("this balancer is the leader");
|
||||||
isLeader.set(true);
|
isLeader.set(true);
|
||||||
writeAssignmentsToHdfs();
|
writeAssignmentsToHdfs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notLeader() {
|
public void notLeader() {
|
||||||
LOG.info("this balancer is not the leader");
|
log.info("this balancer is not the leader");
|
||||||
isLeader.set(false);
|
isLeader.set(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startServiceListener(CuratorFramework curatorFramework) {
|
private void startServiceListener(CuratorFramework curatorFramework) {
|
||||||
try {
|
try {
|
||||||
ServiceDiscovery<ServerDetails> discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class)
|
ServiceDiscovery<ServerDetails> discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class).client(curatorFramework)
|
||||||
.client(curatorFramework).basePath(SERVICE_DISCOVERY_PATH).build();
|
.basePath(SERVICE_DISCOVERY_PATH).build();
|
||||||
discovery.start();
|
discovery.start();
|
||||||
Collection<ServiceInstance<ServerDetails>> instances = discovery.queryForInstances("timely-server");
|
Collection<ServiceInstance<ServerDetails>> instances = discovery.queryForInstances("timely-server");
|
||||||
|
|
||||||
@@ -272,11 +298,11 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
try {
|
try {
|
||||||
for (ServiceInstance<ServerDetails> si : instances) {
|
for (ServiceInstance<ServerDetails> si : instances) {
|
||||||
ServerDetails pl = si.getPayload();
|
ServerDetails pl = si.getPayload();
|
||||||
TimelyBalancedHost tbh = TimelyBalancedHost.of(pl.getHost(), pl.getTcpPort(), pl.getHttpPort(),
|
TimelyBalancedHost tbh = TimelyBalancedHost.of(pl.getHost(), pl.getTcpPort(), pl.getHttpPort(), pl.getWsPort(), pl.getUdpPort(),
|
||||||
pl.getWsPort(), pl.getUdpPort());
|
new ArrivalRate(arrivalRateExecutor));
|
||||||
LOG.info("adding service {} host:{} tcpPort:{} httpPort:{} wsPort:{} udpPort:{}", si.getId(),
|
log.info("adding service {} host:{} tcpPort:{} httpPort:{} wsPort:{} udpPort:{}", si.getId(), pl.getHost(), pl.getTcpPort(),
|
||||||
pl.getHost(), pl.getTcpPort(), pl.getHttpPort(), pl.getWsPort(), pl.getUdpPort());
|
pl.getHttpPort(), pl.getWsPort(), pl.getUdpPort());
|
||||||
tbh.setBalancerConfig(balancerConfig);
|
tbh.setBalancerProperties(balancerProperties);
|
||||||
serverList.add(tbh);
|
serverList.add(tbh);
|
||||||
}
|
}
|
||||||
healthChecker.setTimelyHosts(serverList);
|
healthChecker.setTimelyHosts(serverList);
|
||||||
@@ -284,8 +310,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
balancerLock.writeLock().unlock();
|
balancerLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
final ServiceCache<ServerDetails> serviceCache = discovery.serviceCacheBuilder().name("timely-server")
|
final ServiceCache<ServerDetails> serviceCache = discovery.serviceCacheBuilder().name("timely-server").build();
|
||||||
.build();
|
|
||||||
ServiceCacheListener listener = new ServiceCacheListener() {
|
ServiceCacheListener listener = new ServiceCacheListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -296,10 +321,10 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
List<ServiceInstance<ServerDetails>> instances = serviceCache.getInstances();
|
List<ServiceInstance<ServerDetails>> instances = serviceCache.getInstances();
|
||||||
Set<TimelyBalancedHost> availableHosts = new HashSet<>();
|
Set<TimelyBalancedHost> availableHosts = new HashSet<>();
|
||||||
for (ServiceInstance<ServerDetails> si : instances) {
|
for (ServiceInstance<ServerDetails> si : instances) {
|
||||||
ServerDetails pl = (ServerDetails) si.getPayload();
|
ServerDetails pl = si.getPayload();
|
||||||
TimelyBalancedHost tbh = TimelyBalancedHost.of(pl.getHost(), pl.getTcpPort(),
|
TimelyBalancedHost tbh = TimelyBalancedHost.of(pl.getHost(), pl.getTcpPort(), pl.getHttpPort(), pl.getWsPort(), pl.getUdpPort(),
|
||||||
pl.getHttpPort(), pl.getWsPort(), pl.getUdpPort());
|
new ArrivalRate(arrivalRateExecutor));
|
||||||
tbh.setBalancerConfig(balancerConfig);
|
tbh.setBalancerProperties(balancerProperties);
|
||||||
availableHosts.add(tbh);
|
availableHosts.add(tbh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,10 +337,9 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
availableHosts.remove(h);
|
availableHosts.remove(h);
|
||||||
} else {
|
} else {
|
||||||
itr.remove();
|
itr.remove();
|
||||||
LOG.info("removing service {}:{} host:{} tcpPort:{} httpPort:{} wsPort:{} udpPort:{}",
|
log.info("removing service {}:{} host:{} tcpPort:{} httpPort:{} wsPort:{} udpPort:{}", h.getHost(), h.getTcpPort(), h.getHost(),
|
||||||
h.getHost(), h.getTcpPort(), h.getHost(), h.getTcpPort(), h.getHttpPort(),
|
h.getTcpPort(), h.getHttpPort(), h.getWsPort(), h.getUdpPort());
|
||||||
h.getWsPort(), h.getUdpPort());
|
for (Map.Entry<String,TimelyBalancedHost> e : metricToHostMap.entrySet()) {
|
||||||
for (Map.Entry<String, TimelyBalancedHost> e : metricToHostMap.entrySet()) {
|
|
||||||
if (e.getValue().equals(h)) {
|
if (e.getValue().equals(h)) {
|
||||||
reassignMetrics.add(e.getKey());
|
reassignMetrics.add(e.getKey());
|
||||||
}
|
}
|
||||||
@@ -326,9 +350,8 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
|
|
||||||
// add new hosts that were not previously known
|
// add new hosts that were not previously known
|
||||||
for (TimelyBalancedHost h : availableHosts) {
|
for (TimelyBalancedHost h : availableHosts) {
|
||||||
LOG.info("adding service {}:{} host:{} tcpPort:{} httpPort:{} wsPort:{} udpPort:{}",
|
log.info("adding service {}:{} host:{} tcpPort:{} httpPort:{} wsPort:{} udpPort:{}", h.getHost(), h.getTcpPort(), h.getHost(),
|
||||||
h.getHost(), h.getTcpPort(), h.getHost(), h.getTcpPort(), h.getHttpPort(),
|
h.getTcpPort(), h.getHttpPort(), h.getWsPort(), h.getUdpPort());
|
||||||
h.getWsPort(), h.getUdpPort());
|
|
||||||
serverList.add(h);
|
serverList.add(h);
|
||||||
rebalanceNeeded = true;
|
rebalanceNeeded = true;
|
||||||
}
|
}
|
||||||
@@ -337,8 +360,13 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
if (isLeader.get()) {
|
if (isLeader.get()) {
|
||||||
for (String s : reassignMetrics) {
|
for (String s : reassignMetrics) {
|
||||||
TimelyBalancedHost h = getRoundRobinHost(null);
|
TimelyBalancedHost h = getRoundRobinHost(null);
|
||||||
assignMetric(s, h);
|
if (h == null) {
|
||||||
LOG.debug("Assigned server removed. Assigning {} to server {}:{}", s, h.getTcpPort());
|
unassignMetric(s);
|
||||||
|
log.debug("Assigned server removed and none available. Unassigning {}", s);
|
||||||
|
} else {
|
||||||
|
assignMetric(s, h);
|
||||||
|
log.debug("Assigned server removed. Assigning {} to server {}:{}", s, h.getTcpPort());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,14 +383,14 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) {
|
public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) {
|
||||||
LOG.info("serviceCache state changed. Connected:{}", connectionState.isConnected());
|
log.info("serviceCache state changed. Connected:{}", connectionState.isConnected());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
serviceCache.addListener(listener);
|
serviceCache.addListener(listener);
|
||||||
serviceCache.start();
|
serviceCache.start();
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,12 +399,12 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
TimelyBalancedHost tbh = null;
|
TimelyBalancedHost tbh = null;
|
||||||
balancerLock.readLock().lock();
|
balancerLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
Map<Double, TimelyBalancedHost> rateSortedHosts = new TreeMap<>();
|
Map<Double,TimelyBalancedHost> rateSortedHosts = new TreeMap<>();
|
||||||
for (TimelyBalancedHost s : serverList) {
|
for (TimelyBalancedHost s : serverList) {
|
||||||
rateSortedHosts.put(s.getArrivalRate(), s);
|
rateSortedHosts.put(s.getArrivalRate(), s);
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<Map.Entry<Double, TimelyBalancedHost>> itr = rateSortedHosts.entrySet().iterator();
|
Iterator<Map.Entry<Double,TimelyBalancedHost>> itr = rateSortedHosts.entrySet().iterator();
|
||||||
|
|
||||||
while (itr.hasNext() && tbh == null) {
|
while (itr.hasNext() && tbh == null) {
|
||||||
TimelyBalancedHost currentTBH = itr.next().getValue();
|
TimelyBalancedHost currentTBH = itr.next().getValue();
|
||||||
@@ -441,11 +469,11 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
return tbh;
|
return tbh;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimelyBalancedHost chooseHost(Set<TimelyBalancedHost> potentialHosts,
|
private TimelyBalancedHost chooseHost(Set<TimelyBalancedHost> potentialHosts, Map<TimelyBalancedHost,Double> calculatedRates, double referenceRate,
|
||||||
Map<TimelyBalancedHost, Double> calculatedRates, double referenceRate, BalanceType balanceType) {
|
BalanceType balanceType) {
|
||||||
|
|
||||||
TimelyBalancedHost tbh = null;
|
TimelyBalancedHost tbh = null;
|
||||||
Map<Long, TimelyBalancedHost> weightedList = new TreeMap<>();
|
Map<Long,TimelyBalancedHost> weightedList = new TreeMap<>();
|
||||||
long cumulativeWeight = 0;
|
long cumulativeWeight = 0;
|
||||||
for (TimelyBalancedHost h : potentialHosts) {
|
for (TimelyBalancedHost h : potentialHosts) {
|
||||||
double currentDiff;
|
double currentDiff;
|
||||||
@@ -460,7 +488,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
|
|
||||||
if (cumulativeWeight > 0) {
|
if (cumulativeWeight > 0) {
|
||||||
long randomWeight = r.nextLong() % cumulativeWeight;
|
long randomWeight = r.nextLong() % cumulativeWeight;
|
||||||
for (Map.Entry<Long, TimelyBalancedHost> e : weightedList.entrySet()) {
|
for (Map.Entry<Long,TimelyBalancedHost> e : weightedList.entrySet()) {
|
||||||
if (randomWeight <= e.getKey()) {
|
if (randomWeight <= e.getKey()) {
|
||||||
tbh = e.getValue();
|
tbh = e.getValue();
|
||||||
break;
|
break;
|
||||||
@@ -474,10 +502,10 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
|
|
||||||
int numReassigned = 0;
|
int numReassigned = 0;
|
||||||
if (isLeader.get()) {
|
if (isLeader.get()) {
|
||||||
double controlBandPercentage = balancerConfig.getControlBandPercentage();
|
double controlBandPercentage = balancerProperties.getControlBandPercentage();
|
||||||
// save current rates so that we can modify
|
// save current rates so that we can modify
|
||||||
double totalArrivalRate = 0;
|
double totalArrivalRate = 0;
|
||||||
Map<TimelyBalancedHost, Double> calculatedRates = new HashMap<>();
|
Map<TimelyBalancedHost,Double> calculatedRates = new HashMap<>();
|
||||||
for (TimelyBalancedHost h : serverList) {
|
for (TimelyBalancedHost h : serverList) {
|
||||||
double tbhArrivalRate = h.getArrivalRate();
|
double tbhArrivalRate = h.getArrivalRate();
|
||||||
calculatedRates.put(h, tbhArrivalRate);
|
calculatedRates.put(h, tbhArrivalRate);
|
||||||
@@ -506,34 +534,32 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (highHosts.isEmpty() && lowHosts.isEmpty()) {
|
if (highHosts.isEmpty() && lowHosts.isEmpty()) {
|
||||||
LOG.debug("Host's arrival rates are within {} of the average", controlBandPercentage);
|
log.debug("Host's arrival rates are within {} of the average", controlBandPercentage);
|
||||||
} else if (!highHosts.isEmpty() && !lowHosts.isEmpty()) {
|
} else if (!highHosts.isEmpty() && !lowHosts.isEmpty()) {
|
||||||
LOG.debug("begin rebalancing {}", BalanceType.HIGH_LOW);
|
log.debug("begin rebalancing {}", BalanceType.HIGH_LOW);
|
||||||
numReassigned = rebalance(highHosts, lowHosts, calculatedRates, averageArrivalRate,
|
numReassigned = rebalance(highHosts, lowHosts, calculatedRates, averageArrivalRate, BalanceType.HIGH_LOW);
|
||||||
BalanceType.HIGH_LOW);
|
log.debug("end rebalancing {} - reassigned {}", BalanceType.HIGH_LOW, numReassigned);
|
||||||
LOG.debug("end rebalancing {} - reassigned {}", BalanceType.HIGH_LOW, numReassigned);
|
|
||||||
} else if (lowHosts.isEmpty()) {
|
} else if (lowHosts.isEmpty()) {
|
||||||
LOG.debug("begin rebalancing {}", BalanceType.HIGH_AVG);
|
log.debug("begin rebalancing {}", BalanceType.HIGH_AVG);
|
||||||
numReassigned = rebalance(highHosts, avgHosts, calculatedRates, averageArrivalRate,
|
numReassigned = rebalance(highHosts, avgHosts, calculatedRates, averageArrivalRate, BalanceType.HIGH_AVG);
|
||||||
BalanceType.HIGH_AVG);
|
log.debug("end rebalancing {} - reassigned {}", BalanceType.HIGH_AVG, numReassigned);
|
||||||
LOG.debug("end rebalancing {} - reassigned {}", BalanceType.HIGH_AVG, numReassigned);
|
|
||||||
} else {
|
} else {
|
||||||
LOG.debug("begin rebalancing {}", BalanceType.AVG_LOW);
|
log.debug("begin rebalancing {}", BalanceType.AVG_LOW);
|
||||||
numReassigned = rebalance(avgHosts, lowHosts, calculatedRates, averageArrivalRate, BalanceType.AVG_LOW);
|
numReassigned = rebalance(avgHosts, lowHosts, calculatedRates, averageArrivalRate, BalanceType.AVG_LOW);
|
||||||
LOG.debug("end rebalancing {} - reassigned {}", BalanceType.AVG_LOW, numReassigned);
|
log.debug("end rebalancing {} - reassigned {}", BalanceType.AVG_LOW, numReassigned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return numReassigned;
|
return numReassigned;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int rebalance(Set<TimelyBalancedHost> losingHosts, Set<TimelyBalancedHost> gainingHosts,
|
public int rebalance(Set<TimelyBalancedHost> losingHosts, Set<TimelyBalancedHost> gainingHosts, Map<TimelyBalancedHost,Double> calculatedRates,
|
||||||
Map<TimelyBalancedHost, Double> calculatedRates, double targetArrivalRate, BalanceType balanceType) {
|
double targetArrivalRate, BalanceType balanceType) {
|
||||||
|
|
||||||
int numReassigned = 0;
|
int numReassigned = 0;
|
||||||
if (isLeader.get()) {
|
if (isLeader.get()) {
|
||||||
balancerLock.writeLock().lock();
|
balancerLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
Map<String, ArrivalRate> tempMetricMap = new HashMap<>();
|
Map<String,ArrivalRate> tempMetricMap = new HashMap<>();
|
||||||
tempMetricMap.putAll(metricMap);
|
tempMetricMap.putAll(metricMap);
|
||||||
|
|
||||||
Set<TimelyBalancedHost> focusedHosts;
|
Set<TimelyBalancedHost> focusedHosts;
|
||||||
@@ -555,39 +581,39 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sort metrics by rate
|
// sort metrics by rate
|
||||||
Map<Double, String> rateSortedMetrics = new TreeMap<>(Collections.reverseOrder());
|
Map<Double,String> rateSortedMetrics = new TreeMap<>(Collections.reverseOrder());
|
||||||
for (Map.Entry<String, ArrivalRate> e : tempMetricMap.entrySet()) {
|
for (Map.Entry<String,ArrivalRate> e : tempMetricMap.entrySet()) {
|
||||||
if (metricToHostMap.get(e.getKey()).equals(h)) {
|
TimelyBalancedHost tbh = metricToHostMap.get(e.getKey());
|
||||||
|
if (tbh != null && tbh.equals(h)) {
|
||||||
rateSortedMetrics.put(e.getValue().getRate(), e.getKey());
|
rateSortedMetrics.put(e.getValue().getRate(), e.getKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.trace("focusHost {}:{} desiredChange:{} rateSortedMetrics.size():{}", h.getHost(),
|
log.trace("focusHost {}:{} desiredChange:{} rateSortedMetrics.size():{}", h.getHost(), h.getTcpPort(), desiredChange,
|
||||||
h.getTcpPort(), desiredChange, rateSortedMetrics.size());
|
rateSortedMetrics.size());
|
||||||
|
|
||||||
boolean doneWithHost = false;
|
boolean doneWithHost = false;
|
||||||
while (!doneWithHost) {
|
while (!doneWithHost) {
|
||||||
Iterator<Map.Entry<Double, String>> itr = rateSortedMetrics.entrySet().iterator();
|
Iterator<Map.Entry<Double,String>> itr = rateSortedMetrics.entrySet().iterator();
|
||||||
while (!doneWithHost && itr.hasNext()) {
|
while (!doneWithHost && itr.hasNext()) {
|
||||||
Map.Entry<Double, String> e = null;
|
Map.Entry<Double,String> e = null;
|
||||||
// find largest metric that does not exceed desired change
|
// find largest metric that does not exceed desired change
|
||||||
while (e == null && itr.hasNext()) {
|
while (e == null && itr.hasNext()) {
|
||||||
e = itr.next();
|
e = itr.next();
|
||||||
if (e.getKey() > desiredChange) {
|
if (e.getKey() > desiredChange) {
|
||||||
LOG.trace("Skipping:{} rate:{}", e.getValue(), e.getKey());
|
log.trace("Skipping:{} rate:{}", e.getValue(), e.getKey());
|
||||||
e = null;
|
e = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e == null) {
|
if (e == null) {
|
||||||
LOG.trace("no metric small enough");
|
log.trace("no metric small enough");
|
||||||
doneWithHost = true;
|
doneWithHost = true;
|
||||||
} else {
|
} else {
|
||||||
LOG.trace("Selected:{} rate:{}", e.getValue(), e.getKey());
|
log.trace("Selected:{} rate:{}", e.getValue(), e.getKey());
|
||||||
TimelyBalancedHost candidateHost = chooseHost(selectFromHosts, calculatedRates,
|
TimelyBalancedHost candidateHost = chooseHost(selectFromHosts, calculatedRates, calculatedRates.get(h), balanceType);
|
||||||
calculatedRates.get(h), balanceType);
|
|
||||||
if (candidateHost == null) {
|
if (candidateHost == null) {
|
||||||
LOG.trace("candidate host is null");
|
log.trace("candidate host is null");
|
||||||
doneWithHost = true;
|
doneWithHost = true;
|
||||||
} else {
|
} else {
|
||||||
String metric = e.getValue();
|
String metric = e.getValue();
|
||||||
@@ -600,26 +626,24 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
// don't move this metric again this host or balance
|
// don't move this metric again this host or balance
|
||||||
itr.remove();
|
itr.remove();
|
||||||
tempMetricMap.remove(metric);
|
tempMetricMap.remove(metric);
|
||||||
LOG.info(
|
log.info("rebalancing: reassigning metric:{} rate:{} from server {}:{} to {}:{} remaining delta {}", metric, metricRate,
|
||||||
"rebalancing: reassigning metric:{} rate:{} from server {}:{} to {}:{} remaining delta {}",
|
h.getHost(), h.getTcpPort(), candidateHost.getHost(), candidateHost.getTcpPort(), desiredChange);
|
||||||
metric, metricRate, h.getHost(), h.getTcpPort(), candidateHost.getHost(),
|
|
||||||
candidateHost.getTcpPort(), desiredChange);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!itr.hasNext()) {
|
if (!itr.hasNext()) {
|
||||||
LOG.trace("Reached end or rateSortedMetrics");
|
log.trace("Reached end or rateSortedMetrics");
|
||||||
doneWithHost = true;
|
doneWithHost = true;
|
||||||
}
|
}
|
||||||
if (balanceType.equals(BalanceType.HIGH_LOW) || balanceType.equals(BalanceType.HIGH_AVG)) {
|
if (balanceType.equals(BalanceType.HIGH_LOW) || balanceType.equals(BalanceType.HIGH_AVG)) {
|
||||||
if (calculatedRates.get(h) <= targetArrivalRate) {
|
if (calculatedRates.get(h) <= targetArrivalRate) {
|
||||||
doneWithHost = true;
|
doneWithHost = true;
|
||||||
LOG.trace("calculatedRates.get(h) <= targetArivalRate");
|
log.trace("calculatedRates.get(h) <= targetArivalRate");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (calculatedRates.get(h) >= targetArrivalRate) {
|
if (calculatedRates.get(h) >= targetArrivalRate) {
|
||||||
doneWithHost = true;
|
doneWithHost = true;
|
||||||
LOG.trace("calculatedRates.get(h) >= targetArivalRate");
|
log.trace("calculatedRates.get(h) >= targetArivalRate");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -634,7 +658,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
private void addNonCachedMetrics(Collection<String> nonCachedMetricsUpdate) {
|
private void addNonCachedMetrics(Collection<String> nonCachedMetricsUpdate) {
|
||||||
if (!nonCachedMetricsUpdate.isEmpty()) {
|
if (!nonCachedMetricsUpdate.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
LOG.debug("Adding {} to local nonCachedMetrics", nonCachedMetricsUpdate);
|
log.debug("Adding {} to local nonCachedMetrics", nonCachedMetricsUpdate);
|
||||||
nonCachedMetricsLocalLock.writeLock().lock();
|
nonCachedMetricsLocalLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
nonCachedMetrics.addAll(nonCachedMetricsUpdate);
|
nonCachedMetrics.addAll(nonCachedMetricsUpdate);
|
||||||
@@ -652,14 +676,13 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
if (currentNonCachedMetricsDistributedBytes == null) {
|
if (currentNonCachedMetricsDistributedBytes == null) {
|
||||||
currentNonCachedMetricsIP = new TreeSet<>();
|
currentNonCachedMetricsIP = new TreeSet<>();
|
||||||
} else {
|
} else {
|
||||||
currentNonCachedMetricsIP = SerializationUtils
|
currentNonCachedMetricsIP = SerializationUtils.deserialize(currentNonCachedMetricsDistributedBytes);
|
||||||
.deserialize(currentNonCachedMetricsDistributedBytes);
|
|
||||||
}
|
}
|
||||||
if (currentNonCachedMetricsIP.containsAll(nonCachedMetricsUpdate)) {
|
if (currentNonCachedMetricsIP.containsAll(nonCachedMetricsUpdate)) {
|
||||||
LOG.debug("nonCachedMetricsIP already contains {}", nonCachedMetricsUpdate);
|
log.debug("nonCachedMetricsIP already contains {}", nonCachedMetricsUpdate);
|
||||||
} else {
|
} else {
|
||||||
nonCachedMetricsUpdate.removeAll(currentNonCachedMetricsIP);
|
nonCachedMetricsUpdate.removeAll(currentNonCachedMetricsIP);
|
||||||
LOG.debug("Adding {} to nonCachedMetricsIP", nonCachedMetricsUpdate);
|
log.debug("Adding {} to nonCachedMetricsIP", nonCachedMetricsUpdate);
|
||||||
TreeSet<String> updateSet = new TreeSet<>();
|
TreeSet<String> updateSet = new TreeSet<>();
|
||||||
updateSet.addAll(currentNonCachedMetricsIP);
|
updateSet.addAll(currentNonCachedMetricsIP);
|
||||||
updateSet.addAll(nonCachedMetricsUpdate);
|
updateSet.addAll(nonCachedMetricsUpdate);
|
||||||
@@ -673,7 +696,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
nonCachedMetricsIPRWLock.writeLock().release();
|
nonCachedMetricsIPRWLock.writeLock().release();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -684,16 +707,15 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
} catch (Exception e1) {
|
} catch (Exception e1) {
|
||||||
try {
|
try {
|
||||||
curatorFramework.delete().deletingChildrenIfNeeded().forPath(path);
|
curatorFramework.delete().deletingChildrenIfNeeded().forPath(path);
|
||||||
curatorFramework.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT)
|
curatorFramework.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path);
|
||||||
.forPath(path);
|
|
||||||
} catch (Exception e2) {
|
} catch (Exception e2) {
|
||||||
LOG.info(e2.getMessage(), e2);
|
log.info(e2.getMessage(), e2);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
lock.writeLock().release();
|
lock.writeLock().release();
|
||||||
} catch (Exception e3) {
|
} catch (Exception e3) {
|
||||||
LOG.error(e3.getMessage(), e3);
|
log.error(e3.getMessage(), e3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -724,7 +746,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
try {
|
try {
|
||||||
for (String r : nonCachedMetrics) {
|
for (String r : nonCachedMetrics) {
|
||||||
if (metricName.matches(r)) {
|
if (metricName.matches(r)) {
|
||||||
LOG.debug("Adding {} to list of non-cached metrics", metricName);
|
log.debug("Adding {} to list of non-cached metrics", metricName);
|
||||||
addNonCachedMetrics(Collections.singleton(metricName));
|
addNonCachedMetrics(Collections.singleton(metricName));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -736,7 +758,6 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TimelyBalancedHost getHostPortKeyIngest(String metric) {
|
public TimelyBalancedHost getHostPortKeyIngest(String metric) {
|
||||||
|
|
||||||
TimelyBalancedHost tbh = null;
|
TimelyBalancedHost tbh = null;
|
||||||
@@ -744,18 +765,26 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
boolean chooseMetricSpecificHost;
|
boolean chooseMetricSpecificHost;
|
||||||
try {
|
try {
|
||||||
chooseMetricSpecificHost = shouldCache(metric) ? true : false;
|
chooseMetricSpecificHost = shouldCache(metric) ? true : false;
|
||||||
|
ArrivalRate rate = metricMap.get(metric);
|
||||||
|
if ((chooseMetricSpecificHost && rate == null) || (!chooseMetricSpecificHost && rate != null)) {
|
||||||
|
if (!balancerLock.isWriteLockedByCurrentThread()) {
|
||||||
|
balancerLock.readLock().unlock();
|
||||||
|
balancerLock.writeLock().lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (chooseMetricSpecificHost) {
|
if (chooseMetricSpecificHost) {
|
||||||
ArrivalRate rate = metricMap.get(metric);
|
|
||||||
if (rate == null) {
|
if (rate == null) {
|
||||||
rate = new ArrivalRate(arrivalRateTimer);
|
rate = new ArrivalRate(arrivalRateExecutor);
|
||||||
if (!balancerLock.isWriteLockedByCurrentThread()) {
|
// already write locked above
|
||||||
balancerLock.readLock().unlock();
|
|
||||||
balancerLock.writeLock().lock();
|
|
||||||
}
|
|
||||||
metricMap.put(metric, rate);
|
metricMap.put(metric, rate);
|
||||||
}
|
}
|
||||||
rate.arrived();
|
rate.arrived();
|
||||||
} else {
|
} else {
|
||||||
|
if (rate != null) {
|
||||||
|
// already write locked above
|
||||||
|
metricMap.remove(metric);
|
||||||
|
}
|
||||||
metric = null;
|
metric = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -765,20 +794,19 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
tbh = metricToHostMap.get(metric);
|
tbh = metricToHostMap.get(metric);
|
||||||
if (tbh == null) {
|
if (tbh == null) {
|
||||||
tbh = getRoundRobinHost(null);
|
tbh = getRoundRobinHost(null);
|
||||||
if (!balancerLock.isWriteLockedByCurrentThread()) {
|
|
||||||
balancerLock.readLock().unlock();
|
|
||||||
balancerLock.writeLock().lock();
|
|
||||||
}
|
|
||||||
assignMetric(metric, tbh);
|
|
||||||
} else if (!tbh.isUp()) {
|
} else if (!tbh.isUp()) {
|
||||||
TimelyBalancedHost oldTbh = tbh;
|
TimelyBalancedHost oldTbh = tbh;
|
||||||
tbh = getLeastUsedHost();
|
tbh = getLeastUsedHost();
|
||||||
LOG.debug("rebalancing from host that is down: reassigning metric {} from server {}:{} to {}:{}",
|
if (tbh != null) {
|
||||||
metric, oldTbh.getHost(), oldTbh.getTcpPort(), tbh.getHost(), tbh.getTcpPort());
|
log.debug("rebalancing from host that is down: reassigning metric {} from server {}:{} to {}:{}", metric, oldTbh.getHost(),
|
||||||
if (!balancerLock.isWriteLockedByCurrentThread()) {
|
oldTbh.getTcpPort(), tbh.getHost(), tbh.getTcpPort());
|
||||||
balancerLock.readLock().unlock();
|
|
||||||
balancerLock.writeLock().lock();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!balancerLock.isWriteLockedByCurrentThread()) {
|
||||||
|
balancerLock.readLock().unlock();
|
||||||
|
balancerLock.writeLock().lock();
|
||||||
|
}
|
||||||
|
if (tbh != null) {
|
||||||
assignMetric(metric, tbh);
|
assignMetric(metric, tbh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -812,7 +840,6 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
return tbh;
|
return tbh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TimelyBalancedHost getHostPortKey(String metric) {
|
public TimelyBalancedHost getHostPortKey(String metric) {
|
||||||
TimelyBalancedHost tbh = null;
|
TimelyBalancedHost tbh = null;
|
||||||
|
|
||||||
@@ -878,6 +905,41 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
return tbh;
|
return tbh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected FileSystem getFileSystem(Path path) throws IOException {
|
||||||
|
Configuration configuration = new Configuration();
|
||||||
|
if (StringUtils.isNotBlank(balancerProperties.getDefaultFs())) {
|
||||||
|
configuration.set(FS_DEFAULT_NAME_KEY, balancerProperties.getDefaultFs());
|
||||||
|
}
|
||||||
|
if (balancerProperties.getFsConfigResources() != null) {
|
||||||
|
for (String resource : balancerProperties.getFsConfigResources()) {
|
||||||
|
configuration.addResource(new Path(resource));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FileSystem.get(path.toUri(), configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createAssignmentFile() {
|
||||||
|
try {
|
||||||
|
log.info("Creating assignment file: " + this.assignmentFile);
|
||||||
|
this.fs.create(this.assignmentFile);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long getLastWrittenToHdfsTimestamp() {
|
||||||
|
try {
|
||||||
|
FileStatus fileStatus = this.fs.getFileStatus(this.assignmentFile);
|
||||||
|
return fileStatus.getModificationTime();
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
createAssignmentFile();
|
||||||
|
return System.currentTimeMillis();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
return System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void readAssignmentsFromHdfs(boolean checkIfNecessary) {
|
private void readAssignmentsFromHdfs(boolean checkIfNecessary) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -885,32 +947,28 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
long lastHdfsUpdate = assignmentsLastUpdatedInHdfs.get().postValue();
|
long lastHdfsUpdate = assignmentsLastUpdatedInHdfs.get().postValue();
|
||||||
if (checkIfNecessary) {
|
if (checkIfNecessary) {
|
||||||
if (lastHdfsUpdate <= lastLocalUpdate) {
|
if (lastHdfsUpdate <= lastLocalUpdate) {
|
||||||
LOG.debug("Not reading assignments from hdfs lastHdfsUpdate ({}) <= lastLocalUpdate ({})",
|
log.debug("Not reading assignments from hdfs lastHdfsUpdate ({}) <= lastLocalUpdate ({})", new Date(lastHdfsUpdate),
|
||||||
new Date(lastHdfsUpdate), new Date(lastLocalUpdate));
|
new Date(lastLocalUpdate));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG.debug("Reading assignments from hdfs lastHdfsUpdate ({}) > lastLocalUpdate ({})",
|
log.debug("Reading assignments from hdfs lastHdfsUpdate ({}) > lastLocalUpdate ({})", new Date(lastHdfsUpdate), new Date(lastLocalUpdate));
|
||||||
new Date(lastHdfsUpdate), new Date(lastLocalUpdate));
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// proceed with reading from HDFS
|
// proceed with reading from HDFS
|
||||||
|
|
||||||
Map<String, TimelyBalancedHost> assignedMetricToHostMap = new TreeMap<>();
|
Map<String,TimelyBalancedHost> assignedMetricToHostMap = new TreeMap<>();
|
||||||
|
CsvReader reader = null;
|
||||||
try {
|
try {
|
||||||
boolean acquired = false;
|
boolean acquired = false;
|
||||||
while (!acquired) {
|
while (!acquired) {
|
||||||
acquired = assignmentsIPRWLock.readLock().acquire(60, TimeUnit.SECONDS);
|
acquired = assignmentsIPRWLock.readLock().acquire(60, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
balancerLock.writeLock().lock();
|
balancerLock.writeLock().lock();
|
||||||
Configuration configuration = new Configuration();
|
FSDataInputStream iStream = this.fs.open(this.assignmentFile);
|
||||||
FileSystem fs = FileSystem.get(configuration);
|
reader = new CsvReader(iStream, ',', Charset.forName("UTF-8"));
|
||||||
Path assignmentFile = new Path(balancerConfig.getAssignmentFile());
|
|
||||||
FSDataInputStream iStream = fs.open(assignmentFile);
|
|
||||||
|
|
||||||
CsvReader reader = new CsvReader(iStream, ',', Charset.forName("UTF-8"));
|
|
||||||
reader.setUseTextQualifier(false);
|
reader.setUseTextQualifier(false);
|
||||||
|
|
||||||
// skip the headers
|
// skip the headers
|
||||||
@@ -928,30 +986,31 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
if (tbh == null) {
|
if (tbh == null) {
|
||||||
tbh = getRoundRobinHost(null);
|
tbh = getRoundRobinHost(null);
|
||||||
} else {
|
} else {
|
||||||
LOG.trace("Found assigment: {} to {}:{}", metric, host, tcpPort);
|
log.trace("Found assigment: {} to {}:{}", metric, host, tcpPort);
|
||||||
|
}
|
||||||
|
if (tbh != null) {
|
||||||
|
assignedMetricToHostMap.put(metric, tbh);
|
||||||
}
|
}
|
||||||
assignedMetricToHostMap.put(metric, tbh);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
metricToHostMap.clear();
|
metricToHostMap.clear();
|
||||||
for (Map.Entry<String, TimelyBalancedHost> e : assignedMetricToHostMap.entrySet()) {
|
for (Map.Entry<String,TimelyBalancedHost> e : assignedMetricToHostMap.entrySet()) {
|
||||||
if (StringUtils.isNotBlank(e.getKey()) && e.getValue() != null) {
|
if (StringUtils.isNotBlank(e.getKey()) && e.getValue() != null) {
|
||||||
if (shouldCache(e.getKey())) {
|
if (shouldCache(e.getKey())) {
|
||||||
metricToHostMap.put(e.getKey(), e.getValue());
|
metricToHostMap.put(e.getKey(), e.getValue());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Exception e1 = new IllegalStateException(
|
Exception e1 = new IllegalStateException("Bad assignment metric:" + e.getKey() + " host:" + e.getValue());
|
||||||
"Bad assignment metric:" + e.getKey() + " host:" + e.getValue());
|
log.warn(e1.getMessage(), e1);
|
||||||
LOG.warn(e1.getMessage(), e1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nonCachedMetricsLocalLock.readLock().lock();
|
nonCachedMetricsLocalLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
Iterator<Map.Entry<String, TimelyBalancedHost>> itr = metricToHostMap.entrySet().iterator();
|
Iterator<Map.Entry<String,TimelyBalancedHost>> itr = metricToHostMap.entrySet().iterator();
|
||||||
while (itr.hasNext()) {
|
while (itr.hasNext()) {
|
||||||
Map.Entry<String, TimelyBalancedHost> e = itr.next();
|
Map.Entry<String,TimelyBalancedHost> e = itr.next();
|
||||||
if (nonCachedMetrics.contains(e.getKey())) {
|
if (nonCachedMetrics.contains(e.getKey())) {
|
||||||
itr.remove();
|
itr.remove();
|
||||||
}
|
}
|
||||||
@@ -959,17 +1018,26 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
} finally {
|
} finally {
|
||||||
nonCachedMetricsLocalLock.readLock().unlock();
|
nonCachedMetricsLocalLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
|
// remove metric from metricMap (ArrivalRate) if not being cached
|
||||||
|
metricMap.entrySet().removeIf(e -> !metricToHostMap.containsKey(e.getKey()));
|
||||||
|
|
||||||
assignmentsLastUpdatedLocal.set(assignmentsLastUpdatedInHdfs.get().postValue());
|
assignmentsLastUpdatedLocal.set(assignmentsLastUpdatedInHdfs.get().postValue());
|
||||||
LOG.info("Read {} assignments from hdfs lastHdfsUpdate = lastLocalUpdate ({})", metricToHostMap.size(),
|
log.info("Read {} assignments from hdfs lastHdfsUpdate = lastLocalUpdate ({})", metricToHostMap.size(),
|
||||||
new Date(assignmentsLastUpdatedLocal.get()));
|
new Date(assignmentsLastUpdatedLocal.get()));
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
createAssignmentFile();
|
||||||
|
metricToHostMap.clear();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
} finally {
|
} finally {
|
||||||
|
if (reader != null) {
|
||||||
|
reader.close();
|
||||||
|
}
|
||||||
balancerLock.writeLock().unlock();
|
balancerLock.writeLock().unlock();
|
||||||
try {
|
try {
|
||||||
assignmentsIPRWLock.readLock().release();
|
assignmentsIPRWLock.readLock().release();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -986,27 +1054,23 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
nonCachedMetricsLocalLock.readLock().lock();
|
nonCachedMetricsLocalLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
if (!metricToHostMap.isEmpty()) {
|
if (!metricToHostMap.isEmpty()) {
|
||||||
Configuration configuration = new Configuration();
|
if (!this.fs.exists(this.assignmentFile.getParent())) {
|
||||||
FileSystem fs = FileSystem.get(configuration);
|
this.fs.mkdirs(this.assignmentFile.getParent());
|
||||||
Path assignmentFile = new Path(balancerConfig.getAssignmentFile());
|
|
||||||
if (!fs.exists(assignmentFile.getParent())) {
|
|
||||||
fs.mkdirs(assignmentFile.getParent());
|
|
||||||
}
|
}
|
||||||
FSDataOutputStream oStream = fs.create(assignmentFile, true);
|
FSDataOutputStream oStream = this.fs.create(this.assignmentFile, true);
|
||||||
writer = new CsvWriter(oStream, ',', Charset.forName("UTF-8"));
|
writer = new CsvWriter(oStream, ',', Charset.forName("UTF-8"));
|
||||||
writer.setUseTextQualifier(false);
|
writer.setUseTextQualifier(false);
|
||||||
writer.write("metric");
|
writer.write("metric");
|
||||||
writer.write("host");
|
writer.write("host");
|
||||||
writer.write("tcpPort");
|
writer.write("tcpPort");
|
||||||
writer.endRecord();
|
writer.endRecord();
|
||||||
for (Map.Entry<String, TimelyBalancedHost> e : metricToHostMap.entrySet()) {
|
for (Map.Entry<String,TimelyBalancedHost> e : metricToHostMap.entrySet()) {
|
||||||
if (!nonCachedMetrics.contains(e.getKey())) {
|
if (e.getValue() != null && !nonCachedMetrics.contains(e.getKey())) {
|
||||||
writer.write(e.getKey());
|
writer.write(e.getKey());
|
||||||
writer.write(e.getValue().getHost());
|
writer.write(e.getValue().getHost());
|
||||||
writer.write(Integer.toString(e.getValue().getTcpPort()));
|
writer.write(Integer.toString(e.getValue().getTcpPort()));
|
||||||
writer.endRecord();
|
writer.endRecord();
|
||||||
LOG.trace("Saving assigment: {} to {}:{}", e.getKey(), e.getValue().getHost(),
|
log.trace("Saving assigment: {} to {}:{}", e.getKey(), e.getValue().getHost(), e.getValue().getTcpPort());
|
||||||
e.getValue().getTcpPort());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1016,15 +1080,17 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
if (!assignmentsLastUpdatedInHdfs.get().succeeded()) {
|
if (!assignmentsLastUpdatedInHdfs.get().succeeded()) {
|
||||||
assignmentsLastUpdatedInHdfs.forceSet(now);
|
assignmentsLastUpdatedInHdfs.forceSet(now);
|
||||||
}
|
}
|
||||||
LOG.debug("Wrote {} assignments to hdfs lastHdfsUpdate = lastLocalUpdate ({})",
|
log.info("Wrote {} assignments to hdfs lastHdfsUpdate = lastLocalUpdate ({})", metricToHostMap.size(),
|
||||||
metricToHostMap.size(), new Date(assignmentsLastUpdatedLocal.get()));
|
new Date(assignmentsLastUpdatedLocal.get()));
|
||||||
|
// remove metric from metricMap (ArrivalRate) if not being cached
|
||||||
|
metricMap.entrySet().removeIf(e -> !metricToHostMap.containsKey(e.getKey()));
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
nonCachedMetricsLocalLock.readLock().unlock();
|
nonCachedMetricsLocalLock.readLock().unlock();
|
||||||
balancerLock.readLock().unlock();
|
balancerLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
} finally {
|
} finally {
|
||||||
if (writer != null) {
|
if (writer != null) {
|
||||||
writer.close();
|
writer.close();
|
||||||
@@ -1032,12 +1098,12 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
try {
|
try {
|
||||||
assignmentsIPRWLock.writeLock().release();
|
assignmentsIPRWLock.writeLock().release();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assignMetric(String metric, TimelyBalancedHost tbh) {
|
protected void assignMetric(String metric, TimelyBalancedHost tbh) {
|
||||||
if (isLeader.get()) {
|
if (isLeader.get()) {
|
||||||
if (StringUtils.isNotBlank(metric) && tbh != null) {
|
if (StringUtils.isNotBlank(metric) && tbh != null) {
|
||||||
balancerLock.writeLock().lock();
|
balancerLock.writeLock().lock();
|
||||||
@@ -1049,7 +1115,21 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Exception e = new IllegalStateException("Bad assignment metric:" + metric + " host:" + tbh);
|
Exception e = new IllegalStateException("Bad assignment metric:" + metric + " host:" + tbh);
|
||||||
LOG.warn(e.getMessage(), e);
|
log.warn(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void unassignMetric(String metric) {
|
||||||
|
if (isLeader.get()) {
|
||||||
|
if (StringUtils.isNotBlank(metric)) {
|
||||||
|
balancerLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
metricToHostMap.remove(metric);
|
||||||
|
assignmentsLastUpdatedLocal.set(System.currentTimeMillis());
|
||||||
|
} finally {
|
||||||
|
balancerLock.writeLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package timely.balancer;
|
||||||
|
|
||||||
|
import org.springframework.boot.WebApplicationType;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
|
||||||
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
|
|
||||||
|
@SpringBootApplication(scanBasePackages = {"timely.balancer", "timely.common"}, exclude = {ErrorMvcAutoConfiguration.class})
|
||||||
|
public class TimelyBalancer {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new SpringApplicationBuilder(TimelyBalancer.class).web(WebApplicationType.NONE).run(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,123 +1,58 @@
|
|||||||
package timely.balancer.configuration;
|
package timely.balancer.configuration;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import timely.configuration.Cache;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
@Validated
|
import io.netty.handler.ssl.SslContext;
|
||||||
@Component
|
import timely.balancer.Balancer;
|
||||||
@ConfigurationProperties(prefix = "timely-balancer")
|
import timely.balancer.HealthChecker;
|
||||||
|
import timely.balancer.MetricResolver;
|
||||||
|
import timely.common.component.AuthenticationService;
|
||||||
|
import timely.common.configuration.CacheProperties;
|
||||||
|
import timely.common.configuration.SecurityProperties;
|
||||||
|
import timely.common.configuration.SslClientProperties;
|
||||||
|
import timely.common.configuration.SslServerProperties;
|
||||||
|
import timely.common.configuration.ZookeeperProperties;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties({BalancerProperties.class, BalancerServerProperties.class, BalancerWebsocketProperties.class, BalancerHttpProperties.class})
|
||||||
public class BalancerConfiguration {
|
public class BalancerConfiguration {
|
||||||
|
|
||||||
@Valid
|
@Bean
|
||||||
@NestedConfigurationProperty
|
@ConditionalOnMissingBean
|
||||||
private BalancerServer server = new BalancerServer();
|
public Balancer balancer(ApplicationContext applicationContext, @Qualifier("nettySslContext") SslContext serverSslContext,
|
||||||
|
@Qualifier("outboundJDKSslContext") SSLContext clientSSLContext, AuthenticationService authenticationService, MetricResolver metricResolver,
|
||||||
@Valid
|
BalancerProperties balancerProperties, ZookeeperProperties zookeeperProperties, SecurityProperties securityProperties,
|
||||||
@NestedConfigurationProperty
|
SslServerProperties sslServerProperties, SslClientProperties sslClientProperties, BalancerServerProperties balancerServerProperties,
|
||||||
private BalancerHttp http = new BalancerHttp();
|
BalancerHttpProperties balancerHttpProperties, BalancerWebsocketProperties balancerWebsocketProperties) {
|
||||||
|
Balancer balancer = new Balancer(applicationContext, serverSslContext, clientSSLContext, authenticationService, metricResolver, balancerProperties,
|
||||||
@Valid
|
zookeeperProperties, securityProperties, sslServerProperties, sslClientProperties, balancerServerProperties, balancerHttpProperties,
|
||||||
@NestedConfigurationProperty
|
balancerWebsocketProperties);
|
||||||
private BalancerWebsocket websocket = new BalancerWebsocket();
|
balancer.start();
|
||||||
|
return balancer;
|
||||||
@Valid
|
|
||||||
@NestedConfigurationProperty
|
|
||||||
private ZooKeeper zooKeeper = new ZooKeeper();
|
|
||||||
|
|
||||||
@Valid
|
|
||||||
@NestedConfigurationProperty
|
|
||||||
private BalancerSecurity security = new BalancerSecurity();
|
|
||||||
|
|
||||||
@Valid
|
|
||||||
@NestedConfigurationProperty
|
|
||||||
private Cache cache = new Cache();
|
|
||||||
|
|
||||||
private boolean loginRequired = false;
|
|
||||||
|
|
||||||
private String assignmentFile;
|
|
||||||
|
|
||||||
private Double controlBandPercentage = 0.05;
|
|
||||||
|
|
||||||
private long checkServerHealthInterval = 10000;
|
|
||||||
|
|
||||||
private int serverFailuresBeforeDown = 3;
|
|
||||||
|
|
||||||
private int serverSuccessesBeforeUp = 3;
|
|
||||||
|
|
||||||
public ZooKeeper getZooKeeper() {
|
|
||||||
return zooKeeper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLoginRequired(boolean loginRequired) {
|
@Bean
|
||||||
this.loginRequired = loginRequired;
|
@ConditionalOnMissingBean
|
||||||
|
public HealthChecker healthChecker(BalancerProperties balancerProperties, BalancerServerProperties balancerServerProperties) {
|
||||||
|
HealthChecker healthChecker = new HealthChecker(balancerProperties, balancerServerProperties);
|
||||||
|
healthChecker.start();
|
||||||
|
return healthChecker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLoginRequired() {
|
@Bean
|
||||||
return loginRequired;
|
@ConditionalOnMissingBean
|
||||||
}
|
public MetricResolver metricResolver(CuratorFramework curatorFramework, BalancerProperties balancerProperties, CacheProperties cacheProperties,
|
||||||
|
HealthChecker healthChecker) throws Exception {
|
||||||
public String getAssignmentFile() {
|
MetricResolver metricResolver = new MetricResolver(curatorFramework, balancerProperties, cacheProperties, healthChecker);
|
||||||
return assignmentFile;
|
metricResolver.start();
|
||||||
}
|
return metricResolver;
|
||||||
|
|
||||||
public void setAssignmentFile(String assignmentFile) {
|
|
||||||
this.assignmentFile = assignmentFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setControlBandPercentage(Double controlBandPercentage) {
|
|
||||||
this.controlBandPercentage = controlBandPercentage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getControlBandPercentage() {
|
|
||||||
return controlBandPercentage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BalancerSecurity getSecurity() {
|
|
||||||
return security;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BalancerServer getServer() {
|
|
||||||
return server;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BalancerHttp getHttp() {
|
|
||||||
return http;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BalancerWebsocket getWebsocket() {
|
|
||||||
return websocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Cache getCache() {
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCheckServerHealthInterval(long checkServerHealthInterval) {
|
|
||||||
this.checkServerHealthInterval = checkServerHealthInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getCheckServerHealthInterval() {
|
|
||||||
return checkServerHealthInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getServerFailuresBeforeDown() {
|
|
||||||
return serverFailuresBeforeDown;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setServerFailuresBeforeDown(int serverFailuresBeforeDown) {
|
|
||||||
this.serverFailuresBeforeDown = serverFailuresBeforeDown;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getServerSuccessesBeforeUp() {
|
|
||||||
return serverSuccessesBeforeUp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setServerSuccessesBeforeUp(int serverSuccessesBeforeUp) {
|
|
||||||
this.serverSuccessesBeforeUp = serverSuccessesBeforeUp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package timely.balancer.configuration;
|
|
||||||
|
|
||||||
import javax.validation.Valid;
|
|
||||||
|
|
||||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
|
||||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
|
||||||
import timely.configuration.Http;
|
|
||||||
|
|
||||||
public class BalancerHttp extends Http {
|
|
||||||
|
|
||||||
@Valid
|
|
||||||
@NestedConfigurationProperty
|
|
||||||
private GenericKeyedObjectPoolConfig<CloseableHttpClient> httpClientPool = new GenericKeyedObjectPoolConfig<>();
|
|
||||||
|
|
||||||
public GenericKeyedObjectPoolConfig<CloseableHttpClient> getHttpClientPool() {
|
|
||||||
return httpClientPool;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package timely.balancer.configuration;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||||
|
|
||||||
|
import timely.common.configuration.HttpProperties;
|
||||||
|
|
||||||
|
@RefreshScope
|
||||||
|
@ConfigurationProperties(prefix = "timely.balancer.http")
|
||||||
|
public class BalancerHttpProperties extends HttpProperties {
|
||||||
|
|
||||||
|
private int connectionRequestTimeout = 5000;
|
||||||
|
private int connectTimeout = 5000;
|
||||||
|
private int socketTimeout = 300000;
|
||||||
|
private int requestTimeout = 300000;
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
@NestedConfigurationProperty
|
||||||
|
private GenericKeyedObjectPoolConfiguration<CloseableHttpClient> httpClientPool = new GenericKeyedObjectPoolConfiguration<>();
|
||||||
|
|
||||||
|
public GenericKeyedObjectPoolConfiguration<CloseableHttpClient> getHttpClientPool() {
|
||||||
|
return httpClientPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnectionRequestTimeout(final int connectionRequestTimeout) {
|
||||||
|
this.connectionRequestTimeout = connectionRequestTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getConnectionRequestTimeout() {
|
||||||
|
return connectionRequestTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnectTimeout(final int connectTimeout) {
|
||||||
|
this.connectTimeout = connectTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getConnectTimeout() {
|
||||||
|
return connectTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSocketTimeout(final int socketTimeout) {
|
||||||
|
this.socketTimeout = socketTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSocketTimeout() {
|
||||||
|
return socketTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestTimeout(int requestTimeout) {
|
||||||
|
this.requestTimeout = requestTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRequestTimeout() {
|
||||||
|
return requestTimeout;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package timely.balancer.configuration;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
@Validated
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "timely.balancer")
|
||||||
|
public class BalancerProperties {
|
||||||
|
|
||||||
|
private boolean loginRequired = false;
|
||||||
|
|
||||||
|
private String assignmentFile;
|
||||||
|
|
||||||
|
private String defaultFs;
|
||||||
|
|
||||||
|
private List<String> fsConfigResources;
|
||||||
|
|
||||||
|
private Double controlBandPercentage = 0.05;
|
||||||
|
|
||||||
|
private long checkServerHealthInterval = 10000;
|
||||||
|
|
||||||
|
private int serverFailuresBeforeDown = 3;
|
||||||
|
|
||||||
|
private int serverSuccessesBeforeUp = 3;
|
||||||
|
|
||||||
|
public void setLoginRequired(boolean loginRequired) {
|
||||||
|
this.loginRequired = loginRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLoginRequired() {
|
||||||
|
return loginRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAssignmentFile() {
|
||||||
|
return assignmentFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAssignmentFile(String assignmentFile) {
|
||||||
|
this.assignmentFile = assignmentFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDefaultFs() {
|
||||||
|
return defaultFs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultFs(String defaultFs) {
|
||||||
|
this.defaultFs = defaultFs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getFsConfigResources() {
|
||||||
|
return fsConfigResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFsConfigResources(List<String> fsConfigResources) {
|
||||||
|
this.fsConfigResources = fsConfigResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setControlBandPercentage(Double controlBandPercentage) {
|
||||||
|
this.controlBandPercentage = controlBandPercentage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getControlBandPercentage() {
|
||||||
|
return controlBandPercentage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCheckServerHealthInterval(long checkServerHealthInterval) {
|
||||||
|
this.checkServerHealthInterval = checkServerHealthInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCheckServerHealthInterval() {
|
||||||
|
return checkServerHealthInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getServerFailuresBeforeDown() {
|
||||||
|
return serverFailuresBeforeDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerFailuresBeforeDown(int serverFailuresBeforeDown) {
|
||||||
|
this.serverFailuresBeforeDown = serverFailuresBeforeDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getServerSuccessesBeforeUp() {
|
||||||
|
return serverSuccessesBeforeUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerSuccessesBeforeUp(int serverSuccessesBeforeUp) {
|
||||||
|
this.serverSuccessesBeforeUp = serverSuccessesBeforeUp;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package timely.balancer.configuration;
|
|
||||||
|
|
||||||
import javax.validation.Valid;
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
|
||||||
import timely.configuration.Security;
|
|
||||||
|
|
||||||
public class BalancerSecurity extends Security {
|
|
||||||
|
|
||||||
@Valid
|
|
||||||
@NestedConfigurationProperty
|
|
||||||
private ClientSsl clientSsl = new ClientSsl();
|
|
||||||
|
|
||||||
public ClientSsl getClientSsl() {
|
|
||||||
return clientSsl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package timely.balancer.configuration;
|
|
||||||
|
|
||||||
import javax.validation.Valid;
|
|
||||||
|
|
||||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
|
||||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
|
||||||
import timely.client.tcp.TcpClient;
|
|
||||||
import timely.client.udp.UdpClient;
|
|
||||||
import timely.configuration.Server;
|
|
||||||
|
|
||||||
public class BalancerServer extends Server {
|
|
||||||
|
|
||||||
@Valid
|
|
||||||
@NestedConfigurationProperty
|
|
||||||
private GenericKeyedObjectPoolConfig<UdpClient> udpClientPool = new GenericKeyedObjectPoolConfig<>();
|
|
||||||
|
|
||||||
@Valid
|
|
||||||
@NestedConfigurationProperty
|
|
||||||
private GenericKeyedObjectPoolConfig<TcpClient> tcpClientPool = new GenericKeyedObjectPoolConfig<>();
|
|
||||||
|
|
||||||
private int numTcpPools = 1;
|
|
||||||
|
|
||||||
private int tcpBufferSize = -1;
|
|
||||||
|
|
||||||
public GenericKeyedObjectPoolConfig<UdpClient> getUdpClientPool() {
|
|
||||||
return udpClientPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GenericKeyedObjectPoolConfig<TcpClient> getTcpClientPool() {
|
|
||||||
return tcpClientPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumTcpPools() {
|
|
||||||
return numTcpPools;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNumTcpPools(int numTcpPools) {
|
|
||||||
this.numTcpPools = numTcpPools;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTcpBufferSize() {
|
|
||||||
return tcpBufferSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTcpBufferSize(int tcpBufferSize) {
|
|
||||||
this.tcpBufferSize = tcpBufferSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package timely.balancer.configuration;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||||
|
|
||||||
|
import timely.client.tcp.TcpClient;
|
||||||
|
import timely.client.udp.UdpClient;
|
||||||
|
import timely.common.configuration.ServerProperties;
|
||||||
|
|
||||||
|
@RefreshScope
|
||||||
|
@ConfigurationProperties(prefix = "timely.balancer.server")
|
||||||
|
public class BalancerServerProperties extends ServerProperties {
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
@NestedConfigurationProperty
|
||||||
|
private GenericKeyedObjectPoolConfiguration<UdpClient> udpClientPool = new GenericKeyedObjectPoolConfiguration<>();
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
@NestedConfigurationProperty
|
||||||
|
private GenericKeyedObjectPoolConfiguration<TcpClient> tcpClientPool = new GenericKeyedObjectPoolConfiguration<>();
|
||||||
|
|
||||||
|
private int tcpBufferSize = -1;
|
||||||
|
|
||||||
|
public GenericKeyedObjectPoolConfiguration<UdpClient> getUdpClientPool() {
|
||||||
|
return udpClientPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenericKeyedObjectPoolConfiguration<TcpClient> getTcpClientPool() {
|
||||||
|
return tcpClientPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTcpBufferSize() {
|
||||||
|
return tcpBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTcpBufferSize(int tcpBufferSize) {
|
||||||
|
this.tcpBufferSize = tcpBufferSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package timely.balancer.configuration;
|
|
||||||
|
|
||||||
import javax.validation.Valid;
|
|
||||||
|
|
||||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
|
||||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
|
||||||
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
|
|
||||||
import timely.configuration.Websocket;
|
|
||||||
|
|
||||||
public class BalancerWebsocket extends Websocket {
|
|
||||||
|
|
||||||
@Valid
|
|
||||||
@NestedConfigurationProperty
|
|
||||||
private GenericKeyedObjectPoolConfig<WebSocketSubscriptionClient> wsClientPool = new GenericKeyedObjectPoolConfig<>();
|
|
||||||
|
|
||||||
public GenericKeyedObjectPoolConfig<WebSocketSubscriptionClient> getWsClientPool() {
|
|
||||||
return wsClientPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int incomingBufferSize = 50000000;
|
|
||||||
|
|
||||||
public int getIncomingBufferSize() {
|
|
||||||
return incomingBufferSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIncomingBufferSize(int incomingBufferSize) {
|
|
||||||
this.incomingBufferSize = incomingBufferSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package timely.balancer.configuration;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||||
|
|
||||||
|
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
|
||||||
|
import timely.common.configuration.WebsocketProperties;
|
||||||
|
|
||||||
|
@RefreshScope
|
||||||
|
@ConfigurationProperties(prefix = "timely.balancer.websocket")
|
||||||
|
public class BalancerWebsocketProperties extends WebsocketProperties {
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
@NestedConfigurationProperty
|
||||||
|
private GenericKeyedObjectPoolConfiguration<WebSocketSubscriptionClient> wsClientPool = new GenericKeyedObjectPoolConfiguration<>();
|
||||||
|
|
||||||
|
public GenericKeyedObjectPoolConfiguration<WebSocketSubscriptionClient> getWsClientPool() {
|
||||||
|
return wsClientPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int incomingBufferSize = 50000000;
|
||||||
|
|
||||||
|
public int getIncomingBufferSize() {
|
||||||
|
return incomingBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIncomingBufferSize(int incomingBufferSize) {
|
||||||
|
this.incomingBufferSize = incomingBufferSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
package timely.balancer.configuration;
|
|
||||||
|
|
||||||
public class ClientSsl {
|
|
||||||
|
|
||||||
private String keyFile;
|
|
||||||
private String keyType;
|
|
||||||
private String keyPassword;
|
|
||||||
private String trustStoreFile;
|
|
||||||
private String trustStoreType;
|
|
||||||
private String trustStorePassword;
|
|
||||||
private boolean useClientCert = true;
|
|
||||||
private boolean hostVerificationEnabled = true;
|
|
||||||
|
|
||||||
public String getKeyFile() {
|
|
||||||
return keyFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKeyFile(String keyFile) {
|
|
||||||
this.keyFile = keyFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getKeyType() {
|
|
||||||
return keyType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKeyType(String keyType) {
|
|
||||||
this.keyType = keyType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getKeyPassword() {
|
|
||||||
return keyPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKeyPassword(String keyPassword) {
|
|
||||||
this.keyPassword = keyPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTrustStoreFile() {
|
|
||||||
return trustStoreFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTrustStoreFile(String trustStoreFile) {
|
|
||||||
this.trustStoreFile = trustStoreFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTrustStoreType() {
|
|
||||||
return trustStoreType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTrustStoreType(String trustStoreType) {
|
|
||||||
this.trustStoreType = trustStoreType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTrustStorePassword() {
|
|
||||||
return trustStorePassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTrustStorePassword(String trustStorePassword) {
|
|
||||||
this.trustStorePassword = trustStorePassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUseClientCert(boolean useClientCert) {
|
|
||||||
this.useClientCert = useClientCert;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isUseClientCert() {
|
|
||||||
return useClientCert;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHostVerificationEnabled(boolean hostVerificationEnabled) {
|
|
||||||
this.hostVerificationEnabled = hostVerificationEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isHostVerificationEnabled() {
|
|
||||||
return hostVerificationEnabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+83
@@ -0,0 +1,83 @@
|
|||||||
|
package timely.balancer.configuration;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
import org.apache.commons.pool2.impl.AbandonedConfig;
|
||||||
|
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||||
|
|
||||||
|
public class GenericKeyedObjectPoolConfiguration<T> extends GenericKeyedObjectPoolConfig<T> {
|
||||||
|
|
||||||
|
private Duration removeAbandonedTimeout = null;
|
||||||
|
private boolean removeAbandonedLogging = false;
|
||||||
|
private boolean removeAbandonedOnBorrow = false;
|
||||||
|
private boolean removeAbandonedOnMaintenance = false;
|
||||||
|
|
||||||
|
public void setMaxWaitMillis(long maxWaitMillis) {
|
||||||
|
super.setMaxWait(Duration.ofMillis(maxWaitMillis));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
|
||||||
|
super.setMinEvictableIdleTime(Duration.ofMillis(minEvictableIdleTimeMillis));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvictorShutdownTimeoutMillis(long evictorShutdownTimeoutMillis) {
|
||||||
|
super.setEvictorShutdownTimeout(Duration.ofMillis(evictorShutdownTimeoutMillis));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis) {
|
||||||
|
super.setSoftMinEvictableIdleTime(Duration.ofMillis(softMinEvictableIdleTimeMillis));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
|
||||||
|
super.setTimeBetweenEvictionRuns(Duration.ofMillis(timeBetweenEvictionRunsMillis));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemoveAbandonedTimeoutMillis(long removeAbandonedTimeoutMillis) {
|
||||||
|
this.removeAbandonedTimeout = Duration.ofMillis(removeAbandonedTimeoutMillis);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Duration getRemoveAbandonedTimeout() {
|
||||||
|
return removeAbandonedTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemoveAbandonedOnBorrow(boolean removeAbandonedOnBorrow) {
|
||||||
|
this.removeAbandonedOnBorrow = removeAbandonedOnBorrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getRemoveAbandonedOnBorrow() {
|
||||||
|
return removeAbandonedOnBorrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemoveAbandonedOnMaintenance(boolean removeAbandonedOnMaintenance) {
|
||||||
|
this.removeAbandonedOnMaintenance = removeAbandonedOnMaintenance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getRemoveAbandonedOnMaintenance() {
|
||||||
|
return removeAbandonedOnMaintenance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemoveAbandonedLogging(boolean removeAbandonedLogging) {
|
||||||
|
this.removeAbandonedLogging = removeAbandonedLogging;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getRemoveAbandonedLogging() {
|
||||||
|
return removeAbandonedLogging;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbandonedConfig getAbandonedConfig() {
|
||||||
|
AbandonedConfig abandonedConfig = null;
|
||||||
|
if (removeAbandonedTimeout != null) {
|
||||||
|
abandonedConfig = new AbandonedConfig();
|
||||||
|
abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
|
||||||
|
if (removeAbandonedLogging) {
|
||||||
|
abandonedConfig.setLogAbandoned(removeAbandonedLogging);
|
||||||
|
abandonedConfig.setLogWriter(new PrintWriter(System.out, true, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
abandonedConfig.setRemoveAbandonedOnBorrow(removeAbandonedOnBorrow);
|
||||||
|
abandonedConfig.setRemoveAbandonedOnMaintenance(removeAbandonedOnMaintenance);
|
||||||
|
}
|
||||||
|
return abandonedConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package timely.balancer.configuration;
|
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
|
|
||||||
@SpringBootApplication(scanBasePackageClasses = { SpringBootstrap.class })
|
|
||||||
public class SpringBootstrap {
|
|
||||||
}
|
|
||||||
@@ -1,19 +1,17 @@
|
|||||||
package timely.balancer.connection;
|
package timely.balancer.connection;
|
||||||
|
|
||||||
import java.util.Timer;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import timely.balancer.ArrivalRate;
|
import timely.balancer.ArrivalRate;
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
import timely.balancer.configuration.BalancerProperties;
|
||||||
|
|
||||||
public class TimelyBalancedHost {
|
public class TimelyBalancedHost {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(TimelyBalancedHost.class);
|
private static final Logger log = LoggerFactory.getLogger(TimelyBalancedHost.class);
|
||||||
static private Timer arrivalRateTimer = new Timer("ArrivalRateTimerTBH", true);
|
|
||||||
|
|
||||||
private String host;
|
private String host;
|
||||||
private int tcpPort;
|
private int tcpPort;
|
||||||
@@ -21,41 +19,30 @@ public class TimelyBalancedHost {
|
|||||||
private int wsPort;
|
private int wsPort;
|
||||||
private int udpPort;
|
private int udpPort;
|
||||||
private boolean isUp = true;
|
private boolean isUp = true;
|
||||||
private BalancerConfiguration balancerConfig;
|
private BalancerProperties balancerProperties;
|
||||||
private int failures = 0;
|
private int failures = 0;
|
||||||
private int successes = 0;
|
private int successes = 0;
|
||||||
private ArrivalRate arrivalRate = new ArrivalRate(arrivalRateTimer);
|
private ArrivalRate arrivalRate = null;
|
||||||
|
|
||||||
public TimelyBalancedHost() {
|
private TimelyBalancedHost() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimelyBalancedHost(String host, int tcpPort, int httpPort, int wsPort, int udpPort) {
|
private TimelyBalancedHost(String host, int tcpPort, int httpPort, int wsPort, int udpPort, ArrivalRate arrivalRate) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.tcpPort = tcpPort;
|
this.tcpPort = tcpPort;
|
||||||
this.httpPort = httpPort;
|
this.httpPort = httpPort;
|
||||||
this.wsPort = wsPort;
|
this.wsPort = wsPort;
|
||||||
this.udpPort = udpPort;
|
this.udpPort = udpPort;
|
||||||
|
this.arrivalRate = arrivalRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimelyBalancedHost(String host, int basePort) {
|
static public TimelyBalancedHost of(String host, int tcpPort, int httpPort, int wsPort, int udpPort, ArrivalRate arrivalRate) {
|
||||||
this.host = host;
|
return new TimelyBalancedHost(host, tcpPort, httpPort, wsPort, udpPort, arrivalRate);
|
||||||
this.tcpPort = basePort;
|
|
||||||
this.httpPort = basePort + 1;
|
|
||||||
this.wsPort = basePort + 2;
|
|
||||||
this.udpPort = basePort + 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static public TimelyBalancedHost of(String host, int tcpPort, int httpPort, int wsPort, int udpPort) {
|
public void setBalancerProperties(BalancerProperties balancerProperties) {
|
||||||
return new TimelyBalancedHost(host, tcpPort, httpPort, wsPort, udpPort);
|
this.balancerProperties = balancerProperties;
|
||||||
}
|
|
||||||
|
|
||||||
static public TimelyBalancedHost of(String host, int basePort) {
|
|
||||||
return new TimelyBalancedHost(host, basePort);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBalancerConfig(BalancerConfiguration balancerConfig) {
|
|
||||||
this.balancerConfig = balancerConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized public boolean isUp() {
|
synchronized public boolean isUp() {
|
||||||
@@ -63,38 +50,38 @@ public class TimelyBalancedHost {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void reportSuccess() {
|
public void reportSuccess() {
|
||||||
int serverSuccessesBeforeUp = balancerConfig.getServerSuccessesBeforeUp();
|
int serverSuccessesBeforeUp = balancerProperties.getServerSuccessesBeforeUp();
|
||||||
String h = host;
|
String h = host;
|
||||||
int p = tcpPort;
|
int p = tcpPort;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (LOG.isTraceEnabled()) {
|
if (log.isTraceEnabled()) {
|
||||||
LOG.trace("success reported host:{} port:{} isUp:{} successes:{} serverSuccessesBeforeUp:{}", h, p,
|
log.trace("success reported host:{} port:{} isUp:{} successes:{} serverSuccessesBeforeUp:{}", h, p, isUp, (successes + 1),
|
||||||
isUp, (successes + 1), serverSuccessesBeforeUp);
|
serverSuccessesBeforeUp);
|
||||||
}
|
}
|
||||||
if (!isUp) {
|
if (!isUp) {
|
||||||
if (++successes >= serverSuccessesBeforeUp) {
|
if (++successes >= serverSuccessesBeforeUp) {
|
||||||
isUp = true;
|
isUp = true;
|
||||||
successes = 0;
|
successes = 0;
|
||||||
LOG.info("host up host:{} port:{}", h, p);
|
log.info("host up host:{} port:{}", h, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reportFailure() {
|
public void reportFailure() {
|
||||||
int serverFailuresBeforeDown = balancerConfig.getServerFailuresBeforeDown();
|
int serverFailuresBeforeDown = balancerProperties.getServerFailuresBeforeDown();
|
||||||
String h = host;
|
String h = host;
|
||||||
int p = tcpPort;
|
int p = tcpPort;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (LOG.isTraceEnabled()) {
|
if (log.isTraceEnabled()) {
|
||||||
LOG.trace("failure reported host:{} port:{} isUp:{} failures:{} serverFailuresBeforeUp:{}", h, p, isUp,
|
log.trace("failure reported host:{} port:{} isUp:{} failures:{} serverFailuresBeforeUp:{}", h, p, isUp, (failures + 1),
|
||||||
(failures + 1), serverFailuresBeforeDown);
|
serverFailuresBeforeDown);
|
||||||
}
|
}
|
||||||
if (isUp) {
|
if (isUp) {
|
||||||
if (++failures >= serverFailuresBeforeDown) {
|
if (++failures >= serverFailuresBeforeDown) {
|
||||||
isUp = false;
|
isUp = false;
|
||||||
failures = 0;
|
failures = 0;
|
||||||
LOG.info("host down host:{} port:{}", h, p);
|
log.info("host down host:{} port:{}", h, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,11 +128,17 @@ public class TimelyBalancedHost {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void arrived() {
|
public void arrived() {
|
||||||
arrivalRate.arrived();
|
if (this.arrivalRate != null) {
|
||||||
|
this.arrivalRate.arrived();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getArrivalRate() {
|
public double getArrivalRate() {
|
||||||
return arrivalRate.getRate();
|
if (this.arrivalRate == null) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return this.arrivalRate.getRate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -6,24 +6,26 @@ import org.apache.commons.pool2.KeyedPooledObjectFactory;
|
|||||||
import org.apache.commons.pool2.PooledObject;
|
import org.apache.commons.pool2.PooledObject;
|
||||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import timely.balancer.configuration.BalancerSecurity;
|
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
|
||||||
|
|
||||||
public class HttpClientFactory implements KeyedPooledObjectFactory<TimelyBalancedHost, CloseableHttpClient> {
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
import timely.client.http.HttpClient;
|
||||||
|
import timely.common.configuration.SslClientProperties;
|
||||||
|
|
||||||
|
public class HttpClientFactory implements KeyedPooledObjectFactory<TimelyBalancedHost,CloseableHttpClient> {
|
||||||
|
|
||||||
private final SSLContext sslContext;
|
private final SSLContext sslContext;
|
||||||
private final BalancerSecurity security;
|
private SslClientProperties sslClientProperties;
|
||||||
|
|
||||||
public HttpClientFactory(BalancerSecurity security, SSLContext sslContext) {
|
public HttpClientFactory(SSLContext sslContext, SslClientProperties sslClientProperties) {
|
||||||
this.security = security;
|
|
||||||
this.sslContext = sslContext;
|
this.sslContext = sslContext;
|
||||||
|
this.sslClientProperties = sslClientProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PooledObject<CloseableHttpClient> makeObject(TimelyBalancedHost k) throws Exception {
|
public PooledObject<CloseableHttpClient> makeObject(TimelyBalancedHost k) throws Exception {
|
||||||
// disable cookie management because we are sharing connections
|
// disable cookie management because we are sharing connections
|
||||||
return new DefaultPooledObject<>(timely.client.http.HttpClient.get(this.sslContext, null,
|
return new DefaultPooledObject<>(
|
||||||
security.getClientSsl().isHostVerificationEnabled(), security.getClientSsl().isUseClientCert()));
|
HttpClient.get(this.sslContext, null, sslClientProperties.isHostVerificationEnabled(), sslClientProperties.isUseClientCert()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ import javax.net.ssl.SSLContext;
|
|||||||
|
|
||||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
|
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import timely.balancer.configuration.BalancerHttp;
|
|
||||||
import timely.balancer.configuration.BalancerSecurity;
|
import timely.balancer.configuration.BalancerHttpProperties;
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
import timely.common.configuration.SslClientProperties;
|
||||||
|
|
||||||
public class HttpClientPool extends GenericKeyedObjectPool<TimelyBalancedHost, CloseableHttpClient> {
|
public class HttpClientPool extends GenericKeyedObjectPool<TimelyBalancedHost,CloseableHttpClient> {
|
||||||
|
|
||||||
public HttpClientPool(BalancerSecurity balancerSecurity, BalancerHttp http, SSLContext sslContext) {
|
public HttpClientPool(BalancerHttpProperties config, SSLContext sslContext, SslClientProperties sslClientProperties) {
|
||||||
super(new HttpClientFactory(balancerSecurity, sslContext), http.getHttpClientPool());
|
super(new HttpClientFactory(sslContext, sslClientProperties), config.getHttpClientPool(), config.getHttpClientPool().getAbandonedConfig());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,10 +5,11 @@ import java.io.IOException;
|
|||||||
import org.apache.commons.pool2.KeyedPooledObjectFactory;
|
import org.apache.commons.pool2.KeyedPooledObjectFactory;
|
||||||
import org.apache.commons.pool2.PooledObject;
|
import org.apache.commons.pool2.PooledObject;
|
||||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||||
|
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.client.tcp.TcpClient;
|
import timely.client.tcp.TcpClient;
|
||||||
|
|
||||||
public class TcpClientFactory implements KeyedPooledObjectFactory<TimelyBalancedHost, TcpClient> {
|
public class TcpClientFactory implements KeyedPooledObjectFactory<TimelyBalancedHost,TcpClient> {
|
||||||
|
|
||||||
private int bufferSize;
|
private int bufferSize;
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package timely.balancer.connection.tcp;
|
package timely.balancer.connection.tcp;
|
||||||
|
|
||||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
|
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
|
||||||
|
import timely.balancer.configuration.BalancerServerProperties;
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.client.tcp.TcpClient;
|
import timely.client.tcp.TcpClient;
|
||||||
|
|
||||||
public class TcpClientPool extends GenericKeyedObjectPool<TimelyBalancedHost, TcpClient> {
|
public class TcpClientPool extends GenericKeyedObjectPool<TimelyBalancedHost,TcpClient> {
|
||||||
|
|
||||||
public TcpClientPool(BalancerConfiguration config) {
|
public TcpClientPool(BalancerServerProperties config) {
|
||||||
super(new TcpClientFactory(config.getServer().getTcpBufferSize()), config.getServer().getTcpClientPool());
|
super(new TcpClientFactory(config.getTcpBufferSize()), config.getTcpClientPool(), config.getTcpClientPool().getAbandonedConfig());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,13 +5,13 @@ import java.io.IOException;
|
|||||||
import org.apache.commons.pool2.KeyedPooledObjectFactory;
|
import org.apache.commons.pool2.KeyedPooledObjectFactory;
|
||||||
import org.apache.commons.pool2.PooledObject;
|
import org.apache.commons.pool2.PooledObject;
|
||||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||||
|
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.client.udp.UdpClient;
|
import timely.client.udp.UdpClient;
|
||||||
|
|
||||||
public class UdpClientFactory implements KeyedPooledObjectFactory<TimelyBalancedHost, UdpClient> {
|
public class UdpClientFactory implements KeyedPooledObjectFactory<TimelyBalancedHost,UdpClient> {
|
||||||
|
|
||||||
public UdpClientFactory() {
|
public UdpClientFactory() {}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PooledObject<UdpClient> makeObject(TimelyBalancedHost k) throws Exception {
|
public PooledObject<UdpClient> makeObject(TimelyBalancedHost k) throws Exception {
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package timely.balancer.connection.udp;
|
package timely.balancer.connection.udp;
|
||||||
|
|
||||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
|
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
|
||||||
|
import timely.balancer.configuration.BalancerServerProperties;
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.client.udp.UdpClient;
|
import timely.client.udp.UdpClient;
|
||||||
|
|
||||||
public class UdpClientPool extends GenericKeyedObjectPool<TimelyBalancedHost, UdpClient> {
|
public class UdpClientPool extends GenericKeyedObjectPool<TimelyBalancedHost,UdpClient> {
|
||||||
|
|
||||||
public UdpClientPool(BalancerConfiguration config) {
|
public UdpClientPool(BalancerServerProperties config) {
|
||||||
super(new UdpClientFactory(), config.getServer().getUdpClientPool());
|
super(new UdpClientFactory(), config.getUdpClientPool(), config.getUdpClientPool().getAbandonedConfig());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,28 +5,35 @@ import javax.net.ssl.SSLContext;
|
|||||||
import org.apache.commons.pool2.KeyedPooledObjectFactory;
|
import org.apache.commons.pool2.KeyedPooledObjectFactory;
|
||||||
import org.apache.commons.pool2.PooledObject;
|
import org.apache.commons.pool2.PooledObject;
|
||||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
|
||||||
|
import timely.balancer.configuration.BalancerProperties;
|
||||||
|
import timely.balancer.configuration.BalancerWebsocketProperties;
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
|
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
|
||||||
|
import timely.common.configuration.SslClientProperties;
|
||||||
|
|
||||||
public class WsClientFactory implements KeyedPooledObjectFactory<TimelyBalancedHost, WebSocketSubscriptionClient> {
|
public class WsClientFactory implements KeyedPooledObjectFactory<TimelyBalancedHost,WebSocketSubscriptionClient> {
|
||||||
|
|
||||||
private final SSLContext sslContext;
|
private final SSLContext sslContext;
|
||||||
private BalancerConfiguration balancerConfig;
|
private BalancerProperties balancerProperties;
|
||||||
|
private BalancerWebsocketProperties balancerWebsocketProperties;
|
||||||
|
private SslClientProperties sslClientProperties;
|
||||||
|
|
||||||
public WsClientFactory(BalancerConfiguration balancerConfig, SSLContext sslContext) {
|
public WsClientFactory(BalancerProperties balancerProperties, BalancerWebsocketProperties balancerWebsocketProperties,
|
||||||
this.balancerConfig = balancerConfig;
|
SslClientProperties sslClientProperties, SSLContext sslContext) {
|
||||||
|
this.balancerProperties = balancerProperties;
|
||||||
|
this.balancerWebsocketProperties = balancerWebsocketProperties;
|
||||||
|
this.sslClientProperties = sslClientProperties;
|
||||||
this.sslContext = sslContext;
|
this.sslContext = sslContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PooledObject<WebSocketSubscriptionClient> makeObject(TimelyBalancedHost k) throws Exception {
|
public PooledObject<WebSocketSubscriptionClient> makeObject(TimelyBalancedHost k) throws Exception {
|
||||||
|
|
||||||
int bufferSize = balancerConfig.getWebsocket().getIncomingBufferSize();
|
int bufferSize = balancerWebsocketProperties.getIncomingBufferSize();
|
||||||
WebSocketSubscriptionClient client = new WebSocketSubscriptionClient(sslContext, k.getHost(), k.getHttpPort(),
|
WebSocketSubscriptionClient client = new WebSocketSubscriptionClient(sslContext, k.getHost(), k.getHttpPort(), k.getWsPort(),
|
||||||
k.getWsPort(), balancerConfig.getSecurity().getClientSsl().isUseClientCert(),
|
sslClientProperties.isUseClientCert(), balancerProperties.isLoginRequired(), sslClientProperties.isHostVerificationEnabled(),
|
||||||
balancerConfig.isLoginRequired(), "", "",
|
bufferSize);
|
||||||
balancerConfig.getSecurity().getClientSsl().isHostVerificationEnabled(), bufferSize);
|
|
||||||
return new DefaultPooledObject<>(client);
|
return new DefaultPooledObject<>(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,18 @@ package timely.balancer.connection.ws;
|
|||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
|
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
|
||||||
|
import timely.balancer.configuration.BalancerProperties;
|
||||||
|
import timely.balancer.configuration.BalancerWebsocketProperties;
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
|
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
|
||||||
|
import timely.common.configuration.SslClientProperties;
|
||||||
|
|
||||||
public class WsClientPool extends GenericKeyedObjectPool<TimelyBalancedHost, WebSocketSubscriptionClient> {
|
public class WsClientPool extends GenericKeyedObjectPool<TimelyBalancedHost,WebSocketSubscriptionClient> {
|
||||||
|
|
||||||
public WsClientPool(BalancerConfiguration balancerConfig, SSLContext sslContext) {
|
public WsClientPool(BalancerProperties balancerProperties, BalancerWebsocketProperties config, SslClientProperties sslClientProperties,
|
||||||
super(new WsClientFactory(balancerConfig, sslContext), balancerConfig.getWebsocket().getWsClientPool());
|
SSLContext sslContext) {
|
||||||
|
super(new WsClientFactory(balancerProperties, config, sslClientProperties, sslContext), config.getWsClientPool(),
|
||||||
|
config.getWsClientPool().getAbandonedConfig());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package timely.balancer.healthcheck;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
|
||||||
import timely.balancer.connection.tcp.TcpClientPool;
|
|
||||||
|
|
||||||
public class HealthChecker {
|
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(HealthChecker.class);
|
|
||||||
private List<TimelyBalancedHost> timelyHosts = new ArrayList<>();
|
|
||||||
private Timer timer;
|
|
||||||
final private TCPServerHealthCheck tcpServerHealthCheck;
|
|
||||||
private TimerTask check = new TimerTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
synchronized (timelyHosts) {
|
|
||||||
for (TimelyBalancedHost h : timelyHosts) {
|
|
||||||
try {
|
|
||||||
if (tcpServerHealthCheck.isServerHealthy(h)) {
|
|
||||||
h.reportSuccess();
|
|
||||||
} else {
|
|
||||||
h.reportFailure();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error(e.getMessage(), e);
|
|
||||||
h.reportFailure();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public HealthChecker(BalancerConfiguration config, TcpClientPool tcpClientPool) {
|
|
||||||
this.tcpServerHealthCheck = new TCPServerHealthCheck(tcpClientPool);
|
|
||||||
this.timer = new Timer("HealthCheckerThread", true);
|
|
||||||
this.timer.scheduleAtFixedRate(check, 0, config.getCheckServerHealthInterval());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTimelyHosts(List<TimelyBalancedHost> timelyHosts) {
|
|
||||||
synchronized (timelyHosts) {
|
|
||||||
this.timelyHosts.clear();
|
|
||||||
this.timelyHosts.addAll(timelyHosts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,7 @@ package timely.balancer.netty.http;
|
|||||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
|
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -10,8 +11,29 @@ import java.util.Collection;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import org.apache.http.Header;
|
||||||
|
import org.apache.http.client.config.RequestConfig;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.client.methods.HttpRequestBase;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.message.BasicHeader;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
|
||||||
|
import com.google.common.base.Throwables;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
@@ -21,38 +43,30 @@ import io.netty.handler.codec.http.FullHttpResponse;
|
|||||||
import io.netty.handler.codec.http.HttpMethod;
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||||
import io.netty.handler.codec.http.HttpVersion;
|
import io.netty.handler.codec.http.HttpVersion;
|
||||||
import io.netty.util.ReferenceCountUtil;
|
|
||||||
import org.apache.http.Header;
|
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
|
||||||
import org.apache.http.client.methods.HttpGet;
|
|
||||||
import org.apache.http.client.methods.HttpPost;
|
|
||||||
import org.apache.http.client.methods.HttpUriRequest;
|
|
||||||
import org.apache.http.entity.StringEntity;
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
|
||||||
import org.apache.http.message.BasicHeader;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.util.StreamUtils;
|
|
||||||
import timely.api.request.AuthenticatedRequest;
|
import timely.api.request.AuthenticatedRequest;
|
||||||
|
import timely.api.request.HttpRequest;
|
||||||
import timely.api.request.MetricRequest;
|
import timely.api.request.MetricRequest;
|
||||||
import timely.api.request.timeseries.HttpRequest;
|
|
||||||
import timely.api.request.timeseries.QueryRequest;
|
import timely.api.request.timeseries.QueryRequest;
|
||||||
import timely.api.response.TimelyException;
|
import timely.api.response.TimelyException;
|
||||||
|
import timely.auth.TimelyAuthenticationToken;
|
||||||
import timely.auth.util.HttpHeaderUtils;
|
import timely.auth.util.HttpHeaderUtils;
|
||||||
import timely.auth.util.ProxiedEntityUtils;
|
import timely.auth.util.ProxiedEntityUtils;
|
||||||
|
import timely.balancer.MetricResolver;
|
||||||
|
import timely.balancer.configuration.BalancerHttpProperties;
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.balancer.connection.http.HttpClientPool;
|
import timely.balancer.connection.http.HttpClientPool;
|
||||||
import timely.balancer.resolver.MetricResolver;
|
|
||||||
import timely.netty.http.TimelyHttpHandler;
|
import timely.netty.http.TimelyHttpHandler;
|
||||||
import timely.netty.http.auth.TimelyAuthenticationToken;
|
|
||||||
|
|
||||||
public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> implements TimelyHttpHandler {
|
public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> implements TimelyHttpHandler {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(HttpRelayHandler.class);
|
private static final Logger log = LoggerFactory.getLogger(HttpRelayHandler.class);
|
||||||
|
private BalancerHttpProperties balancerHttpProperties;
|
||||||
private final HttpClientPool httpClientPool;
|
private final HttpClientPool httpClientPool;
|
||||||
private MetricResolver metricResolver;
|
private MetricResolver metricResolver;
|
||||||
|
private ExecutorService requestExecutor = Executors.newCachedThreadPool();
|
||||||
|
|
||||||
public HttpRelayHandler(MetricResolver metricResolver, HttpClientPool httpClientPool) {
|
public HttpRelayHandler(BalancerHttpProperties balancerHttpProperties, MetricResolver metricResolver, HttpClientPool httpClientPool) {
|
||||||
|
this.balancerHttpProperties = balancerHttpProperties;
|
||||||
this.metricResolver = metricResolver;
|
this.metricResolver = metricResolver;
|
||||||
this.httpClientPool = httpClientPool;
|
this.httpClientPool = httpClientPool;
|
||||||
}
|
}
|
||||||
@@ -65,6 +79,7 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
|||||||
CloseableHttpResponse relayedResponse = null;
|
CloseableHttpResponse relayedResponse = null;
|
||||||
FullHttpRequest request = null;
|
FullHttpRequest request = null;
|
||||||
try {
|
try {
|
||||||
|
String relayURI = "";
|
||||||
try {
|
try {
|
||||||
request = msg.getHttpRequest();
|
request = msg.getHttpRequest();
|
||||||
String originalURI = request.uri();
|
String originalURI = request.uri();
|
||||||
@@ -88,7 +103,7 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
|||||||
}
|
}
|
||||||
client = httpClientPool.borrowObject(k);
|
client = httpClientPool.borrowObject(k);
|
||||||
|
|
||||||
Multimap<String, String> headers = HttpHeaderUtils.toMultimap(request.headers());
|
Multimap<String,String> headers = HttpHeaderUtils.toMultimap(request.headers());
|
||||||
if (msg instanceof AuthenticatedRequest) {
|
if (msg instanceof AuthenticatedRequest) {
|
||||||
AuthenticatedRequest authenticatedRequest = (AuthenticatedRequest) msg;
|
AuthenticatedRequest authenticatedRequest = (AuthenticatedRequest) msg;
|
||||||
TimelyAuthenticationToken token = authenticatedRequest.getToken();
|
TimelyAuthenticationToken token = authenticatedRequest.getToken();
|
||||||
@@ -100,69 +115,62 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<Header> relayedHeaderList = new ArrayList<>();
|
List<Header> relayedHeaderList = new ArrayList<>();
|
||||||
for (Map.Entry<String, String> h : headers.entries()) {
|
for (Map.Entry<String,String> h : headers.entries()) {
|
||||||
if (!h.getKey().equals(CONTENT_LENGTH.toString())) {
|
if (!h.getKey().equals(CONTENT_LENGTH.toString())) {
|
||||||
relayedHeaderList.add(new BasicHeader(h.getKey(), h.getValue()));
|
relayedHeaderList.add(new BasicHeader(h.getKey(), h.getValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Header[] headerArray = new Header[relayedHeaderList.size()];
|
Header[] headerArray = new Header[relayedHeaderList.size()];
|
||||||
relayedHeaderList.toArray(headerArray);
|
relayedHeaderList.toArray(headerArray);
|
||||||
|
relayURI = "https://" + k.getHost() + ":" + k.getHttpPort() + originalURI;
|
||||||
String relayURI = "https://" + k.getHost() + ":" + k.getHttpPort() + originalURI;
|
HttpRequestBase relayedRequest = null;
|
||||||
if (request.method().equals(HttpMethod.GET)) {
|
if (request.method().equals(HttpMethod.GET)) {
|
||||||
HttpUriRequest relayedRequest = new HttpGet(relayURI);
|
relayedRequest = new HttpGet(relayURI);
|
||||||
if (headerArray.length > 0) {
|
|
||||||
relayedRequest.setHeaders(headerArray);
|
|
||||||
}
|
|
||||||
relayedResponse = client.execute(relayedRequest);
|
|
||||||
|
|
||||||
} else if (request.method().equals(HttpMethod.POST)) {
|
} else if (request.method().equals(HttpMethod.POST)) {
|
||||||
HttpPost relayedRequest = new HttpPost(relayURI);
|
relayedRequest = new HttpPost(relayURI);
|
||||||
|
|
||||||
String content = request.content().toString(StandardCharsets.UTF_8);
|
String content = request.content().toString(StandardCharsets.UTF_8);
|
||||||
StringEntity entity = new StringEntity(content);
|
StringEntity entity = new StringEntity(content);
|
||||||
relayedRequest.setEntity(entity);
|
((HttpPost) relayedRequest).setEntity(entity);
|
||||||
if (headerArray.length > 0) {
|
} else {
|
||||||
relayedRequest.setHeaders(headerArray);
|
throw new IllegalArgumentException("Unsupported HTTP method: " + request.method());
|
||||||
}
|
|
||||||
relayedResponse = client.execute(relayedRequest);
|
|
||||||
}
|
}
|
||||||
|
if (headerArray.length > 0) {
|
||||||
|
relayedRequest.setHeaders(headerArray);
|
||||||
|
}
|
||||||
|
relayedResponse = executeHttpRequest(client, relayedRequest, balancerHttpProperties.getRequestTimeout());
|
||||||
|
} catch (IOException e) {
|
||||||
|
String message = String.format("%s calling %s", e.getMessage() == null ? "" : e.getMessage(), relayURI);
|
||||||
|
log.error(message, e);
|
||||||
|
this.sendHttpError(ctx, new TimelyException(HttpResponseStatus.GATEWAY_TIMEOUT.code(), e.getMessage(), e.getLocalizedMessage(), e));
|
||||||
|
return;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String message = e.getMessage();
|
String message = e.getMessage();
|
||||||
if (message == null) {
|
if (message != null && message.contains("No matching tags")) {
|
||||||
LOG.error("", e);
|
log.trace(message);
|
||||||
} else {
|
} else {
|
||||||
if (message.contains("No matching tags")) {
|
message = String.format("%s calling %s", e.getMessage() == null ? "" : e.getMessage(), relayURI);
|
||||||
LOG.trace(message);
|
log.error(message, e);
|
||||||
} else {
|
|
||||||
LOG.error(message, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.sendHttpError(ctx, new TimelyException(HttpResponseStatus.INTERNAL_SERVER_ERROR.code(),
|
this.sendHttpError(ctx, new TimelyException(HttpResponseStatus.INTERNAL_SERVER_ERROR.code(), e.getMessage(), e.getLocalizedMessage(), e));
|
||||||
e.getMessage(), e.getLocalizedMessage(), e));
|
|
||||||
return;
|
return;
|
||||||
} finally {
|
|
||||||
if (request != null && request instanceof AutoCloseable) {
|
|
||||||
ReferenceCountUtil.release(request);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
FullHttpResponse response = null;
|
FullHttpResponse response;
|
||||||
if (relayedResponse == null) {
|
if (relayedResponse == null) {
|
||||||
this.sendHttpError(ctx, new TimelyException(HttpResponseStatus.METHOD_NOT_ALLOWED.code(),
|
this.sendHttpError(ctx, new TimelyException(HttpResponseStatus.METHOD_NOT_ALLOWED.code(), "Method not allowed", "Method not allowed"));
|
||||||
"Method not allowed", "Method not allowed"));
|
|
||||||
} else {
|
} else {
|
||||||
ByteArrayOutputStream baos = new MyByteArrayOutputStream();
|
ByteArrayOutputStream baos = new MyByteArrayOutputStream();
|
||||||
StreamUtils.copy(relayedResponse.getEntity().getContent(), baos);
|
StreamUtils.copy(relayedResponse.getEntity().getContent(), baos);
|
||||||
|
|
||||||
response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
|
response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(relayedResponse.getStatusLine().getStatusCode()),
|
||||||
HttpResponseStatus.valueOf(relayedResponse.getStatusLine().getStatusCode()),
|
Unpooled.copiedBuffer(baos.toByteArray()));
|
||||||
Unpooled.copiedBuffer(baos.toByteArray()));
|
|
||||||
for (Header h : relayedResponse.getAllHeaders()) {
|
for (Header h : relayedResponse.getAllHeaders()) {
|
||||||
response.headers().add(h.getName(), h.getValue());
|
response.headers().add(h.getName(), h.getValue());
|
||||||
}
|
}
|
||||||
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
|
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
|
||||||
sendResponse(ctx, response);
|
sendResponse(ctx, response);
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
} finally {
|
} finally {
|
||||||
if (relayedResponse != null) {
|
if (relayedResponse != null) {
|
||||||
relayedResponse.close();
|
relayedResponse.close();
|
||||||
@@ -170,15 +178,14 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
|||||||
if (client != null && k != null) {
|
if (client != null && k != null) {
|
||||||
httpClientPool.returnObject(k, client);
|
httpClientPool.returnObject(k, client);
|
||||||
} else {
|
} else {
|
||||||
LOG.error("NOT RETURNING CONNECTION! " + msg.getHttpRequest().uri());
|
log.error("NOT RETURNING CONNECTION! " + msg.getHttpRequest().uri());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static public class MyByteArrayOutputStream extends ByteArrayOutputStream {
|
static public class MyByteArrayOutputStream extends ByteArrayOutputStream {
|
||||||
|
|
||||||
public MyByteArrayOutputStream() {
|
public MyByteArrayOutputStream() {}
|
||||||
}
|
|
||||||
|
|
||||||
public MyByteArrayOutputStream(int size) {
|
public MyByteArrayOutputStream(int size) {
|
||||||
super(size);
|
super(size);
|
||||||
@@ -202,4 +209,22 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
|||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CloseableHttpResponse executeHttpRequest(CloseableHttpClient httpClient, HttpRequestBase relayedRequest, long timeout) throws Exception {
|
||||||
|
try {
|
||||||
|
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
|
||||||
|
requestConfigBuilder.setConnectionRequestTimeout(this.balancerHttpProperties.getConnectionRequestTimeout());
|
||||||
|
requestConfigBuilder.setConnectTimeout(this.balancerHttpProperties.getConnectTimeout());
|
||||||
|
requestConfigBuilder.setSocketTimeout(this.balancerHttpProperties.getSocketTimeout());
|
||||||
|
RequestConfig requestConfig = requestConfigBuilder.build();
|
||||||
|
relayedRequest.setConfig(requestConfig);
|
||||||
|
Future<CloseableHttpResponse> f = requestExecutor.submit(() -> httpClient.execute(relayedRequest));
|
||||||
|
return f.get(timeout, TimeUnit.MILLISECONDS);
|
||||||
|
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||||
|
Throwable cause = Throwables.getRootCause(e);
|
||||||
|
throw new IOException(cause.getMessage(), cause);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,50 +1,43 @@
|
|||||||
package timely.balancer.netty.tcp;
|
package timely.balancer.netty.tcp;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import timely.api.request.MetricRequest;
|
import timely.api.request.MetricRequest;
|
||||||
import timely.api.request.TcpRequest;
|
import timely.api.request.TcpRequest;
|
||||||
|
import timely.balancer.MetricResolver;
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.balancer.connection.tcp.TcpClientPool;
|
import timely.balancer.connection.tcp.TcpClientPool;
|
||||||
import timely.balancer.resolver.BalancedMetricResolver;
|
|
||||||
import timely.balancer.resolver.MetricResolver;
|
|
||||||
import timely.client.tcp.TcpClient;
|
import timely.client.tcp.TcpClient;
|
||||||
import timely.netty.Constants;
|
import timely.netty.Constants;
|
||||||
|
|
||||||
public class TcpRelayHandler extends SimpleChannelInboundHandler<TcpRequest> {
|
public class TcpRelayHandler extends SimpleChannelInboundHandler<TcpRequest> {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(TcpRelayHandler.class);
|
private static final Logger log = LoggerFactory.getLogger(TcpRelayHandler.class);
|
||||||
private static final String LOG_ERR_MSG = "Error storing put metric: {}";
|
private static final String LOG_ERR_MSG = "Error storing put metric: {}";
|
||||||
private static final String ERR_MSG = "Error storing put metric: ";
|
private static final String ERR_MSG = "Error storing put metric: ";
|
||||||
|
|
||||||
private BalancedMetricResolver metricResolver;
|
private MetricResolver metricResolver;
|
||||||
private List<TcpClientPool> tcpClientPools;
|
private TcpClientPool tcpClientPool;
|
||||||
|
|
||||||
public TcpRelayHandler(MetricResolver metricResolver, List<TcpClientPool> tcpClientPools) {
|
public TcpRelayHandler(MetricResolver metricResolver, TcpClientPool tcpClientPool) {
|
||||||
this.metricResolver = (BalancedMetricResolver) metricResolver;
|
this.metricResolver = metricResolver;
|
||||||
this.tcpClientPools = tcpClientPools;
|
this.tcpClientPool = tcpClientPool;
|
||||||
}
|
|
||||||
|
|
||||||
private TcpClientPool tcpClientPool() {
|
|
||||||
int x = Math.toIntExact(Thread.currentThread().getId() % tcpClientPools.size());
|
|
||||||
return tcpClientPools.get(x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void channelRead0(ChannelHandlerContext ctx, TcpRequest msg) throws Exception {
|
protected void channelRead0(ChannelHandlerContext ctx, TcpRequest msg) throws Exception {
|
||||||
LOG.trace("Received {}", msg);
|
log.trace("Received {}", msg);
|
||||||
try {
|
try {
|
||||||
String line;
|
String line;
|
||||||
Pair<TimelyBalancedHost, TcpClient> keyClientPair = null;
|
Pair<TimelyBalancedHost,TcpClient> keyClientPair = null;
|
||||||
try {
|
try {
|
||||||
if (msg instanceof MetricRequest) {
|
if (msg instanceof MetricRequest) {
|
||||||
String metricName = ((MetricRequest) msg).getMetric().getName();
|
String metricName = ((MetricRequest) msg).getMetric().getName();
|
||||||
@@ -58,34 +51,34 @@ public class TcpRelayHandler extends SimpleChannelInboundHandler<TcpRequest> {
|
|||||||
keyClientPair.getRight().write(line + "\n");
|
keyClientPair.getRight().write(line + "\n");
|
||||||
} finally {
|
} finally {
|
||||||
if (keyClientPair != null && keyClientPair.getLeft() != null && keyClientPair.getRight() != null) {
|
if (keyClientPair != null && keyClientPair.getLeft() != null && keyClientPair.getRight() != null) {
|
||||||
tcpClientPool().returnObject(keyClientPair.getLeft(), keyClientPair.getRight());
|
tcpClientPool.returnObject(keyClientPair.getLeft(), keyClientPair.getRight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
LOG.error(LOG_ERR_MSG, msg, e);
|
log.error(LOG_ERR_MSG, msg, e);
|
||||||
ChannelFuture cf = ctx.writeAndFlush(
|
ChannelFuture cf = ctx.writeAndFlush(Unpooled.copiedBuffer((ERR_MSG + e.getMessage() + "\n").getBytes(StandardCharsets.UTF_8)));
|
||||||
Unpooled.copiedBuffer((ERR_MSG + e.getMessage() + "\n").getBytes(StandardCharsets.UTF_8)));
|
|
||||||
if (!cf.isSuccess()) {
|
if (!cf.isSuccess()) {
|
||||||
LOG.error(Constants.ERR_WRITING_RESPONSE, cf.cause());
|
Throwable t = cf.cause();
|
||||||
|
String message = (t == null) ? "" : t.getMessage();
|
||||||
|
log.error(String.format(Constants.ERR_WRITING_RESPONSE, message), cf.cause());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<TimelyBalancedHost, TcpClient> getClient(String metric, boolean metricRequest) {
|
private Pair<TimelyBalancedHost,TcpClient> getClient(String metric, boolean metricRequest) {
|
||||||
TcpClient client = null;
|
TcpClient client = null;
|
||||||
TimelyBalancedHost k = null;
|
TimelyBalancedHost k = null;
|
||||||
int failures = 0;
|
int failures = 0;
|
||||||
while (client == null) {
|
while (client == null) {
|
||||||
try {
|
try {
|
||||||
k = (metricRequest == true) ? metricResolver.getHostPortKeyIngest(metric)
|
k = (metricRequest == true) ? metricResolver.getHostPortKeyIngest(metric) : metricResolver.getHostPortKey(metric);
|
||||||
: metricResolver.getHostPortKey(metric);
|
client = tcpClientPool.borrowObject(k);
|
||||||
client = tcpClientPool().borrowObject(k);
|
|
||||||
} catch (Exception e1) {
|
} catch (Exception e1) {
|
||||||
failures++;
|
failures++;
|
||||||
client = null;
|
client = null;
|
||||||
if (failures % 10 == 0) {
|
if (failures % 10 == 0) {
|
||||||
LOG.error(e1.getMessage(), e1);
|
log.error(e1.getMessage(), e1);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Thread.sleep(failures < 10 ? 500 : 60000);
|
Thread.sleep(failures < 10 ? 500 : 60000);
|
||||||
|
|||||||
@@ -2,24 +2,25 @@ package timely.balancer.netty.udp;
|
|||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import timely.api.request.MetricRequest;
|
import timely.api.request.MetricRequest;
|
||||||
import timely.api.request.UdpRequest;
|
import timely.api.request.UdpRequest;
|
||||||
|
import timely.balancer.MetricResolver;
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.balancer.connection.udp.UdpClientPool;
|
import timely.balancer.connection.udp.UdpClientPool;
|
||||||
import timely.balancer.resolver.MetricResolver;
|
|
||||||
import timely.client.udp.UdpClient;
|
import timely.client.udp.UdpClient;
|
||||||
import timely.netty.Constants;
|
import timely.netty.Constants;
|
||||||
|
|
||||||
public class UdpRelayHandler extends SimpleChannelInboundHandler<UdpRequest> {
|
public class UdpRelayHandler extends SimpleChannelInboundHandler<UdpRequest> {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(UdpRelayHandler.class);
|
private static final Logger log = LoggerFactory.getLogger(UdpRelayHandler.class);
|
||||||
private static final String LOG_ERR_MSG = "Error storing put metric: {}";
|
private static final String LOG_ERR_MSG = "Error storing put metric: {}";
|
||||||
private static final String ERR_MSG = "Error storing put metric: ";
|
private static final String ERR_MSG = "Error storing put metric: ";
|
||||||
|
|
||||||
@@ -33,11 +34,11 @@ public class UdpRelayHandler extends SimpleChannelInboundHandler<UdpRequest> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void channelRead0(ChannelHandlerContext ctx, UdpRequest msg) throws Exception {
|
protected void channelRead0(ChannelHandlerContext ctx, UdpRequest msg) throws Exception {
|
||||||
LOG.trace("Received {}", msg);
|
log.trace("Received {}", msg);
|
||||||
try {
|
try {
|
||||||
MetricRequest metricRequest = (MetricRequest) msg;
|
MetricRequest metricRequest = (MetricRequest) msg;
|
||||||
String metricName = metricRequest.getMetric().getName();
|
String metricName = metricRequest.getMetric().getName();
|
||||||
Pair<TimelyBalancedHost, UdpClient> keyClientPair = null;
|
Pair<TimelyBalancedHost,UdpClient> keyClientPair = null;
|
||||||
try {
|
try {
|
||||||
keyClientPair = getClient(metricName, true);
|
keyClientPair = getClient(metricName, true);
|
||||||
keyClientPair.getRight().write(metricRequest.getLine() + "\n");
|
keyClientPair.getRight().write(metricRequest.getLine() + "\n");
|
||||||
@@ -49,28 +50,28 @@ public class UdpRelayHandler extends SimpleChannelInboundHandler<UdpRequest> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(LOG_ERR_MSG, msg, e);
|
log.error(LOG_ERR_MSG, msg, e);
|
||||||
ChannelFuture cf = ctx.writeAndFlush(
|
ChannelFuture cf = ctx.writeAndFlush(Unpooled.copiedBuffer((ERR_MSG + e.getMessage() + "\n").getBytes(StandardCharsets.UTF_8)));
|
||||||
Unpooled.copiedBuffer((ERR_MSG + e.getMessage() + "\n").getBytes(StandardCharsets.UTF_8)));
|
|
||||||
if (!cf.isSuccess()) {
|
if (!cf.isSuccess()) {
|
||||||
LOG.error(Constants.ERR_WRITING_RESPONSE, cf.cause());
|
Throwable t = cf.cause();
|
||||||
|
String message = (t == null) ? "" : t.getMessage();
|
||||||
|
log.error(String.format(Constants.ERR_WRITING_RESPONSE, message), cf.cause());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<TimelyBalancedHost, UdpClient> getClient(String metric, boolean metricRequest) {
|
private Pair<TimelyBalancedHost,UdpClient> getClient(String metric, boolean metricRequest) {
|
||||||
UdpClient client = null;
|
UdpClient client = null;
|
||||||
TimelyBalancedHost k = null;
|
TimelyBalancedHost k = null;
|
||||||
int failures = 0;
|
int failures = 0;
|
||||||
while (client == null) {
|
while (client == null) {
|
||||||
try {
|
try {
|
||||||
k = (metricRequest == true) ? metricResolver.getHostPortKeyIngest(metric)
|
k = (metricRequest == true) ? metricResolver.getHostPortKeyIngest(metric) : metricResolver.getHostPortKey(metric);
|
||||||
: metricResolver.getHostPortKey(metric);
|
|
||||||
client = udpClientPool.borrowObject(k);
|
client = udpClientPool.borrowObject(k);
|
||||||
} catch (Exception e1) {
|
} catch (Exception e1) {
|
||||||
failures++;
|
failures++;
|
||||||
client = null;
|
client = null;
|
||||||
LOG.error(e1.getMessage(), e1);
|
log.error(e1.getMessage(), e1);
|
||||||
try {
|
try {
|
||||||
Thread.sleep(failures < 10 ? 500 : 60000);
|
Thread.sleep(failures < 10 ? 500 : 60000);
|
||||||
} catch (InterruptedException e2) {
|
} catch (InterruptedException e2) {
|
||||||
|
|||||||
@@ -9,23 +9,25 @@ import javax.websocket.CloseReason;
|
|||||||
import javax.websocket.EndpointConfig;
|
import javax.websocket.EndpointConfig;
|
||||||
import javax.websocket.Session;
|
import javax.websocket.Session;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.common.collect.HashMultimap;
|
import com.google.common.collect.HashMultimap;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||||
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
|
||||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||||
import io.netty.util.concurrent.ScheduledFuture;
|
import io.netty.util.concurrent.ScheduledFuture;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import timely.api.response.TimelyException;
|
import timely.api.response.TimelyException;
|
||||||
|
import timely.auth.TimelyAuthenticationToken;
|
||||||
import timely.auth.util.ProxiedEntityUtils;
|
import timely.auth.util.ProxiedEntityUtils;
|
||||||
import timely.client.websocket.ClientHandler;
|
import timely.client.websocket.ClientHandler;
|
||||||
import timely.netty.http.auth.TimelyAuthenticationToken;
|
|
||||||
|
|
||||||
public class WsClientHandler extends ClientHandler {
|
public class WsClientHandler extends ClientHandler {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(WsClientHandler.class);
|
private static final Logger log = LoggerFactory.getLogger(WsClientHandler.class);
|
||||||
private final ChannelHandlerContext ctx;
|
private final ChannelHandlerContext ctx;
|
||||||
private final TimelyAuthenticationToken token;
|
private final TimelyAuthenticationToken token;
|
||||||
private ScheduledFuture<?> ping;
|
private ScheduledFuture<?> ping;
|
||||||
@@ -34,22 +36,22 @@ public class WsClientHandler extends ClientHandler {
|
|||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.ping = this.ctx.executor().scheduleAtFixedRate(() -> {
|
this.ping = this.ctx.executor().scheduleAtFixedRate(() -> {
|
||||||
LOG.trace("Sending ping on channel {}", ctx.channel());
|
log.trace("Sending ping on channel {}", ctx.channel());
|
||||||
ctx.writeAndFlush(new PingWebSocketFrame());
|
ctx.writeAndFlush(new PingWebSocketFrame());
|
||||||
}, pingRate, pingRate, TimeUnit.SECONDS);
|
}, pingRate, pingRate, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beforeRequest(Map<String, List<String>> headers) {
|
public void beforeRequest(Map<String,List<String>> headers) {
|
||||||
if (token.getClientCert() != null) {
|
if (token.getClientCert() != null) {
|
||||||
Multimap<String, String> proxyRequestHeaders = HashMultimap.create();
|
Multimap<String,String> proxyRequestHeaders = HashMultimap.create();
|
||||||
ProxiedEntityUtils.addProxyHeaders(proxyRequestHeaders, token.getClientCert());
|
ProxiedEntityUtils.addProxyHeaders(proxyRequestHeaders, token.getClientCert());
|
||||||
for (String s : proxyRequestHeaders.keySet()) {
|
for (String s : proxyRequestHeaders.keySet()) {
|
||||||
headers.put(s, new ArrayList<>(proxyRequestHeaders.get(s)));
|
headers.put(s, new ArrayList<>(proxyRequestHeaders.get(s)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Multimap<String, String> originalRequestHeaders = token.getHttpHeaders();
|
Multimap<String,String> originalRequestHeaders = token.getHttpHeaders();
|
||||||
for (String s : originalRequestHeaders.keySet()) {
|
for (String s : originalRequestHeaders.keySet()) {
|
||||||
if (!headers.containsKey(s)) {
|
if (!headers.containsKey(s)) {
|
||||||
// add pre-existing values if key does not exist in proxyRequest
|
// add pre-existing values if key does not exist in proxyRequest
|
||||||
@@ -62,7 +64,7 @@ public class WsClientHandler extends ClientHandler {
|
|||||||
public void onOpen(Session session, EndpointConfig config) {
|
public void onOpen(Session session, EndpointConfig config) {
|
||||||
session.addMessageHandler(String.class, message -> {
|
session.addMessageHandler(String.class, message -> {
|
||||||
ctx.writeAndFlush(new TextWebSocketFrame(message));
|
ctx.writeAndFlush(new TextWebSocketFrame(message));
|
||||||
LOG.debug("Message received on Websocket session {}: {}", session.getId(), message);
|
log.debug("Message received on Websocket session {}: {}", session.getId(), message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,9 +72,8 @@ public class WsClientHandler extends ClientHandler {
|
|||||||
public void onClose(Session session, CloseReason reason) {
|
public void onClose(Session session, CloseReason reason) {
|
||||||
super.onClose(session, reason);
|
super.onClose(session, reason);
|
||||||
if (!reason.getCloseCode().equals(CloseReason.CloseCodes.NORMAL_CLOSURE)) {
|
if (!reason.getCloseCode().equals(CloseReason.CloseCodes.NORMAL_CLOSURE)) {
|
||||||
LOG.error("Abnormal close: " + reason.getReasonPhrase());
|
log.error("Abnormal close: " + reason.getReasonPhrase());
|
||||||
Exception e = new TimelyException(HttpResponseStatus.INTERNAL_SERVER_ERROR.code(), reason.getReasonPhrase(),
|
Exception e = new TimelyException(HttpResponseStatus.INTERNAL_SERVER_ERROR.code(), reason.getReasonPhrase(), "");
|
||||||
"");
|
|
||||||
WsRelayHandler.sendErrorResponse(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR, e);
|
WsRelayHandler.sendErrorResponse(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR, e);
|
||||||
}
|
}
|
||||||
if (!ping.isCancelled()) {
|
if (!ping.isCancelled()) {
|
||||||
@@ -83,7 +84,7 @@ public class WsClientHandler extends ClientHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void onError(Session session, Throwable t) {
|
public void onError(Session session, Throwable t) {
|
||||||
super.onError(session, t);
|
super.onError(session, t);
|
||||||
LOG.error(t.getMessage(), t);
|
log.error(t.getMessage(), t);
|
||||||
Exception e = new TimelyException(HttpResponseStatus.INTERNAL_SERVER_ERROR.code(), t.getMessage(), "");
|
Exception e = new TimelyException(HttpResponseStatus.INTERNAL_SERVER_ERROR.code(), t.getMessage(), "");
|
||||||
WsRelayHandler.sendErrorResponse(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR, e);
|
WsRelayHandler.sendErrorResponse(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR, e);
|
||||||
if (!ping.isCancelled()) {
|
if (!ping.isCancelled()) {
|
||||||
|
|||||||
@@ -4,15 +4,16 @@ import java.io.IOException;
|
|||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.balancer.connection.ws.WsClientPool;
|
import timely.balancer.connection.ws.WsClientPool;
|
||||||
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
|
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
|
||||||
|
|
||||||
public class WsClientHolder {
|
public class WsClientHolder {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(WsClientHolder.class);
|
private static final Logger log = LoggerFactory.getLogger(WsClientHolder.class);
|
||||||
private WebSocketSubscriptionClient client = null;
|
private WebSocketSubscriptionClient client;
|
||||||
private TimelyBalancedHost host = null;
|
private TimelyBalancedHost host;
|
||||||
|
|
||||||
public WsClientHolder(TimelyBalancedHost host, WebSocketSubscriptionClient client) {
|
public WsClientHolder(TimelyBalancedHost host, WebSocketSubscriptionClient client) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
@@ -32,7 +33,7 @@ public class WsClientHolder {
|
|||||||
try {
|
try {
|
||||||
client.close();
|
client.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.error("Error closing web socket client", e);
|
log.error("Error closing web socket client", e);
|
||||||
}
|
}
|
||||||
wsClientPool.returnObject(host, client);
|
wsClientPool.returnObject(host, client);
|
||||||
client = null;
|
client = null;
|
||||||
|
|||||||
@@ -5,11 +5,15 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
|
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelFutureListener;
|
import io.netty.channel.ChannelFutureListener;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
@@ -17,32 +21,30 @@ import io.netty.channel.SimpleChannelInboundHandler;
|
|||||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||||
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
|
||||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||||
import org.slf4j.Logger;
|
import timely.api.request.websocket.AddSubscription;
|
||||||
import org.slf4j.LoggerFactory;
|
import timely.api.request.websocket.CloseSubscription;
|
||||||
import timely.api.request.subscription.AddSubscription;
|
import timely.api.request.websocket.CreateSubscription;
|
||||||
import timely.api.request.subscription.CloseSubscription;
|
import timely.api.request.websocket.RemoveSubscription;
|
||||||
import timely.api.request.subscription.CreateSubscription;
|
import timely.api.request.websocket.SubscriptionRequest;
|
||||||
import timely.api.request.subscription.RemoveSubscription;
|
|
||||||
import timely.api.request.subscription.SubscriptionRequest;
|
|
||||||
import timely.api.response.TimelyException;
|
import timely.api.response.TimelyException;
|
||||||
import timely.auth.util.ProxiedEntityUtils;
|
import timely.auth.util.ProxiedEntityUtils;
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
import timely.balancer.MetricResolver;
|
||||||
|
import timely.balancer.configuration.BalancerWebsocketProperties;
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.balancer.connection.ws.WsClientPool;
|
import timely.balancer.connection.ws.WsClientPool;
|
||||||
import timely.balancer.resolver.MetricResolver;
|
|
||||||
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
|
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
|
||||||
import timely.netty.http.TimelyHttpHandler;
|
import timely.netty.http.TimelyHttpHandler;
|
||||||
|
|
||||||
public class WsRelayHandler extends SimpleChannelInboundHandler<SubscriptionRequest> implements TimelyHttpHandler {
|
public class WsRelayHandler extends SimpleChannelInboundHandler<SubscriptionRequest> implements TimelyHttpHandler {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(WsRelayHandler.class);
|
private static final Logger log = LoggerFactory.getLogger(WsRelayHandler.class);
|
||||||
|
|
||||||
private final BalancerConfiguration balancerConfig;
|
private BalancerWebsocketProperties balancerWebsocketProperties;
|
||||||
private final WsClientPool wsClientPool;
|
private WsClientPool wsClientPool;
|
||||||
private MetricResolver metricResolver;
|
private MetricResolver metricResolver;
|
||||||
static private ObjectMapper mapper;
|
static private ObjectMapper mapper;
|
||||||
Map<String, Map<String, WsClientHolder>> wsClients = new ConcurrentHashMap<>();
|
Map<String,Map<String,WsClientHolder>> wsClients = new ConcurrentHashMap<>();
|
||||||
Map<String, ChannelHandlerContext> wsSubscriptions = new ConcurrentHashMap<>();
|
Map<String,ChannelHandlerContext> wsSubscriptions = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
mapper = new ObjectMapper();
|
mapper = new ObjectMapper();
|
||||||
@@ -52,9 +54,8 @@ public class WsRelayHandler extends SimpleChannelInboundHandler<SubscriptionRequ
|
|||||||
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
|
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public WsRelayHandler(BalancerConfiguration balancerConfig, MetricResolver metricResolver,
|
public WsRelayHandler(BalancerWebsocketProperties balancerWebsocketProperties, MetricResolver metricResolver, WsClientPool wsClientPool) {
|
||||||
WsClientPool wsClientPool) {
|
this.balancerWebsocketProperties = balancerWebsocketProperties;
|
||||||
this.balancerConfig = balancerConfig;
|
|
||||||
this.metricResolver = metricResolver;
|
this.metricResolver = metricResolver;
|
||||||
this.wsClientPool = wsClientPool;
|
this.wsClientPool = wsClientPool;
|
||||||
}
|
}
|
||||||
@@ -67,7 +68,7 @@ public class WsRelayHandler extends SimpleChannelInboundHandler<SubscriptionRequ
|
|||||||
try {
|
try {
|
||||||
String metric = null;
|
String metric = null;
|
||||||
|
|
||||||
Multimap<String, String> headers = msg.getRequestHeaders();
|
Multimap<String,String> headers = msg.getRequestHeaders();
|
||||||
ProxiedEntityUtils.addProxyHeaders(headers, msg.getToken().getClientCert());
|
ProxiedEntityUtils.addProxyHeaders(headers, msg.getToken().getClientCert());
|
||||||
|
|
||||||
if (msg instanceof CreateSubscription) {
|
if (msg instanceof CreateSubscription) {
|
||||||
@@ -83,14 +84,13 @@ public class WsRelayHandler extends SimpleChannelInboundHandler<SubscriptionRequ
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
public void operationComplete(ChannelFuture future) throws Exception {
|
||||||
Map<String, WsClientHolder> metricToClientMap = wsClients.get(currentSubscriptionId);
|
Map<String,WsClientHolder> metricToClientMap = wsClients.get(currentSubscriptionId);
|
||||||
|
|
||||||
if (metricToClientMap != null) {
|
if (metricToClientMap != null) {
|
||||||
synchronized (metricToClientMap) {
|
synchronized (metricToClientMap) {
|
||||||
// close all clients for this subscriptionId
|
// close all clients for this subscriptionId
|
||||||
LOG.info("Channel closed, closing subscriptions for subscriptionId:%s",
|
log.debug("Channel closed, closing subscriptions for subscriptionId:{}", currentSubscriptionId);
|
||||||
currentSubscriptionId);
|
for (Map.Entry<String,WsClientHolder> entry : metricToClientMap.entrySet()) {
|
||||||
for (Map.Entry<String, WsClientHolder> entry : metricToClientMap.entrySet()) {
|
|
||||||
entry.getValue().close(wsClientPool);
|
entry.getValue().close(wsClientPool);
|
||||||
}
|
}
|
||||||
wsClients.remove(currentSubscriptionId);
|
wsClients.remove(currentSubscriptionId);
|
||||||
@@ -108,12 +108,10 @@ public class WsRelayHandler extends SimpleChannelInboundHandler<SubscriptionRequ
|
|||||||
if (origContext == null) {
|
if (origContext == null) {
|
||||||
// send error because user never sent a CreateSubscription
|
// send error because user never sent a CreateSubscription
|
||||||
// and we have nowhere to send the results
|
// and we have nowhere to send the results
|
||||||
LOG.info("ChannelHandlerContext not found for subscriptionId:%s - createSubscription not called?",
|
log.info("ChannelHandlerContext not found for subscriptionId:{} - createSubscription not called?", subscriptionId);
|
||||||
subscriptionId);
|
sendErrorResponse(ctx, HttpResponseStatus.BAD_REQUEST, new IllegalArgumentException("Must call create first"));
|
||||||
sendErrorResponse(ctx, HttpResponseStatus.BAD_REQUEST,
|
|
||||||
new IllegalArgumentException("Must call create first"));
|
|
||||||
}
|
}
|
||||||
Map<String, WsClientHolder> metricToClientMap = wsClients.get(subscriptionId);
|
Map<String,WsClientHolder> metricToClientMap = wsClients.get(subscriptionId);
|
||||||
if (metricToClientMap == null) {
|
if (metricToClientMap == null) {
|
||||||
metricToClientMap = new HashMap<>();
|
metricToClientMap = new HashMap<>();
|
||||||
wsClients.put(subscriptionId, metricToClientMap);
|
wsClients.put(subscriptionId, metricToClientMap);
|
||||||
@@ -124,14 +122,13 @@ public class WsRelayHandler extends SimpleChannelInboundHandler<SubscriptionRequ
|
|||||||
if (hostClientHolder == null) {
|
if (hostClientHolder == null) {
|
||||||
k = metricResolver.getHostPortKey(metric);
|
k = metricResolver.getHostPortKey(metric);
|
||||||
client = wsClientPool.borrowObject(k);
|
client = wsClientPool.borrowObject(k);
|
||||||
client.open(new WsClientHandler(origContext, add.getToken(),
|
client.open(new WsClientHandler(origContext, add.getToken(), (balancerWebsocketProperties.getTimeout() / 2)));
|
||||||
(balancerConfig.getWebsocket().getTimeout() / 2)));
|
|
||||||
metricToClientMap.put(metric, new WsClientHolder(k, client));
|
metricToClientMap.put(metric, new WsClientHolder(k, client));
|
||||||
} else {
|
} else {
|
||||||
client = hostClientHolder.getClient();
|
client = hostClientHolder.getClient();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Map<String, String> tags = null;
|
Map<String,String> tags = null;
|
||||||
|
|
||||||
Long startTime = 0L;
|
Long startTime = 0L;
|
||||||
Long endTime = 0L;
|
Long endTime = 0L;
|
||||||
@@ -155,25 +152,25 @@ public class WsRelayHandler extends SimpleChannelInboundHandler<SubscriptionRequ
|
|||||||
RemoveSubscription remove = (RemoveSubscription) msg;
|
RemoveSubscription remove = (RemoveSubscription) msg;
|
||||||
metric = remove.getMetric();
|
metric = remove.getMetric();
|
||||||
subscriptionId = remove.getSubscriptionId();
|
subscriptionId = remove.getSubscriptionId();
|
||||||
Map<String, WsClientHolder> metricToClientMap = wsClients.get(subscriptionId);
|
Map<String,WsClientHolder> metricToClientMap = wsClients.get(subscriptionId);
|
||||||
if (metricToClientMap != null) {
|
if (metricToClientMap != null) {
|
||||||
synchronized (metricToClientMap) {
|
synchronized (metricToClientMap) {
|
||||||
WsClientHolder hostClientHolder = metricToClientMap.get(metric);
|
WsClientHolder hostClientHolder = metricToClientMap.get(metric);
|
||||||
if (hostClientHolder != null) {
|
if (hostClientHolder != null) {
|
||||||
hostClientHolder.getClient().removeSubscription(metric);
|
hostClientHolder.getClient().removeSubscription(metric);
|
||||||
} else {
|
} else {
|
||||||
LOG.info("client not found for subscriptionId:%s metric:%s", subscriptionId, metric);
|
log.info("client not found for subscriptionId:{} metric:{}", subscriptionId, metric);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (msg instanceof CloseSubscription) {
|
} else if (msg instanceof CloseSubscription) {
|
||||||
CloseSubscription close = (CloseSubscription) msg;
|
CloseSubscription close = (CloseSubscription) msg;
|
||||||
subscriptionId = close.getSubscriptionId();
|
subscriptionId = close.getSubscriptionId();
|
||||||
Map<String, WsClientHolder> metricToClientMap = wsClients.get(subscriptionId);
|
Map<String,WsClientHolder> metricToClientMap = wsClients.get(subscriptionId);
|
||||||
if (metricToClientMap != null) {
|
if (metricToClientMap != null) {
|
||||||
synchronized (metricToClientMap) {
|
synchronized (metricToClientMap) {
|
||||||
// close all clients for this subscriptionId
|
// close all clients for this subscriptionId
|
||||||
for (Map.Entry<String, WsClientHolder> entry : metricToClientMap.entrySet()) {
|
for (Map.Entry<String,WsClientHolder> entry : metricToClientMap.entrySet()) {
|
||||||
entry.getValue().close(wsClientPool);
|
entry.getValue().close(wsClientPool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,11 +180,11 @@ public class WsRelayHandler extends SimpleChannelInboundHandler<SubscriptionRequ
|
|||||||
ctx.writeAndFlush(new CloseWebSocketFrame(1000, "Client requested close."));
|
ctx.writeAndFlush(new CloseWebSocketFrame(1000, "Client requested close."));
|
||||||
}
|
}
|
||||||
} catch (ConnectException e1) {
|
} catch (ConnectException e1) {
|
||||||
LOG.error(e1.getMessage(), e1);
|
log.error(e1.getMessage(), e1);
|
||||||
ChannelHandlerContext errorCtx = origContext == null ? ctx : origContext;
|
ChannelHandlerContext errorCtx = origContext == null ? ctx : origContext;
|
||||||
sendErrorResponse(errorCtx, HttpResponseStatus.INTERNAL_SERVER_ERROR, e1);
|
sendErrorResponse(errorCtx, HttpResponseStatus.INTERNAL_SERVER_ERROR, e1);
|
||||||
} catch (Exception e2) {
|
} catch (Exception e2) {
|
||||||
LOG.error(e2.getMessage(), e2);
|
log.error(e2.getMessage(), e2);
|
||||||
ChannelHandlerContext errorCtx = origContext == null ? ctx : origContext;
|
ChannelHandlerContext errorCtx = origContext == null ? ctx : origContext;
|
||||||
sendErrorResponse(errorCtx, HttpResponseStatus.INTERNAL_SERVER_ERROR, e2);
|
sendErrorResponse(errorCtx, HttpResponseStatus.INTERNAL_SERVER_ERROR, e2);
|
||||||
}
|
}
|
||||||
@@ -201,7 +198,7 @@ public class WsRelayHandler extends SimpleChannelInboundHandler<SubscriptionRequ
|
|||||||
String json = mapper.writeValueAsString(te);
|
String json = mapper.writeValueAsString(te);
|
||||||
ctx.writeAndFlush(new TextWebSocketFrame(json));
|
ctx.writeAndFlush(new TextWebSocketFrame(json));
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
LOG.error("Error serializing exception");
|
log.error("Error serializing exception");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package timely.balancer.resolver;
|
|
||||||
|
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
|
||||||
|
|
||||||
public interface MetricResolver {
|
|
||||||
|
|
||||||
public TimelyBalancedHost getHostPortKeyIngest(String metric);
|
|
||||||
|
|
||||||
public TimelyBalancedHost getHostPortKey(String metric);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
===============================================================================
|
||||||
|
_______ _ _ ____ _
|
||||||
|
|__ __(_) | | | _ \ | |
|
||||||
|
| | _ _ __ ___ ___| |_ _ | |_) | __ _| | __ _ _ __ ___ ___ _ __
|
||||||
|
| | | | '_ ` _ \ / _ \ | | | | | _ < / _` | |/ _` | '_ \ / __/ _ \ '__|
|
||||||
|
| | | | | | | | | __/ | |_| | | |_) | (_| | | (_| | | | | (_| __/ |
|
||||||
|
|_| |_|_| |_| |_|\___|_|\__, | |____/ \__,_|_|\__,_|_| |_|\___\___|_|
|
||||||
|
__/ |
|
||||||
|
|___/
|
||||||
|
===============================================================================
|
||||||
|
TimelyBalancer ${application.formatted-version}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: timely-balancer
|
||||||
|
config:
|
||||||
|
name: timely-balancer
|
||||||
|
location: ${CONF_DIR}/
|
||||||
@@ -10,4 +10,12 @@
|
|||||||
<Method name="getBuf" />
|
<Method name="getBuf" />
|
||||||
<Bug pattern="EI_EXPOSE_REP" />
|
<Bug pattern="EI_EXPOSE_REP" />
|
||||||
</Match>
|
</Match>
|
||||||
|
<Match>
|
||||||
|
<!-- these are probably avoidable, but needs further triage to fix -->
|
||||||
|
<Bug pattern="EI_EXPOSE_REP" />
|
||||||
|
</Match>
|
||||||
|
<Match>
|
||||||
|
<!-- these are probably avoidable, but needs further triage to fix -->
|
||||||
|
<Bug pattern="EI_EXPOSE_REP2" />
|
||||||
|
</Match>
|
||||||
</FindBugsFilter>
|
</FindBugsFilter>
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package timely.balancer.configuration;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import io.netty.handler.ssl.SslContext;
|
||||||
|
import timely.balancer.HealthChecker;
|
||||||
|
import timely.balancer.MetricResolver;
|
||||||
|
import timely.balancer.test.TestBalancer;
|
||||||
|
import timely.balancer.test.TestHealthChecker;
|
||||||
|
import timely.balancer.test.TestMetricResolver;
|
||||||
|
import timely.common.component.AuthenticationService;
|
||||||
|
import timely.common.configuration.CacheProperties;
|
||||||
|
import timely.common.configuration.SecurityProperties;
|
||||||
|
import timely.common.configuration.SslClientProperties;
|
||||||
|
import timely.common.configuration.SslServerProperties;
|
||||||
|
import timely.common.configuration.ZookeeperProperties;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan(basePackages = {"timely.balancer", "timely.common", "timely.test"})
|
||||||
|
public class TestBalancerConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TestBalancer balancer(ApplicationContext applicationContext, @Qualifier("nettySslContext") SslContext serverSslContext,
|
||||||
|
@Qualifier("outboundJDKSslContext") SSLContext clientSSLContext, AuthenticationService authenticationService, MetricResolver metricResolver,
|
||||||
|
BalancerProperties balancerProperties, ZookeeperProperties zookeeperProperties, SecurityProperties securityProperties,
|
||||||
|
SslServerProperties sslServerProperties, SslClientProperties sslClientProperties, BalancerServerProperties balancerServerProperties,
|
||||||
|
BalancerHttpProperties balancerHttpProperties, BalancerWebsocketProperties balancerWebsocketProperties) {
|
||||||
|
TestBalancer balancer = new TestBalancer(applicationContext, serverSslContext, clientSSLContext, authenticationService, metricResolver,
|
||||||
|
balancerProperties, zookeeperProperties, securityProperties, sslServerProperties, sslClientProperties, balancerServerProperties,
|
||||||
|
balancerHttpProperties, balancerWebsocketProperties);
|
||||||
|
balancer.start();
|
||||||
|
return balancer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TestHealthChecker healthChecker(BalancerProperties balancerProperties, BalancerServerProperties balancerServerProperties) {
|
||||||
|
TestHealthChecker healthChecker = new TestHealthChecker(balancerProperties, balancerServerProperties);
|
||||||
|
healthChecker.start();
|
||||||
|
return healthChecker;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TestMetricResolver metricResolver(CuratorFramework curatorFramework, BalancerProperties balancerProperties, CacheProperties cacheProperties,
|
||||||
|
HealthChecker healthChecker) throws Exception {
|
||||||
|
TestMetricResolver metricResolver = new TestMetricResolver(curatorFramework, balancerProperties, cacheProperties, healthChecker);
|
||||||
|
metricResolver.start();
|
||||||
|
return metricResolver;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package timely.balancer.configuration;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import org.apache.zookeeper.server.ServerConfig;
|
||||||
|
import org.apache.zookeeper.server.ZooKeeperServerMain;
|
||||||
|
import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import timely.common.configuration.ZookeeperProperties;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnProperty(name = "timely.in-memory-accumulo.enabled", havingValue = "true")
|
||||||
|
public class TestZookeeperConfiguration {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(TestZookeeperConfiguration.class);
|
||||||
|
private static final int MAX_PORT = 100;
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
private ZookeeperProperties zookeeperProperties;
|
||||||
|
|
||||||
|
@Bean(name = "ZooKeeperServerMain", destroyMethod = "close")
|
||||||
|
public ZooKeeperServerMain zooKeeperServerMain(ZookeeperProperties zookeeperProperties) throws Exception {
|
||||||
|
this.zookeeperProperties = zookeeperProperties;
|
||||||
|
this.port = getNextPort(2181);
|
||||||
|
this.zookeeperProperties.setServers(String.format("localhost:%d", port));
|
||||||
|
|
||||||
|
File tempDir;
|
||||||
|
try {
|
||||||
|
tempDir = Files.createTempDirectory("zookeeper_temp").toFile();
|
||||||
|
tempDir.deleteOnExit();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Unable to create temp directory for mini accumulo cluster");
|
||||||
|
}
|
||||||
|
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.put("dataDir", tempDir.getAbsolutePath() + "/data");
|
||||||
|
properties.put("clientPort", port);
|
||||||
|
properties.put("skipACL", "true");
|
||||||
|
properties.put("leaderServes", "yes");
|
||||||
|
properties.put("4lw.commands.whitelist", "*");
|
||||||
|
properties.put("admin.enableServer", "false");
|
||||||
|
QuorumPeerConfig quorumPeerConfig = new QuorumPeerConfig();
|
||||||
|
quorumPeerConfig.parseProperties(properties);
|
||||||
|
|
||||||
|
ZooKeeperServerMain zookeeper = new ZooKeeperServerMain();
|
||||||
|
final ServerConfig config = new ServerConfig();
|
||||||
|
config.readFrom(quorumPeerConfig);
|
||||||
|
Executors.newSingleThreadExecutor().submit(() -> {
|
||||||
|
try {
|
||||||
|
zookeeper.runFromConfig(config);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
log.info("Started TestZookeeper on port {}", port);
|
||||||
|
return zookeeper;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getNextPort(int start) {
|
||||||
|
for (int port = start; port < start + MAX_PORT; ++port) {
|
||||||
|
try {
|
||||||
|
new ServerSocket(port).close();
|
||||||
|
return port;
|
||||||
|
} catch (IOException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package timely.balancer.integration;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.experimental.categories.Category;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
import timely.balancer.configuration.BalancerHttpProperties;
|
||||||
|
import timely.netty.http.HttpStrictTransportSecurityHandler;
|
||||||
|
import timely.test.IntegrationTest;
|
||||||
|
import timely.test.TimelyTestRule;
|
||||||
|
|
||||||
|
@Category(IntegrationTest.class)
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
|
||||||
|
public class HTTPStrictTransportSecurityIT {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Rule
|
||||||
|
public TimelyTestRule testRule;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BalancerHttpProperties httpProperties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected SSLContext clientSslContext;
|
||||||
|
|
||||||
|
private String baseHttpUrl;
|
||||||
|
private String baseHttpsUrl;
|
||||||
|
private String HSTS_HEADER_VALUE;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
baseHttpUrl = "http://" + httpProperties.getHost() + ":" + httpProperties.getPort();
|
||||||
|
baseHttpsUrl = "https://" + httpProperties.getHost() + ":" + httpProperties.getPort();
|
||||||
|
HSTS_HEADER_VALUE = String.format("max-age=%d; includeSubDomains; preload", httpProperties.getStrictTransportMaxAge());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SSLSocketFactory getSSLSocketFactory() throws Exception {
|
||||||
|
return clientSslContext.getSocketFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HttpsURLConnection getUrlConnection(URL url) throws Exception {
|
||||||
|
HttpsURLConnection.setDefaultSSLSocketFactory(getSSLSocketFactory());
|
||||||
|
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||||
|
con.setHostnameVerifier((host, session) -> true);
|
||||||
|
return con;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHttpRequest() throws Exception {
|
||||||
|
URL url = new URL(baseHttpUrl + "/api/metrics");
|
||||||
|
HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
||||||
|
con.setRequestMethod("GET");
|
||||||
|
int responseCode = con.getResponseCode();
|
||||||
|
assertEquals(403, responseCode);
|
||||||
|
// should not have HSTS header on HTTP response
|
||||||
|
assertNull(con.getHeaderField(HttpStrictTransportSecurityHandler.HSTS_HEADER_NAME));
|
||||||
|
con.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHttpsRequestHSTS() throws Exception {
|
||||||
|
URL url = new URL(baseHttpsUrl + "/version");
|
||||||
|
HttpsURLConnection con = getUrlConnection(url);
|
||||||
|
int responseCode = con.getResponseCode();
|
||||||
|
assertEquals(200, responseCode);
|
||||||
|
assertEquals(HSTS_HEADER_VALUE, con.getHeaderField(HttpStrictTransportSecurityHandler.HSTS_HEADER_NAME));
|
||||||
|
con.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHttpsRequestNotFound() throws Exception {
|
||||||
|
URL url = new URL(baseHttpsUrl);
|
||||||
|
HttpsURLConnection con = getUrlConnection(url);
|
||||||
|
int responseCode = con.getResponseCode();
|
||||||
|
assertEquals(404, responseCode);
|
||||||
|
assertEquals(HSTS_HEADER_VALUE, con.getHeaderField(HttpStrictTransportSecurityHandler.HSTS_HEADER_NAME));
|
||||||
|
con.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
package timely.balancer.integration;
|
||||||
|
|
||||||
|
import static timely.Constants.SERVICE_DISCOVERY_PATH;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
|
import org.apache.curator.framework.state.ConnectionState;
|
||||||
|
import org.apache.curator.x.discovery.ServiceCache;
|
||||||
|
import org.apache.curator.x.discovery.ServiceDiscovery;
|
||||||
|
import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
|
||||||
|
import org.apache.curator.x.discovery.ServiceInstance;
|
||||||
|
import org.apache.curator.x.discovery.ServiceInstanceBuilder;
|
||||||
|
import org.apache.curator.x.discovery.details.ServiceCacheListener;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.experimental.categories.Category;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
import timely.ServerDetails;
|
||||||
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
import timely.balancer.test.TestHealthChecker;
|
||||||
|
import timely.balancer.test.TestMetricResolver;
|
||||||
|
import timely.test.IntegrationTest;
|
||||||
|
import timely.test.TimelyTestRule;
|
||||||
|
|
||||||
|
@Category(IntegrationTest.class)
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
|
||||||
|
public class MetricResolverIT {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(MetricResolverIT.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Rule
|
||||||
|
public TimelyTestRule testRule;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TestMetricResolver metricResolver;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TestHealthChecker healthChecker;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CuratorFramework curatorFramework;
|
||||||
|
|
||||||
|
private ServiceDiscovery<ServerDetails> discovery;
|
||||||
|
private ServiceCache<ServerDetails> serviceCache;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws Exception {
|
||||||
|
discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class).client(curatorFramework).basePath(SERVICE_DISCOVERY_PATH).build();
|
||||||
|
discovery.start();
|
||||||
|
serviceCache = discovery.serviceCacheBuilder().name("timely-server").build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ServiceRegistrationTest() {
|
||||||
|
LinkedBlockingQueue<List<ServiceInstance<ServerDetails>>> updateQueue = getServiceUpdateQueue(serviceCache);
|
||||||
|
registerService(curatorFramework, TimelyBalancedHost.of("host1", 5242, 5243, 5244, 5245, null));
|
||||||
|
registerService(curatorFramework, TimelyBalancedHost.of("host1", 5342, 5343, 5344, 5345, null));
|
||||||
|
registerService(curatorFramework, TimelyBalancedHost.of("host1", 5442, 5443, 5444, 5445, null));
|
||||||
|
registerService(curatorFramework, TimelyBalancedHost.of("host1", 5542, 5543, 5544, 5545, null));
|
||||||
|
try {
|
||||||
|
List<ServiceInstance<ServerDetails>> currentUpdate;
|
||||||
|
List<ServiceInstance<ServerDetails>> lastUpdate = null;
|
||||||
|
do {
|
||||||
|
currentUpdate = updateQueue.poll(200, TimeUnit.MILLISECONDS);
|
||||||
|
if (currentUpdate != null) {
|
||||||
|
lastUpdate = currentUpdate;
|
||||||
|
}
|
||||||
|
} while (currentUpdate != null);
|
||||||
|
Assert.assertNotNull(lastUpdate);
|
||||||
|
Assert.assertEquals(4, lastUpdate.size());
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Assert.fail("" + e.getMessage());
|
||||||
|
}
|
||||||
|
Assert.assertEquals(4, metricResolver.getServerList().size());
|
||||||
|
Assert.assertEquals(4, healthChecker.getTimelyHosts().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerService(CuratorFramework curatorFramework, TimelyBalancedHost server) {
|
||||||
|
try {
|
||||||
|
ServerDetails payload = new ServerDetails();
|
||||||
|
payload.setHost(server.getHost());
|
||||||
|
payload.setTcpPort(server.getTcpPort());
|
||||||
|
payload.setHttpPort(server.getHttpPort());
|
||||||
|
payload.setWsPort(server.getWsPort());
|
||||||
|
payload.setUdpPort(server.getUdpPort());
|
||||||
|
|
||||||
|
ServiceInstanceBuilder<ServerDetails> builder = ServiceInstance.builder();
|
||||||
|
String serviceName = server.getHost() + ":" + server.getTcpPort();
|
||||||
|
ServiceInstance<ServerDetails> serviceInstance = builder.id(serviceName).name("timely-server").address(server.getHost()).port(server.getTcpPort())
|
||||||
|
.payload(payload).build();
|
||||||
|
|
||||||
|
ServiceDiscovery<ServerDetails> discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class).client(curatorFramework)
|
||||||
|
.basePath(SERVICE_DISCOVERY_PATH).build();
|
||||||
|
discovery.start();
|
||||||
|
discovery.registerService(serviceInstance);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinkedBlockingQueue<List<ServiceInstance<ServerDetails>>> getServiceUpdateQueue(ServiceCache<ServerDetails> serviceCache) {
|
||||||
|
|
||||||
|
LinkedBlockingQueue<List<ServiceInstance<ServerDetails>>> updates = new LinkedBlockingQueue<>();
|
||||||
|
try {
|
||||||
|
|
||||||
|
ServiceCacheListener listener = new ServiceCacheListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cacheChanged() {
|
||||||
|
updates.add(serviceCache.getInstances());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
serviceCache.addListener(listener);
|
||||||
|
serviceCache.start();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return updates;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package timely.balancer.test;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
|
import io.netty.handler.ssl.SslContext;
|
||||||
|
import timely.balancer.Balancer;
|
||||||
|
import timely.balancer.MetricResolver;
|
||||||
|
import timely.balancer.configuration.BalancerHttpProperties;
|
||||||
|
import timely.balancer.configuration.BalancerProperties;
|
||||||
|
import timely.balancer.configuration.BalancerServerProperties;
|
||||||
|
import timely.balancer.configuration.BalancerWebsocketProperties;
|
||||||
|
import timely.common.component.AuthenticationService;
|
||||||
|
import timely.common.configuration.SecurityProperties;
|
||||||
|
import timely.common.configuration.SslClientProperties;
|
||||||
|
import timely.common.configuration.SslServerProperties;
|
||||||
|
import timely.common.configuration.ZookeeperProperties;
|
||||||
|
|
||||||
|
public class TestBalancer extends Balancer {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(TestBalancer.class);
|
||||||
|
|
||||||
|
public TestBalancer(ApplicationContext applicationContext, SslContext serverSslContext, SSLContext clientSSLContext,
|
||||||
|
AuthenticationService authenticationService, MetricResolver metricResolver, BalancerProperties balancerProperties,
|
||||||
|
ZookeeperProperties zookeeperProperties, SecurityProperties securityProperties, SslServerProperties sslServerProperties,
|
||||||
|
SslClientProperties sslClientProperties, BalancerServerProperties balancerServerProperties, BalancerHttpProperties balancerHttpProperties,
|
||||||
|
BalancerWebsocketProperties balancerWebsocketProperties) {
|
||||||
|
super(applicationContext, serverSslContext, clientSSLContext, authenticationService, metricResolver, balancerProperties, zookeeperProperties,
|
||||||
|
securityProperties, sslServerProperties, sslClientProperties, balancerServerProperties, balancerHttpProperties,
|
||||||
|
balancerWebsocketProperties);
|
||||||
|
DEFAULT_EVENT_LOOP_THREADS = 1;
|
||||||
|
log.info("Starting TestBalancer");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package timely.balancer.test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import timely.balancer.HealthChecker;
|
||||||
|
import timely.balancer.configuration.BalancerProperties;
|
||||||
|
import timely.balancer.configuration.BalancerServerProperties;
|
||||||
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
|
||||||
|
public class TestHealthChecker extends HealthChecker {
|
||||||
|
|
||||||
|
public TestHealthChecker(BalancerProperties balancerProperties, BalancerServerProperties balancerServerProperties) {
|
||||||
|
super(balancerProperties, balancerServerProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TimelyBalancedHost> getTimelyHosts() {
|
||||||
|
return this.timelyHosts;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package timely.balancer.test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import timely.balancer.HealthChecker;
|
||||||
|
import timely.balancer.MetricResolver;
|
||||||
|
import timely.balancer.configuration.BalancerProperties;
|
||||||
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
import timely.common.configuration.CacheProperties;
|
||||||
|
|
||||||
|
public class TestMetricResolver extends MetricResolver {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(TestMetricResolver.class);
|
||||||
|
|
||||||
|
public TestMetricResolver(CuratorFramework curatorFramework, BalancerProperties balancerProperties, CacheProperties cacheProperties,
|
||||||
|
HealthChecker healthChecker) throws Exception {
|
||||||
|
super(curatorFramework, balancerProperties, cacheProperties, healthChecker);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createAssignmentFile() {
|
||||||
|
try {
|
||||||
|
log.info("Creating assignment file: " + balancerProperties.getAssignmentFile());
|
||||||
|
Configuration configuration = new Configuration();
|
||||||
|
FileSystem fs = FileSystem.get(configuration);
|
||||||
|
Path assignmentFile = new Path(balancerProperties.getAssignmentFile());
|
||||||
|
fs.setWriteChecksum(false);
|
||||||
|
fs.create(assignmentFile);
|
||||||
|
fs.deleteOnExit(assignmentFile);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TimelyBalancedHost> getServerList() {
|
||||||
|
return this.serverList;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package timely.balancer.test;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
import org.springframework.security.authentication.ProviderManager;
|
||||||
|
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Primary
|
||||||
|
@Component
|
||||||
|
public class TestTimelyAuthenticationManager extends ProviderManager {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public TestTimelyAuthenticationManager(@Qualifier("file") PreAuthenticatedAuthenticationProvider file) {
|
||||||
|
super(Collections.singletonList(file));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
logging:
|
||||||
|
level:
|
||||||
|
ROOT: info
|
||||||
|
timely: debug
|
||||||
|
org.apache.zookeeper: error
|
||||||
|
|
||||||
|
timely:
|
||||||
|
test: true
|
||||||
|
instance: 1
|
||||||
|
accumulo:
|
||||||
|
instance-name: default
|
||||||
|
username: root
|
||||||
|
password: secret
|
||||||
|
mini-accumulo:
|
||||||
|
enabled: true
|
||||||
|
rootAuths: A,B,C,D,E,F,G,H,I
|
||||||
|
zookeeper:
|
||||||
|
servers: localhost:0
|
||||||
|
timeout: 30s
|
||||||
|
security:
|
||||||
|
session-max-age: 86400
|
||||||
|
cache-expiration-minutes: 60
|
||||||
|
cache-refresh-minutes: 5
|
||||||
|
allow-anonymous-http-access: true
|
||||||
|
allow-anonymous-ws-access: true
|
||||||
|
authorized-users:
|
||||||
|
- subject-dn: cn=example.com
|
||||||
|
roles: G,H,I
|
||||||
|
auths: D,E,F
|
||||||
|
user-type: USER
|
||||||
|
- subject-dn: cn=test a. user, ou=example developers, o=example corp, c=us
|
||||||
|
issuer-dn: cn=example corp ca, o=example corp, c=us
|
||||||
|
roles: G,H,I
|
||||||
|
auths: A,B,C
|
||||||
|
user-type: USER
|
||||||
|
server-ssl:
|
||||||
|
key-store-type: PKCS12
|
||||||
|
key-store-file: classpath:ssl/testServer.p12
|
||||||
|
key-store-password: ChangeIt
|
||||||
|
trust-store-type: JKS
|
||||||
|
trust-store-file: classpath:ssl/ca.jks
|
||||||
|
trust-store-password: ChangeIt
|
||||||
|
use-generated-keypair: false
|
||||||
|
ignore-ssl-handshake-errors: true
|
||||||
|
use-openssl: true
|
||||||
|
client-ssl:
|
||||||
|
key-store-type: PKCS12
|
||||||
|
key-store-file: classpath:ssl/testUser.p12
|
||||||
|
key-store-password: ChangeIt
|
||||||
|
trust-store-type: JKS
|
||||||
|
trust-store-file: classpath:ssl/ca.jks
|
||||||
|
trust-store-password: ChangeIt
|
||||||
|
cache:
|
||||||
|
enabled: false
|
||||||
|
metric-age-off-hours:
|
||||||
|
default: 26
|
||||||
|
non-cached-metrics:
|
||||||
|
balancer:
|
||||||
|
check-server-health-interval: 10000
|
||||||
|
server-failures-before-down: 6
|
||||||
|
server-successes-before-up: 1
|
||||||
|
assignment-file: file://${java.io.tmpdir}/timely/balancer/assignments.csv
|
||||||
|
server:
|
||||||
|
ip: 127.0.0.1
|
||||||
|
tcp-base-port: 9242
|
||||||
|
tcp-buffer-size: 100
|
||||||
|
tcp-client-pool:
|
||||||
|
min-idle-per-key: 5
|
||||||
|
max-idle-per-key: 5
|
||||||
|
max-total-per-key: 5
|
||||||
|
max-total: -1
|
||||||
|
lifo: false
|
||||||
|
fairness: true
|
||||||
|
max-wait-millis: 60000
|
||||||
|
min-evictable-idle-time-millis: -1
|
||||||
|
evictor-shutdown-timeout-millis: 10000
|
||||||
|
soft-min-evictable-idle-time-millis: 300000
|
||||||
|
num-tests-per-eviction-run: 3
|
||||||
|
time-between-eviction-runs-millis: 30000
|
||||||
|
block-when-exhausted: true
|
||||||
|
remove-abandoned-on-borrow: false
|
||||||
|
remove-abandoned-on-maintenance: true
|
||||||
|
remove-abandoned-timeout-millis: 600000
|
||||||
|
remove-abandoned-logging: true
|
||||||
|
jmx-enabled: true
|
||||||
|
test-on-borrow: false
|
||||||
|
test-on-return: false
|
||||||
|
udp-base-port: 9245
|
||||||
|
udp-client-pool:
|
||||||
|
min-idle-per-key: 5
|
||||||
|
max-idle-per-key: 5
|
||||||
|
max-total-per-key: 5
|
||||||
|
max-total: -1
|
||||||
|
lifo: false
|
||||||
|
fairness: true
|
||||||
|
max-wait-millis: 60000
|
||||||
|
min-evictable-idle-time-millis: -1
|
||||||
|
evictor-shutdown-timeout-millis: 10000
|
||||||
|
soft-min-evictable-idle-time-millis: 300000
|
||||||
|
num-tests-per-eviction-run: 3
|
||||||
|
time-between-eviction-runs-millis: 30000
|
||||||
|
block-when-exhausted: true
|
||||||
|
remove-abandoned-on-borrow: false
|
||||||
|
remove-abandoned-on-maintenance: true
|
||||||
|
remove-abandoned-timeout-millis: 600000
|
||||||
|
remove-abandoned-logging: true
|
||||||
|
jmx-enabled: true
|
||||||
|
test-on-borrow: false
|
||||||
|
test-on-return: false
|
||||||
|
http:
|
||||||
|
host: localhost
|
||||||
|
ip: 127.0.0.1
|
||||||
|
base-port: 9243
|
||||||
|
redirect-path: /secure-me
|
||||||
|
strict-transport-max-age: 604800
|
||||||
|
connection-request-timeout: 5000
|
||||||
|
connect-timeout: 5000
|
||||||
|
socket-timeout: 300000
|
||||||
|
request-timeout: 300000
|
||||||
|
cors:
|
||||||
|
allow-any-origin: false
|
||||||
|
allow-null-origin: false
|
||||||
|
allow-credentials: true
|
||||||
|
allowed-origins:
|
||||||
|
allowed-methods: DELETE,GET,HEAD,OPTIONS,PUT,POST
|
||||||
|
allowed-headers: content-type
|
||||||
|
http-client-pool:
|
||||||
|
min-idle-per-key: 10
|
||||||
|
max-idle-per-key: 40
|
||||||
|
max-total-per-key: 40
|
||||||
|
max-total: -1
|
||||||
|
lifo: false
|
||||||
|
fairness: true
|
||||||
|
max-wait-millis: 60000
|
||||||
|
min-evictable-idle-time-millis: -1
|
||||||
|
evictor-shutdown-timeout-millis: 10000
|
||||||
|
soft-min-evictable-idle-time-millis: 300000
|
||||||
|
num-tests-per-eviction-run: 3
|
||||||
|
time-between-eviction-runs-millis: 30000
|
||||||
|
block-when-exhausted: true
|
||||||
|
remove-abandoned-on-borrow: false
|
||||||
|
remove-abandoned-on-maintenance: true
|
||||||
|
remove-abandoned-timeout-millis: 600000
|
||||||
|
remove-abandoned-logging: true
|
||||||
|
jmx-enabled: true
|
||||||
|
test-on-borrow: false
|
||||||
|
test-on-return: false
|
||||||
|
websocket:
|
||||||
|
ip: 127.0.0.1
|
||||||
|
base-port: 9244
|
||||||
|
timeout: 60
|
||||||
|
subscription-lag: 120
|
||||||
|
scanner-batch-size: 10000
|
||||||
|
flush-interval-seconds: 30
|
||||||
|
scanner-read-ahead: 1
|
||||||
|
subscription-batch-size: 5000
|
||||||
|
incoming-buffer-size: 50000000
|
||||||
|
ws-client-pool:
|
||||||
|
min-idle-per-key: 0
|
||||||
|
max-idle-per-key: 40
|
||||||
|
max-total-per-key: 40
|
||||||
|
max-total: -1
|
||||||
|
lifo: false
|
||||||
|
fairness: true
|
||||||
|
max-wait-millis: 60000
|
||||||
|
min-evictable-idle-time-millis: -1
|
||||||
|
evictor-shutdown-timeout-millis: 10000
|
||||||
|
soft-min-evictable-idle-time-millis: 300000
|
||||||
|
num-tests-per-eviction-run: 3
|
||||||
|
time-between-eviction-runs-millis: 30000
|
||||||
|
block-when-exhausted: true
|
||||||
|
remove-abandoned-on-borrow: false
|
||||||
|
remove-abandoned-on-maintenance: true
|
||||||
|
remove-abandoned-timeout-millis: 600000
|
||||||
|
remove-abandoned-logging: true
|
||||||
|
jmx-enabled: true
|
||||||
|
test-on-borrow: false
|
||||||
|
test-on-return: false
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: timely-balancer
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
Configuration:
|
||||||
|
status: warn
|
||||||
|
monitorInterval: 60
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
Property:
|
||||||
|
- name: PID
|
||||||
|
value: "????"
|
||||||
|
- name: LOG_PATTERN
|
||||||
|
value: "%clr{%d{yyyy-MM-dd HH:mm:ss.SSS}}{faint} %clr{%5p} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n%wEx"
|
||||||
|
|
||||||
|
Appenders:
|
||||||
|
Console:
|
||||||
|
name: Console
|
||||||
|
target: SYSTEM_OUT
|
||||||
|
follow: true
|
||||||
|
PatternLayout:
|
||||||
|
pattern: "${LOG_PATTERN}"
|
||||||
|
|
||||||
|
Loggers:
|
||||||
|
Root:
|
||||||
|
level: warn
|
||||||
|
AppenderRef:
|
||||||
|
- ref: Console
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
Bag Attributes: <No Attributes>
|
||||||
|
subject=/C=US/O=Example Corp/CN=EXAMPLE CORP CA
|
||||||
|
issuer=/C=US/O=Example Corp/CN=EXAMPLE CORP CA
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDTjCCAjagAwIBAgIURUj8l+ms/i9jeabIBBi19KxEhAgwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwPjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDEV4YW1wbGUgQ29ycDEYMBYGA1UE
|
||||||
|
AxMPRVhBTVBMRSBDT1JQIENBMCAXDTIzMDIwMTIzMTUwMFoYDzIxMjMwMTA4MjMx
|
||||||
|
NTAwWjA+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRXhhbXBsZSBDb3JwMRgwFgYD
|
||||||
|
VQQDEw9FWEFNUExFIENPUlAgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||||
|
AoIBAQDVBr2XF20SKmGXfvp2BUY44BF1fm3Qw83GkC66qIHgpgQxzJ8u44P34vV1
|
||||||
|
DYTj4XzrBpx23J0nCMEiAW8YW9MxZJPEokZafRNKFQAngVdgmAW9fHemHRQfaYwe
|
||||||
|
ySVz2UZ+z28DJ3C0QshvqXskrYstwLVs4Ss2uoX+XpeFbW9IVVg4aW+GX3LHPNTk
|
||||||
|
7Hji13Capp6BCiS61AGQAiMWNBW2aRgHVLOb7RDQug2Bka/dcJ44XxJDh26C6kV1
|
||||||
|
pNEZm0ToqWAiVfvyzionPec5im6NKX9kStZc+C/iikfx5vdmrvGIF5zxy6phdhJ7
|
||||||
|
AGd6cF6UBkkYm/SsIP3WTXpBek5LAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP
|
||||||
|
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSPLNlCmmp9PH+crzCx9TNp5BoCajAN
|
||||||
|
BgkqhkiG9w0BAQsFAAOCAQEAkjLnZKqLMjbu5Hy8YOVoKaEKahP+t/tNYZW/NtrC
|
||||||
|
xSxKmGLz5kVCkjpLgCykkcpu4h2wZW4MGZJ4nc87+tN22mJOg1WnqEpBzRsEPajk
|
||||||
|
7duVjdU2FDCarERj53hxF41l/u8BxvMGbFnrAijv5SzspeLi+VCGF3wu53Bi6UHi
|
||||||
|
7WO1dIhZLMHepqgtwbDDudxwlKbG/JWjJ7OspCNqOpktpY8BFUAQ42ctYZcOHy2w
|
||||||
|
kdZDcK5IhRztkBH2aSWOhudYh/CF7BOu2nSUdtR5NwhXnsStmSbud7ahw3W5Jc9/
|
||||||
|
IVAFXf2brkrfIzwrY5kmjnEPJ8mjUyLepwSlOlMTBrehzQ==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
Binary file not shown.
@@ -0,0 +1,51 @@
|
|||||||
|
Bag Attributes
|
||||||
|
localKeyID: 22 89 1C EA 4E FF 9A F6 11 1B E7 9B 5E 4F 59 B7 B1 0F AA FA
|
||||||
|
friendlyName: example-server
|
||||||
|
subject=/C=US/O=Example Corp/OU=Servers/CN=testserver.example.com
|
||||||
|
issuer=/C=US/O=Example Corp/CN=EXAMPLE CORP CA
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDwjCCAqqgAwIBAgIUe6yBgkY1m/oXuPXA9j/c/7+w16UwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwPjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDEV4YW1wbGUgQ29ycDEYMBYGA1UE
|
||||||
|
AxMPRVhBTVBMRSBDT1JQIENBMCAXDTIzMDIwMTIzMTUwMFoYDzIxMjMwMTA4MjMx
|
||||||
|
NTAwWjBXMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRXhhbXBsZSBDb3JwMRAwDgYD
|
||||||
|
VQQLEwdTZXJ2ZXJzMR8wHQYDVQQDExZ0ZXN0c2VydmVyLmV4YW1wbGUuY29tMIIB
|
||||||
|
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmb1pEWg9a6ZChQULazK75ppc
|
||||||
|
XScU5Ap29L70/5zcaOcbaBwqKhpKhdZCoZ1TD+Sdkk9kp7IlabCQjM2vVjknb6NY
|
||||||
|
msl3PbQFNva0EkH6s5cvpX4WhQDsWK77/4eztHT+0fpaG1YoKQn+Gy3VuW0CDyR6
|
||||||
|
GzGKifnI/aNLevgUBebbiiTPLEdGlo0jp3SXlZfoDZdbvnhBWI8Xc+aDekNlrXxW
|
||||||
|
X2TVnc02Fi914PECYJzkMpmxnBRPAcljU24WSqaUVgRoSbafkm4OXDw0xtvxnIrJ
|
||||||
|
s3iO0uZfRf7+OxAlqlvh4ZJ9/PufPMEKvmr6zea05KkFjBotKMip5Md43H3lQQID
|
||||||
|
AQABo4GcMIGZMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
|
||||||
|
KwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUDWwMrl9/uc1wplERWxas
|
||||||
|
bDROB4MwHwYDVR0jBBgwFoAUjyzZQppqfTx/nK8wsfUzaeQaAmowGgYDVR0RBBMw
|
||||||
|
EYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQBfG7StgQf3WNk/
|
||||||
|
EnaYuurwvaOOpcOV5NDcZ6tmgaXUrISPVDpyIWfsDGetNEXc+4gpefLQtGF2wuiW
|
||||||
|
odiLc4H9JwQ/yEkVYwzrFViPdZKVvxNU2EjiwO/e/3sl+SxxkTDy6o838uTXX+X5
|
||||||
|
Q8DabmL5L8ukcnqUHVOqW38oA1vRNBKiJX58JzOr8ezX8crZmqU9h8cNwG/V+ZXE
|
||||||
|
5U7+hSRzLm7gRwtixj8ZsTDUiGJxOdbyUKImPClt1Se9TizB2Q/xOPTdmYB1qiiB
|
||||||
|
+XVKkGwQPgIbHckLsZWhBor2u5cgdrBGW09Q+H88maagwq5sBHNMs33vkkgbUDpB
|
||||||
|
6WSEBJMi
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
Bag Attributes: <No Attributes>
|
||||||
|
subject=/C=US/O=Example Corp/CN=EXAMPLE CORP CA
|
||||||
|
issuer=/C=US/O=Example Corp/CN=EXAMPLE CORP CA
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDTjCCAjagAwIBAgIURUj8l+ms/i9jeabIBBi19KxEhAgwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwPjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDEV4YW1wbGUgQ29ycDEYMBYGA1UE
|
||||||
|
AxMPRVhBTVBMRSBDT1JQIENBMCAXDTIzMDIwMTIzMTUwMFoYDzIxMjMwMTA4MjMx
|
||||||
|
NTAwWjA+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRXhhbXBsZSBDb3JwMRgwFgYD
|
||||||
|
VQQDEw9FWEFNUExFIENPUlAgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||||
|
AoIBAQDVBr2XF20SKmGXfvp2BUY44BF1fm3Qw83GkC66qIHgpgQxzJ8u44P34vV1
|
||||||
|
DYTj4XzrBpx23J0nCMEiAW8YW9MxZJPEokZafRNKFQAngVdgmAW9fHemHRQfaYwe
|
||||||
|
ySVz2UZ+z28DJ3C0QshvqXskrYstwLVs4Ss2uoX+XpeFbW9IVVg4aW+GX3LHPNTk
|
||||||
|
7Hji13Capp6BCiS61AGQAiMWNBW2aRgHVLOb7RDQug2Bka/dcJ44XxJDh26C6kV1
|
||||||
|
pNEZm0ToqWAiVfvyzionPec5im6NKX9kStZc+C/iikfx5vdmrvGIF5zxy6phdhJ7
|
||||||
|
AGd6cF6UBkkYm/SsIP3WTXpBek5LAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP
|
||||||
|
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSPLNlCmmp9PH+crzCx9TNp5BoCajAN
|
||||||
|
BgkqhkiG9w0BAQsFAAOCAQEAkjLnZKqLMjbu5Hy8YOVoKaEKahP+t/tNYZW/NtrC
|
||||||
|
xSxKmGLz5kVCkjpLgCykkcpu4h2wZW4MGZJ4nc87+tN22mJOg1WnqEpBzRsEPajk
|
||||||
|
7duVjdU2FDCarERj53hxF41l/u8BxvMGbFnrAijv5SzspeLi+VCGF3wu53Bi6UHi
|
||||||
|
7WO1dIhZLMHepqgtwbDDudxwlKbG/JWjJ7OspCNqOpktpY8BFUAQ42ctYZcOHy2w
|
||||||
|
kdZDcK5IhRztkBH2aSWOhudYh/CF7BOu2nSUdtR5NwhXnsStmSbud7ahw3W5Jc9/
|
||||||
|
IVAFXf2brkrfIzwrY5kmjnEPJ8mjUyLepwSlOlMTBrehzQ==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
Bag Attributes
|
||||||
|
localKeyID: 22 89 1C EA 4E FF 9A F6 11 1B E7 9B 5E 4F 59 B7 B1 0F AA FA
|
||||||
|
friendlyName: example-server
|
||||||
|
Key Attributes: <No Attributes>
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCZvWkRaD1rpkKF
|
||||||
|
BQtrMrvmmlxdJxTkCnb0vvT/nNxo5xtoHCoqGkqF1kKhnVMP5J2ST2SnsiVpsJCM
|
||||||
|
za9WOSdvo1iayXc9tAU29rQSQfqzly+lfhaFAOxYrvv/h7O0dP7R+lobVigpCf4b
|
||||||
|
LdW5bQIPJHobMYqJ+cj9o0t6+BQF5tuKJM8sR0aWjSOndJeVl+gNl1u+eEFYjxdz
|
||||||
|
5oN6Q2WtfFZfZNWdzTYWL3Xg8QJgnOQymbGcFE8ByWNTbhZKppRWBGhJtp+Sbg5c
|
||||||
|
PDTG2/GcismzeI7S5l9F/v47ECWqW+Hhkn38+588wQq+avrN5rTkqQWMGi0oyKnk
|
||||||
|
x3jcfeVBAgMBAAECggEAZEHC7NkfhL4NjxV1Ftkk9AMhzJWZ6ARzArQsrSysB7T+
|
||||||
|
iGwliwNOKe1J0n74FdsubqVbrIheIYhFG61edEodT44kT/ylyBVHeUp0r5tbVBZ5
|
||||||
|
ueB56w5pEoQ6Ta8/H6VUL7alYEJVOj4L+clwINXXi+xrvKQYBlZgHheJN43j8NxS
|
||||||
|
9lCrVcm58rzX3i29S7ErBf7RqDabgD6j2m7rehnSq5Ps2wxwV/LXMl4Lxlwa0jz/
|
||||||
|
LV8szNMZViPOWAqOCy7NZbwCCaCfKVUAwmNGBkE3p4JVPeLNLzCBY9G0rHVmFJLK
|
||||||
|
yPnCB7PtCZeFTsU+8OHHWoxMFsaOO9Pp8FtB/r8PYQKBgQDI0OzEo3t/QKvbwAdz
|
||||||
|
9Eze0LQvstzZIidTWbYMTxH0g7DIt+3p11d61GKtfeuYUTPlLodufdv/BaP8G9sI
|
||||||
|
NzxisB3uH/787M9fwi1OzO7zMMZZCVa7Q1vZk6ta1qY3PekcYMPqjBJhxP1X3S7x
|
||||||
|
8+mrW5vTq/l8ZRVFeLvEkh6bpQKBgQDD/MCRJoq6nzd2DoTyT9m5qO+Jlztmu9+T
|
||||||
|
vqVOg7q0NO7U7dzyMbWgMvMFoEBidnyllU1rEj2YOo4OrI2v/JmSPUVS8VXsBkkG
|
||||||
|
UqInV4F/g0Wp3hzrkZFMqHLa6AydugmRNkOpgurRKOiwAL0Pgvk8+bOIbKMM7JBE
|
||||||
|
tZ6Zvi0gbQKBgD4S5r0505jYQsdgqm0bXQ+a77e20DGGLyXCm1Ves6wjcOf6gt4/
|
||||||
|
pFjhgccjH0or/6CeK1rqKLDB65ioe6IkgNP4oKfU2BsSkF+HRD4RduNRdl5bVqX4
|
||||||
|
AlJVJSilJSf6SS5ucuDzf1MdczpPso0z2k0PujFJ/YqILHUXBuOST0fJAoGAZAdX
|
||||||
|
nX3HZpKmsumcLzRUEq9HerkmRzvyU60FH/qZyyoND75Le42lfpsicCenVNnWqoh2
|
||||||
|
WASaTVztbk3hjwXkt7/v5vJoASwAD2sTefLulE9Cuf00U4MbXr3GyTWQYtw1z9ib
|
||||||
|
ViQMhy5S/KmT1Rvq65UibanM2mbPB1KPHTb0P00CgYEAgieJ1YXYYHPjABWJ7/S9
|
||||||
|
3Z/8eJY0kuUe1DRFaKOlfej8SOCFFIa90IW2mAnujh55H4N2lww4s/N+FIRQoQpA
|
||||||
|
1Hrch9tYRiXyouQc67dFlLxmCOVJIf31ZUt7I4HcPhsfr4fuCJXUPBs1jaDmwQsk
|
||||||
|
90VWrXaTwSjmP+yHMiPfaA0=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
Binary file not shown.
@@ -0,0 +1,50 @@
|
|||||||
|
Bag Attributes
|
||||||
|
localKeyID: 57 F6 9F DF B2 94 61 47 B0 B0 2E 3A F7 79 98 C8 15 5C 64 FA
|
||||||
|
friendlyName: example-client
|
||||||
|
subject=/C=US/O=Example Corp/OU=Example Developers/CN=Test A. User
|
||||||
|
issuer=/C=US/O=Example Corp/CN=EXAMPLE CORP CA
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDmzCCAoOgAwIBAgIUFp4IuIaZ2XId7UNvzP6ZB9hChyUwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwPjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDEV4YW1wbGUgQ29ycDEYMBYGA1UE
|
||||||
|
AxMPRVhBTVBMRSBDT1JQIENBMCAXDTIzMDIwMTIzMTUwMFoYDzIxMjMwMTA4MjMx
|
||||||
|
NTAwWjBYMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRXhhbXBsZSBDb3JwMRswGQYD
|
||||||
|
VQQLExJFeGFtcGxlIERldmVsb3BlcnMxFTATBgNVBAMTDFRlc3QgQS4gVXNlcjCC
|
||||||
|
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMOMeN0ElMDxYKST2VD1wP6Z
|
||||||
|
jmy543Zv/QgRLTYizg3U9t3uZU0C3HqUJnK+c4+OJnRIyHuMXuJWEYVdairyAdYW
|
||||||
|
ZDF5sfiL9ikG9rZ2WxR2z7nsYLJcDGwKAt/Duzuoed6KSccEpiQc+BkoOTs9p87I
|
||||||
|
l4s7saX/anESMUY7YOomLSqS2zvQZh/zTjIdP1/9kG9PLzXPClJELuiC3pJCmr7Y
|
||||||
|
xdJIXecu6YKFpApy0y+rKcfYUVPML15gyRu9pIqH3U39y7mCkn+YP9Qc9GcZAoqR
|
||||||
|
iYdUEl1rFAgV/a3o0pmf1tFFRDOsoPSMUGNNQlaCjv1uZIbRm25nvvQlPfstFDEC
|
||||||
|
AwEAAaN1MHMwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAwG
|
||||||
|
A1UdEwEB/wQCMAAwHQYDVR0OBBYEFPAe3n59DcNwRcnpIwQY2kPawbCVMB8GA1Ud
|
||||||
|
IwQYMBaAFI8s2UKaan08f5yvMLH1M2nkGgJqMA0GCSqGSIb3DQEBCwUAA4IBAQBo
|
||||||
|
+zadU9DwR1rnHTBZF6CJXmiIdrQmArojH4a3NOHbNjFjRXm7dkd/tAy5LtgDJkww
|
||||||
|
yg+ZrOyOKHbFgk6IXRZ8nw2b1Ck9I9MDW1vxfjid9YLW2nhDaMcIeTXz3aIBO5i6
|
||||||
|
gMCV+xMcFaU/O57Ohia+ADUqrqu14nG9Moi171UWPbMr5N3gYn3Fs4VrTGYs4i0Z
|
||||||
|
5x2itm88WB3bWj+cd06zKQopU9b0Y76mQv9h+w4EHxq4uWA7GmIDDkvtI61MQo8+
|
||||||
|
twdX159Ms6o4lW43SRqVBHeMgSJbiLDkdkypYJvd9PvAjWgmQK/sD1SYKxfgYhtx
|
||||||
|
hqIvAjlGeDwdf+55EGjf
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
Bag Attributes: <No Attributes>
|
||||||
|
subject=/C=US/O=Example Corp/CN=EXAMPLE CORP CA
|
||||||
|
issuer=/C=US/O=Example Corp/CN=EXAMPLE CORP CA
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDTjCCAjagAwIBAgIURUj8l+ms/i9jeabIBBi19KxEhAgwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwPjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDEV4YW1wbGUgQ29ycDEYMBYGA1UE
|
||||||
|
AxMPRVhBTVBMRSBDT1JQIENBMCAXDTIzMDIwMTIzMTUwMFoYDzIxMjMwMTA4MjMx
|
||||||
|
NTAwWjA+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRXhhbXBsZSBDb3JwMRgwFgYD
|
||||||
|
VQQDEw9FWEFNUExFIENPUlAgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||||
|
AoIBAQDVBr2XF20SKmGXfvp2BUY44BF1fm3Qw83GkC66qIHgpgQxzJ8u44P34vV1
|
||||||
|
DYTj4XzrBpx23J0nCMEiAW8YW9MxZJPEokZafRNKFQAngVdgmAW9fHemHRQfaYwe
|
||||||
|
ySVz2UZ+z28DJ3C0QshvqXskrYstwLVs4Ss2uoX+XpeFbW9IVVg4aW+GX3LHPNTk
|
||||||
|
7Hji13Capp6BCiS61AGQAiMWNBW2aRgHVLOb7RDQug2Bka/dcJ44XxJDh26C6kV1
|
||||||
|
pNEZm0ToqWAiVfvyzionPec5im6NKX9kStZc+C/iikfx5vdmrvGIF5zxy6phdhJ7
|
||||||
|
AGd6cF6UBkkYm/SsIP3WTXpBek5LAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP
|
||||||
|
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSPLNlCmmp9PH+crzCx9TNp5BoCajAN
|
||||||
|
BgkqhkiG9w0BAQsFAAOCAQEAkjLnZKqLMjbu5Hy8YOVoKaEKahP+t/tNYZW/NtrC
|
||||||
|
xSxKmGLz5kVCkjpLgCykkcpu4h2wZW4MGZJ4nc87+tN22mJOg1WnqEpBzRsEPajk
|
||||||
|
7duVjdU2FDCarERj53hxF41l/u8BxvMGbFnrAijv5SzspeLi+VCGF3wu53Bi6UHi
|
||||||
|
7WO1dIhZLMHepqgtwbDDudxwlKbG/JWjJ7OspCNqOpktpY8BFUAQ42ctYZcOHy2w
|
||||||
|
kdZDcK5IhRztkBH2aSWOhudYh/CF7BOu2nSUdtR5NwhXnsStmSbud7ahw3W5Jc9/
|
||||||
|
IVAFXf2brkrfIzwrY5kmjnEPJ8mjUyLepwSlOlMTBrehzQ==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
Bag Attributes
|
||||||
|
localKeyID: 57 F6 9F DF B2 94 61 47 B0 B0 2E 3A F7 79 98 C8 15 5C 64 FA
|
||||||
|
friendlyName: example-client
|
||||||
|
Key Attributes: <No Attributes>
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDDjHjdBJTA8WCk
|
||||||
|
k9lQ9cD+mY5sueN2b/0IES02Is4N1Pbd7mVNAtx6lCZyvnOPjiZ0SMh7jF7iVhGF
|
||||||
|
XWoq8gHWFmQxebH4i/YpBva2dlsUds+57GCyXAxsCgLfw7s7qHneiknHBKYkHPgZ
|
||||||
|
KDk7PafOyJeLO7Gl/2pxEjFGO2DqJi0qkts70GYf804yHT9f/ZBvTy81zwpSRC7o
|
||||||
|
gt6SQpq+2MXSSF3nLumChaQKctMvqynH2FFTzC9eYMkbvaSKh91N/cu5gpJ/mD/U
|
||||||
|
HPRnGQKKkYmHVBJdaxQIFf2t6NKZn9bRRUQzrKD0jFBjTUJWgo79bmSG0ZtuZ770
|
||||||
|
JT37LRQxAgMBAAECggEBALFWsT1vLCAWRxi55Hkhhhbe12UO55O/V+969E+GHOw6
|
||||||
|
WG9IBaJjl+Oqe3vP8CkeNw15/CbfVCVa/KS/5Mpxkuy+fbrIrHfFJkZqxE8Q4uSa
|
||||||
|
IyRvk/nstG8+XQDlFuWxkmQZcXMFak6R3wWhjtWEwqwrChQA3Mi366YDY6BXtTpi
|
||||||
|
MuLJVWXqYVF2RirWX3a7eosR4MYBCJ1S8NnpI1w4oZwuew6iYiCJNkURctxnGKOe
|
||||||
|
hoop/711PEyIb/qHETBIlReY9scvZgJQZMgGe5mTGgFmAA8Bzo4e1/F2QrVIi7wy
|
||||||
|
REOSj4U+tP/QrYMSPk0cMpH5ft5+2mfh/o+D1ugm/AkCgYEA2qt3P4vlm1TMmJru
|
||||||
|
vMYc8iZjfe7UQTnD+J1EgrASBI0JP565zSZKBRIXnheumWhWS+2KR1MP8N6KAu4Q
|
||||||
|
xE/E7TKfLuE1CPzn7Rh/WZAxDqGNeQthk0qTbeBZ4/mHPKvt8V7c+N4vLjZ00uul
|
||||||
|
bKitlLpb49T+8FpSgRmk+nrBsesCgYEA5O6LmxH1+ip5NoMHoZVBhLbgJkxoXEzn
|
||||||
|
xHT7On8CjQ9B0T85NW9O38/a2gyIb5dIavcrh4dMvOKX8hdrVlal3chrXFRemyvy
|
||||||
|
VzpW7HZpMwthJb/QSim+GQ4u2Jsm+eXQAswq/yfowls9mp7K81McBgdfcdWgWuqc
|
||||||
|
Ttf3dBRS71MCgYBCPpu7ppgCfKgWuykEC0iNm0+cwROQRv21fX9Z0BlFQ6y/l0hW
|
||||||
|
e/kEnDyHakk8tD0gd2/it6kmoWRSCukNb9UKvsE2pIc6l9NzIm7CJUqXUh3Xw7jl
|
||||||
|
tDwBl2vkAp4TpUpKSyDKTBUi/OBbXYQZ7OfZHLPly4sIKXTBI5G1SCcRzQKBgE3Y
|
||||||
|
Y7ZmRBs+CBumMJkcVLwZJ10+jBoeuIzQLoF0oNxwfLP3aK+n2s02M7gDnP09Fw3w
|
||||||
|
YGfkdQ6hioNyvTgNnLcuqHsr4UOojO5mUxpzJVCLJQyeDei6Cv8gGIPlNjqxj6rz
|
||||||
|
3AcJfhdgyTDjoCVfdF8EcMsXlkB0GJSi0W0yYAUrAoGAVK5v0cbEEV+gxdQgh848
|
||||||
|
FwSQXx7i9jVOB2BUTLX2Q+gLUJibtFzLnh03sGCXtTa8sK+hLW4FCMWZa9Ev5ZjG
|
||||||
|
ylFyA96U97CNpS+2/ZW5+hvRZ/GuY/0yB8w26BeS38lI8RnmxSPi5cnexdl32NIX
|
||||||
|
5FkU9WJ4HKmi1n0304CkF+4=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
Binary file not shown.
+8
-7
@@ -4,13 +4,13 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely</artifactId>
|
<artifactId>timely</artifactId>
|
||||||
<version>1.2.8-SNAPSHOT</version>
|
<version>2.2.6-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>timely-client</artifactId>
|
<artifactId>timely-client</artifactId>
|
||||||
<properties>
|
<properties>
|
||||||
<!-- PEP 440 compliant version gets substituted into src/main/python/template/setup.py -->
|
<!-- PEP 440 compliant version gets substituted into src/main/python/template/setup.py -->
|
||||||
<!-- use .dev0 instead of -SNAPSHOT -->
|
<!-- use .dev0 instead of -SNAPSHOT -->
|
||||||
<python.client.version>1.2.8.dev0</python.client.version>
|
<python.client.version>2.2.6.dev0</python.client.version>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -53,6 +53,10 @@
|
|||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>timely</groupId>
|
||||||
|
<artifactId>timely-common</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
<artifactId>log4j-api</artifactId>
|
<artifactId>log4j-api</artifactId>
|
||||||
@@ -63,21 +67,18 @@
|
|||||||
<artifactId>log4j-core</artifactId>
|
<artifactId>log4j-core</artifactId>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!--
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
<artifactId>log4j-slf4j-impl</artifactId>
|
<artifactId>log4j-slf4j-impl</artifactId>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>timely</groupId>
|
|
||||||
<artifactId>timely-common</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ public class AddSubscription extends SubscriptionRequest {
|
|||||||
|
|
||||||
private String operation = "add";
|
private String operation = "add";
|
||||||
private String metric = null;
|
private String metric = null;
|
||||||
private Optional<Map<String, String>> tags = Optional.empty();
|
private Optional<Map<String,String>> tags = Optional.empty();
|
||||||
private Optional<Long> startTime = Optional.empty();
|
private Optional<Long> startTime = Optional.empty();
|
||||||
private Optional<Long> endTime = Optional.empty();
|
private Optional<Long> endTime = Optional.empty();
|
||||||
private Optional<Long> delayTime = Optional.empty();
|
private Optional<Long> delayTime = Optional.empty();
|
||||||
@@ -20,7 +20,7 @@ public class AddSubscription extends SubscriptionRequest {
|
|||||||
return metric;
|
return metric;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Map<String, String>> getTags() {
|
public Optional<Map<String,String>> getTags() {
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ public class AddSubscription extends SubscriptionRequest {
|
|||||||
this.metric = metric;
|
this.metric = metric;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTags(Optional<Map<String, String>> tags) {
|
public void setTags(Optional<Map<String,String>> tags) {
|
||||||
this.tags = tags;
|
this.tags = tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,9 +71,8 @@ public class AddSubscription extends SubscriptionRequest {
|
|||||||
}
|
}
|
||||||
if (obj instanceof AddSubscription) {
|
if (obj instanceof AddSubscription) {
|
||||||
AddSubscription other = (AddSubscription) obj;
|
AddSubscription other = (AddSubscription) obj;
|
||||||
return (this.subscriptionId.equals(other.subscriptionId) && this.metric.equals(other.metric)
|
return (this.subscriptionId.equals(other.subscriptionId) && this.metric.equals(other.metric) && this.tags.equals(other.tags)
|
||||||
&& this.tags.equals(other.tags) && this.startTime.equals(other.startTime)
|
&& this.startTime.equals(other.startTime) && this.endTime.equals(other.endTime) && this.delayTime.equals(other.delayTime));
|
||||||
&& this.endTime.equals(other.endTime) && this.delayTime.equals(other.delayTime));
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
package timely.api;
|
|
||||||
|
|
||||||
public class BasicAuthLogin {
|
|
||||||
|
|
||||||
protected String username;
|
|
||||||
protected String password;
|
|
||||||
|
|
||||||
public String getUsername() {
|
|
||||||
return username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUsername(String user) {
|
|
||||||
this.username = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPassword() {
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPassword(String password) {
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return (username + password).hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (null == obj) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (obj == this) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (obj instanceof BasicAuthLogin) {
|
|
||||||
BasicAuthLogin other = (BasicAuthLogin) obj;
|
|
||||||
return (this.username.equals(other.username) && this.password.equals(other.password));
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package timely.api;
|
||||||
|
|
||||||
|
public class VersionRequest {
|
||||||
|
|
||||||
|
private String operation = "version";
|
||||||
|
|
||||||
|
public String getOperation() {
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,9 +5,13 @@ import java.util.List;
|
|||||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||||
|
|
||||||
import timely.model.Metric;
|
import timely.model.Metric;
|
||||||
import timely.model.Tag;
|
import timely.model.Tag;
|
||||||
|
|
||||||
|
@JsonPropertyOrder({"metric", "timestamp", "value", "tags", "subscriptionId", "complete"})
|
||||||
public class MetricResponse {
|
public class MetricResponse {
|
||||||
|
|
||||||
private String metric;
|
private String metric;
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import org.glassfish.tyrus.client.SslContextConfigurator;
|
|||||||
|
|
||||||
public class HttpClient {
|
public class HttpClient {
|
||||||
|
|
||||||
public static SSLContext getSSLContext(String trustStoreFile, String trustStoreType, String trustStorePass,
|
public static SSLContext getSSLContext(String trustStoreFile, String trustStoreType, String trustStorePass, String keyStoreFile, String keyStoreType,
|
||||||
String keyStoreFile, String keyStoreType, String keyStorePass) {
|
String keyStorePass) {
|
||||||
SslContextConfigurator scc = new SslContextConfigurator();
|
SslContextConfigurator scc = new SslContextConfigurator();
|
||||||
scc.setTrustStoreFile(trustStoreFile);
|
scc.setTrustStoreFile(trustStoreFile);
|
||||||
scc.setTrustStoreType(trustStoreType);
|
scc.setTrustStoreType(trustStoreType);
|
||||||
@@ -31,12 +31,10 @@ public class HttpClient {
|
|||||||
return scc.createSSLContext();
|
return scc.createSSLContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CloseableHttpClient get(String trustStoreFile, String trustStoreType, String trustStorePass,
|
public static CloseableHttpClient get(String trustStoreFile, String trustStoreType, String trustStorePass, String keyStoreFile, String keyStoreType,
|
||||||
String keyStoreFile, String keyStoreType, String keyStorePass, CookieStore cookieStore,
|
String keyStorePass, CookieStore cookieStore, boolean hostVerificationEnabled) {
|
||||||
boolean hostVerificationEnabled) {
|
|
||||||
|
|
||||||
SSLContext ssl = getSSLContext(trustStoreFile, trustStoreType, trustStorePass, keyStoreFile, keyStoreType,
|
SSLContext ssl = getSSLContext(trustStoreFile, trustStoreType, trustStorePass, keyStoreFile, keyStoreType, keyStorePass);
|
||||||
keyStorePass);
|
|
||||||
return get(ssl, cookieStore, hostVerificationEnabled);
|
return get(ssl, cookieStore, hostVerificationEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,8 +42,7 @@ public class HttpClient {
|
|||||||
return get(ssl, cookieStore, hostVerificationEnabled, false);
|
return get(ssl, cookieStore, hostVerificationEnabled, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CloseableHttpClient get(SSLContext ssl, CookieStore cookieStore, boolean hostVerificationEnabled,
|
public static CloseableHttpClient get(SSLContext ssl, CookieStore cookieStore, boolean hostVerificationEnabled, boolean clientAuth) {
|
||||||
boolean clientAuth) {
|
|
||||||
HostnameVerifier hostnameVerifier;
|
HostnameVerifier hostnameVerifier;
|
||||||
if (hostVerificationEnabled) {
|
if (hostVerificationEnabled) {
|
||||||
hostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
|
hostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
|
||||||
@@ -55,16 +52,15 @@ public class HttpClient {
|
|||||||
RequestConfig defaultRequestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
|
RequestConfig defaultRequestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
|
||||||
HttpClientBuilder builder;
|
HttpClientBuilder builder;
|
||||||
if (cookieStore == null) {
|
if (cookieStore == null) {
|
||||||
builder = HttpClients.custom().setSSLContext(ssl).disableCookieManagement()
|
builder = HttpClients.custom().setSSLContext(ssl).disableCookieManagement().setDefaultRequestConfig(defaultRequestConfig)
|
||||||
.setDefaultRequestConfig(defaultRequestConfig).setSSLHostnameVerifier(hostnameVerifier);
|
.setSSLHostnameVerifier(hostnameVerifier);
|
||||||
} else {
|
} else {
|
||||||
builder = HttpClients.custom().setSSLContext(ssl).setDefaultCookieStore(cookieStore)
|
builder = HttpClients.custom().setSSLContext(ssl).setDefaultCookieStore(cookieStore).setDefaultRequestConfig(defaultRequestConfig)
|
||||||
.setDefaultRequestConfig(defaultRequestConfig).setSSLHostnameVerifier(hostnameVerifier);
|
.setSSLHostnameVerifier(hostnameVerifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientAuth) {
|
if (clientAuth) {
|
||||||
SSLConnectionSocketFactory sslCSF = new SSLConnectionSocketFactory(ssl,
|
SSLConnectionSocketFactory sslCSF = new SSLConnectionSocketFactory(ssl, new String[] {"TLSv1.1", "TLSv1.2"}, null, hostnameVerifier);
|
||||||
new String[] { "TLSv1.1", "TLSv1.2" }, null, hostnameVerifier);
|
|
||||||
builder.setSSLSocketFactory(sslCSF);
|
builder.setSSLSocketFactory(sslCSF);
|
||||||
}
|
}
|
||||||
return builder.build();
|
return builder.build();
|
||||||
|
|||||||
@@ -4,31 +4,41 @@ import java.io.BufferedWriter;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class TcpClient implements AutoCloseable {
|
public class TcpClient implements AutoCloseable {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(TcpClient.class);
|
private static final Logger log = LoggerFactory.getLogger(TcpClient.class);
|
||||||
|
|
||||||
private final String host;
|
private final String host;
|
||||||
private final int port;
|
private final int port;
|
||||||
private Socket sock = null;
|
private Socket sock = null;
|
||||||
private BufferedWriter out = null;
|
private BufferedWriter out = null;
|
||||||
private long connectTime = 0L;
|
private long connectTime = 0L;
|
||||||
private long backoff = 2000;
|
private long INIT_BACKOFF = 1000;
|
||||||
private int bufferSize = -1;
|
private long MAX_BACKOFF = 60000;
|
||||||
|
private long backoff = INIT_BACKOFF;
|
||||||
|
private int bufferSize;
|
||||||
|
private long latency;
|
||||||
private int writesSinceFlush = 0;
|
private int writesSinceFlush = 0;
|
||||||
|
private long lastFlushTime = System.currentTimeMillis();
|
||||||
|
|
||||||
public TcpClient(String hostname, int port) {
|
public TcpClient(String hostname, int port) {
|
||||||
this(hostname, port, -1);
|
this(hostname, port, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TcpClient(String hostname, int port, int bufferSize) {
|
public TcpClient(String hostname, int port, int bufferSize) {
|
||||||
|
this(hostname, port, bufferSize, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TcpClient(String hostname, int port, int bufferSize, long latency) {
|
||||||
this.host = hostname;
|
this.host = hostname;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.bufferSize = bufferSize;
|
this.bufferSize = bufferSize;
|
||||||
|
this.latency = latency;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,20 +63,54 @@ public class TcpClient implements AutoCloseable {
|
|||||||
if (connect() != 0) {
|
if (connect() != 0) {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
out.write(metric);
|
try {
|
||||||
writesSinceFlush++;
|
out.write(metric);
|
||||||
if (bufferSize > 0 && writesSinceFlush >= bufferSize) {
|
writesSinceFlush++;
|
||||||
flush();
|
if (bufferSize > 0 && writesSinceFlush >= bufferSize) {
|
||||||
|
if (log.isTraceEnabled()) {
|
||||||
|
log.trace(String.format("Flushing buffer writesSinceFlush >= %d", writesSinceFlush));
|
||||||
|
}
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
if (latency > 0 && (System.currentTimeMillis() - lastFlushTime) >= latency) {
|
||||||
|
if (log.isTraceEnabled()) {
|
||||||
|
log.trace(String.format("Flushing buffer timeSinceFlush >= %d", latency));
|
||||||
|
}
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
reset();
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void flush() throws IOException {
|
public synchronized void flush() throws IOException {
|
||||||
if (null != out) {
|
if (null != out) {
|
||||||
out.flush();
|
try {
|
||||||
writesSinceFlush = 0;
|
long start = System.currentTimeMillis();
|
||||||
|
out.flush();
|
||||||
|
lastFlushTime = System.currentTimeMillis();
|
||||||
|
if (log.isTraceEnabled()) {
|
||||||
|
log.trace(String.format("Flushed %d metrics to socket in %d ms", writesSinceFlush, (lastFlushTime - start)));
|
||||||
|
}
|
||||||
|
writesSinceFlush = 0;
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(String.format("Failed to flush %d metrics to socket", writesSinceFlush), e);
|
||||||
|
reset();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized void reset() {
|
||||||
|
out = null;
|
||||||
|
sock = null;
|
||||||
|
backoff = INIT_BACKOFF;
|
||||||
|
writesSinceFlush = 0;
|
||||||
|
lastFlushTime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the tcp connection to Timely
|
* Closes the tcp connection to Timely
|
||||||
*
|
*
|
||||||
@@ -74,8 +118,8 @@ public class TcpClient implements AutoCloseable {
|
|||||||
* if an error occurs
|
* if an error occurs
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public synchronized void close() throws IOException {
|
||||||
LOG.trace("Shutting down connection to Timely at {}:{}", host, port);
|
log.info(String.format("Shutting down connection to Timely at %s:%d", host, port));
|
||||||
if (null != sock) {
|
if (null != sock) {
|
||||||
try {
|
try {
|
||||||
if (null != out) {
|
if (null != out) {
|
||||||
@@ -86,7 +130,7 @@ public class TcpClient implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
sock.close();
|
sock.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.error("Error closing connection to Timely at " + host + ":" + port + ". Error: " + e.getMessage());
|
log.error(String.format("Error closing connection to Timely at %s:%d", host, port), e);
|
||||||
} finally {
|
} finally {
|
||||||
sock = null;
|
sock = null;
|
||||||
}
|
}
|
||||||
@@ -96,22 +140,48 @@ public class TcpClient implements AutoCloseable {
|
|||||||
private synchronized int connect() {
|
private synchronized int connect() {
|
||||||
if (null == sock || !sock.isConnected()) {
|
if (null == sock || !sock.isConnected()) {
|
||||||
if (System.currentTimeMillis() > (connectTime + backoff)) {
|
if (System.currentTimeMillis() > (connectTime + backoff)) {
|
||||||
|
OutputStreamWriter osw = null;
|
||||||
try {
|
try {
|
||||||
connectTime = System.currentTimeMillis();
|
connectTime = System.currentTimeMillis();
|
||||||
sock = new Socket(host, port);
|
sock = new Socket(host, port);
|
||||||
out = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
|
osw = new OutputStreamWriter(sock.getOutputStream(), StandardCharsets.UTF_8);
|
||||||
backoff = 2000;
|
out = new BufferedWriter(osw);
|
||||||
LOG.trace("Connected to Timely at {}:{}", host, port);
|
backoff = INIT_BACKOFF;
|
||||||
} catch (IOException e) {
|
log.info(String.format("Connected to Timely at %s:%d", host, port));
|
||||||
LOG.error("Error connecting to Timely at {}:" + host + ":" + port + ". Error: " + e.getMessage());
|
} catch (Exception e) {
|
||||||
backoff = backoff * 2;
|
log.error(String.format("Error connecting to Timely at %s:%d", host, port), e);
|
||||||
sock = null;
|
if (sock != null) {
|
||||||
out = null;
|
try {
|
||||||
LOG.info("Will retry connection in {} ms.", backoff);
|
sock.close();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
log.error(e1.getMessage());
|
||||||
|
} finally {
|
||||||
|
sock = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (osw != null) {
|
||||||
|
try {
|
||||||
|
osw.close();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
log.error(e1.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (out != null) {
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
log.error(e1.getMessage());
|
||||||
|
} finally {
|
||||||
|
out = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backoff = Math.min(MAX_BACKOFF, backoff * 2);
|
||||||
|
if (log.isTraceEnabled()) {
|
||||||
|
log.trace(String.format("Will retry connection in %d ms", backoff));
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG.warn("Not writing to Timely, waiting to reconnect");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,4 +191,22 @@ public class TcpClient implements AutoCloseable {
|
|||||||
public long getConnectTime() {
|
public long getConnectTime() {
|
||||||
return connectTime;
|
return connectTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getWritesSinceFlush() {
|
||||||
|
return writesSinceFlush;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimeSinceFlush() {
|
||||||
|
return System.currentTimeMillis() - lastFlushTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean isConnected() {
|
||||||
|
boolean isConnected = (null != sock && sock.isConnected());
|
||||||
|
if (isConnected) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
int status = connect();
|
||||||
|
return status == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
public class UdpClient implements AutoCloseable {
|
public class UdpClient implements AutoCloseable {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(UdpClient.class);
|
private static final Logger log = LoggerFactory.getLogger(UdpClient.class);
|
||||||
|
|
||||||
private final String host;
|
private final String host;
|
||||||
private final int port;
|
private final int port;
|
||||||
@@ -38,12 +38,11 @@ public class UdpClient implements AutoCloseable {
|
|||||||
throw new IllegalStateException("Must call open first");
|
throw new IllegalStateException("Must call open first");
|
||||||
}
|
}
|
||||||
this.packet.setData(metric.getBytes(UTF_8));
|
this.packet.setData(metric.getBytes(UTF_8));
|
||||||
LOG.info("writing '" + metric + "' to " + this.host + ":" + this.port);
|
log.info("writing '" + metric + "' to " + this.host + ":" + this.port);
|
||||||
this.sock.send(packet);
|
this.sock.send(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {}
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (null != sock) {
|
if (null != sock) {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import java.util.Map;
|
|||||||
import javax.websocket.CloseReason;
|
import javax.websocket.CloseReason;
|
||||||
import javax.websocket.Endpoint;
|
import javax.websocket.Endpoint;
|
||||||
import javax.websocket.EndpointConfig;
|
import javax.websocket.EndpointConfig;
|
||||||
import javax.websocket.MessageHandler;
|
|
||||||
import javax.websocket.Session;
|
import javax.websocket.Session;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -14,30 +13,25 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
public abstract class ClientHandler extends Endpoint {
|
public abstract class ClientHandler extends Endpoint {
|
||||||
|
|
||||||
private final static Logger LOG = LoggerFactory.getLogger(ClientHandler.class);
|
private final static Logger log = LoggerFactory.getLogger(ClientHandler.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOpen(Session session, EndpointConfig config) {
|
public void onOpen(Session session, EndpointConfig config) {
|
||||||
LOG.info("Websocket session {} opened.", session.getId());
|
log.info("Websocket session {} opened.", session.getId());
|
||||||
session.addMessageHandler(new MessageHandler.Whole<String>() {
|
session.addMessageHandler(String.class, message -> {
|
||||||
|
log.info("Message received on Websocket session {}: {}", session.getId(), message);
|
||||||
@Override
|
|
||||||
public void onMessage(String message) {
|
|
||||||
LOG.info("Message received on Websocket session {}: {}", session.getId(), message);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClose(Session session, CloseReason reason) {
|
public void onClose(Session session, CloseReason reason) {
|
||||||
LOG.info("Websocket session {} closed.", session.getId());
|
log.info("Websocket session {} closed.", session.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(Session session, Throwable error) {
|
public void onError(Session session, Throwable error) {
|
||||||
LOG.error("Error occurred on Websocket session" + session.getId(), error);
|
log.error("Error occurred on Websocket session" + session.getId(), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void beforeRequest(Map<String, List<String>> headers) {
|
public void beforeRequest(Map<String,List<String>> headers) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ public class TimelyEndpointConfig implements ClientEndpointConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> getUserProperties() {
|
public Map<String,Object> getUserProperties() {
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ public class TimelyEndpointConfig implements ClientEndpointConfig {
|
|||||||
return new Configurator() {
|
return new Configurator() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beforeRequest(Map<String, List<String>> headers) {
|
public void beforeRequest(Map<String,List<String>> headers) {
|
||||||
super.beforeRequest(headers);
|
super.beforeRequest(headers);
|
||||||
if (null != sessionCookie) {
|
if (null != sessionCookie) {
|
||||||
headers.put("Cookie", Collections.singletonList(sessionCookie));
|
headers.put("Cookie", Collections.singletonList(sessionCookie));
|
||||||
|
|||||||
@@ -10,17 +10,13 @@ import javax.net.ssl.SSLContext;
|
|||||||
import javax.websocket.DeploymentException;
|
import javax.websocket.DeploymentException;
|
||||||
import javax.websocket.Session;
|
import javax.websocket.Session;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
import org.apache.http.client.HttpResponseException;
|
import org.apache.http.client.HttpResponseException;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
import org.apache.http.client.methods.HttpPost;
|
|
||||||
import org.apache.http.client.methods.HttpRequestBase;
|
import org.apache.http.client.methods.HttpRequestBase;
|
||||||
import org.apache.http.client.utils.HttpClientUtils;
|
import org.apache.http.client.utils.HttpClientUtils;
|
||||||
import org.apache.http.cookie.Cookie;
|
import org.apache.http.cookie.Cookie;
|
||||||
import org.apache.http.entity.StringEntity;
|
|
||||||
import org.apache.http.impl.client.BasicCookieStore;
|
import org.apache.http.impl.client.BasicCookieStore;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.glassfish.tyrus.client.ClientManager;
|
import org.glassfish.tyrus.client.ClientManager;
|
||||||
@@ -28,21 +24,20 @@ import org.glassfish.tyrus.client.ClientProperties;
|
|||||||
import org.glassfish.tyrus.client.SslEngineConfigurator;
|
import org.glassfish.tyrus.client.SslEngineConfigurator;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import timely.api.BasicAuthLogin;
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
import timely.client.http.HttpClient;
|
import timely.client.http.HttpClient;
|
||||||
import timely.serialize.JsonSerializer;
|
|
||||||
|
|
||||||
public class WebSocketClient implements AutoCloseable {
|
public class WebSocketClient implements AutoCloseable {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(WebSocketClient.class);
|
private static final Logger log = LoggerFactory.getLogger(WebSocketClient.class);
|
||||||
|
|
||||||
private final String timelyHostname;
|
private final String timelyHostname;
|
||||||
private final int timelyHttpsPort;
|
private final int timelyHttpsPort;
|
||||||
private final int timelyWssPort;
|
private final int timelyWssPort;
|
||||||
private final boolean doLogin;
|
private final boolean doLogin;
|
||||||
private final boolean clientAuth;
|
private final boolean clientAuth;
|
||||||
private final String timelyUsername;
|
|
||||||
private final String timelyPassword;
|
|
||||||
private final boolean hostVerificationEnabled;
|
private final boolean hostVerificationEnabled;
|
||||||
private final int bufferSize;
|
private final int bufferSize;
|
||||||
private final SSLContext ssl;
|
private final SSLContext ssl;
|
||||||
@@ -51,39 +46,27 @@ public class WebSocketClient implements AutoCloseable {
|
|||||||
protected Session session = null;
|
protected Session session = null;
|
||||||
protected volatile boolean closed = true;
|
protected volatile boolean closed = true;
|
||||||
|
|
||||||
protected WebSocketClient(SSLContext ssl, String timelyHostname, int timelyHttpsPort, int timelyWssPort,
|
protected WebSocketClient(SSLContext ssl, String timelyHostname, int timelyHttpsPort, int timelyWssPort, boolean clientAuth, boolean doLogin,
|
||||||
boolean clientAuth, boolean doLogin, String timelyUsername, String timelyPassword,
|
boolean hostVerificationEnabled, int bufferSize) {
|
||||||
boolean hostVerificationEnabled, int bufferSize) {
|
|
||||||
this.ssl = ssl;
|
this.ssl = ssl;
|
||||||
this.timelyHostname = timelyHostname;
|
this.timelyHostname = timelyHostname;
|
||||||
this.timelyHttpsPort = timelyHttpsPort;
|
this.timelyHttpsPort = timelyHttpsPort;
|
||||||
this.timelyWssPort = timelyWssPort;
|
this.timelyWssPort = timelyWssPort;
|
||||||
this.doLogin = doLogin;
|
this.doLogin = doLogin;
|
||||||
this.clientAuth = clientAuth;
|
this.clientAuth = clientAuth;
|
||||||
this.timelyUsername = timelyUsername;
|
|
||||||
this.timelyPassword = timelyPassword;
|
|
||||||
this.hostVerificationEnabled = hostVerificationEnabled;
|
this.hostVerificationEnabled = hostVerificationEnabled;
|
||||||
this.bufferSize = bufferSize;
|
this.bufferSize = bufferSize;
|
||||||
|
|
||||||
Preconditions.checkNotNull(timelyHostname, "%s must be supplied", "Timely host name");
|
Preconditions.checkNotNull(timelyHostname, "%s must be supplied", "Timely host name");
|
||||||
Preconditions.checkNotNull(timelyHttpsPort, "%s must be supplied", "Timely HTTPS port");
|
Preconditions.checkNotNull(timelyHttpsPort, "%s must be supplied", "Timely HTTPS port");
|
||||||
Preconditions.checkNotNull(timelyWssPort, "%s must be supplied", "Timely WSS port");
|
Preconditions.checkNotNull(timelyWssPort, "%s must be supplied", "Timely WSS port");
|
||||||
|
|
||||||
if (doLogin && !clientAuth) {
|
|
||||||
if ((StringUtils.isEmpty(timelyUsername) && !StringUtils.isEmpty(timelyPassword)
|
|
||||||
|| (!StringUtils.isEmpty(timelyUsername) && StringUtils.isEmpty(timelyPassword)))) {
|
|
||||||
throw new IllegalArgumentException("Both Timely username and password must be empty or non-empty");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected WebSocketClient(String timelyHostname, int timelyHttpsPort, int timelyWssPort, boolean clientAuth,
|
protected WebSocketClient(String timelyHostname, int timelyHttpsPort, int timelyWssPort, boolean clientAuth, boolean doLogin, String keyStoreFile,
|
||||||
boolean doLogin, String timelyUsername, String timelyPassword, String keyStoreFile, String keyStoreType,
|
String keyStoreType, String keyStorePass, String trustStoreFile, String trustStoreType, String trustStorePass,
|
||||||
String keyStorePass, String trustStoreFile, String trustStoreType, String trustStorePass,
|
boolean hostVerificationEnabled, int bufferSize) {
|
||||||
boolean hostVerificationEnabled, int bufferSize) {
|
this(HttpClient.getSSLContext(trustStoreFile, trustStoreType, trustStorePass, keyStoreFile, keyStoreType, keyStorePass), timelyHostname,
|
||||||
this(HttpClient.getSSLContext(trustStoreFile, trustStoreType, trustStorePass, keyStoreFile, keyStoreType,
|
timelyHttpsPort, timelyWssPort, clientAuth, doLogin, hostVerificationEnabled, bufferSize);
|
||||||
keyStorePass), timelyHostname, timelyHttpsPort, timelyWssPort, clientAuth, doLogin, timelyUsername,
|
|
||||||
timelyPassword, hostVerificationEnabled, bufferSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void open(ClientHandler clientEndpoint) throws IOException, DeploymentException, URISyntaxException {
|
public void open(ClientHandler clientEndpoint) throws IOException, DeploymentException, URISyntaxException {
|
||||||
@@ -93,30 +76,16 @@ public class WebSocketClient implements AutoCloseable {
|
|||||||
try (CloseableHttpClient client = HttpClient.get(ssl, cookieJar, hostVerificationEnabled, clientAuth)) {
|
try (CloseableHttpClient client = HttpClient.get(ssl, cookieJar, hostVerificationEnabled, clientAuth)) {
|
||||||
|
|
||||||
String target = "https://" + timelyHostname + ":" + timelyHttpsPort + "/login";
|
String target = "https://" + timelyHostname + ":" + timelyHttpsPort + "/login";
|
||||||
|
|
||||||
HttpRequestBase request = null;
|
HttpRequestBase request = null;
|
||||||
if (StringUtils.isEmpty(timelyUsername)) {
|
// HTTP GET to /login to use certificate based login
|
||||||
// HTTP GET to /login to use certificate based login
|
request = new HttpGet(target);
|
||||||
request = new HttpGet(target);
|
log.trace("Performing client certificate login");
|
||||||
LOG.trace("Performing client certificate login");
|
|
||||||
} else {
|
|
||||||
// HTTP POST to /login to use username/password
|
|
||||||
BasicAuthLogin login = new BasicAuthLogin();
|
|
||||||
login.setUsername(timelyUsername);
|
|
||||||
login.setPassword(timelyPassword);
|
|
||||||
String payload = JsonSerializer.getObjectMapper().writeValueAsString(login);
|
|
||||||
HttpPost post = new HttpPost(target);
|
|
||||||
post.setEntity(new StringEntity(payload));
|
|
||||||
request = post;
|
|
||||||
LOG.trace("Performing BasicAuth login");
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpResponse response = null;
|
HttpResponse response = null;
|
||||||
try {
|
try {
|
||||||
response = client.execute(request);
|
response = client.execute(request);
|
||||||
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
|
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
|
||||||
throw new HttpResponseException(response.getStatusLine().getStatusCode(),
|
throw new HttpResponseException(response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase());
|
||||||
response.getStatusLine().getReasonPhrase());
|
|
||||||
}
|
}
|
||||||
for (Cookie c : cookieJar.getCookies()) {
|
for (Cookie c : cookieJar.getCookies()) {
|
||||||
if (c.getName().equals("TSESSIONID")) {
|
if (c.getName().equals("TSESSIONID")) {
|
||||||
@@ -125,8 +94,7 @@ public class WebSocketClient implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (null == sessionCookie) {
|
if (null == sessionCookie) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException("Unable to find TSESSIONID cookie header in Timely login response");
|
||||||
"Unable to find TSESSIONID cookie header in Timely login response");
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
HttpClientUtils.closeQuietly(response);
|
HttpClientUtils.closeQuietly(response);
|
||||||
@@ -142,15 +110,14 @@ public class WebSocketClient implements AutoCloseable {
|
|||||||
webSocketClient.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngine);
|
webSocketClient.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngine);
|
||||||
webSocketClient.getProperties().put(ClientProperties.INCOMING_BUFFER_SIZE, bufferSize);
|
webSocketClient.getProperties().put(ClientProperties.INCOMING_BUFFER_SIZE, bufferSize);
|
||||||
String wssPath = "wss://" + timelyHostname + ":" + timelyWssPort + "/websocket";
|
String wssPath = "wss://" + timelyHostname + ":" + timelyWssPort + "/websocket";
|
||||||
session = webSocketClient.connectToServer(clientEndpoint,
|
session = webSocketClient.connectToServer(clientEndpoint, new TimelyEndpointConfig(clientEndpoint, sessionCookie), new URI(wssPath));
|
||||||
new TimelyEndpointConfig(clientEndpoint, sessionCookie), new URI(wssPath));
|
|
||||||
|
|
||||||
final ByteBuffer pingData = ByteBuffer.allocate(0);
|
final ByteBuffer pingData = ByteBuffer.allocate(0);
|
||||||
webSocketClient.getScheduledExecutorService().scheduleAtFixedRate(() -> {
|
webSocketClient.getScheduledExecutorService().scheduleAtFixedRate(() -> {
|
||||||
try {
|
try {
|
||||||
session.getBasicRemote().sendPing(pingData);
|
session.getBasicRemote().sendPing(pingData);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error("Error sending ping", e);
|
log.error("Error sending ping", e);
|
||||||
}
|
}
|
||||||
}, 30, 60, TimeUnit.SECONDS);
|
}, 30, 60, TimeUnit.SECONDS);
|
||||||
closed = false;
|
closed = false;
|
||||||
|
|||||||
+19
-18
@@ -13,37 +13,35 @@ import javax.websocket.DeploymentException;
|
|||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import timely.api.AddSubscription;
|
import timely.api.AddSubscription;
|
||||||
import timely.api.CloseSubscription;
|
import timely.api.CloseSubscription;
|
||||||
import timely.api.CreateSubscription;
|
import timely.api.CreateSubscription;
|
||||||
import timely.api.RemoveSubscription;
|
import timely.api.RemoveSubscription;
|
||||||
|
import timely.api.VersionRequest;
|
||||||
import timely.client.websocket.ClientHandler;
|
import timely.client.websocket.ClientHandler;
|
||||||
import timely.client.websocket.WebSocketClient;
|
import timely.client.websocket.WebSocketClient;
|
||||||
import timely.serialize.JsonSerializer;
|
import timely.serialize.JsonSerializer;
|
||||||
|
|
||||||
public class WebSocketSubscriptionClient extends WebSocketClient {
|
public class WebSocketSubscriptionClient extends WebSocketClient {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(WebSocketSubscriptionClient.class);
|
private static final Logger log = LoggerFactory.getLogger(WebSocketSubscriptionClient.class);
|
||||||
private final String subscriptionId;
|
private final String subscriptionId;
|
||||||
|
|
||||||
public WebSocketSubscriptionClient(SSLContext ssl, String timelyHostname, int timelyHttpsPort, int timelyWssPort,
|
public WebSocketSubscriptionClient(SSLContext ssl, String timelyHostname, int timelyHttpsPort, int timelyWssPort, boolean clientAuth, boolean doLogin,
|
||||||
boolean clientAuth, boolean doLogin, String timelyUsername, String timelyPassword,
|
boolean hostVerificationEnabled, int bufferSize) {
|
||||||
boolean hostVerificationEnabled, int bufferSize) {
|
super(ssl, timelyHostname, timelyHttpsPort, timelyWssPort, clientAuth, doLogin, hostVerificationEnabled, bufferSize);
|
||||||
super(ssl, timelyHostname, timelyHttpsPort, timelyWssPort, clientAuth, doLogin, timelyUsername, timelyPassword,
|
|
||||||
hostVerificationEnabled, bufferSize);
|
|
||||||
subscriptionId = UUID.randomUUID().toString();
|
subscriptionId = UUID.randomUUID().toString();
|
||||||
LOG.trace("Created WebSocketClient with subscriptionId {}", this.subscriptionId);
|
log.trace("Created WebSocketClient with subscriptionId {}", this.subscriptionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebSocketSubscriptionClient(String timelyHostname, int timelyHttpsPort, int timelyWssPort,
|
public WebSocketSubscriptionClient(String timelyHostname, int timelyHttpsPort, int timelyWssPort, boolean clientAuth, boolean doLogin, String keyStoreFile,
|
||||||
boolean clientAuth, boolean doLogin, String timelyUsername, String timelyPassword, String keyStoreFile,
|
String keyStoreType, String keyStorePass, String trustStoreFile, String trustStoreType, String trustStorePass,
|
||||||
String keyStoreType, String keyStorePass, String trustStoreFile, String trustStoreType,
|
boolean hostVerificationEnabled, int bufferSize) {
|
||||||
String trustStorePass, boolean hostVerificationEnabled, int bufferSize) {
|
super(timelyHostname, timelyHttpsPort, timelyWssPort, clientAuth, doLogin, keyStoreFile, keyStoreType, keyStorePass, trustStoreFile, trustStoreType,
|
||||||
super(timelyHostname, timelyHttpsPort, timelyWssPort, clientAuth, doLogin, timelyUsername, timelyPassword,
|
trustStorePass, hostVerificationEnabled, bufferSize);
|
||||||
keyStoreFile, keyStoreType, keyStorePass, trustStoreFile, trustStoreType, trustStorePass,
|
|
||||||
hostVerificationEnabled, bufferSize);
|
|
||||||
subscriptionId = UUID.randomUUID().toString();
|
subscriptionId = UUID.randomUUID().toString();
|
||||||
LOG.trace("Created WebSocketClient with subscriptionId {}", this.subscriptionId);
|
log.trace("Created WebSocketClient with subscriptionId {}", this.subscriptionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -63,14 +61,13 @@ public class WebSocketSubscriptionClient extends WebSocketClient {
|
|||||||
session.getBasicRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(close));
|
session.getBasicRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(close));
|
||||||
session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Client called close."));
|
session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Client called close."));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.info("Unable to send close message to server: {}", e.getMessage());
|
log.info("Unable to send close message to server: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.close();
|
super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Future<Void> addSubscription(String metric, Map<String, String> tags, long startTime, long endTime,
|
public Future<Void> addSubscription(String metric, Map<String,String> tags, long startTime, long endTime, long delayTime) throws IOException {
|
||||||
long delayTime) throws IOException {
|
|
||||||
AddSubscription add = new AddSubscription();
|
AddSubscription add = new AddSubscription();
|
||||||
add.setSubscriptionId(subscriptionId);
|
add.setSubscriptionId(subscriptionId);
|
||||||
add.setMetric(metric);
|
add.setMetric(metric);
|
||||||
@@ -88,4 +85,8 @@ public class WebSocketSubscriptionClient extends WebSocketClient {
|
|||||||
return session.getAsyncRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(remove));
|
return session.getAsyncRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(remove));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Future<Void> requestVersion() throws Exception {
|
||||||
|
VersionRequest version = new VersionRequest();
|
||||||
|
return session.getAsyncRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(version));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<FindBugsFilter>
|
<FindBugsFilter>
|
||||||
<Match>
|
<Match>
|
||||||
<Bug pattern="DM_DEFAULT_ENCODING"/>
|
<!-- these are probably avoidable, but needs further triage to fix -->
|
||||||
<Method name="connect" />
|
<Bug pattern="MS_EXPOSE_REP" />
|
||||||
<Class name="timely.client.tcp.TcpClient"/>
|
|
||||||
</Match>
|
</Match>
|
||||||
<Match>
|
<Match>
|
||||||
<!-- Must ignore these everywhere, because of a javac byte code generation bug -->
|
<!-- these are probably avoidable, but needs further triage to fix -->
|
||||||
<!-- https://github.com/spotbugs/spotbugs/issues/756 -->
|
<Bug pattern="EI_EXPOSE_REP" />
|
||||||
<Bug pattern="RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE" />
|
</Match>
|
||||||
|
<Match>
|
||||||
|
<!-- these are probably avoidable, but needs further triage to fix -->
|
||||||
|
<Bug pattern="EI_EXPOSE_REP2" />
|
||||||
</Match>
|
</Match>
|
||||||
</FindBugsFilter>
|
</FindBugsFilter>
|
||||||
@@ -1,22 +1,16 @@
|
|||||||
package timely.api;
|
package timely.api;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import timely.serialize.JsonSerializer;
|
import timely.serialize.JsonSerializer;
|
||||||
|
|
||||||
public class SerializationTest {
|
public class SerializationTest {
|
||||||
|
|
||||||
private ObjectMapper mapper = JsonSerializer.getObjectMapper();
|
private ObjectMapper mapper = JsonSerializer.getObjectMapper();
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testBasicAuth() throws Exception {
|
|
||||||
BasicAuthLogin login = new BasicAuthLogin();
|
|
||||||
login.setUsername("test");
|
|
||||||
login.setPassword("pass");
|
|
||||||
testSerialization(login);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateSubscription() throws Exception {
|
public void testCreateSubscription() throws Exception {
|
||||||
CreateSubscription create = new CreateSubscription();
|
CreateSubscription create = new CreateSubscription();
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import static org.junit.Assert.assertTrue;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
@@ -30,8 +31,7 @@ public class MetricTest {
|
|||||||
Metric m4 = Metric.newBuilder().name("m4").tag("t2", "v2").tag("t1", "v1").value(1, 0.0).build();
|
Metric m4 = Metric.newBuilder().name("m4").tag("t2", "v2").tag("t1", "v1").value(1, 0.0).build();
|
||||||
assertFalse(m1.equals(m4));
|
assertFalse(m1.equals(m4));
|
||||||
|
|
||||||
Metric m5 = Metric.newBuilder().name("m1").tag("t3", "v3").tag("t2", "v2").tag("t1", "v1").value(1, 0.0)
|
Metric m5 = Metric.newBuilder().name("m1").tag("t3", "v3").tag("t2", "v2").tag("t1", "v1").value(1, 0.0).build();
|
||||||
.build();
|
|
||||||
assertFalse(m1.equals(m5));
|
assertFalse(m1.equals(m5));
|
||||||
|
|
||||||
Metric m6 = Metric.newBuilder().name("m1").tag("t2", "v2").tag("t1", "v1").value(2, 0.0).build();
|
Metric m6 = Metric.newBuilder().name("m1").tag("t2", "v2").tag("t1", "v1").value(2, 0.0).build();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import timely.model.Metric;
|
import timely.model.Metric;
|
||||||
import timely.model.Tag;
|
import timely.model.Tag;
|
||||||
|
|
||||||
|
|||||||
Loaded 100 of 744 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user