小笙's Blog

后端资源常见的使用优化2018.05.19 09:56

随着服务端流量的不断递增,对底层资源的依赖也越来越重,连接数增多,IO负载高等,很多性能瓶颈由此产生。下面结合自身经验,主要谈谈DB/Redis/Mc的优化。

1.DB

DB的查询会触发磁盘IO,我们知道IO的代价是很高的,所以DB的优化主要从降低IO

a. 优化慢查询

优化慢查询主要考虑从索引入手,众所周知,Innodbs索引存储结构为B+树,真正的数据项只存在于叶子节点,所以要考虑降低树的查询长度,例如:有一表的列字段如下。

1
2
`card` varchar(10) DEFAULT NULL,
UNIQUE KEY `idx_card` (`card`),
1
explain SELECT * FROM `table` WHERE `card` = 187300;

由于SQL的隐式转换(关于隐式转换,推荐阅读Type Conversion in Expression Evaluation),这个查询并没有办法命中索引。需要类型进行对应,正确写法:

1
explain SELECT * FROM `table` WHERE `card` = '187300';

在比如COUNT,SUM,LIKE,等列运算,应尽量避免,具体结合对应的业务场景。比如:COUNT通过计数器缓存,LIKE使用最左匹配等。

b.分库分表

数据库的划分,可以按具体业务划分成不同的微服务库,这样方便单体资源的监控、扩容。例如:媒资库、用户库等等。

分表逻辑可以从两个维度考虑。一方面是水平分割,例如:常见Feed查询场景,我关注的一批(多个uid)用户的某些行为,数据表可以按照月或者天水平切分,具体的切分粒度要参考业务数据量,保证每张表的数据量都在百万行即可。

垂直切分的话,也分两个方面,一个是表列的切分,可以划分为内容表,索引表,主表,附属表等。表数据的切分要依据查询场景,例如:针对用户内容表的查询(主键查询基本内容),将uid取模hash即可。由于垂直切分写入更新时,要同时处理多张表,所以要考虑数据的一致性(原子性)。

2. Redis

a. 资源类型划分

我们知道Redis内部是已单进程的模式运行的,即每次只能执行一个redis命令,所以很容出现一种情况是,一个复杂的操作,例如:hash/set等操作导致用户进程卡住,连接没有及时释放,后续redis操作无法及时响应等等。这种情况,需要把Redis拆分成KV和复杂操作两个资源类型,KV时间复杂度为O(1),可以用于counter,kv缓存等常见场景,其他操作都放在复杂操作资源里执行。

b. 集群的使用

之所以单独说一下redis集群,是因为redis3.0之前官方并没有支持集群,集群的使用需要通过一致性Hash算法,也要考虑到节点的容灾与新增节点后相邻节点的数据同步,对业务要求比较高。也有开源的集群方案,例如:codis,twemproxy、redis cluster等。

3. MC

memcache常用于缓存临时数据,因为是内存kv,所以存储场景大多是基本content跟list数据。

对MC的优化主要集中在业务调用上,例如:DB写入后需要同步写入MC,DB更新后直接更新MC缓存,而不是删除。

另一方面,由于MC使用基于过期时间的LRU的方式淘汰内存,应该着重评估过期时间的设置,例如:设置了很多不过期(expire time为0)的数据,当逐步把内存占满后,设置过期时间的数据将很快失效,这样会导致MC命中率非常低,资源的配置、key、过期时间等应该统一管理。

最后,业务对资源的操作也应该有统一的出入口,降低资源之间的相互依赖,保证模块化的资源可用性与可扩展性。


  • 正在加载用户留言,请稍后~
点击这里取消回复

  • 请选择邮箱类型
  • @qq.com
  • @163.com
  • @sina.com
  • @126.com
  • @vip.qq.com
  • @sina.com.cn

:love: :kiss: :twist: :top: :shake: :bye: :han: :sleep: :lula: :rou: :happy: