OS

软中断 中断请求的处理程序应该要短且快,因为中断处理程序要求关中断(不接受新的中断请求),如果中断处理程序执行时间过长,可能在还未执行完中断处理程序前,会丢失当前其他设备的中断请求。 为了解决由于中断处理时间过长,导致新来的中断丢失,将中断分成两个部分: 硬中断:先关中断,处理跟硬件紧密相关或者时间敏感的事情 软中断:由内核触发,完成该中断剩余的耗时工作 其中硬中断直接抢占cpu,而软中断有专门的内核线程ksoftirqd处理,由操作系统调度执行。 软中断不只是设备中断的下半部分,一些内核自定义事件也属于软中断,比如内核调度等、RCU 锁。 linux上/proc/softirqs记录当前各类型软中断个数,如果NET_RX个数变化过快,说明很多网络包打进来,可以用tcpdump抓包分析,如果发现是异常流量,可以加防火墙,如果是正常流量,需要考虑升级硬件。 进程的状态 挂起态:处于阻塞状态的进程,进程可能会占用着物理内存空间,那么,就需要一个新的状态,来描述进程没有占用实际的物理内存空间的情况,这个状态就是挂起状态。(sleep或者ctrl+z) 进程和线程比较 创建: 进程是资源(内存、文件等)分配的基本单位,线程是调度的基本单位 进程创建涉及内存管理、文件管理等操作。而线程独享的资源只有寄存器和栈,对于内存和文件只需要共享即可 线程销毁更快,因为相对要释放的资源更少 切换调度 同一进程的线程切换更快,因为线程共享进程的地址空间,内存管理单元不涉及切换过程,不需要切换页表,不用冲刷TLB,要切换的上下文信息也少了很多 数据传递 同一进程的线程传递数据更快,由于共享内存、文件等资源,那么线程传递数据不需要经过内核,经过内核意味着需要切换到系统栈上执行,相当于切换上下文,并且系统调用由于不相信外界用户代码,会有额外的检查工作 死锁 条件: 互斥 资源不可剥夺 循环等待 占有并等待 切换内核态开销大的原因 每个进程都会有两个栈,一个内核态栈和一个用户态栈。当中断执行时就会由用户态栈转向内核态栈,系统调用时需要进行栈的切换,而且内核代码对用户不信任,需要进行额外的检查。系统调用的返回过程有很多额外工作,比如检查是否需要调度等。 虚拟内存 进程访问一个虚拟地址时,CPU芯片中的内存管理单元MMU会将其映射为物理地址,最终拿着这个物理地址去访问内存。而虚拟地址物理地址的映射方式主要有分段和分页两种。 分段:由程序员将虚拟内存划分为一个个段,虚拟地址划分为段号和段内偏移量,段号用于在段表中查询段的物理基地址、段大小、特权等级等。段基地址+段内偏移量就构成了物理地址。 分段存在的问题: 内存碎片:会有外部碎片。解决外部碎片是通过内存交换,也就是通过swap的方式实现了碎片整理,具体是将在用的内存先交换到硬盘上,然后再装载到内存当中,但是不是装载回原来的位置,而是紧邻上一片正在使用的内存。 内存交换率低:由于涉及到读写硬盘,因此swap的效率低是必然的。 综上,分段由于经常出现外部内存碎片,经常触发swap整理碎片,导致整个机器的卡顿。 分页:由操作系统将虚拟内存划分成一个个大小相同的页,虚拟地址划分为页号和页内偏移量,页号用于在页表中查询页的物理页号,拼接上页内偏移量就构成了物理地址。 分页的特点:消除了外部碎片,并且通过限制页的大小,限制了每次swap也只有一个或几个页,提高swap的效率。但是由于操作系统给进程分配物理内存是以页为单位的,当一个页没有全部使用到的话,会出现内部碎片,但页大小比较小,因此内部碎片的大小也会控制在一定范围内。 多级页表:由于一个虚拟地址必须通过查询页表来找到对应的物理页,而32位机器+4KB页大小的环境下,一个进程的页表占据4MB大小,这样纯属是一种浪费。因此引入二级页表,让一级页表长居内存,而二级页表在需要的时候再加载到内存,由于程序的空间局部性,最好的情况下内存只需要为进程保留一级页表和一页的二级页表。 linux内存布局 每个进程的虚拟内存空间划分为用户空间和内核空间,所有进程的内核空间实际上映射的是同一块物理内存: 下面是用户空间的具体布局: 其中文件映射段的内存和堆内存一样都是动态分配的,比如使用 C 标准库的 malloc() 或者 mmap() ,就可以分别在堆和文件映射段动态分配内存。 malloc分配内存的原理 malloc可能会使用brk或者mmap这两个系统调用来向操作系统申请内存:当分配内存小于128KB则用brk,大于128KB则用mmap。brk的内存在free之后会归还内存池,不会归还给操作系统,而mmap的内存free之后直接归还给操作系统。因此,如果全部使用mmap来分配内存,那么每次分配内存都触发系统调用,并且每次都触发缺页中断,效率非常低。 OOM原理 触发异步回收,不阻塞进程执行 触发同步回收,阻塞进程执行 OOM 可以被回收的内存分为文件页和匿名页,对于脏页,会触发IO写回硬盘,否则可以直接释放。对于匿名页(堆、栈等用户程序使用到的内存)则通过swap机制换出到硬盘。因为触发磁盘IO,降低系统运行效率,看起来就是发生卡顿。 如果没有空闲文件页和匿名页,并且也没有未分配的物理内存,就会触发OOM,根据算法选择占用物理内存较高的进程,然后将其杀死,以便释放内存资源,直到有足够的内存进行分配。 如何保护一个进程不被OOM杀掉:OOM killer选择被杀程序的时候通过计算一个分数来决定,分数越高越优先被杀 // points 代表打分的结果 // process_pages 代表进程已经使用的物理内存页面数 // oom_score_adj 代表 OOM 校准值 // totalpages 代表系统总的可用页面数 points = process_pages + oom_score_adj*totalpages/1000 oom_score_adj可设置的范围为[-1000, 1000],默认为0,只与进程占用的物理内存页数相关。可以通过设置oom_score_adj为 -1000,降低该进程被 OOM 杀死的概率。一般是特别重要的系统服务才会做这样的配置。 ...

