0%

HTTPS(HTTP over SSL)是以安全为目标的 HTTP 通道,可以理解为 HTTP + SSL/TLS,即在 HTTP 下加入 SSL/TLS 层作为安全基础。其中 TLS 的前身是 SSL,目前广泛使用的是 TLS 1.2。

TLS性能调优

TLS 被普遍认为会使服务变慢,主要是早期 CPU 还很慢,只有少数站点买得起加密服务。但是今天计算能力不再是 TLS 的瓶颈。2010年,Google 默认情况下对其电子邮件服务上启用了加密,之后他们表示 SSL/TLS 不再花费昂贵的计算成本:

1
在我们的前端服务上,SSL/TLS 计算只占 CPU 负载的不到 1%,每个连接只占不到 10KB 的内存,以及不到 2% 的网络开销。

1. 延迟和连接管理

网络通讯的速度由两个主要因素决定:带宽和延迟。

  • 带宽:用来衡量在单位时间内有多少数据可发送
  • 延迟:描述一个消息从一端发送到另一端接收所需的时间

其中,带宽是次要因素,因为通常你可以随时购买更多带宽;而延迟则是无法避免的,因为它是在数据通过网络连接传输时被强加的限制。

延迟对 TLS 影响特别大,因为它有自己精心设计的握手,在连接初始化的时候额外增加了两个往返。

1.1 TCP优化

每个 TCP 连接都有一个称为 拥塞窗口 的速度极限,这个窗口最初时较小,在可靠性能保证的情况下随时间增长。这种机制被称为 慢启动

因此,对于所有的 TCP 连接,启动速度很慢,对于 TLS 连接情况则更糟糕,因为 TLS 握手协议消耗了宝贵的初始连接字节(当拥塞窗口较小时)。如果拥塞窗口足够大,那么慢启动不会有额外的延迟。但是,如果较长的握手协议超过了拥塞窗口的大小,发送方必须将它拆分为两块,先发送一块,等待确认(一个往返),增加拥塞窗口,然后再发送剩下的部分。

1.1.1 拥塞窗口调优

启动速度限制被称为 初始拥塞窗口。RFC6928 建议初始拥塞窗口设置为10个网络段(约15KB)。早期的建议是使用2-4个网络段起步。

在旧版本的Linux平台上,可以改变路由的初始拥塞窗口:

1
# ip route | while read p; do ip route change $p initcwnd 10; done

1.1.2 防止空闲时慢启动

慢启动可以作用于一段时间内没有任何流量的连接上,降低其速度,并且速度下降地非常快。 在 Linux 上,可以在连接空闲时禁用慢启动:

1
# sysctl -w net.ipv4.tcp_slow_start_after_idle=0

可以通过将该设置添加到 /etc/sysctl.conf 配置使其永久生效。

1.2 长连接

大部分情况下 TLS 性能影响集中在每一个连接的开始握手阶段。一个重要的优化技术是在连接数允许的情况下尽可能保持每个连接不断开。

现在的趋势是使用事件驱动的 WEB 服务器,通过使用固定的线程池(甚至单个线程)处理所有通讯,从而减少每个连接的成本以及被攻击的可能性。

长连接的缺点是在最后一个 HTTP 连接完成之后,服务器在关闭连接之前会等待一定时间,虽然一个连接不会消耗太多的资源,但是降低了服务器的总体伸缩性。长连接适用于客户端突发大量请求的场景。

1
当配置较大的长连接超时时间时,限制并发连接数以免服务器超负荷是至关重要的。通过测试调整服务器,使其运行在容量限制内。如果 TLS 是由 OpenSSL 处理的,请确保服务器正确设置 SSL_MODE_RELEASE_BUFFERS 标识。

1.3 HTTP/2.0

HTTP/2.0 是 二进制协议,具备 多路复用头部压缩 等特性,可以提升性能。

1.4 CDN

使用 CDN 可以实现世界级的性能,它利用地理上分散的服务器提供边缘缓存和流量优化。

当用户离你的服务器越远,访问网络就越慢,在这种情况下连接建立是一个很大的限制因素。为了服务器尽可能靠近最终用户,CDN 经营着大量的地理分布的服务器,它可以提供两种降低延迟的方式,即边缘缓存和连接管理。

