Akawa

ETY001的博客

在部署 LightDB 第二阶段的代码的时候,需要基于 alpine 构建 PHP 镜像,结果发现 iconv 扩展有缺陷,具体表现见 https://github.com/docker-library/php/issues/240

通过该 issue 中提到的那个 hack 方法可以临时解决

1
2
RUN apk add --no-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing gnu-libiconv
ENV LD_PRELOAD /usr/lib/preloadable_libiconv.so

但是并不是完美解决,虽然 iconv 函数可用了,但是扩展使用的库版本依旧是 unknown,并且在使用 yetanotherape/diff-match-patch 的时候,依旧有报错无法使用。( yetanotherape/diff-match-patch 在我之前的 这篇文章 里有介绍 )

基本上导致 iconv 有问题的原因,可能是 alpine 使用的是 musl ,目前基于 musl 的 iconv 库可能本身就有些问题,具体问题不详。

最终不得不改用 ubuntu 18.04 来构建,可参考我的 构建文件。使用 ubuntu 构建的最大问题就是最终的镜像包过大,目前我的这个封装,镜像包大约300多兆,之前基于 alpine 构建的话,大小在100M以内。

为了让 LightDB 在退出的时候更加安全,因此考虑加入信号处理。目前 LightDB 在主循环中,先获取区块数据,再遍历区块数据进行加工,最后入库,这几个步骤中,最不希望发生的事情就是,在加工数据最后入库的时候,程序被中断。

因此加入信号处理,对人为执行 ctrl + c 的时候,把程序中断放到获取数据阶段或者入库结束之后。

以下是示例代码

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
<?php
//使用ticks需要PHP 4.3.0以上版本
// declare(ticks = 1);

class a {
public function __construct() {
pcntl_signal(SIGTERM, array($this, 'handle'));
pcntl_signal(SIGINT, array($this, 'handle'));
}

public function handle($signo) {
var_dump($signo);
exit();
}

public function start() {
while (1) {
echo time()."\n";
sleep(1);
echo "11111111\n";
pcntl_signal_dispatch();
echo "22222222\n";
}
}

}

$b = new a();
$b->start();

PHP处理信号的方法是,把程序收到的信号入队列,然后再从队列里取信号处理。这样在使用 pcntl_signal 方法的时候,需要加上 declare(ticks = 1); 或者 pcntl_signal_dispatch();,二者添加一个即可。declare(ticks = 1); 的作用是,让 PHP 每执行一行代码就去触发下从队列取信号的操作。pcntl_signal_dispatch(); 的作用则是,主动去处理队列里的信号。如果这两句不添加一个,那么最终的执行效果是,你触发了信号,但是程序只是对信号进行入队列的操作,没有程序来执行队列中的信号。

另外一个需要注意的就是,pcntl_signal 的第二个参数的使用。网上多是面向过程的使用方法,直接写要绑定的回调函数的名字即可,PHP文档中也只是有面向过程的使用方法。经过搜索,才找到绑定对象中的函数的方法,就是上面示例代码的方法。

Over!

LightDB 开发过程中,如何把已修改的文章更新到原有文章上,是个很重要的功能。

Steem 对于大篇幅的文章修改,使用的是 patch 的方式,把增量信息存入到区块链上,这样可以很大程度上减少空间开销,但是原始数据对人类不友好。因此在最终给人阅读前,需要由程序把所有变动的 patch 都依次打上才行。

经过调研,发现 Steem 使用的是 Google 的 DiffMatchPatch 这个库,但是遗憾的是,没有针对 PHP 的封装。不过最终我也还是找到一个 PHP 的库,https://github.com/yetanotherape/diff-match-patch

这个库的使用非常的简单,直接上示例

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
require __DIR__ . '/vendor/autoload.php';
use DiffMatchPatch\DiffMatchPatch;
$dmp = new DiffMatchPatch();

$old = "[SteemLightDB](https://github.com/ety001/steem-lightdb) (以下简称 LightDB ) 是一个基于 Steem 链的 MySQL 数据服务。

