根本原因

  • 此错误消息表示您没有受信任的证书,例如,如果在安装期间未提供证书,则由DTR生成的默认自签名证书。

解决方案

  • 连接的时候不验证服务端证书
    import (
      "crypto/tls"
      "net/http"
    )
    func main() {
        transport := &http.Transport{
            TLSClientConfig:    &tls.Config{
                InsecureSkipVerify: true//true不验证服务器证书
            },
        }
        client := &http.Client{Transport: transport}
        resp, err := client.Get("https://www.timiguo.com:8081")
    }
  • 在dockerfile里更新证书
  RUN apk update \
        && apk upgrade \
        && apk add --no-cache \
        ca-certificates \
        && update-ca-certificates 2>/dev/null || true
  • 挂在系统证书目录
    golang查找公共根证书的路径,根据自己的系统挂在对应目录上去即可
"/etc/ssl/certs/ca-certificates.crt",                // Debian/Ubuntu/Gentoo etc.
"/etc/pki/tls/certs/ca-bundle.crt",                  // Fedora/RHEL 6
"/etc/ssl/ca-bundle.pem",                            // OpenSUSE
"/etc/pki/tls/cacert.pem",                           // OpenELEC
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
"/etc/ssl/certs",               // SLES10/SLES11
"/system/etc/security/cacerts", // Android
"/usr/local/share/certs",       // FreeBSD
"/etc/pki/tls/certs",           // Fedora/RHEL
"/etc/openssl/certs",           // NetBSD

  • RSA和DH都基于非对称算法。
  • RSA: 常用的示例是Alice向Bob发送消息,并使用Bob的公钥加密消息。向Bob发送消息。鲍勃用他的私钥解密。验证签名以确保Alice发送签名。该消息将成为对称加密密钥。这是用于保护连接的内容。
  • DH Diffie Hellman交换依赖于生成秘密值的两个单独实体。通过一些数学算法,他们都能够产生共同的密钥值。这是一个对称密钥。
  • 使用RSA,可以进行加密和签名的密钥对。使用DH,只执行加密,没有签名机制。

  • 主键一定会创建一个唯一索引,但是有唯一索引的列不一定是主键;
  • 主键不允许为空值,唯一索引列允许空值;
  • 一个表只能有一个主键,但是可以有多个唯一索引;
  • 主键可以被其他表引用为外键,唯一索引列不可以;
  • 主键是一种约束,而唯一索引是一种索引,是表的冗余数据结构,两者有本质的差别

https证书签发与认证

签发证书的步骤:

  • Signing阶段,首先撰写证书的元信息:签发人、地址、签发时间、过期失效等等;
  • 通过通用的hash算法将信息摘要提取出来;
  • Hash摘要通过签发者的私钥进行非对称加密,生成一个签名密文;
  • 将签名密文attach到文件证书上,使之变成一个签名过的证书。

验证证书的步骤:

  • Verification阶段,浏览器获得之前签发的证书;
  • 将其解压后分别获得“元数据”和“签名密文”;
  • 将同样的Hash算法应用到“元数据”获取摘要;
  • 将密文通过公钥(非对称算法,私钥加密,公钥解密)解密获得同样的摘要值。
  • 在这里的签名密文是一个重要凭证,Signature与签发人的公钥一同传输,可以避免中间人在获取证书时对证书内容的篡改。

通过CA,可以保证server提供的公钥(public key)不被proxy篡改,否则签发“元信息”不满足信任链(Chain of trust),会被浏览器识别为“不安全”的。

有关信任链的验证流程,可以参考下图:
信任链的验证流程

在redis3.2之前,sds只有一个类型,定义如下:

struct sdshdr {
    unsigned int len;//表示sds当前的长度
    unsigned int free;//已为sds分配的长度-sds当前的长度
    char buf[];//sds实际存放的位置
};

3.2开始改成如下

struct __attribute__ ((__packed__)) sdshdr5 {
    //实际上这个类型redis不会被使用。他的内部结构也与其他sdshdr不同,直接看sdshdr8就好。
    unsigned char flags; //一共8位,低3位用来存放真实的flags(类型),高5位用来存放len(长度)。
    char buf[];//sds实际存放的位置
};
struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len;//表示当前sds的长度(单位是字节)
    uint8_t alloc; //表示已为sds分配的内存大小(单位是字节)
    unsigned char flags; //用一个字节表示当前sdshdr的类型,因为有sdshdr有五种类型,所以至少需要3位来表示000:sdshdr5,001:sdshdr8,010:sdshdr16,011:sdshdr32,100:sdshdr64。高5位用不到所以都为0。
    char buf[];//sds实际存放的位置
};
struct __attribute__ ((__packed__)) sdshdr16 {
    uint16_t len; /* used */
    uint16_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
    uint32_t len; /* used */
    uint32_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
    uint64_t len; /* used */
    uint64_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};

flags用来判断是什么类型,只需 flags&SDS_TYPE_MASK和SDS_TYPE_n比较即可(之所以需要SDS_TYPE_MASK是因为有sdshdr5这个特例,它的高5位不一定为0
不同长度的字符串用不同的结构体,例如100byte的用sdshdr8,主要是看2^8字节长度用sdshdr8,2^16字节长度用sdshdr16,以此类推
根据len能知道字符串长度,而不用每次都遍历才能知道长度
根据长度,可以存储二进制数据,而不单单存字符串,因为在c语言里,0表示字符串结束,所以如果二进制数据中有0的话,就会表示读取结束,知道长度就可以这么用

memcpy(s, init, initlen); //memcpy不会因为'\0'而停下,支持二进制数据的拷贝

sds加长内存分配规则,如图所示
sds加长和缩短内存分配规则
加长的时候,字符串最终长度如果小于SDS_MAX_PREALLOC,就以当前长度的2倍扩增,如果大于等于SDS_MAX_PREALLOC,给以SDS_MAX_PREALLOC递增,其中SDS_MAX_PREALLOC在sds.h里默认是1mb
如果扩充后的sdshdr类型不变,则在原有的地方realloc就好。因为len和alloc的类型还是原来的。
如果扩充后的sdshdr类型变了,那就只能重新在别的地方分配内存,然后重新赋值,释放掉旧的内存。

sds缩减的话,有三个函数:sdsclear、sdstrim、sdsrange,他们都不会改变alloc的大小即不会释放任何内存,这就是sds字符串内存管理的一种方式:惰性释放。额外调用sdsRemoveFreeSpace释放内存,这样就节省了每次sds缩减长度而导致的内存释放开销。sdsRemoveFreeSpace这个函数压缩内存,让alloc=len。如果type变小了,则另开一片内存复制,重新执行sds加长操作,如果type不变,则realloc