OpenTSDB之HTTP请求接口、Java开发

  • HTTP API
    • 数据写入
    • 查询数据
    • Timestamp
    • Filtering
    • Aggregation
    • downsample(采样功能)
    • 执行顺序
    • Rate Conversion(增长率)
    • 其他接口
  • JAVA的调用

HTTP API

由于OpenTSDB没有支持Java的SDK进行调用,所以基于Java开发OpenTSDB的调用将要依靠HTTP请求的方式进行。下面就先介绍下部分HTTP API的特性:

数据写入

写入特性

  • 为了节省传输带宽,提高传输效率,该接口可以实现批量写入多个属于不同时序的点
  • 写入请求处理时 ,毫无关系的点分开单独处理,即使其中一个点存储失败,也不会影响其他点的保存;
  • 一次请求的点过多,响应请求的速度会变慢。当HTTP请求体的大小超过一定限制,可以进行分块传输(Chunked Transfer),OpenTSDB可以通过对 tsd.http.request.enable_chunked 的配置设置为true(默认为false),即可使OpenTSDB 支持 HTTP 的 Chunked Transfer Encoding。
  • tsd.mode 的配置对写入操作有影响,配置 ro 表示只读状态,配置 rw 表示读写状态,当写入操作一直失败时,可以确认此配置项。

写入请求可选参数

  • /api/put:根据 url 参数的不同,可以选择是否获取详细的信息。

    • 通过POST方式插入数据,JSON格式,例如
    {"metric":"self.test", "timestamp":1456123787, "value":20, "tags":{"host":"web1"}
    }
    
  • /api/put?summary:返回写入操作的概述信息(包括失败和成功的个数)
    {"failed": 0,"success": 1
    }
    
  • /api/put?details:返回写入操作的详细信息
    {"errors": [],"failed": 0,"success": 1
    }
    
  • /api/put?sync:写入操作为同步写入,即所有点写入完成(成功或失败)才向客户端返回响应,默认为异步写入。
  • /api/put?sync_timeout:同步写入的超时时间。

