0%

服务端后台开发笔记

一、服务端常用工具

  • 内存kv数据库: redis
  • 关系型数据库: mysql
  • 集群分布式配置: etcd

二、服务端设计

1. 常用知识

1.1. 互联网三高

  • 高可用: High availability
  • 高拓展: High scalability
  • 高性能: High efficiency
    • 低延迟(响应快): low latency
    • 高吞吐(高并发): high throughput

1.2. cap

  • 一致性
  • 可用性
  • 强一致性会破坏可用性

1.3. 一致性

  • 强一致性
  • 弱一致性
  • 最终一致性

2. 注意点

  1. 升级
    • 升级: 升级前检查脚本,升级脚本,配置备份,升级后重启,版本号修改,升级失败回退
    • 降级: 支持配置回退
    • 补丁: 考虑失败的回退,文件替换要有备份,可一键回退
    • 定制: 同补丁
    • 在线升级: 发布前最好考虑在线升级,这样出了问题可以后台出静默升级包,不需要一个一个客户去上门
  2. 配置
    • 支持升级的配置转换,并有一条路径线,尽可能支持跨多个版本升级
    • 每天备份所有重要配置,保留7天,可以及时恢复
  3. 集群
    • 集群同步列表
    • 同步后的服务重启
  4. 备份
    • 重要数据设置备份机制,和正在使用的数据分开,失败有恢复机制
  5. 安全

3. 设计干货

  • 多进程模块间使用redis做消息订阅机制进行传递消息,当一个模块变化,发送消息,所有订阅此消息的模块都可以受到消息做相应的操作
  • 进程内部可以使用event进行消息订阅机制,一个线程或者模块改了一个东西,发送消息,订阅此消息的模块根据需要相应的改动(这里操作非事务,可能出现失败的情况)
  • 后台执行命令单独提取一个进程进行,只提供接口,不允许直接拼接命令来执行,所有传入参数做防shell注入校验
  • 所有接口在一个统一的地方进行参数校验,不做逻辑校验,统一一套校验机制,不需要再模块执行中做参数合法性校验,但是复杂逻辑的还需要校验
  • 配置转换可以参照这个模式
    • 所有配置转换脚本均要执行
    • 有一个地方存放执行过哪些配置转换的脚本,执行过的不执行
    • 所有执行的脚本要分为升级和降级两个步骤,这样可以直接进行降级
  • 对所有接口加上权限,针对不同的角色,有不同的权限,增删改查
  • 利用中间件做是否认证校验,洋葱结构,中间件进入调用,出来再次调用
  • 共享内存前面预留一页4k或8k做写保护,里面可以放一些只读配置信息,防止前面踩内存导致未知问题

4. 集群形态

  • 单机不可能存在完全可靠,如果保证持续可用,需要主备集群

4.1. 主备集群

  • 为了追求数据可靠,主备数据基本一致,主挂掉,备机上阵
  • 完全一致性: 主更新数据,要求从更新完成才返回,但是增加了风险,可能从挂掉影响主运行
  • 弱一致性: 主更新数据,从节点进行异步更新数据,但是可能主从数据不一致
    • 异步请求更新数据
    • 定期同步数据

4.2. 分片集群

  • 数据分片存储在不同的数据服务器上,也叫扩容,主备集群不叫扩容
  • 但是分片集群一般会要求每个分片是一个主备集群,防止数据丢失导致整体不可用

4.3. journalnode集群

  • 强一致性
  • 使用相互的是否联通作为统计数据,一般认为联通是双方相互通信
  • 例如,存在5台机器,其中3台相互联通,认为可以对外提供服务,另外2台相互联通认为不可以提供服务

1) 为什么集群机器数量使用奇数

  • 如果存在3台,那么使用2作为可用数值,容许错误机器数为1,风险为2
  • 如果存在4台,那么使用3作为可用数值,容许错误机器数为1,风险为3
  • 使用偶数和奇数比并没有增加容许错误数,反而增加了风险

5. 提高系统性能

  • 延迟降低吞吐也会提升

5.1. 单机

1) 提高响应时间

  • 优化算法
    • 消息队列异步处理
  • 优化锁机制
  • 优化io模型
    • 异步io模型
    • 缓存
    • 热点数据多级缓存

