diff --git a/about.org b/about.org new file mode 100644 index 0000000..f5fd510 --- /dev/null +++ b/about.org @@ -0,0 +1,3 @@ +#+TITLE: About + +Nothing diff --git a/index.org b/index.org index 3a2f836..29cb413 100644 --- a/index.org +++ b/index.org @@ -10,6 +10,7 @@ display: none #+END_EXPORT -- [[./shell notebook/touch bar + bettertouchtool + shell 一键优化工作流程.org][touch bar + shell 一键优化工作流程]] - [[./emacs notebook/搭建我的笔记系统.org][搭建我的笔记系统]] - [[./emacs notebook/org-mode gtd.org][我的 GTD 系统]] +- [[./redis notebook/redis源码阅读计划.org][redis 源码阅读计划]] +- [[./shell notebook/touch bar + bettertouchtool + shell 一键优化工作流程.org][touch bar + shell 优化工作流程]] diff --git "a/others notebook/ssh key \347\231\273\351\231\206\350\277\234\347\250\213.org" "b/others notebook/ssh key \347\231\273\351\231\206\350\277\234\347\250\213.org" index 217f12c..0dbbc78 100644 --- "a/others notebook/ssh key \347\231\273\351\231\206\350\277\234\347\250\213.org" +++ "b/others notebook/ssh key \347\231\273\351\231\206\350\277\234\347\250\213.org" @@ -2,7 +2,7 @@ * 生成 public_key 和 private_key #+BEGIN_SRC shell -$ ssh-keygen -t rsa -C "shi_zhonghe@163.com” +$ ssh-keygen -t rsa -C "shi_zhonghe@163.com" #+END_SRC 会生成 2 个文件 diff --git a/qu/qu.org b/qu/qu.org index 3dfd2d1..be22ac7 100644 --- a/qu/qu.org +++ b/qu/qu.org @@ -1,3 +1,4 @@ #+TITLE: 私人笔记 - [[./ShadowsocksR.org][ShadowsocksR 配置]] +- [[./redis 面试题.org][redis 面试题]] diff --git "a/qu/redis \351\235\242\350\257\225\351\242\230.org" "b/qu/redis \351\235\242\350\257\225\351\242\230.org" new file mode 100644 index 0000000..2a7812f --- /dev/null +++ "b/qu/redis \351\235\242\350\257\225\351\242\230.org" @@ -0,0 +1,69 @@ +#+TITLE: redis 面试题 + +* Redis 有哪些数据结构? + +字符串 String、字典 Hash、列表 List、集合 Set、有序集合 SortedSet。 + +如果你是 Redis 中高级用户,还需要加上下面几种数据结构 HyperLogLog、Geo、Pub/Sub。 + +如果你说还玩过 Redis Module,像 BloomFilter,RedisSearch,Redis-ML + +* 使用过 Redis 分布式锁么,它是什么回事? + +使用命令:SETNX key value 和 EXPIRE key seconds + +追问:如果在 setnx 之后执行 expire 之前进程意外 crash 或者要重启维护了,那会怎么样? + +使用命令:SET key value [EX seconds] [PX milliseconds] [NX|XX] + +例如: +#+BEGIN_EXAMPLE +SET test_key "hello" EX 60 NX +SET test_key "hello" PX 60000 NX +#+END_EXAMPLE + +* Redis 里有 1 亿个 key,其中 10w 个 key 以某个固定前缀开头,将它们找出来 + +使用命令:keys pattern + +追问:如果这个 redis 正在给线上的业务提供服务,那使用 keys 指令会有什么问题? + +这个时候你要回答 redis 关键的一个特性:redis 的单线程的。keys 指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用 scan 指令,scan 指令可以无阻塞的提取出指定模式的 key 列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用 keys 指令长。 + +* 使用过 Redis 做异步队列么,你是怎么用的? + +一般使用 list 结构作为队列,rpush 生产消息,lpop 消费消息。当 lpop 没有消息的时候,要适当 sleep 一会再重试。 + +如果对方追问可不可以不用 sleep 呢?list 还有个指令叫 blpop,在没有消息的时候,它会阻塞住直到消息到来。 + +如果对方追问能不能生产一次消费多次呢?使用 pub/sub 主题订阅者模式,可以实现 1:N 的消息队列。 + +如果对方追问 pub/sub 有什么缺点?在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如 rabbitmq 等。 + +如果对方追问 redis 如何实现延时队列?我估计现在你很想把面试官一棒打死如果你手上有一根棒球棍的话,怎么问的这么详细。但是你很克制,然后神态自若的回答道:使用 sortedset,拿时间戳作为 score,消息内容作为 key 调用 zadd 来生产消息,消费者用 zrangebyscore 指令获取 N 秒之前的数据轮询进行处理。 + +* 如果有大量的 key 需要设置同一时间过期,一般需要注意什么? + +如果大量的 key 过期时间设置的过于集中,到过期的那个时间点,redis 可能会出现短暂的卡顿现象。一般需要在时间上加一个随机值,使得过期时间分散一些。 + +* Redis如何做持久化的? + +bgsave 做镜像全量持久化,aof 做增量持久化。因为 bgsave 会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要 aof 来配合使用。在 redis 实例重启时,会使用 bgsave 持久化文件重新构建内存,再使用 aof 重放近期的操作指令来实现完整恢复重启之前的状态。 + +对方追问那如果突然机器掉电会怎样?取决于 aof 日志 sync 属性的配置,如果不要求性能,在每条写指令时都 sync 一下磁盘,就不会丢失数据。但是在高性能的要求下每次都 sync 是不现实的,一般都使用定时 sync,比如 1s1 次,这个时候最多就会丢失 1s 的数据。 + +对方追问 bgsave 的原理是什么?你给出两个词汇就可以了,fork 和 cow。fork 是指 redis 通过创建子进程来进行 bgsave 操作,cow 指的是 copy on write,子进程创建后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。 + +* Pipeline 有什么好处,为什么要用 pipeline? + +可以将多次 IO 往返的时间缩减为一次,前提是 pipeline 执行的指令之间没有因果相关性。使用 redis-benchmark 进行压测的时候可以发现影响 redis 的 QPS 峰值的一个重要因素是 pipeline 批次指令的数目。 + +* Redis 的同步机制了解么? + +Redis 可以使用主从同步,从从同步。第一次同步时,主节点做一次 bgsave,并同时将后续修改操作记录到内存 buffer,待完成后将 rdb 文件全量同步到复制节点,复制节点接受完成后将 rdb 镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。 + +* 是否使用过 Redis 集群,集群的原理是什么? + +Redis Sentinal 着眼于高可用,在 master 宕机时会自动将 slave 提升为 master,继续提供服务。 + +Redis Cluster 着眼于扩展性,在单个 redis 内存不足时,使用 Cluster 进行分片存储。 diff --git a/redis notebook/redis.org b/redis notebook/redis.org index 5197074..c715e1c 100644 --- a/redis notebook/redis.org +++ b/redis notebook/redis.org @@ -1,5 +1,6 @@ #+TITLE: redis 笔记 +- [[./redis相关资料.org][redis 相关资料]] - [[./redis源码难点:字典的遍历dictScan.org][redis 源码难点:字典的遍历 dictScan]] - [[../algorithm notebook/skiplist 跳表.org][skiplist 跳表]] - [[./redis源码阅读计划.org][redis 源码阅读计划]] diff --git "a/redis notebook/redis\346\272\220\347\240\201\351\230\205\350\257\273\350\256\241\345\210\222.org" "b/redis notebook/redis\346\272\220\347\240\201\351\230\205\350\257\273\350\256\241\345\210\222.org" index 3087f6c..c7de647 100644 --- "a/redis notebook/redis\346\272\220\347\240\201\351\230\205\350\257\273\350\256\241\345\210\222.org" +++ "b/redis notebook/redis\346\272\220\347\240\201\351\230\205\350\257\273\350\256\241\345\210\222.org" @@ -10,8 +10,54 @@ * 底层数据结构实现 ** DONE sds +**数据结构** +#+BEGIN_SRC c + typedef char *sds; // sds 是一个 char* 指针,指向 sdshdr.buf + struct sdshdr { + int len; // buf 数组已使用字节数 + int free; // buf 数组剩余字节数 + char buf[]; + }; +#+END_SRC + +**sds 和 C 字符串区别** +- sds 二进制安全。C 字符串只能存放文本数据,且末尾必须是 '\0',它不能保存图片、音频、视频等二进制数据 +- 获取字符串长度的时间复杂度为 O(1)。C 字符串获取长度时间复杂度为 O(n) +- sds 的 API 会自动扩容,避免缓冲区溢出。而 C 语言的 strcat(s1, s2) 函数在使用之前就需要检查字符串 s1 分配的空间是否足够 +- 减少频繁修改字符串带来的内存重分配次数 + - 空间预分配。假设修改后的字符串长度为 len, + - 如果 len < 1MB,会分配 2*len + 1Byte 空间 + - 如果 len >= 1MB,会分配 len + 1MB + 1Byte 空间 + - 惰性空间释放。sds 字符串缩短时,并不会主动释放多余空间,只是记录在 sdshdr.free 中。当然,sds 也提供了相应的 API,真正的释放 sds 的未使用空间 + ** DONE 双端链表 +** DONE 字典 + +关于 rdb 持久化或 aof 持久化时,哈希表的负载因子: +- 一般情况下,load-factor >= 1 时,对哈希表执行扩展操作。扩展后 load-factor <= 0.5 附近 +- 在执行持久化操作前,redis 服务器会把执行扩展操作的负载因子提高到 5,load-factor >= 5 时,才执行扩展操作。为什么这样呢? + - 持久化时,主进程会 fork 一个子进程,由子进程进行持久化操作。操作系统采用 copy-on-write 技术来优化子进程的使用效率。在子进程存在期间,提高执行扩展操作所需的负载因子,尽量避免在子进程存在期间进行 rehash。从而防止操作系统为进程拷贝大量的内存页。换句话说,就是为了让父进程和子进程尽量共享内存页,提高效率 + +当 dict 中键值对过多时会分多次 rehash,而不是一次性完成。 **渐进式 rehash** 同时采用如下 2 种方式 +1. 设置本次 rehash 时间为 x 毫秒。每次 rehash 100 步(一步就是对一个非空 bucket 进行 rehash,空 bucket 就跳过),rehash 之后检查用的总时间是否超过 x。如果没有,继续 rehash 100 步;否则,此次 rehash 结束,等待下一次继续 rehash +2. 对 dict 进行插入、删除、查找、获取一个随机 key 的操作前,执行: **当该 dict 没有安全迭代器,进行单步 rehash** 。这样就把该 dict 的 rehash 操作均摊到对字典的插入、删除等操作上了,避免了集中 rehash 带来的庞大计算量 + +**隐藏难点** +关于安全迭代器和非安全迭代器: +- dict 结构体中存在一个引用计数,当有一个安全迭代器在该 dict 上迭代时,该 dict 的引用计数 +1。 +- 非安全迭代器是迭代一个 dict 时,该 dict 是只读的。不能对 dict 执行导致哈希表 resize 的操作或其它造成 dict 改变的操作,否则可能发生重复迭代。迭代前和迭代后,dict 指纹必须相同。迭代过程中只能调用 dictNext() 接口 +- 安全迭代器在迭代过程中 dict 是可写的。在迭代过程中可以调用字典的 dictAdd(), dictFind() 等接口 +- 安全迭代器能够保证在迭代器未释放之前,字典的哈希表不会进行单步 rehash,在一定程度上保证了不会重复迭代同一元素。rehash 对迭代器的影响很大。假设一个迭代器在 dict 的哈希表 0 上进行迭代,其中一个元素 x 已经被迭代过了。在一次 rehash 后,x 被 rehash 到哈希表 1 中。而哈希表 1 此时还没开始迭代呢。所以最后 x 肯定会被重复迭代一次。所以安全迭代器能够保证访问到的元素不重复 + - 在对该 dict 执行:插入、删除、查找、获取一个随机 key 的操作时,如果该 dict 上没有安全迭代器(当然也肯定不会有非安全迭代器,因为非安全迭代器是只读的),执行单步 rehash + - 在对该 dict 执行:插入、删除、查找、获取一个随机 key 的操作时,如果该 dict 上存在安全迭代器,不进行 rehash。 +- redis rdb 或 aof 持久化时,会 fork 一个子进程。在子进程中会对整个 redis 服务器中的数据进行迭代,以将所有内容序列化到 rdb 或 aof 文件中。 + - 如果采用安全迭代器进行迭代,被迭代的 dict 的安全迭代器的引用计数 +1。由于进行了写操作,所以操作系统会复制相应的旧的物理内存页的内容到新的物理内存页中,然后设置虚拟内存与物理内存的映射关系,最后把父子进程的物理内存设置可读写,这样父子进程相同的虚拟内存都指向不同的物理内存。 + - 如果采用非安全迭代器,数据被认为是不可变的,所以在子进程中使用不安全的迭代器有助于减少 copy-on-write + +**难点** +关于游标迭代器:[[./redis源码难点:字典的遍历dictScan.org][字典的遍历dictScan]] + ** DONE skiplist ** DELAY hyperloglog @@ -21,6 +67,16 @@ ** DONE ziplist 数据结构 +文件 ziplist.c + +- 压缩列表是为了节约内存而开发的顺序型数据结构。 **主要是为了节约内存** + - 如果字符串能转换成整数就转换成整数存储 + - 当字符串不能转换成整数时才存储字符串原串 +- ziplist 占用一整块内存存储整个列表。而不像数据结构中的链表似的,链表每插入一个元素申请一块内存 +- ziplist 不会预先申请多余的内存容量以备将来的存储,它每次插入结点都会使用 realloc 重新分配一整块内存空间(每次插入结点至少使用一次 realloc,且一般情况下使用一次 realloc) +- ziplist 和 inset 一样,无论在大端机还是小端机,都是以小端字节序存储整数值 +- 在 redis 中,使用 ziplist 作为底层实现的有列表键、哈希键、有序集合键。当列表、哈希表、有序集合中的元素少时,会使用 ziplist 作为底层实现。 + * redis 数据类型实现 ** DONE list 键 @@ -193,12 +249,119 @@ redis 数据库中使用 redisDb.expires 字典来保存到期时间。其中 ke }; #+END_SRC -** TODO RDB 持久化 -** TODO AOF 持久化 +** DONE RDB 持久化 + +文件 rdb.h rdb.c + +rdb 持久化是指将 redis 中的所有非空数据库以及它们的所有键值对序列化后保存到磁盘。 + +为节省磁盘空间,redis 持久化时, +- 如果一个字符串能转化成整数值,就转化成整数值保存; +- 如果能进行压缩(配置文件中允许 RDB 压缩功能 且 字符串长度大于 20 byte),就使用压缩算法压缩一下再保存到 rdb 文件中 +- 如果以上 2 种情况都不行,才会原样保存字符串 + +redis 对文件流的读写(fread 和 fwrite)进行了封装,实现文件 rio.c 和 rio.h。读数据时直接从文件中读。写数据时先写入一个缓冲区,写入后,根据缓冲区已有数据的大小来判断是否需要把缓冲区的数据同步到文件中。当然,这里的同步是指把 redis 缓冲区的数据写入到 C 库的缓冲区中。在 rdb 文件保存结束时,需要调用 fflush 把 C 库的缓冲区中的数据同步到内核的缓冲区;然后调用 fsysc 把内核缓冲区的数据同步到磁盘 + +** DONE AOF 持久化 + +文件 aof.c + +aof 持久化是通过保存 redis 服务器所执行的写命令来记录数据库状态的。 + +aof 重写过程: +1. redis 父进程创建一个子进程 + - 子进程带有父进程的 redis 数据副本。它会遍历该 redis 数据副本在临时文件中对 AOF 文件进行重写。 + - 父进程继续处理客户端命令请求。处理请求时,它会把写命令追加到 **AOF 缓冲区(sds)** 和 **AOF 重写缓冲区** (重写缓冲区是一个链表,链表元素是一个 10MB 的缓存块) +2. 父进程收到子进程的退出信号后,如果子进程正常退出的话,父进程会把 AOF 重写缓冲区的数据追加到临时文件(此时主进程调用了 write,会被阻塞一会儿,阻塞时不能处理客户端命令请求)。然后对临时文件 rename(2),替换旧的 AOF 文件。重写完成 + +AOF 缓冲区追加内容与 AOF文件的写入和同步: +redis 执行写命令时会把命令追加到 **AOF 缓冲区 aof_buf** 。把 aof_buf 的内容写入并同步到磁盘的方式有 3 种: +1. =AOF_FSYNC_ALWAYS= 总是将 aof_buf 的所有内容写入并同步到 AOF 文件 +2. =AOF_FSYNC_EVERYSEC= 默认采用这种方式。将 aof_buf 的所有内容写入到 AOF 文件。如果距上次同步时间超过 1 秒,就使用一个线程把缓冲区内容同步到 AOF 文件 +3. =AOF_FSYNC_NO= 将 aof_buf 的所有内容写入到 AOF 文件。并不显式同步数据。何时同步由操作系统自己决定 + +关于 sync 和 sdatasync: +- rdb 使用 fsync 把内核缓冲区数据同步到磁盘。 +- 在 linux 上 aof 使用函数 fdatasync 把内核缓冲区数据同步到磁盘,每写入 32M 就显式调用一次 fdatasync,防止缓存累积过多造成 I/O 阻塞时间过长。 +- fsync 一般至少需要 2 次 I/O 操作,一次是同步文件修改的内容,另外一次是同步文件元数据(比如文件大小,访问时间等) +- fdatasync 一般情况下 1 次 I/O 操作就够了,它会同步文件修改的内容,一般不会同步元数据,只有在需要元数据才能正确处理后续的数据检索的时候才会同步元数据(例如:使用 ftruncate 函数修改了文件大小时,fdatasync 会需要 2 次 I/O) +- 根据 Wikipedia 的数据,当前硬盘驱动的平均寻道时间(Average seek time)大约是 3~15ms,7200RPM 硬盘的平均旋转延迟(Average rotational latency)大约为 4ms,因此一次 IO 操作的耗时大约为 10ms 左右 * 客户端和服务器的实现 -** TODO 事件处理器实现 -** TODO Redis 的网络连接库 +** DONE 事件处理器实现 +文件 ae.c ae.h ae_epoll.c 等 + +redis 需要处理两种事件:时间事件、文件事件 + +时间事件使用链表来实现的,所有的时间事件都存放在一个链表里。查找下一个超时的事件的时间复杂度为 O(n)。可以使用小根堆来优化,堆顶元素就是下一个超时的时间事件,查找时间复杂度为 O(1) + +时间事件是单次定时事件还是循环定时事件取决于时间事件的回调函数的返回值。返回值 ret = -1 表示是单次定时事件;非 -1 表示 ret 毫秒后再次处理该事件 + +关于人为调整系统时间导致的定时器时间混乱问题: +- 系统时间被用户改小了,redis 选择的策略是立即执行所有时间事件。这样事件可能会被提前处理 +- 系统时间被用户改大了,redis 不做处理。这样时间事件会提前处理 +所以只要人为调整操作系统的时间,已注册的时间事件一般都会提前处理。 + +** DOING Redis 客户端 +文件 networking.c + +通过使用由 I/O 多路复用技术实现的文件事件处理器,redis 服务器使用单线程单进程的方式来处理命令请求,并与多个客户端进行网络通信 + +对于每个和服务器进行连接的客户端,服务器使用 redisClient 结构来保存客户端的状态信息。服务器使用一个链表来保存所有和该服务器连接的客户端状态结构 + +redis 客户端分两种,这两种客户端的套接字描述符 fd 有区别: +- =伪客户端(fake client)= fd 值为 -1。伪客户端处理的命令请求来源于 AOF 文件 或者 Lua 脚本,而非网络 +- =普通客户端= fd 值为非 -1。普通客户端使用套接字来与服务器进行网络通信 + +**输入缓冲区 命令和命令参数** +- + #+BEGIN_SRC c + typedef struct redisClient { + // ... + sds querybuf; + robj **argv; + int argc; + // ... + } redisClient; + #+END_SRC + +- 例如命令: + #+BEGIN_EXAMPLE + SET key value + #+END_EXAMPLE + + querybuf 的 sds 值为 + #+BEGIN_EXAMPLE + *3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n + #+END_EXAMPLE + 服务器将客户端发送的命令请求保存到 querybuf 中后,服务器会对命令内容进行解析,相关信息保存到 argc 和 argv 属性中。如:argc 的值为 3。argv[0] 指向的 robj 类型的字符串对象为 "SET";argv[1] 对应 "key";argv[2] 对应 "value" + +- 输入缓冲区的大小会根据输入内容动态地缩小或扩大,但它的大小最大不能超过 1GB,否则服务器会关闭这个客户端 + +**回复缓冲区** +- 每个客户端都有 2 个回复缓冲区可用。一个是固定大小的缓冲区,16k;另外一个是可变大小的缓冲区,是一个列表 + - + #+BEGIN_SRC c + typedef struct redisClient { + // ... + char buf[REDIS_REPLY_CHUNK_BYTES]; // 固定大小的回复缓冲区 + int bufpos; // 回复缓冲区偏移量 + // ... + } redisClient; + #+END_SRC + - + #+BEGIN_SRC c + typedef struct redisClient { + // ... + list *reply; // 可变大小的回复缓冲区。它是一个字符串对象列表 + // ... + } redisClient; + #+END_SRC +- 服务器会首先尝试使用固定大小的缓冲区。当 buf 数组已经用完,或回复内容过大而无法放进 buf 数组中时,服务器就开始使用可变大小缓冲区。此时,固定大小的回复缓冲区和可变大小的回复缓冲区中的数据加一块就是要回复给客户端的内容 +- 每次向回复缓冲区添加内容后都会检查回复缓冲区的大小。 + 1. 如果回复缓冲区大小 >= 硬性限制(hard limit)所设置的大小,那么服务器会执行异步关闭客户端操作(redisServer.clients_to_close 链表保存了所有待关闭的客户端。异步关闭客户端就是把待关闭客户端添加到 redisServer.clients_to_close 链表尾部,服务器下一次执行 serverCron 函数时会关闭这个客户端)。否则执行步骤 2; + 2. 如果回复缓冲区大小 >= 软性限制(soft limit)所设置的大小,且其持续时间超过服务器设置的时长,那么服务器会执行异步关闭客户端操作。 + ** TODO 单机 Redis 服务器的实现 * 多机功能的实现 ** TODO redis 主从复制 diff --git "a/redis notebook/redis\347\233\270\345\205\263\350\265\204\346\226\231.org" "b/redis notebook/redis\347\233\270\345\205\263\350\265\204\346\226\231.org" new file mode 100644 index 0000000..35a63e3 --- /dev/null +++ "b/redis notebook/redis\347\233\270\345\205\263\350\265\204\346\226\231.org" @@ -0,0 +1,5 @@ +#+TITLE: redis 相关资料 + +- [[http://redisdoc.com/][redis 命令]] +- [[https://doc.yonyoucloud.com/doc/wiki/project/redis/index.html][Redis 源码日志]] +- [[http://redisbook.com/][Redis 设计与实现]] diff --git "a/shell notebook/shell \345\270\270\347\224\250\345\221\275\344\273\244.org" "b/shell notebook/shell \345\270\270\347\224\250\345\221\275\344\273\244.org" new file mode 100644 index 0000000..d0c5ab1 --- /dev/null +++ "b/shell notebook/shell \345\270\270\347\224\250\345\221\275\344\273\244.org" @@ -0,0 +1,82 @@ +#+TITLE: shell 常用命令 + +* tldr 查看指定命令的常用命令 +快速查看各种命令的常用命令 +#+BEGIN_SRC shell + $ tldr tar + + tar + + Archiving utility. + Often combined with a compression method, such as gzip or bzip. + + - Create an archive from files: + tar -cf target.tar file1 file2 file3 + + - Create a gzipped archive: + tar -czf target.tar.gz file1 file2 file3 + + - Extract an archive in a target directory: + tar -xf source.tar -C directory + + - Extract a gzipped archive in the current directory: + tar -xzf source.tar.gz + + - Extract a bzipped archive in the current directory: + tar -xjf source.tar.bz2 + + - Create a compressed archive, using archive suffix to determine the compression program: + tar -caf target.tar.xz file1 file2 file3 + + - List the contents of a tar file: + tar -tvf source.tar + + - Extract files matching a pattern: + tar -xf source.tar --wildcards "*.html" +#+END_SRC +* nslookup 查看域名解析是否正常 +查询DNS的记录,查看域名解析是否正常,在网络故障的时候用来诊断网络问题 +#+BEGIN_SRC shell + $ nslookup www.langdebuqing.com + Server: 8.8.8.8 + Address: 8.8.8.8#53 + + Non-authoritative answer: + Name: www.langdebuqing.com + Address: 149.28.67.225 +#+END_SRC +* netstat 查看端口网络连接信息 +查看网络连接信息 +#+BEGIN_SRC shell + $ netstat -anp | grep 1942 # 查看端口 1942 的网络连接信息 + tcp6 0 0 :::1942 :::* LISTEN 7677/python + tcp6 0 0 149.28.67.225:1942 218.249.22.2:52013 ESTABLISHED 7677/python + tcp6 0 0 149.28.67.225:1942 218.249.22.2:52023 ESTABLISHED 7677/python + tcp6 0 0 149.28.67.225:1942 218.249.22.2:52007 ESTABLISHED 7677/python + udp6 0 0 :::1942 :::* 7677/python + $ netstat -atp # 查看 tcp 的网络连接信息 + Active Internet connections (servers and established) + Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name + tcp 0 0 localhost:smtp 0.0.0.0:* LISTEN 1217/master + tcp 0 0 0.0.0.0:bintec-admin 0.0.0.0:* LISTEN 4638/sshd + tcp 0 0 0.0.0.0:http 0.0.0.0:* LISTEN 975/nginx: master p + tcp 0 0 149.28.67.:bintec-admin 218.249.22.2:50573 ESTABLISHED 2013/sshd: root@pts + tcp 0 0 149.28.67.:bintec-admin 218.249.22.2:50493 ESTABLISHED 1563/sshd: root@pts + tcp 0 76 149.28.67.:bintec-admin 218.249.22.2:51960 ESTABLISHED 5943/sshd: root@pts + tcp6 0 0 localhost:smtp [::]:* LISTEN 1217/master + tcp6 0 0 [::]:bintec-admin [::]:* LISTEN 4638/sshd + tcp6 0 0 [::]:1942 [::]:* LISTEN 7677/python + $ netstat -aup # 查看 udp 的网络连接信息 + Active Internet connections (servers and established) + Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name + udp 0 0 0.0.0.0:46753 0.0.0.0:* 7677/python + udp 0 0 localhost:323 0.0.0.0:* 492/chronyd + udp 0 0 0.0.0.0:bootpc 0.0.0.0:* 871/dhclient + udp6 0 0 [::]:1942 [::]:* 7677/python + udp6 0 0 localhost:323 [::]:* 492/chronyd +#+END_SRC +* tcptraceroute 基于 TCP 的 traceroute +可用来检测 tcp 阻断 +#+BEGIN_SRC shell + sudo tcptraceroute langdebuqing.com 2345 # 必须使用 sudo 权限 +#+END_SRC diff --git a/shell notebook/shell.org b/shell notebook/shell.org index 66f02da..a4ba881 100644 --- a/shell notebook/shell.org +++ b/shell notebook/shell.org @@ -22,3 +22,4 @@ - [[./regular expression.org][regular expression]] - [[./firewall-cmd防火墙.org][firewall-cmd 防火墙]] - [[./systemd.org][systemd]] +- [[./shell 常用命令.org][shell 常用命令]] diff --git a/templates-test/preamble.html b/templates-test/preamble.html index 1e5ea82..643b203 100644 --- a/templates-test/preamble.html +++ b/templates-test/preamble.html @@ -7,7 +7,7 @@
  • About
  • diff --git a/templates/preamble.html b/templates/preamble.html index 70193ec..3a5139d 100644 --- a/templates/preamble.html +++ b/templates/preamble.html @@ -7,7 +7,7 @@
  • About