Akawa

ETY001的博客

为了方便查看相关的系统参数和变量,我写了一个工具,文章中提到的参数都可以在工具中看到。
工具地址:https://dev-tools.steem.fans/

一、通胀与每个块理论产出STEEM量

steem 的通胀率是按照规律线性递减的,直到达到设置的值,通胀率就不会再减小了。

通胀率如何计算?

通胀率从 STEEM_INFLATION_RATE_START_PERCENT(978)开始,到 STEEM_INFLATION_RATE_STOP_PERCENT(95)结束。

即从 9.78% 到 0.95%。其中递减率是每 STEEM_INFLATION_NARROWING_PERIOD(250000)块减少 0.01%。

公式:

1
current_inflation_rate = max( STEEM_INFLATION_RATE_START_PERCENT - head_block_num / STEEM_INFLATION_NARROWING_PERIOD, STEEM_INFLATION_RATE_STOP_PERCENT )

通胀是针对现有供应量来算的,所以每年新增的STEEM数量按照当前所在的25万块这个区间的通胀率算的话是:

1
virtual_supply * current_inflation_rate

由于每3秒出一个块,所以理论上如果不丢块,每年出块数量为 STEEM_BLOCKS_PER_YEAR(即 6060243653),

进而当前25万块区间内,每个块的理论产出为:virtual_supply * current_inflation_rate / STEEM_BLOCKS_PER_YEAR

按照当前写文章时间的高度(45429466)算出来的块理论产出STEEM数量为 EachBlockRewardInTheory = 2.944 STEEM

相关代码:https://github.com/steemit/steem/blob/0.23.x/libraries/chain/database.cpp#L2396-L2403

二、每个块理论产生STEEM量如何分配

总的来说,每个块是按照 65% content reward, 15% vesting_reward, 10% SPS fund, 10% witness reward。

按照上边的例子,分别得到

1
2
3
content_reward = EachBlockRewardInTheory * 0.65 = 1.913 STEEM
vesting_reward = EachBlockRewardInTheory * 0.15 = 0.441 STEEM
sps_fund = EachBlockRewardInTheory * 0.1 = 0.294 STEEM

注意:
这里在 HF17 之后有这样的操作,new_content_reward = pay_reward_funds( content_reward ),
目前 pay_reward_funds 没看懂,我的工具暂时定义 new_content_reward = content_reward 。

另外,见证人收益不是直接乘以 10%,而是减出来的,即

1
witness_reward = EachBlockRewardInTheory - new_content_reward - vesting_reward - sps_fund

如此便得到最初的四项分配值。

之后还需要进行一些计算和分类,来最终把块产生的STEEM加入到各个池子中。

其中,需要先处理见证人的收益。

见证人分为TOP20(Elected)和非TOP20(TimeShare),两者的权重(weight)不同。

见证人的最终收益计算公式:

1
new_witness_reward = witness_reward * STEEM_MAX_WITNESSES * weight / witness_pay_normalization_factor

其中 STEEM_MAX_WITNESSES 为 21,witness_pay_normalization_factor 为 25.

TOP20的权重(elected_weight)为 1,非TOP20的权重(timeshare_weight)为 5.

除了见证人外,对于 sps_fund_reward 也需要单独计算,因为 SPS 最终是以 SBD 为单位,而块产生的是STEEM,所以需要进行转换。

转换率来自喂价,即 current_median_history。最终公式为:

1
sps_sbd = sps_fund_reward * current_median_history

这个时候,所有的计算工作基本结束,开始对数据进行写入操作,也就是进入各个池子,

1
2
3
4
5
6
total_vesting_fund_steem += vesting_reward
total_reward_fund_steem += new_content_reward
current_supply += new_content_reward + vesting_reward + new_witness_reward
current_sbd_supply += new_sbd
virtual_supply += new_content_reward + vesting_reward + new_witness_reward + sps_fund
sps_interval_ledger += sps_fund

最后一步,把 new_witness_rewardvesting_shares 的形式发放给见证人。 vesting_shares 就是 SP 的实质。

