做网站建设的名声很差吗,怎样查看网站开发语言,网络建设工程师是干什么的,wordpress私密页面深信服面经---云计算高级开发一、一面问题概览二、实操相关三、复盘对问题答案进行整理#xff08;查漏补缺#xff09;3.1、go语言简单了解3.2、项目中成就感最大或挑战最大的地方3.3、项目问题---协议头引入之后#xff0c;包的大小增加了多少3.4、如何建立缓存3.5、cache…
深信服面经---云计算高级开发一、一面问题概览二、实操相关三、复盘对问题答案进行整理查漏补缺3.1、go语言简单了解3.2、项目中成就感最大或挑战最大的地方3.3、项目问题---协议头引入之后包的大小增加了多少3.4、如何建立缓存3.5、cache中间件更新机制3.6、redis缓存的写策略3.7、redis缓存热点数据在什么场景下会产生脏数据3.8、在CRUD中如果操作主数据库和缓存数据库3.9、内存泄漏怎么检测3.10、socket句柄比较多怎么分析和解决3.11、什么是零拷贝3.12、协程、线程、进程三者的关系和区别3.13、父子进程在资源上有什么区别3.14、C中map数据结构底层为什么不使用高度平衡二叉树3.15、消息队列存在的价值3.16、引入消息队列会带来什么问题四、面向stack overflow编程五、算法题总结参考一、一面问题概览
1、先做一下的自我介绍。 2、是否了解go语言 3、项目中成就感最大的是哪个 4、协议头引入之后包的大小增加了多少根据项目问的 5、redis缓存问题如何建立缓存根据项目问的 6、cache中间件更新机制是怎么样的根据项目问的 7、为什么更新数据的时候不是用写的方式而是使用删除的方式根据项目问的 8、redis缓存热点数据具体在什么场景下会产生脏数据 9、在CRUD中你的后台服务是先处理数据库还是先处理缓存redis这四个操作分别是怎么处理的 10、缓存方案中先删除缓存数据再更新数据库最后再同步写这种方式在高并发下会产生什么问题 数据一致性会不会有问题或者说同时出现并发读和并发写的情况会发生什么 11、还知道其他的缓存更新模式吗 12、内存泄漏怎么检测 13、如果一个服务的句柄文件句柄或socket句柄一直增加没有下降怎么分析是什么问题 14、系统下调大句柄数量的命令是什么ulimit。 15、socket句柄比较多怎么分析和解决这种现象在什么情况下是正常的在什么场景下是不正常的 16、服务非常多接口也非常多现在不知道在内存或socket句柄在何处泄漏的怎么分析 17、什么是零拷贝 18、哪些技术可以做到零拷贝 19、什么是Direct IO 20、操作系统上说一下协程、线程、进程三者的关系在资源上面有什么差别 21、父子进程在资源上有什么区别可以从fork的写时复制来说明 22、C中map数据结构底层为什么不使用高度平衡二叉树来做https://blog.csdn.net/weixin_61207303/article/details/123402294 23、对windows上的程序开发是怎么理解的 24、window开发客户端最头疼的问题是什么 25、windows用户界面库有哪些qt、duilibUI 26、消息队列存在的价值是什么主要解决什么问题 27、引入消息队列会带来什么问题 28、说一下消息队列的优缺点
二、实操相关
1、面向google编程面向stack overflow编程画出流程图。 1Google不到代码怎么办 2如果google到的代码最后验证不是想要或合适的验证失败怎么办 2、算法题给一个数组root[]{6,3,5,3,6,7,8,-1,-1,5,6},构建二叉树然后中序遍历输出二叉树。
#mermaid-svg-9kyMRZvCLgN2zZO5 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-9kyMRZvCLgN2zZO5 .error-icon{fill:#552222;}#mermaid-svg-9kyMRZvCLgN2zZO5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9kyMRZvCLgN2zZO5 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-9kyMRZvCLgN2zZO5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9kyMRZvCLgN2zZO5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9kyMRZvCLgN2zZO5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9kyMRZvCLgN2zZO5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9kyMRZvCLgN2zZO5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9kyMRZvCLgN2zZO5 .marker.cross{stroke:#333333;}#mermaid-svg-9kyMRZvCLgN2zZO5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9kyMRZvCLgN2zZO5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9kyMRZvCLgN2zZO5 .cluster-label text{fill:#333;}#mermaid-svg-9kyMRZvCLgN2zZO5 .cluster-label span{color:#333;}#mermaid-svg-9kyMRZvCLgN2zZO5 .label text,#mermaid-svg-9kyMRZvCLgN2zZO5 span{fill:#333;color:#333;}#mermaid-svg-9kyMRZvCLgN2zZO5 .node rect,#mermaid-svg-9kyMRZvCLgN2zZO5 .node circle,#mermaid-svg-9kyMRZvCLgN2zZO5 .node ellipse,#mermaid-svg-9kyMRZvCLgN2zZO5 .node polygon,#mermaid-svg-9kyMRZvCLgN2zZO5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9kyMRZvCLgN2zZO5 .node .label{text-align:center;}#mermaid-svg-9kyMRZvCLgN2zZO5 .node.clickable{cursor:pointer;}#mermaid-svg-9kyMRZvCLgN2zZO5 .arrowheadPath{fill:#333333;}#mermaid-svg-9kyMRZvCLgN2zZO5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9kyMRZvCLgN2zZO5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9kyMRZvCLgN2zZO5 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-9kyMRZvCLgN2zZO5 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-9kyMRZvCLgN2zZO5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9kyMRZvCLgN2zZO5 .cluster text{fill:#333;}#mermaid-svg-9kyMRZvCLgN2zZO5 .cluster span{color:#333;}#mermaid-svg-9kyMRZvCLgN2zZO5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9kyMRZvCLgN2zZO5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}635367856小结
回答方式有待提升需要拓展讲述技术切忌一问一答应该就问的知识点进行扩展讲述。回答需清晰贯通尽量避免停顿。语速平和逻辑要清晰。
三、复盘对问题答案进行整理查漏补缺
3.1、go语言简单了解
大厂后端高并发程序 / 服务基本都有引入golang语言来开发所以需要了解一下golang语言。
golang为高并发而生由google在2009年正式发布golang从语言级别支持并发通过轻量协程goroutine实现程序并发运行。 golang语言是google推出的具有强类型原生支持并发且具有垃圾回收GC功能的编译型语言。Go 语言语法与 C 相近但功能上有内存安全GC垃圾回收结构形态及 CSP-style 并发计算。
golang的轻量主要体现在
上下文切换代价小。goroutine上下文切换只涉及三个寄存器计数寄存器PC、堆栈指针寄存器SP、数据寄存器DX的值修改而对比线程的上下文切换则需要涉及模式切换从用户态切换到内核态、以及 超过16 个寄存器的刷新。内存占用少。线程栈空间是2Mgoroutine的栈空间最小只有2K。
Golang 程序中可以轻松支持10w 级别的 Goroutine 运行而线程数量达到 1k 时内存占用就已经达到 2G。
go调度器模型通常称为G-P-M模型它包括四个重要结构G、P、M、Sched。go程序通过调度器来调度goroutine在内核线程上的执行但是Ggoroutine并不直接绑定OS线程MMachine运行而是由goroutine scheduler中的Pprocessor逻辑处理器来作为获取内核线程资源的中介。 Go 调度器中有两个不同的运行队列全局运行队列(GRQ)和本地运行队列(LRQ)每个 P 都有一个 LRQ用于管理分配给在 P 的上下文中执行的 Goroutines这些 Goroutine 轮流被和 P 绑定的 M 进行上下文切换。GRQ 适用于尚未分配给 P 的 Goroutines。
1GGoroutine每个 Goroutine 对应一个 G 结构体G 存储 Goroutine 的运行堆栈、状态以及任务函数可重用。G 并非执行体每个 G 需要绑定到 P 才能被调度执行。 2P: Processor表示逻辑处理器对 G 来说P 相当于 CPU 核G 只有绑定到 P 才能被调度。对 M 来说P 提供了相关的执行环境(Context)如内存分配状态任务队列等。P 的数量决定了系统内最大可并行的 G 的数量前提物理 CPU 核数 P 的数量。P 的数量由用户设置的 GoMAXPROCS 决定但是不论 GoMAXPROCS 设置为多大P 的数量最大为 256。 3M: MachineOS 内核线程抽象代表着真正执行计算的资源在绑定有效的 P 后进入 schedule 循环而 schedule 循环的机制大致是从 Global 队列、P 的 Local 队列以及 wait 队列中获取。M 的数量是不定的由 Go Runtime 调整为了防止创建过多 OS 线程导致系统调度不过来目前默认最大限制为 10000 个。M 并不保留 G 状态这是 G 可以跨 M 调度的基础。 4SchedGo 调度器它维护有存储 M 和 G 的队列以及调度器的一些状态信息等。调度器循环的机制大致是从各种队列、P 的本地队列中获取 G切换到 G 的执行栈上并执行 G 的函数调用 Go exit 做清理工作并回到 M如此反复。
Go 程序可以利用少量的内核级线程来支撑大量 Goroutine 的并发。多个 Goroutine 通过用户级别的上下文切换来共享内核线程 M 的计算资源但对于操作系统来说并没有线程上下文切换产生的性能损耗。
为了更加充分利用线程的计算资源Go 调度器采取了以下几种调度策略 1任务窃取work-stealing。当每个 P 之间的 G 任务不均衡时调度器允许从 GRQ或者其他 P 的 LRQ 中获取 G 执行。
2减少阻塞。在 Go 里面阻塞主要分为一下 4 种场景
由于原子、互斥量或通道操作调用导致 Goroutine 阻塞调度器将把当前阻塞的 Goroutine 切换出去重新调度 LRQ 上的其他 Goroutine。由于网络请求和 IO 操作导致 Goroutine 阻塞Go 程序提供了网络轮询器NetPoller来处理网络请求和 IO 操作的问题其后台实现 IO 多路复用。通过使用 NetPoller 进行网络系统调用调度器可以防止 Goroutine 在进行这些系统调用时阻塞 M。这可以让 M 执行 P 的 LRQ 中其他的 Goroutines而不需要创建新的 M有助于减少操作系统上的调度负载。实现了 goroutine-per-connection 简单的网络编程模式但是大量的 Goroutine 也会带来额外的问题比如栈内存增加和调度器负担加重。 当调用一些系统方法的时候如果系统方法调用的时候发生阻塞这种情况下网络轮询器NetPoller无法使用而进行系统调用的 Goroutine 将阻塞当前 M。调度器将 M1 与 P 分离同时也将 G1 带走。然后调度器引入新的 M2 来服务 P。此时可以从 LRQ 中选择 G2 并在 M2 上进行上下文切换。阻塞的系统调用完成后G1 可以移回 LRQ 并再次由 P 执行。如果这种情况再次发生M1 将被放在旁边以备将来重复使用。 如果在 Goroutine 去执行一个 sleep 操作导致 M 被阻塞了。Go 程序后台有一个监控线程 sysmon它监控那些长时间运行的 G 任务然后设置可以强占的标识符别的 Goroutine 就可以抢先进来执行。只要下次这个 Goroutine 进行函数调用那么就会被强占同时也会保护现场然后重新放入 P 的本地队列里面等待下次执行。
3.2、项目中成就感最大或挑战最大的地方
没有有挑战的项目可以考虑项目用到的技术栈有哪些风险然后针对存在的风险给出一套完美的解决方案。 有好项目的可以从系统设计的层面上讲述。
比如我的项目中要设计开发一个局域网内高效的后台服务器程序最大的成就是设计了一个高效网络传输协议为集中式并发提供高效应答或者最大的挑战是如何设计出一个高效的网络模型和通信协议实现高并发应答项目中客户端只知道服务端开放的端口第一个版本中为了保证数据的可靠性主要使用TCP传输数据但是因为不知道服务器的IP所以先使用UDP发送广播来探寻服务器获得服务器IP后转为TCP来传输数据后来经过验证传输的数据大部分都比较小而且在局域网内UDP丢失数据的概率极低因此转为UDP为主进行应答因为UDP 具有较好的实时性工作效率比 TCP 高应答效率和数据传输效率提高了一倍。
这个过程不仅仅体现出你排查解决问题的能力另一方面也突出你的沉淀和自我思考能力。
3.3、项目问题—协议头引入之后包的大小增加了多少
在我的项目中引入了这样的协议头 1 byte 1 byte 6 bytes
---------------------------------------------------------------------
| opcode | pl_len | src_ip |
-----------------------------------------------------------------------
| src_ip |
----------------------------------------------------------------------
| src_ip | src_mac |
---------------------------------------------------------------------
| src_mac | src_port | des_ip |
-----------------------------------------------------------------------
| des_ip |
----------------------------------------------------------------------
| des_ip | des_mac |
---------------------------------------------------------------------
| des_mac | des_port | preload |
-----------------------------------------------------------------------
| ... |
| preload |
| ... |
-----------------------------------------------------------------------7*8-254字节所以最大多出了54字节最少22字节只有头、MAC地址以及端口其中有一个字节包含了可能存在的分片预留位。
3.4、如何建立缓存
采用redis nosql数据库作为Mysql数据库的缓存在查找的时候首先查找redis缓存如果找到则返回结果如果在redis中没有找到那么查找Mysql数据库找到的话则返回结果并且更新redis如果没有找到则返回空。对于写入的情况直接写入mysql数据库mysql数据库通过触发器及UDF机制自动把变更的内容更新到redis中。
#mermaid-svg-st0sZOh1T3eMhv48 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-st0sZOh1T3eMhv48 .error-icon{fill:#552222;}#mermaid-svg-st0sZOh1T3eMhv48 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-st0sZOh1T3eMhv48 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-st0sZOh1T3eMhv48 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-st0sZOh1T3eMhv48 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-st0sZOh1T3eMhv48 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-st0sZOh1T3eMhv48 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-st0sZOh1T3eMhv48 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-st0sZOh1T3eMhv48 .marker.cross{stroke:#333333;}#mermaid-svg-st0sZOh1T3eMhv48 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-st0sZOh1T3eMhv48 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-st0sZOh1T3eMhv48 .cluster-label text{fill:#333;}#mermaid-svg-st0sZOh1T3eMhv48 .cluster-label span{color:#333;}#mermaid-svg-st0sZOh1T3eMhv48 .label text,#mermaid-svg-st0sZOh1T3eMhv48 span{fill:#333;color:#333;}#mermaid-svg-st0sZOh1T3eMhv48 .node rect,#mermaid-svg-st0sZOh1T3eMhv48 .node circle,#mermaid-svg-st0sZOh1T3eMhv48 .node ellipse,#mermaid-svg-st0sZOh1T3eMhv48 .node polygon,#mermaid-svg-st0sZOh1T3eMhv48 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-st0sZOh1T3eMhv48 .node .label{text-align:center;}#mermaid-svg-st0sZOh1T3eMhv48 .node.clickable{cursor:pointer;}#mermaid-svg-st0sZOh1T3eMhv48 .arrowheadPath{fill:#333333;}#mermaid-svg-st0sZOh1T3eMhv48 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-st0sZOh1T3eMhv48 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-st0sZOh1T3eMhv48 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-st0sZOh1T3eMhv48 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-st0sZOh1T3eMhv48 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-st0sZOh1T3eMhv48 .cluster text{fill:#333;}#mermaid-svg-st0sZOh1T3eMhv48 .cluster span{color:#333;}#mermaid-svg-st0sZOh1T3eMhv48 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-st0sZOh1T3eMhv48 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}serverread找到没有找到返回空找到就返回数据找到就同时更新redis检索没有找到检索是否找到redisMySQL是否找到client#mermaid-svg-9nDVOjdQhf7wsPkg {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-9nDVOjdQhf7wsPkg .error-icon{fill:#552222;}#mermaid-svg-9nDVOjdQhf7wsPkg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9nDVOjdQhf7wsPkg .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-9nDVOjdQhf7wsPkg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9nDVOjdQhf7wsPkg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9nDVOjdQhf7wsPkg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9nDVOjdQhf7wsPkg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9nDVOjdQhf7wsPkg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9nDVOjdQhf7wsPkg .marker.cross{stroke:#333333;}#mermaid-svg-9nDVOjdQhf7wsPkg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9nDVOjdQhf7wsPkg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9nDVOjdQhf7wsPkg .cluster-label text{fill:#333;}#mermaid-svg-9nDVOjdQhf7wsPkg .cluster-label span{color:#333;}#mermaid-svg-9nDVOjdQhf7wsPkg .label text,#mermaid-svg-9nDVOjdQhf7wsPkg span{fill:#333;color:#333;}#mermaid-svg-9nDVOjdQhf7wsPkg .node rect,#mermaid-svg-9nDVOjdQhf7wsPkg .node circle,#mermaid-svg-9nDVOjdQhf7wsPkg .node ellipse,#mermaid-svg-9nDVOjdQhf7wsPkg .node polygon,#mermaid-svg-9nDVOjdQhf7wsPkg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9nDVOjdQhf7wsPkg .node .label{text-align:center;}#mermaid-svg-9nDVOjdQhf7wsPkg .node.clickable{cursor:pointer;}#mermaid-svg-9nDVOjdQhf7wsPkg .arrowheadPath{fill:#333333;}#mermaid-svg-9nDVOjdQhf7wsPkg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9nDVOjdQhf7wsPkg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9nDVOjdQhf7wsPkg .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-9nDVOjdQhf7wsPkg .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-9nDVOjdQhf7wsPkg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9nDVOjdQhf7wsPkg .cluster text{fill:#333;}#mermaid-svg-9nDVOjdQhf7wsPkg .cluster span{color:#333;}#mermaid-svg-9nDVOjdQhf7wsPkg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9nDVOjdQhf7wsPkg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}serverwriteredis触发器udf、kafka、cannal、go-mysql-transfer 等方式更新缓存MySQLclient3.5、cache中间件更新机制
同步方案可以有 1伪装从数据库。比如阿里开源的canal方案、kafka、go-mysql-transfer等。 2MySQL的触发器udf。udf全称User-defined function是MySQL提供的一种可扩展代码。UDF不具备事务不能回滚而且效率较低。
3.6、redis缓存的写策略
以MySQL为主保证缓存不可用整个系统依然要保持正常工作mysql 不可用的话系统停摆停止对外提供服务。 1从安全优先方面考虑先删除缓存再写 mysql后面数据同步交由 go-mysql-transfer 等中间件处理。先删除缓存为了避免其他服务读取旧的数据也是告知系统这个数据已经不是最新建议从 mysql 获取数据。 2从效率优先方面考虑先写缓存并设置过期时间如 200ms再写mysql后面数据同步交由其他中间件处理。这里设置的过期时间是预估时间大致上是 mysql 到缓存同步的时间。在写的过程中如果 mysql 停止服务或数据没写入 mysql则200 ms 内提供了脏数据服务但仅仅只有 200ms 的数据错乱即效率优先的写策略也有安全性的问题但只会影响200ms。
3.7、redis缓存热点数据在什么场景下会产生脏数据
所谓产生脏数据就是主数据库与缓存数据库的数据不一致这种情况一般在效率优先的写策略中会产生但因为设置了过期时间所以只会影响一定时间。
3.8、在CRUD中如果操作主数据库和缓存数据库
1C创建一条数据从安全优先考虑先写入MySQL然后通过中间件go-mysql-transfer更新缓存数据库redis从效率优先考虑先写入redis并设置过期时间再写入mysql。 2R查询数据先查询redis如果有则直接返回如果没有再访问mysql查询mysql中也没有就返回空mysql中有就返回数据并通过中间键更新redis缓存。 3U更新数据先删除redis的数据再写数据库然后通过中间件go-mysql-transfer更新缓存数据库redis。 4D删除数据先删除redis的数据再删除mysql的数据。
3.9、内存泄漏怎么检测
debug版本通过VLD库或CRT库分析内存泄漏但是服务器有很多问题需要在线上并发压力情况下才出现因此讨论Debug版调试方法意义不大。
对于release版本 1静态方式检测。使用cppcheck、BEAM等工具检测代码文件是否有内存泄漏隐患。 2入侵式检测。实现内存泄漏检测组件嵌入代码中比如hook住分配内存的函数、mtrace追踪内存分配、对象计数方式C还可以重载内存分配和释放函数 new 和 delete。这种方式的缺点是要修改原代码而且对于第三方库、STL容器、脚本泄漏等因无法修改代码而无法定位。 3已经上线的服务器程序可以使用Valgrind、AddressSanitizer等工具定位到具体的内存泄漏位置。
3.10、socket句柄比较多怎么分析和解决
1查看当前socket使用状态。
# 方法一
cat /proc/net/sockstat
# 方法二
ss -s2如果是FIN_WAIT和TIME_WAIT的可以调整fin超时时间或者其他内核参数来解决。 3如果是出现大量CLOSING状态基本上业务上要处理的逻辑过多导致一直在CLOSING状态可以使用异步将网络层和业务层分离单独处理。
3.11、什么是零拷贝
零拷贝技术就是绕过用户态用户缓存区不参与数据拷贝避免了内核态和用户态的冗余数据拷贝减少上下文切换。 linux系统提供两个零拷贝接口mmap和sendfile
mmap通过DMA将磁盘数据拷贝到内核缓冲区接着操作系统会把这段内核缓冲区与应用程序共享这样就不用将内核缓冲区的数据拷贝到用户缓冲区应用程序调用send或者write时系统直接将内核缓冲区的内容拷贝到socket缓冲区然后发送出去。使用mmap至少减少了一次数据拷贝但是仍然会有用户空间和内核空间的上下文切换。sendfile的数据传输只发生在内核态应用程序调用sendfile系统会将数据拷贝到page cache然后拷贝到socket buffer再通过网卡发送出去。这种发送不仅减少了数据拷贝的次数还减少了上下文切换。如果网卡支持SG-DMA还可以再去除 Socket 缓冲区的拷贝这样一共只有 2 次内存拷贝。
此外还有一个direct io技术绕过内核缓冲区在用户空间和磁盘之间传输数据减少内核缓冲区和用户数据的复制次数。降低了文件读写所带来的CPU负载能力和内存带宽的占用率。
#mermaid-svg-6NWlTGamtSYSrvI3 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6NWlTGamtSYSrvI3 .error-icon{fill:#552222;}#mermaid-svg-6NWlTGamtSYSrvI3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6NWlTGamtSYSrvI3 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-6NWlTGamtSYSrvI3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6NWlTGamtSYSrvI3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6NWlTGamtSYSrvI3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6NWlTGamtSYSrvI3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6NWlTGamtSYSrvI3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6NWlTGamtSYSrvI3 .marker.cross{stroke:#333333;}#mermaid-svg-6NWlTGamtSYSrvI3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6NWlTGamtSYSrvI3 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6NWlTGamtSYSrvI3 .cluster-label text{fill:#333;}#mermaid-svg-6NWlTGamtSYSrvI3 .cluster-label span{color:#333;}#mermaid-svg-6NWlTGamtSYSrvI3 .label text,#mermaid-svg-6NWlTGamtSYSrvI3 span{fill:#333;color:#333;}#mermaid-svg-6NWlTGamtSYSrvI3 .node rect,#mermaid-svg-6NWlTGamtSYSrvI3 .node circle,#mermaid-svg-6NWlTGamtSYSrvI3 .node ellipse,#mermaid-svg-6NWlTGamtSYSrvI3 .node polygon,#mermaid-svg-6NWlTGamtSYSrvI3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6NWlTGamtSYSrvI3 .node .label{text-align:center;}#mermaid-svg-6NWlTGamtSYSrvI3 .node.clickable{cursor:pointer;}#mermaid-svg-6NWlTGamtSYSrvI3 .arrowheadPath{fill:#333333;}#mermaid-svg-6NWlTGamtSYSrvI3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6NWlTGamtSYSrvI3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6NWlTGamtSYSrvI3 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-6NWlTGamtSYSrvI3 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-6NWlTGamtSYSrvI3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6NWlTGamtSYSrvI3 .cluster text{fill:#333;}#mermaid-svg-6NWlTGamtSYSrvI3 .cluster span{color:#333;}#mermaid-svg-6NWlTGamtSYSrvI3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6NWlTGamtSYSrvI3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}零拷贝标准IO数据将缓存在page cache中读数据首先被复制到内核缓冲区page cache之后再从内核缓冲区复制到用户缓冲区中写用户缓冲区的内容首先被复制到内核缓冲区中再被写到磁盘或通过socket发送到网络DMA外部设备与内存数据交互优化一种高速的数据传输操作允许外部设备和内存之间之间读写数据既不通过CPU也不需要CPU干预DMA是指外部设备不通过CPU而之间与系统内存交换数据的接口技术传输速度取决于存储器和外设的工作速度Direct IO避开内核缓冲区在用户空间和磁盘之间传输数据场景应用程序具有自己用户空间的缓存机制高并发环境中大文件的传输缺点不经过内核缓冲区直接进行磁盘读写操作必然会引起阻塞需要配合异步IO协调使用无法享受page cache带来的性能提升定义绕过用户态用户缓冲区不参与数据拷贝避免内核缓冲区和用户缓冲区的冗余数据拷贝减少了上下文切换减少一次copymmap内存地址映射sendfile系统调用减少两次copy网卡支持SG-DMA可去除socket buffer的拷贝mmap和sendfile的区别mmap适合小数据量读写sendfile适合大文件传输mmap需要4次上下文切换3次数据拷贝sendfile需要3次上下文切换至少2次数据拷贝sendfile可以利用DMA减少CPU拷贝mmap不行必须要把数据拷贝到socket buffer3.12、协程、线程、进程三者的关系和区别
进程是一个运行程序有自己独立的内存空间是系统资源分配的最小单位。进程比较重量占据独立的内存所以上下文进程间的切换开销栈、寄存器、虚拟内存、文件句柄等比较大但相对比较稳定安全。 线程是一个轻量级的进程一个进程至少包含一个线程同一个进程中的线程组共享内存空间是操作系统调度执行的最小单位。线程间通信主要通过共享内存上下文切换很快资源开销较少但相⽐进程不够稳定容易丢失数据。 协程一个用户态的轻量级线程协程的调度完全由应用程序控制。协程拥有自己的寄存器上下文和栈。协程调度切换时将寄存器上下文和栈保存到其他地方在切回来的时候恢复先前保存的寄存器上下文和栈直接操作栈则基本没有内核切换的开销可以不加锁的访问全局变量所以上下文的切换非常快。
3.13、父子进程在资源上有什么区别
父进程通过fork创建子进程刚开始时两者都没有对内存作出改动父子进程共享内存资源。内核fork()时并不复制整个进程地址空间而是让父子进程共享一个地址空间只有在需要写入时数据才会被复制从而使各个进程拥有各自的拷贝数据。也就是说只有在需要写入的时候才复制资源在此之前以只读方式共享。
3.14、C中map数据结构底层为什么不使用高度平衡二叉树
最常见的两种自平衡树算法是红黑树和AVL树。为了在插入/更新后平衡树两种算法都使用旋转的概念其中树的节点被旋转以实现重新平衡。
AVL的左右子树高度差不能超过1每次进行插入或删除操作时几乎都需要通过旋转操作保持平衡在频繁插入或删除的场景中频繁的旋转操作使得AVL的性能大打折扣。 红黑树的红黑规则只需要保证黑色节点高度一样黑高通过牺牲严格的平衡换取插入、删除时少量的旋转操作整体性能优于AVL。红黑树插入的不平衡不超过两次旋转就可以解决删除时的不平衡不超过三次旋转就能解决。
虽然在这两种算法中插入/删除操作都是 O(log2n)O(log_2^n)O(log2n)但在红黑树重新平衡旋转的情况下是 O(1) 操作而在 AVL 的情况下这是一个 O(log2n)O(log_2^n)O(log2n)操作这使得红黑树在重新平衡阶段的这一方面更有效这也是它更常用的可能原因之一。
3.15、消息队列存在的价值
消息队列的优点
解耦允许独立的扩展或修改队列两边的处理过程。可恢复性即使一个处理消息的进程挂掉加入队列中的消息仍然可以在系统恢复后被处理。缓冲有助于解决生产消息和消费消息的处理速度不一致的情况。灵活性和峰值处理能力不会因为突发的超负荷的请求而完全崩溃消息队列能够使关键组件顶住突发的访问压力。异步通信消息队列允许用户把消息放入队列但不立即处理它。
3.16、引入消息队列会带来什么问题
消息队列会降低系统的可用性。会提高系统复杂度。需要考虑一致性问题。
四、面向stack overflow编程
Created with Raphaël 2.3.0google 问题进入出来的前两个就是stack overflow检查问题解决方案是否满足结束yesno五、算法题
给一个数组root[]{6,3,5,3,6,7,8,-1,-1,5,6},构建二叉树然后中序遍历输出二叉树。
#mermaid-svg-ZjIcd5WSZ5FKyFHp {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .error-icon{fill:#552222;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .marker.cross{stroke:#333333;}#mermaid-svg-ZjIcd5WSZ5FKyFHp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .cluster-label text{fill:#333;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .cluster-label span{color:#333;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .label text,#mermaid-svg-ZjIcd5WSZ5FKyFHp span{fill:#333;color:#333;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .node rect,#mermaid-svg-ZjIcd5WSZ5FKyFHp .node circle,#mermaid-svg-ZjIcd5WSZ5FKyFHp .node ellipse,#mermaid-svg-ZjIcd5WSZ5FKyFHp .node polygon,#mermaid-svg-ZjIcd5WSZ5FKyFHp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .node .label{text-align:center;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .node.clickable{cursor:pointer;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .arrowheadPath{fill:#333333;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .cluster text{fill:#333;}#mermaid-svg-ZjIcd5WSZ5FKyFHp .cluster span{color:#333;}#mermaid-svg-ZjIcd5WSZ5FKyFHp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZjIcd5WSZ5FKyFHp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}635367856#include vector
#include string
#include queue
#include iostream
using namespace std;//二叉树结点结构
struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode() :val(0), left(nullptr), right(nullptr) {}TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}TreeNode(int x, TreeNode* left, TreeNode* right) :val(x), left(left), right(right) {}
};TreeNode* createBinaryTree(vectorint nodes) {int len nodes.size();if (len 0) {return NULL;}if (nodes[0] -1) {return nullptr;}TreeNode* root;//建立结点队列并将根节点入队queueTreeNode* nodesQue;root new TreeNode(nodes[0]);nodesQue.push(root);//loc遍历数组每次取两个结点for (int loc 1; loc len; loc loc 2) {//获取结点并出队TreeNode* node nodesQue.front();nodesQue.pop();//获取队头结点的左右结点int left nodes[loc];int right nodes[loc 1];//赋予左右结点if (left -1) {node-left nullptr;}else {node-left new TreeNode(left);nodesQue.push(node-left);}if (right -1) {node-right nullptr;}else {node-right new TreeNode(right);nodesQue.push(node-right);}}return root;
}void dfs(TreeNode* root)
{if(rootnullptr){coutnullendl;return;}coutroot-valendl;dfs(root-left);dfs(root-right);
}int main()
{vectorint root{6,3,5,3,6,7,8,-1,-1,5,6};TreeNode* cur createBinaryTree(root);dfs(cur);return 0;
}
总结
从 Go 调度器架构层面上介绍了 G-P-M 模型通过该模型怎样实现少量内核线程支撑大量 Goroutine 的并发运行。以及通过 NetPoller、sysmon 等帮助 Go 程序减少线程阻塞充分利用已有的计算资源从而最大限度提高 Go 程序的运行效率。消息队列带来的好处解耦、削峰、异步提高系统响应速度和稳定性。
参考
腾讯技术MySQL缓存策略Go语言详解DMADirect IO和零拷贝C SLT map和unorder_map底层原理