字节一面

1.elasticsearch为什么快?分片存储是怎么分片的?

  • 倒排索引:分词处理,根据词语定位词语出现在文档的哪个位置,避免全文搜索。
  • 分片存储/分布式架构:es将索引分为分片,每个分片独立存储和处理数据,查询数据时会并行查询再汇总结果。es集群由多个节点组成,每个节点可以存储和处理请求,提高查询速度。
  • 缓存机制:es会缓存最近查询结果。
  • 基于Lucene:es的核心,是一个全文搜索库,es封装它实现搜索功能。Lucene内部的优化算法包括跳跃表、布隆过滤器。

2.请求到达后怎么处理?(这个没太明白问的是什么)

  • 检查redis是否命中,有返回;没有查询mysql再写到redis中。

3.redis和mysql怎么保证同步/一致性?延迟双删的延迟设为多久?缓存的数据是什么?

https://www.cnblogs.com/coderacademy/p/18137480

  • 三种读写策略:
    • 旁路缓存:
      • 读:缓存读,命中返回;没有命中读数据库,更新缓存,返回。
      • 写:先更新mysql,再删缓存。
      • 为什么不直接更新缓存?假设两个线程都执行先更新db后更新redis的操作,两个线程更新的值不同时,假设执行的顺序是线程a写db、线程b写db、线程b写redis、线程a写redis,最终导致db和redis中更新的值不同。
    • 读写穿透(缓存系统内部自动化完成):
      • 读:类似与旁路缓存,不同在于写缓存的过程是由缓存系统内部实现的一个自动化流程
      • 写:缓存系统先更新缓存,再将更新同步给db。
    • 异步缓存:
      • 写:先执行缓存更新,记录此次更新暂存于队列,当队列到达一定大小时取出更新操作,批量写入db。
  • 三种方案:
    • 延迟双删:先删缓存再更新,设定一段延迟时间(几百毫秒),然后再删。
    • 删除缓存重试:假设删除缓存失败,进行多次尝试直到缓存删除。
    • 监听并读取binlog异步删除缓存:当数据库写时,记录到binlog或其他日志中,用一个异步服务或者监听器订阅binlog变化,然后将需要更新缓存的数据发送到消息队列,异步的删除或者更新缓存。
  • 延时时长:过短可能导致再次写入,过长导致脏数据存储过长时间。可以设置为数据库写时间+网络延迟的2-3倍(大概200ms-1s)。

4.jwt、token、session、cookie的区别?

https://www.cnblogs.com/RudeCrab/p/14251154.html
https://zhuanlan.zhihu.com/p/164696755
阮一峰老师的 JSON Web Token 入门教程

  • http无状态,不会保存任务会话信息,所以服务端和浏览器通过cookie/session进行会话跟踪。
    • cookie:客户端。服务器发送到浏览器上保存的一小块数据,在下次请求时一起发送给服务器。不可跨域。只支持存字符串。可以长时间保存。
    • session:服务端。基于cookie实现,服务端基于第一次访问的信息创建session,再将sessionid返回给客户端存储在cookie中。在用户之后的访问中将cookie发送给服务端,服务端再根据sessionid查找对应的session。靠sessionid确定! 可以存储任意类型。有效期较短。
    • token:访问api的凭证。 uid+时间戳+签名。 服务端无状态的验证方式,不用存储到token中,减少服务端的存储,用解析token的时间换取session存储空间,减轻数据库查询压力。(这个地方感觉是jwt的实现方法,是无状态的实现方式。也可以存储在服务端,有状态的存储,每次校验客户端发送的token和服务端的token是否匹配。)
      • 验证过程:客户端使用用户名+密码登录。服务端验证作为数字签名,加密后得到token,发送一个给客户端,客户端可以存储在cookie或者本地内存中,每次请求资源时卸载token验证(放在http的header中)。
    • jwt:json web token。 跨域认证。 用HMAC/RSA算法加密。无状态的认证方法。
      • jwt包含:header(签名算法)+payload(声明:传递数据包括id、过期时间)+signature(哈希算法基于header和payload生成,验证token是否被纂改)
      • jwt验证过程:签名验证->token解码、提取payload->过期验证
属性 Cookie Session Token JWT
定义 客户端存储的一段数据,用于维护用户与服务器的状态。 服务器端存储的一段数据,用于管理用户会话。 身份验证的标识符,可以是任意形式的字符串。 JSON Web Token,带有规范格式的 Token。
存储位置 存储在客户端(浏览器)中。 存储在服务器端(内存、数据库、分布式缓存等)。 通常存储在客户端,也可能只保存在服务器端。 通常存储在客户端的 Cookie 或 LocalStorage 中。
自包含性 不自包含,只是简单的数据存储机制。 不自包含,依赖服务器端存储会话数据。 通常不自包含,仅是标识符,需服务器查询其含义。 自包含,直接包含用户信息和权限声明等。
状态管理 无状态,客户端主动发送数据到服务器。 有状态,依赖服务器存储会话状态信息。 可无状态(如 JWT 实现),也可有状态(服务器记录 Token)。 无状态,服务器无需存储会话信息,只需验证签名。
数据格式 键值对(如 name=value)。 自定义格式,由服务器定义存储结构。 任意字符串,可能是 UUID 或 Base64 编码。 规范格式,包含 Header、Payload 和 Signature 三部分。
验证方式 浏览器自动携带,服务器解析后进行处理。 服务器通过 Session ID 获取会话信息并验证。 通常通过服务器端存储和验证(如 Redis)。 基于签名验证,服务器验证签名和有效期即可。
安全性 - 数据易被用户篡改(需加密和设置 HTTPOnly)。 - 服务器端存储,更安全,用户无法直接访问或修改。 - 不暴露数据内容,但依赖服务器验证安全性。 - 数据暴露于 Token 中(需 HTTPS 保护签名密钥)。
有效期 可通过 ExpiresMax-Age 设置,支持持久化。 默认与会话一致,浏览器关闭会失效(可持久化存储)。 由开发者定义,可随时更新或失效。 有固定的有效期,支持无状态的刷新机制(如 Refresh Token)。
优点 - 轻量级,适合存储少量的非敏感数据。 - 适合复杂状态管理,安全性较高。 - 灵活性高,适合多种身份验证场景。 - 自包含,无需服务器存储,分布式架构友好。
缺点 - 容易被篡改,大小有限。 - 依赖服务器资源,性能随会话数量增长可能下降。 - 需额外服务器存储(非 JWT 实现)。 - 数据暴露风险大,Token 长度较大。
适用场景 保存用户偏好、个性化设置、Session ID。 保存用户会话状态(如购物车、登录状态)。 OAuth2.0 或其他身份认证的标识符。 RESTful API 的无状态认证,分布式系统认证。
关系 可以独立使用,通常结合 Session 存储会话 ID。 依赖 Cookie 存储 Session ID 或其他标识符。 广义的身份验证字符串,可以包含 JWT。 Token 的具体实现形式,属于规范化的 Token。

5.jwt有加密吗?用了什么加密算法?是哈希算法吗?是对称的吗?

  • HS256。哈希算法,不是对称的。哈希算法不属于对称/不对称算法。
