<p><strong>编辑1</strong>看到您有1个虚拟核心的评论,在所有相关点上添加评论</p>
<p><strong>编辑2</strong>来自Maverick的更多信息,因此我正在消除排除的想法并开发确认的问题。</p>
<p><strong>编辑3</strong>填写了有关uwsgi请求队列和缩放选项的更多详细信息。改进了语法。</p>
<p><strong>编辑4</strong>来自Maverick和小改进的更新</p>
<p>评论太小,下面是一些想法:</p>
<ol>
<li>平均负载基本上是有多少进程正在运行或等待CPU的关注。对于具有1个CPU核的完全加载系统,平均负载应为1.0;对于4核系统,平均负载应为4.0。运行web测试的那一刻,线程启动,有很多进程在等待CPU。除非平均负载超过CPU核心的数量有很大的差距,否则不需要担心</li>
<li>4s的第一个“每次请求的时间”值与请求队列的长度相关-1000个请求几乎瞬间转储到Django上,平均需要4s服务,其中约3.4s在队列中等待。这是由于请求数(100)与处理器数(16)之间的严重不匹配导致84个请求在任何时刻等待处理器。</li>
<li><p>测试以100的并发运行,以24个请求/秒的速度运行41秒。您有16个进程(线程),因此每个请求的处理时间大约为700ms。根据您的事务类型,每个请求的时间都是<em>长</em>的。这可能是因为:</p>
<ol>
<li><strike>在Django中,每个请求的CPU开销都很高(考虑到调试工具栏中的低CPU值,这是极不可能的)</strike></li>
<li>操作系统经常进行任务切换(特别是当负载平均值高于4-8时),而延迟纯粹是因为进程太多。</li>
<li><strike>没有足够的数据库连接为16个进程提供服务,因此进程正在等待一个可用的数据库连接。每个进程至少有一个可用连接吗?</strike></li>
<li><p><strike>数据库周围有相当大的</em>延迟,或者</strike>:</p>
<ol>
<li><strike>每个请求占用数十个小请求,比如10毫秒,其中大部分是网络开销。如果是这样,您是否可以引入缓存或将SQL调用减少到较小的数目。或</strike></li>
<li><strike>一个或几个请求需要100毫秒。若要检查此问题,请在数据库上运行分析。如果是,您需要优化该请求。</strike></li>
</ol></li>
</ol></li>
<li><p>在系统中,系统和用户CPU成本的比例异常高,尽管总CPU很低。这意味着Django中的大部分工作都与内核相关,比如网络或磁盘。在这种情况下,可能是网络成本(例如接收和发送HTTP请求以及接收和发送请求到DB)。有时这会很高,因为<em>分页</em>。如果没有分页,那么您可能根本不必担心这个问题。</p></li>
<li>您已将进程设置为16,但具有高负载平均值<strike>(您没有声明的高度)</strike>。理想情况下,您应该始终至少有一个<em>进程在等待CPU(这样CPU就不会空转)。这里的进程似乎不受CPU限制,但有明显的延迟,所以您需要的进程比核心多。还有多少?尝试使用不同数量的处理器(1、2、4、8、12、16、24等)运行uwsgi,直到获得最佳吞吐量。如果更改平均进程的延迟,则需要再次调整。</li>
<li>500并发级别肯定是个问题,但它是客户机还是服务器?报告说,有50个(100个)的内容长度不正确,这意味着服务器有问题。非2xx似乎也指向那里。是否可以捕获用于调试堆栈跟踪的非2xx响应或者,特定的错误消息将非常有用</strike>(EDIT),并且是由uwsgi请求队列以默认值100运行引起的。</li>
</ol>
<p>因此,总而言之:</p>
<p><img src="https://i.stack.imgur.com/hIK9U.png" alt="enter image description here"/></p>
<ol>
<li>Django看起来不错</li>
<li>负载测试的并发性(100或500)与进程(16)之间的不匹配:您将太多并发请求推送到系统中,无法处理进程数。一旦超过进程数,将发生的所有事情就是延长web服务器中的HTTP请求队列</li>
<li><p>有很大的延迟,所以</p>
<ol>
<li><p>进程(16)和CPU核心(1)之间不匹配:如果平均负载为3,则可能是进程太多。用较少的进程重试</p>
<ol>
<li><strike>平均加载>;2->;尝试8个进程</strike></li>
<li><strike>平均加载>;4->;尝试4个进程</strike></li>
<li>平均负载>;8->;尝试2个进程</li>
</ol></li>
<li><p><strike>如果负载平均值<;3,则它可能在数据库中,因此分析数据库以查看是否有小请求负载(额外导致延迟)或一个或两个SQL语句是问题所在</strike></p></li>
</ol></li>
<li>如果不捕获失败的响应,对于500并发时的失败,我就不能说太多了</li>
</ol>
<p><strong>发展创意</strong></p>
<p>你在一台单芯机器上的平均负载是10,非常讨厌,而且(正如你观察到的)会导致很多任务切换和一般的慢行为。我个人不记得看到一台平均负载为19的机器(你有16个进程的负载)-恭喜你把它弄得这么高;)</p>
<p>数据库的性能很好,所以我现在就把它说清楚。</p>
<p><strong>分页</strong>:要回答有关如何查看分页的问题,可以通过多种方式检测操作系统分页。例如,在顶部,页眉有页进和页出(请参阅最后一行):</p>
<pre>Processes: 170 total, 3 running, 4 stuck, 163 sleeping, 927 threads 15:06:31
Load Avg: 0.90, 1.19, 1.94 CPU usage: 1.37% user, 2.97% sys, 95.65% idle SharedLibs: 144M resident, 0B data, 24M linkedit.
MemRegions: 31726 total, 2541M resident, 120M private, 817M shared. PhysMem: 1420M wired, 3548M active, 1703M inactive, 6671M used, 1514M free.
VM: 392G vsize, 1286M framework vsize, 1534241(0) pageins, 0(0) pageouts. Networks: packets: 789684/288M in, 912863/482M out. Disks: 739807/15G read, 996745/24G written.</pre>
<p><strong>进程数</strong>:在当前配置中,进程数太高。<strong>将进程数缩放回2。我们稍后可能会将此值调高,具体取决于是否将此服务器的负载进一步转移。</p>
<p><strong>Apache基准的位置</strong>:一个进程的平均负载为1.85,这表明您正在与uwsgi在同一台计算机上运行负载生成器-这是正确的吗?</p>
<p>如果是这样,您确实需要从另一台机器上运行该程序,否则测试运行就不能代表实际的负载—您将从web进程中获取内存和CPU,以便在负载生成器中使用。此外,负载生成器的100或500个线程通常会以现实生活中不会发生的方式给服务器带来压力。事实上,这可能是整个测试失败的原因。</p>
<p><strong>数据库的位置</strong>:一个进程的平均负载也表明您正在与web进程在同一台计算机上运行数据库-是否正确?</p>
<p>如果我对DB的看法是正确的,那么开始缩放的第一个也是最好的方法是将DB移到另一台机器上。我们这样做有几个原因:</p>
<ol>
<li><p>数据库服务器需要与处理节点不同的硬件配置文件:</p>
<ol>
<li>磁盘:数据库需要大量快速、冗余、备份的磁盘,而处理节点只需要一个基本磁盘</li>
<li>CPU:一个处理节点需要你能负担得起的最快的CPU,而DB机器通常可以不用(通常它的性能是在磁盘和RAM上选通的)</li>
<li>RAM:DB机器通常需要尽可能多的RAM(最快的DB在RAM中有<em>all</em>它的数据),而许多处理节点需要更少的RAM(你的每个进程需要大约20MB-非常小</li>
<li>扩展:<strong>Atomic</strong>DBs通过拥有多个CPU的大型计算机来扩展,而web层(没有状态)可以通过插入多个标识来扩展我的小盒子。</li>
</ol></li>
<li><p>CPU关联性:CPU的平均负载为1.0,进程与单个核心的关联性更好。这样做可以最大限度地使用CPU缓存,并最大限度地减少任务切换开销。通过分离DB和处理节点,您可以在HW中强制执行此关联。</p></li>
</ol>
<p><strong>500异常并发</strong>上图中的请求队列最多为100-如果uwsgi在队列满时接收到请求,请求将被拒绝,并出现5xx错误。我认为这是在500个并发负载测试中发生的——基本上,队列中填满了前100个左右的线程,然后其他400个线程发出其余900个请求,并立即收到5xx个错误。</p>
<p>要处理每秒500个请求,您需要确保以下两点:</p>
<ol>
<li>请求队列大小配置为处理突发:使用<code>--listen</code>参数来<code>uwsgi</code></li>
<li>如果500是正常情况,系统可以以每秒500个以上的请求处理吞吐量,如果500是峰值,系统可以以每秒500个以上的请求处理吞吐量。请参阅下面的缩放注释。</li>
</ol>
<p>我认为uwsgi将队列设置为一个较小的数字,以便更好地处理DDoS攻击;如果放置在巨大的负载下,大多数请求会立即失败,几乎没有处理,从而使整个框仍能对管理员作出响应。</p>
<p><strong>缩放系统的一般建议</strong></p>
<p>您最重要的考虑可能是最大化吞吐量。另一个可能的需求是最小化响应时间,但我不会在这里讨论这个问题。在最大化吞吐量时,您试图最大化<em>系统</em>,而不是单个组件;一些本地减少可能会提高整个系统的吞吐量(例如,为了提高DB</em>的性能而进行的更改会增加web层的延迟<em>,这是一种净增益)。</p>
<p>具体内容:</p>
<ol>
<li><strong>将数据库移到单独的机器上。之后,在负载测试期间通过运行<code>top</code>和您最喜欢的MySQL监视工具来分析数据库。你需要能够侧写。将DB移动到单独的机器上会给每个请求带来一些额外的延迟(几毫秒),因此希望稍微增加web层的进程数,以保持相同的吞吐量。</li>
<li>确保<code>uswgi</code>请求队列足够大,可以使用<code>--listen</code>参数处理突发通信。这应该是系统每秒可以处理的最大稳态请求数的几倍。</li>
<li><p>在web/app层:<strong>平衡进程数与CPU核数和进程固有的延迟。太多的进程会降低性能,太少的进程意味着您永远无法充分利用系统资源。没有固定的平衡点,因为每个应用程序和使用模式都是不同的,所以基准测试和调整。作为指导,如果每个任务都有:</p>
<ul>
<li>0%延迟,则每个核心需要1个进程</li>
<li>50%的延迟(即CPU时间是实际时间的一半),那么每个核心需要2个进程</li>
<li>67%的延迟,那么每个核心需要3个进程</li>
</ul></li>
<li><p>在测试期间检查<code>top</code>以确保您的cpu利用率高于90%(对于每个核心)<em>并且</em>您的平均负载略高于1.0。如果负载平均值较高,请缩减进程。如果一切顺利,在某个时候你将无法实现这一目标,而DB现在可能是瓶颈</p></li>
<li>在某种程度上,你将需要更多的权力在网络层。您可以选择向计算机添加更多的CPU(相对容易),因此添加更多的进程,<strong>和/或</strong>您可以添加更多的处理节点(水平可伸缩性)。后者可以在uwsgi中使用由<a href="https://stackoverflow.com/users/1154047/ukasz-mierzwa">Łukasz Mierzwa</a>讨论的方法来实现</li>
</ol>