在有 SBDS 的情况下,为啥还要在弄一个 SteemLightDB 呢?

由于之前搭建过 SBDS 服务,发现里面有很多的问题,其中稳定性、数据原始性、数据容量这三个问题比较突出。

* SBDS 的稳定性直接依赖于其取数据的节点的稳定性;
* SBDS 的数据太原始,加工度不够,如果应用开发者需要一些数据之间的关系,需要开发者获取后自己加工,增加了开发者的开发工作量和难度;
* SBDS 占用空间太大,对于穷人来说,服务器费用开销太大。";


$patches = "@@ -32,11 +32,8 @@
om/e
-ty0
01/s
@@ -90,17 +90,16 @@
%E6%95%B0%E6%8D%AE%E6%9C%8D%E5%8A%A1%E3%80%82%0A%0A
-%E5%9C%A8
%E6%9C%89 SBDS %E7%9A%84
";



$new_content = "[SteemLightDB](https://github.com/e01/steem-lightdb) (以下简称 LightDB ) 是一个基于 Steem 链的 MySQL 数据服务。

有 SBDS 的情况下,为啥还要在弄一个 SteemLightDB 呢?

由于之前搭建过 SBDS 服务,发现里面有很多的问题,其中稳定性、数据原始性、数据容量这三个问题比较突出。

* SBDS 的稳定性直接依赖于其取数据的节点的稳定性;
* SBDS 的数据太原始,加工度不够,如果应用开发者需要一些数据之间的关系,需要开发者获取后自己加工,增加了开发者的开发工作量和难度;
* SBDS 占用空间太大,对于穷人来说,服务器费用开销太大。";



$patches = $dmp->patch_fromText($patches);
$res = $dmp->patch_apply($patches, $old);
var_dump($res);
var_dump($new_content);

这里需要注意一点,就是 patch 中数据的格式。之前一直卡在这里调不出来的原因就是 steemd.com 中提供的 patch 数据格式有问题。就像我上面给出的示例代码中的 patch ,其中有些行前面是有空格的,而在 steemd.com 提供数据中,这些空格是消失了的。。。

除此之外,还有一个坑,就是 Steem 会针对文章长短来采取是否使用 patch。。。也就是说如果你的文章就一句话,如果你编辑修好提交了,那么就不会用 patch,而是直接把你新修改的内容直接提交保存。。。具体多长我也不清楚,我没有看源码,但是有一点可以肯定就是这个操作让人很蛋疼。目前我的解决方案是使用 try catch 来区分是否使用了 patch。

1
2
3
4
5
6
try {
$patches = $dmp->patch_fromText($patches);
$res = $dmp->patch_apply($patches, $old);
} catch(\Exception $e) {
$res = $patches;
}

虽然目前看貌似没有什么问题,但是感觉实现的很不优雅。

OVER!

SteemLightDB 的用户表设计,
之前使用的是 Many To Many self-referencing 的方法来实现的用户关注关系的数据库实现。

昨天发现在关注数据中,还有一个 what 字段我给疏忽了,这个字段表明是“关注”还是“屏蔽”,
于是想要在 join table 中加一个字段。但是看了 Doctrine 的文档后,发现并没有相关的方法,
按照 Doctrine 的意思是,ManyToMany 的 join table 的目的是为了连接两个表,
因此只会存储两个被连接表的外键字段,如果想要增加 extra column,需要自己手动建立 join table,
实现 OneToMany <=> ManyToOne 的关系。

Over!

真的是刚爬出一个坑,又跳到一个新坑。LightDBTransfer 组件使用 Symfony4 框架,感觉 Symfony3 出来都没有多久,就又出来4了。本来想使用框架来节约开发时间的,结果又额外增加了时间。

Symfony 的最新文档里,给出的在 Console 中使用数据库的最佳实践方案是,把数据库的调用封装进 Service ,然后通过容器注入,来实现最终的数据库调用。