相关代码:https://github.com/steemit/steem/blob/0.23.x/libraries/chain/database.cpp#L2404-L2453

最后是我画的产出STEEM流向图:

steem-block-reward.jpg


Some very cheap and good VPS

SteemPower 平时都被叫做 SP,这个单位虽然我们经常见,但是这个并不是真正的资产。

SP 的背后其实是 VestingShares。鉴于 Steem 的通胀,SP其实是用来表示当前你持有的 VestingShares 价值多少 Steem 的单位。

VestingShares 我们把他看做一个商品会更容易理解。

Steem 币购买 VestingShares 的过程就是 PowerUP,相对的,卖出 VestingShares 得到 Steem 币的操作就是 PowerDown

而购买价格就是 total_vesting_sharestotal_vesting_fund_steem 的比值,

这个在这里可以看到:https://github.com/steemit/steem/blob/0.23.x/libraries/chain/include/steem/chain/global_property_object.hpp#L67-L73

之所以价格这样计算,是因为系统要求,当用户 PowerUp 的时候,要求 total_vesting_shares / total_vesting_fund_steem 比值不变。

total_vesting_shares / total_vesting_fund_steem = (total_vesting_shares + delta_vesting_shares) / (total_vesting_fund_steem + delta_vesting_fund_steem)

其中 delta_vesting_fund_steem 就是我们要 PowerUpSteem,我们需要知道能获取多少 vesting_shares,即 delta_vesting_shares

整理一下就是 delta_vesting_shares = (total_vesting_shares / total_vesting_fund_steem) * delta_vesting_fund_steem

由此得到价格关系。

相关代码:https://github.com/steemit/steem/blob/0.23.x/libraries/chain/database.cpp#L1199-L1314

total_vesting_fund_steem 这个池子除了上面提到的 PowerUp 操作会增加这个池子,还有就是每次出块会增加。

每次出块,每个块总产出 Steem 的 15% 会进入到 total_vesting_fund_steem

total_vesting_shares 的增加来源于见证人收益,因为每个块的见证人收益(即不到10%的块总产出)是以 VestingShares 发放,而不是以 Steem 发放。

发放见证人收益的时候,会同时增加 total_vesting_fund_steemtotal_vestting_shares

综上两点,就意味着 total_vesting_fund_steem 增长速度会快于 total_vesting_shares,也就是说 vesting_shares 会越来越值钱。

而 SP 的意义目前也就是实时展示你持有的 VestingShares 现在值多少 Steem。你如果不在这个时刻 PowerDown,那么这个 SP 就是没有意义的,只是一个数字。

如果说 SP 只是为了实时表示 VestingSharesSteem 价值,那么 SP 这个概念可能是个很失败的引入。


Some very cheap and good VPS

IP相关统计

统计IP访问量

1
awk '{print $1}' access.log | sort -n | uniq | wc -l

查看某一时间段的IP访问量(4-5点)

1
grep "07/Apr/2017:0[4-5]" access.log | awk '{print $1}' | sort | uniq -c| sort -nr | wc -l

查看访问最频繁的前100个IP

1
awk '{print $1}' access.log | sort -n |uniq -c | sort -rn | head -n 100

查看访问100次以上的IP

1
awk '{print $1}' access.log | sort -n |uniq -c |awk '{if($1 >100) print $0}'|sort -rn

查询某个IP的详细访问情况,按访问频率排序

1
grep '104.217.108.66' access.log |awk '{print $7}'|sort |uniq -c |sort -rn |head -n 100

页面访问统计

查看访问最频的页面(TOP100)

1
awk '{print $7}' access.log | sort |uniq -c | sort -rn | head -n 100

