ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ(要知道对好事的称颂过于夸大,也会招来人们的反感轻蔑和嫉妒。——培根)
ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ
什么是NodeJs
应用场景
和JavaScript的区别
NodeJs和Java相比的区别和优缺点
NodeJs特性都有哪些
NodeJs事件驱动是什么
NodeJs事件驱动的优缺点
优点
缺点
解决办法: 将单个cpu密集型任务拆成多个子任务,留出一定时间间隔执行其他任务。
解决办法: 1.开启宿主提供的多线程功能。 2. 如果在node端,通过nginx代理,同时开启多个node进程进行处理。
NodeJs事件驱动原理
事件循环是 Node.js 处理非阻塞 I/O 操作的机制——尽管 JavaScript 是单线程处理的——当有可能的时候,它们会把操作转移到系统内核中去。
既然目前大多数内核都是多线程的,它们可在后台处理多种操作。当其中的一个操作完成的时候,内核通知 Node.js 将适合的回调函数添加到 轮询 队列中等待时机执行
详解链接
libuv线程池运行原理
libuv最初是为nodejs编写的跨平台支持库。它是围绕事件驱动的异步 I/O 模型设计的
libuv 提供了一个线程池,可用于运行用户代码并在循环线程中获得通知。此线程池在内部用于运行所有文件系统操作,以及 getaddrinfo 和 getnameinfo 请求。
它的默认大小是 4,但可以在启动时通过将 UV_THREADPOOL_SIZE环境变量设置为任何值来更改它,最大支持1024个线程
线程池是全局的,并且在所有事件循环中共享。当特定函数使用线程池时(即使用时uv_queue_work()),libuv 会预先分配并初始化 允许的最大线程数 UV_THREADPOOL_SIZE。这会导致相对较小的内存开销(128 个线程约为 1MB),但会提高运行时线程的性能
NodeJs如何使用libuv中的线程池
NodeJs事件驱动和浏览器的事件循环区别是什么
nodejs 中事件循环不再是由单一个 task queue 和 micro-task queue 组成,而是由多个 阶段 phase 的多个回调函数队列 callbacks queues 组成一次事件循环 tick。 并且在每一个单独的阶段都存在一个单独的 回调函数 FIFO 队列Http七层协议工作原理,都有哪些状态码,分别是什么意思
为什么需要协议?
四层协议关系
端口号范围0-65535,1024之前不允许用
物理层
数据链路层
网络层
传输层
TCP协议简述
存在长连接和短连接
短链接
TCP短连接:client向server发起连接请求,server接到请求,然后双方建立连接。client向server发送消息,server回应client,然后一次请求就完成了。这时候双方任意都可以发起close操作,不过一般都是client先发起close操作。上述可知,短连接一般只会在 client/server间传递一次请求操作。
短连接的优点是:管理起来比较简单,存在的连接都是有用的连接,不需要额外的控制手段
长连接 keepalive
什么时候用长连接或者短连接
服务于会话层
建立在某个主机的某个端口到另一个主机下某个端口的连接和通信的,这个通信是使用socket来实现,通过socket实现上面的ip寻址,而且还会建立端口间的连接。规定了一套基于端口的通信协议,包括建立连接,发送和读取消息。
大概机制就是在数据包中加入端口号,寻址到ip后,再去寻找监听该端口号的服务,将数据包发送过去
特点
UDP协议简述
会话层
表示层
表示层执行三个基本功能:翻译、压缩和加密/解密。应用层 http协议(80端口),https(443端口),ftp(21),ssh(22),smtp(25)
TCP能传输数据了,为什么还需要类似http这种应用层协议?
http长连接 keep-alive
若开启后,在一次http请求中,服务器进行响应后,不再直接断开TCP连接,而是将TCP连接维持一段时间。在这段时间内,如果同一客户端再次向服务端发起http请求,便可以复用此TCP连接,向服务端发起请求,并重置timeout时间计数器,在接下来一段时间内还可以继续复用。这样无疑省略了反复创建和销毁TCP连接的损耗
启用HTTP keep-Alive的优缺点:
优点:keep-alive机制避免了频繁建立和销毁连接的开销。 同时,减少服务端TIME_WAIT状态的TCP连接的数量(因为由服务端进程主动关闭连接)
缺点:若keep-alive timeout设置的时间较长,长时间的TCP连接维持,会一定程度的浪费系统资源。
总体而言,HTTP keep-Alive的机制还是利大于弊的,只要合理使用、配置合理的timeout参数。
和TCP的keepalive区别是
什么是DNS
WebSocket面试题
websocket和socket的区别
什么是socket协议
sockey协议调用流程
socket核心api
**socket():**创建套接字。
**bind():**指定本地地址。一个套接字用socket()创建后,它其实还没有与任何特定的本地或目的地址相关联。在很多情况下,应用程序并不关心它们使用的本地地址,这时就可以不用调用bind指定本地的地址,而由协议软件为它们选择一个。但是,在某个知名端口(Well-known Port)上操作的服务器进程必须要对系统指定本地端口。所以一旦创建了一个套接字,服务器就必须使用bind()系统调用为套接字建立一个本地地址。
**listen():**设置等待连接状态。对于一个服务器的程序,当申请到套接字,并调用bind()与本地地址绑定后,就应该等待某个客户机的程序来要求连接。listen()就是把一个套接字设置为这种状态的函数。
**connect():**将套接字连接到目的地址。初始创建的套接字并未与任何外地目的地址关联。客户机可以调connect()为套接字绑定一个永久的目的地址,将它置于已连接状态。对数据流方式的套接字,必须在传输数据前,调用connect()构造一个与目的地的TCP连接,并在不能构造连接时返回一个差错代码。如果是数据报方式,则不是必须在传输数据前调用connect。如果调用了connect(),也并不像数据流方式那样发送请求建连的报文,而是只在本地存储目的地址,以后该socket上发送的所有数据都送往这个地址,程序员就可以免去为每一次发送数据都指定目的地址的麻烦。
**accept():**接受连接请求。服务器进程使用系统调用socket,bind和listen创建一个套接字,将它绑定到知名的端口,并指定连接请求的队列长度。然后,服务器调用accept进入等待状态,直到到达一个连接请求。
**read()、write():**当服务器与客户已经建立好连接之后。可以调用网络I/O进行读写操作了,即实现了网咯中不同进程之间的通信,网络I/O操作有下面几组:
什么是websocket
运行原理
为什么要用
应用场景
特点
基于TCP再次封装的另一个协议
首先在连接的时候会发送一个协议升级请求,在http请求上加上socket相关的请求头
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: k1kbxGRqGIBD5Y/LdIFwGQ==
Sec-WebSocket-Version: 13
Upgrade: websocket
服务端如果支持socket的话,会返回101状态码同意协议升级
总结概述
WebSocket和Http区别,相比的优缺点
为什么用这个技术
WebSocket和Socket.io区别
socket.io工作原理
socket.io通过一个http请求,并且该请求头中带有升级协议(Connection:Upgrade、Upgrade:websocket)等信息,告诉服务端准备建立连接,此时,后端返回的response数据scoket.io会根据当前客户端环境是否支持Websocket。如果支持,则建立一个websocket连接,否则使用polling(xhr、jsonp)长轮询进行双向数据通信socket.io与engine.io的一大区别在于,socket.io并不直接提供连接功能,而是在engine.io层提供。什么是跨域,如何解决
script标签发起一个请求(将回调函数的名称放到这个请求的query参数里),然后服务端返回这个回调函数的执行,并将需要响应的数据放到回调函数的参数里,前端的script标签请求到这个执行的回调函数后会立马执行,于是就拿到了执行的响应数据。
XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制XMLHttpRequest或ActiveX的支持callback的方式回传结果GET请求而不支持 POST 等其它类型的 HTTP 请求Nodejs的buffer原理和应用场景
Nodejs的流的应用场景以及运行原理
Nodejs await/async原理
function关键字与函数名之间有一个星号;yield表达式Nodejs多进程应用场景,如何做负载均衡和进程间通讯
进程和线程的区别
CommonJs概念
ExpressJs
KoaJs
概念
特点
洋葱卷模型
概述
源码
function compose (middleware) {
// …
return function (context, next) {
// last called middleware #
let index = -1
// 一开始的时候传入为 0,后续会递增
return dispatch(0)
function dispatch (i) {
// 假如没有递增,则说明执行了多次
if (i <= index) return Promise.reject(new Error(‘next() called multiple times’))
index = i
// 拿到当前的中间件
let fn = middleware[i]
if (i === middleware.length) fn = next
// 当 fn 为空的时候,就会开始执行 next() 后面部分的代码
if (!fn) return Promise.resolve()
try {
// 执行中间件,留意这两个参数,都是中间件的传参,第一个是上下文,第二个是 next 函数
// 也就是说执行 next 的时候也就是调用 dispatch 函数的时候
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err)
}
}
}
}
为什么需要
没有内置任何中间件,比express更轻量
基于es6,默认await/async
有一个统一上下文遍历ctx,方便业务处理,不再需要层层向下传递。
比koa1中的generator更简单的异步,async/await
EggJs
NestJs
onModuleDestroy()完成(Promise被resolved或者rejected);一旦完成,将关闭所有连接(调用app.close() 方法).V8虚拟机
什么是V8虚拟机?说说你对虚拟机的理解
为什么v8引擎的性能强劲
垃圾回收机制
内存结构
为什么需要堆栈区
堆区
堆栈区(栈区)
栈区和堆区的区别示例
以图书馆作为例子,图书馆就是系统 全部 的内存空间,里面的任何东西都是基于图书馆来分配空间。
每一本书就是一个 对象实体,他们存放在书架上,书架就是 堆。假设图书馆有各种各样的书架,可以满足所有大小的书本,即使书的大小各异,管理员只需要找到合适的位置存放。
为了方便存取书本,图书馆管理员会为每一本书设计一个编号,并记录在一个表格上,编号就是对象实体的 内存地址。
那什么是 对象引用 呢,答案就是读者的每一条借书记录,每一次的借书行为可以理解为对书本的一次引用。借书的记录都会登记在一个表格上,这个表格就是 栈。借书记录仅仅是一段文字,所需要的空间很小,而且大小基本固定,通常情况下用一个本子、一个电子表格、一个数据库,做一个表格就可以满足需求。
书本、编号、借书记录三者的结合,相辅相成,让整个图书馆的对图书的管理更加的灵活、方便和规范。
其实,代码世界中很多的设计原理都是源于我们的生活,又高于生活。设计模式就在我们身边,无处不在,善于观察生活中的事物,从生活中领悟设计模式吧
都用过哪些NodeJs模块
看过哪些模块的源码
lodash
出于好奇,看了isEmpty源码
先判断是否为空
再判断是否像数组
接下在像数组的情况下继续进行或的判断
上面条件都不满足,则执行nativeKeys方法
Object.prototype.toString.call()原理
和instanceof,type of区别
typeof只能判断基本类型,引用类型都是object
instanceof判断构造函数的 prototype 属性是否出现在某个实例对象的原型链上
function instance_of(L, R) {//L 表示左表达式,R 表示右表达式 var O = R.prototype; // 取 R 的显示原型 L = L.__proto__; // 取 L 的隐式原型 while (true) { if (L === null) return false; if (O === L) // 当 O 显式原型 严格等于 L隐式原型 时,返回true return true; L = L.__proto__; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
instanceof 的工作原理就是将 s 每一层的 proto 与 F.prototype 做比较
找到相同返回 true
至最后一层仍没有找到返回 false
比如判断 一个字段的类型是否是数组
但instanceof有个缺点,不能用来判断是否为Object,因为最终都指向了Object。
koa-bodyparser
什么是原型和原型链
什么是闭包
函数内部保存的变量不随这个函数调用结束而被销毁就是闭包
闭包的应用场景
闭包的例子
const fun = ()=>{
let num = 0;
return (v)=>{
return num += v;
};
}
const data5 = fun(); //初始化函数fun并得到函数的匿名函数返回值(这里只初始化了一次)
console.log(data5(1)); //1 给匿名函数传参并得到累加的结果
console.log(data5(1)); //2 由于fun函数未重新初始化,且此时num的值为1,所以累加得2
console.log(data5(1)); //3 与上面雷同
什么是深拷贝和浅拷贝
JavaScript作用域
分为全局和局部作用域
每次代码执行前会先进行"预编译"
比如有下面一段代码
var a = 1;
function foo(){
var b = 2;
function bar(){
var c = 3;
console.log(c + b + a);
}
bar();
}
foo();
在执行之前会先预编译成一下的预编译代码
生成全局作用域 global object 简称go
GO{
a: undefined,
foo: function foo{...}
}
执行到foo的时候 生成foo的函数局部作用域 active object 简称ao
AO1{
b: undefined,
bar: function bar(){...}
}
执行foo内部函数bar的时候,生成bar的函数局部作用域
AO2{
c: undefined
}
然后先执行ao2,给变量c复制,在当前局部作用域可以找到,然后执行b,发现当前局部作用域没有,于是就去外层的作用域查找,找到了,执行。然后执行c,发现发现当前局部作用域没有,于是就去外层的作用域查找,发现也没有,一直找到全局作用域,找到了执行,没找到就当作undefind处理
JavaScript继承
es5
原型继承
使用prototype重新赋值,然后再扩展新对象的prototype
示例
// 继承
B.prototype=new A()
// 扩展
B.prototype.splice = ()=>{};
call和apply
用来改变this的指向,将一个对象作为另一个对象的实现
示例
function myfunc1(){
this.name = 'Lee';
this.myTxt = function(txt) {
console.log( 'i am',txt );
}
}
function myfunc2(){
myfunc1.call(this);
}
var myfunc3 = new myfunc2();
myfunc3.myTxt('Geing'); // i am Geing
console.log (myfunc3.name); // Lee
其中myfun2中没有任何实现,只是将myfun1替换了myfun2的实现
区别
es6
使用class类,通过extends关键字实现继承
类只是一个语法糖,背后其实还是构造函数来实现的
原理
通过_inherits函数实现
先判断当前对象是否是函数,如果不是函数则报错类型异常
然后就是继承父类的原型和原型链,下面是示例
// 继承原型链
B.prototype._proto_ = A.prototype
//
super关键字用来做什么
super为什么在构造函数中必须写在前面,否则就不能用this?
比如下面的代码
class Person {
constructor(name) {
this.name = name;
}
}
class PolitePerson extends Person {
constructor(name) {
this.greetColleagues(); //这行代码是无效的,后面告诉你为什么
super(name);
}
greetColleagues() {
alert('Good morning folks!');
}
}
如果允许在调用super之前使用this的话。一段时间后,我们可能会修改greetColleagues,并在提示消息中添加Person的name:
greetColleagues() {
alert('Good morning folks!');
alert('My name is ' + this.name + ', nice to meet you!');
}
但是我们忘记了super()在设置this.name之前先调用了this.greetColleagues()。 所以此时this.name还没有定义,就会出现出现undefind
所以javascript强制在this之前调用super,先完成父类构造函数的构建,再执行子类
super的实现也是使用call方法
bind,call和apply应用场景和区别
2个等于号和3个等于号区别
线上cpu高的问题
线上内存高的问题
排查内存泄漏的方案是什么
数组和链表数据结构和区别
什么是缓冲区
Nodejs最近大版本都更新了什么
官网维护的更新日志
https://github.com/nodejs/node/tree/main/doc/changelogs
node 10
node 12
node 14
node 16
node 18
js如何判断数据类型
typeof,instanceof,Object.prototype.toString.call
Object.prototype.toString.call()原理
和instanceof,type of区别
typeof只能判断基本类型,引用类型都是object
instanceof判断构造函数的 prototype 属性是否出现在某个实例对象的原型链上
function instance_of(L, R) {//L 表示左表达式,R 表示右表达式 var O = R.prototype; // 取 R 的显示原型 L = L.__proto__; // 取 L 的隐式原型 while (true) { if (L === null) return false; if (O === L) // 当 O 显式原型 严格等于 L隐式原型 时,返回true return true; L = L.__proto__; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
instanceof 的工作原理就是将 s 每一层的 proto 与 F.prototype 做比较
找到相同返回 true
至最后一层仍没有找到返回 false
比如判断 一个字段的类型是否是数组
但instanceof有个缺点,不能用来判断是否为Object,因为最终都指向了Object。
node如何接受客户端上传的文件
箭头函数
单元测试
TypeScript
特点
应用场景
缺点
目前用的什么版本,有什么特性
目前用的最新的4.6版本
特性
super关键字允许写在this后面,以前只能写在前面
枚举类型支持解构
type Action =
| { kind: "NumberContents", payload: number }
| { kind: "StringContents", payload: string };
// 以前结构会报错
const { kind, payload } = action;
if (kind === "NumberContents") {
let num = payload * 2
// ...
}
更智能的jsdoc,通过注释也可以看到类型
其他的问题修复等
经常用哪些类型接口
Mongodb
关系型和非关系型区别
Mongodb应用场景
Mongo优缺点
Mongo集群是否了解
都有哪些数据类型
ObjectId如何组成
什么是索引
常用的索引类型
索引的优缺点
mongodb索引数据结构和原理
Mongo查询计划
如何查找慢查询,找到之后如何优化
开启mongodb慢查询检测
--开启慢查询,且记录超过10ms的语句
db.setProfilingLevel( 1 , 10 );
-- 获取当前设置的级别
db.getProfilingLevel()
--设置profile级别
db.setProfilingLevel(2)
// 根据条件查询慢查询
db.system.profile.find( { millis : { $gt : 5 } } )
数据库语句执行过程
数据库cpu高的问题
数据库内存高的问题
数据库流量高的问题
Mongo底层存储结构
Redis
和其他传统数据库区别
Redis应用场景都有哪些
为什么Redis快
常用的数据结构有哪些
缓存击穿
缓存穿透
缓存雪崩
过期策略
内存淘汰策略
持久化机制,优缺点
RDB
概念
备份策略
save 3600 1 -> 3600秒内有1个key被修改,则触发RDB
save 300 100 -> 300秒内有100个key被修改,则触发RDB
save 60 10000 -> 60秒内有10000个key被修改,则触发RDB
重写操作是redis主进程fork一个子进程来处理,避免阻塞主进程
redis默认是rbd策略
AOF
概念
开启aof
备份策略
AOF重写
背景
触发命令 bgrewriteaof
触发策略
重写流程
(1)bgrewriteaof触发重写,判断是否存在bgsave或者bgrewriteaof正在执行,存在则等待其执行结束再执行;
(2)主进程fork子进程,防止主进程阻塞无法提供服务;
(3)子进程遍历Redis内存快照中数据写入临时AOF文件,同时会将新的写指令写入aof_buf和aof_rewrite_buf两个重写缓冲区,前者是为了写回旧的AOF文件,后者是为了后续刷新到临时AOF文件中,防止快照内存遍历时新的写入操作丢失;
(4)子进程结束临时AOF文件写入后,通知主进程;
(5)主进程会将上面的aof_rewirte_buf缓冲区中的数据写入到子进程生成的临时AOF文件中;
(6)主进程使用临时AOF文件替换旧AOF文件,完成整个重写过程。
RDB优缺点
AOF优缺点
redis高可用
slaveof no one)到主从服务器,这需要人工干预。分布式锁的使用和问题,解决方案
什么是缓存重建
redis是单线程还是多线程,6.0以后多线程解决了什么问题
redis事务
MULTI,EXEC,DISCARD,WATCH 四个命令是 Redis 事务的四个基础命令。其中:
MULTI,告诉 Redis 服务器开启一个事务。注意,只是开启,而不是执行 。
EXEC,告诉 Redis 开始执行事务 。
DISCARD,告诉 Redis 取消事务。
WATCH,监视某一个键值对,它的作用是在事务执行之前如果监视的键值被修改,事务会被取消。
应用场景
redis发布订阅
cpu高
内存高
微服务的优缺点
什么是restful风格
简称rest,它是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件,它主要用于客户端和服务端交互类的软件。基于这个风格设计的软件可以更简介,更有层次
特性
如何设计
路径设计:数据库设计完毕之后,基本上就可以确定有哪些资源要进行操作,相对应的路径也可以设计出来。
动词设计:也就是针对资源的具体操作类型,有HTTP动词表示,常用的HTTP动词如下:POST、DELETE、PUT、GET
常用的设计模式,应用场景,解决了什么问题
什么是DDD设计模式,应用场景,解决了什么问题
Kakfa
topic有5个分区,当你一次性向 kafka 中推 1000 条数据时,这 1000 条数据默认会分配到 5 个分区中,其中每个分区存储 200 条数据Apollo
私有包使用nexus作为仓储
Docker
K8s
什么是k8s,和docker区别
特点,应用场景和优缺点
k8s的组成
k8s核心概念
k8s的健康检查机制都有哪些
如何实现集群管理
K8S基础
K8S中POD的概念
k8s内的一个容器单元,相当于一个拥有命名空间和存储卷的docker容器
K8S的命名空间
命名空间 namespace 是 k8s 集群级别的资源,可以给不同的用户、租户、环境或项目创建对应的命名空间,例如,可以为 test、devlopment、production 环境分别创建各自的命名空间
Deployment无状态应用的部署
编写一个yml文件,按照k8s的格式定以命名空间,pod标签,端口号,镜像id等
Service的类型
clusterip
通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是默认的 ServiceType
NodePort
通过每个节点上的 IP 和静态端口(NodePort)暴露服务。 NodePort 服务会路由到自动创建的 ClusterIP 服务。 通过请求 <节点 IP>:<节点端口>,你可以从集群的外部访问一个 NodePort 服务。
LoadBalancer
使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上
Service和pod的关系
service和pod并没有直接的关系。pod通过endpoints暴露出来,只要pod发生变更,便会同步至endpoints中。有了service和endpoints后,kube-proxy会实时监听它们的更新和删除操作,然后更新iptables代理规则,重新生成该service访问pod的ip和端口映射规则
labels标签
当相同类型的资源越来越多,对资源划分管理是很有必要,此时就可以使用label为资源对象 命名,以便于配置,部署等管理工作,提升资源的管理效率
labels selector 标签选择器
Label selector(标签选择器)是Kubernetes核心的分组机制,通过label selector客户端/用户能够识别一组有共同特征或属性的资源对象
Ingress七层负载均衡
ingress其实类似nginx,通过k8s监听ingress资源的变化,重新生成nginx.conf文件,然后生效
K8S深入
K8S的资源配额、限制
K8S的环境变量
K8S配置管理(ConfigMap、Secret等)
K8S的滚动更新
K8S的健康检查
g) K8S的有状态服务StatefulSet
h) K8S的Job、CronJob
i) 使用流水线部署K8S应用
四、 K8S进阶
a) K8S集群规划、搭建
b) K8S的概念架构、技术架构
c) K8S负载类型
d) K8S的调度策略(亲和、反亲和等)
e) K8S的存储(本地存储、分布式存储等)
f) K8S中的负载均衡(ClusterIP、NodePort、L4、L7负载均衡)
g) K8S的弹性伸缩(HPA、CA等)
h) 使用Helm Chart发布应用
i) K8S的日志、监控、告警体系
j) Istio服务网格与流量治理
k) K8S技术演进路线(AKS、ASK、ACI、FaaS等)
你们线上运行多少机器,都是什么配置,为什么这样配置
QPS达到多少
你们登录加密token怎么做的
单点登录如何做的
说说对sass行业的理解
什么是线程安全和不安全
什么是GRPC
该篇是对标了几个大厂常问和一些偏八股文的问题
TCP和UDP是什么还有区别
HTTP和HTTPS区别
HTTP长连接和短链接区别
TCP使用问题,比如粘包
TCP如何保证可靠性传输
浏览器输入网址后都发生了什么
HTTP1.0,1.1,2.0的区别
HTTP协议和TCP/IP协议区别
HTTP协议是无状态的怎么理解
HTTP三次握手和四次挥手过程
为什么是三次握手而不是两次
TCP/IP四层网络模型
进程,线程,协程区别
线程之间如何通信
GRPC
时间和空间复杂度
链路追踪如何做的
一个对象的创建过程
serverless