Fork me on GitHub

network

network

概念

  • 安全和幂等

在 HTTP 协议里,所谓的「安全」是指请求方法不会「破坏」服务器上的资源。
所谓的「幂等」,意思是多次执行相同的操作,结果都是「相同」的。

GET方法 安全且幂等,POST方法不安全也不幂等。

SSL 是洋文 “Secure Sockets Layer 的缩写,中文叫做「安全套接层」。它是在上世纪 90 年代中期,由网景公司设计的。到了1999年,SSL 因为应用广泛,已经成为互联网上的事实标准。IETF 就在那年把 SSL 标准化。标准化之后的名称改为 TLS(是 “Transport Layer Security” 的缩写),中文叫做 「传输层安全协议」。

TCP/IP网络模型

对于同一台设备上的进程间通信,有很多种方式,比如有管道、消息队列、共享内存、信号等方式,而对于不同设备上的进程间通信,就需要网络通信,而设备是多样性的,所以要兼容多种多样的设备,就协商出了一套通用的网络协议。

应用层(Application Layer)

应用层是工作在操作系统中的用户态,传输层及以下则工作在内核态。

传输层(Transport Layer)

在传输层会有两个传输协议,分别是 TCP 和 UDP。
TCP 的全称叫传输层控制协议(Transmission Control Protocol),大部分应用使用的正是 TCP 传输层协议,比如 HTTP 应用层协议。TCP 相比 UDP 多了很多特性,比如流量控制、超时重传、拥塞控制等,这些都是为了保证数据包能可靠地传输给对方。
UDP 就相对很简单,简单到只负责发送数据包,不保证数据包是否能抵达对方,但它实时性相对更好,传输效率也高。当然,UDP 也可以实现可靠传输,把 TCP 的特性在应用层上实现就可以,不过要实现一个商用的可靠 UDP 传输协议,也不是一件简单的事情。
应用需要传输的数据可能会非常大,如果直接传输就不好控制,因此当传输层的数据包大小超过 MSS(TCP 最大报文段⻓度) ,就要将数据包分块,这样即使中途有一个分块丢失或损坏了,只需要重新这一个分块,而不用重新发送整个数据包。在 TCP 协议中,我们把每个分块称为一个 TCP 段(TCP Segment)

网络层(Internet Layer)

网络层最常使用的是 IP 协议(Internet Protocol),IP 协议会将传输层的报文作为数据部分,再加上 IP 包头组装成 IP 报文,如果 IP 报文大小超过 MTU(以太网中一般为 1500 字节)就会再次进行分片,得到一个即将发送到网络的 IP 报文。

需要将 IP 地址分成两种意义:
一个是网络号,负责标识该 IP 地址是属于哪个子网的;
一个是主机号,负责标识同一子网下的不同主机;
怎么分的呢?这需要配合子网掩码才能算出 IP 地址 的网络号和主机号。那么在寻址的过程中,先匹配到相同的网络号,才会去找对应的主机。
除了寻址能力, IP 协议还有另一个重要的能力就是路由。实际场景中,两台设备并不是用一条网线连接起来的,而是通过很多网关、路由器、交换机等众多网络设备连接起来的,那么就会形成很多条网络的路径,因此当数据包到达一个网络节点,就需要通过算法决定下一步走哪条路径。所以,IP 协议的寻址作用是告诉我们去往下一个目的地该朝哪个方向走,路由则是根据「下一个目的地」选择路径。寻址更像在导航,路由更像在操作方向盘。

路由器怎么知道这个 IP 地址是哪个设备的呢?
于是,就需要有一个专⻔的层来标识网络中的设备,让数据在一个链路中传输,这就是数据链路层(Data Link Layer),它主要为网络层提供链路级别传输的服务。

每一台设备的网卡都会有一个 MAC 地址,它就是用来唯一标识设备的。路由器计算出了下一个目的地 IP 地址,再通过 ARP 协议找到该目的地的 MAC 地址,这样就知道这个 IP 地址是哪个设备的了。

物理层(Physical Layer)

当数据准备要从设备发送到网络时,需要把数据包转换成电信号,让其可以在物理介质中传输,这一层就是物理层(Physical Layer),它主要是为数据链路层提供二进制传输的服务。

HTTP(HyperText Transfer Protocol)

问题

释义

HTTP的名字「超文本协议传输」,它可以拆成三个部分:

  • 超文本
  • 传输
  • 协议

「协」字,代表的意思是必须有两个以上的参与者。例如三方协议里的参与者有三个:你、公司、学校三个;租房协议里的参与者有两个:你和房东。
「议」字,代表的意思是对参与者的一种行为约定和规范。例如三方协议里规定试用期期限、毁约金等;租房协议里规定租期期限、每月租金金额、违约如何处理等。

OK,经过了对 HTTP 里这三个名词的详细解释,就可以给出比「超文本传输协议」这七个字更准确更有技术含量
的答案:
HTTP 是一个在计算机世界里专⻔在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」。

状态码

1xx 类状态码属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。
2xx 类状态码表示服务器成功处理了客户端的请求,也是我们最愿意看到的状态。
「200 OK」是最常⻅的成功状态码,表示一切正常。如果是非 HEAD 请求,服务器返回的响应头都会有 body 数据。
「204 No Content」也是常⻅的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据。

「206 Partial Content」是应用于 HTTP 分块下载或断点续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。
3xx 类状态码表示客户端请求的资源发送了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向。
「301 Moved Permanently」表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。
「302 Found」表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。
301 和 302 都会在响应头里使用字段 Location ,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。
「304 Not Modified」不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,用于缓存控制。
4xx 类状态码表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。
「400 Bad Request」表示客户端请求的报文有错误,但只是个笼统的错误。
「403 Forbidden」表示服务器禁止访问资源,并不是客户端的请求出错。
「404 Not Found」表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端。
5xx 类状态码表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码。
「500 Internal Server Error」与 400 类型,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道。
「501 Not Implemented」表示客户端请求的功能还不支持,类似“即将开业,敬请期待”的意思。
「502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。
「503 Service Unavailable」表示服务器当前很忙,暂时无法响应服务器,类似“网络服务正忙,请稍后重试”的意思。

连接

http三次握手建立连接

建立 TCP 连接需要三次握手:

  1. 客户端想要连接服务端时,向服务端发送 SYN message。Message 还包含 sequence number(32位的随机数),ACK 为0,window size、最大 segment 大小。例如,如果 window size 是 2000 bits,最大 segment 大小是 200 bits,则最大可传输 segments 是 10 data。
  2. 服务端收到客户端 synchronization request 后,回复客户端 SYN 和 ACK。ACK 数值是收到的 SYN 加一。例如客户端发送的 SYN 是 1000,则服务端回复的 ACK 是 1001。如果服务端也想建立连接,回复中还会包括一个 SYN,这里的 SYN 是另一随机数,与客服端的 SYN 不相同。这一阶段完成时,客户端与服务端的连接已经建立。
  3. 收到服务端的 SYN 后,客户端回复 ACK,ACK 值是 SYN 值加一。这一过程完成后,服务端与客户端的连接也建立了起来。

TCP 连接的双方通过三次握手确定 TCP 连接的初始序列号、窗口大小以及最大数据段,这样通信双方就能利用连接中的初始序列号保证双方数据段的不重不漏,通过窗口大小控制流量,并使用最大数据段避免 IP 协议对数据包分片。

换个角度看为什么需要三次握手?客户端和服务端通信前要进行连接,三次握手就是为了确保自己和对方的收发能力是正常的。

  1. 第一次握手:客户端发送、服务端接收网络包,服务端可以得出:客户端发送能力、服务端接收能力是正常的。
  2. 第二次握手:服务端发送、客户端接收网络包。从客户端的视角来看,我接收到了服务端发送的响应数据包,说明服务端收到了第一次握手时我发出的网络包,且收到请求后进行了响应,这说明服务端的接收、发送能力正常,我的发送、接收能力正常。
  3. 第三次握手:客户端发送、服务端接收网络包,这样服务端就能得出结论:客户端的接收、发送能力正常,服务端的发送、接收能力正常。第一次、二次握手后,服务端并不知道客户端的接收能力,以及自己的发送能力是否正常。第三次握手后,这些能力才得以确认。

三次握手后,客户端、服务端才确认了自己的接收、发送能力均是正常的。

HTTPS四次握手建立连接

SSL/TLS 1.2 需要 4 握手,需要 2 个 RTT 的时延,我文中的图是把每个交互分开画了,实际上把他们合在一起发送,就是 4 次握手。

另外, SSL/TLS 1.3 优化了过程,只需要 1 个 RTT 往返时延,也就是只需要 3 次握手:

