zoukankan      html  css  js  c++  java
  • 高性能MySql学习笔记第十四章:应用层优化

    1. 常见问题

    • 有一些经常会碰到的问题清单:

      • 什么东西在消耗系统中每台主机的 CPU、磁盘、网络以及内存资源?这些值是否合理?
      • 应用真的需要所有获取到的数据吗?
      • 应用在处理本应由数据库处理的事情吗?比如统计行数。
      • 应用执行了太多的查询?比如数据库服务器为多个表匹配数据做了很多优化,应用程序完全可以删除多余的嵌套循环而使用数据库的关联来代替。
      • 应用执行的查询太少了?有些情况,应用侧进行关联允许更细的粒度控制和更有效的使用缓存以及更少的锁争用。
      • 应用创建了没必要的 MySQL 链接吗?如果可以从缓存中获取数据,就不需要再访问数据库。
      • 应用对一个 MySQL 实例创建连接的次数太多了吗?通常来说更好的办法是重用相同的链接。
      • 应用做了太多的垃圾查询?
      • 应用使用了连接池吗?
      • 应用是否使用长连接?这可能导致太多连接,通常来说长连接不是很好。
      • 应用是否在不使用的时候还保持连接打开。如果是这样,可能会过多消耗其他进程所需要的连接。
    • 长连接和连接池的区别可能使人困惑。长连接和连接池可能有相同的副作用,因为重用的连接在这两种情况下都是有状态的。但是连接池通常不会导致服务器连接过多,因为它们会在进程间排队和共享连接。而长连接是在每个进程的基础上创建,不会在进程间共享。

    2. Web 服务器问题

    • Apache 服务每个进程经常使用50M 或100M 的内存。有可能出现一个占据内存很多的进程为一个很小的请求服务的情况。
    • 如果开启了 Keep-Alive 设置,进程可能很长时间出于繁忙状态。
    • 不要使用 Apache 来做静态内容服务,或者至少和动态服务使用不用的 Apache 实例。替代品有 nginx 和 lighttpd。
    • 不要让 Apache 填鸭式地服务客户端,这不仅会导致慢,也会导致 DDoS 攻击变得简单。
    • 打开 gzip 压缩。对于当代的 CPU 而言代价很小,但是可以节省大部分流量。
    • 不要为用于长距离连接的 Apache 配置启用 Keep-Alive 选项,这会使得重量级的 Apache 进程存活很长时间。可以用服务器端的代理来处理保持连接的工作,防止 Apache 被客户端拖垮。
    • 每个 Web 服务器都有一个最佳并发度——让进程处理请求尽可能快,并且不超过系统负载的最优的并发连接数。随着并发的增加,服务器会逐渐到达它的最大吞吐量。在这之后,吞吐量通常开始降低,响应时间也会因为排队而开始增加。
    • 对于 CPU 密集型工作负载,最佳并发度等于 CPU 数量。然而进程并不总数处于可运行状态,因为会有一些阻塞式的请求,比如IO、数据库查询等。因此,最佳并发度通常比 CPU 数量高一些。

    3. 缓存

    • 可以把缓存分为两大类:被动缓存和主动缓存。被动缓存除了缓存和返回数据外不做任何事情。当从被动缓存请求数据时,要么得到结果,要么得到"结果不存在"。相比之下,主动程序会在访问未命中时做一些额外的工作。通常会将请求转发给应用的其他部分来生成请求结果。涉及应用程序时,通常希望缓存是主动的。

    应用层缓存

    • 应用层缓存通常在同一台机器的内存中存储数据,或者通过网络存在另一台机器的内存中。
    • 因为应用可以缓存部分计算结果,所以应用层缓存可能比更低层次的缓存更有效。因此,应用层缓存可以节省两方面的工作:存取数据以及基于这些数据进行计算。
    • 应用层缓存的缺点是缓存命中率可能更低,并且使用较多的内存。
    • 应用层缓存有如下几种:
      • 本地缓存。本地缓存可以有效地避免对某些资源的重复请求。通常只是应用代码中的一个变量或者哈希表。
      • 本地共享内存缓存。这种缓存一般是中等大小(几个 GB),快速,难以在多台机器间同步。
      • 分布式内存缓存。最常见的分布式内存缓存的例子是 memcached。分布式缓存比本地共享内存缓存要大得多,增长也容易。分布式缓存比本地共享缓存的延时要高得多,所以最高效的使用方法是批量进行多个获取操作。
      • 磁盘上的缓存。磁盘是很慢的,所以缓存在磁盘上的最好是持久化对象,很难全部装进内存的对象,或者静态内容。

    缓存控制策略

    • TTL (time to live, 存活时间)。缓存对象设置一个过期时间,可以通过清理进程在达到过期时间后删掉对象,或者先留着直到下次访问时再清理。
    • 显式失效。如果不能接受脏数据,那么进程在更新原始数据时需要同时使缓存失效。包括:写—失效和写—更新。
    • 读时失效。在更改旧数据时,为了避免要同时失效派生出来的脏数据,可以在缓存中保存一些信息,当从缓存中读取数据时可以利用这些信息判断数据是否已经失效。一种最简单的读时失效的办法是采用对象版本控制。使用这种方法,在缓存中存储一个对象时,也可以存储对象所依赖数据的当前版本号或者时间戳,并以此判断缓存是否过期。

    缓存对象分层

    • 分层缓存对象对检索、失效和内存利用都有帮助。相对于只缓存对象,也可以缓存对象的 ID 或者 ID 组等通常需要一起检索的数据。
    • 比如电子商务网站的搜索结果列表。比起直接缓存整个列表,分别缓存搜索列表的产品 ID 和每一个 ID 对应的产品数据是一个更好的做法。这样做不会重复存放任何结果数据,也更易在失效产品的粒度上去失效缓存。
    • 但是上述做法也会有一些问题,假如使用 TTL 策略来失效搜索结果,当产品变更时显式地去失效某个单品。但是如果是一个产品的描述变化导致其不在包含搜索中匹配的关键字,但是搜索结果的缓存还没有过期失效,这时用户就会看到错误的搜索结果。

    作为基础组件的缓存

    • 认为缓存虽然很好用,但并不是重要到非有不可的东西是一种误解。应该设计一些高可用性缓存(包括数据和服务)的解决方案。

    4. MySQL 的替代品

    • 在传统的文件系统中存储文件,而不是在表中。一般的做法是:在文件系统中存储图片或其他大型二进制文件,而在 MySQL 中只存储文件名。
    • 对于某些操作——如图形关系和树遍历——关系型数据库并不总数正确的典范。MySQL 并不擅长分布式数据处理,因为它缺乏并行执行查询的能力。
  • 相关阅读:
    把一个"结构体"当做属性后碰到的问题
    执行 Application.Terminate 后, OnDestroy 中的代码还会执行
    JavaScript 演练(4). 回调函数
    给 System.Zip 增加了个(多文件解压时的)解压进度事件
    各种媒体数据以 base64 编码方式直接嵌入网页中的写法
    JavaScript 演练(3). 判断是否是数组
    JavaScript 演练(1). 定义一组常量或一组函数
    覆盖、再覆盖
    一组文件名(主要以数字命名), 我想按数字大小排序
    Enterprise Library 2.0 Hands On Lab 翻译(12):安全应用程序块(一)
  • 原文地址:https://www.cnblogs.com/lianggx6/p/15680542.html
Copyright © 2011-2022 走看看