写在前面

这家公司招的是go,所以不面Java相关内容

项目

只问了我自己的项目,一个广告推荐系统,一个rpc

粘包问题

位置归一化,svd

序列化的时候和前端会出现什么问题,比如有的类型前端并没有

在序列化和前端交互时,如果前端没有某些类型,可能会遇到以下问题:

  1. 类型不匹配:后端发送的数据类型在前端不存在或不兼容,例如Java中的某些复杂对象类型,前端可能不支持或不能正确解析。这可能会导致数据丢失或解析错误。

  2. 类型转换问题:一些数据类型在序列化后可能需要在前端进行转换,比如Java中的BigDecimal在JavaScript中没有直接对应的类型,可能需要转换为字符串或其他类型进行处理。

  3. 数据丢失:由于前端不支持某些类型,序列化后的数据可能会丢失精度或部分信息。例如,Java中的日期类型LocalDateTime,在JSON序列化后可能丢失时区信息。

  4. 反序列化错误:前端在接收到不支持的数据类型时,可能会出现反序列化错误,导致无法正确解析数据,从而影响前端功能的正常运行。

为了解决这些问题,可以采取以下措施:

  • 使用通用的数据格式:在序列化时,使用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进行告警通知。

回答示例:

当面试官问到这个问题时,你可以这样回答:


在微服务架构中,我使用以下策略来监控链路上的日志:

  1. 分布式追踪:使用Jaeger或Zipkin进行分布式追踪,每个请求生成一个唯一的Trace ID,并在请求链路中传递。每个微服务处理请求时创建一个Span,记录开始时间、结束时间和其他元数据。

  2. 集中式日志管理:使用ELK Stack(Elasticsearch, Logstash, Kibana)收集、存储和分析来自不同微服务的日志。通过统一的日志格式(如JSON),便于解析和关联日志。

  3. 日志关联:在每个日志条目中包含Trace ID和Span ID,通过集中式日志管理工具将不同微服务的日志关联起来,形成完整的请求链路日志。

  4. 监控和告警:使用Prometheus和Grafana进行日志监控和告警,定义监控指标和告警规则,如错误率和延迟等。通过Prometheus采集日志数据,并配置Alertmanager进行告警通知。

通过这些策略和工具,我能够有效地监控微服务链路上的日志,及时发现和解决问题,确保系统的稳定性和性能。

redis缓存击穿怎么解决的

当谈到在项目中使用Redis解决缓存击穿的问题时,除了逻辑过期和互斥锁外,你还可以补充以下几种常见的解决方案,以展示你对缓存击穿问题的全面理解:

1. 逻辑过期

你提到的逻辑过期是一种非常有效的方式。可以进一步补充说明这种方法的细节:

  • 实现方式:在缓存数据时,除了设置Redis的TTL(时间到期)外,还在缓存的数据中增加一个逻辑过期时间字段。
  • 过期检查:每次访问缓存时,先检查逻辑过期时间。如果数据已过期,后台异步更新缓存数据,同时返回旧数据,避免缓存击穿。

2. 互斥锁

使用互斥锁可以避免多个请求同时重建缓存,进一步补充说明:

  • 实现方式:在缓存失效时,通过Redis的分布式锁(如SETNX命令)来控制缓存重建的过程。
  • 细节:只有获取到锁的请求才能重建缓存,其他请求等待或返回旧数据。重建完成后释放锁,更新缓存。

3. 预加载/定时刷新

定时刷新缓存可以有效减少缓存击穿的概率:

  • 实现方式:使用定时任务在缓存过期前预先加载新数据,确保缓存总是有效。
  • 细节:可以使用Redis的定时任务或者应用层的定时任务来实现定时刷新。

4. 热点数据永不过期

对于访问频繁的热点数据,可以设置较长的过期时间或者永不过期:

  • 实现方式:识别出热点数据,设置为永不过期,定期手动刷新这些缓存。
  • 细节:定期分析缓存访问日志,识别出新的热点数据,并及时更新缓存策略。

5. 双重缓存

双重缓存策略可以有效缓解缓存击穿的问题:

  • 实现方式:维护两个缓存区,主缓存和备份缓存。在主缓存失效时,访问备份缓存,同时异步更新主缓存。
  • 细节:备份缓存的数据可以设置较长的过期时间,确保在主缓存失效时仍有数据可用。