SSL/TLS 协议建立的详细流程:

  1. ClientHello
    首先,由客户端向服务器发起加密通信请求,也就是 ClientHello 请求。在这一步,客户端主要向服务器发送以下信息:
    (1)客户端支持的 SSL/TLS 协议版本,如 TLS 1.2 版本。
    (2)客户端生产的随机数( Client Random ),后面用于生产「会话秘钥」。
    (3)客户端支持的密码套件列表,如 RSA 加密算法。
  2. SeverHello
    服务器收到客户端请求后,向客户端发出响应,也就是 SeverHello 。服务器回应的内容有如下内容:
    (1)确认 SSL/ TLS 协议版本,如果浏览器不支持,则关闭加密通信。
    (2)服务器生产的随机数( Server Random ),后面用于生产「会话秘钥」。
    (3)确认的密码套件列表,如 RSA 加密算法。
    (4)服务器的数字证书。
  3. 客户端回应
    客户端收到服务器的回应之后,首先通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书的真实性。如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后使用它加密报文,向服务器发送如下信息:
    (1)一个随机数( pre-master key )。该随机数会被服务器公钥加密。
    (2)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。
    (3)客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供服务端校验。

上面第一项的随机数是整个握手阶段的第三个随机数,这样服务器和客户端就同时有三个随机数,接着就用双方协商的加密算法,各自生成本次通信的「会话秘钥」。

  1. 服务器的最后回应
    服务器收到客户端的第三个随机数( pre-master key )之后,通过协商的加密算法,计算出本次通信的「会话秘钥」。然后,向客户端发生最后的信息:
    (1)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。
    (2)服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供客户端校验。
    至此,整个 SSL/TLS 的握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的 HTTP 协议,只不过用「会话秘钥」加密内容。

HTTP/1.1、HTTP/2、HTTP/3 演变

HTTP

缺点
  • 无状态(优缺点),无法完成关联性操作。-Cookie技术
  • 短连接
  • 不安全
    • 明文传输,容易泄露信息
    • 篡改,无法保证数据完整性
    • 伪造,无法验证通信方身份

HTTP/1.1改善

长连接

期 HTTP/1.0 性能上的一个很大的问题,那就是每发起一个请求,都要新建一次 TCP 连接(三次握手),而且是串行请求,做了无谓的 TCP 连接建立和断开,增加了通信开销。

HTTP/1.1 提出了⻓连接的通信方式,也叫持久连接。这种方式的好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载

持久连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。

管道传输

即可在同一个 TCP 连接里面,客户端可以发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间

问题:但是服务器还是按照顺序,先回应 A 请求,完成后再回应 B 请求。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为「队头堵塞」。

HTTP 与 HTTPS 有哪些区别?
  1. HTTP 是超文本传输协议,信息是明文传输,存在安全⻛险的问题。HTTPS 则解决 HTTP 不安全的缺陷,在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。
  2. HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而 HTTPS 在 TCP 三次握手之后,还需进行 SSL/TLS 的四次握手过程,才可进入加密报文传输。
  3. HTTP 的端口号是 80,HTTPS 的端口号是 443。
  4. HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。
HTTPS 解决了 HTTP 的哪些问题?

HTTP 由于是明文传输,所以安全上存在以下三个⻛险:

  • 窃听⻛险,比如通信链路上可以获取通信内容,用户号容易没。
  • 篡改⻛险,比如强制植入垃圾广告,视觉污染,用户眼容易瞎。
  • 冒充⻛险,比如冒充淘宝网站,用户钱容易没。

TTPS 在 HTTP 与 TCP 层之间加入了 SSL/TLS 协议,可以很好的解决了上述的⻛险:

  • 信息加密:交互信息无法被窃取,但你的号会因为「自身忘记」账号而没。
  • 校验机制:无法篡改通信内容,篡改了就不能正常显示,但百度「竞价排名」依然可以搜索垃圾广告。
  • 身份证书:证明淘宝是真的淘宝网,但你的钱还是会因为「剁手」而没。

HTTPS 是如何解决上面的三个⻛险的?

  • 混合加密的方式实现信息的机密性,解决了窃听的⻛险。
  • 摘要算法的方式来实现完整性,它能够为数据生成独一无二的「指纹」,指纹用于校验数据的完整性,解决了篡改的⻛险。
  • 将服务器公钥放入到数字证书中,解决了冒充的⻛险
混合加密

HTTPS 采用的是对称加密和非对称加密结合的「混合加密」方式:

  • 在通信建立前采用非对称加密的方式交换「会话秘钥」,后续就不再使用非对称加密。
  • 在通信过程中全部使用对称加密的「会话秘钥」的方式加密明文数据。
    采用「混合加密」的方式的原因:
  • 对称加密只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换。
  • 非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但速度慢。
摘要算法
数字证书

客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密。
这就存在些问题,如何保证公钥不被篡改和信任度?

这里就需要借助第三方权威机构 CA (数字证书认证机构),将服务器公钥放在数字证书(由数字证书认证机构颁发)中,只要证书是可信的,公钥就是可信的。

其他改善方法
合并请求
  • 有的网⻚会含有很多小图片、小图标,有多少个小图片,客户端就要发起多少次请求。那么对于这些小图片,我们可以考虑使用 CSS Image Sprites 技术把它们合成一个大图片,这样浏览器就可以用一次请求获得一个大图片,然后再根据 CSS 数据把大图片切割成多张小图片。
  • 还有服务端使用 webpack 等打包工具将 js、css 等资源合并打包成大文件,也是能达到类似的效果。
  • 还可以将图片的二进制数据用 base64 编码后,以 URL 的形式潜入到 HTML 文件,跟随 HTML 文件一并发送。
延迟发送请求
  • 请求网⻚的时候,没必要把全部资源都获取到,而是只获取当前用户所看到的⻚面资源,当用户向下滑动⻚面的时候,再向服务器获取接下来的资源,这样就达到了延迟发送请求的效果。
减小数据大小

无损压缩:无损压缩是指资源经过压缩后,信息不被破坏,还能完全恢复到压缩前的原样,适合用在文本文件、程序可执行文件、程序源代码。霍夫曼编码、gzip。

有损压缩:有损压缩主要将次要的数据舍弃,牺牲一些质量来减少数据量、提高压缩比,这种方法经常用于压缩多媒体数据,比如音频、视频、图片。q 质量因子, H264、H265。

HTTP/1.0缺点
  • 请求 / 响应头部(Header)未经压缩就发送,首部信息越多延迟越大。只能压缩 Body 的部分;
  • 发送冗⻓的首部。每次互相发送相同的首部造成的浪费较多;
  • 服务器是按请求的顺序响应的,如果服务器响应慢,会招致客户端一直请求不到数据,也就是队头阻塞;
  • 没有请求优先级控制;
  • 请求只能从客户端开始,服务器只能被动响应。

HTTP/2改善

HTTP/2 协议是基于 HTTPS 的,所以 HTTP/2 的安全性也是有保障的

头部压缩

HTTP/2 会压缩头(Header)如果你同时发出多个请求,他们的头是一样的或是相似的,那么,协议会帮你消除重复的部分。
这就是所谓的 HPACK 算法:在客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。

二进制格式

HTTP/2 不再像 HTTP/1.1 里的纯文本形式的报文,而是全面采用了二进制格式,头信息和数据体都是二进制,并且统称为帧(frame):头信息帧和数据帧。

收到报文后,无需再将明文的报文转成二进制,而是直接解析二进制报文,这增加了数据传输的效率

数据流

HTTP/2 的数据包不是按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。
每个请求或回应的所有数据包,称为一个数据流( Stream )。每个数据流都标记着一个独一无二的编号,其中规定客户端发出的数据流编号为奇数, 服务器发出的数据流编号为偶数。
客户端还可以指定数据流的优先级。优先级高的请求,服务器就先响应该请求。

多路复用

HTTP/2 是可以在一个连接中并发多个请求或回应,而不用按照顺序一一对应。
移除了 HTTP/1.1 中的串行请求,不需要排队等待,也就不会再出现「队头阻塞」问题,降低了延迟,大幅度提高了连接的利用率
举例来说,在一个 TCP 连接里,服务器收到了客户端 A 和 B 的两个请求,如果发现 A 处理过程非常耗时,于是就回应 A 请求已经处理好的部分,接着回应 B 请求,完成后,再回应 A 请求剩下的部分。

服务器推送

HTTP/2 还在一定程度上改善了传统的「请求 - 应答」工作模式,服务不再是被动地响应,也可以主动向客户端发送消息。
举例来说,在浏览器刚请求 HTML 的时候,就提前把可能会用到的 JS、CSS 文件等静态资源主动发给客户端,减少延时的等待,也就是服务器推送(Server Push,也叫 Cache Push)。

HTTP/2缺陷

HTTP/2 主要的问题在于,多个 HTTP 请求在复用一个 TCP 连接,下层的 TCP 协议是不知道有多少个 HTTP 请求的。所以一旦发生了丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传回来。
HTTP/1.1 中的管道( pipeline)传输中如果有一个请求阻塞了,那么队列后请求也统统被阻塞住了。
HTTP/2 多个请求复用一个TCP连接,一旦发生丢包,就会阻塞住所有的 HTTP 请求。

HTTP/3改善

这都是基于 TCP 传输层的问题,所以 HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP!

