访问量
访客数

简要概述如何做好程序设计

2022.08.02 阅读量

数据库设计

  • 表结构设计:确保表和字段的设计符合业务需求,避免重复数据和不必要的复杂性。
  • 表的关联关系:检查表之间的关系,如外键,确保它们符合业务规则,并能支持常见的关系模式,如一对多和多对多。
  • 索引设计:创建必要的索引来加快查询速度,但不要过多,以免影响数据写入性能。
  • 大数据量表处理:对数据量大的表使用分片策略,将数据分散到多个位置,防止单个数据库过载。
  • 分片字段设计:选择合适的字段(如用户ID或日期)来分片数据,确保数据均匀分布,避免热点问题。
  • 表结构评审:定期检查和测试表结构,确保在高负载情况下依然能保持良好的性能。

缓存设计

  • 缓存结构选择:选择合适的 Redis 数据结构(如 stringhashlistset)。对于高并发接口,如果使用 hash 结构,要小心固定的 key 可能导致性能问题。 可以考虑使用 string 结构,并尽量压缩 value,例如将 {"groupId":"536363737", "groupId":"989898989"} 改为 "536363737#989898989",这样能节省 Redis 的存储空间。 如果需要检查数据是否存在,数据量很大时,可以用 set 结构,这样查询速度会更快,利用 sismember 方法很有效。
  • 缓存过期时间:设置合理的过期时间,避免设置过长时间,如 2 分钟或半小时。如果过期时间太长,Redis 的内存可能会被占满。
  • 预热和重建机制:设计预热缓存的方案,比如系统启动时自动加载数据到缓存中,或者后台提供手动刷新缓存的功能。还可以设置定时任务来定期刷新缓存,以保持数据的及时性。
  • 避免使用 delete 命令:尽量避免用 delete 命令删除缓存,这可能会阻塞 Redis,特别是当数据量很大时。使用 expire 命令设置数据过期时间,这样就能避免直接删除数据。
  • 二级缓存设计:考虑使用本地缓存和分布式缓存结合的方案。对于数据量较小(例如 1 万条以下,每条数据 10KB 以下)的热点数据,可以使用本地缓存(如 CaffeineGuava)。这样可以减少对 Redis 的压力,特别是对于频繁访问的数据。
  • 防止缓存穿透:避免让查询不到的数据直接查询数据库,这样会导致数据库负担过重。如果查询不到数据,要记得记录日志,方便后续检查。可以在系统启动时预热缓存,或者后台提供手动刷新缓存的按钮,或者用定时任务来保持缓存数据的更新。

定时任务设计

  • 幂等性:根据业务场景确保 Job 逻辑设计是幂等的,即作业执行多次结果一致,避免重复处理带来的问题。
  • 逻辑轻量:尽量保持作业逻辑简单,不要让它过于复杂,导致执行时间过长。如果逻辑较复杂,可以考虑将作业拆分成多个小作业,或优化代码,比如分批处理数据,减少单次处理的数据量。
  • 缓存重建:构建数据到缓存的作业最好安排在晚上 12 点以后执行。避免在白天执行,因为白天流量较大,重建缓存可能会导致接口抖动。
  • 定时任务:设定作业的执行时间时,要根据实际情况配置 cron 表达式,避免随意设置。如果本次作业执行时间较长,下一次作业可能会错过。
  • 大数据量处理:对于处理大表数据(如百万级、千万级甚至亿级),可以使用 xxjobsaturn 等分布式调度框架的分片处理能力,进行并行处理,以提高处理速度。

接口设计

  • 高并发测试:对高并发接口在测试环境中进行压力测试,了解接口的 QPS 支持情况。根据测试报告,及时调整线上配置和优化代码。
  • C端接口:明确接口的暴露位置,并根据预期调用流量和测试中支持的最大 QPS,决定是否需要扩容、限流、兜底逻辑或熔断。
  • 异常监控:配置错误监控和告警,便于及时发现程序中的异常情况。
  • 日志管理:在业务关键位置记录 info 级别的日志,高并发接口要设置日志开关,避免因日志记录影响性能。
  • 程序优化:对于高并发接口,尽量使用缓存和异步处理(如 MQ),避免多线程异步。设计时使用无锁机制以防止线程锁导致 CPU 使用过高,并考虑批量写入数据库。
  • 过滤无效请求:在接口前置进行请求过滤,尽早丢弃不合规的请求,缩短接口调用链路,提高整体吞吐量。
  • 设计考虑:设计时考虑无状态性、幂等性(如分布式锁的唯一 key)、安全性(如接口签名、第三方防刷服务判断是否为黑产用户)。
  • 第三方服务:对第三方服务采取零信任策略,设计降级和熔断机制,并与业务方确认好兜底逻辑处理。
  • 使用成熟工具:优先使用成熟的工具类库,如 ApacheGoogle 的开源框架,避免使用小众的开源框架,以免引入潜在的 bug 和性能瓶颈。
  • 时间复杂度:在设计时尽量保持时间复杂度为 O(1)。例如,调用第三方接口时,尽量将循环调用优化为批量调用,以将时间复杂度从 O(n) 降至 O(1)

监控设计

  • 核心接口监控:关注核心接口的表现,包括调用量的变化(如上涨/下跌超过 80%)、接口健康度(如 5 分钟内 error 超过 100 次、接口响应时间超过 1s 的次数超过 100 次、不可用次数超过 1000 次)。
  • 应用监控:监控应用的 CPU 使用率、内存使用情况、GC 活动、繁忙线程数和数据库连接池的连接数,设置相关告警。
  • 中间件监控:监控中间件如 Redis 的可用性,跟踪 CPU 使用、内存使用、流量、大 key、热 key 和慢查询情况。对 Kafka 进行可用性监控,监控消息积压情况和消息丢失率,并设置告警。
  • 数据库监控:监控 MySQLCPU 使用情况和慢 SQL 查询,并设置相关告警。
  • 业务监控:跟踪业务指标,如发券量的波动(暴涨或暴跌)、活动注册人数的同比或环比异常。

预案设计

  • 全局开关:设置全局开关以应对系统接近不可用的情况。通过配置中心快速切断接口流量,确保系统的基本可用性。
  • 非核心功能下线:在系统故障时,通过配置中心的开关下线非核心功能,保持核心服务的可用性。
  • 自动扩容:确保应用可以自动扩容。应用需要设计成无状态的,以便新节点可以无缝加入。避免依赖需要白名单的加密机等设计,这类设计会影响自动扩容能力。
发表评论