1.4.1 边缘缓存

由于 CDN 服务器贴近用户,可以将你的文件提供给用户,就像你的服务器真的在那里一样。

1.4.2 连接管理

如果你的内容是动态的、用户特定的,那么久无法通过 CDN 缓存数据。但是,一个不错的 CDN 即使没有任何缓存,也能通过连接管理提供帮助,那就是它可以通过长时间保持的长连接消除大部分建立连接的成本。

建立连接期间大部分的时间都花在等待上面。为了尽量较少等待,CDN 通过自己的基础设置将流量路由到距离目的地最近的一个点。因为是 CDN 自己完全可控的服务器,它可以内部保持长连接很长一段时间。

当使用 CDN 时,用户连接到最近的 CDN 节点,这只有很短的距离,TLS 握手的网络延迟也很短;而 CDN 与服务器之间可以直接复用已有的远距离长连接。这意味着与 CDN 快速初始 TLS 握手后,用户与服务器就建立了有效连接。

2. TLS协议优化

在连接管理之后我们可以专注于 TLS 的性能特征,具备对 TLS 协议进行安全和速度调优的知识。

2.1 密钥交换

使用 TLS 最大的成本除了延迟以外,就是用于安全参数协商的 CPU 密集型加密操作。这部分通讯称为密钥交换(key exchange)。密钥交换的 CPU 消耗很大程度上取决于服务器选择的私钥算法、私钥长度和密钥交换算法。

  • 密钥长度
    破解密钥的难度取决于密钥的长度,密钥越长越安全。但较长的密钥同时也意味着需要花费更多时间进行加密和解密。

  • 密钥算法
    目前有两种密钥算法可用:RSA 和 ECDSA。当前 RSA密钥算法推荐最小长度2048位(112位加密强度),将来更多会部署3072位(128位加密强度)。ECDSA在性能和安全性上要优于 RSA,256位的 ECDSA (128位加密强度)提供和 3072位的 RSA 一样的安全性,却有更好地性能。

  • 密钥交换
    目前有两种可用的密钥交换算法:DHE 和 ECDHE。其中 DHE 太慢不推荐使用。 密钥交换算法的性能取决于配置的协商参数长度。对于 DHE,常用的1024和2048位,分别提供80和112位安全等级。对于 ECDHE,安全和性能取决于一种称为 曲线 的东西。secp256r1提供128位安全等级。

你在实践中不能随意组合密钥钥和密钥交换算法,但可以使用由协议指定的组合。

2.2 证书

一次完整的 TLS 握手期间,服务器会把它的证书链发送给客户端验证。证书链的长度和正确性对握手的性能有很大影响。

  • 使用尽可能少的证书
    证书链里的每个证书都会增大握手数据包,证书链中包含太多证书有可能导致 TCP 初始拥塞窗口溢出。

  • 只包含必需的证书
    证书链里包含非必需证书是个常见错误,每个这样的证书会给握手协议额外增加1-2KB。

  • 提供完整的证书链
    服务器必须提供一个被根证书信任的完整证书链。

  • 使用椭圆曲线证书链
    因为 ECDSA 私钥长度使用更少的位,所以 ECDSA 证书会更小。

  • 避免同一张证书绑定过多域名
    每增加一个域名都会增加证书的大小,对于大量域名来说会有明显的影响。

2.3 吊销检查

虽然证书吊销状态在不断变化,并且用户代理对证书吊销的行为差异很大,但是作为服务器,要做的就是尽可能快地传递吊销信息。

  • 使用 OCSP
    信息的证书 OCSP 被设计用于提供实时查询,允许用户代理只请求访问网站的吊销信息,查询简短而快速(一个HTTP请求)。相比之下 CRL 是一个包含大量被吊销证书的列表。

  • 使用具有快速且可靠的 OCSP 响应程序的 CA
    不同 CA 之间的 OCSP 响应程序性能不同,在你向 CA 提交之前先检查他们的历史 OCSP 响应程序。 另一个选择 CA 的标准是它更新 OCSP 响应程序的速度。

  • 部署 OCSP stapling
    OCSP stapling 是一种允许在 TLS 握手中包含吊销信息(整个OCSP响应)的协议功能。启用之后,通过给予用户代理进行吊销检查的全部信息以带来更好地性能,可以省去用户代理通过独立的连接获取 CA 的 OCSP 响应程序来查询吊销信息。

