字节跳动国际电商后端,难度有点大呀

alt

1. tcp的客户端如果异常断开连接了服务端如何处理?

在 TCP 网络协议中,当客户端异常断开连接时,服务器需要采取一些措施来正确处理这种情况:

  1. 检测断开连接

    • TCP Keepalive:服务器可以使用 TCP Keepalive 选项来检测连接的状态。TCP Keepalive 会定期发送探测包,如果在一定时间内没有收到客户端的响应,服务器会认为连接已经断开。
    • 错误处理:当服务器尝试读写数据时,如果发现连接断开,通常会收到一个错误,例如 ECONNRESETEPIPE,服务器可以通过捕获这些错误来检测断开连接。
  2. 资源清理

    • 关闭套接字:一旦检测到客户端断开连接,服务器需要关闭相应的套接字。调用 close() 函数来释放资源。
    • 释放内存和资源:确保释放与该连接相关的所有资源,包括内存、文件描述符等。
  3. 处理半关闭连接

    • 在 TCP 协议中,连接的一端可以执行半关闭操作,即关闭连接的写方向而保持读方向打开。服务器需要处理这种情况,通常可以通过 shutdown() 函数来关闭连接的读方向或写方向。
  4. 使用超时机制

    • 服务器可以设置读写操作的超时时间,通过 setsockopt() 函数设置 SO_RCVTIMEOSO_SNDTIMEO 选项。如果在超时时间内没有完成操作,服务器可以认为连接已经断开并采取相应的措施。
  5. 检测 FIN 和 RST 包

    • 当客户端正常关闭连接时,会发送一个 FIN 包,服务器收到后需要回复一个 ACK 包。当服务器关闭连接时,也会发送一个 FIN 包,客户端回复 ACK 包。如果客户端异常断开连接,服务器可能会收到一个 RST 包,这意味着连接被强制重置。服务器需要处理这些 TCP 包以正确管理连接状态。

2. https的ssl加密是如何做的?

HTTPS 使用 SSL/TLS 来实现加密和安全通信。

1. SSL/TLS 握手过程

SSL/TLS 握手是建立加密连接的过程,包括以下几个步骤:

a. 客户端问候 (Client Hello)

客户端向服务器发送一个“客户端问候”消息,内容包括:

  • 支持的 SSL/TLS 版本。
  • 支持的加密算法 (Cipher Suites)。
  • 一个随机数 (Client Random)。

b. 服务器问候 (Server Hello)

服务器响应客户端,发送一个“服务器问候”消息,内容包括:

  • 选择的 SSL/TLS 版本。
  • 选择的加密算法。
  • 一个随机数 (Server Random)。
  • 服务器的数字证书 (包含服务器的公钥)。
  • (可选)请求客户端证书。

c. 服务器证书验证

客户端验证服务器的数字证书,确保证书由可信任的证书颁发机构 (CA) 签发,且证书未过期。如果验证失败,握手过程会终止。

d. 客户端密钥交换 (Client Key Exchange)

客户端生成一个称为 Pre-Master Secret 的随机数,并用服务器的公钥加密,然后发送给服务器。

e. 会话密钥生成

服务器使用自己的私钥解密 Pre-Master Secret,客户端和服务器根据之前交换的随机数和 Pre-Master Secret 共同生成会话密钥。

f. 客户端完成消息 (Client Finished)

客户端使用会话密钥发送一条“完成”消息,这条消息是客户端到服务器的第一个加密消息,用于确认握手过程的完整性。

g. 服务器完成消息 (Server Finished)

服务器也使用会话密钥发送一条“完成”消息,确认握手过程结束。

2. 加密通信

在握手过程完成后,客户端和服务器之间的通信将使用会话密钥进行对称加密。对称加密算法如 AES、DES、ChaCha20 等可以高效地加密和解密数据。

3. 连接终止

当通信完成后,客户端或服务器可以发起连接终止过程:

  • 发送一个“关闭通知”消息,表示即将关闭加密连接。
  • 对方接收到“关闭通知”后,也会发送一个“关闭通知”消息,然后关闭连接。

