OpenTSDB之HTTP请求接口、Java开发

本文档介绍了如何使用OpenTSDB的HTTP API进行数据写入和查询操作,包括使用Java进行开发的方法。涵盖写入数据的特性、请求参数、查询数据的方法、过滤和聚合功能等关键知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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+(v2v0)((t1t0)/(t2t0));这里假设 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 connection
		connManager.setMaxTotal(maxTotalConnections);
		// Increase default max connection per route
		connManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);

		// config timeout
		RequestConfig 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 them
		IdleConnectionMonitorThread 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-8
			String 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();
    
    ...
}
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值