2.4 协议兼容

如果你的服务器与一些新版本协议的特性(例如TLS 1.2)不兼容,浏览器可能需要通过与服务器进行多次尝试,才能协商一个加密的连接。确保良好的 TLS 性能的最好方式是升级最新的 TLS 协议栈以支持较新的协议版本和扩展。

2.5 硬件加速

随着 CPU 速度的不断提高,基于软件的 TLS 实现在普通 CPU 上已经运行得足够快,无需专门的加密硬件就能处理大量的 HTTPS 请求。但安装加速卡或许能够提升速度。

参考文章
《HTTPS权威指南:在服务器和Web应用上部署SSL/TLS和PKI》

via: https://www.cnblogs.com/cyfonly/p/9061262.html

相信不管是做前端开发还是后端开发的同学,或多或少在开发过程中接触过缓存的概念。最简单的例子就是前端对于静态资源–即css、js、图片等文件资源进行缓存。但是大部分同学知道的可能就是设置Cache-Control: max-age=xxx来设置资源的过期时间,然而缓存的运用在互联网中可谓是无处不在,一个好的缓存方案可以大大提升服务的性能,而一个不好的缓存方案可能会导致网站的可用性降低。所以今天我们就来聊聊HTTP协议中的缓存。

首先HTTP协议中主要涉及缓存的Header就是Cache-ControlExpires,目前阶段来说Expires已经渐渐被淘汰了,所以我们主要讲讲Cache-Control

Cache-Control并不是只有指定max-age过期时间这么一种使用方式,事实上这只是Cache-Control最基础的用法,我们来看看Cache-Control有哪些可以设置的值

  1. private、public和no-cache用来指定客户端和代理缓存的可缓存性
  2. max-age和s-maxage用来指定客户端和代理缓存的缓存时间
  3. must-revalidate和proxy-revalidate用来指定缓存过期后是否必须验证才能使用
  4. no-store用来表明任何地方都不应该缓存内容
  5. 其他一些不常用的设置

首先大家必须要弄清楚的一点是,缓存不仅仅只有浏览器可以缓存,互联网中存在着各式各样的代理缓存。HTTP仅仅是一个应用层的协议,在数据传输的过程中逃不开各种中继的设备,而本身HTTP是明文传输的,所以每个中继设备都可以解析HTTP数据包中的内容,所以如果某个中继设备想,他就可以成为一个代理缓存(想想曾经的某些运行商做的事)。当然HTTP的代理缓存更多还是服务假设者自己做的,但是本质上是一个意思。

那么相对于大家都知道的客户端缓存,代理缓存有什么好处呢?最明显的优势就是:客户端缓存是一对一的,但是代理缓存是一对多的。

从这张图中我们可以看到,对于同一个源服务器可以存在不同的代理(有些CDN就近获取资源就有用到缓存的知识)。如果这些代理都开启来缓存功能,那么用户一在第一次访问数据的时候,代理通过源服务器获取资源返回给用户,并同时缓存来这个请求,这时候用户二再次来请求的时候,就不需要经过源服务器,直接从代理缓存读取就可以来。

所以对于耗时操作而且数据修改不频繁的数据,开启代理缓存对于性能的提升是非常明显的,哪怕你每次缓存的时间只有5秒,对于并发量很高请求带来的性能提升也是不可估量的。

当然这个操作源服务器通过自己设置缓存也可以实现,但是代理缓存的好处是,如果你的代理离用户足够近,那么减少的延时也是非常明显的。比如如果你的服务器在美国纽约,如果你不在国内设置一个代理缓存,那么所有数据都要跨国半个地球再绕回来,而有代理缓存的情况就不一样来。

那么说回来,怎么控制代理缓存的使用?还是靠HTTP协议,在HTTP协议的发展历史中,已经有非常多的实践让协议进行修改和发展,所以目前的缓存方案可以说已经比较完善了。一般来说,代理缓存服务器都会对最新的HTTP协议的标准进行实现,并且适当兼容老得标准,一般不会出现一些魔改实现。所以只要你对HTTP协议的缓存方案充分了解,那么你就可以很好得使用代理服务器的缓存了。

