圈量科技面试
写在前面
这家公司招的是go,所以不面Java相关内容
项目
只问了我自己的项目,一个广告推荐系统,一个rpc
粘包问题
位置归一化,svd
序列化的时候和前端会出现什么问题,比如有的类型前端并没有
在序列化和前端交互时,如果前端没有某些类型,可能会遇到以下问题:
类型不匹配:后端发送的数据类型在前端不存在或不兼容,例如Java中的某些复杂对象类型,前端可能不支持或不能正确解析。这可能会导致数据丢失或解析错误。
类型转换问题:一些数据类型在序列化后可能需要在前端进行转换,比如Java中的
BigDecimal
在JavaScript中没有直接对应的类型,可能需要转换为字符串或其他类型进行处理。数据丢失:由于前端不支持某些类型,序列化后的数据可能会丢失精度或部分信息。例如,Java中的日期类型
LocalDateTime
,在JSON序列化后可能丢失时区信息。反序列化错误:前端在接收到不支持的数据类型时,可能会出现反序列化错误,导致无法正确解析数据,从而影响前端功能的正常运行。
为了解决这些问题,可以采取以下措施:
- 使用通用的数据格式:在序列化时,使用JSON或XML等通用格式,这些格式在大多数前端技术中都有良好的支持。
- 数据类型转换:在后端序列化之前,将特定的复杂类型转换为前端能够处理的简单类型。例如,将日期类型转换为ISO 8601字符串。
- 契约式编程:定义好前后端的接口契约,确保两端的类型一致,并通过文档和测试来保证实现的一致性。
- 类型适配器:在前端和后端之间实现类型适配器,自动将不兼容的类型转换为兼容类型。
微服务中链路上的日志如何监控
在微服务架构中,监控链路上的日志对于调试、问题排查和性能优化非常重要。下面是一些常见的策略和工具,用于在微服务中实现链路日志监控:
1. 分布式追踪
使用分布式追踪系统来跟踪每个请求在不同微服务中的流动,能够提供端到端的请求可视性。
工具:
- Jaeger:开源的分布式追踪系统,支持跨多个微服务的请求追踪。
- Zipkin:开源的分布式追踪系统,帮助收集时间数据来解决延迟问题。
- OpenTelemetry:统一的工具链,支持分布式追踪和度量。
实现方式:
- Trace ID:每个请求生成一个唯一的Trace ID,并在请求链路中传递。每个微服务处理请求时,将Trace ID添加到日志中。
- Span:每个微服务在处理请求时创建一个Span,记录开始时间、结束时间和其他元数据。
2. 集中式日志管理
集中化日志收集和分析,能够统一查看和分析来自不同微服务的日志。
工具:
- ELK Stack:Elasticsearch, Logstash, Kibana组合,用于日志收集、存储和可视化。
- EFK Stack:Elasticsearch, Fluentd, Kibana组合,与ELK类似,但使用Fluentd作为日志收集器。
- Graylog:开源的日志管理工具,提供强大的日志收集、存储和分析功能。
实现方式:
- 日志收集器:使用Logstash或Fluentd等工具收集不同微服务的日志,并发送到Elasticsearch或Graylog。
- 日志格式化:使用统一的日志格式(如JSON)便于解析和分析。
- 集中存储和查询:将日志集中存储在Elasticsearch中,通过Kibana或Graylog进行查询和可视化。
3. 日志关联
通过Trace ID和Span ID将不同微服务的日志关联起来,形成完整的请求链路日志。
实现方式:
- 在每个日志条目中包含Trace ID和Span ID。
- 使用集中式日志管理工具进行日志关联和查询,查看完整的请求链路。
4. 监控和告警
实时监控日志,并设置告警规则,当日志中出现错误或异常时,立即通知相关人员。
工具:
- Prometheus:开源的系统监控和告警工具,通常与Grafana结合使用。
- Alertmanager:与Prometheus结合使用,用于管理告警。
- Grafana:可视化工具,可以与Prometheus结合,创建仪表板和告警。
实现方式:
- 定义监控指标和告警规则,如错误率、延迟等。
- 在Prometheus中采集日志数据,并配置Alertmanager进行告警通知。
回答示例:
当面试官问到这个问题时,你可以这样回答:
在微服务架构中,我使用以下策略来监控链路上的日志:
分布式追踪:使用Jaeger或Zipkin进行分布式追踪,每个请求生成一个唯一的Trace ID,并在请求链路中传递。每个微服务处理请求时创建一个Span,记录开始时间、结束时间和其他元数据。
集中式日志管理:使用ELK Stack(Elasticsearch, Logstash, Kibana)收集、存储和分析来自不同微服务的日志。通过统一的日志格式(如JSON),便于解析和关联日志。
日志关联:在每个日志条目中包含Trace ID和Span ID,通过集中式日志管理工具将不同微服务的日志关联起来,形成完整的请求链路日志。
监控和告警:使用Prometheus和Grafana进行日志监控和告警,定义监控指标和告警规则,如错误率和延迟等。通过Prometheus采集日志数据,并配置Alertmanager进行告警通知。
通过这些策略和工具,我能够有效地监控微服务链路上的日志,及时发现和解决问题,确保系统的稳定性和性能。
redis缓存击穿怎么解决的
当谈到在项目中使用Redis解决缓存击穿的问题时,除了逻辑过期和互斥锁外,你还可以补充以下几种常见的解决方案,以展示你对缓存击穿问题的全面理解:
1. 逻辑过期
你提到的逻辑过期是一种非常有效的方式。可以进一步补充说明这种方法的细节:
- 实现方式:在缓存数据时,除了设置Redis的TTL(时间到期)外,还在缓存的数据中增加一个逻辑过期时间字段。
- 过期检查:每次访问缓存时,先检查逻辑过期时间。如果数据已过期,后台异步更新缓存数据,同时返回旧数据,避免缓存击穿。
2. 互斥锁
使用互斥锁可以避免多个请求同时重建缓存,进一步补充说明:
- 实现方式:在缓存失效时,通过Redis的分布式锁(如
SETNX
命令)来控制缓存重建的过程。 - 细节:只有获取到锁的请求才能重建缓存,其他请求等待或返回旧数据。重建完成后释放锁,更新缓存。
3. 预加载/定时刷新
定时刷新缓存可以有效减少缓存击穿的概率:
- 实现方式:使用定时任务在缓存过期前预先加载新数据,确保缓存总是有效。
- 细节:可以使用Redis的定时任务或者应用层的定时任务来实现定时刷新。
4. 热点数据永不过期
对于访问频繁的热点数据,可以设置较长的过期时间或者永不过期:
- 实现方式:识别出热点数据,设置为永不过期,定期手动刷新这些缓存。
- 细节:定期分析缓存访问日志,识别出新的热点数据,并及时更新缓存策略。
5. 双重缓存
双重缓存策略可以有效缓解缓存击穿的问题:
- 实现方式:维护两个缓存区,主缓存和备份缓存。在主缓存失效时,访问备份缓存,同时异步更新主缓存。
- 细节:备份缓存的数据可以设置较长的过期时间,确保在主缓存失效时仍有数据可用。
回答示例:
当面试官问到这个问题时,你可以这样回答:
在我的项目中使用Redis来解决缓存击穿的问题,除了逻辑过期和互斥锁外,我还采取了以下措施:
预加载/定时刷新:我使用定时任务在缓存过期前预先加载新数据,确保缓存总是有效。这样可以大大减少缓存击穿的概率。
热点数据永不过期:对于访问频繁的热点数据,我设置了较长的过期时间或者永不过期,并定期手动刷新这些缓存,确保热点数据始终可用。
双重缓存:我维护了两个缓存区,主缓存和备份缓存。在主缓存失效时,系统会访问备份缓存,同时异步更新主缓存。备份缓存的数据设置了较长的过期时间,确保在主缓存失效时仍有数据可用。
通过这些措施,我能够有效地防止缓存击穿问题,提高系统的稳定性和性能。
分布式事务
分布式事务,我是基于一个本地消息表来实现的,这个消息表每条数据都有一个状态字段显示是已完成或者是未完成,我将任务通过mq分发到各个服务中,等待所有服务都完成后才会将状态字段修改为已完成,其中我还有定时器一直轮询这个本地消息表的未完成的数据,重新进行发送。 但是面试官问我,如果一直失败怎么办呢?
对于你的分布式事务设计,如果一直失败,可以考虑以下几种策略来处理:
1. 最大重试次数
设置一个最大重试次数,如果某条消息已经重试了多次(例如3次或5次)仍然失败,可以将其标记为“失败”状态,并记录日志或触发报警。这种方法可以避免系统无限重试,防止资源浪费。
实现方式:
在本地消息表中增加一个重试次数字段,每次重试时增加该字段的值。达到最大重试次数后,改变状态为“失败”。
2. 人工干预
当消息多次重试仍然失败时,系统可以发送报警通知(例如邮件或短信)给运维人员,由他们来手动检查并处理失败的事务。
实现方式:
在达到最大重试次数后,触发报警系统通知相关人员。
3. 死信队列
对于无法处理的消息,可以使用MQ的死信队列(Dead Letter Queue, DLQ)。当消息多次处理失败后,自动将其移动到死信队列,后续可以由专门的系统或人员来处理这些消息。
实现方式:
配置MQ的死信队列功能,超过最大重试次数后,自动将消息发送到死信队列。
4. 补偿机制
设计补偿机制,通过反向操作来回滚或补偿已经部分执行的事务。补偿机制可以是自动的,也可以是半自动的,由系统提供补偿方案,人工确认执行。
实现方式:
在事务设计中引入补偿逻辑,每个操作都有对应的补偿操作。失败时,自动或人工执行补偿操作。
5. 幂等性
确保所有操作具有幂等性,即同一操作多次执行不会对系统状态产生额外影响。这可以避免因重复重试导致的数据不一致问题。
实现方式:
在设计服务接口时,确保每个操作具备幂等性,例如通过唯一请求ID来控制操作执行。
6. 日志和监控
对所有事务和重试操作进行详细日志记录,并通过监控系统实时监控重试情况,发现异常时及时响应。
实现方式:
集成日志系统(如ELK、Splunk)和监控系统(如Prometheus、Grafana),对分布式事务进行全面监控。
回答示例:
当面试官问到这个问题时,你可以这样回答:
在我的分布式事务实现中,如果某个任务一直失败,我采用了以下措施来处理:
最大重试次数:对于每条消息,我设置了一个最大重试次数。如果超过这个次数仍然失败,我会将该消息标记为“失败”,并记录详细日志。
人工干预:在消息标记为“失败”后,我会触发报警系统通知运维人员,由他们来手动检查并处理这些失败的事务。
死信队列:我们还使用了MQ的死信队列功能,将多次处理失败的消息转移到死信队列中,以便后续进行分析和处理。
补偿机制:设计了补偿机制,通过反向操作来回滚或补偿已经部分执行的事务,确保系统状态的一致性。
幂等性:所有操作都设计为幂等操作,确保同一操作多次执行不会对系统状态产生额外影响,避免因重复重试导致的数据不一致问题。