字节一面
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 保护签名密钥)。 |
有效期 | 可通过 Expires 或 Max-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.面试表现:语句组织有点差,想好了再说,分层次分点说,常问题可以整理一个模板。