下面是代码示例:

src/Service/ExampleManager.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
namespace App\Service;

use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Example;

class ExampleManager
{
private $em;

public function __construct(
EntityManagerInterface $em
)
{
$this->em = $em;
}

public function findSomething($id)
{
return $this->em->getRepository(Example::class)->find($id);
}
}

src/Command/ExampleRunCommand.php

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
31
32
33
34
35
36
<?php
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

use App\Service\ExampleManager;

class TransferRunCommand extends Command
{
protected static $defaultName = 'example:run';
private $example_manager;

public function __construct(
ExampleManager $example_manager,
)
{
parent::__construct();
$this->example_manager = $example_manager;
}

protected function configure()
{
$this
->setDescription('run the example shell')
;
}

protected function execute(InputInterface $input, OutputInterface $output)
{
$result = $this->example_manager->findSomething(1);
}
}

Over!!!

昨天新购置了一台大硬盘服务器,为了完成 Steem LightDB 也是拼了。今天机房那边完成了服务器的部署,登陆后发现原本 2 X 1T 的硬盘,只挂了一块,如图:

一看是通过 LVM 完成的硬盘管理。并且在 /dev/sda 这块硬盘上划出了243M做 /boot。还有两个 /dev/mapper/vg-* 的 Logical Volume。

再看下目前硬盘的各个分区以及 LVM 是怎么配置的。(注意:一定要仔细看下现有LVM的配置,我刚开始由于粗心,一直误认为PV是做在了sda上,以为sdb是空硬盘啊,差点酿成大错!!!坑爹的配置,第一次见sda上只放一个引导区的。。。

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
[root@lightdb ~]# fdisk -l

Disk /dev/sdb: 1000.2 GB, 1000204886016 bytes, 1953525168 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x000e0ad8

Device Boot Start End Blocks Id System
/dev/sdb1 2048 1953523711 976760832 8e Linux LVM

Disk /dev/sda: 1000.2 GB, 1000204886016 bytes, 1953525168 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x00040a3c

Device Boot Start End Blocks Id System
/dev/sda1 * 2048 514047 256000 83 Linux

Disk /dev/mapper/vg-root: 990.7 GB, 990665244672 bytes, 1934893056 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mapper/vg-swap: 8455 MB, 8455716864 bytes, 16515072 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mapper/vg-tmp: 1073 MB, 1073741824 bytes, 2097152 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes



### 一开始粗心没看好这里!!!也是太长时间不摸LVM了。。。

[root@lightdb ~]# pvdisplay
--- Physical volume ---
PV Name /dev/sdb1
VG Name vg
PV Size 931.51 GiB / not usable 4.00 MiB
Allocatable yes
PE Size 4.00 MiB
Total PE 238466
Free PE 1
Allocated PE 238465
PV UUID 3MQezN-W53d-oj6q-I3GK-9GdP-j4Yj-hag2Dj





[root@lightdb ~]# vgdisplay
--- Volume group ---
VG Name vg
System ID
Format lvm2
Metadata Areas 1
Metadata Sequence No 4
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 3
Open LV 3
Max PV 0
Cur PV 1
Act PV 1
VG Size <931.51 GiB
PE Size 4.00 MiB
Total PE 238466
Alloc PE / Size 238465 / 931.50 GiB
Free PE / Size 1 / 4.00 MiB
VG UUID dzuyJa-LoIn-ZUAY-BvEN-X13J-EYkc-daFgy5






[root@lightdb ~]# lvdisplay
--- Logical volume ---
LV Path /dev/vg/swap
LV Name swap
VG Name vg
LV UUID qNuaiE-j4mA-5dZJ-RsZZ-YqKX-4zSm-P2vWg8
LV Write Access read/write
LV Creation host, time lightdb, 2018-05-12 15:20:38 -0400
LV Status available
# open 2
LV Size <7.88 GiB
Current LE 2016
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 256
Block device 253:1

--- Logical volume ---
LV Path /dev/vg/tmp
LV Name tmp
VG Name vg
LV UUID oaS1B0-eSu3-s7B4-L2Dl-EUAs-wQxU-Ueohsl
LV Write Access read/write
LV Creation host, time lightdb, 2018-05-12 15:20:39 -0400
LV Status available
# open 1
LV Size 1.00 GiB
Current LE 256
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 256
Block device 253:2

--- Logical volume ---
LV Path /dev/vg/root
LV Name root
VG Name vg
LV UUID wqdC7u-9sg4-ekEH-dwR5-kBpy-PdN0-TXVcN0
LV Write Access read/write
LV Creation host, time lightdb, 2018-05-12 15:20:40 -0400
LV Status available
# open 1
LV Size <922.63 GiB
Current LE 236193
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 256
Block device 253:0

/dev/sda 这个硬盘上创建新的分区,使用剩余的全部空间

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
[root@lightdb ~]# fdisk /dev/sda
Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): t
Partition number (1,2, default 2): 2
Hex code (type L to list all codes): 8e
Changed type of partition 'Linux' to 'Linux LVM'

