入职面试-反问

职责#

  • On-call (电话值班)的计划或者规定是什么?值班或者遇到问题加班时候有加班费吗?
  • 我的日常工作是什么?
  • 有给我设定的特定目标吗?
  • 团队里面初级和高级工程师的比例是多少?(有计划改变吗)
  • 入职培训 (onboarding) 会是什么样的?
  • 每个开发者有多大的自由来做出决定?
  • 在你看来,这个工作做到什么程度算成功?
  • 你期望我在最初的一个月 / 三个月能够完成什么?
  • 试用期结束的时候,你会怎么样衡量我的绩效?
  • 自己单独的开发活动和按部就班工作的比例大概是怎样的?
  • 一个典型的一天或者一周的工作是怎样安排的?
  • 对我的申请你有什么疑虑么?
  • 在这份工作上,我将会和谁紧密合作?
  • 我的直接上级他们的上级都是什么样的管理风格?(事无巨细还是着眼宏观)
  • 我在这个岗位上应该如何发展?会有哪些机会?
  • 每天预期 / 核心工作时间是多少小时?
  • 我入职的岗位是新增还是接替之前离职的同事?(是否有技术债需要还)?(zh)
  • 入职之后在哪个项目组,项目是新成立还是已有的?(zh)

技术#

  • 公司常用的技术栈是什么?
  • 你们怎么使用源码控制系统?
  • 你们怎么测试代码?
  • 你们怎么追踪 bug?
  • 你们怎样监控项目?
  • 你们怎么集成和部署代码改动?是使用持续集成和持续部署吗 (CI/CD)?
  • 你们的基础设施搭建在版本管理系统里吗?或者是代码化的吗?
  • 从计划到完成一项任务的工作流是什么样的?
  • 你们如何准备故障恢复?
  • 有标准的开发环境吗?是强制的吗?
  • 你们需要花费多长时间来给产品搭建一个本地测试环境?(分钟 / 小时 / 天)
  • 你们需要花费多长时间来响应代码或者依赖中的安全问题?
  • 所有的开发者都可以使用他们电脑的本地管理员权限吗?
  • 介绍一下你们的技术原则或者展望。
  • 你们的代码有开发文档吗?有没有单独的供消费者阅读的文档?
  • 你们有更高层次的文档吗?比如说 ER 图,数据库范式
  • 你们使用静态代码分析吗?
  • 你们如何管理内部和外部的数字资产?
  • 你们如何管理依赖?
  • 公司是否有技术分享交流活动?有的话,多久一次呢?(zh)
  • 你们的数据库是怎么进行版本控制的?(zh)
  • 业务需求有没有文档记录?是如何记录的?(zh)
  • 你们是如何面对和解决技术债的?是否有专门的时间或者预算用于重构?
  • 你们如何进行单元测试呢,是否都有单元测试的习惯?

团队#

  • 工作是怎么组织的?
  • 团队内 / 团队间的交流通常是怎样的?
  • 你们使用什么工具来做项目组织?你的实际体会是什么?
  • 如果遇到不同的意见怎样处理?
  • 谁来设定优先级 / 计划?
  • 如果团队没能赶上预期发布日期怎么办?
  • 每周都会开什么类型的会议?
  • 会有定期的和上级的一对一谈话吗?
  • 产品 / 服务的规划是什么样的?(n 周一发布 / 持续部署 / 多个发布流 / …)
  • 生产环境发生事故了怎么办?是否有不批评人而分析问题的文化?
  • 有没有一些团队正在经历还尚待解决的挑战?
  • 你们如何跟踪进度?
  • 预期和目标是如何设定的?谁来设定?
  • Code Review 如何实施?
  • 给我介绍下团队里一个典型的 sprint
  • 你们如何平衡技术和商业目标?
  • 你们如何共享知识?
  • 团队有多大?
  • 公司技术团队的架构和人员组成?(zh)
  • 团队内开发、产品、运营哪一方是需求的主要提出方?哪一方更强势?(zh)