查询数据

  • /api/query:可以选择 Get 或者 Post 两种方式,推荐使用 Post 方式,

    • 请求JSON 格式
    {"start": 1456123705,        // 该查询的起始时间"end": 1456124985,          // 该查询的结束时间"globalAnnotation": false,  // 查询结果中是否返回 global annotation"noAnnotations": false,     // 查询结果中是否返回 annotation"msResolution": false,      // 返回的点的精度是否为毫秒级,如果该字段为false,// 则同一秒内的点将按照 aggregator 指定的方式聚合得到该秒的最终值"showTSUIDs": true,         // 查询结果中是否携带 tsuid"showQuery": true,          // 查询结果中是否返回对应的子查询"showSummary": false,       // 查询结果中是否携带此次查询时间的一些摘要信息"showStats": false,         // 查询结果中是否携带此次查询时间的一些详细信息"delete": false,            // 注意:如果该值设为true,则所有符合此次查询条件的点都会被删除"queries": [// 子查询,为一个数组,可以指定多条相互独立的子查询]
    }
    
    • Metric Query 类型子查询:指定完整的 metric、tag 及聚合信息。

      • metric 和 tags 是用于过滤的查询条件。
    {"metric": "JVM_Heap_Memory_Usage_MB",    // 查询使用的 metric"aggregator": "sum",                 // 使用的聚合函数"downsample": "30s-avg",              // 采样时间间隔和采样函数"tags": {                               // tag组合,在OpenTSDB 2.0 中已经标记为废弃// 推荐使用下面的 filters 字段"host": "server01"},"filters": [],                         // TagFilter,下面将详细介绍 Filter 相关的内容"explicitTags": false,                    // 查询结果是否只包含 filter 中出现的 tag"rate": false,                            // 是否将查询结果转换成 rate"rateOption": {}                        // 记录了 rate 相关的参数,具体参数后面会进行介绍}
    
    • TSUIDS Query 类型子查询(可看做 Metric Query 的优化):指定一条或多条 tsuid,不再指定 metric、tag 等。
    {"aggregator": "sum",  // 使用的聚合函数"tsuids": [             // 查询的 tsuids 集合,这里的 tsuids 可理解为// 时序数据库的 id"123","456"]
    }
    
    • 返回字符串也为json格式
    [{"metric": "self.test","tags": {},"aggregateTags": ["host"],"dps": {"1456123785": 10,"1456123786": 10}},{"metric": "self.test","tags": {"host": "web1"},"aggregateTags": [],"dps": {"1456123784": 10,"1456123786": 15}}
    ]
    

Timestamp

OpenTSDB的查询中的两种类型的时间:

  • 绝对时间:用于精确指定查询的起止时间,格式 yyyy/MM/dd-HH:mm:ss
  • 相对时间:用于指定查询的时间范围,格式 (amount) (time unit)-ago,例如:3h-ago(查询的结束时间是当前时间,起始时间是3小时之前)。
    • amount:表示时间跨度
    • time out:表示时间跨度单位,相应的时间跨度的单位,ms(毫秒)、s(秒) 、m(分钟)、h(小时)、d(天,24小时)、w(周,7天)、n(月,30天)、y(年,365天)
    • -ago:固定项

由于存储时间序列的最高精度是毫秒,毫秒级、秒级所占用字节数:

  • 使用毫秒精度:HBase RowKey 中的时间戳占用6个字节
  • 使用秒精度:RowKey 中的时间戳占用4个字节

注意:毫秒级存储,在查询时默认返回秒级数据(按照查询中指定的聚合方式对 1秒内的时序数据进行采样聚合,形成最终结果);可以通过 msResolution 参数设置,返回毫秒级数据。

Filtering

Filter 详解:

  • Filter 类似于 SQL 语句中的 Where 子句,主要用于 tagv 的过滤;
  • 同一个子查询中多个 Filter 进行过滤时,FIlter 之间的关系是 AND
  • 多个 Filter 同时对一组 Tag 进行过滤,只要一个 Filter 开启分组功能,就会按照 Tag 进行分组。

Filter 的具体格式:

{"type": "wildcard",    // Fliter 类型,可以直接使用 OpenTSDB 中内置的 Filter,也可以通过插件// 的方式增加自定义的 Filter 类型"tagk": "host",        // 被过滤的 TagKey"filter": "*",         // 过滤表达式,该表达式作用于 TagValue 上,不同类型的 Filter 支持不同形式的表达式"groupBy": true        // 是否对过滤结果进行分组(group by),默认为 false,即查询结果会被聚合成一条时序数据
}

几个实用内置 Filter 类型详解:

  • literal_or、ilteral_or 类型:

    • 支持单个字符串,也支持使用 “|” 连接多个字符串

    • 含义与 SQL 语句中的 “WHERE host IN(‘server01’,‘server02’,‘server03’)” 相同;

    • ilteral_or 是 literal_or 的大小写不敏感版本,使用方式一致。

    • 使用方式:

      {"type": "literal_or","tagk": "host","filter": "server01|server02|server03","groupBy": false
      }
      
  • not_literal_or、not_iliteral_or 类型:

    • 与 literal_or 的含义相反,使用方式与 literal_or 一致
    • 含义与 SQL 语句中的 “WHERE host NOT IN(‘server01’,‘server02’)” 相同;
    • not_ilteral_or 是 not_literal_or 的大小写不敏感版本,使用方式一致。
    • 使用方式:
      {"type": "not_literal_or","tagk": "host","filter": "server01|server02","groupBy": false
      }
      
  • wildcard、iwildcard 类型:

    • wildcard 类型的 Filter 提供前缀、中缀、后缀的匹配功能;
    • 支持使用 “*” 通配符匹配任何字符,其表达式中可以包含多个(但至少包含一个)
    • 使用方式:
    • iwildcard 是 wildcard 的大小写不敏感版本,使用方式一致。
      {"type": "wildcard","tagk": "host","filter": "server*","groupBy": false
      }
      
  • regexp 类型:

    • regexp 类型的 Filter 提供了正则表达式的过滤条件功能;
    • 其含义与 SQL 语句中的 “ WHERE host REGEXP ‘.*’ ” 相同。
      {"type": "regexp","tagk": "host","filter": ".*","groupBy": false
      }
      
  • not_key 类型:

    • not_key 类型的 Filter 提供了过滤指定 TagKey 的功能;
    • 其含义是跳过任何包含 host 这个 TagKey 的时序,注意,其 Filter 表达式必须为空。
      {"type": "not_key","tagk": "host","filter": "","groupBy": false
      }
      

Aggregation

aggregator 是用于对查询结果进行聚合,将同一 unix 时间戳内的数据进行聚合计算后返回结果,例如如果 tags 不填,1456123705 有两条数据,一条 host=web1,另外一条 host=web2,值都为10,那么返回的该时间点的值为 sum 后的 20。

  • 条件过滤
    可以针对 tag 进行一些条件的过滤,返回 tag 中 host 的值以 web 开头的数据。

    "queries": [{"aggregator": "sum","metric": "self.test","filters": [{"type": "wildcard","tagk": "host","filter": "web*"}]}
    ]
    

OpenTSDB 中提供了 interpolation 来解决聚合时数据缺失的补全问题,目前支持如下四种类型:

  • LERP(Linear Interpolation):根据丢失点的前后两个点估计该点的值。

    • 例如,时间戳 t1 处的点丢失,则使用 t0 和 t2 两个点的值(其前后两个点)估计 t1 的值,公式是: v 1 = v 0 + ( v 2 − v 0 ) ∗ ( ( t 1 − t 0 ) / ( t 2 − t 0 ) ) v1=v0+(v2-v0)*((t1-t0)/(t2-t0)) v1=v0+(v2−v0)∗((t1−t0)/(t2−t0));这里假设 t0、t1、t2 的时间间隔为 5s,v0 和 v2 分别是 10 和 20,则 v1 的估计值为 15。
    • ZIM(Zero if missing):如果存在丢失点,则使用 0 进行替换。
    • MAX:如果存在丢失点,则使用其类型的最大值替换。
    • MIN:如果存在丢失点,则使用其类型的最小值替换。

列出部分常用的Aggregator 函数 机器使用的 Interpolation 类型:

Aggregator 描述 Interpolation
avg 计算平均值作为聚合结果 Linear Interpolation
count 点的个数作为聚合结果 ZIM
dev 标准差 Linear Interpolation
min 最小值作为聚合结果 Linear Interpolation
max 最大值作为聚合结果 Linear Interpolation
sum 求和 Linear Interpolation
zimsum 求和 ZIM
p99 将p99作为聚合结果 Linear Interpolation

downsample(采样功能)

简单来说就是对指定时间段内的数据进行聚合后返回;例如,需要返回每分钟的平均值数据,按照 5m-avg 的方式进行采样;分析 5m-avg 参数:

  • 第一部分,采样的时间范围,即5分钟一次采样;
  • 第二部分,采样使用的聚合函数,这里使用的是 avg(平均值)的聚合方式。

其含义是 每5分钟为一个采样区间,将每个区间的平均值作为返回的点。返回结果中,每个点之间的时间间隔为5分钟。

"queries": [{"aggregator": "sum","metric": "self.test","downsample": "5m-avg","tags": {"host": "web1"}}
]

时序数据的丢失也会对 Downsampling 处理结果产生一定的影响。OpenTSDB 也为 Downsampling 提供了相应的填充策略,Downsampling 的填充策略如下:

  • None(none):默认填充策略,当 Downsampling 结果中缺失某个节点时,不会进行处理,而是在进行 “Aggregator” 时通过相应的 interpolation 进行填充。
  • NaN(nan):当 Downsampling 结果中缺少某个节点时,会将其填充为 NaN,在进行 “Aggregation” 时会跳过该点。
  • Null(null):与 NaN 类似。
  • Zero(zero):当 Downsampling 结果中缺少某个节点时,会将其填充为 0。

执行顺序

Created with Raphaël 2.3.0 Filtering(过滤) Grouping(分组) Downsampling(采样) Interpolation(填充) Aggregation(聚合) Rate Conversion(增长率) Functions(函数) Expressions(表达式)

Rate Conversion(增长率)

在子查询中,有两个字段与 Rate Conversion 相关

  • rate 字段:表示是否进行 Rate Conversion 操作;参数为 true 或 false。
  • rateOptions 字段:记录 Rate Conversion 操作的一些参数,该字段是一个 Map,其中的字段及含义如下。
    • counter 字段:参与 Rate Conversion 操作的时序记录是否为一个会溢出(rollover)的单调递增值。
    • counterMax 字段:时序的最大值,详细介绍。
    • resetValue 字段:当计算得到的比值超过该字段值时会返回0,主要是防止出现异常的峰值。
    • dropResets 字段:是否直接丢弃 resetValue 的点或出现 rollover 的点。

其他接口

  • /api/suggest 接口:该接口的主要功能是根据给定的前缀查询符合该前缀的 metric、tagk 或 tagv,主要用于给页面提供自动补全功能。请求结构如下:

    {"type": "metric",  // 查询的字符串的类型,可选项有 metrics、tagk、tagv"q": "sys",        // 字符串前缀"max": 10         // 此次请求返回值携带的字符串个数上限
    }
    
  • /api/query/exp 接口:该接口支持表达式查询。
  • /api/query/gexp 接口:该接口主要为了兼容 Graphite 到 OpenTSDB 的迁移。
  • /api/query/last 接口:在有些场景中,只需要一条时序数据中最近的一个点的值。
  • /api/uid/assign 接口:该接口主要为 metric、tagk、tagv 分配 UID,UID 的相关内容和分配的具体实现在后面会进行详细分析。
  • /api/uid/tsmeta 接口:该接口支持查询、编辑、删除 TSMeta 元数据。
  • /api/uid/uidmeta 接口:改接口支持编辑、删除 UIDMeta 元数据。
  • /api/annotation 接口:改接口支持添加、编辑、删除 Annotation 数据。

JAVA的调用

OpenTSDB提供三种方式的读写操作:telnet、http、post,但官方并没提供JAVA版的API。在GitHub上有的Java的opentsdb-client ,才使得我能对openTSDB的读写操作进行封装,从而分享至此:https://github.com/shifeng258/opentsdb-client
在此项目上包装开发或将其打包成SDK使用均可。本人将用前一种方式进行的。
增加的一个统一调用类OpentsdbClient

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ygsoft.opentsdb.client.ExpectResponse;
import com.ygsoft.opentsdb.client.HttpClient;
import com.ygsoft.opentsdb.client.HttpClientImpl;
import com.ygsoft.opentsdb.client.builder.MetricBuilder;
import com.ygsoft.opentsdb.client.request.Query;
import com.ygsoft.opentsdb.client.request.QueryBuilder;
import com.ygsoft.opentsdb.client.request.SubQueries;
import com.ygsoft.opentsdb.client.response.Response;
import com.ygsoft.opentsdb.client.response.SimpleHttpResponse;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.IOException;
import java.util.*;/*** Opentsdb读写工具类*/
public class OpentsdbClient {private static Logger log = LoggerFactory.getLogger(OpentsdbClient.class);/*** 取平均值的聚合器*/public static String AGGREGATOR_AVG = "avg";/*** 取累加值的聚合器*/public static String AGGREGATOR_SUM = "sum";private HttpClient httpClient;public OpentsdbClient(String opentsdbUrl) {this.httpClient = new HttpClientImpl(opentsdbUrl);}/*** 写入数据 * @param metric 指标 * @param timestamp 时间点 * @param value * @param tagMap * @return * @throws Exception*/public boolean putData(String metric, Date timestamp, long value, Map tagMap) throws Exception {long timsSecs = timestamp.getTime() / 1000;return this.putData(metric, timsSecs, value, tagMap);}/*** 写入数据 * @param metric 指标  * @param timestamp 时间点 * @param value * @param tagMap * @return * @throws Exception*/public boolean putData(String metric, Date timestamp, double value, Map tagMap) throws Exception {long timsSecs = timestamp.getTime() / 1000;return this.putData(metric, timsSecs, value, tagMap);}/*** 写入数据 * @param metric 指标 * @param timestamp 转化为秒的时间点 * @param value * @param tagMap * @return * @throws Exception*/public boolean putData(String metric, long timestamp, long value, Map tagMap) throws Exception {MetricBuilder builder = MetricBuilder.getInstance();builder.addMetric(metric).setDataPoint(timestamp, value).addTags(tagMap);try {log.debug("write quest:{}", builder.build());Response response = httpClient.pushMetrics(builder, ExpectResponse.SUMMARY);log.debug("response.statusCode: {}", response.getStatusCode());return response.isSuccess();} catch (Exception e) {log.error("put data to opentsdb error: ", e);throw e;}}/*** 写入数据 * @param metric 指标 * @param timestamp 转化为秒的时间点 * @param value * @param tagMap * @return * @throws Exception*/public boolean putData(String metric, long timestamp, double value, Map tagMap) throws Exception {MetricBuilder builder = MetricBuilder.getInstance();builder.addMetric(metric).setDataPoint(timestamp, value).addTags(tagMap);try {log.debug("write quest:{}", builder.build());Response response = httpClient.pushMetrics(builder, ExpectResponse.SUMMARY);log.debug("response.statusCode: {}", response.getStatusCode());return response.isSuccess();} catch (Exception e) {log.error("put data to opentsdb error: ", e);throw e;}}/*** 批量写入数据 * @param metric 指标  * @param timestamp 时间点 * @param value * @param tagMap * @return * @throws Exception*/public boolean putData(JSONArray jsonArr) throws Exception {return this.putDataBatch(jsonArr);}/*** 批量写入数据 * @param metric 指标 * @param timestamp 转化为秒的时间点 * @param value * @param tagMap * @return * @throws Exception*/public boolean putDataBatch(JSONArray jsonArr) throws Exception {MetricBuilder builder = MetricBuilder.getInstance();try {for(int i = 0; i < jsonArr.size(); i++){Map tagMap = new HashMap();for(String key : jsonArr.getJSONObject(i).getJSONObject("tags").keySet()){tagMap.put(key, jsonArr.getJSONObject(i).getJSONObject("tags").get(key));}String metric = jsonArr.getJSONObject(i).getString("metric").toString();long timestamp = DateTimeUtil.parse(jsonArr.getJSONObject(i).getString("timestamp"), "yyyy/MM/dd HH:mm:ss").getTime() / 1000;double value = Double.valueOf(jsonArr.getJSONObject(i).getString("value"));builder.addMetric(metric).setDataPoint(timestamp, value).addTags(tagMap);}log.debug("write quest:{}", builder.build());Response response = httpClient.pushMetrics(builder, ExpectResponse.SUMMARY);log.debug("response.statusCode: {}", response.getStatusCode());return response.isSuccess();} catch (Exception e) {log.error("put data to opentsdb error: ", e);throw e;}}/*** 查询数据,返回的数据为json格式,结构为: * "[ * " { * " metric: mysql.innodb.row_lock_time, * " tags: { * " host: web01, * " dc: beijing * " }, * " aggregateTags: [], * " dps: { * " 1435716527: 1234, * " 1435716529: 2345 * " } * " }, * " { * " metric: mysql.innodb.row_lock_time, * " tags: { * " host: web02, * " dc: beijing * " }, * " aggregateTags: [], * " dps: { * " 1435716627: 3456 * " } * " } * "]"; * @param metric 要查询的指标 * @param aggregator 查询的聚合类型, 如: OpentsdbClient.AGGREGATOR_AVG, OpentsdbClient.AGGREGATOR_SUM * @param tagMap 查询的条件 * @param downsample 采样的时间粒度, 如: 1s,2m,1h,1d,2d * @param startTime 查询开始时间,时间格式为yyyy/MM/dd HH:mm:ss * @param endTime 查询结束时间,时间格式为yyyy/MM/dd HH:mm:ss*/public String getData(String metric, Map tagMap, String aggregator, String downsample, String startTime, String endTime) throws IOException {QueryBuilder queryBuilder = QueryBuilder.getInstance();Query query = queryBuilder.getQuery();query.setStart(DateTimeUtil.parse(startTime, "yyyy/MM/dd HH:mm:ss").getTime() / 1000);query.setEnd(DateTimeUtil.parse(endTime, "yyyy/MM/dd HH:mm:ss").getTime() / 1000);List sqList = new ArrayList();SubQueries sq = new SubQueries();sq.addMetric(metric);sq.addTag(tagMap);sq.addAggregator(aggregator);sq.setDownsample(downsample + "-" + aggregator);sqList.add(sq);query.setQueries(sqList);try {log.debug("query request:{}", queryBuilder.build()); //这行起到校验作用SimpleHttpResponse spHttpResponse = httpClient.pushQueries(queryBuilder, ExpectResponse.DETAIL);log.debug("response.content: {}", spHttpResponse.getContent());if (spHttpResponse.isSuccess()) {return spHttpResponse.getContent();}return null;} catch (IOException e) {log.error("get data from opentsdb error: ", e);throw e;}}/*** 查询数据,返回tags与时序值的映射: Map> * @param metric 要查询的指标 * @param aggregator 查询的聚合类型, 如: OpentsdbClient.AGGREGATOR_AVG, OpentsdbClient.AGGREGATOR_SUM * @param tagMap 查询的条件 * @param downsample 采样的时间粒度, 如: 1s,2m,1h,1d,2d * @param startTime 查询开始时间, 时间格式为yyyy/MM/dd HH:mm:ss * @param endTime 查询结束时间, 时间格式为yyyy/MM/dd HH:mm:ss * @param retTimeFmt 返回的结果集中,时间点的格式, 如:yyyy/MM/dd HH:mm:ss 或 yyyyMMddHH 等 * @return Map>*/public Map getData(String metric, Map tagMap, String aggregator, String downsample, String startTime, String endTime, String retTimeFmt) throws IOException {String resContent = this.getData(metric, tagMap, aggregator, downsample, startTime, endTime);return this.convertContentToMap(resContent, retTimeFmt);}public Map convertContentToMap(String resContent, String retTimeFmt) {Map tagsValuesMap = new HashMap();if (resContent == null || "".equals(resContent.trim())) {return tagsValuesMap;}JSONArray array = (JSONArray) JSONObject.parse(resContent);if (array != null) {for (int i = 0; i < array.size(); i++) {JSONObject obj = (JSONObject) array.get(i);JSONObject tags = (JSONObject) obj.get("tags");JSONObject dps = (JSONObject) obj.get("dps"); //timeValueMap.putAll(dps); Map timeValueMap = new HashMap(); for (Iterator it = dps.keySet().iterator(); it.hasNext(); ) { String timstamp = it.next(); Date datetime = new Date(Long.parseLong(timstamp)*1000); timeValueMap.put(DateTimeUtil.format(datetime, retTimeFmt), dps.get(timstamp)); } tagsValuesMap.put(tags.toString(), timeValueMap); } } return tagsValuesMap; }}}return tagsValuesMap;}
}

增加一个时间处理类

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;public class DateTimeUtil {public static Date parse(String date,String fm){Date res=null;try {SimpleDateFormat sft=new SimpleDateFormat(fm);res=sft.parse(date);} catch (ParseException e) {e.printStackTrace();}return res;}}

为了建立HTTP的长连接,将PoolingHttpClient进行单例模式的修改(防止调用时频繁的实例化引起的资源消耗)

public class PoolingHttpClient {.../*单例模式修改*/private static PoolingHttpClient poolingHttpClient;private PoolingHttpClient() {// Increase max total connectionconnManager.setMaxTotal(maxTotalConnections);// Increase default max connection per routeconnManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);// config timeoutRequestConfig config = RequestConfig.custom().setConnectTimeout(connectTimeout).setConnectionRequestTimeout(waitTimeout).setSocketTimeout(readTimeout).build();httpClient = HttpClients.custom().setKeepAliveStrategy(keepAliveStrategy).setConnectionManager(connManager).setDefaultRequestConfig(config).build();// detect idle and expired connections and close themIdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(connManager);staleMonitor.start();}public static PoolingHttpClient getInstance() {if (null == poolingHttpClient) {//加锁保证线程安全synchronized (PoolingHttpClient.class) {if (null == poolingHttpClient) {poolingHttpClient = new PoolingHttpClient();}}}return poolingHttpClient;}/*单例模式修改结束*/public SimpleHttpResponse doPost(String url, String data)throws IOException {StringEntity requestEntity = new StringEntity(data);HttpPost postMethod = new HttpPost(url);postMethod.setEntity(requestEntity);HttpResponse response = execute(postMethod);int statusCode = response.getStatusLine().getStatusCode();SimpleHttpResponse simpleResponse = new SimpleHttpResponse();simpleResponse.setStatusCode(statusCode);HttpEntity entity = response.getEntity();if (entity != null) {// should return: application/json; charset=UTF-8String ctype = entity.getContentType().getValue();String charset = getResponseCharset(ctype);String content = EntityUtils.toString(entity, charset);simpleResponse.setContent(content);}/*增加线程回收开始*/EntityUtils.consume(entity);postMethod.releaseConnection();/*增加线程回收结束*/return simpleResponse;}...}

修改HttpClientImpl对单例模式的PoolingHttpClient调用

public class HttpClientImpl implements HttpClient {...//private PoolingHttpClient httpClient = new PoolingHttpClient();private PoolingHttpClient httpClient = PoolingHttpClient.getInstance();...
}

OpenTSDB之HTTP请求接口、Java开发相关推荐

  1. jmeter java接口_JMeter接口Java开发五步曲

    想做jmeter接口二次开发但不知道如何入手,要解决这个问题,我们可以分为5个步骤 第一步:了解jmeter处理java请求的流程 第二步:通过实现jmeter中的接口JavaSamplerClien ...

  2. 快递鸟API单号查询接口Java开发调用源码

    快递鸟是专业的第三方物流数据服务商,国家高新技术企业,已先后完成四轮融资,一直专注于企业级物流API技术研发和打通物流各节点信息服务,致力于成为全球最大的物流信息枢纽中心,为零售电商企业级提供标准的物 ...

  3. java http请求实现_java工程实现http请求接口

    java工程实现http请求接口 java工程实现http请求接口 1.实现代码 package com.home; import com.alibaba.fastjson.JSON; import ...

  4. Java开发在线支付平台视频教程(AVI格式)

    Java开发在线支付平台视频教程,主要教授如何让自己的网站与银行系统进行对接.如何让用户通过网上银行向你支付费用等内容,全AVI视频格式 JAVA开发视频内容目录: Java开发在线支付平台视频教程_ ...

  5. 我也没想到,Java开发 API接口可以不用写 Controller了

    大家好,我是小富~ 今天介绍我正在用的一款高效敏捷开发工具magic-api,顺便分享一点工作中使用它的心得 缘起 先说一下我为什么会使用这个工具? 最近新启动一个项目,业务并不算复杂,那种典型的管理 ...

  6. java 轮询请求接口_Android RxJava 实际应用讲解:(无条件)网络请求轮询

    前言 Rxjava,由于其基于事件流的链式调用.逻辑简洁 & 使用简单的特点,深受各大 Android开发者的欢迎. Github截图 RxJava如此受欢迎的原因,在于其提供了丰富 & ...

  7. java服务器访问接口提示network error_北京JAVA开发三年,拿到美团35K的offer面试心得...

    前言 长文干货提示,文章为大家完整记录了一位在北京做了3年的JAVA开发的朋友,如何通过美团的面试及拿到35K的offer.全篇内容由全程电话录音再手打腾稿,原创手打不易,请记得三连支持! 文章末尾有 ...

  8. java请求接口示例_用示例解释Java接口

    java请求接口示例 介面 (Interfaces) Interface in Java is a bit like the Class, but with a significant differe ...

  9. java开发http协议接口_java开发接口利用http协议传输数据

    java开发接口利用http协议传输数据java 这个接口主要用来登陆,java服务器提供一个接口,移动设备客户端(android和ios)能经过这个接口把用户名和密码之类的东东传过来到服务器验证,而 ...

最新文章

  1. SocketIO---bio2---带线程池处理任务
  2. Kafka—简明教程
  3. java学习笔记-良葛格_Java良葛格 学习笔记《二》
  4. SAP cloud platform + 504 gateway time out Cloud connector
  5. linux 如何赋值目录,Linux文件系统之目录的建立
  6. [virtualenvwrapper] 命令小结
  7. WIN10 下 PHP7 中文乱码的解决办法
  8. Spring Data JPA 禁止自动更新
  9. c语言周林答案,C语言程序设计实训教程教学课件作者周林ch04结构化程序设计课件.ppt...
  10. 11-散列1 电话聊天狂人
  11. Mozilla 开源支持计划:首批捐助 7 开源项目 50 万美元
  12. vb UTF文本文件访问
  13. 解决WordPress设置错误的url网站不能访问的问题
  14. Linux shell 中的那些你值得一试的小把戏
  15. IT项目管理规范模板及IT软件招投标模板(共367份,488M)
  16. 你所学的专业是怎么回事——摄影测量与遥感
  17. 【渝粤教育】国家开放大学2018年春季 8624-21T物业管理案例分析 参考试题
  18. 20189200余超 2018-2019-2 移动平台应用开发实践第十一周作业
  19. win10,win11后在cmd命令行输入python自动调用微软应用商店
  20. silhouette value 聚类

热门文章

  1. DataGrip使用进阶(一)
  2. 最大似然法、似然函数及对数似然函数
  3. 在android8.1 展锐 关闭系统的selinux seandroid
  4. 五个小程序用户增长技巧
  5. python协程—asyncio模块
  6. 2023兔年开工大吉
  7. 云展网教程 | 设置单本书籍访问次数限制
  8. 终身学习(LifeLong Learning)/ 增量学习(Incremental Learning)、在线学习(Online Learning)
  9. STC89C52RC最小系统板原理图(12MHZ)
  10. 开源资产管理软件-GLPI安装