UDP 发生是不管顺序,也不管丢包的,所以不会出现 HTTP/1.1 的队头阻塞 和 HTTP/2 的一个丢包全部重传问题。
UDP 是不可靠传输的,但基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠性传输。

  • QUIC 有自己的一套机制可以保证传输的可靠性的。当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响。
  • TLS3 升级成了最新的 1.3 版本,头部压缩算法也升级成了 QPack 。
  • HTTPS 要建立一个连接,要花费 7 次交互,先是建立三次握手,然后是 TLS/1.3 的四次握手。QUIC 直接把以往的 TCP 和 TLS/1.3 的 7 次交互合并成了 3 次,减少了交互次数

所以, QUIC 是一个在 UDP 之上的伪 TCP + TLS + HTTP/2 的多路复用的协议。

TCP

IP

实现主机与主机之间的通信,也叫点对点(end to end)通信.MAC 的作⽤则是实现「直连」的两个设备 之间通信,⽽ IP 则负责在「没有直连」的两个⽹络之间进⾏通信传输。

源IP地址和⽬标IP地址在传输过程中是不会变化的,只有源 MAC 地址和⽬标 MAC ⼀直在变化.

⽆分类地址 CIDR(无类域间路由(Classless Inter-Domain Routing,CIDR))

正因为 IP 分类存在许多缺点,所以后⾯提出了⽆分类地址的⽅案,即 CIDR 。
这种⽅式不再有分类地址的概念,32 ⽐特的 IP 地址被划分为两部分,前⾯是⽹络号,后⾯是主机号。怎么划分⽹络号和主机号的呢?
表示形式 a.b.c.d/x ,其中 /x 表示前 x 位属于⽹络号, x 的范围是 0 ~ 32 ,这就使得 IP 地址更加具有灵活性。
⽐如 10.100.122.2/24,这种地址表示形式就是 CIDR,/24 表示前 24 位是⽹络号,剩余的 8 位是主机号.

本地地址(环回地址)

环回地址是不会流向⽹络的。

环回地址是在同⼀台计算机上的程序之间进⾏⽹络通信时所使⽤的⼀个默认地址。

计算机使⽤⼀个特殊的 IP 地址 127.0.0.1 作为环回地址。与该地址具有相同意义的是⼀个叫做 localhost 的主机 名。使⽤这个 IP 或主机名时,数据包不会流向⽹络。

IPV6

标识

IPv4 地址⻓度共 32 位,是以每 8 位作为⼀组,并⽤点分⼗进制的表示⽅式。

IPv6 地址⻓度是 128 位,是以每 16 位作为⼀组,每组⽤冒号 「:」 隔开。

如果出现连续的 0 时还可以将这些 0 省略,并⽤两个冒号 「::」隔开。但是,⼀个 IP 地址中只允许出现⼀次两个 连续的冒号。

包结构

相关协议

DNS 域名解析

ARP与RARP协议

DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)

DHCP,Dynamic Host Configuration Protocol,动态主机配置协议,简单来说就是主机获取IP地址的过程,属于应用层协议。
DHCP采用UDP的68(客户端)和67(服务器)端口进行通信。

DHCP过程主要为DHCP Discover–>DHCP Offer–>DHCP Request–>DHCP Ack四个过程。

C:\Users\25433>ipconfig /release

C:\Users\25433>ipconfig /renew

可以发现,DHCP 交互中,全程都是使用 UDP 广播通信

用的是广播,那如果 DHCP 服务器和客户端不是在同一个局域网内,路由器又不会转发广播包,那不是每个网络都要配一个 DHCP 服务器?

所以,为了解决这一问题,就出现了 DHCP 中继代理。有了 DHCP 中继代理以后,对不同网段的 IP 地址分配也可以由一个 DHCP 服务器统一进行管理。

DHCP 客户端会向 DHCP 中继代理发送 DHCP 请求包,⽽ DHCP 中继代理在收到这个⼴播包以后,再以单播 的形式发给 DHCP 服务器。

服务器端收到该包以后再向 DHCP 中继代理返回应答,并由 DHCP 中继代理将此包⼴播给 DHCP 客户端 。

因此,DHCP 服务器即使不在同⼀个链路上也可以实现统⼀分配和管理IP地址。

NAT网络地址转换

ICMP

ICMP 全称是 Internet Control Message Protocol,也就是互联网控制报文协议

ICMP 主要的功能包括:确认 IP 包是否成功送达目标地址、报告发送过程中 IP 包被废弃的原因和改善网络设置等。

IP 通信中如果某个 IP 包因为某种原因未能达到目标地址,那么这个具体的原因将由 ICMP 负责通知

ICMP 包头的类型字段,大致可以分为两大类:

  • 一类是用于诊断的查询消息,也就是「查询报文类型
  • 另一类是通知出错原因的错误消息,也就是「差错报文类型

选项数据中,ping 还会存放发送请求的时间值,来计算往返时间,说明路程的长短。

a. 网络不可达代码为 0

IP 地址是分为网络号和主机号的,所以当路由器中的路由器表匹配不到接收方 IP 的网络号,就通过 ICMP 协议以网络不可达Network Unreachable)的原因告知主机。

自从不再有网络分类以后,网络不可达也渐渐不再使用了。

b. 主机不可达代码为 1

当路由表中没有该主机的信息,或者该主机没有连接到网络,那么会通过 ICMP 协议以主机不可达Host Unreachable)的原因告知主机。

c. 协议不可达代码为 2

当主机使用 TCP 协议访问对端主机时,能找到对端的主机了,可是对端主机的防火墙已经禁止 TCP 协议访问,那么会通过 ICMP 协议以协议不可达的原因告知主机。

d. 端口不可达代码为 3

当主机访问对端主机 8080 端口时,这次能找到对端主机了,防火墙也没有限制,可是发现对端主机没有进程监听 8080 端口,那么会通过 ICMP 协议以端口不可达的原因告知主机。

e. 需要进行分片但设置了不分片位代码为 4

发送端主机发送 IP 数据报时,将 IP 首部的分片禁止标志位设置为1。根据这个标志位,途中的路由器遇到超过 MTU 大小的数据包时,不会进行分片,而是直接抛弃。

随后,通过一个 ICMP 的不可达消息类型,代码为 4 的报文,告知发送端主机。

原点抑制消息(ICMP Source Quench Message) —— 类型 4

在使用低速广域线路的情况下,连接 WAN 的路由器可能会遇到网络拥堵的问题。

ICMP 原点抑制消息的目的就是为了缓和这种拥堵情况

当路由器向低速线路发送数据时,其发送队列的缓存变为零而无法发送出去时,可以向 IP 包的源地址发送一个 ICMP 原点抑制消息

收到这个消息的主机借此了解在整个线路的某一处发生了拥堵的情况,从而增大 IP 包的传输间隔,减少网络拥堵的情况。

然而,由于这种 ICMP 可能会引起不公平的网络通信,一般不被使用。

重定向消息(ICMP Redirect Message) —— 类型 5

如果路由器发现发送端主机使用了「不是最优」的路径发送数据,那么它会返回一个 ICMP 重定向消息给这个主机。

在这个消息中包含了最合适的路由信息和源数据。这主要发生在路由器持有更好的路由信息的情况下。路由器会通过这样的 ICMP 消息告知发送端,让它下次发给另外一个路由器。

超时消息(ICMP Time Exceeded Message) —— 类型 11

IP 包中有一个字段叫做 TTLTime To Live,生存周期),它的值随着每经过一次路由器就会减 1,直到减到 0 时该 IP 包会被丢弃。

此时,IP 路由器将会发送一个 ICMP 超时消息给发送端主机,并通知该包已被丢弃。

设置 IP 包生存周期的主要目的,是为了在路由控制遇到问题发生循环状况时,避免 IP 包无休止地在网络上被转发。

ICMP 时间超过消息

此外,有时可以用 TTL 控制包的到达范围,例如设置一个较小的 TTL 值

ping

在规定的时候间内,源主机如果没有接到 ICMP 的应答包,则说明目标主机不可达;如果接收到了 ICMP 回送响应消息,则说明目标主机可达。

此时,源主机会检查,用当前时刻减去该数据包最初从源主机上发出的时刻,就是 ICMP 数据包的时间延迟。

ping 这个程序是使用了 ICMP 里面的 ECHO REQUEST(类型为 8 ) 和 ECHO REPLY (类型为 0)

traceroute

有一款充分利用 ICMP 差错报文类型的应用叫做 traceroute(在UNIX、MacOS中是这个命令,而在Windows中对等的命令叫做 tracert )

它的原理就是利用 IP 包的生存期限 从 1 开始按照顺序递增的同时发送 UDP 包,强制接收 ICMP 超时消息的一种方法。

比如,将 TTL 设置 为 1,则遇到第一个路由器,就牺牲了,接着返回 ICMP 差错报文网络包,类型是时间超时。

接下来将 TTL 设置为 2,第一个路由器过了,遇到第二个路由器也牺牲了,也同意返回了 ICMP 差错报文数据包,如此往复,直到到达目的主机。

这样的过程,traceroute 就可以拿到了所有的路由器 IP。

