跳到主要内容

亚信安全AI面试

一、I/O多路复用

1 什么是I/O多路复用?它解决了什么问题?相比传统的阻塞I/O有什么优势?

定义: I/O 多路复用(I/O Multiplexing)是一种 允许单个线程或进程同时监听多个文件描述符(如 socket) 的技术。当其中某个描述符就绪(如有数据可读/可写)时,就通知应用程序进行相应操作,而不需要为每个连接单独创建线程或进程。

它解决的问题:

  • 在传统阻塞 I/O 模型中,每个连接都要占用一个线程或进程;大量连接时会导致线程数爆炸、上下文切换频繁。
  • I/O 多路复用允许使用少量线程同时管理大量连接(如数万长连接)。

优势:

对比项阻塞 I/OI/O 多路复用
线程/进程每连接一个少量线程监听多个连接
资源消耗高(线程多)低(少量线程)
适用场景少连接场景高并发连接场景
响应效率阻塞等待事件驱动,及时响应

典型应用:Nginx、Redis、Netty、libevent、libuv。

2 I/O多路复用是如何实现同时监听多个文件描述符的?它的底层机制是什么?

  • 操作系统内核为每个文件描述符维护一个事件状态(如是否可读/可写)。
  • 程序通过系统调用(如 selectpollepoll)向内核注册要监听的多个 fd。
  • 内核在某个 fd 状态变化时(比如数据可读),将其放入就绪队列。
  • 系统调用返回就绪的 fd 列表,应用程序只需对就绪的 fd 进行 I/O 操作。

底层机制核心:

  • 利用操作系统内核的事件通知机制(如 epoll 的事件回调机制)。
  • 不需要轮询所有 fd,提高性能。
  • 事件驱动模型避免无效等待和资源浪费。

3 select/poll/epoll的区别?

特性selectpollepoll
出现时间最早改进版 select高效版本
FD 上限有(一般 1024)无明显限制无明显限制
内核态实现轮询轮询事件驱动
时间复杂度O(n)O(n)O(1)
使用方式每次调用传入全部 fd每次传入全部 fd通过 epoll_ctl 注册一次
性能一般
边缘触发不支持不支持支持 ET、LT

epoll 在大量连接且活跃连接较少时性能优势明显。

4 epoll是否适用于所有场景?

不完全适用。

适用场景:

  • 高并发连接,活跃连接较少(如 IM、消息推送)。
  • I/O 密集型应用(如 Web 服务器、网关、代理)。

不适用场景:

  • 连接数少但活跃度高,select/poll 也能满足。
  • 业务逻辑复杂时,epoll 的事件驱动编程模型维护成本较高。
  • Windows 平台不支持 epoll(Windows 用 IOCP)。

二、ArrayList和LinkedList

1 ArrayList和LinkedList的区别?

对比项ArrayListLinkedList
底层结构动态数组双向链表
随机访问O(1)O(n)
插入/删除可能 O(n),需移动元素O(1),不需移动元素
占用内存较少较多(需存储前后节点引用)
是否线程安全

2 在高并发场景下,选择ArrayList还是LinkedList?

一般选择 ArrayList

  • ArrayList 的查询效率高。
  • LinkedList 在高并发环境下频繁修改结构,GC 压力较大。

如果是频繁插入删除、链表特性更适用,但在高并发下都不推荐直接使用非线程安全的集合类。

3 在高并发场景下使用,如何保证线程安全?

方式:

  1. 使用 Collections.synchronizedList() 包装:

    List<String> list = Collections.synchronizedList(new ArrayList<>());
  2. 使用 CopyOnWriteArrayList 替代:

    • 适合 读多写少 的场景。
  3. 自行加锁(如 ReentrantLocksynchronized)。

  4. 使用并发集合框架(如 ConcurrentLinkedQueue / ConcurrentSkipListMap)。

4 CopyOnWriteList

CopyOnWriteArrayList 是一种 写时复制 的线程安全 List 实现。

写操作时会拷贝原数组,新数组写入后再替换。

读操作无需加锁,性能高。

适合读多写少的场景,比如缓存、白名单列表。

三、Fluentd

1 Fluentd的主要作用?

Fluentd 是一个开源的 日志收集与分发系统

统一收集不同来源的日志,结构化处理后再发送到目标系统(如 Elasticsearch、Kafka、S3)。

优点:

  • 插件丰富(input/output/filter)。
  • 易于扩展和管理。
  • 支持高可用和容错机制。

2 分布式系统中,日志格式和来源非常多样化,Fluentd如何处理这些差异?

  • 多输入插件(Input Plugin):支持 tail、syslog、http、kafka 等。
  • Parser 机制:可通过正则、JSON、LTSV、nginx/apache 格式解析。
  • Filter 插件:标准化字段、增加标签、结构化数据。
  • Tag + Route:根据日志类型灵活路由到不同输出目标。

👉 这样即便来源格式不同,也能实现统一处理与转发。

3 如果日志量激增,Fluentd在传输过程中出现延迟和丢失,如何应对?

常见手段:

  1. 增加 buffer(缓冲)
    • Fluentd 支持内存/文件 buffer。
    • 使用 file buffer 可以避免丢失。
  2. 集群部署 Fluentd
    • 多节点负载均衡,分摊压力。
  3. 调优 flush_interval / retry_wait 等配置。
  4. 上游限流
    • 防止 Fluentd 过载。
  5. 采用 Fluent Bit 作为边车(sidecar)
    • Fluent Bit 更轻量,适合高吞吐场景,再转发给 Fluentd。

四、MySQL索引

1 什么是聚簇索引和非聚簇索引?在InnoDB存储引擎中,主键索引是哪一种?

  • 聚簇索引(Clustered Index)
    • 数据和索引存储在一起。
    • 叶子节点存储的是数据本身。
    • InnoDB 的主键索引就是聚簇索引。
    • 优点:查询效率高,范围查询快。
  • 非聚簇索引(Secondary Index)
    • 叶子节点存储的是主键值,而不是数据。
    • 查询时需要“回表”查真实数据。

👉 例如:

select * from user where id=1;   -- 主键查询,不回表
select * from user where name='张三'; -- 非主键查询,要先查索引,再回表

2 如果一个表没有定义主键,会发生什么?InnoDB如何处理?

InnoDB 会自动选择:

  1. 第一个非空唯一索引 作为聚簇索引;
  2. 如果没有唯一索引,会 自动生成一个隐藏的 RowID 作为聚簇索引。

这种情况不利于数据管理和性能调优。 ✅ 建议总是为表定义主键。

五、加签验签

SHA256和RSA算法

  • SHA256
    • 是一种 不可逆 的哈希算法。
    • 常用于数据摘要和签名时的摘要部分。
    • 例如对请求体计算 SHA256 哈希,保证数据完整性。
  • RSA
    • 是一种 非对称加密算法
    • 分为公钥和私钥。
    • 加签时用 私钥签名,验签时用 公钥验证
    • 常与 SHA256 配合使用(如 SHA256withRSA):
      1. 先对数据做 SHA256 摘要。
      2. 再用 RSA 私钥对摘要加密生成签名。
      3. 验签时用公钥解密签名,比对摘要一致性。

👉 这种方式确保:

  • 防篡改(数据一致性)
  • 身份认证(只有私钥持有者能签名)
  • 不可否认性(签名不可伪造)