Command (m for help): p

Disk /dev/sda: 1000.2 GB, 1000204886016 bytes, 1953525168 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x00040a3c

Device Boot Start End Blocks Id System
/dev/sda1 * 2048 514047 256000 83 Linux
/dev/sda2 514048 1953525167 976505560 8e Linux LVM

Command (m for help): w
The partition table has been altered!

/dev/sda2 做成 PV

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
[root@lightdb ~]# pvcreate /dev/sda2 
Physical volume "/dev/sda2" successfully created.


[root@lightdb ~]# pvdisplay
--- Physical volume ---
PV Name /dev/sdb1
VG Name vg
PV Size 931.51 GiB / not usable 4.00 MiB
Allocatable yes
PE Size 4.00 MiB
Total PE 238466
Free PE 1
Allocated PE 238465
PV UUID 3MQezN-W53d-oj6q-I3GK-9GdP-j4Yj-hag2Dj

"/dev/sda2" is a new physical volume of "<931.27 GiB"
--- NEW Physical volume ---
PV Name /dev/sda2
VG Name
PV Size <931.27 GiB
Allocatable NO
PE Size 0
Total PE 0
Free PE 0
Allocated PE 0
PV UUID gGrU32-2AW0-10Sv-upON-cXEE-hqC9-fe3X76

给 VG 扩容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@lightdb ~]# vgextend vg /dev/sda2 
Volume group "vg" successfully extended

[root@lightdb ~]# vgdisplay
--- Volume group ---
VG Name vg
System ID
Format lvm2
Metadata Areas 2
Metadata Sequence No 6
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 3
Open LV 3
Max PV 0
Cur PV 2
Act PV 2
VG Size <1.82 TiB
PE Size 4.00 MiB
Total PE 476870
Alloc PE / Size 476870 / <1.82 TiB
Free PE / Size 0 / 0
VG UUID dzuyJa-LoIn-ZUAY-BvEN-X13J-EYkc-daFgy5

/dev/mapper/vg-root 这个 LV 扩容

1
2
3
4
[root@lightdb ~]# lvextend -l +100%FREE /dev/vg/root
Size of logical volume vg/root changed from <922.63 GiB (236193 extents) to 1.81 TiB (474598 extents).
Logical volume vg/root successfully resized.

刷新文件系统

1
2
3
4
5
[root@lightdb ~]# resize2fs /dev/vg/root
resize2fs 1.42.9 (28-Dec-2013)
Filesystem at /dev/vg/root is mounted on /; on-line resizing required
old_desc_blocks = 116, new_desc_blocks = 232
The filesystem on /dev/vg/root is now 485988352 blocks long.

查看下是否成功