九月 2, 2024 · by NOSAE

Redis

字符串 实现 使用SDS(简单动态字符串),SDS不仅可以保存字符串还可以保存二进制数据,获取长度的时间复杂度是O(1),SDS的API是安全的,比如拼接字符串不会造成缓冲区溢出,总的来说就是对数组封装,提供一系列方便操作的API。 字符串对象有三种编码:int、raw、embstr 整数:ptr从void*转换为long 短字符串(至于多短,每个redis版本不一样):分配一块连续空间保存redisObject和SDS 长字符串:分别为redisObject和SDS分配两个内存,redisObject.ptr指向SDS embstr如果要修改大小的话,只能重新分配空间。因此embstr实际上是只读的,当要修改embstr的长度,redis会先将其转换为raw再进行修改。 使用场景 缓存对象、常规计数(INCR)、分布式锁(SET-NX)、共享Session List 列表 List在使用上就是一个Deque双端队列,存字符串 实现 redis3.2之前:小列表使用压缩列表实现,大列表使用双向链表实现 redis3.2之后:使用quicklist实现 使用场景 消息队列: 保序:LPUSH+RPOP,但是RPOP需要轮询,浪费CPU性能,因此还提供了BRPOP阻塞式读取 处理重复:每条消息设置一个全局唯一ID,利用ID判断是否已经消费,List不会为消息生成ID,需要用户自己添加 保证可靠:BRPOPLPUSH,读取的同时将消息插入另一个List作为留存,如果用户处理消息时失败,下次从留存List重新读取 作为消息队列的缺点: 不支持消费者组 Hash 哈希 适合存储对象 实现 redis7.0之前:小Hash使用压缩列表,大Hash使用哈希表 redis7.0之后:小Hash使用listpack,大Hash使用哈希表 使用场景 缓存对象:一般可以用String+序列化存储对象,并将变化频繁的字段抽出来用Hash存储 Set 集合 实现 元素都是整数的小Set:整数集合 否则:哈希表 使用场景 点赞:保证每个用户只能点一次赞 共同关注(SINTER) 推荐关注(SDIFF) 抽奖(允许重复中奖SRANDMEMBER,不允许SPOP) 潜在风险:「并、交、差」的计算复杂度高,数据量大的情况下会阻塞redis。可以用从库进行计算,或交给客户端来自行处理,从而不阻塞主库 ZSet 有序集合 比Set多了一个score,按照score排序。ZSet不支持「差」运行 实现 redis7.0之前:小zset使用压缩列表,大zset使用跳表 redis7.0之后:小zset使用listpack,大zset使用跳表 使用场景 排行榜:score最大的前几个(ZREVRANGE),范围score内最小的前几个(ZRANGEBYSCORE) 电话排序:获取132、133开头的号码( ZRANGEBYLEX phone [132 (134 ),不要在分数不一致的 SortSet 集合中去使用 ZRANGEBYLEX和 ZREVRANGEBYLEX 指令,因为获取的结果会不准确 BitMap 实现 String 使用场景 签到统计:比如一年的签到只需要365个bit 判断登陆态:用户ID作为offset,如果ID是连续的,5000 万用户只需要 6 MB 的空间(5000万位) ...

九月 2, 2024 · by NOSAE

网络

tcp 报文 tcp 三次握手 客户端发送:SYN、随机序列号 x 服务端发送:SYN、ACK、随机序列号 y、确认应答号 x+1 客户端发送:ACK,可以携带数据 tcp 为什么不是两次握手 防止旧的 SYN 建立连接:如果只有两次握手,那么服务端收到 SYN 后直接进入 established 状态(此时可以发送数据),然后返回 ack 给客户端,如果这个 SYN 是旧的,那么最终客户端发现不是想要的 ack,就会发送 rst 断开连接,那么服务端又要去断开已经建立好的连接,浪费资源。 如果是三次握手,那么服务端不会直接进入 established。 同步序列号:初始化序列号是最重要的,所以客户端发送初始序列号 x(第一次握手),客户端需要得知服务端已经收到并且服务端发送初始序列号 y(第二次握手),服务端需要得知客户端已经收到(第三次握手) 如果第三次握手没发送到对端:本端也能直接发送数据,因为: 但这不说明只需两次握手,三次握手和和两次握手的区别在于第二次握手后,对端是否直接进入 established。 tcp keepalive keepalive 是 TCP 保鲜定时器,链接空闲时的心跳机制。 当超过一段时间之后,TCP 自动发送一个数据为空的报文给对方,如果对方回应了这个报文,说明对方还在线,链接可以继续保持,如果对方没有报文返回,并且重试了多次之后则认为链接丢失,没有必要保持链接。 tcp 四次挥手 客户端发送:FIN 服务端发送:ACK 服务端发送:FIN 客户端发送:ACK 客户端进入 TIME_WAIT,等待 2MSL(报文最大生存时间) 其中,客户端一直收不到第三次握手 FIN 的话,客户端有两种情况: 对于客户端调用 shutdown() 的情况,只关闭发送数据不关闭接收数据,因此客户端死等 对于客户端调用 close() 的情况,同时关闭发送和接收数据,长时间收不到 FIN 就会主动 close 服务端一直收不到第四次握手 ACK 的话(在这之前处于 CLOSED_WAIT,并且服务端调用 close(),发送了 FIN),就会主动 close。 ...

九月 2, 2024 · by NOSAE

在MacOS中运行k3s

k3s https://github.com/caicloud/kube-ladder 安装ubuntu家的multipass虚拟机 brew install multipass (镜像路径在/var/root/Library/Caches/multipassd/qemu/vault/images下) 创建一个虚拟机并启动 multipass launch -n k3s01 -c 2 -m 2G -d 16G 查看虚拟机 multipass list multipass info k3s01 进入虚拟机终端 multipass shell k3s01 设置root密码,更新apt sudo passwd apt-get update 数据卷,数据传输 multipass mount host-path vm-name:vm-path multipass umount vm-name multipass transfer host-file vm-name:vm-path 虚拟机操作 multipass start/stop/delete/purge vm-name 指定虚拟机初始化时的配置、执行的命令等 multipass launch -n vm-name --cloud-init config.yaml # config.yaml runcmd: - apt-get update # 更新包 - curl -sfL https://get.k3s.io | sh - # 安装k3s - echo "alias k=kubectl" >> ~/.bash_aliases 指定k3s启动时config的访问权限,使得在非root用户下也能kubectl管理k3s ...

九月 1, 2024 · by NOSAE

jekyll chrispy主题的语法

Headings H1 — heading {: .mt-4 .mb-0 } H2 — heading {: data-toc-skip=’’ .mt-4 .mb-0 } H3 — heading {: data-toc-skip=’’ .mt-4 .mb-0 } H4 — heading {: data-toc-skip=’’ .mt-4 } Paragraph Quisque egestas convallis ipsum, ut sollicitudin risus tincidunt a. Maecenas interdum malesuada egestas. Duis consectetur porta risus, sit amet vulputate urna facilisis ac. Phasellus semper dui non purus ultrices sodales. Aliquam ante lorem, ornare a feugiat ac, finibus nec mauris. Vivamus ut tristique nisi. Sed vel leo vulputate, efficitur risus non, posuere mi. Nullam tincidunt bibendum rutrum. Proin commodo ornare sapien. Vivamus interdum diam sed sapien blandit, sit amet aliquam risus mattis. Nullam arcu turpis, mollis quis laoreet at, placerat id nibh. Suspendisse venenatis eros eros. ...

八月 31, 2024 · by NOSAE