面试宝典第四话 -- 如何设计一个支持10万QPS的会员系统

在大型互联网系统中,设计 一个支持10WQPS的会员系统是一项具有跳转性的任务。
本文将从架构设计、技术选型、性能优化等多个方面,详细介绍如何在Java中实现这样一个高性能的会员系统。

1.系统需求分析

高并发处理:系统需求处理每秒10W次的会员相关操作,如登录、注册、查询会员信息等 。
数据一致性:保证会员接口数据一致性和完整性。
高可用性:系统必须具备容错和快速恢复的能力,保证高可用性。
扩展性:系统应用随着业务增长,轻松扩展支持更高的QPS.

2.架构设计

为了支持10WQPS,系统架构应该具备以下基础设施

2.1 微服务架构

可将会员系统再次细分为多个微服务,每个服务负责不同的功能模块,比如会员注册登录,会员信息,会员积分管理等等。这种架构可以实现水平扩展,避免单点瓶颈。

2.2 分布式缓存

使用分布式缓存(Redis)缓存热点数据,减少对数据库的直接访问,从而提高系统性能。

2.3 数据库主从,读写分离,分表分库

对于高并发的会员系统,单一数据库可能成为瓶颈。因为需要对数据库做分表分库,按照会员ID或者其他唯一标识进行分片存储。
另外为保证数据库高可用性,需要做主从高可用架构,同时实现读写分离,提升数据库得到读写性能。

2.4 API网关与负载均衡

通过API网关统一管理所有服务的入口,并通过负载均衡将请求分发到多个服务器实例上,避免单个实例的负载过高。

3.技术选型

3.1 技术栈

Spring Boot:用于构建微服务。
Redis:用于分布式缓存。
Mysql + ShardingSphere:用于分表分库管理。
Nginx + Gateway:用于负载均衡和反向代理。
Kafka/RabbitMQ:用于异步处理和消息队列。

3.2 关键组件配置

  • Redis缓存配置
    在高并发场景下,通过Redis缓存会员信息,减少数据库查询压力。

yaml配置

spring:
  data:
    redis:
      #数据库索引
      database: 0
      host: 192.168.168.131
      port: 6379
      password:
      #连接超时时间
      timeout: 5000
      repositories:
        enabled: false

数据库分库分表配置,使用详情在之前的文章,SpringBoot整合ShardingSphere-JDBC 5.3.2 实现读写分离、分库分表。

spring:
  shardingsphere:
    datasource:
      names: ds0, ds1
      ds0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/db0
        username: root
        password: password
      ds1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/db1
        username: root
        password: password
    sharding:
      tables:
        member:
          actual-data-nodes: ds$->{0..1}.member_$->{0..3}
          table-strategy:
            inline:
              sharding-column: member_id
              algorithm-expression: member_$->{member_id % 4}

4.性能优化

4.1 缓存策略

缓存预热:在系统启动时,将热点数据加载到缓存中,减少首次访问延迟。
缓存更新:采用先更新缓存再更新数据库策略 ,确保缓存与数据库的一致性。
缓存分布式锁:对应高并发写操作,通过分布式锁实现,避免缓存击穿。

4.2 限流与降级

限流:通过限流算法(如令牌桶)限制单个用户或IP的请求频率,防止流量突增导致系统奔溃。
降级:在系统压力过大时,对非核心功能进行降级处理,优先保证核心功能的可用性。

4.3 异步处理

使用消息队列(如Kafka、RabbitMQ)将一些可异步的、耗时的操作(如积分计算,发送通知)异步处理,减少主业务的响应时间。

5.实例代码

以下是一个简单的会员查询接口的实现,采用Redis的Hash缓存来优化查询性能:

@RestController
@RequestMapping("/member")
public class MemberController {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private MemberService memberService;

    @GetMapping("/{id}")
    public ResponseEntity<UserInfo> getUserInfo(@PathVariable Long id) {
        String cacheKey = "member:" + id;
        // 先从缓存中获取
        UserInfo userInfo = JSONObject.parseObject( redisTemplate.opsForValue().hgetAll(cacheKey),UserInfo.class);
        if (userInfo == null) {
            // 如果缓存中不存在,从数据库获取并缓存
            userInfo = memberService.getMemberById(id);
            if (userInfo != null) {
                memberService.handlerUserInfoCache(userInfo);
            }
        }
        return ResponseEntity.ok(userInfo);
    }
}

//处理缓存 存map数据格式
@Override
public void handlerUserInfoCache(UserInfo userInfo) {
   //把用户信息存入缓存 如果其他服务要 从缓存取 用户这里缓存存永久
   List<Field> fieldList = new ArrayList<>();
   Class<?> clazz = userInfo.getClass();
   //缓存的空字段需要移除 需要获取父级getFields可以获取父类public的 但难免忘记
   while (clazz != null && clazz != Object.class) {
       fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));
       clazz = clazz.getSuperclass(); //得到父类,然后赋给自己
   }

   JSONObject object = JSONObject.parseObject(JSONObject.toJSONString(userInfo));
   String redisKey = "member:" + userInfo.getId();
   String fieldName;
   for (Field field : fieldList) {
       fieldName = field.getName();
       if (!object.containsKey(fieldName)) {
           redisManager.hDelete(redisKey, fieldName);
       } else {
           redisManager.hPut(redisKey, fieldName, object.getString(fieldName));
       }
   }
}

6.总结

设计一个支持10万QPS的会员系统,需要从架构、技术选型、性能优化等多个方面综合考虑。通过微服务架构、分布式缓存、分库分表、负载均衡等技术手段,可以有效应对高并发的挑战,保证系统的高可用性和高性能。

以上就是本文的全部内容了,希望这篇文章对你有所帮助!

上一篇:面试宝典第三话 – 如果系统QPS突然提升10倍该怎么处理?
下一篇:面试宝典第五话 – xxx

非学无以广才,非志无以成学。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值