1
2
3
4
5
6
7
8
9
10
[root@lightdb ~]# df -hP
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/vg-root 1.8T 1.2G 1.7T 1% /
devtmpfs 7.8G 0 7.8G 0% /dev
tmpfs 7.8G 0 7.8G 0% /dev/shm
tmpfs 7.8G 8.6M 7.8G 1% /run
tmpfs 7.8G 0 7.8G 0% /sys/fs/cgroup
/dev/sda1 243M 148M 83M 65% /boot
/dev/mapper/vg-tmp 976M 2.6M 907M 1% /tmp
tmpfs 1.6G 0 1.6G 0% /run/user/0

根目录已经是1.8T,扩容成功!

重启服务器看了下,也没有什么异常,OVER!


扩展阅读

简单说下什么是 LVM

LVMLogical Volume Manager 的简称。可以用来在物理硬盘上创建虚拟的卷,使服务器的硬盘动态扩容变的更加轻松。

其中这里面涉及到以下几个常用概念:

  • 物理卷(PV, Physical Volume)
    物理卷就是指磁盘,磁盘分区或从逻辑上和磁盘分区具有同样功能的设备(如RAID),是LVM的基本存储逻辑块,但和基本的物理存储介质(如分区、磁盘等)比较,却包含有和LVM相关的管理参数。当前LVM允许你在每个物理卷上保存这个物理卷的0至2份元数据拷贝.默认为1,保存在设备的开始处.为2时,在设备结束处保存第二份备份.

  • 卷组(VG, Volume Group)
    LVM卷组类似于非LVM系统中的物理硬盘,其由物理卷组成。能在卷组上创建一个或多个“LVM分区”(逻辑卷),LVM卷组由一个或多个物理卷组成。

  • 逻辑卷(LV, Logical Volume)
    LVM的逻辑卷类似于非LVM系统中的硬盘分区,在逻辑卷之上能建立文件系统(比如/home或/usr等)。

其实可以简单的理解为:PV相当于是传统硬盘的扇区,VG相当于是传统硬盘,LV是在VG上划分的逻辑分区。

Over!

通过跑前几天的脚本,发现网络不稳定会导致区块数据同步不全,因此还需要写一个守护脚本,定期去检查下未完成的区块,并完成同步。

但在写的过程中发现了一个坑,目前还没有找到触发的原因,临时找到了解决方案。

下面就是简化版的问题代码:

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!/usr/bin/python3
#encoding:UTF-8
import sys, time
from contextlib import suppress
import pymysql
# init db
try:
conn = pymysql.connect(
host = "steem-lightdb.com",
user = "steem",
password = "steem",
database = "steemdb",
charset = 'utf8',
cursorclass = pymysql.cursors.DictCursor)
#conn.autocommit(True)
except Exception as e:
print('[warning] DB connection failed', e)
sys.exit()

def getLatestBlockNumFromDB():
global conn
sql = '''
Select block_num from blocks
Order by block_num desc limit 1;
'''
try:
with conn.cursor() as cursor:
cursor.execute(sql)
result = cursor.fetchone()
if result:
return int(result['block_num']) + 1
else:
return 1
conn.commit()
except Exception as e:
print('[warning]get latest block num error', e)
return 1

def run():
while True:
latest_block_num = getLatestBlockNumFromDB()
print(latest_block_num)
time.sleep(3)

if __name__ == '__main__':
with suppress(KeyboardInterrupt):
run()

问题 :每次获取最新的区块号,总是一样的,就像被 cache 了一样。手动 commit 没有效果。

临时解决方案 :把 autocommit 打开即可。

参考:https://github.com/PyMySQL/PyMySQL/issues/76

等以后有机会再解决吧。。。

在使用 pymysql 的时候遇到的两个坑。

第一个,在 pymysqlsql 语句中的占位符并不是 Python 中常规的占位符,sql 中的所有占位符都是 %s。如果你在 sql 中使用了类似 %d 这样的占位符,你会得到类似 TypeError: %d format: a number is required, not str 这样的错误提示。参考:https://stackoverflow.com/questions/5785154/python-mysqldb-issues-typeerror-d-format-a-number-is-required-not-str

第二个坑,依旧是使用规则上的问题,先看代码:

1
2
3
4
5
6
sql = "insert into TABLE (col_a, col_b) values (%s, %s)"
data = ("abc", "xyz")
cursor.execute(sql, data)

sql = "insert into TABLE (col_a, col_b) values ('%s', '%s')" % ("abc", "xyz")
cursor.execute(sql)

以上两种用法都是可以的,但是坑就在于不要混用,比如下面这两种情况:

1
2
3
4
5
6
sql = "insert into TABLE (col_a, col_b) values (%s, %s)" % ("abc", "xyz")
cursor.execute(sql)

sql = "insert into TABLE (col_a, col_b) values ('%s', '%s')"
data = (("abc", "xyz"), ("efg", "uvw"))
cursor.executemany(sql, data)

由于 pymysql 里有相应的机制来处理传入的 sql 语句和数据,但是机制并不完善,所以混用将会导致有多余的引号出现。

之前在家里的服务器上搭建了一个 BTS 的 API 节点,使用的是 Let’s Encrypt 的证书服务。搭建好以后,一直有一个奇怪的问题没有解决,就是在交易所使用没有问题,但是用 wscat 连接就会报 Error: unable to verify the first certificate 的错误,如下图:

使用 openssl s_client -connect bts.to0l.cn:4443 检查也是有报错的

由于不影响我使用交易所,所以就忽略了。今天 @abit 在群里说我的节点证书有问题,虽然没有指出具体问题在哪,我目测应该就是这个问题。

经过检查,证书生成没有问题,最后确定是 nginx 的证书配置有问题,参考了这个帖子 https://serverfault.com/questions/875297/verify-return-code-21-unable-to-verify-the-first-certificate-lets-encrypt-apa

就是把

1
ssl_certificate      /root/.acme.sh/bts.to0l.cn/fullchain.cer;

替换成

1
ssl_certificate      /root/.acme.sh/bts.to0l.cn/bts.to0l.cn.cer;

这次之所以出现这个问题,也是疏忽。之前在服务器上一直用 certbot 生成证书,certbot 生成证书后,会提示使用如下两个文件

1
2
/etc/letsencrypt/live/xxxx.net/fullchain.pem;
/etc/letsencrypt/live/xxxx.net/privkey.pem;

而这次使用家里搭建服务器,由于联通封锁了家庭网络的 80 和 443 ,所以没有办法用 certbot 来签发证书,因此使用的是 acme 脚本,通过 DNS 来完成证书签发过程中的域名认证。而 acme 最后生成好后,给出的两个文件是

1
2
/root/.acme.sh/bts.to0l.cn/bts.to0l.cn.cer;
/root/.acme.sh/bts.to0l.cn/bts.to0l.cn.key;

所以相当然的就配置上了。

具体的这两个证书文件为何不同还不清楚,目测 bts.to0l.cn.cer 是一个不完整的证书吧,以后有时间再去研究下。

部署YOYOW见证人有几个月了,发现貌似没有人关注丢块的问题,我也没有找到有相关的开源软件可以去完成丢块自动下线的功能。像 Steem 社区有太多的类似程序了,python 的、nodejs 的,多的数不胜数。只能说 YOYOW 还是很年轻。

作为一个 YOYOW 的见证人,有义务去开发一款这样开源版本的工具。经过一晚上的折腾,基本功能已经是完成了。代码库在 这里。这个工具是基于docker进行部署的,如果你看了上一篇我写的《YOYOW 见证人教程》 , 那么这个工具的部署应该会很轻松。因为我花了大量的时间在部署脚本上(大约6个小时),目的就是尽可能把部署过程傻瓜化。

准备

  • 一台 Linux 服务器,装有 docker , wget
  • 如果需要通知服务,请自行注册discord,并创建一个新的服务器、频道和频道的webhook(文章最后有个简易获取 Webhook 的教程)。

开始

1.首先下载代码

1
2
git clone https://github.com/ety001/yoyow-witness-watcher.git
cd yoyow-witness-watcher