问未来的同事#

  • 开发者倾向于从哪里学习?
  • 你对在这里工作最满意的地方是?
  • 最不满意的呢?
  • 如果可以的话,你想改变哪里?
  • 团队最老的成员在这里多久了?
  • 在小团队中,有没有出现成员性格互相冲突的情况?最后是如何解决的?

公司#

  • 公司为什么在招人?(产品发展 / 新产品 / 波动…)
  • 有没有会议 / 旅行预算?使用的规定是什么?
  • 晋升流程是怎样的?要求 / 预期是怎样沟通的?
  • 绩效评估流程是怎样的?
  • 技术和管理两条职业路径是分开的吗?
  • 对于多元化招聘的现状或者观点是什么?
  • 有公司级别的学习资源吗?比如电子书订阅或者在线课程?
  • 有获取证书的预算吗?
  • 公司的成熟度如何?(早期寻找方向 / 有内容的工作 / 维护中 / …)
  • 我可以为开源项目做贡献吗?是否需要审批?
  • 你认为公司未来五年或者十年会发展成什么样子?
  • 公司的大多数员工是如何看待整洁代码的?
  • 你上次注意到有人成长是什么时候?他们在哪方面成长了?
  • 在这里成功的定义是什么?如何衡量成功?
  • 有体育活动或者团建么?
  • 有内部的黑客马拉松活动吗?
  • 公司支持开源项目吗?
  • 有竞业限制或者保密协议需要签吗?
  • 你们认为公司文化中的空白是什么?
  • 能够跟我说一公司处于不良情况,以及如何处理的故事吗?
  • 您在这工作了多久了?您觉得体验如何?(zh)
  • 大家为什么会喜欢这里?(zh)
  • 公司的调薪制度是如何的?(zh)
  • 公司有没有申请调岗的制度?
  • 公司对于员工的心理健康和福祉有什么具体措施?
  • 你对在这里工作最满意的地方是?你为什么留在这家公司?

社会问题#

  • 你们关于多元化招聘什么看法?
  • 你们的公司文化如何?你认为有什么空白么?
  • 这里的工作生活平衡地怎么样?
  • 公司对气候变化有什么态度吗?

冲突#

  • 不同的意见如何处理?
  • 如果被退回了会怎样?(“这个在预计的时间内做不完”)
  • 当团队有压力并且在超负荷工作的时候怎么处理?
  • 如果有人注意到了在流程或者技术等其他方面又改进的地方,怎么办?
  • 当管理层的预期和工程师的绩效之间有差距的时候如何处理?
  • 能给我讲一个公司深处有毒环境以及如何处理的故事吗?
  • 如果在公司内你的同事因涉嫌性侵犯他人而被调查,请问你会如何处理?
  • 假设我自己很不幸是在公司内被性侵的受害者,在公司内部有没有争取合法权益的渠道?

商业#

  • 你们现在盈利吗?
  • 如果没有的话,还需要多久?
  • 如果有的话,年度营业额是大概有多少?(我现在的公司年度营业额是 5 亿)
  • 公司的资金来源是什么?谁影响或者制定高层计划或方向?
  • 你们如何挣钱?
  • 什么阻止了你们挣更多的钱?
  • 公司未来一年的增长计划怎样?五年呢?
  • 你们认为什么是你们的竞争优势?
  • 你们的竞争优势是什么?
  • 公司未来的商业规划是怎样的?有上市的计划吗?(zh)
  • 都在做副业吗?

远程工作#

  • 远程工作和办公室工作的比例是多少?
  • 公司提供硬件吗?更新计划如何?
  • 使用自己的硬件办公可以吗?现在有政策吗?
  • 额外的附件和家具可以通过公司购买吗?这方面是否有预算?
  • 有共享办公或者上网的预算吗?
  • 多久需要去一次办公室?
  • 公司的会议室是否一直是视频会议就绪的?

办公室布局#

  • 办公室的布局如何?(开放的 / 小隔间 / 独立办公室)
  • 有没有支持 / 市场 / 或者其他需要大量打电话的团队在我的团队旁边办公?

终极问题#

  • 该职位为何会空缺?
  • 公司如何保证人才不流失?
  • 这份工作 / 团队 / 公司最好和最坏的方面是?
  • 你最开始为什么选择了这家公司?
  • 你为什么留在这家公司?

