八奈见 level
获赞
1024
粉丝
205
关注
228
看过 TA
8065
蚌埠坦克学院
2025
golang
IP属地:上海
你离开我的时候 说过祝我实现梦想
私信
关注
2024-08-27 23:50
蚌埠坦克学院 golang
地址栏输入 URL 回车后的过程中,详细展开说下 dns tcp http 协议使用的过程。这篇个人感觉整理得一般,要是刷到了不建议阅读,觉得角度不错可以自己看后面参考和小林重做整理--DNS 解析:● 浏览器缓存 chrome://net-internals/#dns -> hosts文件 gethostbyname库函数-> DNS Server● server 一般显示 本地子网 arp 查询,然后去 isp 查 dns 缓存dns 解析之后,下面进入浏览器内核代码的网络编程部分● 这个时候还没有 http 参与,我们需要事先建立好连接● 调用 socket 相关系统函数,创建客户端 socket● 建立连接的请求直接由 tcp packet 提供信息,往下分别通过网络层,链路层等流程,然后通过某种网络环境,经过路由器进行网络传输在如上的循环中进行 TCP 三次握手(四次挥手也是)● 客户端初始化 isn,设置 syn 位作为第一次 tcp packet 的内容发送● 服务端收到,ack 域设置 isn+1 表示收到。然后同样设置 syn 初始化 isn● 客户端同样设置 ack 位并且 ack 域设置 server isn + 1● (后面确保可靠传输的流程就是把 ack 的数字 编程 + byte 数)如果说,我们在 url 解析阶段(不是 dns 解析)得到的端口是 443,那么我们开始进行 tls 握手● 相互 hello:确定套件算法版本等,主要交换客户端随机数和服务端证书。(一般不做客户端验证,这个是服务端网络编程部分决定的)● 客户端响应:生成第二个客户端随机数 pre master,证书公钥加密传输。并包含 Finish 消息便于做摘要验证○ 根据本机信任 ca 列表验证服务端证书○ premaster + 客户端第一个随机数 + 服务端随机数 = 生成 = 会话密钥○ 验证原理是所有内容先做 sha 摘要下来,然后加上密钥 输入 prf 伪随机数函数得到「验证消息」,客户端通过相同方案来看验证消息是否正确● 服务端响应:同样做摘要得到验证消息○ 同上生成会话密钥,密钥不直接做交换。http● 服务器端通过 「http deamon 程序」来处理 http 请求,一般是 nginx apache 或者编程语言 web 框架了。往后一般离用户态比较近了,比较常接触,可定义性也比较强。不过也有有些常见的操作。● nginx 常见操作:url 重写、负载均衡、虚拟主机● web 框架常见操作:○ http 整个消息拆分成几个主要部分,关键就是方法,路径○ 然后路由处理、过中间件等(待扩展,一时半会我也想不起来有哪些了。--因为感觉这个题目,个人平常都答得太简单了,其实这确实是个引出来常见其他计网面试题的好过程,整理一下主要想串起来其次也是后面就能占据主动了。参考 https://github.com/skyline75489/what-happens-when-zh_CN ,有不对请指出--#每天一篇简单博客 day2 (个人打卡,欢迎监督今天比较水了,不过坚持最重要
0 点赞 评论 收藏
分享
2024-08-26 21:53
已编辑
蚌埠坦克学院 golang
放在以前是比较冷的项目,现在已经人手一个了有空建议阅读极客兔兔原文手敲一遍这里来个速成版作为个人原理复习也供各位快速回顾,有什么问题希望能不吝赐教 实现了哪些基本功能?我们从最简单的内存 kv 缓存开始认知:● 直接一个 map[string]any 就行了。必要功能 1: 内存过期● 实现方案考虑开一个协程计时,或者直接懒删除等用到再删。分别的缺点就是耗 cpu 和耗内存。● 一般最优解还是学 redis 的懒删除 + 定时清理,综合了两者的优点必要功能 2:被动缓存、自动回源● 一个简单的缓存是不用回源的,这个适用于我们在业务逻辑中控制了所有手动设置缓存的场景。但更多场景的缓存设置逻辑是相同的,就是简单的不存在就设置,所以我们将其抽象成自动回源策略。● 自动回源除了自动被动缓存以外,也可以设置定时的主动回源,方便一些我们想做缓存预热的情况。● 回源的实现,在一些框架里边是直接接 db 的。但是这里的设计是直接留一个接口供用户自己实现。然后由于这块我们其实只抽象了一个函数,所以可以用‘接口型函数’的技巧省去一个结构体的定义。优化点 1:并发不安全● 首先考虑直接加互斥锁。● 其次可以锁分片降低锁粒度 + 用 hash 来固定定位到某个分片。这个是泛用性更强的做法,同时这种思想也用在其他很多地方,数据库的分片横向扩展也有减少锁竞争这样的好处。● 直接上 sync.Map 来主要用在增长型 set 读多写少或者插入多不怎么需要更新的场景。优化点 2:内存泄露● 必要性只是因为内存是理论会无限增长的,我们加一个兜底淘汰保护就好了。参考 redis 的策略默认是不提供服务,但是也能选择淘汰算法。● 我们可以实现一个基础的 LRU 来做淘汰,当然如果确有热点数据的话,可以微调出 LRU-K 来应付实际情况。一些细节● 值没有使用 any,抽象了 一个 byteview,没有类型问题和反射的性能消耗,然后通过返回拷贝的方式来实现只读实际这个项目里面其实没实现那么多后面的变化大概就是从 go-cache 到 groupcache 了,实现源码也可以参考这两个项目 怎么解决分布式下的几个问题的:怎么定位节点,节点数量变化。● 一致性 hash + http pool● 一致性哈希○ 一个哈希环,可以理解为首尾相接的数轴。我们的 key 和 ip 分别通过某种哈希算法,可以得到一个值,取模落到哈希环上。○ 节点 ip 的哈希是环上的常驻值,然后 key 得到的值,落到环上以后,顺时针去找到它应该在的节点,这样就不用担心节点数量变化了。○ 这种情况下容易存在的问题,就是数据倾斜,可能太多数据在一个节点上。解决方案就是‘虚拟节点’,我们增加节点数,但是不增加实际机器数。把虚拟节点映射到真实机器节点上● http pool○ 回顾 v 获取流程:当前机器是否有内存?没有->是否在其他机器?没有->回源○ pool 的作用:提供 http 服务(实现 handler) + 保存定位其他 peers○ picker + getter,一个封装一致性哈希,一个封装从 http 请求中获取缓存值 singleflight 怎么实现?singleflight,概括来说,当并发获取缓存的时候,最先来的去拿缓存,其他的等这个最先去的结果,相同时间段内只走一趟,牺牲极小时间的即时性一致性来大量减少回源 db 的情况。实现方案:● key 标识一次调用,map 存储是否在调用,经过 map 走两个不同的路径,有就直接等,没有就正常调用,然后删除。○ 参考:https://paste.mozilla.org/VvqBqQ0X● 几个要点○ map 的三次访问都要加锁○ 利用 wg 来同步,阻塞和通知其他协程第一到的协程调用完了我记得还有别的实现方案,有空来补一下,或者评论区大佬可以说一下。这个我暂时学不过来了。然后这个问题还确实被问过。 protobuf 干嘛的? 和 rpc 的关系?● 单独 protobuf 其实很好理解,一种通用性扩展性极强的用来序列化结构数据的编码方式。● 在分布式缓存里,他的作用就是用来代替 json 的。不过相比 json 因为他需要实现泛用性,需要写 proto 接口定义,我们一般也叫做 idl 接口定义语言。● protobuf 就是 gprc 使用的序列化方案。一般的 rpc 其实最终还是落到用 http 来传输,主要是为了兼容性,否则每个客户端都需要做单独的适配。--#每天一篇简单博客 day1 (个人打卡,欢迎监督
0 点赞 评论 收藏
分享
2024-08-18 23:08
已编辑
蚌埠坦克学院 golang
选择:红黑树什么时候会反转、哪个页面置换算法会触发belady多选:(分值最高),inode、进程优先级会影响调度的什么、有关分库的场景方案哪个是正确的、排序是否稳定整体来说,这里笔试算有意义的一些题目了,不过还是有几个比较偏的。规则特性:编程题可以返回重复改,可以用本地ide编程题,比上一次简单很多多,一个飞机走一个 01数组,初始朝右遇到1或者边界顺时针转90,最终能遍历到多少个块。我直接模拟,不知道为什么只过了三个答案用例。一个小时都在想这个了,选择题根本没挣扎余地希望有大佬做出来的说下可能的原因--每次这种编程题只能过一半就特别痛苦,基本能过的情况十几分钟就写出来,找后面的情况浪费很多没用的时间,不重要的笔试这种情况还是直接放弃性价比更高一点。我自己有反思过,一般就是分边界情况和逻辑不完全正确。后者一般我就多清空一下思路,多重新看看题,但是很多时候还是没办法发现问题。有经验的牛佬也希望能分享下--然后我平常确实非常不喜欢过笔试题,所以还是应该抓住机会现场学习好。这次应该快结束再看一遍前面选择题的。下面直接过一下笔试内容:红黑树:完全不想学原理,直接记结论插入节点时的反转情况 —— 插入节点的父节点和叔叔节点都是红色删除节点时的反转情况 —— 删除节点导致的双重黑色 稳定排序- ologn 里边只有归并是稳定的,因为归并合并子问题用的是合并两个有序数组那种算法,是能保证相对顺序的- on 插入选择冒泡,只有选择是不稳定的(艹这个我选错了。我当时不知道为什么跟插入搞混了)插入稳定是因为你是按顺序去从后面找元素插入的,插入的时候也保证相对顺序就行;而选择是每次都选择最值,假如你有多个最值,你原来的顺序,和你应该要插入的顺序容易出现矛盾具体我们看一个例子:[4, 3, 2, 3, 1]操作的时候,第二个2会因为最小值的规则跑道前面来- 其他排序,希尔不稳定,别的都稳定 页面置换- belady:增加页框命中率反而降低的异常现象- 结论:fifo是会触发的 一个inode可能对应多个文件吗?我理解应该是不能对应多个文件,但是能对应多个文件名复习linux文件系统- 文件:文件实际是硬盘上的区域- inode:存储文件元信息,主要就是文件是怎么存在磁盘上- 目录和文件名:文件名是我们直接看到的东西,目录用来组织文件名的,多个文件名对应同一inode就是硬连接 进程优先级具体有哪些影响?方面:调度算法选择权重、响应时间 / 饥饿老化可能性、资源时间片、抢占优先级具体选项:- 会影响调度队列中的顺序- 在抢占起作用,但是不仅在- 在某些调度算法中,会获得更长cpu时间,但是不一定扩展:sre 相关操作- `$ ps -eo pid,comm,pri,nice` 查看优先级- `nice 设置进程优先级`--
投递大疆等公司7个岗位
0 点赞 评论 收藏
分享
2024-08-24 20:21
已编辑
蚌埠坦克学院 golang
这类问题定位其实很明确,性价比确实没那么高,不算是高频八股。但是如果自己项目有涉及,加上恰好被问到的话,那就可以成为加分项。(但是确实难以去作为一个主动介绍的程度,只能说是一个防备式的准备)以及 Nginx 实现原理有涉及一些常见八股,所以在各种深层原理中性价比就偏高。虽然被问的概率还是总体相对低。反正还是来速成一下。上面和下面的说法都是个人见解,欢迎指出错误。--- 内存池:常见的优化,几乎高性能框架都会设计到内存池池这种思想我个人概括为:不是要用就分配用完就释放,而是用完不马上销毁,后边就能像是预分配一样反复利用nginx 里的要点是: 在os内核层的页式管理上的应用层继续使用了「内存块」的管理方案来管理申请到的大片内存,减少应用层分配碎片和频繁的系统调用effective-go里面就有一个挺有意思的简单例子,这里也分享一https://github.com/bingohuang/effective-go-zh-en/blob/master/14_Concurrency.md 翻到最后概括来说就是 rpc 标准包里边在网络io接受字节流数据的时候,用户态缓冲区我们预分配好放在一个channel中来维护,在用完之后可以回来被复用我觉得这种简单漏桶模型的思想其实是跟池类似的,不过没有池那么灵活了 基于Reactor的多进程并发模型处理大量反向代理等连接事件:(评论区学习的)反向代理,大家应该都知道,就是你的请求过来了,我们帮请求放拿到响应再返回给你。Reactor 模型是一种设计模式,在很多高并发高性能IO系统中也都有用到,比如 Redis、RabbitMQ。Reactor 模型的主要特点可以概括为:事件循环、事件分发、非阻塞io。除了这些高性能系统,浏览器运行js和epoll本身也算是利用了这种设计思想。而 Nginx,概括来说就是:**多进程、非阻塞异步IO** 的并发模型。我们从典型的运行过程来认识这个模型:1. 主进程负责管理配置和生成 worker 进程2. 每个worker开自己的单线程进行事件循环,基于特定的多路复用模型进行单线程处理连接建立和响应事件(其实这里我个人有一定疑问,除非说epoll_wait本身就算是一种异步了)为什么不用多进程?(评论区大佬贡献的问题)这里我个人理解原因主要是:1. 为了 worker 隔离从而确保稳定性2. worker 的设计具有一定独立性,本身就有进程的体量,也是为了实现横向扩展的能力nginx实际实现,就是在每个工作进程(worker process)中都开一个事件循环来等待事件,得到之后进行分发,分发之后的处理也使用非阻塞io,完成之后回调相关函数做后续操作(事件驱动)。然后其中我们获取事件的方式,就交给了os内核的io多路复用机制:这里我们知道,epoll解决的问题是进行网络io的时候如何高效建立连接和监听请求的。传统建立tcp连接的方式,分阻塞和非阻塞两种。阻塞就是监听连接建立和io过程都阻塞不能做其他事;非阻塞就是通过忙轮询的方式来看是否有连接,可以暂时做别的事情,不过io过程也是阻塞的。这里结合网络编程伪代码理解会更好而epoll可以实现多路复用,在单线程内,我们可以同时处理多个连接。具体来说,epoll用红黑树存储事件和他们对应的socket,当有网络连接事件过来的时候,红黑树会扫一遍看看哪些事件要被触发,然后相关socket会进入就绪队列。一般最简单的一种用法,我们通过阻塞的方式获取到当前所有就绪队列的socket,如果是 我们用来监听的 server socket,那么就accept然后建立新的事件和 client socket加入红黑树,如果是client socket我们就正常处理io事件。总结就是有高效查找、事件触发等优势,以此可以高效处理大量连接(和io过程关系不大,主要还是连接建立和连接事件触发两大块)始终使用「边缘触发」的就绪队列维护方式(用户必须一次处理完阻塞获取的所有事件,否则会清理掉)来应付高并发。不过确实nginx只在linux上使用epoll,而且这个其实反向代理关联不会特别大,多一个建立连接的目标而已,上游的连接建立依然会使用 epoll。复杂还是复杂在网络编程的实现,不过能说出来这些感觉已经够了。 零拷贝处理静态文件:就是除了kafka,nginx也用了零拷贝nginx 利用 location 来进行动静分离。动态资源我们反向代理直接丢给服务器处理。nginx 可以利用他自己的优化来单独去处理对静态文件的请求,除了缓存就是零拷贝了。详细原理就不多说了,看小林会更好点。要说详细了我也不会,实际实现还挺复杂的,除了sendfile还有其他调用,只能跟面试官嘤嘤嘤了我感觉说简单了到知道dma是用来承接cpu的一部分操作来处理一次磁盘io过程,然后零拷贝是用来继续减少从用户缓冲区发送到内核socket的两次拷贝和一次上下文切换的。---个人笔记有不对请指出牛佬们其他有关于nginx的常见考点也可以分享下 非常感谢
0 点赞 评论 收藏
分享
2024-08-09 09:55
已编辑
蚌埠坦克学院 golang
ManCity:项目深度这方面我感觉可以参考项目的一些架构设计,就比如说你的项目具体是如何应对高并发,大数据量,如何保证高可用,使用了那些组件,运用了哪些技术,解决了哪些问题,前后修改的对比,未来的优化点等等
我的失利项目复盘
0 点赞 评论 收藏
分享
0 点赞 评论 收藏
分享
2024-08-07 12:48
蚌埠坦克学院 golang
0 点赞 评论 收藏
分享

创作者周榜

更多
关注他的用户也关注了:
牛客网
牛客网在线编程
牛客网题解
牛客企业服务