3. 说一说数据库索引失效的场景?

  1. 不满足最左匹配原则

    • 在联合索引中,查询条件没有使用到最左边的索引列,导致索引失效。例如,假设存在联合索引(sex, age, name),但查询条件只包含age和name,而不包含sex,此时索引将不会被使用。
  2. 索引列上进行计算或函数操作

    • 当在索引列上应用计算或函数时,索引通常会失效。例如,SELECT * FROM table WHERE YEAR(date_column) = 2023; 这样的查询中,由于使用了YEAR函数,date_column上的索引将不会被使用。
  3. 数据类型不匹配

    • 当查询中使用的数据类型与索引列的数据类型不匹配时,索引可能会失效。例如,将字符串类型的列与数值类型进行比较时,索引可能不会被使用。
  4. LIKE查询以通配符开头

    • 在使用LIKE查询时,如果通配符(%)位于搜索模式的开头,索引可能会失效。例如,SELECT * FROM table WHERE name LIKE '%John'; 这样的查询通常不会使用name列上的索引。
  5. 使用OR关键字连接的条件

    • 当查询条件使用OR连接时,如果OR连接的两个条件分别涉及到不同的索引列,或者两边分别使用了范围查询(如>和<),则索引可能会失效。
  6. 使用NOT IN或NOT EXISTS

    • 在某些情况下,使用NOT IN或NOT EXISTS的查询可能会导致索引失效,尤其是当它们涉及到大量数据时。
  7. 使用不等于(<> 或 !=)

    • 当查询条件中使用了不等于操作符时,如果查询的结果集较大,索引可能会失效。
  8. IS NOT NULL

    • 虽然IS NULL通常可以使用索引,但IS NOT NULL在某些情况下可能无法使用索引。
  9. 索引列的顺序不正确

    • 在复合索引中,如果查询条件中列的顺序与复合索引的列顺序不一致,索引可能不会被使用。
  10. 数据分布不均

    • 如果索引列上的数据分布非常不均匀,有些值出现频率特别高,查询这些高频值时,索引可能无法显著提高性能。数据库优化器可能会选择全表扫描而不是使用索引。
  11. 前缀索引使用不当

    • 如果使用了前缀索引,但前缀长度设置得不够长,导致查询结果不准确,索引可能会失效。
  12. 查询条件中包含非索引列

    • 如果查询条件中同时包含了索引列和非索引列,并且查询结果需要非索引列的数据,那么即使索引列上的索引有效,也可能需要进行额外的磁盘I/O操作来检索非索引列的数据,从而影响查询性能。

3. 联合索引中如果建立的顺序是(A,B,C,D),使用时有哪些注意事项?

当联合索引的建立顺序为(A,B,C,D)时,使用时需要注意以下事项:

  1. 最左前缀原则

    • 查询条件必须包含索引的最左列,即A列。如果查询条件中不包含A列,那么索引可能不会被使用。
    • 查询可以仅使用A列,或者使用A和B列,或者A、B和C列,或者完整的A、B、C、D列,这些查询都可以利用该联合索引。
  2. 列顺序

    • 在创建联合索引时,列的顺序应该根据查询的需求和数据的选择性来决定。通常,将选择性最高的列放在最左侧可以提高查询性能。
    • 例如,如果查询经常根据A列和B列进行,并且B列的选择性较高,那么将B列放在A列之后可能不是最佳选择。
  3. 索引宽度

    • 联合索引的宽度是所有索引列的宽度之和。过宽的联合索引可能会导致索引占用更多的磁盘空间,并且在内存中加载索引时可能会增加额外的开销。
    • 在设计联合索引时,需要权衡列的选择和索引的宽度,避免创建过宽的索引。
  4. 查询覆盖

    • 如果查询只需要访问索引中的信息,而不需要访问表中的数据行,那么这个查询就被称为“覆盖索引”查询。这样的查询通常非常快。
    • 在设计联合索引时,可以考虑将查询所需的列都包含在索引中,以实现覆盖查询,提高查询性能。
  5. 冗余索引

    • 当表已经有了一个联合索引时,不需要再创建包含该联合索引的子集的单列索引。因为联合索引已经可以支持包含该子集的查询,创建冗余索引只会增加索引维护的开销,浪费存储空间。
  6. 更新代价

    • 联合索引在插入、更新和删除操作时需要维护索引。如果表的更新操作频繁,联合索引可能会增加更新的代价。因此,在设计联合索引时,要考虑到表的更新模式和频率。
  7. 查询选择性

    • 联合索引的选择性是指索引列中不同值的数量与总行数的比率。选择性越高,索引的效果越好。因此,在选择联合索引的列时,应考虑到查询选择性,选择具有高选择性的列作为联合索引的一部分。
  8. 索引列的使用

    • 索引列不能参与计算,保持列“干净”。例如,对索引列使用函数或进行计算可能导致索引失效。
    • 在查询时,尽量按照联合索引的顺序来编写查询条件,以充分利用索引。
  9. 优化器选择

    • MySQL的查询优化器会根据查询语句的成本来选择使用哪个索引。因此,即使存在多个可用的索引,也不一定能保证联合索引总是被使用。

4. 数据库的主键为什么要用自增的?