最主要的你需要知道:

  1. 如何控制代理服务是否缓存或者缓存多少时间
  2. 代理缓存时候可以提供过期缓存的内容
  3. 如何进行缓存验证

知道这些之后,配合一个好用的代理缓存,相信能对你的服务带来很大的性能提升。

最后,HTTP协议是所有WEB相关开发的同学都必须要牢牢掌握的基础,仅仅知道POST、GET、Content-Type并不算理解HTTP协议,HTTP协议中还有非常多好玩又好用的内容等着大家去发掘。

错误现象

Sublime Text 3 在安装Package Control的时候会出现类似如下错误:

Sublime Text 3 Package Control ERROR

开启debug时,console里会出现如下提示:

1
2
3
4
5
6
Package Control: Found previously exported CA bundle at /Users/.../Library/Application Support/Sublime Text 3/Packages/User/oscrypto-ca-bundle.crt (272085 bytes)

Package Control: Urllib HTTPS Debug General
Upgrading connection to SSL using CA certs file at /Users/.../Library/Application Support/Sublime Text 3/Packages/User/Package Control.merged-ca-bundle
Using hostname "packagecontrol.io" for TLS SNI extension
Package Control: Error downloading channel. HTTP exception InvalidCertificateException (Host 127.0.0.1:9090 returned an invalid certificate ([SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:548))) downloading https://packagecontrol.io/channel_v3.json.

特别是用了代理的时候。

解决办法

很多Google中找到的办法都不能解决,可以尝试以下的粗暴办法:

  1. 清空 /Users/…/Library/Application Support/Sublime Text 3/Packages/User/oscrypto-ca-bundle.crt
  2. 将console中提示有SSL问题的域名根证书加入到oscrypto-ca-bundle.crt即可

以packagecontrol.io为例,
packagecontrol.io证书信息

channel_v3.json里涉及的相关公钥

GeoTrust Global CA

相关域名
packagecontrol.io
sublimerge.com

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-----BEGIN CERTIFICATE-----
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
-----END CERTIFICATE-----

via: https://www.geotrust.com/resources/root_certificates/certificates/GeoTrust_Global_CA.pem

DigiCert High Assurance EV Root CA

相关域名
codeload.github.com
bitbucket.org
github.com
s3.amazonaws.com

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
+OkuE6N36B9K
-----END CERTIFICATE-----

via: https://ev-root.chain-demos.digicert.com/info/index.html

DST Root CA X3

相关域名:
packages.monokai.pro
downloads.sourceforge.net
sublime.wbond.net

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-----BEGIN CERTIFICATE-----
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----

via: https://letsencrypt.org/certificates/

Certum Trusted Network CA

相关域名:
serwer1784570.home.pl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-----BEGIN CERTIFICATE-----
MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM
MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E
jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo
ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI
ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu
Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg
AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7
HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA
uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa
TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg
xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q
CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x
O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs
6GAqm4VKQPNriiTsBhYscw==
-----END CERTIFICATE-----

via: https://www.certum.eu/en/cert_expertise_root_certificates/#CTNCA

MWeb 是一款Mac上专业的Markdown写作、记笔记、静态博客生成软件,是一站式的 Markdown 编辑和静态网站生成解决方案,支持大量 Markdown 扩展语法,很不错!

[MWeb 在 Mac App Store上售价人民币98元]