traceroute 在发送 UDP 包时,会填入一个不可能的端口号值作为 UDP 目标端口号(大于 3000 )。当目的主机,收到 UDP 包后,会返回 ICMP 差错报文消息,但这个差错报文消息的类型「端口不可达」。

所以,当差错报文类型是端口不可达时,说明发送方发出的 UDP 包到达了目的主机

IGMP 因特网组管理协议

示例

当键入网址后,到网页显示,其间发生了什么???

  1. url
  1. dns
  1. tcp
  1. ip路由

在网络包传输的过程中,源 IP 和目标 IP 始终是不会变的,一直变化的是 MAC 地址,因为需要 MAC 地址在以太网内进行两个设备之间的包传输。

参考

计算机网络微课堂视频

python

python

使用

Python开机自动运行

假如Python自启动脚本auto.py。那么用root权限编辑以下文件:

1
sudo vim /etc/rc.local

如果没有rc.local请看这篇文章

在exit 0上面编辑启动脚本的命令

1
/usr/bin/python3 /home/selfcs/auto.py > /home/selfcs/auto.log

最后重启Linux,脚本就能自动运行并打印日志了

让Python脚本定时启动

用root权限编辑以下文件

1
sudo vim /etc/crontab

在文件末尾添加以下命令

1
2 * * * * root /usr/bin/python3 /home/selfcs/auto.py > /home/selfcs/auto.log

以上代码的意思是每隔两分钟执行一次脚本并打印日志。

python搭建简易文件服务器

1
/usr/bin/python3 -m http.server --directory=/home/dxshelley/downloads/ 9090 > /home/dxshelley/log/pythonserver.log

sql调优

sql调优

概念

SQL语句执行步骤

语法分析> 语义分析> 视图转换 >表达式转换> 选择优化器 >选择连接方式 >选择连接顺序 >选择数据的搜索路径 >运行“执行计划”。

Oracle优化器

选用适合的Oracle优化器RULE(基于规则)、 COST(基于成本) 、CHOOSE(选择性)

共享 SQL 语句

全表扫描 与 索引扫描

表连接类型

咱写 sql 语句时,表之间的关联关系

(1) 内连接 inner join,简写 join
(2) 左连接 left join
(3) 右连接 right join
(4) 全连接 full join

红色:表连接后的结果集:

表连接方式

执行计划里面的表连接方式.

(1) 嵌套循环 nested loops
(2) 哈希连接 hash join
(3) 排序合并连接 sort merge join
(4) 笛卡尔积 cartesian product

Driving Table(驱动表):执行计划最先执行的那个表 /\+ leading(t1)*/*
Probed Table(匹配表):与驱动表进行连接的表

nested loops

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
1. 工作原理
驱动表 t1,有 m 条记录
匹配表 t2,有 n 条记录

for i in 1 .. m loop
for j in 1 .. n loop
if t1[i].col = t2[j].col then
匹配成功;
end if;
end loop;
end loop;

2. 结论
(1) T1 表每返回一条记录,都要去 T2 表去轮询一次,得到与其匹配的数据,推送到结果集中
所以,在嵌套表循环的使用中,必须设置 '返回记录少' 的表作为驱动表

(2) 可以通过以下两点来提高嵌套循环的速度
第一:尽量提高 T1 表 '取' 记录的速度(T1 表的连接列上创建索引)
第二:尽量提高 T2 表 '匹配' 记录的速度(T2 表的连接列上创建索引)

3. 示例
scott.emp -- 14 条记录
scott.dept -- 4 条记录

SQL> alter session set statistics_level = all;

SQL> select /*+ leading(d) use_nl(e)*/
e.*,
d.*
from scott.emp e,
scott.dept d
where d.deptno = e.deptno;

SQL> select t.*
from v$sql t
where t.sql_text like '%FROM scott.emp e,%'
order by t.last_active_time desc;

SQL> select * from table(dbms_xplan.display_cursor('c2ckftf2gj7qv',null,'allstats last'));

-- -- 情况1:以 scott.dept(小表) 为驱动表
-------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 14 |00:00:00.02 | 35 |
| 1 | NESTED LOOPS | | 1 | 14 | 14 |00:00:00.02 | 35 |
| 2 | TABLE ACCESS FULL| DEPT | 1 | 4 | 4 |00:00:00.02 | 7 |
|* 3 | TABLE ACCESS FULL| EMP | 4 | 4 | 14 |00:00:00.01 | 28 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("D"."DEPTNO"="E"."DEPTNO")

Starts 该 sql 执行的次数
E-Rows 预计返回的行数
A-Rows 实际返回的行数。可以和 E-Rows 比对,确定哪一步出现了问题
A-Time 每一步实际执行的时间
Buffers 每一步实际执行的逻辑读或一致性读
Reads 每一步实际执行的物理读
Writes 每一步实际执行的物理写
OMem 最优执行模式所需的内存评估值
1Mem one-pass模式所需的内存评估值
Used_Mem 则为当前操作实际执行时消耗的内存
括号里面为(发生磁盘交换的次数,1次即为One-Pass,大于1次则为Multi_Pass,如果没有使用磁盘,则显示0)


1. 首先,读取 id = 2 的记录,如下:
读取表 DEPT,读取次数 Starts = 1,实际读取记录数 A-Rows = 4 条

2. 其次,读取 id = 3 的记录,如下:
读取表 EMP,读取次数 Starts = 4,实际读取记录数(每次) A-Rows = 14 条

3. 然后,读取 id = 1,将两表进行 '嵌套循环'

4. 最后,读取 id = 0,查询最终结果

-- -- 情况2:同理,以 scott.emp(“大表”) 为驱动表,Starts = 14(id=4),变多了:
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 14 |00:00:00.01 | 25 |
| 1 | NESTED LOOPS | | 1 | | 14 |00:00:00.01 | 25 |
| 2 | NESTED LOOPS | | 1 | 14 | 14 |00:00:00.01 | 11 |
| 3 | TABLE ACCESS FULL | EMP | 1 | 14 | 14 |00:00:00.01 | 7 |
|* 4 | INDEX UNIQUE SCAN | PK_DEPT | 14 | 1 | 14 |00:00:00.01 | 4 |
| 5 | TABLE ACCESS BY INDEX ROWID| DEPT | 14 | 1 | 14 |00:00:00.01 | 14 |
--------------------------------------------------------------------------------------------------

hash join

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SELECT /*+ leading(e) use_hash(d)*/
e.*,
d.*
FROM scott.emp e,
scott.dept d
WHERE d.deptno = e.deptno;

--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 14 |00:00:00.01 | 25 |
| 1 | NESTED LOOPS | | 1 | | 14 |00:00:00.01 | 25 |
| 2 | NESTED LOOPS | | 1 | 14 | 14 |00:00:00.01 | 11 |
| 3 | TABLE ACCESS FULL | EMP | 1 | 14 | 14 |00:00:00.01 | 7 |
|* 4 | INDEX UNIQUE SCAN | PK_DEPT | 14 | 1 | 14 |00:00:00.01 | 4 |
| 5 | TABLE ACCESS BY INDEX ROWID| DEPT | 14 | 1 | 14 |00:00:00.01 | 14 |
--------------------------------------------------------------------------------------------------

merge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SELECT /*+ leading(e) use_merge(d)*/
e.*,
d.*
FROM scott.emp e,
scott.dept d
WHERE d.deptno = e.deptno;

--------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 14 |00:00:00.01 | 14 |
| 1 | MERGE JOIN | | 1 | 14 | 14 |00:00:00.01 | 14 |
| 2 | SORT JOIN | | 1 | 14 | 14 |00:00:00.01 | 7 |
| 3 | TABLE ACCESS FULL| EMP | 1 | 14 | 14 |00:00:00.01 | 7 |
|* 4 | SORT JOIN | | 14 | 4 | 14 |00:00:00.01 | 7 |
| 5 | TABLE ACCESS FULL| DEPT | 1 | 4 | 4 |00:00:00.01 | 7 |
--------------------------------------------------------------------------------------

思路

切记,性能优化是无止境的,当性能可以满足需求时即可,不要过度优化

计算机系统硬件性能从高到代依次为:CPU——Cache(L1-L2-L3)——内存——SSD硬盘——网络——硬盘。

CPU及内存:缓存数据访问、比较、排序、事务检测、SQL解析、函数或逻辑运算;

网络:结果数据传输、SQL请求、远程数据库访问(dblink);

硬盘:数据访问、数据写入、日志记录、大数据量排序、大表连接.

优化法则 性能提升效 优化成本
减少数据访问 1~1000
返回更少数据 1~100
减少交互次数 1~20
减少服务器CPU开销 1~5
利用更多资源 @~10

减少数据访问

创建并使用正确的索引

返回更少数据

数据分页处理

客户端分页

应用服务器分页

数据库sql分页

只返回需要的字段

减少交互次数

In List

batch DML

设置Fetch Size

使用存储过程

减少服务器CPU开销

使用绑定变量

合理使用排序

可能会发生排序操作的SQL语法:

Order by

Group by

Distinct

Exists子查询

Not Exists子查询

In子查询

Not In子查询

