面试

  • 用户鉴权 用的什么进行鉴权?鉴权方式是什么?证书鉴权的方式是什么?

    • 两段式鉴权
      • 业务登录鉴权:发生于 SDK管理平台 之间

        • SDK用户名/密码 + optional TOTPSDKAuth,用于确认 “这个人是不是合法用户”
        • SDK 登录成功后,平台会下发 ca/ cert /key/ server[],客户端再用这些材料去建立 OpenVPN 实例去建立连接。
      • VPN 接入鉴权:发生于 OpenVPN 插件与 管理平台 之间

        • 到了服务端,插件在 TLS_VERIFY 阶段取客户端证书的 **序列号 SNCN**,再调用同步 RPC 方法 CertStatus 查询这个证书当前是不是有效、属于哪个实体、对应哪个用户。
    • 所以插件做的主鉴权不是用户名/密码,而是:
      • mTLS 握手
      • 远端证书状态校验。
  • 证书里面的内容是什么?基于什么的呢?

    • 这套系统底层是基于 X.509 证书 + PKI/CA 体系 的 OpenVPN 双向 TLS
    • 插件实际会读取证书里的 CNSN
    • X.509 证书主要包含:
      • Subject(主体)
      • Issuer(签发者)
      • Serial Number(序列号)
      • Validity(有效期)
      • Public Key(公钥)
  • 你讲一下 策略拉取 具体由那些策略?

    • 本质上是用户访问控制策略,主要包括:
      • 拒绝策略 refusePolicy
      • 路由规则 routeRule
      • 限制速率 rateLimit
      • 时间窗 hourFrom/hourTo
  • 网络访问策略还是路由策略?

    • 插件拉取的是 网络访问策略,插件拿到策略后,是用 nftables 做:
      • 允许哪些目的网段;
      • 允许哪些 TCP/UDP 端口;
      • 允许哪些 ICMP 类型;
      • 超过速率怎么处理;
      • 到期后怎么拒绝;
  • 路由策略没有进行管理嘛?

    • 有路由管理,但不在插件这一层。
    • 路由配置 是在托管节点生成 OpenVPN 服务端通过配置进行管理的。
      • 插件负责用户访问控制;
      • OpenVPN 服务配置负责路由下发;
  • 实现方式是什么?

    • 插件先拉用户策略,再把策略编译成 nftables 规则下发到 Linux 内核。
    • 大致流程:
      • 客户端证书校验通过后,插件识别出 userId
      • 异步调用 UserAccessRules(userId)
      • OpenVPNLEARN_ADDRESS 事件拿到这个用户的虚拟 IP
      • UserAccessRules 转成 vpn_access_rules
      • nft_adaptor.add_vpn_user_filter
      • 为这个用户建立独立规则链;
  • libnft 的实现原理知道吗?

    • 用户态先构造规则;
    • libnftables 解析/编译规则;
    • 通过 netlink 把规则发给内核里的 nf_tables
    • 内核在 Netfilter hook 点上执行这些规则;
  • 现在我搭建了一个 openvpn 服务器,它是在互联网上的,现在用户 A 和用户 B ,他们如何通过 openvpn 将他们组建成一个虚拟局域网里呢?让 AB 之间可以进行点对点通信?

    • 官方手册明确说,client-to-client 会让 openVPN 服务端可以在内部路由客户端之间的流量;
    • 否则客户端通常只能“看见服务器”;
  • 流量解析 是如何做的呢?

    • OpenVPN 启动完成后,插件在 OPENVPN_PLUGIN_ROUTE_UP 事件里取到设备名 dev
    • tcapPcapPlusPlus 在这个网卡上做 live capture
    • 把原始包解析成 多层协议对象
    • 解析到哪一层由配置 parseUntil 决定;
    • 当前支持解析的内容包括:EthernetIPv4/IPv6TCP/UDPICMP 等等;
    • 插件再根据 src/dst VIP 去本地在线用户表里补齐 vpn_user 字段;
    • 最后把整条记录序列化成 JSON 发到 Kafka
  • 日志投递 具体指的是什么?

    • 服务日志: OpenVPN 服务端本身的运行日志错误日志
    • 流量审计日志: 插件抓包解析后生成的 JSON 事件;
  • 为什么选择 kafka 做日志投递?

    • 解耦: 避免插件直接依赖某个日志平台的写入接口;
    • 削峰缓冲: VPN 流量是突发的,Kafka 更适合扛 burst,避免反压直接打到接入链路。
    • 多消费者复用: 安全、审计、运维、风控都可以各自消费同一份数据。
    • 可回放: 出现安全事件时可以重放历史流量事件做追查。
  • kafka 顺序写入以及多 Broker 的情况,kafka 会进行多分批发送,kafka 怎么保证顺序呢?

    • Kafka 只保证 “单个 partition 内” 的顺序,不保证跨 partition 的全局顺序。
    • 同一个 topic 下的 partition,事件会按写入顺序追加,消费者也按这个顺序读取。
  • kafka 分区你通常设置成多少个呢?

    • 不太了解,通常托管节点下发给插件的配置
  • 介绍一下基于 N:M 线程模型的高性能服务器框架?

  • 讲解一下线程池如何调度协程任务的嘛?

  • 线程和协程的区别是什么?优劣是什么?

  • 如果只用多线程做协程调度器,它为什么就没有因为上下文造成的影响呢?

  • 你没有解释如何抵消线程进行切换造成的影响?

    • 控制住线程数: 线程数不要跟连接数走;

      8 核机器开 8~16 个线程通常就够了,不是 1000 个连接就开 1000 个线程,线程一少,线程切换总量自然就下来了。

    • 切换尽量发生在线程内部: 线程切换很贵,协程切换便宜。
      • 少做线程切换
      • 多做协程切换
    • 减少线程阻塞和唤醒: 线程最怕因为阻塞频繁的被唤醒,这个过程会不断触发内核调度
      • 线程没事就睡在 epoll_wait
      • 真有 IO 事件来了再醒;
      • 一个线程醒来后能连续处理多个 ready 协程;
    • 减少跨线程迁移:
  • 现在有 1000 个连接需要你去处理,你现在用线程调度器去都调度你的协程,平均你每个线程需要你去调度多少个协程呢?要启动多少个线程呢?

  • 现在我再具体一点,现在我有 1000 个协程任务,你现在要协调都多少个线程来协调多少个协程来达到最高的效率呢?

  • 你怎么知道调度那些协程到那些线程呢?

  • 多线程/多协程的场景下,如果你的程序异常崩溃了,你去怎么排查?

    • 通过线程 id /协程 id,找到崩溃的线程;
    • 通过 gdb 调试崩溃程序;
    • 查看所有线程的调用栈;
    • 查看当前线程在跑哪个协程;
  • gdb 怎么找到死锁的原因?

    • 通过 p mutex 查看哪个线程拥有这把锁;
  • 怎么看出来 内存泄漏

    • Valgrindvalgrind --leak-check=full ./server
  • 内存非法访问怎么查看的?

    • 类型
      • 野指针;
      • 空指针;
      • 选空指针;
      • 越界读写;
    • 通过 gdb 进行调试;+
  • 死在代码行上但是你看不出来?

  • 有什么情况,调用成员函数会直接使得程序崩溃?

  • 可插拔中间件机制是什么?

  • 反问:没能很好的表达你在项目中的细节,你在这个项目能做到多深?