eos cpu_limit

Eos中,通过抵押token的方式,提供cpu运算时间以供用户完成交易。
net资源计算方式与cpu类似。
本文旨在理清变量间关系,故略过大部分中间变量,仅记录关联度较大的部分。

在eos测试中,用账号进行高频的transfer(转账)操作,出现了以下报错。
所以决定做一份关于cpu限制的笔记。

3080004 tx_cpu_usage_exceeded: Transaction exceeded the current CPU usage limit imposed on the transaction
billed CPU time (916 us) is greater than the maximum billable CPU time for the transaction (372 us)
{"billed":916,"billable":372}
thread-0 transaction_context.cpp:361 validate_cpu_usage_to_bill

交易CPU验证三步曲

主要由transaction_context承担验证工作。

  • transaction_context::init
    objective_duration_limit = 等于以下四者最小值。
    _deadline = start + objective_duration_limit。

    • config::max_transaction_cpu_usage:config.hpp
    • trx.max_cpu_usage_ms:nodeos --max-cpu-usage-ms
    • resource_limits_manager::get_block_cpu_limit():动态变化_db.get<resource_limits_config_object>().cpu_limit_parameters.max - _db.get<resource_limits_state_object>().pending_cpu_usage
    • resource_limits_manager::get_account_cpu_limit + leeway:动态变化,用户窗口期可用总值-已使用值。
  • transaction_context::exec
    非延迟类交易立即执行,延迟类交易计算挂起费用(网络、内存),其中内存费用由交易发起者支付。

  • transaction_context::finalize
    验证交易执行结果,计算费用。

    cpu账单需满足以下断言:
    billed_us >= cfg.min_transaction_cpu_usage:config.hpp
    billed_us <= objective_duration_limit.count():上面的objective_duration_limit

由此看来,节点间硬件配置差距将导致结果不唯一。

用户CPU资源使用计算

上面我们大概了解了什么因素会影响cpu_limit的判定,现在要开始弄明白用户cpu的计算方式。

使用cleos get account我们可以看到cpu相关参数如下:

cpu bandwidth:
staked: 4448951.0162 SYS (total stake delegated from account to self)
delegated: 0.0000 SYS (total staked delegated to account from others)
used: 47.11 ms
available: 85.42 hr
limit: 85.42 hr

// 打印代码如下:
std::cout << indent << std::left << std::setw(11) << "used:"      << std::right << std::setw(18) << to_pretty_time( res.cpu_limit.used ) << "\n";
std::cout << indent << std::left << std::setw(11) << "available:" << std::right << std::setw(18) << to_pretty_time( res.cpu_limit.available ) << "\n";
std::cout << indent << std::left << std::setw(11) << "limit:"     << std::right << std::setw(18) << to_pretty_time( res.cpu_limit.max ) << "\n";

其中res.cpu_limit的值源自get_account_cpu_limit_ex,最终与_dbresource_limits*字段相关联。
那么我们需要弄懂相关字段的含义。

  • account_limit

    • _db.get<resource_limits_object, by_owner>(boost::make_tuple(bool pending, account_name account).cpu_weight
      用户抵押货币后理论cpu时间最大值。
      • pending:false时,记录上个块结束时的旧值。
      • pending:true时,记录当前块发生交易后的新值。
        当用户产生交易后,在controller_impl::finalize_block()中更新:
        _db<resource_limits_object, by_owner>(false, account) = _db<resource_limits_object, by_owner>(true, account)
  • account_usage

    • _db.get<resource_usage_object, by_owner>
      窗口期内用户使用的资源,在add_transaction_usage内增加。
  • block_limit

    • _db.get<resource_limits_state_object>:整个块中用户计算资源消耗累计,累计方式同account_usage,根据下文config_object的值决定virtual_net_limit,动态调节限制。
      可以参考virtual_net_limit代码注释:

      /**
      * The virtual number of bytes that would be consumed over blocksize_average_window_ms
      * if all blocks were at their maximum virtual size. This is virtual because the
      * real maximum block is less, this virtual number is only used for rate limiting users.
      *
      * It's lowest possible value is max_block_size * blocksize_average_window_ms / block_interval
      * It's highest possible value is 1000 times its lowest possible value
      *
      * This means that the most an account can consume during idle periods is 1000x the bandwidth
      * it is gauranteed under congestion.
      *
      * Increases when average_block_size < target_block_size, decreases when
      * average_block_size > target_block_size, with a cap at 1000x max_block_size
      * and a floor at max_block_size;
      **/

  • _db.get<resource_limits_config_object>:记录着整个硬件资源限制的配置,目前来看似乎是定值。
class resource_limits_config_object : public chainbase::object<resource_limits_config_object_type, resource_limits_config_object> {
    OBJECT_CTOR(resource_limits_config_object);
    id_type id;

    struct elastic_limit_parameters {
    uint64_t target;           // the desired usage
    uint64_t max;              // the maximum usage
    uint32_t periods;          // the number of aggregation periods that contribute to the average usage

    uint32_t max_multiplier;   // the multiplier by which virtual space can oversell usage when uncongested
    ratio    contract_rate;    // the rate at which a congested resource contracts its limit
    ratio    expand_rate;       // the rate at which an uncongested resource expands its limits

    void validate()const; // throws if the parameters do not satisfy basic sanity checks
    };

    elastic_limit_parameters cpu_limit_parameters = {EOS_PERCENT(config::default_max_block_cpu_usage, config::default_target_block_cpu_usage_pct), config::default_max_block_cpu_usage, config::block_cpu_usage_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}};
    elastic_limit_parameters net_limit_parameters = {EOS_PERCENT(config::default_max_block_net_usage, config::default_target_block_net_usage_pct), config::default_max_block_net_usage, config::block_size_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}};

    // window_size = account_cpu_usage_average_window
    uint32_t account_cpu_usage_average_window = config::account_cpu_usage_average_window_ms / config::block_interval_ms;
    uint32_t account_net_usage_average_window = config::account_net_usage_average_window_ms / config::block_interval_ms;
}
// 在controller_impl::finalize_block中执行更新
uint64_t CPU_TARGET = EOS_PERCENT(chain_config.max_block_cpu_usage, chain_config.target_block_cpu_usage_pct);
resource_limits.set_block_parameters(
    { CPU_TARGET, chain_config.max_block_cpu_usage, config::block_cpu_usage_average_window_ms / config::block_interval_ms, max_virtual_mult, {99, 100}, {1000, 999}},
    {EOS_PERCENT(chain_config.max_block_net_usage, chain_config.target_block_net_usage_pct), chain_config.max_block_net_usage, config::block_size_average_window_ms / config::block_interval_ms, max_virtual_mult, {99, 100}, {1000, 999}}
);

转自:https://www.jianshu.com/p/e3ea61e7ccd9

猜你喜欢

转载自blog.csdn.net/yhc166188/article/details/84862880
eos