Union(并集),Union All 也是一种并集操作,但是不会发生排序,如果你确认两个数据集不需要执行去除重复数据操作,那请使用Union All 代替Union。

Minus(差集)

Intersect(交集)

Create Index

Merge Join,这是一种两个表连接的内部算法,执行时会把两个表先排序好再连接,应用于两个大表连接的操作。如果你的两个表连接的条件都是等值运算,那可以采用Hash Join来提高性能,因为Hash Join使用Hash 运算来代替排序的操作.

减少比较操作

大量复杂运算在客户端处理

什么是复杂运算,一般我认为是一秒钟CPU只能做10万次以内的运算。如含小数的对数及指数运算、三角函数、3DES及BASE64数据加密算法等等。

如果有大量这类函数运算,尽量放在客户端处理,一般CPU每秒中也只能处理1万-10万次这样的函数运算,放在数据库内不利于高并发处理.

利用更多资源

客户端多进程并行访问

以下是一些如何设置并行数的基本建议:

如果瓶颈在服务器主机,但是主机还有空闲资源,那么最大并行数取主机CPU核数和主机提供数据服务的磁盘数两个参数中的最小值,同时要保证主机有资源做其它任务。

如果瓶颈在客户端处理,但是客户端还有空闲资源,那建议不要增加SQL的并行,而是用一个进程取回数据后在客户端起多个进程处理即可,进程数根据客户端CPU核数计算。

如果瓶颈在客户端网络,那建议做数据压缩或者增加多个客户端,采用map reduce的架构处理。

如果瓶颈在服务器网络,那需要增加服务器的网络带宽或者在服务端将数据压缩后再处理了。

数据库并行处理

调优项

from子句-从右往左

ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表 driving table)将被最先处理。

当ORACLE处理多个表时,会运用排序及合并的方式连接它们,并且是从右往左的顺序处理FROM子句。首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行排序,然后扫描第二个表(FROM子句中倒数第二个表),最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并。

只在基于规则的优化器中有效。

使用表的别名(Alias)

当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误。Column歧义指的是由于SQL中不同的表具有相同的Column名,当SQL语句中出现这个Column时,SQL解析器无法判断这个Column的归属。

where子句-从右往左

Where子句中的连接顺序Oracle采用自下而上或自右向左的顺序解析WHERE子句。根据这个原理,表之间的连接必须写在其他WHERE条件之前,那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾

举例:TAB1有 16,384 条记录,TAB2 有 1 条记录

1
2
3
4
5
6
7
/*选择TAB2作为基础表 (最好的方法)*/
SELECT COUNT(*) FROM TAB1,TAB2
/*执行时间0.96秒*/

/*选择TAB1作为基础表 (不佳的方法)*/
SELECT COUNT(*) FROM TAB2,TAB1
/*执行时间26.09秒*/

用Where子句替换Having子句

避免使用HAVING子句,HAVING 只会在检索出所有记录之后才对结果集进行过滤。这个处理需要排序、总计等操作。如果能通过WHERE子句限制记录的数目,就能减少这方面的开销。

用EXISTS替换DISTINCT

当提交一个包含对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT。一般可以考虑用EXIST替换。EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果

用EXISTS替代IN 用NOT EXISTS替代NOT IN

用表连接替换EXISTS

尽量使用数字型字段

若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连 接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了

用Explain Plan分析SQL语句

SQL是一种傻瓜式语言,每一个条件就是一个需求,访问的顺序不同就形成了不同的执行计划。Oracle必须做出选择,一次只能有一种访问路径。执行计划是一条查询语句在Oracle中的执行过程或访问路径的描述

访问方式

table access full(全表扫描)

  • Oracle 会读取表中所有的行,并检查每一行是否满足 where 限制条件。

  • 全表扫描时可以使用多块读(一次 I/O 读取多块数据块)操作,提升吞吐量。

  • 使用建议:数据量太大的表不建议使用全表扫描,除非本身需要取出的数据较多,占到表数据总量的 5% ~ 10% 或以上。

table access by rowid(通过 rowid 扫描)

  • rowid:伪列,Oracle 自带的,不会存储 rowid 的值,不能被增、删、改
  • 一旦一行数据插入后,则其对应的 rowid 在该行的生命周期内是唯一的,即使发生行迁移,该行的 rowid 值也不变。

table access by index scan(索引扫描)

  • 在索引块中,既存储每个索引的键值,也存储具有该键值行的 rowid
  • 所以索引扫描其实分为两步:
    • 扫描索引得到对应的 rowid
    • 通过 rowid 定位到具体的行读取数据
index unique scan(索引唯一扫描)
  • 每次至多返回一条记录
  • 有下列两种情况(当查询字段有下列约束时)
    • unique
    • primary key
index range scan(索引范围扫描)
  • 每次至少返回一条记录
  • 一般有下列三种情况
    • 在唯一索引列上使用了范围操作符(如:> < >= <= between)
    • 在组合索引上,只使用部分列进行查询(查询时必须包含前导列,否则会走全表扫描)
    • 对非唯一索引列上进行的任何查询
index full scan(索引全扫描)
  • order by 唯一索引列
index fast full scan(索引快速扫描)
  • 与 index full scan 类似,只是不进行排序
index skip scan(索引跳跃扫描)
  • 必须是 组合索引
  • 除了前导列(索引中第一列)外的其他列作为条件

提示(Hints)

  • FULL hint 告诉ORACLE使用全表扫描的方式访问指定表。
  • INDEX Hint 告诉ORACLE使用基于索引的扫描方式。
  • ROWID hint 告诉ORACLE使用TABLE ACCESS BY ROWID的操作访问表。
  • CACHE hint 来告诉优化器把查询结果数据保留在SGA中。

SQL什么条件会使用索引?

当字段上建有索引时,通常以下情况会使用索引:

INDEX_COLUMN = ?

INDEX_COLUMN > ?

INDEX_COLUMN >= ?

INDEX_COLUMN < ?

INDEX_COLUMN <= ?

INDEX_COLUMN between ? and ?

INDEX_COLUMN in (?,?,…,?)

INDEX_COLUMN like ?||’%’(后导模糊查询)

T1. INDEX_COLUMN=T2. COLUMN1(两个表通过索引字段关联)

SQL什么条件不会使用索引?

查询条件 不能使用索引原因
INDEX_COLUMN <> ? INDEX_COLUMN not in (?,?,…,?) 不等于操作不能使用索引
function(INDEX_COLUMN) = ? INDEX_COLUMN + 1 = ? INDEX_COLUMN || ‘a’ = ? 经过普通运算或函数运算后的索引字段不能使用索引
INDEX_COLUMN like ‘%’||? INDEX_COLUMN like ‘%’||?||’%’ 含前导模糊查询的Like语法不能使用索引
INDEX_COLUMN is null B-TREE索引里不保存字段为NULL值记录,因此IS NULL不能使用索引
NUMBER_INDEX_COLUMN=’12345’ CHAR_INDEX_COLUMN=12345 Oracle在做数值比较时需要将两边的数据转换成同一种数据类型,如果两边数据类型不同时会对字段值隐式转换,相当于加了一层函数处理,所以不能使用索引。
a.INDEX_COLUMN=a.COLUMN_1 给索引查询的值应是已知数据,不能是未知字段值。
注:经过函数运算字段的字段要使用可以使用函数索引,这种需求建议与DBA沟通。有时候我们会使用多个字段的组合索引,如果查询条件中第一个字段不能使用索引,那整个查询也不能使用索引如:我们company表建了一个id+name的组合索引,以下SQL是不能使用索引的Select * from company where name=?Oracle9i后引入了一种index skip scan的索引方式来解决类似的问题,但是通过index skip scan提高性能的条件比较特殊,使用不好反而性能会更差。

索引列不能 is null

应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描。

索引列不能 not (如使用 != 或 <> 操作符)

索引只能告诉你什么存在于表中,而不能告诉你什么不存在于表中.

索引列不能使用函数

使用函数将停用索引

等式比较优先于范围比较

1
2
3
SELECT ENAME FROM EMP
WHERE DEPTNO > 20
AND EMP_CAT = 'A'

避免在索引列上使用计算

WHERE子句中,如果索引列是函数的一部分。优化器将不使用索引而使用全表扫描。

如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。

避免在索引列上使用NOT

我们要避免在索引列上使用NOT,NOT会产生在和在索引列上使用函数相同的影响。当ORACLE遇到NOT,它就会停止使用索引转而执行全表扫描。

用 >= 替代

1
2
3
/*高效SQL*/
SELECT * FROM EMP
WHERE DEPTNO >=4
1
2
3
/*低效SQL*/
SELECT * FROM EMP
WHERE DEPTNO >3

两者的区别在于,前者DBMS将直接跳到第一个DEPT等于4的记录,而后者将首先定位到DEPTNO等于3的记录并且向前扫描到第一个DEPT大于3的记录。

用Union替换OR(适用于索引列)

对索引列使用OR将造成全表扫描。注意,以上规则只针对多个索引列有效。

1
2
3
4
5
select id from t where num=10 or Name = 'admin'
可以这样查询:
select id from t where num = 10
union all
select id from t where Name = 'admin'