数据库的主键使用自增有多个原因:

  1. 唯一性: 主键的主要目的是确保表中每一行数据的唯一性。自增字段可以确保每次插入新行时都会生成一个新的、唯一的值。

  2. 简化开发: 在插入新记录时,开发人员不需要手动为每一行生成一个唯一的值。数据库系统会自动处理自增值的生成,从而简化了开发过程。

  3. 减少冲突: 如果使用其他值(如 UUID 或自定义的唯一字符串)作为主键,可能会存在与其他表中的值冲突的风险。自增值通常是整数,并且在每次插入时递增,因此不太可能与其他表中的值冲突。

  4. 性能: 整数类型的主键通常比长字符串或UUID等更复杂的数据类型具有更好的性能。整数在存储、索引和查询时通常更快。

  5. 易于排序和分页: 由于自增值是顺序递增的,因此它们很容易用于排序和分页操作。例如,你可以很容易地获取表中的前10个记录,或者跳过前100个记录并获取接下来的10个记录。

  6. 扩展性: 虽然整数类型的主键有范围限制,但在大多数情况下,这个范围对于单个表来说已经足够大了。如果需要存储更多的数据,可以考虑使用BIGINT类型的主键,它可以支持更大的范围。

  7. 避免暴露业务逻辑: 如果主键是基于业务逻辑生成的,那么当业务逻辑发生变化时,可能需要更改主键的生成逻辑。这可能会导致数据迁移、应用程序修改等复杂问题。而使用自增主键可以避免这种情况,因为主键的生成完全由数据库系统控制。

  8. 易于备份和恢复: 如果数据库需要备份和恢复操作,使用自增主键可以简化这些过程。因为每次恢复数据库时,自增字段都会从上次的最大值开始递增,所以不需要担心重复的主键值问题。

5. 数据库的四种事物隔离级别以及它们的细节?

数据库的四种事务隔离级别,按照从低到高的顺序,分别是:读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。以下是这四种隔离级别的详细解释:

  1. 读未提交(Read Uncommitted)

    • 简述:最低的隔离级别,一个事务可以读取另一个事务尚未提交的数据修改。
    • 特性:
      • 允许脏读:事务A可以读取事务B尚未提交的数据修改。
      • 不保证一致性:由于允许脏读,无法保证事务的一致性。
      • 低并发性:需要较少的并发控制和锁定操作,但增加了数据不一致的风险。
    • 应用场景:通常用于对数据一致性要求不高、并发性要求较高的场景,如临时数据分析任务。
  2. 读已提交(Read Committed)

    • 简述:一个事务只能读取到已经提交的数据修改。
    • 特性:
      • 已提交数据可见:其他事务尚未提交的数据修改对当前事务是不可见的。
      • 一致性保证:保证事务读取到的数据是一致的。
      • 不可重复读:同一个事务在不同的时间点多次读取同一行数据,可能会得到不同的结果。
      • 无法解决幻读问题:无法解决由其他事务插入或删除数据导致的查询结果不一致问题。
    • 应用场景:提供了一定程度的数据隔离,避免了脏读问题,并保证了读取到的数据是一致的。
  3. 可重复读(Repeatable Read)

    • 简述:一个事务在执行过程中多次读取同一行数据,可以得到一致的结果。
    • 特性:
      • 保证一致性:在事务执行过程中,多次读取同一行数据得到的结果始终保持一致。
      • 防止不可重复读:解决了读已提交隔离级别中的不可重复读问题。
      • 防止幻读(部分):一定程度上防止了幻读问题,但不完全保证查询结果的完全一致性。
    • 应用场景:提供了较高的隔离性,保证了事务内部多次读取同一行数据的一致性。
  4. 串行化(Serializable)

    • 简述:最高的隔离级别,事务串行化顺序执行。
    • 特性:
      • 避免所有并发问题:完全避免了脏读、不可重复读和幻读等所有并发问题。
      • 性能影响:由于事务需要串行执行,对系统的性能产生较大影响。
      • 死锁风险:可能导致死锁的风险增加。
    • 应用场景:提供了最高的隔离性,可以完全避免所有的并发问题。但由于其严格的执行顺序要求,可能会对系统的性能产生较大的影响。

6. 操作系统进程调度算法以及它们的优缺点?

