邵珠庆の日记 生命只有一次,你可以用它来做很多伟大的事情–Make the world a little better and easier


281月/19

使用acme.sh为nginx配置https

发布在 邵珠庆

使用acme.sh一键安装Let's Encrypt提供的免费SSL证书 并为nginx配置https

本文章使用derror.com域名作为示例

安装nginx

正常配置并启动nginx保证http能够正常访问: 配置好root目录, 比如: /home/work/local/www/

安装acme.sh

$ curl https://get.acme.sh | sh

开始生成证书(issue a cert)

$ acme.sh --issue -d derror.com -w /home/work/local/www

成功应该会得到以下消息

[Mon Oct 29 08:12:04 EDT 2018] Your cert is in  /root/.acme.sh/derror.com/mrnil.com.cer
[Mon Oct 29 08:12:04 EDT 2018] Your cert key is in  /root/.acme.sh/derror.com/mrnil.com.key
[Mon Oct 29 08:12:05 EDT 2018] The intermediate CA cert is in  /root/.acme.sh/derror.com/ca.cer
[Mon Oct 29 08:12:05 EDT 2018] And the full chain certs is there:  /root/.acme.sh/derror.com/fullchain.cer

配置自动更新证书

$ acme.sh --install-cert -d derror.com \
--key-file       /home/work/local/cert/derror.com/key.pem  \
--fullchain-file /home/work/local/cert/derror.com/cert.pem \
--reloadcmd     "systemctl restart nginx"
--reloadcmd "systemctl restart nginx" 更新后自动重启nginx激活新证书

生成 dhparan.pem

$ openssl dhparam -out /home/work/local/cert/derror.com/dhparam.pem 2048

nginx配置ssl

www.conf

server {
    listen       80 default_server;
    listen       [::]:80 default_server;
    listen       443 ssl;
    server_name  _;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl on;
    ssl_certificate         /home/work/local/cert/derror.com/cert.pem;
    ssl_certificate_key     /home/work/local/cert/derror.com/key.pem;
    # ssl_dhparam
    ssl_dhparam             /home/work/local/cert/derror.com/dhparam.pem;

    root         /home/work/local/www;
    index index.html index.htm;
    location / {
    }
}

重启nginx即可

$ systemctl restart nginx

验证ssl

https://derror.com

https://ssllabs.com/ssltest/analyze.html?d=derror.com

添加二级域名

上面的操作基本就完成了. 下面我们来尝试再添加一个二级域名lab.derror.com

$ acme.sh --issue -d lab.derror.com -w /home/work/local/www
...
[Wed Nov 21 04:19:14 EST 2018] Your cert is in  /root/.acme.sh/lab.derror.com/lab.derror.com.cer 
[Wed Nov 21 04:19:14 EST 2018] Your cert key is in  /root/.acme.sh/lab.derror.com/lab.derror.com.key 
[Wed Nov 21 04:19:16 EST 2018] The intermediate CA cert is in  /root/.acme.sh/lab.derror.com/ca.cer 
[Wed Nov 21 04:19:16 EST 2018] And the full chain certs is there:  /root/.acme.sh/lab.derror.com/fullchain.cer

$ mkdir -p /home/work/local/cert/lab.derror.com

$ acme.sh --install-cert -d lab.derror.com \
--key-file       /home/work/local/cert/lab.derror.com/key.pem  \
--fullchain-file /home/work/local/cert/lab.derror.com/cert.pem \
--reloadcmd     "systemctl restart nginx"

[Wed Nov 21 04:21:57 EST 2018] Installing key to:/home/work/local/cert/lab.derror.com/key.pem
[Wed Nov 21 04:21:57 EST 2018] Installing full chain to:/home/work/local/cert/lab.derror.com/cert.pem
[Wed Nov 21 04:21:57 EST 2018] Run reload cmd: systemctl restart nginx
[Wed Nov 21 04:22:04 EST 2018] Reload success

$ openssl dhparam -out /home/work/local/cert/lab.derror.com/dhparam.pem 2048

nginx配置: lab.conf

server {
    listen       80;
    listen       443 ssl;
    server_name  lab.derror.com;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_certificate         /home/work/local/cert/lab.derror.com/cert.pem;
    ssl_certificate_key     /home/work/local/cert/lab.derror.com/key.pem;
    # ssl_dhparam
    ssl_dhparam             /home/work/local/cert/lab.derror.com/dhparam.pem;

    root         /home/work/local/www;
    index index.html index.htm;
    location / {
    }
}
$ systemctl restart nginx
211月/19

常用邮箱的 IMAP/POP3/SMTP 设置

发布在 邵珠庆

POP3

POP3是Post Office Protocol 3的简称,即邮局协议的第3个版本,它规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电子协议。
它是因特网电子邮件的第一个离线协议标准,POP3允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,
同时删除保存在邮件服务器上的邮件,而POP3服务器则是遵循 POP3协议的接收邮件服务器,用来接收电子邮件的。

POP3是Post Office Protocol 3的简称,即邮局协议的第3个版本,是TCP/IP协议族中的一员(默认端口是110)。

本协议主要用于支持使用客户端远程管理在服务器上的电子邮件。

POP与POP3

POP协议支持“离线”邮件存储转发处理:客户端程序连接服务器,下载所有未阅读的电子邮件;一旦将邮件从邮件服务器端送到客户端上,邮件服务器上的邮件将会被删除。

目前的POP3邮件服务器大都可以“只下载邮件,服务器端并不删除”,也就是改进的POP协议。

POP3协议允许电子邮件客户端下载服务器上的邮件,但是在客户端的操作(如移动邮件、标记已读等),不会反馈到服务器上,

比如通过客户端收取了邮箱中的3封邮件并移动到其他文件夹,邮箱服务器上的这些邮件是没有同时被移动的 。

IMAP

IMAP全称是Internet Mail Access Protocol,即交互式邮件访问协议,是一个应用层协议(端口是143)。

用来从本地邮件客户端(Outlook Express、Foxmail、Mozilla Thunderbird等)访问远程服务器上的邮件。

IMAP和POP3的区别
IMAP像POP3那样提供了方便的邮件下载服务,让用户能进行离线阅读。IMAP和POP3是邮件访问最为普遍的Internet标准协议。不同的是:

1、IMAP提供Webmail 与电子邮件客户端之间的双向通信,客户端收取的邮件仍然保留在服务器上,同时在客户端上的操作都会反馈到服务器上
(如:删除邮件,标记已读等,服务器上的邮件也会做相应的动作。所以无论从浏览器登录邮箱或者客户端软件登录邮箱,
看到的邮件以及状态都是一致的。)。而POP3在客户端的操作不会反馈到服务器上。
2、IMAP更好地支持了从多个不同设备中随时访问新邮件。
3、IMAP提供的摘要浏览功能可以让你在阅读完所有的邮件到达时间、主题、发件人、大小等信息后才作出是否下载的决定。
4、POP3需要下载未阅读的邮件,IMAP可以不用把所有的邮件全部下载,而是通过客户端直接对服务器上的邮件进行操作。
所有通过IMAP传输的数据都会被加密,从而保证通信的安全性。
5、IMAP 整体上为用户带来更为便捷和可靠的体验。POP3 更易丢失邮件或多次下载相同的邮件。

SMTP

SMTP的全称是“Simple Mail Transfer Protocol”,即简单邮件传输协议(25号端口)。
它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。
SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。

SMTP是一个“推”的协议,它不允许根据需要从远程服务器上“拉”来消息。
SMTP服务器就是遵循SMTP协议的发送邮件服务器,SMTP认证就是要求必须在提供了账户名和密码之后才可以登录 SMTP 服务器,
这就使得那些垃圾邮件的散播者无可乘之机。

SMTP 的全称是“Simple Mail Transfer Protocol”,即简单邮件传输协议。
它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP 协议属于 TCP/IP 协议簇,
它帮助每台计算机在发送或中转信件时找到下一个目的地。SMTP 服务器就是遵循 SMTP 协议的发送邮件服务器。
(SMTP 认证,简单地说就是要求必须在提供了账户名和密码之后才可以登录 SMTP 服务器,这就使得那些垃圾邮件的散播者无可乘之机。
增加 SMTP 认证的目的是为了使用户避免受到垃圾邮件的侵扰。)

Google Gmail

IMAP, SMTP, POP3 得設定值, 整理如下:

IMAP

  • imap.gmail.com
  • Port: 993
  • Use SSL: Yes

SMTP

  • smtp.gmail.com
  • Port for TLS/STARTTLS: 587
  • Port for SSL: 465

POP3

  • pop.gmail.com
  • Port: 995
  • Use SSL: Yes

阿里云邮箱

已经支持POP3收信和SMTP发信功能,默认已开启。阿里云邮箱服务器信息:

 

服务器名称
服务器地址
服务器端口号(非加密)
服务器端口号(SSL加密)
POP3
pop3.aliyun.com
110
995
SMTP
smtp.aliyun.com
25
465
IMAP imap.aliyun.com 143 993

 

腾讯企业邮箱

如何设置IMAP、POP3/SMTP及其SSL加密方式?

如果您的电子邮件客户端支持SSL,可以在设置中选择使用SSL。
通用配置参数:
(我们已经默认都支持这些协议,用户无需自己手动开启这些服务器与端口)
POP3/SMTP协议

接收邮件服务器:pop.exmail.qq.com ,使用SSL,端口号995
发送邮件服务器:smtp.exmail.qq.com ,使用SSL,端口号465
海外用户可使用以下服务器
接收邮件服务器:hwpop.exmail.qq.com ,使用SSL,端口号995
发送邮件服务器:hwsmtp.exmail.qq.com ,使用SSL,端口号465
IMAP协议
接收邮件服务器:imap.exmail.qq.com  ,使用SSL,端口号993
发送邮件服务器:smtp.exmail.qq.com ,使用SSL,端口号465
海外用户可使用以下服务器
接收邮件服务器:hwimap.exmail.qq.com ,使用SSL,端口号993
发送邮件服务器:hwsmtp.exmail.qq.com ,使用SSL,端口号465
账户名:您的企业邮箱账户名,账户名需要填写完整的邮件地址
密码:您的企业邮箱密码
电子邮件地址:您的企业邮箱的完整邮件地址

腾讯QQ邮箱

POP3:pop.qq.com
SMTP:smtp.qq.com
IMAP:imap.qq.com 端口:143

网易163免费邮箱

相关服务器信息:

网易邮箱已经默认开启 POP3/SMTP/IMAP 服务,方便您可以通过电脑客户端软件更好地收发邮件,如果关闭可以通过以下方式开启:

请登录163邮箱,点击页面正上方的“设置”,再点击左侧上“POP3/SMTP/IMAP”,其中“开启SMTP服务”是系统默认勾选开启的。

您可勾选图中另两个选项,点击确定,即可开启成功。不勾选图中两个选项,点击确定,可关闭成功。 

 

IMAP收件服务器地址:imap.163.com       安全类型:SSL     端口号:993

注:1、126邮箱的IMAP服务器地址:imap.126.com ,yeah邮箱的IMAP服务器地址:imap.yeah.net ;

    2、若安全类型选择“无”,则需将端口号修改为 143。

SMTP发件服务器地址:smtp.163.com        安全类型:SSL     端口号:465 / 994

注:1、126邮箱的SMTP服务器地址:smtp.126.com ,yeah邮箱的SMTP服务器地址:smtp.yeah.net;

    2、若安全类型选择“无”,则需将端口号修改为 25。

POP3收件服务器地址:pop.163.com       端口号:110

(注:126邮箱的POP3服务器地址:pop.126.com ,yeah邮箱的POP3服务器地址:pop.yeah.net ,端口号都是:110)

SMTP发件服务器地址:smtp.163.com         端口号:25

(注:126邮箱的SMTP服务器地址:smtp.126.com ,yeah邮箱的SMTP服务器地址:smtp.yeah.net ,端口号都是:25)

263.net:

POP3服务器地址:pop3.263.net
SMTP服务器地址:smtp.263.net

x263.net:

POP3服务器地址:pop.x263.net
SMTP服务器地址:smtp.x263.net

263.net.cn:

POP3服务器地址:pop.263.net.cn
SMTP服务器地址:smtp.263.net.cn

21cn.com:

POP3服务器地址:pop.21cn.com
SMTP服务器地址:smtp.21cn.com

sina.com:

POP3服务器地址:pop3.sina.com.cn
SMTP服务器地址:smtp.sina.com.cn

tom.com:

POP3服务器地址:pop.tom.com
SMTP服务器地址:smtp.tom.com

elong.com:

POP3服务器地址:pop3.elong.com
SMTP服务器地址:smtp.elong.com

china.com:

POP3服务器地址:pop.china.com
SMTP服务器地址:smtp.china.com

sohu.com:

POP3服务器地址:pop3.sohu.com
SMTP服务器地址:smtp.sohu.com

etang.com:

POP3服务器地址:pop.etang.com
SMTP服务器地址:smtp.etang.com

yahoo.com:

POP3服务器地址:pop.mail.yahoo.com
SMTP服务器地址:smtp.mail.yahoo.com

yahoo.com.cn:

POP3服务器地址:pop.mail.yahoo.com.cn
SMTP服务器地址:smtp.mail.yahoo.com.cn

 

 

移动139邮箱 POP3:pop.139.com SMTP:smtp.139.com
  天翼189邮箱 POP3:pop.189.cn SMTP:smtp.189.cn
  163邮箱 POP3:pop.163.com SMTP:smtp.163.com
  163Vip邮箱 POP3:pop.vip.163.com SMTP:smtp.vip.163.com
  126邮箱 POP3:pop3.126.com SMTP:smtp.126.com
  Gmail POP3:pop.gmail.com SMTP:smtp.gmail.com IMAP:imap.gmail.com 端口:995 465 993
  Yahoo邮箱 POP3:pop.mail.yahoo.com SMTP:smtp.mail.yahoo.com
  Hotmail POP3:pop3.live.com SMTP:smtp.live.com 端口:995
  Sogou邮箱 POP3:pop3.mail.sogou.com SMTP:smtp.mail.sogou.com
邮箱Foxmial ,Outlook等客户端设置

网易邮箱 POP3 和 SMTP 服务器地址设置如下:

邮箱 POP3 服务器(端口110) SMTP 服务器(端口25)

@163.com、 pop3.163.com、 smtp.163.com

@126.com 、pop3.126.com 、smtp.126.com

@netease.com、 pop.netease.com、 smtp.netease.com

@yeah.net 、pop.yeah.net 、smtp.yeah.net

所有的SMTP服务器都需要身份验证。

Sina免费邮件服务器设置

收信(pop3)服务器:pop3.sina.com.cn

发信(smtp)服务器:smtp.sina.com.cn

请选择smtp服务器要求身份验证选项

Yahoo中国免费邮件服务器设置:

接收邮件(POP3)服务器:pop.mail.yahoo.com.cn

发送邮件(SMTP)服务器:smtp.mail.yahoo.com.cn

Yahoo免费邮件服务器设置:(把你的资料填成国外的)

接收邮件(POP3)服务器:pop.mail.yahoo.com

发送邮件(SMTP)服务器:smtp.mail.yahoo.com

Gmail客户端:

POP服务器:pop.gmail.com

打开ssl端口995(注意,pop得默认端口是110,在这里要改成995)

SMTP服务器:smtp.gmail.com

smtp服务器需要身份验证

开启ssl端口465或587

帐户名:你得gmail用户名(包括 ‘@gmail.com‘这部分)