2) 提高吞吐量

  • 增加线程处理

5.2. 集群

1) 提高响应时间

  • 参考单机

2) 提高吞吐量

  • 加机器
  • 分库分表
  • 优化集群调度
  • 增加前置负载均衡器

6. 提高系统稳定性

6.1. 几个基本点

  1. 所有外部调用需要设置超时时间,防止系统阻塞。包括http、rpc、thrift、kafka、redis、mysql、mongo等
  2. 新增加的服务需要添加兜底超时时间
  3. 连接池隔离,分级使用连接池,保障最核心业务的使用
  4. 协程使用事务,需要处理为串行执行,防止并发量大将连接池占满
  5. 使用异步请求或队列执行的,需要考虑对端处理不过来而队列满造成的接口阻塞情况

6.2. 几个问题实例

1) 协程启动事务造成数据库连接池占满,重要业务无法执行

  • 同一时刻上报大量数据需要落库,服务端处理使用协程优化速度,并且使用了事务进行批量更新
  • 由于每一个协程都使用了一个连接,事务相互之间存在竞争会卡住部分协程,造成总连接池占满,无法执行重要业务

2) 协程耗尽造成拒绝服务

  • 服务端协程数量有限,对于协程使用的不合理,造成大量协程建立并卡住,最终造成服务端没有协程可用,无法对外提供服务

3) 日志服务器性能不足卡死业务服务

  • 日志服务器处理队列满,造成业务服务器打印日志的接口阻塞,无法提供服务

4) 跨服务调用没有处理超时,造成阻塞

  • 跨服务调用,对方挂了,调用接口没有处理超时,卡死造成业务无法访问

三、实战分析

1. 优化当前系统达到高性能

1.1. 对当前业务系统进行分析(以登陆认证为例)

  1. 使用并发压力工具如 locust 进行登陆注销的大并发压力测试
  2. 过程中进行cpu和内存消耗分析,查看具体占用资源的业务进程
  3. 同时开启mysql和redis的qps统计,查看过程中的qps,分析并发登陆的mysql和redis的资源消耗情况
  4. 查看iotop的磁盘读写情况,是否存在大量io磁盘读写
  5. 单个用户上线的mysql和redis的命令执行次数
  6. 空载和大并发用户登陆后的资源消耗情况

1) 统计图对比

  1. 并发压力过程中cpu消耗图
  2. 内存占用图
  3. 磁盘io占用
  4. 网络吞吐
  5. mysql的qps
  6. redis的qps

2) 单机统计分析优化点和性能瓶颈

  1. 去除mysql、redis调用、磁盘io、cpu高计算的操作查看并发登陆用户的最大值
  2. 添加部分mysql和redis的操作查看并发登陆用户的最大值
  3. 继续添加mysql和redis草最查看并发登陆用户的最大值
  4. 增加部分io磁盘或cpu高计算的操作查看并发登陆用户的最大值
  5. 如果要分析新架构语言的场景,参考上述步骤重新测试对比
  6. 单用户登陆过程查看执行的redis和mysql语句,分析是否存在可优化的语句

3) 集群统计分析优化点和性能瓶颈

  1. 大并发场景查看主从的压力分布
  2. 仅打主节点查看
  3. 仅打从节点查看,主要用于分析主节点是否会因为某些不合理操作而资源占用高

4) 几个优化思路

  1. 配置类主要基于缓存,对可靠性要求不高就异步落盘
  2. 查询类语句调用,考虑合并优化,优选redis,次选mysql
  3. 减少不必要的调用
  4. 占用cpu高的进程,考虑是否可以降低优先级
  5. 部分mysql查询语句考虑使用redis缓存实现
  6. 下发数据尽量减少不必要的数据,只下发必要数据和增量数据等

踩坑记

1. url编码

  • url在请求时,除了规定的格式中的符号,参数中的符号必须要转码
  • 例如get请求中的参数如果有特殊字符,需要使用一个在线转码工具转码才能上传,不然服务端解析会失败

2. 备份

  • 大的逻辑改动一定要备份
  • 环境初始状态要备份