用IN替换OR

避免在索引列上使用is null和is not null

1
2
3
/*低效SQL:(索引失效)*/
SELECT * FROM DEPARTMENT
WHERE DEPT_CODE IS NOT NULL;
1
2
3
/*高效SQL:(索引有效)*/
SELECT * FROM DEPARTMENT
WHERE DEPT_CODE >=0;

使用UNION ALL替代UNION

当SQL语句需要UNION两个查询结果集合时,这两个结果集合会以UNION-ALL的方式被合并,然后在输出最终结果前进行排序。如果用UNION ALL替代UNION,这样排序就不是必要了,效率就会因此得到提高。

DML

使用Truncate而非Delete

  • Delete表中记录的时候,Oracle会在Rollback段中保存删除信息以备恢复。Truncate删除表中记录的时候不保存删除信息,不能恢复。因此Truncate删除记录比Delete快,而且占用资源少。
  • 删除表中记录的时候,如果不需要恢复的情况之下应该尽量使用Truncate而不是Delete。
  • Truncate仅适用于删除全表的记录

尽量多使用COMMIT

COMMIT所释放的资源:

  • 回滚段上用于恢复数据的信息.
  • 被程序语句获得的锁
  • redo log buffer 中的空间
  • ORACLE为管理上述3种资源中的内部花费

oracle 调优过程

1
2
3
4
5
-- -- 获取执行计划
explain plan for select * from dual;

select * from table(dbms_xplan.display());
select * from table( dbms_xplan.display_cursor('&sql_id') );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
-- -- 查找对应sql的sql_id
SELECT * FROM v$sql t;
SELECT sql_id,
sql_text,
LAST_LOAD_TIME
FROM v$sql
WHERE sql_text LIKE '%本年度小计%'
ORDER BY LAST_LOAD_TIME DESC

-- -- 根据sql_id创建该sql的调优任务
DECLARE
my_task_name VARCHAR2(50);
my_sql_id VARCHAR2(64);
BEGIN
my_sql_id := '7t59r6bvu83r5';
my_task_name := DBMS_SQLTUNE.CREATE_TUNING_TASK(
sql_id => my_sql_id,
scope => 'COMPREHENSIVE',
time_limit => 180,
task_name => my_sql_id,
description => 'Task to tune a query on a specified table');
END;

-- -- 执行调优任务
BEGIN
DBMS_SQLTUNE.EXECUTE_TUNING_TASK( task_name => '7t59r6bvu83r5');
end;

-- -- 查看调优报告
SELECT DBMS_SQLTUNE.REPORT_TUNING_TASK( '7t59r6bvu83r5') from DUAL;

-- -- 调优报告一般建议修改profile文件
BEGIN
dbms_sqltune.accept_sql_profile(task_name => '7t59r6bvu83r5',
task_owner => 'CASICZS', replace => TRUE);
end;

-- -- 删除调优任务
BEGIN dbms_sqltune.drop_tuning_task('my_sql_tuning_&sqlid'); END;

参考

Oracle数据库访问性能优化

Oracle 性能优化总结

Oracle 表连接类型及方式详解

docker

docker

概念

安装

卸载

1
2
3
4
5
# 查看相关软件
dpkg -l | grep docker
# 卸载相关软件
apt-get remove docker-ce-cli docker-ce
apt-get autoremove # 会自动卸载containerd.io等一干软件。

配置

国内源

通用的方法就是编辑/etc/docker/daemon.json

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"registry-mirrors" : [
"http://registry.docker-cn.com",
"http://docker.mirrors.ustc.edu.cn",
"http://hub-mirror.c.163.com"
],
"insecure-registries" : [
"registry.docker-cn.com",
"docker.mirrors.ustc.edu.cn"
],
"debug" : true,
"experimental" : true
}

然后重启docker的daemon即可。

网络配置

Docker 容器的网络默认与宿主机、与其他容器都是相互隔离,本文主要介绍 Docker 高级网络功能。

安装 Docker 时,它会自动创建三个网络,bridge(创建容器默认连接到此网络)、 none 、host

1
2
3
4
5
6
7
dxshelley@dxshelley:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
e717c6efd3ef bridge bridge local
412bdc3c52f4 host host local
fae05e35fcf4 my-net bridge local
59dafd69063f none null local
dxshelley@dxshelley:~$
  • host:容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的IP和端口。
  • none:该模式关闭了容器的网络功能。
  • bridge(默认):此模式会为每一个容器分配、设置 IP 等,并将容器连接到一个 docker0 虚拟网桥,通过 docker0 网桥以及 Iptables nat 表配置与宿主机通信。
  • Container:创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围。

众所周知,Docker 使用了 Linux 的 Namespaces 技术来进行资源隔离,如 PID Namespace 隔离进程,Mount Namespace 隔离文件系统,Network Namespace 隔离网络等。

一个 Network Namespace 提供了一份独立的网络环境,包括网卡、路由、Iptable 规则等都与其他的 Network Namespace 隔离。

一个 Docker 容器一般会分配一个独立的 Network Namespace。用host网络,是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。

当 Docker server 启动时,会在主机上创建一个名为 docker0 的虚拟网桥,此主机上启动的 Docker 容器会连接到这个虚拟网桥上。

虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。

接下来就要为容器分配 IP 了,Docker 会从 RFC1918 所定义的私有 IP 网段中,选择一个和宿主机不同的IP地址和子网分配给 docker0,连接到 docker0 的容器就从这个子网中选择一个未占用的 IP 使用。

如一般 Docker 会使用 172.17.0.0/16 这个网段,并将 172.17.0.1/16 分配给 docker0 网桥(在主机上使用 ifconfig 命令是可以看到 docker0 的,可以认为它是网桥的管理接口,在宿主机上作为一块虚拟网卡使用)。

  1. 在主机上创建一对虚拟网卡 veth pair 设备。veth 设备总是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth 设备常用来连接两个网络设备。
  2. Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为 eth0。另一端放在主机中,以 veth65f9 这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中,可以通过 brctl show 命令查看。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