Email地址:你得完整得gmail地址(username@gmail.com)

密码:你得gmail密码

中华网

pop.china.com

smtp.china.com

搜狐

pop.sohu.com

smtp.sohu.com

163电子邮局

163.net

smtp.163.net

263电子邮局

263.net

smtp.263.net

QQ邮箱不提供POP3服务

Hotmail邮箱不提供POP3和SMTP服务

163.net收费邮箱

popx.163vip.net

smtp.163vip.net

常用邮箱POP3和SMTP服务器设置

【网易 163、126免费邮箱目前不直接开放smtp、pop3服务。有需要的用户可通过购买随身邮或邮箱伴侣及加入会员中心获得。从2006年11月16日起新注册用户,将无法使用POP客户端功能,之前注册用户不受影响。】

 

网易163邮箱

POP3:pop.163.com

SMTP:smtp.163.com

SMTP端口号:25

 

网易vip.163邮箱

POP3:pop.vip.163.com

SMTP:smtp.vip.163.com

SMTP端口号:25

 

网易126邮箱

POP3:pop.126.com

SMTP:smtp.126.com

SMTP端口号:25

 

网易188邮箱

POP3:pop.188.com

SMTP:smtp.188.com

SMTP端口号:25

 

网易yeah.net邮箱

POP3:pop.yeah.net

SMTP:smtp.yeah.net

SMTP端口号:25

 

网易netease.com邮箱

POP3:pop.netease.com

SMTP:smtp.netease.com

SMTP端口号:25

 

【新浪 需登陆web邮箱,设置-账户,开通smtp/pop服务,如是VIP,请务必勾选“smtp服务器要求身份验证”一项】

 

新浪免费邮箱

POP3:pop.sina.com

SMTP:smtp.sina.com

SMTP端口号:25

 

新浪VIP邮箱

POP3:pop3.vip.sina.com

SMTP:smtp.vip.sina.com

SMTP端口号:25

 

新浪企业邮箱

POP3:pop.sina.com

SMTP:smtp.sina.com

SMTP端口号:25

 

【yahoo在foxmail 4.1以上的版本设置如下:( outlook 不行)需订制“来电提醒”服务,不定制此项服务,将无法使用POP服务。】

 

雅虎邮箱

POP3:pop.mail.yahoo.cn

SMTP:smtp.mail.yahoo.cn

SMTP端口号:25

 

【搜狐 TOM 规则较多,容易被封账号】

 

搜狐邮箱

POP3:pop3.sohu.com

SMTP:smtp.sohu.com

SMTP端口号:25

 

TOM邮箱

POP3:pop.tom.com

SMTP:smtp.tom.com

SMTP端口号:25

 

【谷歌 需要勾选启用SSL,465端口好像服务器端被封掉了】

 

Gmail邮箱

POP3:pop.gmail.com

SMTP:smtp.gmail.com

SMTP端口号:587 或 25

 

【需登陆web邮箱,设置-帐户,开通smtp/pop服务;设置完成后,请务必勾选“smtp服务器要求身份验证”一项。
邮箱开通15天后才可开通smtp服务。】

 

QQ邮箱

POP3:pop.qq.com

SMTP:smtp.qq.com

SMTP端口号:25

 

 

263邮箱

域名:263.net

POP3:263.net

SMTP:smtp.263.net

SMTP端口号:25

 

域名:x263.net

POP3:pop.x263.net

SMTP:smtp.x263.net

SMTP端口号:25

 

域名:263.net.cn

POP3:263.net.cn

SMTP:263.net.cn

SMTP端口号:25

 

域名:炫我型

POP3:pop.263xmail.com

SMTP:smtp.263xmail.com

SMTP端口号:25

 

21CN  免费邮箱

POP3:pop.21cn.com

SMTP:smtp.21cn.com

IMAP:imap.21cn.com

SMTP端口号:25

 

21CN  经济邮邮箱

POP3:pop.21cn.com

SMTP:smtp.21cn.com

SMTP端口号:25

 

21CN  商务邮邮箱

POP3:pop.21cn.net

SMTP:smtp.21cn.net

SMTP端口号:25

 

21CN  快感邮箱

POP3:vip.21cn.com

SMTP:vip.21cn.com

SMTP端口号:25

 

21CN  Y邮箱

POP3:pop.y.vip.21cn.com

SMTP:smtp.y.vip.21cn.com

SMTP端口号:25

 

中华网任我邮邮箱

POP3:rwpop.china.com

SMTP:rwsmtp.china.com

SMTP端口号:25

 

中华网时尚、商务邮箱

POP3:pop.china.com

SMTP:smtp.china.com

SMTP端口号:25

各种常用邮箱POP3/SMTP/IMAP

1.gmail

gmail 服务器地址 非SSL SSL
IMAP imap.gmail.com  - 993
POP pop.gmail.com  - 995
SMTP ssl://smtp.gmail.com  - 465

 

2.139邮箱

139邮箱 服务器地址 非SSL SSL
IMAP imap.10086.cn 143 -
POP pop.10086.cn 110 995
SMTP smtp.10086.cn 25 465

 

3.163邮箱

163邮箱 服务器地址 非SSL SSL
IMAP imap.163.com 143 993
POP pop.163.com 110 995
SMTP smtp.163.com 25 465/994

 

 

4.qq邮箱

qq邮箱 服务器地址 非SSL SSL
IMAP imap.qq.com 143 993
POP pop.qq.com 110 995
SMTP smtp.qq.com 25 465/587

 

5.sina邮箱

sina邮箱 服务器地址 非SSL SSL
IMAP imap.sina.com 143 993
POP pop.sina.com 110 -
SMTP smtp.sina.com 25 -

 

 

@sina.com
POP3服务器地址:pop3.sina.com.cn
SMTP服务器地址:smtp.sina.com.cn

@sohu.com
POP3服务器地址:pop3.sohu.com
SMTP服务器地址:smtp.sohu.com

@yeah.net
POP3服务器地址:pop3.yeah.net
SMTP服务器地址:smtp.yeah.net

@126.com
POP3服务器地址:pop3.126.com
SMTP服务器地址:smtp.126.com

@163.com
POP3服务器地址:pop.163.com
SMTP服务器地址:smtp.163.com

@tom.com
POP3服务器地址:pop.tom.com
SMTP服务器地址:smtp.tom.com

@263.net
POP3服务器地址:pop.263.net
SMTP服务器地址:smtp.263.net

@21cn.com
POP3服务器地址:pop.21cn.com
SMTP服务器地址:smtp.21cn.com
SMTP服务器地址:imap.21cn.com

@yeahoo.com.cn
POP3服务器地址:pop.mail.yahoo.com.cn
SMTP服务器地址:smtp.mail.yahoo.com.cn

@eyou.com
POP3服务器地址:pop3.eyou.com
SMTP服务器地址:mx.eyou.com

以上所有smtp服务器都要求身份验证
@Gmail

POP3服务器地址: pop.gmail.com

端口:995

支持SSL

SMTP服务器地址: smtp.gmail.com

端口:465

支持SSL(TSL)

邮箱名称
POP地址 SMTP地址 IMAP地址 POP端口 SMTP端口 IMAP端口
 188 邮箱
pop.188.com smtp.188.com imap.188.com 110/995 465/994/25 143/993
  163 邮箱
pop.163.com smtp.163.com imap.163.com 110/995 465/994/25 143/993
  126 邮箱
pop.126.com smtp.126.com imap.126.com 110 25 143
  netease 邮箱
pop.netease.com smtp.netease.com imap.netease.com 110/995 465/587/25 143/993
  yeah 邮箱
pop.yeah.net smtp.yeah.net imap.yeah.net 110/995 465/587/25 143/993
  QQ  邮箱
pop.qq.com smtp.qq.com imap.qq.com 110/995 465/587/25 143/993
  Gmail  邮箱
pop.gmail.com smtp.gmail.com imap.gmail.com 110/995 465/25 993
  Sina  邮箱
pop.sina.com.cn smtp.sina.com.cn imap.sina.com.cn 110 25 993
  sohu  邮箱
pop3.sohu.com smtp.sohu.com imap.sohu.com 110 25 993
  TOM  邮箱
pop3.tom.com smtp.tom.com imap.tom.com 110 25 993

 

  • 163邮箱支持IMAP和POP两种协议,账户名为包含@的网站邮件地址

类型

服务器名称

服务器地址

SSL协议端口号

非SSL协议端口号

备注

收件服务器

POP

pop.163.com

995

110

收件服务器

IMAP

imap.163.com

993

143

发件服务器

SMTP

smtp.163.com

465/994

25

需要身份验证

  • QQ邮箱支持IMAP和POP两种协议以及EXCHANGE同步服务,需要再QQ邮箱的WEB版实验室选项里开通账户名为QQ邮箱账户名(@前的部分,如果您是VIP帐号或Foxmail帐号,账户名需要填写完整的邮件地址)

类型

服务器名称

服务器地址

SSL协议端口号

非SSL协议端口号

备注

收件服务器

POP

pop.qq.com

995

110

收件服务器

IMAP

imap.qq.com

993

143

发件服务器

SMTP

smtp.qq.com

465/587

25

需要身份验证

EXCHANGE同步

exchange

ex.qq.com

用户名为完整EMAIL地址

  • gmail邮箱支持IMAP和POP两种协议以及EXCHANGE同步服务,需要再网页邮箱的设置中先开通。账户名为包含@的网站邮件地址

类型

服务器名称

服务器地址

SSL协议端口号

非SSL协议端口号

备注

收件服务器

POP

pop.gmail.com

995

N/A

收件服务器

IMAP

imap.gmail.com

993

N/A

发件服务器

SMTP

smtp.gmail.com

465/587

25

要求TLS,需要身份验证

EXCHANGE同步

exchange

m.google.com

用户名为完整EMAIL地址

  • 阿里巴巴内网云邮箱支持IMAP和POP3两种协议以及EXCHANGE同步服务,账户名为包含@的网站邮件地址,更多信息,参考http://alimail.alibaba-inc.com/help/

类型

服务器名称

服务器地址

SSL协议端口号

非SSL协议端口号

备注

收件服务器

POP

pop3.alibaba-inc.com

995

N/A

 SSL

收件服务器

IMAP

imap.alibaba-inc.com

993

N/A

 SSL

发件服务器

SMTP

smtp.alibaba-inc.com

465

N/A

要求SSL,需要身份验证

EXCHANGE同步

exchange

ex.alibaba-inc.com

用户名为完整EMAIL地址

LDAP通讯簿服务器

LDAP

ldap.alibaba-inc.com

636

N/A

用户名为完整EMAIL地址

日历服务器

caldav

caldav.alibaba-inc.com

443

 N/A

用户名为完整EMAIL地址

 

1412月/18

CentOS 使用 Google Authenticator 登录验证

发布在 邵珠庆

Google Authentication 项目 包含了多个手机平台的一次性验证码生成器的实现,以及一个可插拔的验证认证模块(PAM)。这些实现支持基于 HMAC 的一次性验证码(HOTP)算法(RFC 4226)和基于时间的一次性验证码(TOTP)算法(RFC 6238)。

下面将在 CentOS 上安装并使用 Google Authenticator 做登录的身份验证,当前系统的版本为

CentOS Linux release 7.2.1511 (Core)

安装 Google Authenticator PAM module

  • 确保 ntpd 已安装并正常运行运行

    yum install -y ntpdate
    systemctl start ntpd
    systemctl enable ntpd
    

    ntpdate 是用来自动同步时间的程序,这里启动它并设置它开机自动启动。

  • 安装一些接下去会用到的组件

    yum install -y git make gcc libtool pam-devel
    
  • 编译安装 Google Authenticator PAM module

    git clone https://github.com/google/google-authenticator
    cd google-authenticator/libpam
    ./bootstrap.sh
    ./configure
    make
    make install
    ln -s /usr/local/lib/security/pam_google_authenticator.so /usr/lib64/security/
    

配置 SSH 服务

打开 /etc/ssh/sshd_config 文件

vim /etc/ssh/sshd_config

修改下面字段的配置

ChallengeResponseAuthentication yes
PasswordAuthentication no
PubkeyAuthentication yes
UsePAM yes

然后重启一下 sshd 服务,使配置生效

systemctl restart sshd

这里将 PubkeyAuthentication 配置成了 yes 表示支持公钥验证登录,即使某个账号启用了 Google Authenticator 验证,只要登录者机器的公钥在这个账号的授权下,就可以不输入密码和 Google Authenticator 的认证码直接登录。

配置 PAM

打开 /etc/pam.d/sshd 文件

vim /etc/pam.d/sshd

这里分四种情况来配置

  • 验证密码和认证码,没有启用 Google Authenticator 服务的账号只验证密码(推荐)

    auth substack password-auth
    #...
    auth required pam_google_authenticator.so nullok
    

    password-auth 与 pam_google_authenticator 的先后顺序决定了先输入密码还是先输入认证码。

  • 验证密码和认证码,没有启用 Google Authenticator 服务的账号无法使用密码登录

    auth substack password-auth
    #...
    auth required pam_google_authenticator.so
    
  • 只验证认证码,不验证密码,没有启用 Google Authenticator 服务的账号不用输入密码直接可以成功登录

    #auth substack password-auth
    #...
    auth required pam_google_authenticator.so nullok
    

    注释掉 auth substack password-auth 配置就不会再验证账号密码了。

  • 只验证认证码,不验证密码,没有启用 Google Authenticator 服务的账号无法使用密码登录

    #auth substack password-auth
    #...
    auth required pam_google_authenticator.so
    

启用 Google Authenticator

切换至想要使用 Google Authenticator 来做登录验证的账号,执行下面操作

google-authenticator

然后会出现下面一系列交互式的对话做对应的设置

Do you want authentication tokens to be time-based (y/n) y
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/shenyu@shenyu.me%3Fsecret%3DKHMH46EWI2RIRZ53KQTNGHXNP4%26issuer%3Dshenyu.me
# 这里是个二维码
Your new secret key is: KHMH46EWI2RIRZ53KQTNGHXNP4
Your verification code is 753579
Your emergency scratch codes are:
  99181037
  68865807
  88385439
  59103432
  81045035

这里会显示一个二维码,如果你的终端终端不支持显示二维码,可以手动打开这个网页链接(墙)来查看二维码或者手动输入后面的密钥(secret key)来代替扫描二维码,之后的操作会用到这个二维码/密钥(secret key)。这里还有一个认证码(verifiction code),暂时不知道有什么用,以及 5 个紧急救助码(emergency scratch code),紧急救助码就是当你无法获取认证码时(比如手机丢了),可以当做认证码来用,每用一个少一个,但其实可以手动添加的,建议如果 root 账户使用 Google Authenticator 的话一定要把紧急救助码另外保存一份。

Do you want me to update your "/home/test/.google_authenticator" file? (y/n) y

是否更新用户的 Google Authenticator 配置文件,选择 y 才能使上面操作对当前用户生效,其实就是在对应用户的 Home 目录下生成了一个 .google_authenticator 文件,如果你想停用这个用户的 Google Authenticator 验证,只需要删除这个用户 Home 目录下的 .google_authenticator 文件就可以了。

Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y

每次生成的认证码是否同时只允许一个人使用?这里选择 y

By default, tokens are good for 30 seconds. In order to compensate for
possible time-skew between the client and the server, we allow an extra
token before and after the current time. If you experience problems with
poor time synchronization, you can increase the window from its default
size of  -1min (window size of 3) to about  -4min (window size of
17 acceptable tokens).
Do you want to do so? (y/n) n