待遇#

  • 如果有奖金计划的话,奖金如何分配?
  • 如果有奖金计划的话,过去的几年里通常会发百分之多少的奖金?
  • 有五险一金(zh)/401k(us)或者其他退休养老金等福利吗?
  • 五险一金中,补充公积金一般交多少比例?/401k一般交多少比例?我可以自己选择这一比例吗?
  • 有什么医疗保险吗?如果有的话何时开始?
  • 有额外商业保险吗?例如人寿保险和额外的养老/医疗保险?
  • 商业保险可以给家人办理吗?成年人/未成年人?
  • 更换工作地点,公司付费吗?
  • 是否可以申请更换工作地点?
  • 是否愿意协助海外应聘者申请工作签证?

休假#

  • 带薪休假时间有多久?
  • 病假和事假是分开的还是一起算?
  • 我可以提前使用假期时间吗?也就是说应休假期是负的?
  • 假期的更新策略是什么样的?也就是说未休的假期能否滚入下一周期
  • 照顾小孩的政策如何?
  • 无薪休假政策是什么样的?
  • 学术性休假政策是怎么样的?
  • 孕产假政策具体是怎样的?

福利#

  • 公司提供 mac 开发吗?
  • 使用自带电脑有补贴吗?
  • 公积金多少比例缴纳?
  • 公司是否有食堂,是否有餐饮福利补贴?
  • 是否提供租房补贴?
  • 是否提供话费补贴?
  • 是否有交通补贴?

人才培养#

  • 升职加薪条件是否量化?
  • 每年给团队安排多少费用用于学习培训?
  • 每年组织多少次关于技术能力提升的讲座/论坛?

网络编程

网络分层图#

![[net_layer.png]]

  • TCP是传输层的协议,而基于TCP造出来的HTTP和各类RPC协议,它们都只是定义了不同消息格式的应用层协议而已。
  • HTTP协议(Hyper Text Transfer Protocol),又叫做超文本传输协议。我们用的比较多,平时上网在浏览器上敲个网址就能访问网页,这里用到的就是HTTP协议。
  • RPC(Remote Procedure Call),又叫做远程过程调用。它本身并不是一个具体的协议,而是一种调用方式。虽然大部分RPC协议底层使用TCP,但实际上它们不一定非得使用TCP,改用UDP或者HTTP,其实也可以做到类似的功能。

RPC#

vs HTTP#

HTTP: ![[http.png]] RPC: ![[rpc.png]]

服务发现 [x]#

首先要向某个服务器发起请求,你得先建立连接,而建立连接的前提是,你得知道IP地址和端口。这个找到服务对应的IP端口的过程,其实就是服务发现。

在HTTP中,你知道服务的域名,就可以通过DNS服务去解析得到它背后的IP地址,默认80端口。

而RPC的话,就有些区别,一般会有专门的中间服务去保存服务名和IP信息,比如consul或者etcd,甚至是redis。想要访问某个服务,就去这些中间服务去获得IP和端口信息。由于dns也是服务发现的一种,所以也有基于dns去做服务发现的组件,比如CoreDNS。

底层连接形式 [x]#

以主流的HTTP1.1协议为例,其默认在建立底层TCP连接之后会一直保持这个连接(keep alive),之后的请求和响应都会复用这条连接。

而RPC协议,也跟HTTP类似,也是通过建立TCP长链接进行数据交互,但不同的地方在于,RPC协议一般还会再建个连接池,在请求量大的时候,建立多条连接放在池内,要发数据的时候就从池里取一条连接出来,用完放回去,下次再复用,可以说非常环保。

由于连接池有利于提升网络请求性能,所以不少编程语言的网络库里都会给HTTP加个连接池,比如go就是这么干的。

可以看出这一块两者也没太大区别,所以也不是关键。

传输的内容#

基于TCP传输的消息,说到底,无非都是消息头header和消息体body。

header是用于标记一些特殊信息,其中最重要的是消息体长度。

body则是放我们真正需要传输的内容,而这些内容只能是二进制01串,毕竟计算机只认识这玩意。所以TCP传字符串和数字都问题不大,因为字符串可以转成编码再变成01串,而数字本身也能直接转为二进制。但结构体呢,我们得想个办法将它也转为二进制01串,这样的方案现在也有很多现成的,比如json,protobuf。

这个将结构体转为二进制数组的过程就叫序列化,反过来将二进制数组复原成结构体的过程叫反序列化。 ![[tobytes.png]]

序列化和反序列化

对于主流的HTTP1.1,虽然它现在叫超文本协议,支持音频视频,但HTTP设计初是用于做网页文本展示的,所以它传的内容以字符串为主。header和body都是如此。在body这块,它使用json来序列化结构体数据。

我们可以随便截个图直观看下。 ![[tobetes_details.png]] HTTP报文

可以看到这里面的内容非常多的冗余,显得非常啰嗦。最明显的,像header里的那些信息,其实如果我们约定好头部的第几位是content-type,就不需要每次都真的把"content-type"这个字段都传过来,类似的情况其实在body的json结构里也特别明显。

而RPC,因为它定制化程度更高,可以采用体积更小的protobuf或其他序列化协议去保存结构体数据,同时也不需要像HTTP那样考虑各种浏览器行为,比如302重定向跳转啥的。因此性能也会更好一些,这也是在公司内部微服务中抛弃HTTP,选择使用RPC的最主要原因。

当然上面说的HTTP,其实特指的是现在主流使用的HTTP1.1,HTTP2在前者的基础上做了很多改进,所以性能可能比很多RPC协议还要好,甚至连gRPC底层都直接用的HTTP2。

结论#

  • 纯裸TCP是能收发数据,但它是个无边界的数据流,上层需要定义消息格式用于定义消息边界。于是就有了各种协议,HTTP和各类RPC协议就是在TCP之上定义的应用层协议。
  • RPC本质上不算是协议,而是一种调用方式,而像gRPC和thrift这样的具体实现,才是协议,它们是实现了RPC调用的协议。目的是希望程序员能像调用本地方法那样去调用远端的服务方法。同时RPC有很多种实现方式,不一定非得基于TCP协议。
  • 从发展历史来说,**HTTP主要用于b/s架构,而RPC更多用于c/s架构。但现在其实已经没分那么清了,b/s和c/s在慢慢融合。**很多软件同时支持多端,所以对外一般用HTTP协议,而内部集群的微服务之间则采用RPC协议进行通讯。
  • RPC其实比HTTP出现的要早,且比目前主流的HTTP1.1性能要更好,所以大部分公司内部都还在使用RPC。
  • HTTP2.0在HTTP1.1的基础上做了优化,性能可能比很多RPC协议都要好,但由于是这几年才出来的,所以也不太可能取代掉RPC。

TCP#

八股文常背,TCP是有三个特点,面向连接、可靠、基于字节流。

粘包问题#

因为: ![[tcp_is_dataflow.png]] 所以: ![[nianbaowenti.png]] 无法区分上述两种情况。 得出: 纯裸TCP是不能直接拿来用的,你需要在这个基础上加入一些自定义的规则,用于区分消息边界。

于是我们会把每条要发送的数据都包装一下,比如加入消息头,消息头里写清楚一个完整的包长度是多少,根据这个长度可以继续接收数据,截取出来后它们就是我们真正要传输的消息体。

建立连接示例#

![[socket_connect.gif]]

三次握手:#

  1. 客户端通过向服务器端发送一个SYN来创建一个主动打开,作为三次握手的一部分。客户端把这段连接的序号设定为随机数 A。
  2. 服务器端应当为一个合法的SYN回送一个SYN/ACK。ACK 的确认码应为 A+1,SYN/ACK 包本身又有一个随机序号 B。
  3. 最后,客户端再发送一个ACK。当服务端受到这个ACK的时候,就完成了三路握手,并进入了连接创建状态。此时包序号被设定为收到的确认号 A+1,而响应则为 B+1。

如图:![[3w4h.png]]#

四次挥手:#

注意: 中断连接端可以是客户端,也可以是服务器端。下面仅以客户端断开连接举例,反之亦然:

Redis进阶

主从架构-主从同步#

在Redis中,主从同步是一种常用的数据复制方式,它允许一个或多个从服务器(slave)获得与主服务器(master)相同的数据副本。这种架构提供了数据的冗余和读取扩展性。

  1. 全量复制:当一个从服务器第一次连接到主服务器时,或是由于某些原因需要重新同步时,会进行全量复制。在这个过程中,主服务器会生成一个当前所有数据的快照,并将这个快照发送至请求同步的从服务器。从服务器接收到数据后,加载到自己的数据空间内。

  2. 部分复制:一旦完成了全量复制,如果从服务器断开连接又重新连接,且中断时间不长,主服务器可以只发送这段时间内发生变化的数据给从服务器,而不是再次进行全量复制。这依赖于主服务器的复制积压缓冲区来存储最近的写命令。

  3. 同步策略:为了保证数据的一致性,从服务器在初始同步完成之前不会对外提供服务。在日常运行时,主服务器会将写命令同时发送给所有的从服务器,以此来保证数据的实时一致性。

主从同步使得从服务器可以承担读操作,减轻主服务器的负载,同时也可以在主服务器遇到故障时,进行故障转移。

主从哨兵架构#

Redis哨兵(Sentinel)系统是用于管理多个Redis服务器的系统。该体系结构具有以下特点:

  1. 监控:哨兵会监控主从服务器是否正常运作。
  2. 自动故障转移:如果主服务器出现故障,哨兵可以自动选举新的主服务器,并让原来的从服务器指向新的主服务器。
  3. 配置提供者:哨兵还会将当前的主服务器地址提供给客户端,确保客户端总是连接到正确的主服务器。

哨兵机制通过这些功能增加了Redis环境的高可用性和稳定性。

切片集群-Redis Cluster#

Redis Cluster是Redis的分布式解决方案。它支持数据的水平分片,以下是其关键特性:

  1. 自动分片:��动将数据分布在不同的节点上,每个节点只保存整个数据集的一部分。
  2. 高可用性:采用主从复制模型,即使在多个节点失败的情况下也能保证服务的可用性。
  3. 无中心设计:没有中心节点,每个节点都保存着整个集群状态的一部分,节点之间通过Gossip协议交换信息。

Redis Cluster通过对键进行CRC16计算并对16384取余数来决定将键分配到哪个槽位,每个节点负责一部分槽位,从而实现负载均衡。

Redis Cluster 通信开销#

由于Redis Cluster节点间需要频繁地交换消息以维护集群状态,因此会产生额外的通信开销:

  1. Gossip通信:节点间通过Gossip协议定期交换信息,包括数据迁移、故障检测等。
  2. 重定向操作:客户端可能会尝试向不包含数据所在槽的节点发起请求,这时节点会返回一个重定向信息

切片集群-Codis

Redis 分布式锁是一种用于多个计算节点之间同步访问共享资源的机制。在分布式系统中,当多个进程需要同时访问某些数据或执行某些任务时,为了避免竞态条件(race conditions)和数据不一致,通常需要使用分布式锁来保证在同一时间只有一个进程能够执行特定的操作。

Redis 分布式锁实现#

一个常见的Redis分布式锁实现是使用 Redis 的 SETNX 命令(Set if not exists)。这个命令只在键不存在的情况下设置键的值,并且返回是否成功设置。由于 SETNX 是原子操作,因此可以用来实现锁的功能。

另一个更加推荐的方式是使用 Redis 2.6.12 版本引入的 SET 命令结合选项 NX(表示只有键不存在时才进行设置)和 PX(给键设置过期时间,单位为毫秒),这可以保证即使在客户端崩溃的情况下,锁也会在一定时间后自动释放,防止死锁。

使用 Redis 分布式锁的步骤:#

  1. 尝试获取锁

    • 使用 SET key value NX PX milliseconds 进行设置。
    • 如果返回 OK,则获取锁成功。
    • 如果返回 nil,则获取锁失败。
  2. 执行业务逻辑

    • 在持有锁的时间内执行必要的操作。
  3. 释放锁