查看访问最频的页面([排除php页面】(TOP100)

1
grep -v ".php"  access.log | awk '{print $7}' | sort |uniq -c | sort -rn | head -n 100

查看页面访问次数超过100次的页面

1
cat access.log | cut -d ' ' -f 7 | sort |uniq -c | awk '{if ($1 > 100) print $0}' | less

查看最近1000条记录,访问量最高的页面

1
tail -1000 access.log |awk '{print $7}'|sort|uniq -c|sort -nr|less

每秒请求量统计

统计每秒的请求数,top100的时间点(精确到秒)

1
awk '{print $4}' access.log |cut -c 14-21|sort|uniq -c|sort -nr|head -n 100

每分钟请求量统计

统计每分钟的请求数,top100的时间点(精确到分钟)

1
awk '{print $4}' access.log |cut -c 14-18|sort|uniq -c|sort -nr|head -n 100

每小时请求量统计

统计每小时的请求数,top100的时间点(精确到小时)

1
awk '{print $4}' access.log |cut -c 14-15|sort|uniq -c|sort -nr|head -n 100

性能分析

在nginx log中最后一个字段加入$request_time

列出传输时间超过 3 秒的页面,显示前20条

1
cat access.log|awk '($NF > 3){print $7}'|sort -n|uniq -c|sort -nr|head -20

列出php页面请求时间超过3秒的页面,并统计其出现的次数,显示前100条

1
cat access.log|awk '($NF > 1 &&  $7~/\.php/){print $7}'|sort -n|uniq -c|sort -nr|head -100

蜘蛛抓取统计

统计蜘蛛抓取次数

1
grep 'Baiduspider' access.log |wc -l

统计蜘蛛抓取404的次数

1
grep 'Baiduspider' access.log |grep '404' | wc -l

TCP连接统计

查看当前TCP连接数

1
netstat -tan | grep "ESTABLISHED" | grep ":80" | wc -l

用tcpdump嗅探80端口的访问看看谁最高

1
tcpdump -i eth0 -tnn dst port 80 -c 1000 | awk -F"." '{print $1"."$2"."$3"."$4}' | sort | uniq -c | sort -nr

转自:https://www.cnblogs.com/coolworld/p/6726538.html

鉴于 Steem 的见证人节点和全节点 replay 的时间很长,所以有必要即使把 replay 好的数据进行备份。

这样一旦出现数据损坏的情况,能最快速度从灾难中完成恢复。

另外,部署新的节点的时候,也可以节省大量的时间。

经过我两天的搜索,最终找到了一台加拿大的廉价大硬盘主机。

1
2
3
4
5
6
7
8
9
Horse Storage Offer

3 core
3 GB ram
3 TB hard disk
100Mbps
no limit bandwidth usage

$110 / Year

有感兴趣的可以点击这里看看 ,找一下 special order 里面有一款叫做 Horse Storage Offer

经过一番安装部署,现在已经上线。

地址: https://files.steem.fans

目前还在上传备份数据过程中。


好用不贵的VPS

昨天发文说到 我上线了一个Steem数据服务,但是 Nginx 自带的 autoindex 功能的 UI 实在是丑爆了,那么怎么美化一下呢?

经过研究发现了三种方案。

方案一

Nginx 的配置中,有下面这两个配置项目:

1
2
add_before_body /xxx/file1.html;
add_after_body /xxx/file2.html;

这两个选项,可以在 Nginx 输出 HTML 之前和之后分别先输出你设定的文件。

这样我们可以在自定义我们的头部或者尾部,加入我们自己想要的样式表或者用 js 实现更牛逼的功能。

完整的配置大概是这样

1
2
3
4
5
6
7
8
9
location / {
root /data/wwwroot/steem;
try_files $uri $uri/ =404;
autoindex on;
autoindex_localtime on;
add_before_body /.beauty/top.html;
add_after_body /.beauty/bot.html;
autoindex_exact_size off;
}

这里需要注意的是这两个参数的寻址,是基于 root 配置项的,也就是在上面的示例中, .beauty 目录是在 /data/wwwroot/steem 目录下面的。另外,如果你的自定义文件里有包含 cssjs 文件,还需要有 try_files 参数配合一下。

这个功能唯一的不好处就是在查看网页源代码的时候,发现这两个参数的插入位置是在原来 <html> 之前和 </html> 之后。

这就让有代码洁癖的人感到很恶心。。。

方案二

该方案是第三方开发的插件:https://www.nginx.com/resources/wiki/modules/fancy_index/

鉴于我使用的是 Docker 版的 Nginx,要想安装个第三方插件,我还要自己编译打包,很麻烦,所以这个方案就没有尝试。

不过看文档说明,应该是跟方案一思路一样,只不过多加了几个注入位置吧。

方案三

目前,我使用的是方案三。这个方案则是依赖的 Nginx 的这个参数 autoindex_format

这个参数可以规定输出信息格式,默认是 html,我们可以设置这里为 json。这样就变成了一个 api 接口。

然后自己去开发一套自己喜欢的前端,调用这个 api 接口就可以了。

这里我从网上找了一套现成的 UI 来使用,地址:https://github.com/spring-raining/pretty-autoindex

Nginx 配置这块,我没有按照这个库的方法配置两个 Server 模块,我是分成了两个 location 来实现。

参考配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
location / {
root /data/wwwroot/pretty-autoindex/dist;
index index.html;
autoindex off;
}

location /data {
alias /data/wwwroot/steem;
autoindex on;
autoindex_localtime on;
autoindex_exact_size off;
autoindex_format json;

# Enable your browser to access here.
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
add_header Access-Control-Allow-Headers "Origin, Authorization, Accept";
add_header Access-Control-Allow-Credentials true;
}

通过 alias 实现 /dataapi 接口,来获取目录结构信息。

经过一下午的折腾,最终终于让 autoindex 页面看上去不是那么丑了,并且还加入了 Google Analytics

以后如果还有什么想搞的好玩的东西,也可以加入到里面了。


好用不贵的VPS

最近在看官方库的Dockerfile相关的脚本,学习到了一些有价值的点。

比如在区块数据备份这块,我发现官方使用的 lz4 压缩工具。

去查了下,发现 lz4 是目前综合来看效率最高的压缩算法,更加侧重压缩解压速度,压缩比并不是第一。在当前的安卓和苹果操作系统中,内存压缩技术就使用的是 lz4 算法,及时压缩手机内存以带来更多的内存空间。本质上是时间换空间。

压缩效率高,对于像 steem 这样的庞大的数据怪物的备份来说,太重要了。

使用起来也很方便,系统应该都是默认安装了 lz4 的。

在目的目录执行下面的命令:

1
tar  -cf  steem_blockchain.tar.lz4  --use-compress-program=lz4   -C  /data2/steem/data/witness_node_data_dir   blockchain/

就可以把 /data2/steem/data/witness_node_data_dir 下面的 blockchain 文件夹打包并使用 lz4 压缩。

经过测试,源目录 blockchain 的大小是 374G,压缩后的文件是 261G,压缩比还可以。

最重要的是时间。往常在我的服务器上使用 gziptar 打包备份,一般就是大半天的时间。而这次使用 lz4 压缩才用了大约两个小时,太惊艳了!

接下来,要把目前所有的备份都换成使用 lz4 进行压缩打包。


好用不贵的VPS

在steem链上注册有三种途径,account_create,create_claimed_accountaccount_create_with_delegation,不过,最后这个 account_create_with_delegation 已经不再建议使用了。所以目前主要是通过 account_createcreate_claimed_account 两个方法来注册新用户。

调用方法

account_create

这个接口使用很简单,只需要交钱就能注册,即花费 steem 代币。

使用方法: https://developers.steem.io/apidefinitions/#broadcast_ops_account_create

create_claimed_account

这个接口注册用户需要配合 claim_account 来进行。需要使用 claim_account 先花费 RC 申请一个牌子,然后再消耗牌子去使用 create_claimed_account 注册用户。

claim_account 使用方法: https://developers.steem.io/apidefinitions/#broadcast_ops_claim_account

create_claimed_account 使用方法: https://developers.steem.io/apidefinitions/#broadcast_ops_create_claimed_account

这里给出一下 claim_accountdemo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const steem = require('steem');
steem.api.setOptions({ url: 'https://steem.61bts.com' });

const ac_key = "";
const user = "";

const keys = {active: ac_key};

const op = [
"claim_account",
{
"fee": "0.000 STEEM",
"creator": user,
"extensions": []
}
];

const tx = {
extensions: [],
operations: [
op
]
};

steem.broadcast.send(tx, keys, (r) => {
console.log(r);
});

关于花费

无论那个接口注册用户,都要涉及到注册费用,只不过 account_create 是直接花费注册费用,而 create_claimed_account 途径注册用户,需要计算消耗多少 RC。

account_create

目前使用 account_create 注册用户会消耗当前用户 3 steem 代币。那么这个数是从哪里获得的呢?

我们看下面的代码:

1
2
3
FC_ASSERT( o.fee == wso.median_props.account_creation_fee, "Must pay the exact account creation fee. paid: ${p} fee: ${f}",
("p", o.fee)
("f", wso.median_props.account_creation_fee) );

上面的代码来自 /libararies/chain/steem_evaluator.cpp 中的 void account_create_evaluator::do_apply( const account_create_operation& o )
代码位置: https://github.com/steemit/steem/blob/master/libraries/chain/steem_evaluator.cpp#L331

可以看到在注册费这里需要断言,注册费用为 wso.median_props.account_creation_fee

这个 wso 联系上下文看到是 _db.get_witness_schedule_object(),可以知道是拿的见证人的信息。其中里面涉及到一个 median_props 的成员,需要看看如何实现(看字面意思是中位数)。

1
2
3
4
5
6
/// sort them by account_creation_fee
std::sort( active.begin(), active.end(), [&]( const witness_object* a, const witness_object* b )
{
return a->props.account_creation_fee.amount < b->props.account_creation_fee.amount;
} );
asset median_account_creation_fee = active[active.size()/2]->props.account_creation_fee;

上面的代码来自 /libararies/chain/witness_schedule.cpp 中的 void update_median_witness_props( database& db )
位置在: https://github.com/steemit/steem/blob/master/libraries/chain/witness_schedule.cpp#L37

其中 active 联系上下文,可以知道拿到的是当前活跃的所有见证人(目前的配置是21位),然后对这些活跃的见证人配置中的 account_creation_fee 进行排序,然后取中位数。

结论:如果想要变动注册费用,需要半数以上的活跃见证人同时调整自己的 account_creation_fee 配置。

create_claimed_account

关于 create_claimed_accountclaim_account 这两个函数,目前还没有完全看完,因为其中还涉及到了 RC 部分的代码。

目前还不清楚要扣除的RC的计算公式或者说方法。当前只是了解到在使用 claim_account 的时候的几个限制条件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
if( o.fee.amount == 0 )
{
const auto& gpo = _db.get_dynamic_global_properties();

// This block is a little weird. We want to enforce that only elected witnesses can include the transaction, but
// we do not want to prevent the transaction from propogating on the p2p network. Because we do not know what type of
// witness will have produced the including block when the tx is broadcast, we need to disregard this assertion when the tx
// is propogating, but require it when applying the block.
if( !_db.is_pending_tx() )
{
const auto& current_witness = _db.get_witness( gpo.current_witness );
FC_ASSERT( current_witness.schedule == witness_object::elected, "Subsidized accounts can only be claimed by elected witnesses. current_witness:${w} witness_type:${t}",
("w",current_witness.owner)("t",current_witness.schedule) );

FC_ASSERT( current_witness.available_witness_account_subsidies >= STEEM_ACCOUNT_SUBSIDY_PRECISION, "Witness ${w} does not have enough subsidized accounts to claim",
("w", current_witness.owner) );

_db.modify( current_witness, [&]( witness_object& w )
{
w.available_witness_account_subsidies -= STEEM_ACCOUNT_SUBSIDY_PRECISION;
});
}

FC_ASSERT( gpo.available_account_subsidies >= STEEM_ACCOUNT_SUBSIDY_PRECISION, "There are not enough subsidized accounts to claim" );

_db.modify( gpo, [&]( dynamic_global_property_object& gpo )
{
gpo.available_account_subsidies -= STEEM_ACCOUNT_SUBSIDY_PRECISION;
});
}

上面的代码来自 /libararies/chain/steem_evaluator.cpp 中的 void claim_account_evaluator::do_apply( const claim_account_operation& o )
位置在: https://github.com/steemit/steem/blob/master/libraries/chain/steem_evaluator.cpp#L3211

在代码中,我们能看到有两个数量上的限制:

  • current_witness.available_witness_account_subsidies
  • gpo.available_account_subsidies

其中还涉及到一个全局参数 STEEM_ACCOUNT_SUBSIDY_PRECISION

上面这三个值,我们通过下面的代码可以快速的获取到:

1
2
3
4
5
6
7
8
9
10
11
12
13
steem.api.getActiveWitnesses(function(err, result) {
result.forEach((w)=>{
steem.api.getWitnessByAccount(w, (e, r) => {
console.log(w, r.available_witness_account_subsidies);
})
})
});
steem.api.getDynamicGlobalProperties(function(err, result) {
console.log('available_account_subsidies: ', result['available_account_subsidies']);
});
steem.api.getConfig(function(err, result) {
console.log('STEEM_ACCOUNT_SUBSIDY_PRECISION:', result['STEEM_ACCOUNT_SUBSIDY_PRECISION']);
});

我们用 @justyy 提供的网页工具 可以快速的看到结果。

目前的结论就是,使用 RC 注册用户,不仅受到你自身 RC 数量影响,还会受到当前出块见证人的余量(available_witness_account_subsidies),以及全局的余量(available_account_subsidies) 两个值的限制。具体这两个值怎么恢复,以及申领一个牌子消耗多少RC的计算,等我读完 RC Plugin 的代码应该就可以搞明白了。

注册费最终流向

目前这里没有细看,但是可以看到费用是流向了 @null 账号。在最终的写入区块的操作的时候,也有对 @null 账号的单独处理,
截取一段代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
case STEEM_ASSET_NUM_STEEM:
{
asset new_vesting( (adjust_vesting && delta.amount > 0) ? delta.amount * 9 : 0, STEEM_SYMBOL );
props.current_supply += delta + new_vesting;
props.virtual_supply += delta + new_vesting;
props.total_vesting_fund_steem += new_vesting;
if( check_supply )
{
FC_ASSERT( props.current_supply.amount.value >= 0 );
}
break;
}

上面的代码来自 /libararies/chain/database.cpp 中的 void database::adjust_supply( const asset& delta, bool adjust_vesting )
位置在: https://github.com/steemit/steem/blob/master/libraries/chain/database.cpp#L4689

其中 delta 就是要扣除的手续费,propsdynamic_global_property_object。可以看到是对整个系统的供应做了修改,但是具体如何修改,由于这里涉及的条件很多,还没有理顺清楚。

还未解决

最后列出一下还没有搞清楚的事情:

  • 申请牌子的 RC 计算公式
  • 除了上面提到的 available_witness_account_subsidiesavailable_account_subsidies 这两个限制条件外,对于使用 RC 申请牌子是否还有其他的限制条件。
  • available_witness_account_subsidiesavailable_account_subsidies 这两个值如何恢复。
  • 注册费用最终是如何影响全局供给的。

好用不贵的VPS

Steem Watcher

项目地址: https://github.com/ety001/steem-watcher

该项目基于之前项目的程序修改而来,目的是为了可以定制化监控链上数据.
目前只监控 claim_account, create_claimed_account, account_create 三种数据.

如果你想监测更多类型数据,请自行修改 bin/lib/opType.py

部署

由于使用了 docker 技术,整个部署过程非常简单。

克隆代码

1
git clone https://github.com/ety001/steem-watcher.git

修改配置参数

1
2
cd steem-watcher
cp .env.example .env

参数说明:

1
2
3
4
5
6
STEEMD=https://api.steemit.com  # 节点地址
MYSQL_HOST=172.22.2.2 # 数据库地址,如果 docker-compose.yml 未改动,这里请保持不变
MYSQL_USER=root # 数据库用户名,如果 docker-compose.yml 未改动,这里请保持不变
MYSQL_PASS=123456 # 数据库密码,如果 docker-compose.yml 未改动,这里请保持不变
BLOCK_NUM=43191800 # 从指定高度开始收集数据
SLACK_URL= # Slack 的 Webhook 地址

启动

1
./start.sh

查看 Log

1
./logs.sh

停止

1
./stop.sh

其他说明

  • crontab 配置文件在 config/crontab,需要用 root 权限修改
  • crontab 日志在 ./logs 目录下
  • 如需删除数据库重新开始,请先停止,然后 sudo rm -rf db/*

如有疑问

提 Issue 或者 发邮件给我: work@akawa.ink


好用不贵的VPS

今天在开发 Steem Watcher 过程中,由于需要跑计划任务,所以研究了一下如何在容器环境下使用 crond

在此之前,我曾经使用宿主机的 crond 来启动一个临时容器跑任务,但这个思路很糟糕,并不方便快速移植。于是考虑还是要基于容器内部进行计划任务才是终极方案。

由于我的 Steem Watcher 使用的镜像是我自己基于 alpine 编译的,而 alpine 中已经带有 crond 程序,所以要在容器里实施计划任务还是比较轻松。

我们可以先看下 crond 的参数说明

1
2
3
4
5
6
7
8
9
10
11
12
13
/app # crond -h
crond: unrecognized option: h
BusyBox v1.27.2 (2018-06-06 09:08:44 UTC) multi-call binary.

Usage: crond -fbS -l N -d N -L LOGFILE -c DIR

-f Foreground
-b Background (default)
-S Log to syslog (default)
-l N Set log level. Most verbose 0, default 8
-d N Set log level, log to stderr
-L FILE Log to FILE
-c DIR Cron dir. Default:/var/spool/cron/crontabs

介于容器执行命令不能立即返回,所以我们需要使用 -f 参数让 crond 在前台运行,这样可以保持容器一直运行。

然后查了下手册,发现 crond 的配置文件在 /etc/crontabs/ 目录下面。这里需要注意,由于每个用户的 crontab 是独立的,如果你是 root 用户启动,那么其配置文件为 /etc/crontabs/root

弄明白这些之后,我们想要搞计划任务的话,只需要创建个容器,让其 command 命令是 crond -f,然后把一个配置好的文件 mount 到容器里的 /etc/crontabs/root,再把需要执行的程序 mount 进去,最后启动即可了。

具体可以参考 https://github.com/ety001/steem-watcher/blob/master/docker-compose.yml#L28 这里了解。

除此之外还需要 额外注意的事情 就是,如果通过挂载的方式覆盖 /etc/crontabs/root,那么在宿主机上的配置文件,需要配置为 755 权限,并且用户和用户组需要设置为 root


好用不贵的VPS

之前搭建的 bitshares elastic search ,已经有太久不维护了,最近因为调整服务器的硬盘为 RAID0,这才发现有挺多问题了。其中一个问题就是,通过公网服务器的 nginx 进行反向代理的 kibana 面板一直是空白。

具体的现象就是,直接访问服务端口,一切正常,但是只要通过 nginx 进行反向代理,就是空白页。通过看浏览器,能看到已经把页面的 HTML 代码都下载回来了,但是不知道哪里解析不了。

最终发现是反向代理的配置有问题,贴出来已经测试通过的配置来记录下这次的问题吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server {
listen 443 ssl;
server_name **********;
ssl_certificate /etc/nginx/ssl/****.cer;
ssl_certificate_key /etc/nginx/ssl/****.key;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
location / {
#proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache_bypass $http_upgrade;
proxy_pass http://172.20.0.1:5601;
}
}

好用不贵的VPS

0%