是否增加时间误差?这里选择 n

If the computer that you are logging into isn\'t hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting (y/n) y

是否启用次数限制?这里选择 y,默认每 30 秒最多尝试登录 3 次。

上面交互式的设置也可用通过参数一次性设置(推荐)

google-authenticator -t -f -d -l shenyu@shenyu.me -i SHENYU.ME -r 3 -R 30 -W

可以看到,通过参数还可以自定义 发行商 和 标签,执行 google-authenticator -h 来查看所有的参数设置

google-authenticator []
 -h, --help               Print this message
 -c, --counter-based      Set up counter-based (HOTP) verification
 -t, --time-based         Set up time-based (TOTP) verification
 -d, --disallow-reuse     Disallow reuse of previously used TOTP tokens
 -D, --allow-reuse        Allow reuse of previously used TOTP tokens
 -f, --force              Write file without first confirming with user
 -l, --label=

设置 Google Authenticator 手机 App

在手机上下载并安装 Google Authenticator

手机类型 App 程序名称
IOS Google Authenticator
Android 谷歌动态口令(请在手机对应的应用商店里搜索下载)

安装完后,打开 Google Authenticator/谷歌动态口令 App,点击 开始设置,选择 扫描条形码 扫描上面 google-authenticator 命令生成的二维码,然后手机上就能看到对应的认证码了。

自动草稿

这里的认证码每 30 秒变化一次,认证码上面的 SHENYU.ME 对应的是 google-authenticator 参数 -i 设置的发行商,认证码下面的 shenyu@shenyu.me 对应的是 google-authenticator 参数 -l设置的标签,如果你没有通过 google-authenticator 的参数设置发行商和标签,默认会使用系统的 hostname 来作为发行商,标签则则使用用户名和 hostname 的组合,格式为 username@hostname,标签其实是后期可以通过手机App来修改的,而发行商则修改不了。

现在重新使用 SSH 登录服务器,就会要求输入密码和 Verification code 来验证身份。如果登陆时遇到问题,请查看日志文件 /var/log/secure

参考资料

512月/18

使用树莓派创建WIFI热点

发布在 邵珠庆

http://www.cybersecurityguy.com/Building_a_Raspberry_Pi_Captive_Portal_Wi-Fi_Hotspot.pdf

Have you ever needed to create a second Wi-Fi network in addition to your primary network? If you (or someone close to you) have a business (coffee, restaurant, hairdresser or doctor, in short, a place where people are likely to wait), it is likely that you have already had to provide internet access to your Customers, without wanting to give the password of your box. In the same way, you may have already wanted to create an internal network that is cut off from the Internet, for example to exchange files within a small company, and so on.

For all these situations, the simplest solution is to create what is called a hotspot, that is to say a kind of box that you can control and to which your users can connect to access the internet. In this tutorial, let’s see how we can use a raspberry pi to create our own homemade hotspot, in less than 10 minutes!

The hardware needed to create your hotspot

In order to create our own hotspot, we will need a little bit of hardware, but nothing complicated or too expensive, you will be able to get around for about 50 € to 60 €, and you can use all the equipment for other uses in parallel.

To achieve our hotspot, we will need the following:

As you can see, all these components are just the ones needed to operate a raspberry pi, and you will be able to use the raspberry pi in question for other things in parallel to its role as a hotspot.

Moreover, by tweaking a bit in the configurations, and if you add a second Wi-Fi interface on your raspberry pi, you can also transform your hotspot into a Wi-Fi repeater, in order to increase the range of your box!

Install hostapd and its interface to turn your raspberry pi into a Wi-Fi hotspot

Now that we have all the hardware we need, we will be able to switch to installing the various software needed to transform our raspberry pi to Wi-Fi.

The first step will be to install Raspbian (the lite version, preferably) on your raspberry pi. To do this, we will let you consult our tutorial explaining how to install Raspbian on raspberry pi from Windows, or from Linux.

Once you have installed Raspbian, the first thing to do is to plug your raspberry pi to your internet router using the Ethernet cable and then take control of your raspberry, either directly with a keyboard / screen, or through SSH , as explained in this tutorial.

Once done, we will make sure that the Wi-Fi connection of the raspberry remains available for the creation of the hotspot. For this purpose, we will simply create a copy of the configuration file allowing the connection to a box, in order to keep it aside, and modify the main file.
To do this, go to the terminal of the raspberry pi and run the following commands:

sudo cp /etc/wpa_supplicant/wpa_supplicant.conf /etc/wpa_supplicant/wpa_supplicant.conf.sav
sudo cp /dev/null/etc/wpa_supplicant/wpa_supplicant.conf

Finally, edit in the file /etc/wpa_supplicant/wpa_supplicant.conf and add the following lines:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

Now that we are sure that the Wi-Fi interface is available, all we have to do now is install the various software to make the raspberry pi an access point.