回答示例:

当面试官问到这个问题时,你可以这样回答:


在我的项目中使用Redis来解决缓存击穿的问题,除了逻辑过期和互斥锁外,我还采取了以下措施:

  1. 预加载/定时刷新:我使用定时任务在缓存过期前预先加载新数据,确保缓存总是有效。这样可以大大减少缓存击穿的概率。

  2. 热点数据永不过期:对于访问频繁的热点数据,我设置了较长的过期时间或者永不过期,并定期手动刷新这些缓存,确保热点数据始终可用。

  3. 双重缓存:我维护了两个缓存区,主缓存和备份缓存。在主缓存失效时,系统会访问备份缓存,同时异步更新主缓存。备份缓存的数据设置了较长的过期时间,确保在主缓存失效时仍有数据可用。

通过这些措施,我能够有效地防止缓存击穿问题,提高系统的稳定性和性能。

分布式事务

分布式事务,我是基于一个本地消息表来实现的,这个消息表每条数据都有一个状态字段显示是已完成或者是未完成,我将任务通过mq分发到各个服务中,等待所有服务都完成后才会将状态字段修改为已完成,其中我还有定时器一直轮询这个本地消息表的未完成的数据,重新进行发送。 但是面试官问我,如果一直失败怎么办呢?

对于你的分布式事务设计,如果一直失败,可以考虑以下几种策略来处理:

1. 最大重试次数

设置一个最大重试次数,如果某条消息已经重试了多次(例如3次或5次)仍然失败,可以将其标记为“失败”状态,并记录日志或触发报警。这种方法可以避免系统无限重试,防止资源浪费。

实现方式
在本地消息表中增加一个重试次数字段,每次重试时增加该字段的值。达到最大重试次数后,改变状态为“失败”。

2. 人工干预

当消息多次重试仍然失败时,系统可以发送报警通知(例如邮件或短信)给运维人员,由他们来手动检查并处理失败的事务。

实现方式
在达到最大重试次数后,触发报警系统通知相关人员。

3. 死信队列

对于无法处理的消息,可以使用MQ的死信队列(Dead Letter Queue, DLQ)。当消息多次处理失败后,自动将其移动到死信队列,后续可以由专门的系统或人员来处理这些消息。

实现方式
配置MQ的死信队列功能,超过最大重试次数后,自动将消息发送到死信队列。

4. 补偿机制

设计补偿机制,通过反向操作来回滚或补偿已经部分执行的事务。补偿机制可以是自动的,也可以是半自动的,由系统提供补偿方案,人工确认执行。

实现方式
在事务设计中引入补偿逻辑,每个操作都有对应的补偿操作。失败时,自动或人工执行补偿操作。

5. 幂等性

确保所有操作具有幂等性,即同一操作多次执行不会对系统状态产生额外影响。这可以避免因重复重试导致的数据不一致问题。

实现方式
在设计服务接口时,确保每个操作具备幂等性,例如通过唯一请求ID来控制操作执行。

6. 日志和监控

对所有事务和重试操作进行详细日志记录,并通过监控系统实时监控重试情况,发现异常时及时响应。

实现方式
集成日志系统(如ELK、Splunk)和监控系统(如Prometheus、Grafana),对分布式事务进行全面监控。

回答示例:

当面试官问到这个问题时,你可以这样回答:


在我的分布式事务实现中,如果某个任务一直失败,我采用了以下措施来处理:

  1. 最大重试次数:对于每条消息,我设置了一个最大重试次数。如果超过这个次数仍然失败,我会将该消息标记为“失败”,并记录详细日志。

  2. 人工干预:在消息标记为“失败”后,我会触发报警系统通知运维人员,由他们来手动检查并处理这些失败的事务。

  3. 死信队列:我们还使用了MQ的死信队列功能,将多次处理失败的消息转移到死信队列中,以便后续进行分析和处理。

  4. 补偿机制:设计了补偿机制,通过反向操作来回滚或补偿已经部分执行的事务,确保系统状态的一致性。

  5. 幂等性:所有操作都设计为幂等操作,确保同一操作多次执行不会对系统状态产生额外影响,避免因重复重试导致的数据不一致问题。