属性 JWT Token
定义 JSON Web Token,一种基于 JSON 的身份验证 Token 格式,遵循标准规范(RFC 7519)。 广义的身份验证字符串,可以是任何形式的标识符。
格式 Header.Payload.Signature,由三部分组成,采用 Base64 编码。 通常是随机字符串,如 ABC123DEF456,无固定格式。
自包含性 包含用户信息和声明,无需服务器存储即可验证。 一般不包含信息,只是一个标识符,需要服务器查询其对应信息。
状态管理 无状态,服务器无需存储,客户端保存并每次发送到服务器验证。 有状态,服务器需存储 Token 信息(如 Redis、数据库)。
存储位置 客户端存储于 Cookie、LocalStorage 或 SessionStorage 中。 通常存储于服务器端内存或分布式缓存中。
验证方式 基于签名验证(如 HMAC、RSA),无需查询数据库即可判断有效性。 需通过数据库或缓存查询验证其有效性。
数据安全性 数据未加密,直接暴露于 Token 内,但签名防篡改(需结合 HTTPS 保护传输)。 数据不可见,仅是标识符,不暴露敏感信息。
续期机制 可通过 Refresh Token 或重新生成 Token 实现续期。 服务器端直接更新 Token 数据或生成新的 Token。
优点 - 无需服务器存储,分布式友好;
- 减少数据库查询,性能更高。
- 结构简单,灵活实现;
- 支持复杂的状态管理和权限控制。
缺点 - 容量较大,包含数据量多;
- 数据泄露风险高(需保护签名密钥和使用 HTTPS)。
- 需要额外的服务器存储;
- 依赖查询,验证开销较大。
适用场景 RESTful API 无状态认证,分布式架构和微服务。 会话管理、OAuth 认证等需要状态管理的场景。

6.aop是什么?怎么用aop?原理是什么?在哪里用到

回答的时候要有条理

  • 相关定义:
    • 横切关注点:分散在多个模块中的关注点。日志记录、权限验证、事务管理。
    • 横切面:对横切关注点的具体实现,将横切关注点与核心业务逻辑分离。将横切关注点封装为一个独立的模块,避免代码冗余。
  • 是什么:aspect oriented programming面向切面编程。
  • 做什么:是一种编程思想,是面向对象编程(OOP)的延续和补充。AOP 通过将横切关注点(如日志记录、事务管理、安全性检查等)从主业务逻辑代码中分离出来,以模块化的方式实现对这些关注点的管理和重用。
  • 怎么实现的/原理:Spring Aop动态代理。不修改字节码,在内存中临时为方法生成一个aop对象,包含目标对象的全部方法,在特定的切点做了增强处理,回调原对象的方法。
  • 动态代理的方式:
    • JDK动态代理:通过反射接收被代理类,被代理类需要实现一个接口。没有接口选择CGLIB。
    • CGLIB动态代理:code generation library。通过继承做动态代理,假设用继承实现动态代理,当类为final时无法使用CGLIB。
  • 有什么用:实现关注点的分离,降低代码冗余。

7.redis中怎么实现分布式锁?最基础的set key有什么问题?

讲了基础的set key

  • 基于redis实现简易分布式锁:
    • 通过setnx(set if not exists)设置锁,释放锁用del
    • 为了防止误删,使用LUa脚本判断通过key对应的value判断。
    • 问题:释放锁的逻辑挂掉可能使锁无法释放,导致占用的资源无法被访问。
    • 解决方法:给锁设置过期时间。
    • 实现锁的续期:redisson(看门狗)。
  • 看门狗机制:
    • 解决问题:时间太短时,假设任务执行超过锁过期的时间,锁可能被释放掉;时间太长时,任务结束后锁仍然被占用,导致其他任务无法使用锁。
    • 原理:当客户端获得分布式锁后,存储一个键表示锁存在,默认过期时间为30s,锁被获取后redisson启动一个看门狗线程,默认情况下每隔10s为锁续约重置为30s,续约的前提是锁持有者仍然有效。任务释放锁时看门狗线程停止续约,锁自然过期。

手撕:1.传染树 2.重排链表

思路:1.找树的最大深度 2.leetcode原题

感想:

  • 1.手撕没撕出来,第一题没有思路,第二题写了思路对了但没通过用例,需要自己定义节点数据结构/输入输出。
  • 2.基础知识:不够扎实,有些东西一知半解,能说出来一点但不够深。之前的学习方法有点问题,需要不断用输出检验自己学的深度如何。
  • 3.面试表现:语句组织有点差,想好了再说,分层次分点说,常问题可以整理一个模板。