In this tutorial, we will use the hostapd software, which will allow us to turn the raspberry pi into an access point. And to facilitate the installation and administration of this access point, we will also install a web interface that will allow us to control our hotspot, RaspAP (for more info, go to the Github page of the software, https://github.com/billz/raspap-webgui).

Capture d'écran de l'interface RaspAP

With RaspAP, you can manage your Wi-Fi hotspot with a web interface.

And the good news is that to do all this we will need to run only one command:

wget -q https://git.io/voEUQ -O /tmp/raspap && bash /tmp/raspap

Once the command is launched, you only have to answer the few questions that will be asked, and the installation of all the components will be done by itself.

Connect to your Wi-Fi hotspot

When the installation is complete, your raspberry pi restarts, and you should see a “raspi-webgui” network in the list of accessible networks.

If, however, the network does not appear, find the IP of the raspberry pi, and connect to it via your web browser. You should arrive on the hotspot administration interface, the default password is shown on the github page of the software. Once connected, go to the “Configure Hotspot” section, and change the “Wireless Mode” field, this should solve the problem.

Once the network is visible, all you have to do is connect to it, the default password is ChangeMe.
You can change this password, network name, and many other things by connecting to the admin interface of your raspberry hotspot via your web browser, by default the address should be 10.3.141.1.

And if it still does not work?

For some time, we do not know why, but it seems that Internet access is no longer functional by default after installation. To solve this problem you only need to do the following two things.

As a first step, enable the transfer of IPv4 packets. To do this, edit the file /etc/sysctl.confand uncomment (ie remove it #at the beginning) the following line:

#net.ipv4.ip_forward=1

This done, we will modify iptables to define the output IP that will be indicated so that the servers know who to answer (well, from what I understand, if I’m wrong rectifications are welcome ). To do this, open the file /etc/rc.localand add the following line before the “exit 0” part:

iptables -t nat -A POSTROUTING -j MASQUERADE

Restart the pi and everything should now work as it should!

All you have to do is configure your hotspot to suit your needs!

We hope that this tutorial will have helped you, do not hesitate to consult our other tutorials, such as the one on the creation of a retro-gaming console with the Raspberry Pi, and if you need help, do not hesitate to ask for on the comments !

1211月/18

时序图简单示例-PlantUML

发布在 邵珠庆

简单示例

你可以用->来绘制参与者之间传递的消息, 而不必显式地声明参与者。

你也可以使用 --> 绘制一个虚线箭头。

另外,你还能用 <- 和 <--,这不影响绘图,但可以提高可读性。 注意:仅适用于时序图,对于其它示意图,规则是不同的。

@startuml
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response

Alice -> Bob: Another authentication Request
Alice
自动草稿

声明参与者

关键字 participant 用于改变参与者的先后顺序。

你也可以使用其它关键字来声明参与者:

  • actor
  • boundary
  • control
  • entity
  • database

@startuml
actor Foo1
boundary Foo2
control Foo3
entity Foo4
database Foo5
collections Foo6
Foo1 -> Foo2 : To boundary
Foo1 -> Foo3 : To control
Foo1 -> Foo4 : To entity
Foo1 -> Foo5 : To database
Foo1 -> Foo6 : To collections

@enduml
自动草稿

关键字 as 用于重命名参与者

你可以使用RGB值或者颜色名修改 actor 或参与者的背景颜色。

@startuml
actor Bob #red
\\' The only difference between actor
\\'and participant is the drawing
participant Alice
participant "I have a really\nlong name" as L #99FF99
/\\' You can also declare:
   participant L as "I have a really\nlong name"  #99FF99
  \\'/

Alice->Bob: Authentication Request
Bob->Alice: Authentication Response
Bob->L: Log transaction
@enduml
自动草稿

You can use the orderkeyword to custom the print order of participant.

@startuml
participant Last order 30
participant Middle order 20
participant First order 10
@enduml
自动草稿

在参与者中使用非字母符号

你可以使用引号定义参与者,还可以用关键字 as 给参与者定义别名。

@startuml
Alice -> "Bob()" : Hello
"Bob()" -> "This is very\nlong" as Long
\\' You can also declare:
\\' "Bob()" -> Long as "This is very\nlong"
Long --> "Bob()" : ok
@enduml
自动草稿

给自己发消息

参与者可以给自己发信息,

消息文字可以用\n来换行。

@startuml
Alice->Alice: This is a signal to self.\nIt also demonstrates\nmultiline \ntext
@enduml
自动草稿

修改箭头样式

修改箭头样式的方式有以下几种:

  • 表示一条丢失的消息:末尾加 x
  • 让箭头只有上半部分或者下半部分:将<>替换成\或者 /
  • 细箭头:将箭头标记写两次 (如 >> 或 //)
  • 虚线箭头:用 -- 替代 -
  • 箭头末尾加圈:->o
  • 双向箭头:

@startuml
Bob ->x Alice
Bob -> Alice
Bob ->> Alice
Bob -\ Alice
Bob \\- Alice
Bob //-- Alice

Bob ->o Alice
Bob o\\-- Alice

Bob  Alice
Bob o Alice
@enduml
自动草稿

修改箭头颜色

你可以用以下记号修改箭头的颜色:

@startuml
Bob -[#red]> Alice : hello
Alice -[#0000FF]->Bob : ok
@enduml
自动草稿

对消息序列编号

关键字 autonumber 用于自动对消息编号。

@startuml
autonumber
Bob -> Alice : Authentication Request
Bob
自动草稿

语句 \\'\\'autonumber \\'start\\' 用于指定编号的初始值,而 autonumber \\'start\\' \\'increment\\'\\'\\' 可以同时指定编号的初始值和每次增加的值。

@startuml
autonumber
Bob -> Alice : Authentication Request
Bob  Alice : Another authentication Request
Bob  Alice : Yet another authentication Request
Bob
自动草稿

你可以在双引号内指定编号的格式。

格式是由 Java 的DecimalFormat类实现的: (\\'0\\' 表示数字;\\'\#\\' 也表示数字,但默认为0)。

你也可以用 HTML 标签来制定格式。

@startuml
autonumber "[000]"
Bob -> Alice : Authentication Request
Bob  Alice : Another authentication Request
Bob  Alice : Yet another authentication Request
Bob 
自动草稿

你还可以用语句 autonumber stop 和 \\'\\'autonumber resume \\'increment\\' \\'format\\'\\'\\' 来表示暂停或继续使用自动编号。

@startuml
autonumber 10 10 "[000]"
Bob -> Alice : Authentication Request
Bob  Alice : dummy

autonumber resume "Message 0  "
Bob -> Alice : Yet another authentication Request
Bob  Alice : dummy

autonumber resume 1 "Message 0  "
Bob -> Alice : Yet another authentication Request
Bob 
自动草稿

分割示意图

关键字 newpage 用于把一张图分割成多张。

在 newpage 之后添加文字,作为新的示意图的标题。

这样就能很方便地在 Word 中将长图分几页打印。

@startuml

Alice -> Bob : message 1
Alice -> Bob : message 2

newpage

Alice -> Bob : message 3
Alice -> Bob : message 4

newpage A title for the\nlast page

Alice -> Bob : message 5
Alice -> Bob : message 6
@enduml
自动草稿

组合消息

我们可以通过以下关键词将组合消息:

  • alt/else
  • opt
  • loop
  • par
  • break
  • critical
  • group, 后面紧跟着消息内容

可以在标头(header)添加需要显示的文字(group除外)。

关键词 end 用来结束分组。

注意,分组可以嵌套使用。

@startuml
Alice -> Bob: Authentication Request

alt successful case

	Bob -> Alice: Authentication Accepted
	
else some kind of failure

	Bob -> Alice: Authentication Failure
	group My own label
		Alice -> Log : Log attack start
	    loop 1000 times
	        Alice -> Bob: DNS Attack
	    end
		Alice -> Log : Log attack end
	end
	
else Another type of failure

   Bob -> Alice: Please repeat
   
end
@enduml
自动草稿

给消息添加注释

我们可以通过在消息后面添加 note left 或者 note right 关键词来给消息添加注释。

你也可以通过使用 end note 来添加多行注释。

@startuml
Alice->Bob : hello
note left: this is a first note

Bob->Alice : ok
note right: this is another note

Bob->Bob : I am thinking
note left
	a note
	can also be defined
	on several lines
end note
@enduml
自动草稿

其他的注释

可以使用note left ofnote right ofnote over在节点(participant)的相对位置放置注释。

还可以通过修改背景色来高亮显示注释。

以及使用关键字end note来添加多行注释。

@startuml
participant Alice
participant Bob
note left of Alice #aqua
	This is displayed 
	left of Alice. 
end note
 
note right of Alice: This is displayed right of Alice.

note over Alice: This is displayed over Alice.

note over Alice, Bob #FFAAAA: This is displayed\n over Bob and Alice.

note over Bob, Alice
	This is yet another
	example of
	a long note.
end note
@enduml
自动草稿

改变备注框的形状

你可以使用 hnote 和 rnote 这两个关键字来修改备注框的形状。

@startuml
caller -> server : conReq
hnote over caller : idle
caller
自动草稿

Creole和HTML

可以使用creole格式。

@startuml
participant Alice
participant "The **Famous** Bob" as Bob

Alice -> Bob : hello --there--
... Some ~~long delay~~ ...
Bob -> Alice : ok
note left
  This is **bold**
  This is //italics//
  This is ""monospaced""
  This is --stroked--
  This is __underlined__
  This is ~~waved~~
end note

Alice -> Bob : A //well formatted// message
note right of Alice 
 This is displayed 
 __left of__ Alice. 
end note
note left of Bob 
 This is displayed 
 **left of Alice Bob**. 
end note
note over Alice, Bob
 <w:#FF33FF>This is hosted by 
end note 
@enduml
自动草稿

分隔符

你可以通过使用 == 关键词来将你的图表分割多个步骤。

@startuml

== Initialization ==

Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response

== Repetition ==

Alice -> Bob: Another authentication Request
Alice
自动草稿

引用

你可以在图中通过使用ref over关键词来实现引用

@startuml
participant Alice
actor Bob

ref over Alice, Bob : init

Alice -> Bob : hello

ref over Bob
  This can be on
  several lines
end ref
@enduml
自动草稿

延迟

你可以使用...来表示延迟,并且还可以给延迟添加注释。

@startuml

Alice -> Bob: Authentication Request
...
Bob --> Alice: Authentication Response
...5 minutes latter...
Bob --> Alice: Bye !

@enduml
自动草稿

空间

你可以使用|||来增加空间。

还可以使用数字指定增加的像素的数量。

@startuml

Alice -> Bob: message 1
Bob --> Alice: ok
|||
Alice -> Bob: message 2
Bob --> Alice: ok
||45||
Alice -> Bob: message 3
Bob --> Alice: ok

@enduml
自动草稿

生命线的激活与撤销

关键字activatedeactivate用来表示参与者的生命活动。

一旦参与者被激活,它的生命线就会显示出来。

activatedeactivate适用于以上情形。

destroy表示一个参与者的生命线的终结。

@startuml
participant User

User -> A: DoWork
activate A

A -> B: << createRequest >>
activate B

B -> C: DoWork
activate C
C --> B: WorkDone
destroy C

B --> A: RequestCreated
deactivate B

A -> User: Done
deactivate A

@enduml
自动草稿

还可以使用嵌套的生命线,并且运行给生命线添加颜色。

@startuml
participant User

User -> A: DoWork
activate A #FFBBBB

A -> A: Internal call
activate A #DarkSalmon

A -> B: << createRequest >>
activate B

B --> A: RequestCreated
deactivate B
deactivate A
A -> User: Done
deactivate A

@enduml
自动草稿

创建参与者

你可以把关键字create放在第一次接收到消息之前,以强调本次消息实际上是在创建新的对象。

@startuml
Bob -> Alice : hello

create Other
Alice -> Other : new

create control String
Alice -> String
note right : You can also put notes!

Alice --> Bob : ok

@enduml
自动草稿

进入和发出消息

如果只想关注部分图示,你可以使用进入和发出箭头。

使用方括号[]表示图示的左、右两侧。

@startuml
[-> A: DoWork

activate A

A -> A: Internal call
activate A

A ->] : << createRequest >>

A<--] : RequestCreated
deactivate A
[
自动草稿

还可以使用下面的语法:

@startuml
[-> Bob
[o-> Bob
[o->o Bob
[x-> Bob

[]
Bob ->o]
Bob o->o]
Bob ->x]

Bob <-]
Bob x<-]
@enduml
自动草稿

构造类型和圈点

可以使用<<>>给参与者添加构造类型。

在构造类型中,你可以使用(X,color)格式的语法添加一个圆圈圈起来的字符。

@startuml

participant "Famous Bob" as Bob << Generated >>
participant Alice << (C,#ADD1B2) Testable >>

Bob->Alice: First message

@enduml
自动草稿

默认使用 guillemet 字符来显示构造类型。 你可以使用外观参数 guillemet 来修改显示行为。

@startuml

skinparam guillemet false
participant "Famous Bob" as Bob << Generated >>
participant Alice << (C,#ADD1B2) Testable >>

Bob->Alice: First message

@enduml
自动草稿

@startuml

participant Bob << (C,#ADD1B2) >>
participant Alice << (C,#ADD1B2) >>

Bob->Alice: First message

@enduml
自动草稿

更多标题信息

你可以在标题中使用creole格式。

@startuml

title __Simple__ **communication** example

Alice -> Bob: Authentication Request
Bob -> Alice: Authentication Response

@enduml
自动草稿

在标题描述中使用\n表示换行。

@startuml

title __Simple__ communication example\non several lines

Alice -> Bob: Authentication Request
Bob -> Alice: Authentication Response

@enduml
自动草稿

还可以使用关键字titleend title定义多行标题。

@startuml

title
 Simple communication example
 on several lines and using html
 This is hosted by 
end title

Alice -> Bob: Authentication Request
Bob -> Alice: Authentication Response

@enduml
自动草稿

包裹参与者

可以使用boxend box画一个盒子将参与者包裹起来。

还可以在box关键字之后添加标题或者背景颜色。

@startuml

box "Internal Service" #LightBlue
	participant Bob
	participant Alice
end box
participant Other

Bob -> Alice : hello
Alice -> Other : hello

@enduml
自动草稿

移除脚注

使用hide footbox关键字移除脚注。

@startuml

hide footbox
title Footer removed

Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response

@enduml
自动草稿

外观参数(skinparam)

使用skinparam命令改变颜色和字体。

如下场景可以使用这一命令:

  • 在图示定义中,
  • 在一个包含文件中,
  • 在由命令行或者ANT任务提供的配置文件中。

你也可以修改其他渲染元素,如以下示例:

@startuml
skinparam sequenceArrowThickness 2
skinparam roundcorner 20
skinparam maxmessagesize 60
skinparam sequenceParticipant underline

actor User
participant "First Class" as A
participant "Second Class" as B
participant "Last Class" as C

User -> A: DoWork
activate A

A -> B: Create Request
activate B

B -> C: DoWork
activate C
C --> B: WorkDone
destroy C

B --> A: Request Created
deactivate B

A --> User: Done
deactivate A

@enduml
自动草稿

@startuml
skinparam backgroundColor #EEEBDC
skinparam handwritten true

skinparam sequence {
	ArrowColor DeepSkyBlue
	ActorBorderColor DeepSkyBlue
	LifeLineBorderColor blue
	LifeLineBackgroundColor #A9DCDF
	
	ParticipantBorderColor DeepSkyBlue
	ParticipantBackgroundColor DodgerBlue
	ParticipantFontName Impact
	ParticipantFontSize 17
	ParticipantFontColor #A9DCDF
	
	ActorBackgroundColor aqua
	ActorFontColor DeepSkyBlue
	ActorFontSize 17
	ActorFontName Aapex
}

actor User
participant "First Class" as A
participant "Second Class" as B
participant "Last Class" as C

User -> A: DoWork
activate A

A -> B: Create Request
activate B

B -> C: DoWork
activate C
C --> B: WorkDone
destroy C

B --> A: Request Created
deactivate B

A --> User: Done
deactivate A

@enduml
自动草稿

填充区设置

可以设定填充区的参数配置。

@startuml
skinparam ParticipantPadding 20
skinparam BoxPadding 10

box "Foo1"
participant Alice1
participant Alice2
end box
box "Foo2"
participant Bob1
participant Bob2
end box
Alice1 -> Bob1 : hello
Alice1 -> Out : out
@enduml
自动草稿
811月/18

完全指南:在 Linux 中如何打印和管理打印机

发布在 邵珠庆

Linux 中的打印

虽然现在大量的沟通都是电子化和无纸化的,但是在我们的公司中还有大量的材料需要打印。银行结算单、公用事业帐单、财务和其它报告、以及收益结算单等一些东西还是需要打印的。本教程将介绍在 Linux 中如何使用 CUPS 去打印。

CUPS,是通用 Unix 打印系统Common UNIX Printing System的首字母缩写,它是 Linux 中的打印机和打印任务的管理者。早期计算机上的打印机一般是在特定的字符集和字体大小下打印文本文件行。现在的图形打印机可以打印各种字体和大小的文本和图形。尽管如此,现在你所使用的一些命令,在古老的行式打印守护进程(LPD)技术的历史中仍能找到它们。

本教程将帮你了解 Linux 服务器专业考试(LPIC-1)的第 108 号主题的 108.4 目标。这个目标的权重为 2。

前提条件

为了更好地学习本系列教程,你需要具备基本的 Linux 知识,和使用 Linux 系统实践本教程中的命令的能力,你应该熟悉 GNU 和 UNIX® 命令的使用。有时不同版本的程序输出可能会不同,因此,你的结果可能与本教程中的示例有所不同。

本教程中的示例使用的是 Fedora 27 的系统。

有关打印的一些历史

这一小部分历史并不是 LPI 目标的,但它有助于你理解这个目标的相关环境。

早期的计算机大都使用行式打印机。这些都是击打式打印机,那时,它们使用固定间距的字符和单一的字体来打印文本行。为提升整个系统性能,早期的主机要与慢速的外围设备(如读卡器、卡片穿孔机、和运行其它工作的行式打印机)交叉进行工作。因此就产生了在线的或者假脱机的同步外围操作,这一术语目前在谈到计算机打印时仍然在使用。

在 UNIX 和 Linux 系统上,打印初始化使用的是 BSD(伯克利软件分发版Berkeley Software Distribution)打印子系统,它是由一个作为服务器运行的行式打印守护程序(LPD)组成,而客户端命令如 lpr 是用于提交打印作业。这个协议后来被 IETF 标准化为 RFC 1179 —— 行式打印机守护进程协议

System V 也有一个打印守护程序。它的功能与BSD 的 LPD 守护程序类似,但是它们的命令集不一样。你在后面会经常看到完成相同的任务使用不同选项的两个命令。例如,对于打印文件的命令,伯克利实现版本是 lpr,而 System V 实现版本是 lp

随着打印机技术的进步,在一个页面上混合出现不同字体成为可能,并且可以将图片像文字一样打印。可变间距字体,以及更多先进的打印技术,比如间距和连字符,现在都已经标准化。出现了几种对基本的 lpd/lpr 方法等改进设计,比如 LPRng,下一代的 LPR,以及 CUPS。

许多可以打印图形的打印机,使用 Adobe PostScript 语言进行初始化。一个 PostScript 打印机有一个解释器引擎,它可以解释打印任务中的命令并从这些命令中生成最终的页面。PostScript 经常被用做原始文件(比如一个文本文件或者一个图像文件)和最终格式没有适合的 PostScript 功能的特定打印机之间的中间层。转换这些特定的打印任务,比如将一个 ASCII 文本文件或者一个 JPEG 图像转换为 PostScript,然后再使用过滤器转换 PostScript 到非 PostScript 打印机所需要的最终光栅格式。

现在的便携式文档格式Portable Document Format(PDF),它就是基于 PostScript 的,已经替换了传统的原始 PostScript。PDF 设计为与硬件和软件无关,它封装了要打印的页面的完整描述。你可以查看 以及打印 PDF 文件。

管理打印队列

用户直接打印作业到一个名为打印队列print queue的逻辑实体。在单用户系统中,打印队列和打印机通常是几乎相同的意思。但是,CUPS 允许系统不用连接到一个打印机上,而最终在一个远程系统上的排队打印作业,并且通过使用分类,允许将定向到一个分类的打印作业在该分类第一个可用的打印机上打印。

你可以检查和管理打印队列。对于 CUPS 来说,其中一些命令实现了一些新操作。另外的一些是源于 LPD 的兼容命令,不过现在的一些选项通常是最初的 LPD 打印系统选项的有限子集。

你可以使用 CUPS 的 lpstat 命令去检查队列,以了解打印系统。一些常见选项如下表 1。

< 如显示不全,请左右滑动 >
选项 作用
-a 显示打印机状态
-c 显示打印分类
-p 显示打印状态:enabled 或者 disabled
-s 显示默认打印机、打印机和类。相当于 -d -c -v注意:要指定多个选项,这些选项必须像值一样分隔开。
-v 显示打印机和它们的设备。

表 1. lpstat 命令的选项

你也可以使用 LPD 的 lpc 命令(它可以在 /usr/sbin 中找到)使用它的 status 选项。如果你不想指定打印机名字,将列出所有的队列。列表 1 展示了命令的一些示例。

  1. [ian@atticf27 ~]$ lpstat -d
  2. system default destination: HL-2280DW
  3. [ian@atticf27 ~]$ lpstat -v HL-2280DW
  4. device for HL-2280DW: dnssd://Brother%20HL-2280DW._pdl-datastream._tcp.local/
  5. [ian@atticf27 ~]$ lpstat -s
  6. system default destination: HL-2280DW
  7. members of class anyprint:
  8. HL-2280DW
  9. XP-610
  10. device for anyprint: ///dev/null
  11. device for HL-2280DW: dnssd://Brother%20HL-2280DW._pdl-datastream._tcp.local/
  12. device for XP-610: dnssd://EPSON%20XP-610%20Series._ipp._tcp.local/?uuid=cfe92100-67c4-11d4-a45f-ac18266c48aa
  13. [ian@atticf27 ~]$ lpstat -a XP-610
  14. XP-610 accepting requests since Thu 27 Apr 2017 05:53:59 PM EDT
  15. [ian@atticf27 ~]$ /usr/sbin/lpc status HL-2280DW
  16. HL-2280DW:
  17. printer is on device \'dnssd\' speed -1
  18. queuing is disabled
  19. printing is enabled
  20. no entries
  21. daemon present

列表 1. 显示可用打印队列

这个示例展示了两台打印机 —— HL-2280DW 和 XP-610,和一个分类 anyprint,它允许打印作业定向到这两台打印机中的第一个可用打印机。

在这个示例中,已经禁用了打印到 HL-2280DW 队列,但是打印功能是启用的,这样便于将打印机脱机维护之前可以完成打印队列中的任务。启用还是禁用队列,可以使用 cupsaccept 和 cupsreject 命令来管理。以前它们叫做 accept 和 reject,你或许可能在 /usr/sbin 中找到这些命令,但它们现在都是符号链接到新的命令上了。同样,启用还是禁用打印,你可以使用 cupsenable 和 cupsdisable 命令来管理。在早期版本的 CUPS 中,这些被称为 enable 和 disable,它也许会与 bash shell 内置的 enable 混淆。列表 2 展示了如何去启用打印机 HL-2280DW 上的队列,而禁止它的打印。CUPS 的几个命令支持使用 -r 选项去提供一个该操作的理由。这个理由会在你使用 lpstat 时显示,但是如果你使用的是 lpc 命令则不会显示它。

  1. [ian@atticf27 ~]$ lpstat -a -p HL-2280DW
  2. anyprint accepting requests since Mon 29 Jan 2018 01:17:09 PM EST
  3. HL-2280DW not accepting requests since Thu 27 Apr 2017 05:52:27 PM EDT -
  4. Maintenance scheduled
  5. XP-610 accepting requests since Thu 27 Apr 2017 05:53:59 PM EDT
  6. printer HL-2280DW is idle. enabled since Thu 27 Apr 2017 05:52:27 PM EDT
  7. Maintenance scheduled
  8. [ian@atticf27 ~]$ accept HL-2280DW
  9. [ian@atticf27 ~]$ cupsdisable -r "waiting for toner delivery" HL-2280DW
  10. [ian@atticf27 ~]$ lpstat -p -a
  11. printer anyprint is idle. enabled since Mon 29 Jan 2018 01:17:09 PM EST
  12. printer HL-2280DW disabled since Mon 29 Jan 2018 04:03:50 PM EST -
  13. waiting for toner delivery
  14. printer XP-610 is idle. enabled since Thu 27 Apr 2017 05:53:59 PM EDT
  15. anyprint accepting requests since Mon 29 Jan 2018 01:17:09 PM EST
  16. HL-2280DW accepting requests since Mon 29 Jan 2018 04:03:50 PM EST
  17. XP-610 accepting requests since Thu 27 Apr 2017 05:53:59 PM EDT

列表 2. 启用队列和禁用打印

注意:用户执行这些任务必须经过授权。它可能要求是 root 用户或者其它的授权用户。在 /etc/cups/cups-files.conf 中可以看到 SystemGroup 的条目,cups-files.conf 的 man 页面有更多授权用户组的信息。

管理用户打印作业

现在,你已经知道了一些如何去检查打印队列和类的方法,我将给你展示如何管理打印队列上的作业。你要做的第一件事是,如何找到一个特定打印机或者全部打印机上排队的任意作业。完成上述工作要使用 lpq 命令。如果没有指定任何选项,lpq 将显示默认打印机上的队列。使用 -P 选项和一个打印机名字将指定打印机,或者使用 -a 选项去指定所有的打印机,如下面的列表 3 所示。

  1. [pat@atticf27 ~]$ # As user pat (non-administrator)
  2. [pat@atticf27 ~]$ lpq
  3. HL-2280DW is not ready
  4. Rank Owner Job File(s) Total Size
  5. 1st unknown 4 unknown 6144 bytes
  6. 2nd pat 6 bitlib.h 6144 bytes
  7. 3rd pat 7 bitlib.C 6144 bytes
  8. 4th unknown 8 unknown 1024 bytes
  9. 5th unknown 9 unknown 1024 bytes
  10. [ian@atticf27 ~]$ # As user ian (administrator)
  11. [ian@atticf27 ~]$ lpq -P xp-610
  12. xp-610 is ready
  13. no entries
  14. [ian@atticf27 ~]$ lpq -a
  15. Rank Owner Job File(s) Total Size
  16. 1st ian 4 permutation.C 6144 bytes
  17. 2nd pat 6 bitlib.h 6144 bytes
  18. 3rd pat 7 bitlib.C 6144 bytes
  19. 4th ian 8 .bashrc 1024 bytes
  20. 5th ian 9 .bashrc 1024 bytes

列表 3. 使用 lpq 检查打印队列

在这个示例中,共有五个作业,它们是 4、6、7、8、和 9,并且它是名为 HL-2280DW 的打印机的队列,而不是 XP-610 的。在这个示例中使用 -P 选项,可简单地显示哪个打印机已经准备好,但是没有队列任务。注意,CUPS 的打印机命名,是大小写不敏感的。还要注意的是,用户 ian 提交了同样的作业两次,当一个作业没有第一时间打印时,经常能看到用户的这种动作。

一般情况下,你可能会查看或者维护你自己的打印作业,但是,root 用户或者其它授权的用户通常会去管理其它打印作业。大多数 CUPS 命令都可以使用一个 -E 选项,对 CUPS 服务器与客户端之间的通讯进行加密。

使用 lprm 命令从队列中去删除一个 .bashrc 作业。如果不使用选项,将删除当前的作业。使用 - 选项,将删除全部的作业。要么就如列表 4 那样,指定一个要删除的作业列表。

  1. [[pat@atticf27 ~]$ # As user pat (non-administrator)
  2. [pat@atticf27 ~]$ lprm
  3. lprm: Forbidden
  4. [ian@atticf27 ~]$ # As user ian (administrator)
  5. [ian@atticf27 ~]$ lprm 8
  6. [ian@atticf27 ~]$ lpq
  7. HL-2280DW is not ready
  8. Rank Owner Job File(s) Total Size
  9. 1st ian 4 permutation.C 6144 bytes
  10. 2nd pat 6 bitlib.h 6144 bytes
  11. 3rd pat 7 bitlib.C 6144 bytes
  12. 4th ian 9 .bashrc 1024 bytes

列表 4. 使用 lprm 删除打印作业

注意,用户 pat 不能删除队列中的第一个作业,因为它是用户 ian 的。但是,ian 可以删除他自己的 8 号作业。

另外的可以帮你操作打印队列中的作业的命令是 lp。使用它可以去修改作业属性,比如打印数量或者优先级。我们假设用户 ian 希望他的作业 9 在用户 pat 的作业之前打印,并且希望打印两份。作业优先级的默认值是 50,它的优先级范围从最低的 1 到最高的 100 之间。用户 ian 可以使用 -i-n、以及 -q 选项去指定一个要修改的作业,而新的打印数量和优先级可以如下面的列表 5 所示的那样去修改。注意,使用 -l 选项的 lpq 命令可以提供更详细的输出。

  1. [ian@atticf27 ~]$ lpq
  2. HL-2280DW is not ready
  3. Rank Owner Job File(s) Total Size
  4. 1st ian 4 permutation.C 6144 bytes
  5. 2nd pat 6 bitlib.h 6144 bytes
  6. 3rd pat 7 bitlib.C 6144 bytes
  7. 4th ian 9 .bashrc 1024 bytes
  8. [ian@atticf27 ~]$ lp -i 9 -q 60 -n 2
  9. [ian@atticf27 ~]$ lpq
  10. HL-2280DW is not ready
  11. Rank Owner Job File(s) Total Size
  12. 1st ian 9 .bashrc 1024 bytes
  13. 2nd ian 4 permutation.C 6144 bytes
  14. 3rd pat 6 bitlib.h 6144 bytes
  15. 4th pat 7 bitlib.C 6144 bytes

列表 5. 使用 lp 去改变打印数量和优先级

最后,lpmove 命令可以允许一个作业从一个队列移动到另一个队列。例如,我们可能因为打印机 HL-2280DW 现在不能使用,而想去移动一个作业到另外的队列上。你可以指定一个作业编号,比如 9,或者你可以用一个队列名加一个连字符去限定它,比如,HL-2280DW-0。lpmove 命令的操作要求是授权用户。列表 6 展示了如何去从一个队列移动作业到另外的队列,先是指定打印机和作业 ID 移动,然后是移动指定打印机的所有作业。稍后我们可以去再次检查队列,其中一个作业已经在打印中了。

  1. [ian@atticf27 ~]$ lpmove HL-2280DW-9 anyprint
  2. [ian@atticf27 ~]$ lpmove HL-2280DW xp-610
  3. [ian@atticf27 ~]$ lpq -a
  4. Rank Owner Job File(s) Total Size
  5. active ian 9 .bashrc 1024 bytes
  6. 1st ian 4 permutation.C 6144 bytes
  7. 2nd pat 6 bitlib.h 6144 bytes
  8. 3rd pat 7 bitlib.C 6144 bytes
  9. [ian@atticf27 ~]$ # A few minutes later
  10. [ian@atticf27 ~]$ lpq -a
  11. Rank Owner Job File(s) Total Size
  12. active pat 6 bitlib.h 6144 bytes
  13. 1st pat 7 bitlib.C 6144 bytes

列表 6. 使用 lpmove 移动作业到另外一个打印队列

如果你使用的是 CUPS 之外的打印服务器,比如 LPD 或者 LPRng,大多数的队列管理功能是由 lpc 命令的子命令来处理的。例如,你可以使用 lpc topq 去移动一个作业到队列的顶端。其它的 lpc 子命令包括 disabledownenableholdmoveredirectrelease、和 start。这些子命令在 CUPS 的兼容命令中没有实现。

打印文件

如何去打印创建的作业?大多数图形界面程序都提供了一个打印方法,通常是 文件 菜单下面的选项。这些程序为选择打印机、设置页边距、彩色或者黑白打印、打印数量、选择每张纸打印的页面数(每张纸打印两个页面,通常用于讲义)等等,都提供了图形化的工具。现在,我将为你展示如何使用命令行工具去管理这些功能,然后和图形化实现进行比较。

打印文件最简单的方法是使用 lpr 命令,然后提供一个文件名字。这将在默认打印机上打印这个文件。而 lp 命令不仅可以打印文件,也可以修改打印作业。列表 7 展示了使用这个命令的一个简单示例。注意,lpr 会静默处理这个作业,但是 lp 会显示处理后的作业的 ID。

  1. [ian@atticf27 ~]$ echo "Print this text" > printexample.txt
  2. [ian@atticf27 ~]$ lpr printexample.txt
  3. [ian@atticf27 ~]$ lp printexample.txt
  4. request id is HL-2280DW-12 (1 file(s))

列表 7. 使用 lpr 和 lp 打印

表 2 展示了 lpr 上你可以使用的一些选项。注意, lp 的选项和 lpr 的很类似,但是名字可能不一样;例如,-# 在 lpr 上是相当于 lp 的 -n 选项。查看 man 页面了解更多的信息。

< 如显示不全,请左右滑动 >
选项 作用
-C, -J 或 -T 设置一个作业名字。
-P 选择一个指定的打印机。
-# 指定打印数量。注意这不同于 lp 命令的 -n 选项。
-m 在作业完成时发送电子邮件。
-l 表示打印文件已经为打印做好格式准备。相当于 -o raw
-o 设置一个作业选项。
-p 格式化一个带有阴影标题的文本文件。相关于 -o prettyprint
-q 暂缓(或排队)后面的打印作业。
-r 在文件进入打印池之后,删除文件。

表 2. lpr 的选项

列表 8 展示了一些选项。我要求打印之后给我发确认电子邮件,那个作业被暂缓执行,并且在打印之后删除文件。

  1. [ian@atticf27 ~]$ lpr -P HL-2280DW -J "Ian\'s text file" -#2 -m -p -q -r printexample.txt
  2. [[ian@atticf27 ~]$ lpq -l
  3. HL-2280DW is ready
  4. ian: 1st [job 13 localhost]
  5. 2 copies of Ian\'s text file 1024 bytes
  6. [ian@atticf27 ~]$ ls printexample.txt
  7. ls: cannot access \'printexample.txt\': No such file or directory

列表 8. 使用 lpr 打印

我现在有一个在 HL-2280DW 打印队列上暂缓执行的作业。然后怎么做?lp 命令可以通过使用 -H 的各种选项来暂缓或者投放作业。列表 9 展示了如何投放被暂缓的作业。查看 lp 命令的 man 页面了解其它选项的信息。

  1. [ian@atticf27 ~]$ lp -i 13 -H resume

列表 9. 重启一个暂缓的打印作业

并不是所有的可用打印机都支持相同的选项集。使用 lpoptions 命令去查看一个打印机的常用选项。添加 -l 选项去显示打印机专用的选项。列表 10 展示了两个示例。许多常见的选项涉及到人像/风景打印、页面大小和输出在纸张上的布局。详细信息查看 man 页面。

  1. [ian@atticf27 ~]$ lpoptions -p HL-2280DW
  2. copies=1 device-uri=dnssd://Brother%20HL-2280DW._pdl-datastream._tcp.local/
  3. finishings=3 job-cancel-after=10800 job-hold-until=no-hold job-priority=50
  4. job-sheets=none,none marker-change-time=1517325288 marker-colors=#000000,#000000
  5. marker-levels=-1,92 marker-names=\'Black\ Toner\ Cartridge,Drum\ Unit\'
  6. marker-types=toner,opc number-up=1 printer-commands=none
  7. printer-info=\'Brother HL-2280DW\' printer-is-accepting-jobs=true
  8. printer-is-shared=true printer-is-temporary=false printer-location
  9. printer-make-and-model=\'Brother HL-2250DN - CUPS Gutenprint v5.2.13 Simplified\'
  10. printer-state=3 printer-state-change-time=1517325288 printer-state-reasons=none
  11. printer-type=135188 printer-uri-supported=ipp://localhost/printers/HL-2280DW
  12. sides=one-sided
  13. [ian@atticf27 ~]$ lpoptions -l -p xp-610
  14. PageSize/Media Size: *Letter Legal Executive Statement A4
  15. ColorModel/Color Model: *Gray Black
  16. InputSlot/Media Source: *Standard ManualAdj Manual MultiPurposeAdj MultiPurpose
  17. UpperAdj Upper LowerAdj Lower LargeCapacityAdj LargeCapacity
  18. StpQuality/Print Quality: None Draft *Standard High
  19. Resolution/Resolution: *301x300dpi 150dpi 300dpi 600dpi
  20. Duplex/2-Sided Printing: *None DuplexNoTumble DuplexTumble
  21. StpiShrinkOutput/Shrink Page If Necessary to Fit Borders: *Shrink Crop Expand
  22. StpColorCorrection/Color Correction: *None Accurate Bright Hue Uncorrected
  23. Desaturated Threshold Density Raw Predithered
  24. StpBrightness/Brightness: 0 100 200 300 400 500 600 700 800 900 *None 1100
  25. 1200 1300 1400 1500 1600 1700 1800 1900 2000 Custom.REAL
  26. StpContrast/Contrast: 0 100 200 300 400 500 600 700 800 900 *None 1100 1200
  27. 1300 1400 1500 1600 1700 1800 1900 2000 2100 2200 2300 2400 2500 2600 2700
  28. 2800 2900 3000 3100 3200 3300 3400 3500 3600 3700 3800 3900 4000 Custom.REAL
  29. StpImageType/Image Type: None Text Graphics *TextGraphics Photo LineArt

列表 10. 检查打印机选项

大多数的 GUI 应用程序有一个打印对话框,通常你可以使用 文件 >打印 菜单去选择它。图 1 展示了在 GIMP 中的一个示例,GIMP 是一个图像处理程序。

自动草稿

图 1. 在 GIMP 中打印

到目前为止,我们所有的命令都是隐式指向到本地的 CUPS 打印服务器上。你也可以通过指定 -h 选项和一个端口号(如果不是 CUPS 的默认端口号 631 的话)将打印转向到另外一个系统上的服务器。

CUPS 和 CUPS 服务器

CUPS 打印系统的核心是 cupsd 打印服务器,它是一个运行的守护进程。CUPS 配置文件一般位于 /etc/cups/cupsd.conf/etc/cups 目录也有与 CUPS 相关的其它的配置文件。CUPS 一般在系统初始化期间启动,根据你的发行版不同,它也可能通过位于 /etc/rc.d/init.d 或者 /etc/init.d 目录中的 CUPS 脚本来控制。对于 最新使用 systemd 来初始化的系统,CUPS 服务脚本可能在 /usr/lib/systemd/system/cups.service 中。和大多数使用脚本的服务一样,你可以停止、启动、或者重启守护程序。查看我们的教程:学习 Linux,101:运行级别、引导目标、关闭、和重启动,了解使用初始化脚本的更多信息。

配置文件 /etc/cups/cupsd.conf 包含一些管理参数,比如访问打印系统、是否允许远程打印、本地打印池文件等等。在一些系统上,第二部分单独描述了打印队列,它一般是由配置工具自动生成的。列表 11 展示了一个默认的 cupsd.conf 文件中的一些条目。注意,注释是以 # 字符开头的。默认值通常以注释的方式显示,并且可以通过删除前面的 # 字符去改变默认值。

  1. # Only listen for connections from the local machine.
  2. Listen localhost:631
  3. Listen /var/run/cups/cups.sock
  4. # Show shared printers on the local network.
  5. Browsing On
  6. BrowseLocalProtocols dnssd
  7. # Default authentication type, when authentication is required...
  8. DefaultAuthType Basic
  9. # Web interface setting...
  10. WebInterface Yes
  11. # Set the default printer/job policies...
  12. <Policy default>
  13. # Job/subscription privacy...
  14. JobPrivateAccess default
  15. JobPrivateValues default
  16. SubscriptionPrivateAccess default
  17. SubscriptionPrivateValues default
  18. # Job-related operations must be done by the owner or an administrator...
  19. <Limit Create-Job Print-Job Print-URI Validate-Job>
  20. Order deny,allow
  21. Limit>

列表 11. 默认的 /etc/cups/cupsd.conf 文件的部分内容

可以用在 cupsd.conf 中使用的文件、目录、和用户配置命令,现在都存储在作为替代的 cups-files.conf 中。这是为了防范某些类型的提权攻击。列表 12 展示了 cups-files.conf 文件中的一些条目。注意,正如在文件层次结构标准(FHS)中所期望的那样,打印池文件默认保存在文件系统的 /var/spool 目录中。查看 man 页面了解 cupsd.conf 和 cups-files.conf 配置文件的更多信息。

  1. # Location of the file listing all of the local printers...
  2. #Printcap /etc/printcap
  3. # Format of the Printcap file...
  4. #PrintcapFormat bsd
  5. #PrintcapFormat plist
  6. #PrintcapFormat solaris
  7. # Location of all spool files...
  8. #RequestRoot /var/spool/cups
  9. # Location of helper programs...
  10. #ServerBin /usr/lib/cups
  11. # SSL/TLS keychain for the scheduler...
  12. #ServerKeychain ssl
  13. # Location of other configuration files...
  14. #ServerRoot /etc/cups

列表 12. 默认的 /etc/cups/cups-files.conf 配置文件的部分内容

列表 12 提及了 /etc/printcap 文件。这是 LPD 打印服务器的配置文件的名字,并且一些应用程序仍然使用它去确定可用的打印机和它们的属性。它通常是在 CUPS 系统上自动生成的,因此,你可能没有必要去修改它。但是,如果你在诊断用户打印问题,你可能需要去检查它。列表 13 展示了一个示例。

  1. # This file was automatically generated by cupsd(8) from the
  2. # /etc/cups/printers.conf file. All changes to this file
  3. # will be lost.
  4. HL-2280DW|Brother HL-2280DW:rm=atticf27:rp=HL-2280DW:
  5. anyprint|Any available printer:rm=atticf27:rp=anyprint:
  6. XP-610|EPSON XP-610 Series:rm=atticf27:rp=XP-610:

列表 13. 自动生成的 /etc/printcap

这个文件中的每一行都有一个打印机名字、打印机描述,远程机器(rm)的名字、以及那个远程机器上的远程打印机(rp)。老的 /etc/printcap 文件也描述了打印机的能力。

文件转换过滤器

你可以使用 CUPS 打印许多类型的文件,包括明文的文本文件、PDF、PostScript、和各种格式的图像文件,你只需要提供要打印的文件名,除此之外你再无需向 lpr 或 lp 命令提供更多的信息。这个神奇的壮举是通过使用过滤器来实现的。实际上,这些年来最流行的过滤器就就叫做 magicfilter(神奇的过滤器)。

当打印一个文件时,CUPS 使用多用途因特网邮件扩展(MIME)类型去决定合适的转换过滤器。其它的打印数据包可能使用由 file 命令使用的神奇数字机制。关于 file 或者神奇数的更多信息可以查看它们的 man 页面。

输入文件被过滤器转换成中间层的光栅格式或者 PostScript 格式。一些作业信息,比如打印数量也会被添加进去。数据最终通过一个后端发送到目标打印机。还有一些可以用手动过滤的输入文件的过滤器(如 a2ps 或 dvips)。你可以通过这些过滤器获得特殊格式的结果,或者去处理一些 CUPS 原生并不支持的文件格式。

添加打印机

CUPS 支持多种打印机,包括:

  • 本地连接的并行口和 USB 口打印机
  • 因特网打印协议(IPP)打印机
  • 远程 LPD 打印机
  • 使用 SAMBA 的 Microsoft® Windows® 打印机
  • 使用 NCP 的 Novell 打印机
  • HP Jetdirect 打印机

当系统启动或者设备连接时,现在的大多数系统都会尝试自动检测和自动配置本地硬件。同样,许多网络打印机也可以被自动检测到。使用 CUPS 的 web 管理工具(http://localhost:631 或者 http://127.0.0.1:631)去搜索或添加打印机。许多发行版都包含它们自己的配置工具,比如,在 SUSE 系统上的 YaST。图 2 展示了使用 localhost:631 的 CUPS 界面,图 3 展示了 Fedora 27 上的 GNOME 打印机设置对话框。

自动草稿

图 2. 使用 CUPS 的 web 界面

自动草稿

图 3. Fedora 27 上的打印机设置

你也可以从命令行配置打印机。在配置打印机之前,你需要一些关于打印机和它的连接方式的基本信息。如果是一个远程系统,你还需要一个用户 ID 和密码。

你需要去知道你的打印机使用什么样的驱动程序。不是所有的打印机都支持 Linux,有些打印机在 Linux 上压根就不能使用,或者功能受限。你可以去 OpenPrinting.org 去查看是否有你的特定的打印机的驱动程序。lpinfo 命令也可以帮你识别有效的设备类型和驱动程序。使用 -v 选项去列出支持的设备,使用 -m 选项去列出驱动程序,如列表 14 所示。

  1. [ian@atticf27 ~]$ lpinfo -m | grep -i xp-610
  2. lsb/usr/Epson/epson-inkjet-printer-escpr/Epson-XP-610_Series-epson-escpr-en.ppd.gz
  3. EPSON XP-610 Series, Epson Inkjet Printer Driver (ESC/P-R) for Linux
  4. [ian@atticf27 ~]$ locate "Epson-XP-610_Series-epson-escpr-en.ppd.gz"
  5. /usr/share/ppd/Epson/epson-inkjet-printer-escpr/Epson-XP-610_Series-epson-escpr-en.ppd.gz
  6. [ian@atticf27 ~]$ lpinfo -v
  7. network socket
  8. network ipps
  9. network lpd
  10. network beh
  11. network ipp
  12. network http
  13. network https
  14. direct hp
  15. serial serial:/dev/ttyS0?baud=115200
  16. direct parallel:/dev/lp0
  17. network smb
  18. direct hpfax
  19. network dnssd://Brother%20HL-2280DW._pdl-datastream._tcp.local/
  20. network dnssd://EPSON%20XP-610%20Series._ipp._tcp.local/?uuid=cfe92100-67c4-11d4-a45f-ac18266c48aa
  21. network lpd://BRN001BA98A1891/BINARY_P1
  22. network lpd://192.168.1.38:515/PASSTHRU

列表 14. 可用的打印机驱动程序

这个 Epson-XP-610_Series-epson-escpr-en.ppd.gz 驱动程序在我的系统上位于 /usr/share/ppd/Epson/epson-inkjet-printer-escpr/ 目录中。

如果你找不到驱动程序,你可以到打印机生产商的网站看看,说不定会有专用的驱动程序。例如,在写这篇文章的时候,Brother 就有一个我的 HL-2280DW 打印机的驱动程序,但是,这个驱动程序在 OpenPrinting.org 上还没有列出来。

如果你收集齐了基本信息,你可以如列表 15 所示的那样,使用 lpadmin 命令去配置打印机。为此,我将为我的 HL-2280DW 打印机创建另外一个实例,以便于双面打印。

  1. [ian@atticf27 ~]$ lpinfo -m | grep -i "hl.*2280"
  2. HL2280DW.ppd Brother HL2280DW for CUPS
  3. lsb/usr/HL2280DW.ppd Brother HL2280DW for CUPS
  4. [ian@atticf27 ~]$ lpadmin -p HL-2280DW-duplex -E -m HL2280DW.ppd \
  5. > -v dnssd://Brother%20HL-2280DW._pdl-datastream._tcp.local/ \
  6. > -D "Brother 1" -o sides=two-sided-long-edge
  7. [ian@atticf27 ~]$ lpstat -a
  8. anyprint accepting requests since Mon 29 Jan 2018 01:17:09 PM EST
  9. HL-2280DW accepting requests since Tue 30 Jan 2018 10:56:10 AM EST
  10. HL-2280DW-duplex accepting requests since Wed 31 Jan 2018 11:41:16 AM EST
  11. HXP-610 accepting requests since Mon 29 Jan 2018 10:34:49 PM EST

列表 15. 配置一台打印机

你可以使用带 -c 选项的 lpadmin 命令去创建一个仅用于双面打印的新分类,而不用为了双面打印去创建一个打印机的副本。

如果你需要删除一台打印机,使用带 -x 选项的 lpadmin 命令。

列表 16 展示了如何去删除打印机和创建一个替代类。

  1. [ian@atticf27 ~]$ lpadmin -x HL-2280DW-duplex
  2. [ian@atticf27 ~]$ lpadmin -p HL-2280DW -c duplex -E -D "Duplex printing" -o sides=two-sided-long-edge
  3. [ian@atticf27 ~]$ cupsenable duplex
  4. [ian@atticf27 ~]$ cupsaccept duplex
  5. [ian@atticf27 ~]$ lpstat -a
  6. anyprint accepting requests since Mon 29 Jan 2018 01:17:09 PM EST
  7. duplex accepting requests since Wed 31 Jan 2018 12:12:05 PM EST
  8. HL-2280DW accepting requests since Wed 31 Jan 2018 11:51:16 AM EST
  9. XP-610 accepting requests since Mon 29 Jan 2018 10:34:49 PM EST

列表 16. 删除一个打印机和创建一个类

你也可以使用 lpadmin 或者 lpoptions 命令去设置各种打印机选项。详细信息请查看 man 页面。

排错

如果你有打印问题,尝试下列的提示:

  • 确保 CUPS 服务器正在运行。你可以使用 lpstat 命令,如果它不能连接到 cupsd 守护程序,它将会报告一个错误。或者,你可以使用 ps -ef 命令在输出中去检查是否有 cupsd。
  • 如果你试着排队一个打印作业而得到一个错误信息,指示打印机不接受这个作业,你可以使用 lpstat -a 或者 lpc status 去检查那个打印机是否接受作业。
  • 如果一个队列中的作业没有打印,使用 lpstat -p 或 lpc status 去检查那个打印机是否接受作业。如前面所讨论的那样,你可能需要将这个作业移动到其它的打印机。
  • 如果这个打印机是远程的,检查它在远程系统上是否存在,并且是可操作的。
  • 检查配置文件,确保特定的用户或者远程系统允许在这个打印机上打印。
  • 确保防火墙允许远程打印请求,是否允许从其它系统到你的系统,或者从你的系统到其它系统的数据包通讯。
  • 验证是否有正确的驱动程序。

正如你所见,打印涉及到你的系统中的几个组件,甚至还有网络。在本教程中,基于篇幅的考虑,我们仅能给你的诊断提供了几个着手点。大多数的 CUPS 系统也有实现我们所讨论的命令行功能的图形界面。一般情况下,这个界面是从本地主机使用浏览器指向 631 端口(http://localhost:631 或 http://127.0.0.1:631)来访问的,如前面的图 2 所示。

你可以通过将 CUPS 运行在前台而不是做为一个守护进程来诊断它的问题。如果有需要,你也可以通过这种方式去测试替代的配置文件。运行 cupsd -h 获得更多信息,或者查看 man 页面。

CUPS 也带有一个访问日志和错误日志。你可以在 cupsd.conf 中使用 LogLevel 语句来改变日志级别。默认情况下,日志是保存在 /var/log/cups 目录。它们可以在浏览器界面(http://localhost:631)下,从 Administration 选项卡中查看。使用不带任何选项的 cupsctl 命令可以显示日志选项。也可以编辑 cupsd.conf 或者使用 cupsctl 去调整各种日志参数。查看 cupsctl 命令的 man 页面了解更多信息。

在 Ubuntu 的 Wiki 页面上的 调试打印问题 页面也是一个非常好的学习的地方。

这就是关于打印和 CUPS 的介绍。

1810月/18

RedisTemplate访问Redis数据结构

发布在 邵珠庆

Redis五种基本数据结构
redis提供键值对的形式对数据进行存储。支持五种数据类型:String(字符串),List(链表),Hash(散列),Set(无序集合),ZSet(有序集合)。下面是网上对其数据结构简单的归纳比较好的,如下:

结构类型 结构存储的值 结构的读写能力
String 可以是字符串、整数或者浮点数 对整个字符串或者字符串的其中一部分执行操作;对象和浮点数执行 自增(increment)或者自减(decrement)
List 一个链表,链表上的每个节点都包含了一个字符串 从链表的两端推入或者弹出元素;根据偏移量对链表进行修剪(trim);读取单个或者多个元素;根据值来查找或者移除元素
Hash 包含键值对的无序散列表 添加、获取、移除单个键值对;获取所有键值对
Set 包含字符串的无序收集器(unorderedcollection),并且被包含的每个字符串都是独一无二的、各不相同 添加、获取、移除单个元素;检查一个元素是否存在于某个集合中;计算交集、并集、差集;从集合里卖弄随机获取元素
ZSet 字符串成员(member)与浮点数分值(score)之间的有序映射,元素的排列顺序由分值的大小决定 添加、获取、删除单个元素;根据分值范围(range)或者成员来获取元素
Spring-data-Redis简介
对于JAVA语言,我们之前使用Jedis对redis进行基本的指令操作,随着Spring对Jedis进行了很好的封装之后,使用Spring-data-redis包对redis的操作变得更加简单和方便。而Spring-data-Redis则是通过RedisTemplate对象来操作Redis的五种数据结构。

如何引入Spring-data-Redis
1.导入jar包:spring-data-redis-1.8.7.RELEASE.jar 和 jedis-2.9.0.jar
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.8.7.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>

2.配置文件(SpringBoot方式暂不介绍)
redis.properties

redis.host=192.168.132.128
redis.port=10000
redis.password=123456

redis.minIdle=50
redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true

applicationContext.xml

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<!-- 引入小配置文件-->
<value>classpath:redis.properties</value>
</list>
</property>
</bean>

<!-- 连接池 ,本质是对GenericObjectPoolConfig的属性的设置-->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="minIdle" value="${redis.minIdle}" />
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxTotal" value="${redis.maxActive}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>

<!-- REDIS连接工厂 -->
<bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<!-- 基础连接参数 -->
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
<property name="password" value="${redis.password}" />
<!-- 是否启用连接池 -->
<property name="usePool" value="true" />
<property name="poolConfig" ref="poolConfig" />
</bean>

<!-- 对String类型处理的RedisTemplate -->
<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="jedisConnFactory" />
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
</bean>

<!-- 对LIST,SET,ZSET,HASH等类型的处理RedisTemplate -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnFactory"/>
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="valueSerializer">
<!-- 对象序列化方案 -->
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
</property>
</bean>

3.注意
推荐使用GenericJackson2JsonRedisSerializer,而不是Jackson2JsonRedisSerializer,因为GenericJackson2JsonRedisSerializer提供了很好的对泛型的支持,而使用Jackson2JsonRedisSerializer对不同对象进行操作时都需要手动set序列化方案,不能直接集成到配置文件中将其直接托管给spring工厂。当然,我们可以自定义序列化方案,同时也可以使用spring-data-redis集成好的序列化方案,例如集成号称速度最快的fastjson序列化方案,下面提供一个fastjson的Serializer(暂时没有集成对泛型纳入工厂方案的支持)。

package util;

import java.nio.charset.Charset;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

/**
* FASTJSON序列化工具
* @author LiuChengxiang
* @time 2017年9月19日上午9:30:27
*
* @param <T>
*/
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {

public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

private Class<T> clazz;

public FastJson2JsonRedisSerializer(Class<T> clazz){
super();
this.clazz = clazz;
}

@Override
public byte[] serialize(T t) throws SerializationException {
if (t == null) {
return new byte[0];
}
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
}

@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length <= 0) {
return null;
}
String str = new String(bytes, DEFAULT_CHARSET);
return (T)JSON.parseObject(str,clazz);
}

}

RedisTemplate访问Redis数据结构(前言)

RedisTemplate访问Redis数据结构(一)——String
RedisTemplate访问Redis数据结构(二)——List
RedisTemplate访问Redis数据结构(三)——Hash
RedisTemplate访问Redis数据结构(四)——Set
RedisTemplate访问Redis数据结构(五)——ZSet

https://blog.csdn.net/weixin_37490221/article/details/78134105

1510月/18

logback.xml常用配置

发布在 邵珠庆

一、logback的介绍

Logback是由log4j创始人设计的又一个开源日志组件。logback当前分成三个模块:logback-core,logback- classic和logback-access。logback-core是其它两个模块的基础模块。logback-classic是log4j的一个 改良版本。此外logback-classic完整实现SLF4J API使你可以很方便地更换成其它日志系统如log4j或JDK14 Logging。logback-access访问模块与Servlet容器集成提供通过Http来访问日志的功能。 Logback是要与SLF4J结合起来用两个组件的官方网站如下:

logback的官方网站: http://logback.qos.ch

SLF4J的官方网站:http://www.slf4j.org

本文章用到的组件如下:请自行到官方网站下载!

logback-access-1.0.0.jar

logback-classic-1.0.0.jar

logback-core-1.0.0.jar

slf4j-api-1.6.0.jar

二、logback取代 log4j的理由:

Logback和log4j是非常相似的,如果你对log4j很熟悉,那对logback很快就会得心应手。下面列了logback相对于log4j的一些优点:

    1、更快的实现  Logback的内核重写了,在一些关键执行路径上性能提升10倍以上。而且logback不仅性能提升了,初始化内存加载也更小了。

    2、非常充分的测试  Logback经过了几年,数不清小时的测试。Logback的测试完全不同级别的。在作者的观点,这是简单重要的原因选择logback而不是log4j。

    3、Logback-classic非常自然实现了SLF4j    Logback-classic实现了 SLF4j。在使用SLF4j中,你都感觉不到logback-classic。而且因为logback-classic非常自然地实现了SLF4J,  所 以切换到log4j或者其他,非常容易,只需要提供成另一个jar包就OK,根本不需要去动那些通过SLF4JAPI实现的代码。

    4、非常充分的文档  官方网站有两百多页的文档。

    5、自动重新加载配置文件  当配置文件修改了,Logback-classic能自动重新加载配置文件。扫描过程快且安全,它并不需要另外创建一个扫描线程。这个技术充分保证了应用程序能跑得很欢在JEE环境里面。

    6、Lilith   Lilith是log事件的观察者,和log4j的chainsaw类似。而lilith还能处理大数量的log数据 。

    7、谨慎的模式和非常友好的恢复  在谨慎模式下,多个FileAppender实例跑在多个JVM下,能 够安全地写道同一个日志文件。RollingFileAppender会有些限制。Logback的FileAppender和它的子类包括 RollingFileAppender能够非常友好地从I/O异常中恢复。

    8、配置文件可以处理不同的情况   开发人员经常需要判断不同的Logback配置文件在不同的环境下(开发,测试,生产)。而这些配置文件仅仅只有一些很小的不同,可以通过,和来实现,这样一个配置文件就可以适应多个环境。

    9、Filters(过滤器)  有些时候,需要诊断一个问题,需要打出日志。在log4j,只有降低日志级别,不过这样会打出大量的日志,会影响应用性能。在Logback,你可以继续 保持那个日志级别而除掉某种特殊情况,如alice这个用户登录,她的日志将打在DEBUG级别而其他用户可以继续打在WARN级别。要实现这个功能只需 加4行XML配置。可以参考MDCFIlter 。

   10、SiftingAppender(一个非常多功能的Appender)  它可以用来分割日志文件根据任何一个给定的运行参数。如,SiftingAppender能够区别日志事件跟进用户的Session,然后每个用户会有一个日志文件。

   11、自动压缩已经打出来的log  RollingFileAppender在产生新文件的时候,会自动压缩已经打出来的日志文件。压缩是个异步过程,所以甚至对于大的日志文件,在压缩过程中应用不会受任何影响。

   12、堆栈树带有包版本  Logback在打出堆栈树日志时,会带上包的数据。

   13、自动去除旧的日志文件  通过设置TimeBasedRollingPolicy或者SizeAndTimeBasedFNATP的maxHistory属性,你可以控制已经产生日志文件的最大数量。如果设置maxHistory 12,那那些log文件超过12个月的都会被自动移除。

总之,logback比log4j太优秀了,让我们的应用全部建立logback上吧 !

、Logback的配置介绍

1、Logger、appender及layout

Logger作为日志的记录器,把它关联到应用的对应的context上后,主要用于存放日志对象,也可以定义日志类型、级别。

Appender主要用于指定日志输出的目的地,目的地可以是控制台、文件、远程套接字服务器、 MySQL、PostreSQL、 Oracle和其他数据库、 JMS和远程UNIX Syslog守护进程等。

Layout 负责把事件转换成字符串,格式化的日志信息的输出。

     2、logger context

各个logger 都被关联到一个 LoggerContext,LoggerContext负责制造logger,也负责以树结构排列各logger。其他所有logger也通过org.slf4j.LoggerFactory 类的静态方法getLogger取得。 getLogger方法以 logger名称为参数。用同一名字调用LoggerFactory.getLogger 方法所得到的永远都是同一个logger对象的引用。

   3、有效级别及级别的继承

Logger 可以被分配级别。级别包括:TRACE、DEBUG、INFO、WARN 和 ERROR,定义于ch.qos.logback.classic.Level类。如果 logger没有被分配级别,那么它将从有被分配级别的最近的祖先那里继承级别。root logger 默认级别是 DEBUG。

4、打印方法与基本的选择规则

    打印方法决定记录请求的级别。例如,如果 L 是一个 logger 实例,那么,语句 L.info("..")是一条级别为 INFO的记录语句。记录请求的级别在高于或等于其 logger 的有效级别时被称为被启用,否则,称为被禁用。记录请求级别为 p,其 logger的有效级别为 q,只有则当 p>=q时,该请求才会被执行。

    该规则是 logback 的核心。级别排序为: TRACE < DEBUG < INFO < WARN < ERROR

 

四、Logback的默认配置

如果配置文件 logback-test.xml 和 logback.xml 都不存在,那么 logback 默认地会调用BasicConfigurator ,创建一个最小化配置。最小化配置由一个关联到根 logger 的ConsoleAppender 组成。输出用模式为%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 的 PatternLayoutEncoder 进行格式化。root logger 默认级别是 DEBUG。

     1、Logback的配置文件

Logback 配置文件的语法非常灵活。正因为灵活,所以无法用 DTD 或 XML schema 进行定义。尽管如此,可以这样描述配置文件的基本结构:以<configuration>开头,后面有零个或多个<appender>元素,有零个或多个<logger>元素,有最多一个<root>元素。

     2、Logback默认配置的步骤

     (1). 尝试在 classpath 下查找文件 logback-test.xml;

(2). 如果文件不存在,则查找文件 logback.xml;

(3). 如果两个文件都不存在,logback 用 Bas icConfigurator 自动对自己进行配置,这会导致记录输出到控制台

以下为详细代码

<?xml version="1.0" encoding="UTF-8"?>
<!-- 说明: 1、日志级别及文件 日志记录采用分级记录,级别与日志文件名相对应,不同级别的日志信息记录到不同的日志文件中 例如:error级别记录到log_error_xxx.log或log_error.log(该文件为当前记录的日志文件),而log_error_xxx.log为归档日志, 
    日志文件按日期记录,同一天内,若日志文件大小等于或大于2M,则按0、1、2...顺序分别命名 例如log-level-2013-12-21.0.log 
    其它级别的日志也是如此。 2、文件路径 若开发、测试用,在Eclipse中运行项目,则到Eclipse的安装路径查找logs文件夹,以相对路径../logs。 
    若部署到Tomcat下,则在Tomcat下的logs文件中 3、Appender FILEERROR对应error级别,文件名以log-error-xxx.log形式命名 
    FILEWARN对应warn级别,文件名以log-warn-xxx.log形式命名 FILEINFO对应info级别,文件名以log-info-xxx.log形式命名 
    FILEDEBUG对应debug级别,文件名以log-debug-xxx.log形式命名 stdout将日志信息输出到控制上,为方便开发测试使用 -->
<configuration>

    <!-- 在Eclipse中运行,请到Eclipse的安装目录中找log文件,Tomcat下,请到Tomcat目录下找 -->
    <!-- <property name="LOG_PATH" value="/xebest/logs/llmj-app" /> -->
    <property name="LOG_PATH" value="E:/logs/llmj-app" />
    <!-- 日志记录器,日期滚动记录 -->
    <appender name="FILEERROR"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${LOG_PATH}/log_error.log</file>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。 
                而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
            <fileNamePattern>${LOG_PATH}/log-error-%d{yyyy-MM-dd}.%i.log
            </fileNamePattern>
            <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始, 命名日志文件,例如log-error-2013-12-21.0.log -->
            <timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>2MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <!-- 追加方式记录日志 -->
        <append>true</append>
        <!-- 日志文件的格式 -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%-5p [%d][%mdc{mdc_userId}] %C:%L - %m %n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <!-- 此日志文件只记录error级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>error</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="FILEWARN"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/log_warn.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/log-warn-%d{yyyy-MM-dd}.%i.log
            </fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>2MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <append>true</append>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%-5p [%d][%mdc{mdc_userId}] %C:%L - %m %n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <!-- 此日志文件只记录warn级别,不记录大于warn级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="FILEINFO"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/log_info.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/log-info-%d{yyyy-MM-dd}.%i.log
            </fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>2MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <append>true</append>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%-5p [%d][%mdc{mdc_userId}] %C:%L - %m %n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <!-- 此日志文件只记录info级别,不记录大于info级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>


    <appender name="FILEDEBUG"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/log_debug.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/log-debug-%d{yyyy-MM-dd}.%i.log
            </fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>2MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <append>true</append>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%-5p [%d][%mdc{mdc_userId}] %C:%L - %m %n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <!-- 此日志文件只记录debug级别,不记录大于debug级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <Target>System.out</Target>
        <encoder>
            <pattern>%-5p [%d][%mdc{mdc_userId}] %C:%L - %m %n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <!-- 此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
    </appender>

    <appender name="FILTER_INFO"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${LOG_PATH}/log_filter.log</File>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} : %m%n</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <fileNamePattern>${LOG_PATH}/log_filter.%d{yyyy-MM-dd}</fileNamePattern>  
        </rollingPolicy>  
    </appender>
    
     <logger name="FILTER_INFO_LOGGER" additivity="false" level="INFO"> 
         <appender-ref ref="FILTER_INFO" /> 
     </logger>


    <appender name="INTEREST_BEARING_INFO"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${LOG_PATH}/log_interest_bearing.log</File>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} : %m%n</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <fileNamePattern>${LOG_PATH}/log_interest_bearing.%d{yyyy-MM-dd}</fileNamePattern>  
        </rollingPolicy>  
    </appender>
    
     <logger name="INTEREST_BEARING_LOGGER" additivity="true" level="INFO"> 
         <appender-ref ref="INTEREST_BEARING_INFO" /> 
     </logger>


    <!-- 为单独的包配置日志级别,若root的级别大于此级别, 此处级别也会输出 应用场景:生产环境一般不会将日志级别设置为trace或debug,但是为详细的记录SQL语句的情况, 
        可将hibernate的级别设置为debug,如此一来,日志文件中就会出现hibernate的debug级别日志, 而其它包则会按root的级别输出日志 -->
    <logger name="org.springframework" level="DEBUG" />
    <logger name="com.ibatis" level="DEBUG" />  
    <logger name="com.ibatis.common.jdbc.SimpleDataSource" level="DEBUG" />  
    <logger name="com.ibatis.common.jdbc.ScriptRunner" level="DEBUG" />  
    <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" level="DEBUG" />  
    <logger name="java.sql.Connection" level="DEBUG" />  
    <logger name="java.sql.Statement" level="DEBUG" />  
    <logger name="java.sql.PreparedStatement" level="DEBUG" />  


    <!-- 生产环境,将此级别配置为适合的级别,以名日志文件太多或影响程序性能 -->
    <root level="INFO">
        <appender-ref ref="FILEDEBUG" />
        <appender-ref ref="FILEINFO" />
        <appender-ref ref="FILEWARN" />
        <appender-ref ref="FILEERROR" />
        <!-- 生产环境将请stdout去掉 -->
         <appender-ref ref="stdout" /> 
    </root>
</configuration>
1010月/18

使用SecureCRT进行端口转发

发布在 邵珠庆

总共3台机器,我的笔记本,跳转机器,内网服务器:

我的笔记本和内网服务器是不能直连的,必须通过跳板机

每次都要先登陆跳板机,然后在跳板机上通过SSH的方式登陆至内网服务器进行操作是一件特别麻烦的事,并且,如果我在内网服务器的8080端口启动了一个web服务,该如何访问呢?

端口转发的意思是,将所有发送至IP1:port1的请求全部转发至IP2:port2

首先配置至跳板机(150.236.223.72:22)的连接:

配置完成后选择Connect连接至跳板机,输入密码后可选择“Save password”以方便以后使用

一,直接连接至内网服务器

选择“Options” -> "Session Options..."

在左侧边栏中选择“Connection” -> "Port Forwarding",选择“add...”添加一条新的转发规则

添加本任意端口(最好是1024之上的端口)至内网服务器22端口的转发规则

然后选择“OK”,要想配置生效,需要关闭当前连接重新连一次,此时,只要该连接处于连接状态,所有本地(127.0.0.1)2222的请求都会通过跳板机(150.236.223.72)转发至内网服务器(10.170.67.234)的22端口

为了验证配置的正确性,创建一条127.0.0.1:2222的连接(此时连接的username和passward为内网服务器的用户名和密码):

点击“Connect”后,可以发现直接登录至内网服务器

SFTP同样使用22端口,所以此时也可通过127.0.0.1:2222向内网服务器发送文件或从内网服务器下载文件(FileZilla)

 

Status: Connecting to 127.0.0.1:2222...
Response: fzSftp started
Command: open "root@127.0.0.1" 2222
Command: Pass: *******
Status: Connected to 127.0.0.1
Status: Retrieving directory listing...
Command: pwd
Response: Current directory is: "/root"
Command: ls
Status: Listing directory /root
Status: Calculating timezone offset of server...
Command: mtime ".rhosts"
Response: 1413279106
Status: Timezone offsets: Server: 0 seconds. Local: 28800 seconds. Difference: 28800 seconds.
Status: Directory listing successful

 

二,访问内网服务器上的web应用

在至跳板机的连接上添加本任意端口(最好是1024之上的端口)至内网服务器8080端口的转发规则

配置完成后同样需要重新连接,此时就可以通过http://127.0.0.1:8080直接访问内网服务器上8080端口启动的web服务了

 

特别需要注意的是:跳板机的连接关闭,端口转发即失效

309月/18

【开发规范】规范文档:MySQL规范2

发布在 邵珠庆

1. 规范背景与目的

MySQL数据库与 Oracle、 SQL Server 等数据库相比,有其内核上的优势与劣势。我们在使用MySQL数据库的时候需要遵循一定规范,扬长避短。本规范旨在帮助或指导RD、QA、OP等技术人员做出适合线上业务的数据库设计。在数据库变更和处理流程、数据库表设计、SQL编写等方面予以规范,从而为公司业务系统稳定、健康地运行提供保障。

2. 设计规范

2.1 数据库设计

以下所有规范会按照【高危】、【强制】、【建议】三个级别进行标注,遵守优先级从高到低。

对于不满足【高危】和【强制】两个级别的设计,DBA会强制打回要求修改。

2.1.1 库名

  1. 【强制】库的名称必须控制在32个字符以内,相关模块的表名与表名之间尽量提现join的关系,如user表和user_login表。
  2. 【强制】库的名称格式:业务系统名称_子系统名,同一模块使用的表名尽量使用统一前缀。
  3. 【强制】一般分库名称命名格式是库通配名_编号,编号从0开始递增,比如wenda_001以时间进行分库的名称格式是“库通配名_时间”
  4. 【强制】创建数据库时必须显式指定字符集,并且字符集只能是utf8或者utf8mb4。创建数据库SQL举例:create database db1 default character set utf8;

2.1.2 表结构

  1. 【强制】表和列的名称必须控制在32个字符以内,表名只能使用字母、数字和下划线,一律小写。
  2. 【强制】表名要求模块名强相关,如师资系统采用”sz”作为前缀,渠道系统采用”qd”作为前缀等。
  3. 【强制】创建表时必须显式指定字符集为utf8或utf8mb4。
  4. 【强制】创建表时必须显式指定表存储引擎类型,如无特殊需求,一律为InnoDB。当需要使用除InnoDB/MyISAM/Memory以外的存储引擎时,必须通过DBA审核才能在生产环境中使用。因为Innodb表支持事务、行锁、宕机恢复、MVCC等关系型数据库重要特性,为业界使用最多的MySQL存储引擎。而这是其他大多数存储引擎不具备的,因此首推InnoDB。
  5. 【强制】建表必须有comment
  6. 【建议】建表时关于主键:(1)强制要求主键为id,类型为int或bigint,且为auto_increment (2)标识表里每一行主体的字段不要设为主键,建议设为其他字段如user_idorder_id等,并建立unique key索引(可参考cdb.teacher表设计)。因为如果设为主键且主键值为随机插入,则会导致innodb内部page分裂和大量随机I/O,性能下降。
  7. 【建议】核心表(如用户表,金钱相关的表)必须有行数据的创建时间字段create_time和最后更新时间字段update_time,便于查问题。
  8. 【建议】表中所有字段必须都是NOT NULL属性,业务可以根据需要定义DEFAULT值。因为使用NULL值会存在每一行都会占用额外存储空间、数据迁移容易出错、聚合函数计算结果偏差等问题。
  9. 【建议】建议对表里的blobtext等大字段,垂直拆分到其他表里,仅在需要读这些对象的时候才去select。
  10. 【建议】反范式设计:把经常需要join查询的字段,在其他表里冗余一份。如user_name属性在user_accountuser_login_log等表里冗余一份,减少join查询。
  11. 【强制】中间表用于保留中间结果集,名称必须以tmp_开头。备份表用于备份或抓取源表快照,名称必须以bak_开头。中间表和备份表定期清理。
  12. 【强制】对于超过100W行的大表进行alter table,必须经过DBA审核,并在业务低峰期执行。因为alter table会产生表锁,期间阻塞对于该表的所有写入,对于业务可能会产生极大影响。

2.1.3 列数据类型优化

  1. 【建议】表中的自增列(auto_increment属性),推荐使用bigint类型。因为无符号int存储范围为-2147483648~2147483647(大约21亿左右),溢出后会导致报错。
  2. 【建议】业务中选择性很少的状态status、类型type等字段推荐使用tinytint或者smallint类型节省存储空间。
  3. 【建议】业务中IP地址字段推荐使用int类型,不推荐用char(15)。因为int只占4字节,可以用如下函数相互转换,而char(15)占用至少15字节。一旦表数据行数到了1亿,那么要多用1.1G存储空间。
    SQL:select inet_aton(\'192.168.2.12\'); select inet_ntoa(3232236044);
    PHP: ip2long(‘192.168.2.12’); long2ip(3530427185);
  4. 【建议】不推荐使用enumset。 因为它们浪费空间,且枚举值写死了,变更不方便。推荐使用tinyintsmallint
  5. 【建议】不推荐使用blobtext等类型。它们都比较浪费硬盘和内存空间。在加载表数据时,会读取大字段到内存里从而浪费内存空间,影响系统性能。建议和PM、RD沟通,是否真的需要这么大字段。Innodb中当一行记录超过8098字节时,会将该记录中选取最长的一个字段将其768字节放在原始page里,该字段余下内容放在overflow-page里。不幸的是在compact行格式下,原始pageoverflow-page都会加载。
  6. 【建议】存储金钱的字段,建议用int,程序端乘以100和除以100进行存取。因为int占用4字节,而double占用8字节,空间浪费。
  7. 【建议】文本数据尽量用varchar存储。因为varchar是变长存储,比char更省空间。MySQL server层规定一行所有文本最多存65535字节,因此在utf8字符集下最多存21844个字符,超过会自动转换为mediumtext字段。而text在utf8字符集下最多存21844个字符,mediumtext最多存2^24/3个字符,longtext最多存2^32个字符。一般建议用varchar类型,字符数不要超过2700。
  8. 【建议】时间类型尽量选取timestamp。因为datetime占用8字节,timestamp仅占用4字节,但是范围为1970-01-01 00:00:012038-01-01 00:00:00。更为高阶的方法,选用int来存储时间,使用SQL函数unix_timestamp()from_unixtime()来进行转换。

详细存储大小参加下图:

自动草稿

自动草稿

2.1.4 索引设计

  1. 【强制】InnoDB表必须主键为id int/bigint auto_increment,且主键值禁止被更新。
  2. 【建议】主键的名称以“pk_”开头,唯一键以“uk_”或“uq_”开头,普通索引以“idx_”开头,一律使用小写格式,以表名/字段的名称或缩写作为后缀。
  3. 【强制】InnoDB和MyISAM存储引擎表,索引类型必须为BTREE;MEMORY表可以根据需要选择HASH或者BTREE类型索引。
  4. 【强制】单个索引中每个索引记录的长度不能超过64KB。
  5. 【建议】单个表上的索引个数不能超过7个。
  6. 【建议】在建立索引时,多考虑建立联合索引,并把区分度最高的字段放在最前面。如列userid的区分度可由select count(distinct userid)计算出来。
  7. 【建议】在多表join的SQL里,保证被驱动表的连接列上有索引,这样join执行效率最高。
  8. 【建议】建表或加索引时,保证表里互相不存在冗余索引。对于MySQL来说,如果表里已经存在key(a,b),则key(a)为冗余索引,需要删除。

2.1.5 分库分表、分区表

  1. 【强制】分区表的分区字段(partition-key)必须有索引,或者是组合索引的首列。
  2. 【强制】单个分区表中的分区(包括子分区)个数不能超过1024。
  3. 【强制】上线前RD或者DBA必须指定分区表的创建、清理策略。
  4. 【强制】访问分区表的SQL必须包含分区键。
  5. 【建议】单个分区文件不超过2G,总大小不超过50G。建议总分区数不超过20个。
  6. 【强制】对于分区表执行alter table操作,必须在业务低峰期执行。
  7. 【强制】采用分库策略的,库的数量不能超过1024
  8. 【强制】采用分表策略的,表的数量不能超过4096
  9. 【建议】单个分表不超过500W行,ibd文件大小不超过2G,这样才能让数据分布式变得性能更佳。
  10. 【建议】水平分表尽量用取模方式,日志、报表类数据建议采用日期进行分表。

2.1.6 字符集

  1. 【强制】数据库本身库、表、列所有字符集必须保持一致,为utf8utf8mb4
  2. 【强制】前端程序字符集或者环境变量中的字符集,与数据库、表的字符集必须一致,统一为utf8

2.1.7 程序层DAO设计建议

  1. 【建议】新的代码不要用model,推荐使用手动拼SQL 绑定变量传入参数的方式。因为model虽然可以使用面向对象的方式操作db,但是其使用不当很容易造成生成的SQL非常复杂,且model层自己做的强制类型转换性能较差,最终导致数据库性能下降。
  2. 【建议】前端程序连接MySQL或者redis,必须要有连接超时和失败重连机制,且失败重试必须有间隔时间。
  3. 【建议】前端程序报错里尽量能够提示MySQL或redis原生态的报错信息,便于排查错误。
  4. 【建议】对于有连接池的前端程序,必须根据业务需要配置初始、最小、最大连接数,超时时间以及连接回收机制,否则会耗尽数据库连接资源,造成线上事故。
  5. 【建议】对于log或history类型的表,随时间增长容易越来越大,因此上线前RD或者DBA必须建立表数据清理或归档方案。
  6. 【建议】在应用程序设计阶段,RD必须考虑并规避数据库中主从延迟对于业务的影响。尽量避免从库短时延迟(20秒以内)对业务造成影响,建议强制一致性的读开启事务走主库,或更新后过一段时间再去读从库。
  7. 【建议】多个并发业务逻辑访问同一块数据(innodb表)时,会在数据库端产生行锁甚至表锁导致并发下降,因此建议更新类SQL尽量基于主键去更新。
  8. 【建议】业务逻辑之间加锁顺序尽量保持一致,否则会导致死锁。
  9. 【建议】对于单表读写比大于10:1的数据行或单个列,可以将热点数据放在缓存里(如mecache或redis),加快访问速度,降低MySQL压力。

2.1.8 一个规范的建表语句示例

一个较为规范的建表语句为:

CREATE TABLE user (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(11) NOT NULL COMMENT ‘用户id`username` varchar(45) NOT NULL COMMENT \'真实姓名\',
  `email` varchar(30) NOT NULL COMMENT ‘用户邮箱’,
  `nickname` varchar(45) NOT NULL COMMENT \'昵称\',
  `avatar` int(11) NOT NULL COMMENT \'头像\',
  `birthday` date NOT NULL COMMENT \'生日\',
  `sex` tinyint(4) DEFAULT \'0\' COMMENT \'性别\',
  `short_introduce` varchar(150) DEFAULT NULL COMMENT \'一句话介绍自己,最多50个汉字\',
  `user_resume` varchar(300) NOT NULL COMMENT \'用户提交的简历存放地址\',
  `user_register_ip` int NOT NULL COMMENT ‘用户注册时的源ip’,
  `create_time` timestamp NOT NULL COMMENT ‘用户记录创建的时间’,
  `update_time` timestamp NOT NULL COMMENT ‘用户资料修改的时间’,
  `user_review_status` tinyint NOT NULL COMMENT ‘用户资料审核状态,1为通过,2为审核中,3为未通过,4为还未提交审核’,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_user_id` (`user_id`),
  KEY `idx_username`(`username`),
  KEY `idx_create_time`(`create_time`,`user_review_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=\'网站用户基本信息\';

2.2 SQL编写

2.2.1 DML语句

  1. 【强制】SELECT语句必须指定具体字段名称,禁止写成*。因为select *会将不该读的数据也从MySQL里读出来,造成网卡压力。且表字段一旦更新,但model层没有来得及更新的话,系统会报错。
  2. 【强制】insert语句指定具体字段名称,不要写成insert into t1 values(…),道理同上。
  3. 【建议】insert into…values(XX),(XX),(XX)…。这里XX的值不要超过5000个。值过多虽然上线很很快,但会引起主从同步延迟。
  4. 【建议】SELECT语句不要使用UNION,推荐使用UNION ALL,并且UNION子句个数限制在5个以内。因为union all不需要去重,节省数据库资源,提高性能。
  5. 【建议】in值列表限制在500以内。例如select… where userid in(….500个以内…),这么做是为了减少底层扫描,减轻数据库压力从而加速查询。
  6. 【建议】事务里批量更新数据需要控制数量,进行必要的sleep,做到少量多次。
  7. 【强制】事务涉及的表必须全部是innodb表。否则一旦失败不会全部回滚,且易造成主从库同步终端。
  8. 【强制】写入和事务发往主库,只读SQL发往从库。
  9. 【强制】除静态表或小表(100行以内),DML语句必须有where条件,且使用索引查找。
  10. 【强制】生产环境禁止使用hint,如sql_no_cacheforce indexignore keystraight join等。因为hint是用来强制SQL按照某个执行计划来执行,但随着数据量变化我们无法保证自己当初的预判是正确的,因此我们要相信MySQL优化器!
  11. 【强制】where条件里等号左右字段类型必须一致,否则无法利用索引。
  12. 【建议】SELECT|UPDATE|DELETE|REPLACE要有WHERE子句,且WHERE子句的条件必需使用索引查找。
  13. 【强制】生产数据库中强烈不推荐大表上发生全表扫描,但对于100行以下的静态表可以全表扫描。查询数据量不要超过表行数的25%,否则不会利用索引。
  14. 【强制】WHERE 子句中禁止只使用全模糊的LIKE条件进行查找,必须有其他等值或范围查询条件,否则无法利用索引。
  15. 【建议】索引列不要使用函数或表达式,否则无法利用索引。如where length(name)=\'Admin\'where user_id 2=10023
  16. 【建议】减少使用or语句,可将or语句优化为union,然后在各个where条件上建立索引。如where a=1 or b=2优化为where a=1… union …where b=2, key(a),key(b)
  17. 【建议】分页查询,当limit起点较高时,可先用过滤条件进行过滤。如select a,b,c from t1 limit 10000,20;优化为: select a,b,c from t1 where id>10000 limit 20;

2.2.2 多表连接

  1. 【强制】禁止跨db的join语句。因为这样可以减少模块间耦合,为数据库拆分奠定坚实基础。
  2. 【强制】禁止在业务的更新类SQL语句中使用join,比如update t1 join t2…
  3. 【建议】不建议使用子查询,建议将子查询SQL拆开结合程序多次查询,或使用join来代替子查询。
  4. 【建议】线上环境,多表join不要超过3个表。
  5. 【建议】多表连接查询推荐使用别名,且SELECT列表中要用别名引用字段,数据库.表格式,如select a from db1.table1 alias1 where …
  6. 【建议】在多表join中,尽量选取结果集较小的表作为驱动表,来join其他表。

2.2.3 事务

  1. 【建议】事务中INSERT|UPDATE|DELETE|REPLACE语句操作的行数控制在2000以内,以及WHERE子句中IN列表的传参个数控制在500以内。
  2. 【建议】批量操作数据时,需要控制事务处理间隔时间,进行必要的sleep,一般建议值5-10秒。
  3. 【建议】对于有auto_increment属性字段的表的插入操作,并发需要控制在200以内。
  4. 【强制】程序设计必须考虑“数据库事务隔离级别”带来的影响,包括脏读、不可重复读和幻读。线上建议事务隔离级别为repeatable-read
  5. 【建议】事务里包含SQL不超过5个(支付业务除外)。因为过长的事务会导致锁数据较久,MySQL内部缓存、连接消耗过多等雪崩问题。
  6. 【建议】事务里更新语句尽量基于主键或unique key,如update … where id=XX; 否则会产生间隙锁,内部扩大锁定范围,导致系统性能下降,产生死锁。
  7. 【建议】尽量把一些典型外部调用移出事务,如调用webservice,访问文件存储等,从而避免事务过长。
  8. 【建议】对于MySQL主从延迟严格敏感的select语句,请开启事务强制访问主库。

2.2.4 排序和分组

  1. 【建议】减少使用order by,和业务沟通能不排序就不排序,或将排序放到程序端去做。order bygroup bydistinct这些语句较为耗费CPU,数据库的CPU资源是极其宝贵的。
  2. 【建议】order bygroup bydistinct这些SQL尽量利用索引直接检索出排序好的数据。如where a=1 order by可以利用key(a,b)
  3. 【建议】包含了order bygroup bydistinct这些查询的语句,where条件过滤出来的结果集请保持在1000行以内,否则SQL会很慢。

2.2.5 线上禁止使用的SQL语句

  1. 【高危】禁用update|delete t1 … where a=XX limit XX; 这种带limit的更新语句。因为会导致主从不一致,导致数据错乱。建议加上order by PK
  2. 【高危】禁止使用关联子查询,如update t1 set … where name in(select name from user where…);效率极其低下。
  3. 【强制】禁用procedure、function、trigger、views、event、外键约束。因为他们消耗数据库资源,降低数据库实例可扩展性。推荐都在程序端实现。
  4. 【强制】禁用insert into …on duplicate key update…在高并发环境下,会造成主从不一致。
  5. 【强制】禁止联表更新语句,如update t1,t2 where t1.id=t2.id…