PushMeteringData - 推送计量数据

通过实例内部调用PushMeteringData推送计量数据。

接口说明

  • 该命令只支持推送按量付费的计算巢服务实例的计量数据,推送的计量项需要定义为服务商上报。

  • 通过计算巢服务创建的ECSACK实例,可以直接在ECSACK内部调用该接口推送计量数据。如需采用OpenAPI的方式进行调用,请参见通过OpenAPI调用PushMeteringData

请求参数

名称

类型

是否必选

描述

示例值

Metering

String

示例中的参数说明如下:

  • StartTime:计量开始时间。单位:秒。

  • EndTime:计量结束时间。单位:秒。

  • Entities:计量实体对象。

    • Key:计量项属性名称。

      • Frequency:使用次数(次)。

      • Period:使用小时时长(秒)。

        重要

        请求参数中的时长单位为秒,而计费单位为小时,因此计费时会转换为小时,如推送19:00-20:00的用量1800,计费价格为1元/小时,按小时出账该时段费用为1800/3600×1 = 0.5 元,费用如为小数,保留两位小数,超过两位舍弃。

      • Storage:使用存储空间(Byte)。

        重要

        请求参数中的单位为Byte,而计费单位为MB,因此计费时会转换为MB,如推送19:00-20:00的用量524288,计费价格为 1 元/MB,按小时出账该时段费用为524288/1024/1024×1=0.5 元,费用如为小数,保留两位小数,超过两位舍弃。

      • NetworkOut:上行使用流量(Bit)。

        重要

        请求参数中的单位为Bit,而计费单位为MB,因此计费时会转换为MB,如推送 19:00-20:00 的用量524288,计费价格为 1 元/MB,按小时出账该时段费用为 524288/1024/1024×1 = 0.5 元,费用如为小数,保留两位小数,超过两位舍弃。

      • NetworkIn:下行使用流量(Bit)。

        重要

        请求参数中的单位为Bit,而计费单位为MB,因此计费时会转换为MB,如推送 19:00-20:00 的用量524288,计费价格为1 元/MB,按小时出账该时段费用为 524288/1024/1024×1=0.5 元,费用如为小数,保留两位小数,超过两位舍弃。

      • Character:字符数(个)。

      • DailyActiveUser:日活跃用户数(DAU)。

      • PeriodMin:使用分钟时长(分钟)。

      • VirtualCpu:虚拟CPU核数。

        • Unit: Unit(个)

        • Memory: Memory(GB)

    • Value:计量数值(取值>=0),参数类型为Integer。

说明
  • 如果商品设置为实时出账,StartTimeEndTime为任意时间宽度,但是EndTime一定要大于StartTime。

  • 如果商品设置为非实时出账(即选择按小时、按天、按月等),StartTimeEndTime的间隔必须大于5分钟。

[{"StartTime":"1664451045","EndTime":"1664451198","Entities":[{"Key":"Frequency","Value":"6"}]}]

Token

String

用于计算巢对比,判断推送方是否是服务商。

使用MD5加密算法对Metering&Key加密,加密为32位小写的值。

  • Metering:[{"StartTime":"1664451045","EndTime":"1664451198","Entities":[{"Key":"Frequency","Value":"6"}]}],如何获取请参见Metering

  • Key:服务Key。示例e98893f5ecc3ae1ctest,您可在服务详情页获取服务Key。

    说明

    Key全服务唯一,不会随版本变更而变化。

  • 待加密字符串:Metering=[{"StartTime":"1664451045","EndTime":"1664451198","Entities":[{"Key":"Frequency","Value":"6"}]}]&Key=e98893f5ecc3ae1ctest

  • 加密后的Token值:7aa81300b2aea77984b772495c8e4e83

返回参数

名称

类型

描述

示例值

RequestId

String

计算巢请求ID。

e6862d3a-9305-4289-8dd3-9c52a680228b

Success

Boolean

成功状态标识。

true

PushMeteringDataRequestId

String

云市场请求ID。

7lc658a2-tr41-****-****-c25es45vc248

Token

String

用于服务商对比数字签名。请参见计算巢校验数字签名说明

50130a063c6acf833280d23169898bd4

示例

本示例是云市场按量付费的计算巢商品创建的ECS中发起调用。

