Ken的杂谈
  • Ken的杂谈 (current)
  • 关于
  • 杂谈
    Java Spring Spring Boot Spring Cloud MyBatis C# .NET Core .NET ASP.NET Core ASP.NET ClassLibrary Mono 数据库 MySQL SQL Server 网络 缓存 Web Linux CentOS Ubuntu macOS Windows openEuler Nginx ServiceStack JS/JQ 正则 工具 IDE Grafana Exceptions CI/CD Solution 微服务 Arch Docker 杂谈
  • 系列
    Java 快速入门系列教程 Spring Boot 入门教程 Spring Boot 2.x 入门教程 Spring Cloud 入门教程 .NET Core 快速入门教程 ASP.NET Core 2.1 入门教程 CentOS 7 快速上手教程 Ubuntu快速上手入门教程 Hyper-V基础教程 Docker入门教程
  • GitHub

高并发网站/服务常规应对方案和思路

杂谈 Solution Arch @ 2020-06-29 22:36:40 · 阅读:(6057)

一、并发量预估

作为后端的程序开发人员,经常听到高并发,但是高并发到底有多高?其实是没有数值定义的

但是如果在面试的过程中,或者跟别人沟通的过程中,有人提到百万级并发那么可能三种情况

  • 他在吹牛皮
  • 他没有用对并发这个词
  • 他真的很NB(例如:天猫双11关联项目组的)

截至2019/11/11,支付宝双11订单峰值是 54.4W笔/秒,单个服务的集群的QPS破百万的应该也很少

要应对多少并发,我们要看一天有多少访问量/请求量,假如是一个每天有1亿请求的网站/服务

那么:

  • 平均QPS=100000000 / (24 60 60)≈1158
  • 峰值QPS=10,000,000 0.8/(24 60 60 0.2)≈4630

峰值的计算逻辑是根据二八原则,80%的请求集中在20%的时间段内。
这只是通用的计算方式,如果涉及到秒杀或者其他特殊的场景就要用其他的方式来预估了。

所以,高并发的程序,一定是要看自己要实际的用户数跟访问需求

二、服务器预估

1、应用服务器

如果接口响应耗时的99线在100ms以内,单次返回内容<=1KB,那么4C8G的通用虚拟机,通常可以承受300QPS,4630/300≈16,16台应用服务器做负载均衡,分摊请求压力

2、数据库服务器

数据库服务器阿里云8核32GB,扛个1.5W+IOPS都是没问题的,只要没有长事务,easy

根据数据量以及索引的情况,预估好磁盘空间即可

3、负载均衡服务器&带宽

负载均衡服务器通常就NGINX,按照NGINX官方的介绍,志强CPU,18核36线程,请求<=1KB静态资源,只用1个核心,就可以支撑7W+连接

那么2台计算型4C8G云服务器搭建两个NGINX服务器基本上也OK了,服务器带宽的话,46301KB8≈37MB,考虑到冗余,50M带宽也基本够用了

3、其他服务器

缓存服务器,阿里云、腾讯云有成熟服务,根据用量购买即可
CDN服务器,七牛、又拍云有成熟服务,根据用量购买即可

服务器都是钱,所以,有多少的量估多少,估多了,老板也不愿意出这个钱的。

三、缓存方案和场景

1、工具

1、外部缓存:浏览器缓存、NGINX缓存、CDN缓存

2、本地缓存:MemoryCache(.NET)、Caffeine(Java)

3、分布式缓存:Redis、Memcached、MongoDB

2、场景

查询类页面,例如商品介绍,博客文章,都可以用浏览器缓存、CDN

对数据一致性要求不高的,可以用本地缓存,比如站点访问量信息(需要NGINX配合做iphash负载均衡)

对于重要的信息,查询两大,且需要更新的,建议放在Redis,最好要做缓存预热

3、注意事项

一定要做好缓存容量的预估,不要把缓存服务器搞崩了

如果是Redis,要控制好单Key存储的值大小,因为Redis6.0之前都还是单线程设计,但Key值太大会影响性能,通常但Key值控制在1M以内

四、数据库拆分

如果是百万级的数据,单库单表就扛得住,前提是不能有过多的字段,或者是varchar>1000的这种大字段建议做垂直拆分,大字段拆分到扩展表里面。如果数据超千万,会有一定的读写压力,建议做水平拆分

1000W<数据量<10*1000W,2库8表,平均每张表1250W数据

101000W<数据量<1001000W,4库64张表,平均每张表1500W数据

无论拆几个库几张表,表名都应该是连续的且不重复的,例如2库8表,那么:
db0中包含表t0-t3,db1中包含表t4-t7

1、拆分之后的好处

  • 单个数据库承受的连接数都是有限的,分开后可以分摊查询压力,读写是在太频繁还可以拆分服务器升配置
  • 拆表之后可以提升查询效率,单表数据少了扫描磁盘的次数减少了,压力减少性能提升

2、拆分的纬度

  • 按照用户ID取模,比如 uid%4=0/1/2/3,数据分别放在 user_0、user_1、user_2、user_3这4个表
  • 按照时间切分,每三个月1个数据库

3、分片(Sharding)工具

分库后,CRUD需要指定库名表名,部分查询场景还需要从多个表查询后聚合查询结果,需要有工具支持,可以自己写,也可以用现成的:

Sharding-JDBC(Java),EFCore.Sharding(.NET Core)

4、全局唯一ID

分库分表之后,以订单数据为例,就不能用各个表的自增列作为订单ID了,会重复,就算把自增的种子分段设置,也是有个明显缺陷的方案,所以还是需要有办法可以生成全局唯一ID,通常有

  • 基于Redis生成全局唯一ID
  • 使用雪花算法生成全局唯一ID
  • 利用数据库即时单个/批量/预先生成

思路可以参考:https://ken.io/note/id-generate-solution-snowflakex


Ken的杂谈

本文由 ken.io 创作,采用CC BY 3.0 CN协议 进行许可。 可自由转载、引用、甚至修改,但需署名作者且注明出处。

杂谈 Solution Arch

随笔目录


    © Copyright 2012-2025 Ken的杂谈

    豫ICP备10025012号

    ASP.NET Core(6.0) on Linux