dxshelley@dxshelley:~$ docker network inspect bridge 
[
{
"Name": "bridge",
"Id": "e717c6efd3efaa647e13e624c9f5f01283ccc204d623f976a146186f703501a3",
"Created": "2022-03-01T14:35:04.316360758+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"b04b01b20b018e5aa25c34dfefc0b2a5304c6055e9c3af24c6a2880cc96b0bbe": {
"Name": "nextcloud",
"EndpointID": "fbd04b39c2876d965899348960c13acea1dd8c453d4a35775684759670789219",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
},
"c6d7013531830f8ad2a31d57bae90e3f74df87a0280cc3e2bb1e8212782658df": {
"Name": "dev-portainer",
"EndpointID": "e4883cf65a945bd71d28ae40e155d79bafe92a05dea6d4513479d56ed9b12f51",
"MacAddress": "02:42:ac:11:00:04",
"IPv4Address": "172.17.0.4/16",
"IPv6Address": ""
},
"c87ec1659daee7bbf0fd64f9c9332f9d5ace5056fdcf263d46d771e6dac40634": {
"Name": "nextcloud-mysql",
"EndpointID": "e719ddd3f2b8881623b0cb52b79da4d0655901a1716bed28a3ff2ed598ba8614",
"MacAddress": "02:42:ac:11:00:05",
"IPv4Address": "172.17.0.5/16",
"IPv6Address": ""
},
"ec618b79c65504774808db0ba7b516494689fd93252c9e870d5bce4b64ff07bf": {
"Name": "mysql",
"EndpointID": "a64c9aa289bb338b40e973e3f207e52eb3c4b4a2336e14bb40582ea8e9415fec",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
dxshelley@dxshelley:~$

这些选项只有在 docker run 执行时使用,因为它是针对容器的特性内容

  • -h HOSTNAME–hostname=HOSTNAME配置容器主机名
  • –link=CONTAINER_NAME:ALIAS添加到另一个容器的连接
  • –net=bridge|none|container:NAME_or_ID|host配置容器的桥接模式
  • -p SPEC–publish=SPEC映射容器端口到宿主主机
  • -P or –publish-all=true|false` 映射容器所有端口到宿主主机

自定义网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 创建桥接网络
dxshelley@dxshelley:~$ docker network create -d bridge my-net
dxshelley@dxshelley:~$ ifconfig
br-fae05e35fcf4: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.18.0.1 netmask 255.255.0.0 broadcast 172.18.255.255
ether 02:42:03:fa:b0:2d txqueuelen 0 (以太网)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

dxshelley@dxshelley:~$ docker run -it --rm --name busybox2 --network my-net busybox sh
/ #
/ # ping busybox1;
PING busybox1 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.316 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.220 ms
64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.209 ms

dxshelley@dxshelley:~$ docker run -it --rm --name busybox1 --network my-net busybox sh
/ #
/ # ping busybox2;
PING busybox2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.128 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.236 ms

dxshelley@dxshelley:~$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
14df2e882228 busybox "sh" About a minute ago Up About a minute busybox2
12257fefefe3 busybox "sh" About a minute ago Up About a minute
# busybox1 容器和 busybox2 容器建立了互联关系

使用

进入容器

docker exec -it [CONTAINER ID] bash

镜像导出导入

1
2
3
4
5
6
#将镜像存储
docker save nginx:latest > /root/docker-images/nginx.tar
#导入镜像文件
docker load --input /root/docker-images/nginx.tar
#通过符号的方式来导入
docker load < /root/docker-images/nginx.tar

可视化Portainer

1
docker run -d -p 9000:9000 -v /root/portainer:/data -v /var/run/docker.sock:/var/run/docker.sock --name dev-portainer portainer/portainer

安装gitlab

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 设置gitlab宿主机目录
export GITLAB_HOME=/home/pi/docker/gitlab

# 未成功
sudo docker run --detach \
--hostname gitlab.example.com \
--publish 4443:443 --publish 8082:80 --publish 2222:22 \
--name gitlab \
--restart always \
--volume $GITLAB_HOME/config:/etc/gitlab \
--volume $GITLAB_HOME/logs:/var/log/gitlab \
--volume $GITLAB_HOME/data:/var/opt/gitlab \
--shm-size 256m \
gitlab/gitlab-ce:latest

mysql

1
2
3
4
5
6
7
8
9
# 设置mysql宿主机目录
export MYSQL_HOME=/home/pi/docker/mysql

sudo docker run -p 3306:3306 --name mysql -v $MYSQL_HOME/conf:/etc/mysql/conf.d -v $MYSQL_HOME/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7

# 备份数据
$ docker exec some-mysql sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > /some/path/on/your/host/all-databases.sql
# 导入库
$ docker exec -i some-mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD"' < /some/path/on/your/host/all-databases.sql

nextcloud

1
2
3
4
5
6
7
8
9
$ docker run -d \
-p5555:80 \
-v nextcloud:/var/www/html \
-v apps:/var/www/html/custom_apps \
-v config:/var/www/html/config \
-v data:/var/www/html/data \
-v theme:/var/www/html/themes/<YOUR_CUSTOM_THEME> \
-link mysql:mysql
nextcloud

注:By default, this container uses SQLite for data storage but the Nextcloud setup wizard (appears on first run) allows connecting to an existing MySQL/MariaDB or PostgreSQL database. You can also link a database container, e. g. --link my-mysql:mysql, and then use mysql as the database host on setup. More info is in the docker-compose section.

1
2
3
4
5
6
7
$ docker run -d \
-v nextcloud:/var/www/html \
-v apps:/var/www/html/custom_apps \
-v config:/var/www/html/config \
-v data:/var/www/html/data \
--link mysql:mysql
nextcloud

<<<<<<< HEAD

开启缩略图

使用时会发现,Nextcloud 上传的视频不能生成缩略图。其实 Nextcloud 本身支持生成视频缩略图,需要安装 ffm­peg 并修改配置:

http://ffmpeg.org/download.html

1
2
3
4
5
6
7
8
docker exec -it nextcloud bash
apt update
apt install ffmpeg

cd /usr/bin
ln -s /usr/local/ffmpeg-4.4/ffprobe ffprobe
ln -s /usr/local/ffmpeg-4.4/ffmpeg ffmpeg
ln -s /usr/local/ffmpeg-4.4/ffplay ffplay

停止 NextCloud 容器,再修改 /var/www/html/con­fig/con­fig.php 配置文件,添加:

=======

配置邮箱

b243b69759d2d1d54560d6c87508122a6e7d9c8c

1
2
3
4
5
6
7
'enable_previews' => true,
'enabledPreviewProviders' =>
array (
0 => 'OC\\Preview\\Image',
1 => 'OC\\Preview\\Movie',
2 => 'OC\\Preview\\TXT',
),

再次启动容器即可生效。

nginx

1
2
3
4
5
6
7
docker run -d -p 80:80 -p 443:443 --name nginx --restart=always -e TZ="Asia/Shanghai" -v /docker/nginx/html:/usr/share/nginx/html -v /docker/nginx/conf/nginx:/etc/nginx/ -v /docker/nginx/log:/var/log/nginx nginx

docker search nginx
docker pull nginx
docker run -d -p 80:80 --name nginx01 nginx
docker exec -it nginx01 /bin/bash
whereis nginx

自启动docker

1
docker container update --restart=always nginx

vim 编辑器的下载与安装

在使用 docker容器时,有时候里边没有安装vim,运行vim命令时提示说:vim: command not found.

1
2
apt-get update
apt-get install vim

宿主与docker互相拷贝文件

1
pi@raspberrypi:~/docker/mysql $ docker cp mysql:/etc/mysql/my.cnf ./

安装aria2和webgui

1
2
3
docker run -d   --name aria2-pro   --restart unless-stopped   --log-opt max-size=1m   -e PUID=1000   -e PGID=1000   -e UMASK_SET=022   -e RPC_SECRET=mass123   -e RPC_PORT=6800   -p 6800:6800   -e LISTEN_PORT=6888   -p 6888:6888   -p 6888:6888/udp   -v $PWD/aria2-config:/config   -v $PWD/downloads:/downloads   p3terx/aria2-pro

docker run -d --name ariang --log-opt max-size=1m --restart unless-stopped -p 6880:6880 p3terx/ariang

安装elasticsearch

docker run --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -d elasticsearch

安装gogs

1
2
3
4
5
export GOGS_HOME=/home/pi/docker/gogs

docker pull gogs/gogs-rpi

docker run -d --name=gogs -p 3022:22 -p 3080:3000 -v $GOGS_HOME/gogs:/data gogs/gogs-rpi

日志

Docker 引擎日志

Docker 引擎日志一般是交给了 Upstart(Ubuntu 14.04) 或者 systemd (CentOS 7, Ubuntu 16.04)。前者一般位于 /var/log/upstart/docker.log 下,后者我们一般 通过 journalctl -u docker 来进行查看。

系统 日志位置
Ubuntu(14.04) /var/log/upstart/docker.log
Ubuntu(16.04) journalctl -u docker.service
CentOS 7/RHEL 7/Fedora journalctl -u docker.service
CoreOS journalctl -u docker.service
OpenSuSE journalctl -u docker.service
OSX ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/log/d?ocker.log
Debian GNU/Linux 7 /var/log/daemon.log
Debian GNU/Linux 8 journalctl -u docker.service
Boot2Docker /var/log/docker.log

容器日志

问题

docker info 报错

ERROR: Got permission denied while trying to connect to the Docker daemon socket

1
2
3
4
sudo groupadd docker
sudo usermod -aG docker ${USER}
# 执行如下命令或重新登录
su -s ${USER}

Pi Image docker info warnings - No kernel memory limit support #303

https://github.com/me-box/databox/issues/303

nextcloud始终起不来报错

问题描述:

问题原因:mysql内存溢出,需要增加缓存容量。

解决方案:

先找到nextcloud 的输出日志定位问题。

1
2
3
4
5
6
C:\Users\25433>docker exec -it  nextcloud /bin/bash
root@cc91dc46ad6d:/var/www/html#
root@cc91dc46ad6d:/var/www/html#
root@cc91dc46ad6d:/var/www/html# ls -l data/nextcloud.log
-rw-r----- 1 www-data www-data 10277735 Mar 2 06:25 data/nextcloud.log
root@cc91dc46ad6d:/var/www/html#

How to fix this?

In order to fix this error, we can either optimize the query or increase the sort_buffer_size.

To increase the sort_buffer_size, we open the /etc.mysql/my.cnf and add the following lines:

1
sort_buffer_size = 1024 k

After we modify the parameter, we restart the MySQL service:

1
systemctl restart mysqld

In addition, we raise it 4 M using the following command in MySQL:

1
mysql> SET GLOBAL sort_buffer_size = 1024 * 1024 * 4;

参考

nextcloud 集成 onlyoffice

docker文档-nextcloud

docker教程

nextcloud安装教程

nextcloud sqlite转mysql版

使用Docker搭建MySQL服务

docker修改mysql配置文件后,无法启动mysql容器

<<<<<<< HEAD
docker info 报错
=======

Linux 编译安装ffmpeg

Nextcloud 管理员手册

51d1933c4d2ecf90e3494e0fdea0be79eb271ddb

树莓派

树莓派

无网线无显示器环境下配置树莓派连接Wi-Fi开启ssh

连接wifi

在电脑中打开sd卡根目录创建名字为wpa_supplicant.conf 的文件。

1
2
3
4
5
6
7
8
9
country=CN
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
ssid="12345678"
psk="88888888"
key_mgmt=WPA-PSK
priority=1
}

开启ssh

boot分区里新建一个名字为ssh的空文件,这样系统在启动的时候就可以识别出来,从而在开机的时候就开启ssh.

配置

1
raspi-config

配置国内源

注:对于系统版本不一样的,只需要将版本buster 改为相应的版本即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 查看树莓派版本
pi@raspberrypi:~/downloads $ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description: Raspbian GNU/Linux 10 (buster)
Release: 10
Codename: buster
pi@raspberrypi:~/downloads $
pi@raspberrypi:~/downloads $ vi /etc/apt/sources.list
pi@raspberrypi:~/downloads $ cat /etc/apt/sources.list
#deb http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
#deb-src http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi


deb http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ buster main contrib non-free rpi
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
deb-src http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ buster main contrib non-free rpi

pi@raspberrypi:~/downloads $
pi@raspberrypi:~/downloads $ vi /etc/apt/sources.list.d/raspi.list
pi@raspberrypi:~/downloads $ cat /etc/apt/sources.list.d/raspi.list
#deb http://archive.raspberrypi.org/debian/ buster main
deb http://mirrors.ustc.edu.cn/archive.raspberrypi.org/debian/ buster main ui
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
#deb-src http://archive.raspberrypi.org/debian/ buster main
pi@raspberrypi:~/downloads $
pi@raspberrypi:~/downloads $ sudo apt-get update
Hit:1 http://mirrors.ustc.edu.cn/archive.raspberrypi.org/debian buster InRelease
Hit:2 http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian buster InRelease
Hit:3 https://download.docker.com/linux/raspbian buster InRelease
Reading package lists... Done
pi@raspberrypi:~/downloads $
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 各种国内源,配置一个就可以
/etc/apt/sources.list
#清华大学
deb http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ buster main contrib non-free rpi
deb-src http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ buster main contrib non-free rpi

#中国科学技术大学
deb http://mirrors.ustc.edu.cn/raspbian/raspbian/ buster main contrib non-free rpi
deb-src http://mirrors.ustc.edu.cn/raspbian/raspbian/ buster main contribnon-free rpi

#阿里云
deb http://mirrors.aliyun.com/raspbian/raspbian/ buster main contrib non-free rpi
deb-src http://mirrors.aliyun.com/raspbian/raspbian/ buster main contrib non-free rpi

#华中科技大学
deb http://mirrors.hustunique.com/raspbian/raspbian/ buster main contrib non-free rpi
deb-src http://mirrors.hustunique.com/raspbian/raspbian/ buster main contrib non-free rpi

/etc/apt/sources.list.d/raspi.list
#清华大学
deb http://mirrors.tuna.tsinghua.edu.cn/archive.raspberrypi.org/debian/ buster main ui

#中国科学技术大学
deb http://mirrors.ustc.edu.cn/archive.raspberrypi.org/debian/ buster main ui

#阿里云
deb http://mirrors.aliyun.com/archive.raspberrypi.org/debian/ buster main ui

#华中科技大学
deb http://mirrors.hustunique.com/archive.raspberrypi.org/debian/ buster main ui

使用

安装docker

  1. 先配置好国内源-树莓派版的,其他的不好使

问题

  1. 无法正常停止docker进程 原创

https://blog.51cto.com/wutengfei/2946943

参考

BusyBox基本使用

busybox

概念

BusyBox是一个遵循GPL协议、以自由软件形式发行的应用程序。Busybox在单一的可执行文件中提供了精简的Unix工具集,可运行于多款POSIX环境的操作系统,例如Linux(包括Android[6])、Hurd[7]、FreeBSD[8][9]等等。由于BusyBox可执行文件的文件比较小,使得它非常适合使用于嵌入式系统。作者将BusyBox称为“嵌入式Linux的瑞士军刀”

参考

Ubuntu 基本使用

Ubuntu

配置

Ubuntu20.04防火墙设置

Ubuntu20.04一般都默认安装了UFW(Uncomplicated Firewall),它是一款轻量化的工具,主要用于对输入输出的流量进行监控。如果没有安装,请用下面的命令安装:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 查看防火墙状态
sudo ufw status verbose

sudo ufw app list

# 开启或关闭防火墙
sudo ufw enable | disable

# 外来访问默认允许/拒绝
sudo ufw default deny

sudo ufw allow | deny [service]


# 禁止或允许指定ip地址访问
sudo ufw deny from 203.0.113.100
sudo ufw allow from 203.0.113.101
# 禁止子网访问
sudo ufw deny from 203.0.113.0/24
特定ip地址可ssh连接
sudo ufw allow from 203.0.113.103 proto tcp to any port 22

sudo ufw allow https
# 或
sudo ufw allow 443
# 允许入 http或者https的
sudo ufw allow proto tcp from any to any port 80,443

# 删除规则
sudo ufw delete allow from 203.0.113.101

更换阿里云软件源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak    // 备份
sudo vim /etc/apt/sources.list // 修改
// 进入source.list,更换为阿里云软件源

deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse

// 更新
sudo apt update
sudo apt upgrade
命令 描述
apt autoclean 将已删除软件包的.deb安装文件从硬盘中删除
apt clean 同上,但会把已安装的软件包的安装包也删除掉
apt autoremove 删除为了满足其他软件包的依赖而安装,但现在不再需要的软件包
apt remove [软件包名] 删除已安装的软件包(保留配置文件)
apt –purge remove [软件包名] 删除已安装包(不保留配置文件)
sudo apt update 更新本地包数据库
sudo apt upgrade 更新所有已安装的包(也可以使用 full-upgrade)
sudo apt install ./.deb 安装官网已经提供了 Ubuntu 版本 .deb 安装文件

添加开机启动(服务或脚本)

系统启动时需要加载的配置文件

/etc/profile、/root/.bash_profile
/etc/bashrc、/root/.bashrc
/etc/profile.d/*.sh、/etc/profile.d/lang.sh
/etc/sysconfig/i18n、/etc/rc.local(/etc/rc.d/rc.local)

1
2
3
4
5
6
#/etc/rc.local 以及自定义脚本中都不能使用系统变量(比如 $HOME,原因在于其执行自定义脚本时并没有继承系统变量)
# 修改rc.local文件,在 exit 0 前面加入以下命令。保存并退出
sudo vi /etc/rc.local
sudo touch /etc/rc.local
sudo chmod 755 /etc/rc.local
sudo systemctl enable rc-local.service

软件

ping 和 ifconfig

1
2
apt-get install inetutils-ping
apt-get install net-tools

Installing Apache2 / Nginx & Aria2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
sudo apt install apache2 -y
sudo apt install nginx -y
sudo apt install aria2 -y


sudo rm -f /var/www/html/index.html; sudo mkdir /var/www/html/aria2

# 下载aria2WebUI
wget https://github.com/mayswind/AriaNg/releases/download/1.1.6/AriaNg-1.1.6-AllInOne.zip; sudo unzip AriaNg*.zip -d /var/www/html/aria2

sudo mkdir $HOME/.aria2; sudo touch $HOME/.aria2/aria2.conf

# It also require to start Aria2 as RPC-server as a background task, to do that you can use “screen” and “crontab“. You can install “screen” by executing:

sudo apt install screen -y

# 配置随系统启动aria2
crontab -e

# 追加
@reboot screen -d -m -S AriaRPC bash -c 'aria2c --enable-rpc --rpc-listen-all --rpc-allow-origin-all=true'

# 访问
192.168.1.105/aria2

字体缺失

字体缺失:可以去网上下载找资源,因为我是双系统,所以先去 Windows 系统,将 C:/Windows/Fonts 下的字体移动过来了

1
2
3
4
5
6
7
8
9
10
11
12
13
// Fonts字体包移动到 /usr/share/fonts/ 下

sudo mv Fonts字体包位置 /usr/share/fonts/

// 移动好了之后,通过以下方式安装字体

cd /usr/share/fonts/

sudo mkfontdir

sudo mkfontscale

sudo fc-cache

日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
=> /var/log/messages:常规日志消息
=> /var/log/boot:系统启动日志
=> /var/log/debug:调试日志消息
=> /var/log/auth.log:用户登录和身份验证日志
=> /var/log/daemon.log:运行squid,ntpd等其他日志消息到这个文件
=> /var/log/dmesg:Linux内核环缓存日志
=> /var/log/dpkg.log:所有二进制包日志都包括程序包安装和其他信息
=> /var/log/faillog:用户登录日志文件失败
=> /var/log/kern.log:内核日志文件
=> /var/log/lpr.log:打印机日志文件
=> /var/log/mail.*:所有邮件服务器消息日志文件
=> /var/log/mysql.*:MySQL服务器日志文件
=> /var/log/user.log:所有用户级日志
=> /var/log/xorg.0.log:X.org日志文件
=> /var/log/apache2/*:Apache Web服务器日志文件目录
=> /var/log/lighttpd/*:Lighttpd Web服务器日志文件目录
=> /var/log/fsck/*:fsck命令日志
=> /var/log/apport.log:应用程序崩溃报告/日志文件=> /var/log/syslog:系统日志=> /var/log/ufw:ufw防火墙日志=> /var/log/gufw:gufw防火墙日志

#使用tail,more,less和grep命令。
tail -f /var/log/apport.log
more /var/log/xorg.0.log
cat /var/log/mysql.err
less /var/log/messages
grep -i fail /var/log/boot

参考

安装国内firefox(国内账号必须)

  • © 2015-2024 DXShelley
  • Powered by Hexo Theme Ayer

请我喝杯咖啡吧~~~

支付宝
微信