2.部署 yoyow_client,并提供 RPC 服务。

1
./init.sh

首先提示你输入 yoyow_client 的下载地址:

1
2
3
4
5
6
7
8
*********************************************
Welcome to use YOYOW witness watcher.
This tool is made by ETY001. (https://github.com/ety001)
My YOYOW ID is 485699321. It's pleasure to get your votes!
*********************************************

Please input current yoyow_client download URL (https://github.com/yoyow-org/yoyow-core/releases/latest):
https://github.com/yoyow-org/yoyow-core/releases/download/v0.2.1-180313/yoyow-client-v0.2.1-ubuntu-20180313.tgz

下载地址可以在 https://github.com/yoyow-org/yoyow-core/releases/latest 找到,填写下载地址后,回车继续。

当看到出现 Listening for incoming HTTP RPC requests on 0.0.0.0:9999 以及 new >>> 的时候说明 yoyow_client 的 docker 镜像已经做好,现在开始创建钱包并导入你的账号

1
2
3
4
5
6
7
8
9
10
11
Create wallet
Logging RPC to file: logs/rpc/rpc.log
3505859ms th_a main.cpp:120 main ] key_to_wif( committee_private_key ): 5KCBDTcyDqzsqehcb52tW5nU6pXife6V2rX9Yf7c3saYSzbDZ5W
3505862ms th_a main.cpp:124 main ] nathan_pub_key: YYW6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
3505862ms th_a main.cpp:125 main ] key_to_wif( nathan_private_key ): 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
Starting a new wallet with chain ID ae4f234c75199f67e526c9478cf499dd6e94c2b66830ee5c58d0868a3179baf6 (from egenesis)
3505863ms th_a main.cpp:172 main ] wdata.ws_server: wss://wallet.yoyow.org/ws
3506840ms th_a main.cpp:177 main ] wdata.ws_user: wdata.ws_password:
Please use the set_password method to initialize a new wallet before continuing
3509652ms th_a main.cpp:243 main ] Listening for incoming HTTP RPC requests on 0.0.0.0:9999
new >>>

先设置本地钱包密码(比如 123456)

1
set_password 123456

解锁本地钱包

1
unlock 123456

导入你的 YOYOW 账号

1
import_key YOUR_YOYOW_ID  YOUR_YOYOW_ACTIVE_KEY

完成以上工作后,按 ctrl + d 退出钱包,docker 容器开始重启

直到看到 Finish 且已经在监听 9999 端口时,整个 yoyow_client 的部署完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Get Status
00200e8bde55 yoyow_client "/bin/sh -c '/data/y…" 10 seconds ago Up 10 seconds yoyow_client

Logs
Logging RPC to file: logs/rpc/rpc.log
140909ms th_a main.cpp:120 main ] key_to_wif( committee_private_key ): 5K**********************5W
140910ms th_a main.cpp:124 main ] nathan_pub_key: YY************************CV
140910ms th_a main.cpp:125 main ] key_to_wif( nathan_private_key ): 5****************************3
140912ms th_a main.cpp:172 main ] wdata.ws_server: wss://wallet.yoyow.org/ws
141820ms th_a main.cpp:177 main ] wdata.ws_user: wdata.ws_password:
145239ms th_a main.cpp:243 main ] Listening for incoming HTTP RPC requests on 0.0.0.0:9999

************
Finish!

3.部署监控程序

直接运行下面的命令开始部署

1
./install_bot.sh

提示输入你的 YOYOW ID

1
2
3
# ./install_bot.sh
Please input YOYOW ID:
485699321

提示输入你签名块用的公钥。

1
2
3
4
Please input Your Public Key:
If you have multiple public keys, separate them with commas
eg. YYW7TSRLZ9EXZps37Kt31qa7qi,YYW7TSRLZ9EXZpZqk25atoL2s37
YYW7TSRLZ9EXZpZqk25atoL2s37Kt31qa7qi78ZR368kCN969rFiT,YYW733FxEEaAFTHxdTJdowZyQzJ3JnPocsVmdq4aSsm1gSd1VkYDC