curl示例

  1. 获取ECS地域信息

    在调用PushMeteringData前,您需要获取应用部署的ECS地域(regionld)信息。获取到的地域信息会在后续步骤中使用,因此需要服务商记录。

    1. 访问如下网址,获得地域信息。

      curl http://100.100.100.200/latest/meta-data/region-id
    2. 地域返回示例。

      cn-hangzhou
  2. 准备入参

    "Metering":"[{\"StartTime\":\"1664451045\",\"EndTime\":\"1664451198\",\"Entities\":[{\"Key\":\"Frequency\",\"Value\":\"6\"}]}]","Token":"7aa81300b2aea77984b772495c8e4e83"

    • Metering:[{\"StartTime\":\"1664451045\",\"EndTime\":\"1664451198\",\"Entities\":[{\"Key\":\"Frequency\",\"Value\":\"6\"}]}]

      说明

      由于本示例通过curl调用PushMeteringData,需要加入转译符号\。若使用代码调用,则不需要转译。

    • Token:将字符串Metering&服务Key通过MD5加密获取32位小写的值7aa81300b2aea77984b772495c8e4e83

  3. 请求示例

    curl -H "Content-Type: application/json" -XPOST https://cn-hangzhou.axt.aliyun.com/computeNest/marketplace/push_metering_data -d '{"Metering":"[{\"StartTime\":\"1664451045\",\"EndTime\":\"1664451198\",\"Entities\":[{\"Key\":\"Frequency\",\"Value\":\"6\"}]}]","Token":"7aa81300b2aea77984b772495c8e4e83"}'
    说明

    https://cn-hangzhou.axt.aliyun.comcn-hangzhou步骤1中获取的地域,具体调用时请按实际情况更换地域信息。

  4. 返回示例

    {
        "RequestId":"4ca591b5-bc30-****-****-c4d0ec5d24ed", 
        "Success":"true",
        "PushMeteringDataRequestId":"7lc658a2-tr41-****-****-c25es45vc248", 
        "Token":"50130a063c6acf833280d23169898bd4"
    }

代码示例

Python

import requests
import json
import hashlib
import time
from urllib.request import urlopen

def get_region_id():
    """通过阿里云元数据服务获取地域 ID(如 cn-hangzhou)"""
    try:
        with urlopen(
            "http://100.100.100.200/latest/meta-data/region-id",
            timeout=2
        ) as response:
            return response.read().decode().strip()
    except Exception as e:
        print(f"Failed to get region ID: {str(e)}", file=sys.stderr)
        sys.exit(1)

def push_metering_data(entities_map, service_key):
    # 动态获取当前时间(Unix 时间戳,单位秒)
    current_time = int(time.time())
    start_time = current_time 
    end_time = current_time + 1

    # 构建 Metering 数据
    metering_data = [
        {
            "StartTime": str(start_time),
            "EndTime": str(end_time),
            "Entities": [
                {"Key": key, "Value": str(value)} 
                for key, value in entities_map.items()
            ]
        }
    ]
    metering_str = json.dumps(metering_data)

    # 动态获取地域 ID 并构建 URL
    region_id = get_region_id()
    url = f"https://{region_id}.axt.aliyun.com/computeNest/marketplace/push_metering_data"

    # 计算 Token
    token_str = metering_str + "&" + service_key
    token = hashlib.md5(token_str.encode()).hexdigest().lower()

    # 发送 POST 请求
    try:
        response = requests.post(
            url,
            json={
                "Metering": metering_str,
                "Token": token
            },
            headers={"Content-Type": "application/json"}
        )
        print(f"Request URL: {url}")
        print(f"Status Code: {response.status_code}")
        print(f"Response: {response.text}")
    except Exception as e:
        print(f"Request Failed: {str(e)}", file=sys.stderr)

if __name__ == "__main__":
    import sys
    # 示例参数(替换为实际推送数据,key为计量项,value为数值)
    entities = {
        "Frequency": "6"
    }
    # 服务商Key
    service_key = "your_service_key_here"

    # 调用函数
    push_metering_data(entities, service_key)

运行示例:

image

Java

import org.json.JSONArray;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;     

public class MeteringPusher {
    public static void main(String[] args) {
        try {
            // === 动态获取地域 ID === #
            String regionId = getRegionId();
            System.out.println("Detected Region ID: " + regionId);

            // === 构造请求体 === #
            Map<String, String> entities = new HashMap<>(); // 构建Entities, 需替换具体推送内容
            entities.put("Frequency", "6");
            String serviceKey = "your_service_key_here"; // 需替换为实际服务商Key
            JSONObject payload = generateDynamicRequest(regionId, entities, serviceKey);
            String paylodString = payload.toString();

            // 若仅测试可注释上述内容,直接输入下方内容,其中StartTime、EndTime等参数需替换
            // String paylodString = "{\"Metering\":\"[{\\\"StartTime\\\":\\\"1664451045\\\",\\\"EndTime\\\":\\\"1664451198\\\",\\\"Entities\\\":[{\\\"Key\\\":\\\"Frequency\\\",\\\"Value\\\":\\\"6\\\"}]}]\",\"Token\":\"7aa81300b2aea77984b772495c8e4e83\"}";

            // === 发送 POST 请求 === #
            String urlStr = "https://" + regionId + ".axt.aliyun.com/computeNest/marketplace/push_metering_data";
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setDoOutput(true);

            try (OutputStream os = conn.getOutputStream()) {
                byte[] input = paylodString.getBytes("UTF-8");
                os.write(input, 0, input.length);
            }

            // === 读取响应 === #
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            StringBuilder response = new StringBuilder();
            String responseLine;
            while ((responseLine = br.readLine()) != null) {
                response.append(responseLine);
            }
            conn.disconnect();
            System.out.println("Response: " + response.toString());
            System.out.println("Request URL: " + urlStr);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // === 动态获取地域 ID(阿里云元数据服务) === 
    private static String getRegionId() throws Exception {
        String regionIdUrl = "http://100.100.100.200/latest/meta-data/region-id";
        HttpURLConnection conn = (HttpURLConnection) new URL(regionIdUrl).openConnection();
        conn.setRequestMethod("GET");
        conn.setConnectTimeout(2000); // 2秒超时
        conn.setReadTimeout(2000);

        try (BufferedReader in = new BufferedReader(
            new InputStreamReader(conn.getInputStream()))) {
            return in.readLine().trim();
        }
    }

    //  === 动态生成请求数据  === 
    private static JSONObject generateDynamicRequest(String regionId, Map<String, String> entities, String serviceKey) throws Exception {
        // 获取当前时间戳
        long currentTime = System.currentTimeMillis() / 1000;
        long startTime = currentTime;
        long endTime = currentTime + 1;

        // 构建Metering数据
        JSONArray meteringArray = new JSONArray();
        JSONObject meteringItem = new JSONObject();
        meteringItem.put("StartTime", String.valueOf(startTime));
        meteringItem.put("EndTime", String.valueOf(endTime));

        JSONArray entitiesArray = new JSONArray();
        for (Map.Entry<String, String> entry : entities.entrySet()) {
            entitiesArray.put(new JSONObject()
                .put("Key", entry.getKey())
                .put("Value", entry.getValue()));
        }
        meteringItem.put("Entities", entitiesArray);
        meteringArray.put(meteringItem);

        // 计算Token
        String meteringStr = meteringArray.toString();
        String tokenStr = meteringStr + "&" + serviceKey;
        String token = md5(tokenStr);

        // 构造完整请求体
        JSONObject payload = new JSONObject();
        payload.put("Metering", meteringStr);
        payload.put("Token", token);
        return payload;
    }

    // === MD5 加密方法 === 
    private static String md5(String input) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] messageDigest = md.digest(input.getBytes());
        StringBuilder hexString = new StringBuilder();
        for (byte b : messageDigest) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) hexString.append('0');
            hexString.append(hex);
        }
        return hexString.toString();
    }
}

运行示例:

image

说明

确保项目中包含 org.json 库(如 Maven 依赖):

<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20230618</version>
</dependency>

错误码

错误码

错误信息

描述

OperationDenied

The serviceInstance does not supported push metering data.

非按量付费服务实例不支持推送。

Only metering entities classified as Custom and associated with a service can be pushed. The entity ${EntityId} is invalid.

计量项****不支持推送,需要设置为服务商上报且完成计量项绑定。

MissingParameter.${parametersName}

The input parameter "${parametersName}" that is mandatory for processing this request is not supplied.

参数缺失。

InvalidParameter.${parametersName}

The provided parameter "${parametersName}" is invalid.

参数非法。

EntityNotExist.ServiceInstance

The specified service instance cannot be found.

服务实例不存在(非计算巢创建的ECS)。