MWeb for Mac 2.2.4 介绍


  • 「MWeb 获得少数派 2015 年度 Mac App」(http://sspai.com/topic/best-apps-2015/)

  • “ MWeb 是一站式的 Markdown 编辑和静态网站生成解决方案 - Mac玩儿法(www.waerfa.com)”

  • “ MWeb 是一款性价比很高的 Markdown 编辑器,它所能做的事绝对让你物有所值。 - 少数派(sspai.com)”

点这里

第一步:使用npm安装n模块

n模块是专门用来管理nodejs版本的

1
sudo npm install -g n

提示 : 如果不使用sudo作为前缀,很可能出现权限访问异常导致安装失败

第二步:升级nodejs

升级nodejs是有两种方法:
第一种是升级到最新版本

1
sudo n latest

第二种是升级到稳定版本

1
sudo n stable

提示 : 建议是稳定版本
更多n模块管理请搜索【nodejs n模块使用说明】

权限相关的异常:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
npm ERR! Darwin 16.4.0
npm ERR! argv "/usr/local/Cellar/node/6.4.0/bin/node" "/usr/local/bin/npm" "update" "-g"
npm ERR! node v6.4.0
npm ERR! npm v4.1.2
npm ERR! path /usr/local/lib/node_modules/cnpm/node_modules/agentkeepalive
npm ERR! code EACCES
npm ERR! errno -13
npm ERR! syscall access

npm ERR! Error: EACCES: permission denied, access '/usr/local/lib/node_modules/cnpm/node_modules/agentkeepalive'
npm ERR! at Error (native)
npm ERR! { Error: EACCES: permission denied, access '/usr/local/lib/node_modules/cnpm/node_modules/agentkeepalive'
npm ERR! at Error (native)
npm ERR! errno: -13,
npm ERR! code: 'EACCES',
npm ERR! syscall: 'access',
npm ERR! path: '/usr/local/lib/node_modules/cnpm/node_modules/agentkeepalive' }
npm ERR!
npm ERR! Please try running this command again as root/Administrator.

npm ERR! Please include the following file with any support request:
npm ERR! /Users/
admin/Projects/CoPilot/npm-debug.log

提示 : 解决方案是在命令前加sudo

From: Andreas Stieger andreas.stieger@gmx.de
Date: 2013-01-28 19:18:21 +0000
Subject: [PATCH] fix compiler warning about isatty()
Upstream: sent to lar@quicklz.com

Fix compiler error
qpress.cpp: In function ‘int main(int, char**)’:
qpress.cpp:1039:39: error: ‘isatty’ was not declared in this scope

1
2
3
4
5
6
7
8
9
10
--- a/qpress.cpp	2010-09-23 20:09:26.000000000 +0100
+++ b/qpress.cpp 2013-01-28 19:18:21.000000000 +0000
@@ -89,6 +89,7 @@
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
+#include <unistd.h>
#include "aio.hpp"
#include <stdarg.h>
#include <string>

via. https://build.opensuse.org/package/view_file/Archiving/qpress/qpress-1.1-isatty-include.patch?expand=1

Aliyun

MongoDB

1
2
3
4
5
[mongodb]
name=MongoDB Repository
baseurl=https://mirrors.aliyun.com/mongodb/yum/redhat/$releasever/mongodb-org/stable/x86_64/
gpgcheck=0
enabled=1

众所周知,目前的mysql版本中并不支持直接的递归查询,但是通过递归到迭代转化的思路,还是可以在一句SQL内实现树的递归查询的。这个得益于Mysql允许在SQL语句内使用@变量。以下是示例代码。

创建表格

1
2
3
4
5
CREATE TABLE `treenodes` (
`id` int , -- 节点ID
`nodename` varchar (60), -- 节点名称
`pid` int -- 节点父ID
);

插入测试数据

1
2
3
4
5
6
7
8
INSERT INTO `treenodes` (`id`, `nodename`, `pid`) VALUES
('1','A','0'),('2','B','1'),('3','C','1'),
('4','D','2'),('5','E','2'),('6','F','3'),
('7','G','6'),('8','H','0'),('9','I','8'),
('10','J','8'),('11','K','8'),('12','L','9'),
('13','M','9'),('14','N','12'),('15','O','12'),
('16','P','15'),('17','Q','15'),('18','R','3'),
('19','S','2'),('20','T','6'),('21','U','8');

查询语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 SELECT id AS ID,pid AS 父ID ,levels AS 父到子之间级数, paths AS 父到子路径 FROM (
SELECT id,pid,
@le:= IF (pid = 0 ,0,
IF( LOCATE( CONCAT('|',pid,':'),@pathlevel) > 0 ,
SUBSTRING_INDEX( SUBSTRING_INDEX(@pathlevel,CONCAT('|',pid,':'),-1),'|',1) +1
,@le+1) ) levels
, @pathlevel:= CONCAT(@pathlevel,'|',id,':', @le ,'|') pathlevel
, @pathnodes:= IF( pid =0,',0',
CONCAT_WS(',',
IF( LOCATE( CONCAT('|',pid,':'),@pathall) > 0 ,
SUBSTRING_INDEX( SUBSTRING_INDEX(@pathall,CONCAT('|',pid,':'),-1),'|',1)
,@pathnodes ) ,pid ) )paths
,@pathall:=CONCAT(@pathall,'|',id,':', @pathnodes ,'|') pathall
FROM treenodes,
(SELECT @le:=0,@pathlevel:='', @pathall:='',@pathnodes:='') vv
ORDER BY pid,id
) src
ORDER BY id;

最后的结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    ID   父ID  父到子之间级数  父到子路径
------ ------ ------------ ---------------
1 0 0 ,0
2 1 1 ,0,1
3 1 1 ,0,1
4 2 2 ,0,1,2
5 2 2 ,0,1,2
6 3 2 ,0,1,3
7 6 3 ,0,1,3,6
8 0 0 ,0
9 8 1 ,0,8
10 8 1 ,0,8
11 8 1 ,0,8
12 9 2 ,0,8,9
13 9 2 ,0,8,9
14 12 3 ,0,8,9,12
15 12 3 ,0,8,9,12
16 15 4 ,0,8,9,12,15
17 15 4 ,0,8,9,12,15
18 3 2 ,0,1,3
19 2 2 ,0,1,2
20 6 3 ,0,1,3,6
21 8 1 ,0,8

via. http://www.cnblogs.com/dukou/p/4691543.html

关于UTF-8

UTF-8 Unicode Transformation Format-8bit。是用以解决国际上字符的一种多字节编码。

它对英文使用8位(即一个字节) ,中文使用24位(三个字节)来编码。
UTF-8包含全世界所有国家需要用到的字符,是国际编码,通用性强。

UTF-8编码的文字可以在各国支持UTF8字符集额的浏览器上显示。 如果是UTF8编码,则在外国人的英文IE也能显示中文,他们无需下载IE的中文语言支持包。

关于GBK

GBK 是国家标准GB2312基础上扩容后兼容GB2312的标准。
GBK的文字编码是用双字节来表示的,即不论中、英文字符均使用双字节来表示,为了区分中文,将其最高位都设定成1。
GBK包含全部中文字符,是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBK大。

关于utf8mb4

MySql 5.5 之前,UTF8 编码只支持1-3个字节,只支持BMP这部分的unicode编码区,BMP是从哪到哪? [戳这里] (http://en.wikipedia.org/wiki/Mapping_of_Unicode_characters)基本就是 0000 ~ FFFF 这一区。

从MySQL 5.5 开始,可支持4个字节UTF编码utf8mb4,一个字符最多能有4字节,所以能支持更多的字符集。

utf8mb4 is a superset of utf8

tf8mb4兼容utf8,且比utf8能表示更多的字符。
至于什么时候用,看你做的什么项目了。。。 在做移动应用时,会遇到IOS用户在文本的区域输入emoji表情,如果不做一定处理,就会导致插入数据库异常。

汉字长度与编码有关

MySql 5.0 以上的版本:

  1. 一个汉字占多少长度与编码有关:
编码 一个汉字 一个英文
UTF-8 3字节 1字节
GBK 2字节 1字节
  1. varchar(n) 表示n个字符,无论汉字和英文,MySql都能存入 n 个字符,仅实际字节长度有所区别。

  2. MySQL检查长度,可用SQL语言

    1
    SELECT LENGTH(fieldname) FROM tablename

实际测试

首先使用utf8

创建 str_test 表。

1
2
3
4
CREATE TABLE `str_test` (
`name_chn` varchar(20) NOT NULL,
`name_en` varchar(20) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

然后插入值

1
2
mysql> insert into  str_test values ('我爱Ruby', 'I Love Ruby!');
Query OK, 1 row affected (0.02 sec)

打开irb

1
2
3
4
5
>> "我爱Ruby".size
=> 6
>> "I Love Ruby!".size
=> 12
>>

从MySQL中查询出来的结果,对比

1
2
3
4
5
6
7
mysql> select * from str_test;
+------------+--------------+
| name_chn | name_en |
+------------+--------------+
| 我爱Ruby | I Love Ruby! |
+------------+--------------+
1 row in set (0.02 sec)

UTF-8 中文是三个字节,英文是一个字节。

1
2
3
4
5
6
7
mysql> select length(name_chn) from str_test;
+------------------+
| length(name_chn) |
+------------------+
| 10 |
+------------------+
1 row in set (0.01 sec)

3[一个汉字三字节] * 2 + 1[一个英文一字节] * 4 = 10

1
2
3
4
5
6
7
mysql> select length(name_en) from str_test;
+-----------------+
| length(name_en) |
+-----------------+
| 12 |
+-----------------+
1 row in set (0.00 sec)

1[一个英文一字节] * 10 + 1[空格一字节] * 2 = 12

使用 GBK 做测试

创建表

1
2
3
4
CREATE TABLE `str_test` (
`name_chn` varchar(20) NOT NULL,
`name_en` varchar(20) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=62974 DEFAULT CHARSET=gbk

插入数据,并且测试

1
2
mysql> insert into  str_test values ('我爱Ruby', 'I Love Ruby!');
Query OK, 1 row affected (0.00 sec)
1
2
3
4
5
6
7
mysql> select * from str_test;
+------------+--------------+
| name_chn | name_en |
+------------+--------------+
| 我爱Ruby | I Love Ruby! |
+------------+--------------+
1 row in set (0.01 sec)

GBK 中文是两个字节,英文是一个字节。

1
2
3
4
5
6
7
mysql> select length(name_chn) from str_test;
+------------------+
| length(name_chn) |
+------------------+
| 8 |
+------------------+
1 row in set (0.00 sec)

2[中文两个字节] * 2 + 1[英文一个字节] * 4 = 8

1
2
3
4
5
6
7
mysql> select length(name_en) from str_test;
+-----------------+
| length(name_en) |
+-----------------+
| 12 |
+-----------------+
1 row in set (0.00 sec)

1[英文一个字节] * 10 + 1[空格一个字节] * 2 = 12

关于varchar 最多能存多少值

mysql的记录行长度是有限制的,不是无限长的,这个长度是64K,即65535个字节,对所有的表都是一样的。
MySQL对于变长类型的字段会有1-2个字节来保存字符长度。
当字符数小于等于255时,MySQL只用1个字节来记录,因为2的8次方减1只能存到255。
当字符数多余255时,就得用2个字节来存长度了。
在utf-8状态下的varchar,最大只能到 (65535 - 2) / 3 = 21844 余 1。
在gbk状态下的varchar, 最大只能到 (65535 - 2) / 2 = 32766 余 1

使用 utf-8 创建

1
2
3
4
5
mysql> CREATE TABLE `str_test` (
-> `id` tinyint(1) NOT NULL,
-> `name_chn` varchar(21845) NOT NULL
-> ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

使用gbk创建

1
2
3
4
5
mysql>     CREATE TABLE `str_test` (
-> `id` tinyint(1) NOT NULL,
-> `name_chn` varchar(21844) NOT NULL
-> ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.06 sec)

当存储长度为 32768 失败~

1
2
3
4
5
mysql> CREATE TABLE `str_test` (
-> `id` tinyint(1) NOT NULL,
-> `name_chn` varchar(32768) NOT NULL
-> ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=gbk;
ERROR 1074 (42000): Column length too big for column 'name_chn' (max = 32767); use BLOB or TEXT instead

当存储长度为 32767 失败~

1
2
3
4
5
mysql> CREATE TABLE `str_test`(
-> `id` tinyint(1) NOT NULL,
-> `name_chn` varchar(32767) NOT NULL
-> ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=gbk;
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

当存储长度为 32766 成功~

1
2
3
4
5
mysql> CREATE TABLE `str_test` (
-> `id` tinyint(1) NOT NULL,
-> `name_chn` varchar(32766) NOT NULL
-> ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=gbk;
Query OK, 0 rows affected (0.03 sec)

smallint 用两个字节存储,所以

2[smallint] + 32766 * 2[varchar GBK存储长度] + 2[2个字节来存长度] > 65535

所以失败~

1
2
3
4
5
mysql> CREATE TABLE `str_test` (
-> `id` smallint(1) NOT NULL,
-> `name_chn` varchar(32766) NOT NULL
-> ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=gbk;
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

数值类型所占的字节

类型 所占字节
int 4 字节
smallint 2 字节
tinyint 1 字节
decimal 变长

官方关于decimal 的描述如下:

Values for DECIMAL (and NUMERIC) columns are represented using a binary format that packs nine decimal (base 10) digits into four bytes.
Storage for the integer and fractional parts of each value are determined separately.
Each multiple of nine digits requires four bytes, and the “leftover” digits require some fraction of four bytes.
The storage required for excess digits is given by the following table.

翻译为中文

使用二进制格式将9个十进制(基于10)数压缩为4个字节来表示DECIMAL列值。
每个值的整数和分数部分的存储分别确定。
每个9位数的倍数需要4个字节,并且“剩余的”位需要4个字节的一部分。
下表给出了超出位数的存储需求:

> Leftover Digits Number Of Bytes
0 0
1 1
2 1
3 2
4 2
5 3
6 3
7 4
8 4

那:decimal(10,2)占几个字节?

  1. 首先 10 指的是整数与小数部分的总长度, 2指的是小数部分的长度。那么整数部分就只有 10 - 2 = 8 位
  2. 因为整数与小数的存储市各自独立确定的,所以他们各自所占用空间的综合就是所占的总空间了。
  3. 对表可知,整数部分8位占了4个字节,小数部分2位占了1个字节,所以decimal(10,2)总共占了 4 + 1 = 5 个字节。
  4. decimal(6,2) 整数部分(6 - 2 = 4) 位占2字节,小数部分2位占1字节,总共占3字节。

总结

varchar 字段是将实际内容单独存储在聚簇索引之外,内容开头用1到2个字节表示实际长度(长度超过255时需要2个字节),因此最大长度不能超过65535。

在utf-8状态下,汉字最多可以存 21844个字符串, 英文也为 21844个字符串。

在gbk状态下,汉字最多可以存 32766个字符串,英文也为 32766个字符串。

参考

mysql utf8mb4与emoji表情
关于GBK、GB2312、UTF8
阿里云 Rails 项目调整 RDS MySQL 编码为 utf8mb4 的详细步骤
MySQL下varchar类型最大长度是多少

via. https://ruby-china.org/topics/24920

无法打开新数据库 ‘Dong’。CREATE DATABASE 中止。
文件激活失败。物理文件名称’E:\SqlServer\MSSQL\Data\Dong_log.LDF’可能不正确。

无法重新生成日志,原因是数据库关闭时存在打开的事务/用户,该数据库没有检查点或者该数据库是只读的。如果事务日志文件被手动删除或者由于硬件或环境问题而丢失,则可能出现此错误。 (Microsoft SQL Server,错误: 1813)

解决方案:

  1. 新建一个同名数据库。

  2. 停止数据库服务,覆盖新建的数据库主文件(小技巧:最好放在同一个磁盘里面,把新建的数据库主文件删掉或移开,再把要恢复的数据库主文件剪切过去,这样就可以节省时间。)

  3. 启动数据库服务,数据库变为置疑或可疑状态。然后在查询分析器中运行:

    1
    alter database 无日志文件的数据库名称 set emergency

    设置为紧急状态。

  4. 再运行:

    1
    alter database 无日志文件的数据库名称 set single_user

    或者:

    1
    Sp_dboption '无日志文件的数据库名称', 'single user', 'true'

    设置为单用户模式。

  5. 检查并重建日志文件,运行:

    1
    dbcc checkdb('无日志文件的数据库名称',REPAIR_ALLOW_DATA_LOSS)

    这个时间比较长。耐心等待!如果有错误提示,再运行:

    1
    dbcc checkdb('无日志文件的数据库名称',REPAIR_REBUILD)

    进行修复。如果没有错误,可以跳过。

  6. 恢复成多用户模式

    1
    alter database 无日志文件的数据库名称 set multi_user

    或者:

    1
    Sp_dboption '无日志文件的数据库名称', 'single user', 'false'

    刷新数据库,你就可以看到已经修复好的数据库了。

via. http://www.cnblogs.com/lyl6796910/p/3628066.html