新溪blog

新溪-gordon之胡写乱画

0%

问题描述

域名是通过代理商在阿里买的,然后域名解析用的腾讯dnspod的收费版
域名过期消息通知都是发到代理商那里,我们不知道域名过期这事
过期后,阿里把权威dns改成EXPIRENS3.HICHINA.COM/EXPIRENS4.HICHINA.COM。
于是域名解析有问题了,但这个问题因为dns缓存机制,延迟了1整天才被发现。
续费后,权威dns修改正常,同样因为dns缓存机制,有48小时的缓存时间,所以有很多地方请求还是有问题
有一部分机器请求阿里的那个权威dns,一部分请求腾讯的权威dns,而请求阿里那部分失败。

问题解决

中间经历了各种尝试就不细说了,最后
在阿里上也修改二级域名记录,修改后,不管是请求哪个权威dns,结果都是对的
原因可能是:

阿里过期dns对不过期的域名也做了域名解析
阿里云对顶级域服务器来说是有可控的写入权的销售商

问题虽然解决,但以前对dns了解很浅,得把这个问题彻底搞明白
以后再遇到dns的其他问题,就能做到心中有数了

相关定义

权威DNS:

权威DNS是经过上一级授权对域名进行解析的服务器,同时它可以把解析授权转授给其他人,如:
  COM顶级服务器可以授权dns.com这个域名的的权威服务器为NS.ABC.COM
  同时NS.ABC.COM还可以把授权转授给NS.DDD.COM
  这样NS.DDD.COM就成了ABC.COM实际上的权威服务器了
平时我们解析域名的结果都源自权威DNS。比如:
  dns.com的权威DNS服务器就是帝恩思的ns1.dns.com ns2.dns.com
  ali云的权威DNS服务器是:
      DNS9.HICHINA.COM
      DNS10.HICHINA.COM
  dnspod权威dns:
      NS3.DNSV3.COM
      NS3.DNSV3.COM

递归DNS:

负责接受用户对任意域名查询,并返回结果给用户。递归DNS可以缓存结果以避免重复向上查询。
平时使用最多的就是这类DNS,对公众开放服务,一般由网络运营商提供,自己可以架递归DNS提供服务
递归DNS一定要有可靠的互联网连接方可使用。比如:
  谷歌的8.8.8.8和8.8.4.4
  114的114.114.114.114和114.114.115.115都属于这一类DNS
你本地电脑上设置的DNS就是这类DNS

转发DNS:

负责接受用户查询,并返回结果给用户。
但此结果不是按标准域名解析过程得到的,而是直接把递归DNS的结果转发给用户。它也具备缓存功能。
他主要使用在没有直接的互联网连接,但可以连接到一个递归DNS那里,这时使用转发DNS就比较合适。
其缺陷是:
  直接受递归DNS的影响,服务品质较差。
如路由器里面的DNS就是这一类,用路由器的朋友可以看下本地电脑的DNS一般都是192.168.1.1

域名解析过程

用户—本地递归服务器—根权威服务器—COM权威服务器—xxorg.com权威服务器—用户
对顶级域服务器来说销售商有可控的写入权。

递归服务器怎么知道根权威服务器的地址?

很简单,在递归服务器上都保存有一份根服务器的地址列表。最新的根服务器地址列表在这里可以得到:
ftp://ftp.internic.net/domain/named.root

递归服务器每次查询域名都要向根那里找权威服务器吗?

不是的,一旦成功一次,递归服务器就会把权威服务器列表缓存下来
如COM顶级服务器列表可以缓存48小时

操作步骤:

1、在浏览器中输入www.qq.com 域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析。
2、如果hosts里没有这个域名的映射,则查找本地DNS解析器缓存,是否有这个网址映射关系,如果有,直接返回,完成域名解析。
3、如果hosts与本地DNS解析器缓存都没有相应的网址映射关系,首先会找TCP/ip参数中设置的首选DNS服务器,在此我们叫它本地DNS服务器,此服务器收到查询时,如果要查询的域名,包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析,此解析具有权威性。
4、如果要查询的域名,不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析,此解析不具有权威性。
5、如果本地DNS服务器本地区域文件与缓存解析都失效,则根据本地DNS服务器的设置(是否设置转发器)进行查询,如果未用转发模式,本地DNS就把请求发至13台根DNS,根DNS服务器收到请求后会判断这个域名(.com)是谁来授权管理,并会返回一个负责该顶级域名服务器的一个IP。本地DNS服务器收到IP信息后,将会联系负责.com域的这台服务器。这台负责.com域的服务器收到请求后,如果自己无法解析,它就会找一个管理.com域的下一级DNS服务器地址(http://qq.com)给本地DNS服务器。当本地DNS服务器收到这个地址后,就会找http://qq.com域服务器,重复上面的动作,进行查询,直至找到www.qq.com主机。
6、如果用的是转发模式,此DNS服务器就会把请求转发至上一级DNS服务器,由上一级服务器进行解析,上一级服务器如果不能解析,或找根DNS或把转请求转至上上级,以此循环。不管是本地DNS服务器用是是转发,还是根提示,最后都是把结果返回给本地DNS服务器,由此DNS服务器再返回给客户机。https://www.nslookuptool.com 可以查询在进行DNS修改后,域名被各个地区的域名服务器收录的情况,以及当前收录的域名对应的ip地址。

一些信息

13台根DNS服务器在全球的放置:

美国VeriSign公司 2台
美国PSINet公司 1台
美国ISI(Information Sciences Institute) 1台
美国ISC(Internet Software Consortium) 1台
美国马里兰大学(University of Maryland) 1台
美国太空总署(NASA) 1台
美国国防部 1台
美国陆军研究所 1台
挪威NORDUnet 1台
日本WIDE(Widely Integrated Distributed Environments)研究计划 1台
网络管理组织IANA(Internet Assigned Number Authority) 1台
欧洲网络管理组织RIPE-NCC(Resource IP Europeens Network Coordination Centre) 1台

CANN在中国大陆授权的10家国际域名注册商:

ChinaSource Internet Service Co., Ltd.(中资源)
ename Co.,Ltd.(易名中国)
35 Technology Co., Ltd.(三五科技)
Beijing Innovative Linkage Technology Ltd.(新网互联)
Bizcn.com, Inc.(商务中国)
HiChina Web Solutions (Hong Kong) Limited(万网)
Inter China Network Software (Beijing) Co., Ltd.(3721)
OnlineNIC, Inc.(厦门精通,即中国频道)
Todaynic.com, Inc.(时代互联)
Xin Net Technology Corporation(新网)

dig命令的使用

$ dig +trace blog.zhaoweiguo.com:

; <<>> DiG 9.10.3-P4-Debian <<>> +trace blog.zhaoweiguo.com
;; global options: +cmd
.     172206  IN  NS  m.root-servers.net.
.     172206  IN  NS  b.root-servers.net.
.     172206  IN  NS  c.root-servers.net.
.     172206  IN  NS  d.root-servers.net.
.     172206  IN  NS  e.root-servers.net.
.     172206  IN  NS  f.root-servers.net.
.     172206  IN  NS  g.root-servers.net.
.     172206  IN  NS  h.root-servers.net.
.     172206  IN  NS  i.root-servers.net.
.     172206  IN  NS  j.root-servers.net.
.     172206  IN  NS  a.root-servers.net.
.     172206  IN  NS  k.root-servers.net.
.     172206  IN  NS  l.root-servers.net.
.     172206  IN  RRSIG NS 8 0 518400 20190323050000 20190310040000 16749 . TgmuL0MjWMidemDVGJC+v5G2BsE33xO5rayFm8qYfOLlNh8kiM9MtLsD Xicpzchrt3/OI+mOh2t/UyQJ4njI1PTP3MXwkUIgVHEx8rF5vYJKrMyP E4Mohd8XZ2nClb6qyvWk+dIYwE14aPpIonkU7L2wE4uxiGCl6lW9Q0GL j8UDyi4D7UkEHJ8qVebWzYDSeuhv+kWRHJqY7M1/MY/HezA1h6qNyw08 FmRGpf+/xT8bahzIQ1wY9yQwOmBjFhB6KZIxehsB/1HEHP44QuCQRz3R gI4IHwuDW+vw9wOvhM4lqLukONqQ7p3/xHFGlgKyYA+EboF/0QgPaXtF 7ri06w==
;; Received 525 bytes from 8.8.4.4#53(8.8.4.4) in 33 ms

说明:
  从本地递归dns(8.8.4.4)取出13台全球根域名服务器的地址
  继续向这13台全球根域名服务器请求.com顶级域名服务器地址,以最先回复的为准

com.      172800  IN  NS  a.gtld-servers.net.
com.      172800  IN  NS  b.gtld-servers.net.
com.      172800  IN  NS  c.gtld-servers.net.
com.      172800  IN  NS  d.gtld-servers.net.
com.      172800  IN  NS  e.gtld-servers.net.
com.      172800  IN  NS  f.gtld-servers.net.
com.      172800  IN  NS  g.gtld-servers.net.
com.      172800  IN  NS  h.gtld-servers.net.
com.      172800  IN  NS  i.gtld-servers.net.
com.      172800  IN  NS  j.gtld-servers.net.
com.      172800  IN  NS  k.gtld-servers.net.
com.      172800  IN  NS  l.gtld-servers.net.
com.      172800  IN  NS  m.gtld-servers.net.
com.      86400 IN  DS  30909 8 2 E2D3C916F6DEEAC73294E8268FB5885044A833FC5459588F4A9184CF C41A5766
com.      86400 IN  RRSIG DS 8 1 86400 20190324050000 20190311040000 16749 . qNqvX6qD9q7IJMn09ue59cubovzfECVYmWPmNUdHtDEiaBIjNFP8oaA7 pT4B/JA43tQTsPF1B9wC/zivN63n7xv4fNpdY2rXXgGsZX9ycme22kKt dZ/kV6rpiMoSCvZ8qmUlWWKkiq3aXYCYVznWoA9s3xM8oFUNG839N1ke OWiYQlGZn8LoETkUiPG4qCsARNdb/DMrj0BOywzYhO00lc/DnyHvgbT5 l7Dzi+Abxs2jZohrz270A19Sed9l2xulBq+6Y4ryxFYhr6hk6pZ0PqgJ tnMDI05n2mMls0xmpE61u/V2mJxSGAcb3s6UTAlXIPENnx23q4YeLgy/ zh058A==
;; Received 1179 bytes from 192.58.128.30#53(j.root-servers.net) in 308 ms

说明:
  最先回复的根域名服务器是j.root-servers.net(192.58.128.30)
  返回13台.com顶级域名服务器的域名和地址,继续向这些.com顶级域名服务器请求
  查询zhaoweiguo.com二级域名服务器地址

zhaoweiguo.com.   172800  IN  NS  dns9.hichina.com.
zhaoweiguo.com.   172800  IN  NS  dns10.hichina.com.
CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN NSEC3 1 1 0 - CK0Q1GIN43N1ARRC9OSM6QPQR81H5M9A  NS SOA RRSIG DNSKEY NSEC3PARAM
CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN RRSIG NSEC3 8 2 86400 20190316044521 20190309043521 16883 com. DHkCBLG4YbAgDR7yj/Qu+LD/prXqR7NdPThP3mqis2aQcYw2WC6Y5Baq fCdYF1c1bgT9oBe/SusdZgqT56CzrXoF+G1MwRIrMdHCUHvR6BU28GCw 2rJJ9wcmrri2+mWHA0W1qBpt8bm0K3/V2FmLDtit0bJyUyZkfQ8BtRBB hZ8=
KOHGII341DQ77IRB2UN8I8B4L5DQADV9.com. 86400 IN NSEC3 1 1 0 - KOHGO5POINBII7KFF2Q6VC4IKISTH7NC  NS DS RRSIG
KOHGII341DQ77IRB2UN8I8B4L5DQADV9.com. 86400 IN RRSIG NSEC3 8 2 86400 20190318045050 20190311034050 16883 com. gHTSd9Z23gcTTVjl8dLYUBhGXZrMXITQd0q1JwJd+copTe6F+gcIG8DX LhiGiGO2XQtbovo6Lfe9QWtLj3yBa6apIQ2XSab+VpJugPASNDu/8zKX 2v4sPVqvm1kjcIMX6nPwcQVVyAFcVu5uKTH+344QWf8lbpBmCwfNk2TW /0Y=
;; Received 892 bytes from 192.43.172.30#53(i.gtld-servers.net) in 267 ms

说明:
  最先回复的.com顶级域名服务器是i.gtld-servers.net(192.42.93.30)
  (gtld是global top level domain的缩写)
  返回2台zhaoweiguo.com二级域名服务器的域名和地址
  继续向这2个结果请求查询blog.zhaoweiguo.com三级域名服务器

blog.zhaoweiguo.com.  600 IN  CNAME zhaoweiguo.github.io.
;; Received 82 bytes from 106.11.141.116#53(dns10.hichina.com) in 43 ms

说明:
  最先回复的zhaoweiguo.com二级域名服务器是dns10.hichina.com(106.11.141.116)
  返回1个A记录,其中A记录就是最终的解析地址
注意:
  如果阿里域名用dnspod解析,会多出2条NS记录
  blog.zhaoweiguo.com.  600 IN  A 115.29.97.185
  zhaoweiguo.com.    86400 IN  NS  f1g1ns1.dnspod.net.
  zhaoweiguo.com.    86400 IN  NS  f1g1ns2.dnspod.net.

小结

从整体对DNS有了大概的了解,很细节的东西还不是很清楚,需要自己手动搭建一个DNS服务实践一下
从现在的了解的情况来看,有几个时间:

  1. 域名解析时的TTL:递归DNS缓存过期时间:

    大多设置为10分钟
    域名请求递归DNS时,会直接从缓存中取数据,数据过期后,可能会:
    a. 直接请求顶级DNS,取得权威DNS,再请求二级权威DNS得到ip
    b. a请求超时,请求根DNS,再依次取得顶级DNS,二级权威DNS得到ip

  2. 顶级DNS更新权威DNS时间:

    这个大多是48小时内,最高可达72小时
    这也是我们遇到这个问题的根源所在

一些实用网站

https://www.nslookuptool.com
https://www.17ce.com

参考资料

https://www.dns.com/supports/681.html
https://www.jianshu.com/p/babca8224e60

前言

最近遇到一个奇怪的问题,mnesia数据有时能查出来有时查不出来,细查发现是mnesia:delect_object删除时,只删除了索引,没有删除具体的数据

问题重现

  1. 表结构:
1
2
3
4
5
6
7
-record(gordon_test, {
idr, % {id, pid}
id,
pid,
locale,
time = os:timestamp()
}).
  1. 初使化代码:
1
2
3
4
5
6
mnesia:create_table(gordon_test, [
{ram_copies, [node() | nodes()]},
{attributes, record_info(fields, gordon_test)}
]),
mnesia:add_table_index(gordon_test, id),
mnesia:add_table_index(gordon_test, pid).
  1. 插入数据:
1
2
3
mnesia:dirty_write(gordon_test, {gordon_test, {1, 1}, 1, 1, "", "", os:timestamp()}).
mnesia:dirty_write(gordon_test, {gordon_test, {2, 2}, 2, 2, "", "", os:timestamp()}).
mnesia:dirty_write(gordon_test, {gordon_test, {3, 3}, 3, 3, "", "", os:timestamp()}).

3.查询:

1
2
3
4
5
Id = 3,
Pid = 3,
% 查出id=3的所有记录,都能查出一条记录
mnesia:dirty_index_read(gordon_test, Id, #gordon_test.id),
mnesia:dirty_index_match_object(#gordon_test{idr = '$1',id=Id, _='_'}, #gordon_test.id),
  1. 执行删除:
1
2
3
4
5
6
mnesia:dirty_delete_object(X#gordon_test{locale = aaaa}).
or
Trans = fun() ->
mnesia:delete_object(X#gordon_test{locale = aaaa})
end,
mnesia:transaction(Trans)
  1. 两次查询,dirty_index_read查不到数据:
1
2
3
4
% 数据查询为空
mnesia:dirty_index_read(gordon_test, Id, #gordon_test.id),
% 数据不变
mnesia:dirty_index_match_object(#gordon_test{idr = '$1',id=Id, _='_'}, #gordon_test.id),

问题定位

查文档:

1
2
3
4
5
6
If a table is of type bag, it can sometimes be needed to delete only some of the records with a certain key. 
This can be done with the function delete_object/3. A complete record must be supplied to this function.

The semantics of this function is context-sensitive. For details, see mnesia:activity/4.
In transaction-context, it acquires a lock of type LockKind on the record.
Currently, the lock types write and sticky_write are supported.

深层研究

待继续 @todo

前言

最近和同事聊天的时候,我突然想到进程Pid格式为<A1, A2, A3>,其中A1代表Node值, A2, A3则代表指定Node下的进程值,开始A3为0。当A2的值增加到一定数后, A3的值加1,那么问题来了:

1
2
1. A2增加到多少,A31
2. 如果A3的值也增加到这个值后会有什么情况出现呢?

问题1

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-module(spawn_loop_infinite2).
-author("zhaoweiguo").

%% API
-export([loop/1]).
-export([do_nothing/0]).
-export([loop1/2]).

loop(N) ->
{ok, F} = file:open("aaa.txt", [append]),
loop1(F, N).

loop1(_F, 0) ->
ok;
loop1(F, N) ->
Pid = spawn(spawn_loop_infinite, do_nothing, []),
file:write(F, io_lib:format("[~p]:(~p)~n", [N, Pid])),
loop1(F, N-1).

do_nothing() ->
ok.

执行命令:

1
erl> spawn_loop_infinite2:loop(33000).

打开文件aaa.txt:

1
2
3
4
5
[303]:(<0.32766.0>)
[302]:(<0.32767.0>)
[301]:(<0.0.1>)
[300]:(<0.1.1>)
[299]:(<0.2.1>)

结论:

A2增加到32767,A3加1

问题2

源码:

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
% 每次生成100万新进程,打印下一进程的pid,休息0.1秒后再生成100万新进程
-module(spawn_loop_infinite).
-author("zhaoweiguo").

%% API
-export([loop/2]).
-export([do_nothing/0]).

loop(N, N) ->
io:format("stop~n");
loop(M, N) ->
Add = 32768*10,
io:format("~p;", [N]),
{ok, F} = file:open("fff"++ integer_to_list(N) ++".txt", [append]),
loop1(Add, N, F),
file:close(F),
timer:sleep(10),
loop(M, N+1).

loop1(0, _N, _F) ->
ok;
loop1(Add, N, F) ->
Pid = spawn(spawn_loop_infinite, do_nothing, []),
file:write(F, io_lib:format("[~p]:(~p)~n", [Add, Pid])),
loop1(Add-1, N, F).

do_nothing() ->
ok.

在文件fff820.txt中看到::

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[296800]:(<0.32762.8191>)
[296799]:(<0.32763.8191>)
[296798]:(<0.32764.8191>)
[296797]:(<0.32765.8191>)
[296796]:(<0.32766.8191>)
[296795]:(<0.32767.7>)
[296794]:(<0.5.0>)
[296793]:(<0.7.0>)
[296792]:(<0.11.0>)
[296791]:(<0.8.0>)
[296790]:(<0.17.0>)
[296789]:(<0.16.0>)
[296788]:(<0.24.0>)
[296787]:(<0.6.0>)
...
[296755]:(<0.72.0>)
[296754]:(<0.73.0>)
[296753]:(<0.74.0>)
[296752]:(<0.75.0>)
[296751]:(<0.76.0>)
[296750]:(<0.77.0>)
[296749]:(<0.78.0>)

结论:

1
2
3
A3在增加到8191后就不再增加,改为使用已经回收的进程
经过很短的混乱后又变的有序起来
之后每一次A3+1都会先乱,再有序,并且乱的顺序都是对的

其他发现:

1
2
3
4
5
6
7
% 有个有趣的发现, 在每次进程到达<0.32766.8191>后产生的下一个进程分别是:
<0.32767.7>
<0.32767.15>
<0.32767.23>
<0.32767.31>
<0.32767.39>
<0.32767.47>

前言

谷歌提议将证书有效期缩短到13个月,被其他CA和浏览器厂商无情拒绝,但缩短有效期是人心所向
于是,CAB Forum第193号投票确定最长SSL证书有效期由原来的3年(39个月)改为2年(825天)

问题描述

这一个项目是物联网相关的,有app和硬件设备两种类型的client
因历史原来,两种client用的是一个域名,都使用了ssl证书
证书有效期可能很长,但最近到期了
因为设备没办法强制升级,一是设备可能没联网,二是有些设备还没销售出去,三是设备没有用ca对证书校验
于是解决方案是,app强制升级,升级后使用新域名,新证书
但到了域名过期那天,才发现这么一个问题:

1
2
之前宣传部门印制了许多二维码,用的是原来老域名
所以这些二维码现在不可用了

当然,以后二维码使用专门的短域名、app和设备域名不应该用同一个……
未来如何做是另一码事,现在要想如何解决问题

要想达到的结果是:

1
在不影响设备使用的前提下,让一指定uri可用

举例说明:

1
2
3
1.如有一个域名www.abc.com,给硬件设备用,也给app用
2.最近域名证书过期了,要换证书,但硬件设备没法保证用户升级,于是让app强制升级启用新域名
3.但有一批二维码,已经发出去了,请求地址为: www.abc.com/a/b/c

现在想有没有方法,让:

1
2
1.www.abc.com/a/b/c 使用新证书,或不用证书,只要在浏览器中打开就行
2.www.abc.com其他地址使用老证书,保证设备的可用

问题解决方案

方案1:双证书方案

原理:

1
2
3
4
5
6
7
8
9
10
11
Nginx支持ECC、RSA双证书. 
ECC签个最新的,保障较新设备能够正常访问
RSA依旧保留过期的旧证书,给未更新的设备访问

1.设备使用的一般是乐鑫ESP8266或庆科EMW3162的板子实现ssl
而这些板子下的ssl库一般都不支持ECC
2. 除非很古老的浏览器,其他都支持ECC

所以使用Nginx判断:
如果支持ECC则使用新的ECC证书
如果不支持ECC则使用老的RSA证书

说明:

Windows XP 中,使用 ECC 证书的网站时需要浏览器自行 TLS
Android 平台中,也需要 Android 4+ 才支持 ECC 证书

如果此方案能生效,可以保证:

1.所有的请求都可以完美成功
2.甚至都不需要更换域名

方案2:使用openResty

原理:

1
2
3
4
5
6
1.所有的设备请求第1次失败后会再次请求
2.证书错误时,请求快速失败

所以在openResty中做一个k/v表
第一次请求给他返回新证书,并以ip为key插入一条数据,5秒失效
第二次请求过来,一查k/v表,有数据,返回老证书

说明:

此方案会有一定误杀的情况

结论

我们的设备中有一部分用带有OS的系统,是支持ECC的
这些设备对我们来说是很重要的,所以最后我们采用了方案2

双证书的一些简单操作

生成证书:

1
2
3
4
5
openssl ecparam -genkey -name prime256v1 -out 证书名.key
openssl req -new -key 证书名.key -nodes -out 证书名.csr
例:
openssl ecparam -genkey -name prime256v1 -out www.zhaoweiguo.com.key
openssl req -new -sha256 -key www.zhaoweiguo.com.key -nodes -out www.zhaoweiguo.com.csr

Nginx配置双证书rsa+ecc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 它的实现原理是:
# 分析在 TLS 握手中双方协商得到的 Cipher Suite
# 若支持 ECDSA 就返回 ECC 证书,反之返回 RSA 证书
server{
listen 443 ssl;
server_name www.zhaoweiguo.com;
root /var/www/zhaoweiguo.com/www.zhaoweiguo.com;
index index.php index.html;

ssl_certificate /home/wei64/www.zhaoweiguo.com.crt;
ssl_certificate_key /home/wei64/nginx/ca/www.zhaoweiguo.com.key;

ssl_certificate /home/wei64/nginx/ca/www.zhaoweiguo.com.ecc.crt;
ssl_certificate_key /home/wei64/nginx/ca/www.zhaoweiguo.com.ecc.key;

ssl_prefer_server_ciphers on;
## Cipher Suites 一定要配置好,不然双证书并不会生效
ssl_ciphers "EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES";
}

参考项目:

https://github.com/klarna/brod
https://github.com/erlang-lager/lager
http://kafka.apache.org
https://github.com/newforks/lager_kafka_backend

测试目的:

项目使用lager写日志时,如果日志量非常大,会导致消息队列堆积,进而引起更严重的问题,
于是想着增加一kafka的backend:
  一是为了把所有日志合并在一起
  二是为了增加写入效率

测试对比:

1. 测试file写入文件中带delayed_write与不带的性能对比
2. 测试brod写kafka与file写入的性能对比
3. 测试lager_kafka_backend与lager_file_backend的性能对比

测试内容:

写入数据: <<"123456789qwertyuiopasdfghjklzxcvbnm">>
执行Module:loop(Times, Num).
其中:
  Times: 为执行次数
  Num: 每次执行写入数据次数

代码实例:

1. 普通文件写入: 
https://github.com/zhaoweiguo/demo-erlang/blob/6829ca950f2ea16859d3be23a1396aa3d1fdaf2d/apps/demo_lager/src/speed_file.erl

2. 带delayed_write文件写入:
https://github.com/zhaoweiguo/demo-erlang/blob/6829ca950f2ea16859d3be23a1396aa3d1fdaf2d/apps/demo_lager/src/speed_delayfile.erl

3. 普通写kafka(注:要本地启动kafka server)
https://github.com/zhaoweiguo/demo-erlang/blob/6829ca950f2ea16859d3be23a1396aa3d1fdaf2d/apps/demo_lager/src/speed_brod.erl

4. 通过lager写入文件
https://github.com/zhaoweiguo/demo-erlang/blob/6829ca950f2ea16859d3be23a1396aa3d1fdaf2d/apps/demo_lager/src/speed_lager_file.erl

5. 通过lager写入kafka
https://github.com/zhaoweiguo/demo-erlang/blob/6829ca950f2ea16859d3be23a1396aa3d1fdaf2d/apps/demo_lager/src/speed_lager_kafka.erl

测试结果:

(demo_lager@127.0.0.1)3> speed_file:loop(20, 20).

% 测试过程中文件写入不稳定,有时写入数据差10倍以上,原因不明
time:384 | {0,0,384}
time:833 | {0,0,833}
time:2734 | {0,2,734}
time:484 | {0,0,484}
time:642 | {0,0,642}
time:483 | {0,0,483}
time:609 | {0,0,609}
time:582 | {0,0,582}
time:844 | {0,0,844}
time:795 | {0,0,795}
time:506 | {0,0,506}
time:1125 | {0,1,125}
time:490 | {0,0,490}
time:599 | {0,0,599}
time:605 | {0,0,605}
time:444 | {0,0,444}
time:479 | {0,0,479}
time:415 | {0,0,415}
time:421 | {0,0,421}
time:577 | {0,0,577}

(demo_lager@127.0.0.1)4> speed_delayfile:loop(20, 20).

time:39 | {0,0,39}
time:98 | {0,0,98}
time:78 | {0,0,78}
time:86 | {0,0,86}
time:83 | {0,0,83}
time:149 | {0,0,149}
time:51 | {0,0,51}
time:461 | {0,0,461}
time:85 | {0,0,85}
time:58 | {0,0,58}
time:56 | {0,0,56}
time:108 | {0,0,108}
time:60 | {0,0,60}
time:87 | {0,0,87}
time:62 | {0,0,62}
time:58 | {0,0,58}
time:151 | {0,0,151}
time:417 | {0,0,417}
time:75 | {0,0,75}
time:109 | {0,0,109}

(demo_lager@127.0.0.1)14> speed_brod:loop(20, 20).

time:2900 | {0,2,900}
time:229 | {0,0,229}
time:243 | {0,0,243}
time:293 | {0,0,293}
time:971 | {0,0,971}
time:191 | {0,0,191}
time:183 | {0,0,183}
time:607 | {0,0,607}
time:253 | {0,0,253}
time:256 | {0,0,256}
time:233 | {0,0,233}
time:257 | {0,0,257}
time:145 | {0,0,145}
time:195 | {0,0,195}
time:175 | {0,0,175}
time:135 | {0,0,135}
time:197 | {0,0,197}
time:189 | {0,0,189}
time:166 | {0,0,166}
time:200 | {0,0,200}

(demo_lager@127.0.0.1)15> speed_lager_kafka:loop(20, 20).

time:136 | {0,0,136}
time:176 | {0,0,176}
time:203 | {0,0,203}
time:198 | {0,0,198}
time:161 | {0,0,161}
time:161 | {0,0,161}
time:192 | {0,0,192}
time:141 | {0,0,141}
time:229 | {0,0,229}
time:235 | {0,0,235}
time:253 | {0,0,253}
time:247 | {0,0,247}
time:189 | {0,0,189}
time:201 | {0,0,201}
time:150 | {0,0,150}
time:189 | {0,0,189}
time:153 | {0,0,153}
time:235 | {0,0,235}
time:161 | {0,0,161}
time:176 | {0,0,176}

(demo_lager@127.0.0.1)18> speed_lager_file:loop(20, 20).

time:189 | {0,0,189}
time:192 | {0,0,192}
time:233 | {0,0,233}
time:277 | {0,0,277}
time:177 | {0,0,177}
time:183 | {0,0,183}
time:179 | {0,0,179}
time:290 | {0,0,290}
time:218 | {0,0,218}
time:208 | {0,0,208}
time:215 | {0,0,215}
time:256 | {0,0,256}
time:263 | {0,0,263}
time:287 | {0,0,287}
time:238 | {0,0,238}
time:294 | {0,0,294}
time:226 | {0,0,226}
time:276 | {0,0,276}
time:195 | {0,0,195}
time:332 | {0,0,332}

结论:

1.直接写文件,加不加buffer影响很大
2.直接写kafka,比不加buffer的快,但比加buffer的慢
3.通过lager_file_backend与通过lager_kafka_backend性能差别不大
4.通过lager_file_backend加不加buffer,影响不大
5.可能是虚拟机原因,磁盘写入不稳定

配置文件:

[
 {handlers,[{lager_kafka_backend,[
              {level,                         "info"},
              {topic,                         <<"topic">>},
              {broker,                        [{"localhost", 9092}]},
              {send_method,                   async},
              {formatter,                     lager_default_formatter},
              {formatter_config,
                [date, " ", time, "|", node, "|",severity,"|", module, "|", function, "|", line, "|", pid, "|", message]
              }     
           ]}]
  }
]
阅读全文 »

原始使用:

lager:info("handle_call _Request = ~p",[_Request]),

最本质是调用:

lager:do_log(info,
   [
        {application, mongrel}, 
        {module, mongrel},
        {function, handle_call}, 
        {line, 79},
        {pid, pid_to_list(self())}, 
        {node, node()}
        | lager:md()
    ],
   "handle_call _Request= ~p", 
   [_Request], 
   4096, 
   4,
   __Leveldemo_lager_server42, 
   __Tracesdemo_lager_server42, 
   lager_event, 
   __Piddemo_lager_server42
);

do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid)
阅读全文 »

lager_backend_throttle

入口:

init([{sink, Sink}, Hwm, Window])

表:

表lager_config:
{{lager_event,async}, true},

状态:

#state{sink=Sink, hwm=Hwm, window_min=Hwm - Window}
% Sink=lager_event
% Threshold=env(async_threshold)
% Window=env(async_threshold_window)
阅读全文 »

lager_sup

1.ets表:lager_config:

% 初使化时往表里增加2条数据
1.1 Sink
{lager_event, loglevel} => {Int, []}
例:{lager_event,loglevel}, {255,[]}
其中: Int为8位的整形,即下面的and操作
  -define(DEBUG, 128).
  -define(INFO, 64).
  -define(NOTICE, 32).
  -define(WARNING, 16).
  -define(ERROR, 8).
  -define(CRITICAL, 4).
  -define(ALERT, 2).
  -define(EMERGENCY, 1).
  -define(LOG_NONE, 0).

1.2 Handlers
{_global, handlers} => []

2.三个子进程one_for_one:

{lager, {gen_event, start_link, [{local, lager_event}]},
        permanent, 5000, worker, dynamic}
{lager_handler_watcher_sup, {lager_handler_watcher_sup, start_link, []},
        permanent, 5000, supervisor, [lager_handler_watcher_sup]}
//可选,根据env(crash_log)的值
{lager_crash_log, {lager_crash_log, start_link, [File, MaxBytes,
  RotationSize, RotationDate, RotationCount, RotationMod]},
  permanent, 5000, worker, [lager_crash_log]}
阅读全文 »