> 如果你有多台备机,可以用逗号把多个公钥隔开填写,请务必把当前正在运行的节点的公钥放在第一位,程序会在检测到丢块后,自动依次往后切换,直到所有节点都不可用。因此,如果你有两个节点的话,当第一个节点挂掉,程序自动切换到第二个备份节点后,赶紧去修第一个节点,第一个节点重启可用后,一定要重新部署下bot程序,并且填写公钥时,把目前的第二个节点的公钥放在前面

提示输入你的本地钱包密码

1
2
Please input wallet password:
123456

提示输入 discord 的 webhook 地址,如果你想获取通知的话,就配置这项,否则留空。最后会简单说下怎么获取 webhook 地址

1
2
Please input Discord webhook for notify (If you don't need it, leave empty.):
https://discordapp.com/api/webhooks/433204170/X2RWo7-qiFlnMtQeQkk_sSgb5Vn0rQVWZCF5f

当你看到类似以下信息的时候,就已经完成了所有部署工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Get status
string(20) "global value in init"
array(2) {
[0]=>
string(53) "YYW7TSRLZ9EXZpZqk25atoL2s37Kt31qa7qi78ZR368kCN969rFiT"
[1]=>
string(53) "YYW733FxEEaAFTHxdTJdowZyQzJ3JnPocsVmdq4aSsm1gSd1VkYDC"
}
string(9) "485699321"
string(27) "http://172.20.99.2:9999/rpc"
int(3)
send_notify:""
witness_info: [{"id":"1.5.118","account":485699321,"name":"yoyo485699321","sequence":1,"is_valid":true,"signing_key":"YYW7TSRLZ9EXZpZqk25atoL2s37Kt31qa7qi78ZR368kCN969rFiT","pledge":"4800000000","pledge_last_update":"2018-04-09T16:27:36","average_pledge":"4769814330","average_pledge_last_update":"2018-04-10T09:29:36","average_pledge_next_update_block":6208938,"total_votes":"1012502907669","by_pledge_position":"0","by_pledge_position_last_update":"13192707760156474609520154309632187","by_pledge_scheduled_time":"13192779100955781906176323330356157","by_vote_position":"0","by_vote_position_last_update":"8327365446400524735205121087916251","by_vote_scheduled_time":"8327365782480909634055199728870765","last_confirmed_block_num":6208607,"last_aslot":6220862,"total_produced":1143,"total_missed":3,"url":"https:\/\/github.com\/ety001"}]
total_produced: 1143, total_missed: 3
2018-04-10 10:23:38


***********
Finish!!

如果想查看监控程序的工作状态,执行下面的命令即可

1
docker logs --tail 50 yoyow_witness_watcher

4.卸载

卸载非常的简单,只需要执行下面的命令即可

1
./uninstall_bot.sh &amp;&amp; ./uninstall.sh

> 如果你只想重新部署监控程序,只需要执行 ./uninstall_bot.sh 即可,执行完后重新执行 ./install_bot.sh。如果你中途执行安装脚本有错误的话,也需要先执行卸载脚本后,再重新执行安装脚本。卸载脚本如果都要执行的话,执行顺序一定要是先 uninstall_botuninstall

申请 Discord 的频道 Webhook

注册账号就不说了,打开桌面app界面(网页界面应该也差不多),在左下角找到一个加号,点击后如下图

y1.png

选择创建一个服务器,进入下个界面,配置下你的服务器的名字和位置后,即可完成创建,进入你的服务器,新建一个频道,然后在频道右侧有个齿轮,点击一下,如图

y2.png

打开频道配置页面后,找到 Webhook 选项,然后创建一个新的 Webhook,如图

y3.png

填写下 Webhook 的名字后,即可完成创建,里面的 URL 即为你的 Webhook 地址。

欢迎给我投票,我的 YOYOW 号是 485699321

0%