操作系统中的进程调度算法是决定哪个进程将获得CPU资源以执行其任务的重要机制。以下是几种常见的进程调度算法及其优缺点的详细解释:

  1. 先来先服务(FCFS,First Come First Serve)

    • 优点:
      • 易于理解和实现,只需要一个队列即可。
      • 公平,按照进程到达的先后顺序提供服务。
    • 缺点:
      • 不利于短作业,可能导致短作业长时间等待。
      • 如果有长作业先到达,可能导致后续短作业长时间等待,即出现饥饿现象。
  2. 时间片轮转(RR,Round Robin)

    • 优点:
      • 适用于分时系统,保证每个用户都能获得一定的CPU时间。
      • 平均响应时间短,用户交互性好。
    • 缺点:
      • 不利于处理紧急作业,因为即使作业紧急也需要等待当前时间片用完。
      • 时间片大小的选择对系统性能有重要影响,过大可能退化为FCFS,过小则导致频繁切换,增加系统开销。
  3. 短作业优先(SJF,Shortest Job First)

    • 优点:
      • 减少平均等待时间,提高系统吞吐量。
      • 优先照顾短作业,降低平均周转时间。
    • 缺点:
      • 对长作业不利,可能导致长作业长时间得不到执行,出现饥饿现象。
      • 需要准确估计作业的执行时间,估计不准确会影响调度性能。
  4. 高响应比优先(HRRN,Highest Response Ratio Next)

    • 优点:
      • 综合考虑了作业的等待时间和执行时间,避免了SJF中的饥饿现象。
      • 响应比的计算使得即使长作业等待时间较长,也有机会获得CPU资源。
    • 缺点:
      • 计算响应比需要消耗系统资源。
      • 可能导致较长的平均等待时间。
  5. 优先级调度(Priority Scheduling)

    • 优点:
      • 根据作业的紧迫程度进行调度,满足不同需求。
      • 既可以用于作业调度,也可以用于进程调度。
    • 缺点:
      • 可能导致低优先级作业长时间得不到执行,出现饥饿现象。
      • 优先级的设定和修改需要额外的管理和开销。
  6. 多级反馈队列调度(Multilevel Feedback Queue Scheduling)

    • 优点:
      • 兼顾长短作业,有较好的响应时间和吞吐量。
      • 灵活性强,可以根据系统情况动态调整队列级别和时间片大小。
    • 缺点:
      • 实现相对复杂,需要维护多个队列和时间片。
      • 可能导致进程在队列间频繁迁移,增加系统开销。

7. 介绍一下IO多路复用?

IO多路复用是一种高效的IO处理机制,它允许单个线程或进程同时监听多个输入/输出通道(如网络套接字、文件描述符等),并在有数据可读或可写时进行相应的处理,而不需要为每个通道创建一个独立的线程或进程。这种机制可以显著提高系统的性能和资源利用率,减少不必要的线程切换和上下文切换开销。

  1. 基本概念

    • IO多路复用通过一个线程或进程来管理多个IO通道,避免了为每个通道创建独立线程或进程的开销。
    • 常见的IO多路复用机制包括select、poll和epoll(Linux特有)。
  2. 实现方式

    • select
      • 阻塞住监视三类文件描述符(写、读、异常),当有数据可读、可写、出异常或超时时返回。
      • 遍历fdset数组来找到就绪的描述符,然后进行IO操作。
      • 在所有平台上支持,但性能随文件描述符数量增多而下降,且每次调用都需要将fd集合从用户态拷贝到内核态。
    • poll
      • 原理与select一致,也是轮询+遍历,但没有最大文件描述符限制(使用链表方式存储fd)。
      • 同样存在性能随文件描述符数量增多而下降的问题。
    • epoll
      • Linux特有的IO多路复用机制,使用内核事件表来管理和监听多个IO事件的就绪状态。
      • 通过epoll_ctl注册fd,一旦fd就绪就会通过callback回调机制来激活对应fd,进行IO操作。
      • 高效,使用回调通知而不是轮询的方式,不会随着FD数目的增加效率下降。
      • 支持大量文件描述符,且没有fd限制,是构建高性能网络应用的首选。
  3. 优点

    • 减少系统开销:不必创建过多的进程/线程,也不必维护这些进程/线程。
    • 提高性能和可伸缩性:可以有效地处理大量并发请求,提高了性能和可伸缩性。
    • 节省资源:减少内存和系统资源的消耗。
    • 支持非阻塞I/O:允许程序在等待数据准备好时继续执行其他任务。
    • 简化程序结构:不需要处理复杂的线程管理和同步问题。
  4. 应用场景

    • 在许多网络应用中,如Web服务器、聊天应用、实时游戏等,需要同时处理大量的连接请求或数据传输,IO多路复用技术可以显著提高这些应用的性能。
    • 在高性能服务器应用中,如Redis、Nginx等,IO多路复用技术被广泛使用,以支持更多的并发连接请求。

8. leetcode31.下一个排列

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int i = nums.size() - 2;
        while (i >= 0 && nums[i] >= nums[i + 1]) {
            i--;
        }
        if (i >= 0) {
            int j = nums.size() - 1;
            while (j >= 0 && nums[i] >= nums[j]) {
                j--;
            }
            swap(nums[i], nums[j]);
        }
        reverse(nums.begin() + i + 1, nums.end());
    }
};

视频讲解:【字节面经】 https://www.bilibili.com/video/BV1NfhTevE5e/?share_source=copy_web&vd_source=8616a4ca7cd238e3ae63b702819f547f

全部评论

相关推荐

3 15 评论
分享
牛客网
牛客企业服务