python字符串 元组 列表 字典互转

编程语言采菊篱下 发表了文章 • 0 个评论 • 1392 次浏览 • 2015-07-27 01:27 • 来自相关话题

#1、字典
dict = {'name': 'Zara', 'age': 7, 'class': 'First'}

#字典转为字符串,返回:<type 'str'> {'age': 7, 'name': 'Zara', 'class': 'First'}
print type(str(dict)), str(dict)

#字典可以转为元组,返回:('age', 'name', 'class')
print tuple(dict)
#字典可以转为元组,返回:(7, 'Zara', 'First')
print tuple(dict.values())

#字典转为列表,返回:['age', 'name', 'class']
print list(dict)
#字典转为列表
print dict.values

#2、元组
tup=(1, 2, 3, 4, 5)

#元组转为字符串,返回:(1, 2, 3, 4, 5)
print tup.__str__()

#元组转为列表,返回:[1, 2, 3, 4, 5]
print list(tup)

#元组不可以转为字典

#3、列表
nums=[1, 3, 5, 7, 8, 13, 20];

#列表转为字符串,返回:[1, 3, 5, 7, 8, 13, 20]
print str(nums)

#列表转为元组,返回:(1, 3, 5, 7, 8, 13, 20)
print tuple(nums)

#列表不可以转为字典

#4、字符串

#字符串转为元组,返回:(1, 2, 3)
print tuple(eval("(1,2,3)"))
#字符串转为列表,返回:[1, 2, 3]
print list(eval("(1,2,3)"))
#字符串转为字典,返回:<type 'dict'>
print type(eval("{'name':'ljq', 'age':24}"))
这种方式要注意风险,因为eval实际上是解释执行python代码,如果输入来源于外部....

或者:
[quote]>> user
"{'name' : 'jim', 'sex' : 'male', 'age': 18}"
>>> exec("c="+user)
>>> c
{'age': 18, 'name': 'jim', 'sex': 'male'}[/quote]

也可以使用simplejson把JSON转化为Python内置类型
可以这样使用:
JSON到字典转化:
ret_dict = simplejson.loads(json_str)
字典到JSON转化:
json_str = simplejson.dumps(dict 查看全部
#1、字典
dict = {'name': 'Zara', 'age': 7, 'class': 'First'}

#字典转为字符串,返回:<type 'str'> {'age': 7, 'name': 'Zara', 'class': 'First'}
print type(str(dict)), str(dict)

#字典可以转为元组,返回:('age', 'name', 'class')
print tuple(dict)
#字典可以转为元组,返回:(7, 'Zara', 'First')
print tuple(dict.values())

#字典转为列表,返回:['age', 'name', 'class']
print list(dict)
#字典转为列表
print dict.values

#2、元组
tup=(1, 2, 3, 4, 5)

#元组转为字符串,返回:(1, 2, 3, 4, 5)
print tup.__str__()

#元组转为列表,返回:[1, 2, 3, 4, 5]
print list(tup)

#元组不可以转为字典

#3、列表
nums=[1, 3, 5, 7, 8, 13, 20];

#列表转为字符串,返回:[1, 3, 5, 7, 8, 13, 20]
print str(nums)

#列表转为元组,返回:(1, 3, 5, 7, 8, 13, 20)
print tuple(nums)

#列表不可以转为字典

#4、字符串

#字符串转为元组,返回:(1, 2, 3)
print tuple(eval("(1,2,3)"))
#字符串转为列表,返回:[1, 2, 3]
print list(eval("(1,2,3)"))
#字符串转为字典,返回:<type 'dict'>
print type(eval("{'name':'ljq', 'age':24}"))
这种方式要注意风险,因为eval实际上是解释执行python代码,如果输入来源于外部....

或者:
[quote]>> user
"{'name' : 'jim', 'sex' : 'male', 'age': 18}"
>>> exec("c="+user)
>>> c
{'age': 18, 'name': 'jim', 'sex': 'male'}[/quote]

也可以使用simplejson把JSON转化为Python内置类型
可以这样使用:
JSON到字典转化:
ret_dict = simplejson.loads(json_str)
字典到JSON转化:
json_str = simplejson.dumps(dict

使用线程池NGINX提高9倍性能!

运维技术采菊篱下 发表了文章 • 0 个评论 • 1001 次浏览 • 2015-07-26 00:49 • 来自相关话题

介绍

      众所周知,nginx使用异步,事件驱动的方法来处理连接。这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求。为此,NGINX工作在非阻塞的socket模式下,并使用了epool和 kqueue这样有效的方法。
 
      因为满负载进程的数量很少(通常每核CPU只有一个)而且恒定,所以任务切换只消耗很少的内存,而且不会浪费CPU周期。通过NGINX本身的实例,这种方法的优点已经为众人所知。NGINX可以非常好地处理百万级规模的并发请求。



每个进程都消耗额外的内存,而且每次进程间的切换都会消耗CPU周期并丢弃CPU高速缓存中的数据。      但是,异步、事件驱动方法仍然存在问题。或者,我喜欢将这一问题称为"恶魔",这个恶魔的名字叫阻塞(blocking)。不幸的是,很多第三方模块使用了阻塞调用,然而用户(有时甚至是模块的开发者)并不知道阻塞的缺点。阻塞操作可以毁掉NGINX的性能,我们必须不惜一切代价避免使用阻塞。
 
     即使在当前官方的NGINX代码中,依然无法在全部场景中避免使用阻塞,NGINX1.7.11中实现的线程池机制解决了这个问题。我们将在后面讲述这个线程池是什么以及该如何使用。现在,让我们先和我们的"恶魔"进行一次面对面的碰撞。

问题

      首先,为了更好地理解这一问题,我们用几句话说明下NGINX是如何工作的。
 
      通常情况下,NGINX是一个事件处理器,即一个接收来自内核的所有连接事件的信息,然后向操作系统发出做什么指令的控制器。实际上,NGINX干了编排操作系统的全部脏活累活,而操作系统做的是读取和发送字节这样的日常工作。所以,对于NGINX来说,快速和及时的响应是非常重要的。




      事件可以是超时、socket读写就绪的通知,或者发生错误的通知。NGINX接收大量的事件,然后一个接一个地处理它们,并执行必要的操作。因此,所有的处理过程是通过一个线程中的队列,在一个简单循环中完成的。NGINX从队列中取出一个事件并对其做出响应,比如读写socket。在多数情况下,这种方式是非常快的(也许只需要几个CPU周期,将一些数据复制到内存中),NGINX可以在一瞬间处理掉队列中的所有事件。




      但是,如果NGINX要处理的操作是一些又长又重的操作,又会发生什么呢?整个事件处理循环将会卡住,等待这个操作执行完毕。
 
      因此,所谓“阻塞操作”是指任何导致事件处理循环显著停止一段时间的操作。操作可以由于各种原因成为阻塞操作。例如,NGINX可能因长时间、CPU密集型处理,或者可能等待访问某个资源(比如硬盘,或者一个互斥体,亦或要从处于同步方式的数据库获得相应的库函数调用等)而繁忙。关键是在处理这样的操作期间,工作进程无法做其他事情或者处理其他事件,即使有更多的可用系统资源可以被队列中的一些事件所利用。
 
     我们来打个比方,一个商店的营业员要接待他面前排起的一长队顾客。队伍中的第一位顾客想要的某件商品不在店里而在仓库中。这位营业员跑去仓库把东西拿来。现在整个队伍必须为这样的配货方式等待数个小时,队伍中的每个人都很不爽。你可以想见人们的反应吧?队伍中每个人的等待时间都要增加这些时间,除非他们要买的东西就在店里。




      在NGINX中会发生几乎同样的情况,比如当读取一个文件的时候,如果该文件没有缓存在内存中,就要从磁盘上读取。从磁盘(特别是旋转式的磁盘)读取是很慢的,而当队列中等待的其他请求可能不需要访问磁盘时,它们也得被迫等待。导致的结果是,延迟增加并且系统资源没有得到充分利用。




      一些操作系统为读写文件提供了异步接口,NGINX可以使用这样的接口(见AIO指令)。FreeBSD就是个很好的例子。不幸的是,我们不能在Linux上得到相同的福利。虽然Linux为读取文件提供了一种异步接口,但是存在明显的缺点。其中之一是要求文件访问和缓冲要对齐,但NGINX很好地处理了这个问题。但是,另一个缺点更糟糕。异步接口要求文件描述符中要设置O_DIRECT标记,就是说任何对文件的访问都将绕过内存中的缓存,这增加了磁盘的负载。在很多场景中,这都绝对不是最佳选择。
 
      为了有针对性地解决这一问题,在NGINX 1.7.11中引入了线程池。默认情况下,NGINX+还没有包含线程池,但是如果你想试试的话,可以联系销售,NGINX+ R6是一个已经启用了线程池的构建版本。
 
      下面,让我们走进线程池,看看它是什么以及如何工作的。

线程池

      让我们回到那个可怜的,要从大老远的仓库去配货的售货员那儿。这回,他已经变聪明了(或者也许是在一群愤怒的顾客教训了一番之后,他才变得聪明的?),雇用了一个配货服务团队。现在,当任何人要买的东西在大老远的仓库时,他不再亲自去仓库了,只需要将订单丢给配货服务,他们将处理订单,同时,我们的售货员依然可以继续为其他顾客服务。因此,只有那些要买仓库里东西的顾客需要等待配货,其他顾客可以得到即时服务。




      对NGINX而言,线程池执行的就是配货服务的功能。它由一个任务队列和一组处理这个队列的线程组成。
      当工作进程需要执行一个潜在的长操作时,工作进程不再自己执行这个操作,而是将任务放到线程池队列中,任何空闲的线程都可以从队列中获取并执行这个任务。




      那么,这就像我们有了另外一个队列。是这样的,但是在这个场景中,队列受限于特殊的资源。磁盘的读取速度不能比磁盘产生数据的速度快。不管怎么说,至少现在磁盘不再延误其他事件,只有访问文件的请求需要等待。
 
      "从磁盘读取"这个操作通常是阻塞操作最常见的示例,但是实际上,NGINX中实现的线程池可用于处理任何不适合在主循环中执行的任务。
 
      目前,卸载到线程池中执行的两个基本操作是大多数操作系统中的read()系统调用和Linux中的sendfile()。接下来,我们将对线程池进行测试(test)和基准测试(benchmark),在未来的版本中,如果有明显的优势,我们可能会卸载其他操作到线程池中。

基准测试

      现在让我们从理论过度到实践。我们将进行一次模拟基准测试(synthetic benchmark),模拟在阻塞操作和非阻塞操作的最差混合条件下,使用线程池的效果。
 
      另外,我们需要一个内存肯定放不下的数据集。在一台48GB内存的机器上,我们已经产生了每文件大小为4MB的随机数据,总共256GB,然后配置NGINX,版本为1.9.0。
      配置很简单,如下所示:worker_processes 16;

events {
accept_mutex off;
}

http {
include mime.types;
default_type application/octet-stream;

access_log off;
sendfile on;
sendfile_max_chunk 512k;

server {
listen 8000;

location / {
root /storage;
}
}
}      如上所示,为了达到更好的性能,我们调整了几个参数:禁用了logging和accept_mutex,同时,启用了sendfile并设置了sendfile_max_chunk的大小。最后一个指令可以减少阻塞调用sendfile()所花费的最长时间,因为NGINX不会尝试一次将整个文件发送出去,而是每次发送大小为512KB的块数据。
 
      这台测试服务器有2个Intel Xeon E5645处理器(共计:12核、24超线程)和10-Gbps的网络接口。磁盘子系统是由4块西部数据WD1003FBYX 磁盘组成的RAID10阵列。所有这些硬件由Ubuntu服务器14.04.1 LTS供电。




      客户端有2台服务器,它们的规格相同。在其中一台上,在wrk中使用Lua脚本创建了负载程序。脚本使用200个并行连接向服务器请求文件,每个请求都可能未命中缓存而从磁盘阻塞读取。我们将这种负载称作随机负载。
 
      在另一台客户端机器上,我们将运行wrk的另一个副本,使用50个并行连接多次请求同一个文件。因为这个文件将被频繁地访问,所以它会一直驻留在内存中。在正常情况下,NGINX能够非常快速地服务这些请求,但是如果工作进程被其他请求阻塞的话,性能将会下降。我们将这种负载称作恒定负载。
 
      性能将由服务器上ifstat监测的吞吐率(throughput)和从第二台客户端获取的wrk结果来度量。
 
      现在,第一次运行没有线程池将不会我们非常激动人心的结果:% ifstat -bi eth2
eth2
Kbps in Kbps out
5531.24 1.03e+06
4855.23 812922.7
5994.66 1.07e+06
5476.27 981529.3
6353.62 1.12e+06
5166.17 892770.3
5522.81 978540.8
6208.10 985466.7
6370.79 1.12e+06
6123.33 1.07e+06      如上所示,使用这种配置,服务器产生的总流量约为1Gbps。从下面所示的top输出,我们可以看到,工作进程的大部分时间花在阻塞I/O上(它们处于top的D状态):top - 10:40:47 up 11 days, 1:32, 1 user, load average: 49.61, 45.77 62.89
Tasks: 375 total, 2 running, 373 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.3 sy, 0.0 ni, 67.7 id, 31.9 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 49453440 total, 49149308 used, 304132 free, 98780 buffers
KiB Swap: 10474236 total, 20124 used, 10454112 free, 46903412 cached Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4639 vbart 20 0 47180 28152 496 D 0.7 0.1 0:00.17 nginx
4632 vbart 20 0 47180 28196 536 D 0.3 0.1 0:00.11 nginx
4633 vbart 20 0 47180 28324 540 D 0.3 0.1 0:00.11 nginx
4635 vbart 20 0 47180 28136 480 D 0.3 0.1 0:00.12 nginx
4636 vbart 20 0 47180 28208 536 D 0.3 0.1 0:00.14 nginx
4637 vbart 20 0 47180 28208 536 D 0.3 0.1 0:00.10 nginx
4638 vbart 20 0 47180 28204 536 D 0.3 0.1 0:00.12 nginx
4640 vbart 20 0 47180 28324 540 D 0.3 0.1 0:00.13 nginx
4641 vbart 20 0 47180 28324 540 D 0.3 0.1 0:00.13 nginx
4642 vbart 20 0 47180 28208 536 D 0.3 0.1 0:00.11 nginx
4643 vbart 20 0 47180 28276 536 D 0.3 0.1 0:00.29 nginx
4644 vbart 20 0 47180 28204 536 D 0.3 0.1 0:00.11 nginx
4645 vbart 20 0 47180 28204 536 D 0.3 0.1 0:00.17 nginx
4646 vbart 20 0 47180 28204 536 D 0.3 0.1 0:00.12 nginx
4647 vbart 20 0 47180 28208 532 D 0.3 0.1 0:00.17 nginx
4631 vbart 20 0 47180 756 252 S 0.0 0.1 0:00.00 nginx
4634 vbart 20 0 47180 28208 536 D 0.0 0.1 0:00.11 nginx
4648 vbart 20 0 25232 1956 1160 R 0.0 0.0 0:00.08 top
25921 vbart 20 0 121956 2232 1056 S 0.0 0.0 0:01.97 sshd
25923 vbart 20 0 40304 4160 2208 S 0.0 0.0 0:00.53 zsh      在这种情况下,吞吐率受限于磁盘子系统,而CPU在大部分时间里是空闲的。从wrk获得的结果也非常低:Running 1m test @ http://192.0.2.1:8000/1/1/1
12 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 7.42s 5.31s 24.41s 74.73%
Req/Sec 0.15 0.36 1.00 84.62%
488 requests in 1.01m, 2.01GB read
Requests/sec: 8.08
Transfer/sec: 34.07MB      请记住,文件是从内存送达的!第一个客户端的200个连接创建的随机负载,使服务器端的全部的工作进程忙于从磁盘读取文件,因此产生了过大的延迟,并且无法在合理的时间内处理我们的请求。
      现在,我们的线程池要登场了。为此,我们只需在location块中添加aio threads指令:location / {
root /storage;
aio threads;
}      接着,执行NGINX reload重新加载配置。
      然后,我们重复上述的测试:% ifstat -bi eth2
eth2
Kbps in Kbps out
60915.19 9.51e+06
59978.89 9.51e+06
60122.38 9.51e+06
61179.06 9.51e+06
61798.40 9.51e+06
57072.97 9.50e+06
56072.61 9.51e+06
61279.63 9.51e+06
61243.54 9.51e+06
59632.50 9.50e+06      现在,我们的服务器产生的流量是9.5Gbps,相比之下,没有使用线程池时只有约1Gbps!

      理论上还可以产生更多的流量,但是这已经达到了机器的最大网络吞吐能力,所以在这次NGINX的测试中,NGINX受限于网络接口。工作进程的大部分时间只是休眠和等待新的事件(它们处于top的S状态):top - 10:43:17 up 11 days, 1:35, 1 user, load average: 172.71, 93.84, 77.90
Tasks: 376 total, 1 running, 375 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.2 us, 1.2 sy, 0.0 ni, 34.8 id, 61.5 wa, 0.0 hi, 2.3 si, 0.0 st
KiB Mem: 49453440 total, 49096836 used, 356604 free, 97236 buffers
KiB Swap: 10474236 total, 22860 used, 10451376 free, 46836580 cached Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4654 vbart 20 0 309708 28844 596 S 9.0 0.1 0:08.65 nginx
4660 vbart 20 0 309748 28920 596 S 6.6 0.1 0:14.82 nginx
4658 vbart 20 0 309452 28424 520 S 4.3 0.1 0:01.40 nginx
4663 vbart 20 0 309452 28476 572 S 4.3 0.1 0:01.32 nginx
4667 vbart 20 0 309584 28712 588 S 3.7 0.1 0:05.19 nginx
4656 vbart 20 0 309452 28476 572 S 3.3 0.1 0:01.84 nginx
4664 vbart 20 0 309452 28428 524 S 3.3 0.1 0:01.29 nginx
4652 vbart 20 0 309452 28476 572 S 3.0 0.1 0:01.46 nginx
4662 vbart 20 0 309552 28700 596 S 2.7 0.1 0:05.92 nginx
4661 vbart 20 0 309464 28636 596 S 2.3 0.1 0:01.59 nginx
4653 vbart 20 0 309452 28476 572 S 1.7 0.1 0:01.70 nginx
4666 vbart 20 0 309452 28428 524 S 1.3 0.1 0:01.63 nginx
4657 vbart 20 0 309584 28696 592 S 1.0 0.1 0:00.64 nginx
4655 vbart 20 0 30958 28476 572 S 0.7 0.1 0:02.81 nginx
4659 vbart 20 0 309452 28468 564 S 0.3 0.1 0:01.20 nginx
4665 vbart 20 0 309452 28476 572 S 0.3 0.1 0:00.71 nginx
5180 vbart 20 0 25232 1952 1156 R 0.0 0.0 0:00.45 top
4651 vbart 20 0 20032 752 252 S 0.0 0.0 0:00.00 nginx
25921 vbart 20 0 121956 2176 1000 S 0.0 0.0 0:01.98 sshd
25923 vbart 20 0 40304 3840 2208 S 0.0 0.0 0:00.54 zsh      如上所示,基准测试中还有大量的CPU资源剩余。
      wrk的结果如下:Running 1m test @ http://192.0.2.1:8000/1/1/1
12 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 226.32ms 392.76ms 1.72s 93.48%
Req/Sec 20.02 10.84 59.00 65.91%
15045 requests in 1.00m, 58.86GB read
Requests/sec: 250.57
Transfer/sec: 0.98GB      服务器处理4MB文件的平均时间从7.42秒降到226.32毫秒(减少了33倍),每秒请求处理数提升了31倍(250 vs 8)!

       对此,我们的解释是请求不再因为工作进程被阻塞在读文件,而滞留在事件队列中,等待处理,它们可以被空闲的进程处理掉。只要磁盘子系统能做到最好,就能服务好第一个客户端上的随机负载,NGINX可以使用剩余的CPU资源和网络容量,从内存中读取,以服务于上述的第二个客户端的请求。

仍然没有灵丹妙药

      在抛出我们对阻塞操作的担忧并给出一些令人振奋的结果后,可能大部分人已经打算在你的服务器上配置线程池了。先别着急。

      实际上,最幸运的情况是,读取和发送文件操作不去处理缓慢的硬盘驱动器。如果我们有足够多的内存来存储数据集,那么操作系统将会足够聪明地在被称作“页面缓存”的地方,缓存频繁使用的文件。

      "页面缓存"的效果很好,可以让NGINX在几乎所有常见的用例中展示优异的性能。从页面缓存中读取比较快,没有人会说这种操作是“阻塞”。而另一方面,卸载任务到一个线程池是有一定开销的。

      因此,如果内存有合理的大小并且待处理的数据集不是很大的话,那么无需使用线程池,NGINX已经工作在最优化的方式下。

      卸载读操作到线程池是一种适用于非常特殊任务的技术。只有当经常请求的内容的大小,不适合操作系统的虚拟机缓存时,这种技术才是最有用的。至于可能适用的场景,比如,基于NGINX的高负载流媒体服务器。这正是我们已经模拟的基准测试的场景。

      我们如果可以改进卸载读操作到线程池,将会非常有意义。我们只需要知道所需的文件数据是否在内存中,只有不在内存中时,读操作才应该卸载到一个单独的线程中。

      再回到售货员那个比喻的场景中,这回,售货员不知道要买的商品是否在店里,他必须要么总是将所有的订单提交给配货服务,要么总是亲自处理它们。
   
      人艰不拆,操作系统缺少这样的功能。第一次尝试是在2010年,人们试图将这一功能添加到Linux作为fincore()系统调用,但是没有成功。后来还有一些尝试,是使用RWF_NONBLOCK标记作为preadv2()系统调用来实现这一功能(详情见LWN.net上的非阻塞缓冲文件读取操作和异步缓冲读操作)。但所有这些补丁的命运目前还不明朗。悲催的是,这些补丁尚没有被内核接受的主要原因,貌似是因为旷日持久的撕逼大战(bikeshedding)。
 
      另一方面,FreeBSD的用户完全不必担心。FreeBSD已经具备足够好的异步读取文件接口,我们应该用这个接口而不是线程池。

配置线程池

       所以,如果你确信在你的场景中使用线程池可以带来好处,那么现在是时候深入了解线程池的配置了。

      线程池的配置非常简单、灵活。首先,获取NGINX 1.7.11或更高版本的源代码,使用--with-threads配置参数编译。在最简单的场景中,配置看起来很朴实。我们只需要在http、 server,或者location上下文中包含aio threads指令即可:# in the 'http', 'server', or 'location' context
aio threads;      这是线程池的最简配置。实际上的精简版本示例如下:# in the 'main' context
thread_pool default threads=32 max_queue=65536;

# in the 'http', 'server', or 'location' context
aio threads=default;      这里定义了一个名为"default",包含32个线程,任务队列最多支持65536个请求的线程池。如果任务队列过载,NGINX将输出如下错误日志并拒绝请求:thread pool "NAME" queue overflow: N tasks waiting      错误输出意味着线程处理作业的速度有可能低于任务入队的速度了。你可以尝试增加队列的最大值,但是如果这无济于事,那么这说明你的系统没有能力处理如此多的请求了。

      正如你已经注意到的,你可以使用thread_pool指令,配置线程的数量、队列的最大值,以及线程池的名称。最后要说明的是,可以配置多个独立的线程池,将它们置于不同的配置文件中,用做不同的目的:# in the 'main' context
thread_pool one threads=128 max_queue=0;
thread_pool two threads=32;

http {
server {
location /one {
aio threads=one;
}

location /two {
aio threads=two;
}

}

}      如果没有指定max_queue参数的值,默认使用的值是65536。如上所示,可以设置max_queue为0。在这种情况下,线程池将使用配置中全部数量的线程,尽可能地同时处理多个任务;队列中不会有等待的任务。

      现在,假设我们有一台服务器,挂了3块硬盘,我们希望把该服务器用作“缓存代理”,缓存后端服务器的全部响应信息。预期的缓存数据量远大于可用的内存。它实际上是我们个人CDN的一个缓存节点。毫无疑问,在这种情况下,最重要的事情是发挥硬盘的最大性能。

      我们的选择之一是配置一个RAID阵列。这种方法毁誉参半,现在,有了NGINX,我们可以有其他的选择:# 我们假设每块硬盘挂载在相应的目录中:/mnt/disk1、/mnt/disk2、/mnt/disk3

proxy_cache_path /mnt/disk1 levels=1:2 keys_zone=cache_1:256m max_size=1024G
use_temp_path=off;
proxy_cache_path /mnt/disk2 levels=1:2 keys_zone=cache_2:256m max_size=1024G
use_temp_path=off;
proxy_cache_path /mnt/disk3 levels=1:2 keys_zone=cache_3:256m max_size=1024G
use_temp_path=off;

thread_pool pool_1 threads=16;
thread_pool pool_2 threads=16;
thread_pool pool_3 threads=16;

split_clients $request_uri $disk {
33.3% 1;
33.3% 2;
* 3;
}

location / {
proxy_pass http://backend;
proxy_cache_key $request_uri;
proxy_cache cache_$disk;
aio threads=pool_$disk;
sendfile on;
}      在这份配置中,使用了3个独立的缓存,每个缓存专用一块硬盘,另外,3个独立的线程池也各自专用一块硬盘。

      缓存之间(其结果就是磁盘之间)的负载均衡使用split_clients模块,split_clients非常适用于这个任务。

      在 proxy_cache_path指令中设置use_temp_path=off,表示NGINX会将临时文件保存在缓存数据的同一目录中。这是为了避免在更新缓存时,磁盘之间互相复制响应数据。

      这些调优将带给我们磁盘子系统的最大性能,因为NGINX通过单独的线程池并行且独立地与每块磁盘交互。每块磁盘由16个独立线程和读取和发送文件专用任务队列提供服务。

      我敢打赌,你的客户喜欢这种量身定制的方法。请确保你的磁盘也持有同样的观点。

      这个示例很好地证明了NGINX可以为硬件专门调优的灵活性。这就像你给NGINX下了一道命令,让机器和数据用最佳姿势来搞基。而且,通过NGINX在用户空间中细粒度的调优,我们可以确保软件、操作系统和硬件工作在最优模式下,尽可能有效地利用系统资源。

结论

      综上所述,线程池是一个伟大的功能,将NGINX推向了新的性能水平,除掉了一个众所周知的长期危害——阻塞——尤其是当我们真正面对大量内容的时候。

      甚至,还有更多的惊喜。正如前面提到的,这个全新的接口,有可能没有任何性能损失地卸载任何长期阻塞操作。NGINX在拥有大量的新模块和新功能方面,开辟了一方新天地。许多流行的库仍然没有提供异步非阻塞接口,此前,这使得它们无法与NGINX兼容。我们可以花大量的时间和资源,去开发我们自己的无阻塞原型库,但这么做始终都是值得的吗?现在,有了线程池,我们可以相对容易地使用这些库,而不会影响这些模块的性能。
原英文地址:Thread Pools in NGINX Boost Performance 9x! 查看全部


介绍


      众所周知,nginx使用异步,事件驱动的方法来处理连接。这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求。为此,NGINX工作在非阻塞的socket模式下,并使用了epoolkqueue这样有效的方法。
 
      因为满负载进程的数量很少(通常每核CPU只有一个)而且恒定,所以任务切换只消耗很少的内存,而且不会浪费CPU周期。通过NGINX本身的实例,这种方法的优点已经为众人所知。NGINX可以非常好地处理百万级规模的并发请求。
k1.png
 每个进程都消耗额外的内存,而且每次进程间的切换都会消耗CPU周期并丢弃CPU高速缓存中的数据。
      但是,异步、事件驱动方法仍然存在问题。或者,我喜欢将这一问题称为"恶魔",这个恶魔的名字叫阻塞(blocking)。不幸的是,很多第三方模块使用了阻塞调用,然而用户(有时甚至是模块的开发者)并不知道阻塞的缺点。阻塞操作可以毁掉NGINX的性能,我们必须不惜一切代价避免使用阻塞。
 
     即使在当前官方的NGINX代码中,依然无法在全部场景中避免使用阻塞,NGINX1.7.11中实现的线程池机制解决了这个问题。我们将在后面讲述这个线程池是什么以及该如何使用。现在,让我们先和我们的"恶魔"进行一次面对面的碰撞。


问题


      首先,为了更好地理解这一问题,我们用几句话说明下NGINX是如何工作的。
 
      通常情况下,NGINX是一个事件处理器,即一个接收来自内核的所有连接事件的信息,然后向操作系统发出做什么指令的控制器。实际上,NGINX干了编排操作系统的全部脏活累活,而操作系统做的是读取和发送字节这样的日常工作。所以,对于NGINX来说,快速和及时的响应是非常重要的。
k2.png

      事件可以是超时、socket读写就绪的通知,或者发生错误的通知。NGINX接收大量的事件,然后一个接一个地处理它们,并执行必要的操作。因此,所有的处理过程是通过一个线程中的队列,在一个简单循环中完成的。NGINX从队列中取出一个事件并对其做出响应,比如读写socket。在多数情况下,这种方式是非常快的(也许只需要几个CPU周期,将一些数据复制到内存中),NGINX可以在一瞬间处理掉队列中的所有事件。
k3.png

      但是,如果NGINX要处理的操作是一些又长又重的操作,又会发生什么呢?整个事件处理循环将会卡住,等待这个操作执行完毕。
 
      因此,所谓“阻塞操作”是指任何导致事件处理循环显著停止一段时间的操作。操作可以由于各种原因成为阻塞操作。例如,NGINX可能因长时间、CPU密集型处理,或者可能等待访问某个资源(比如硬盘,或者一个互斥体,亦或要从处于同步方式的数据库获得相应的库函数调用等)而繁忙。关键是在处理这样的操作期间,工作进程无法做其他事情或者处理其他事件,即使有更多的可用系统资源可以被队列中的一些事件所利用。
 
     我们来打个比方,一个商店的营业员要接待他面前排起的一长队顾客。队伍中的第一位顾客想要的某件商品不在店里而在仓库中。这位营业员跑去仓库把东西拿来。现在整个队伍必须为这样的配货方式等待数个小时,队伍中的每个人都很不爽。你可以想见人们的反应吧?队伍中每个人的等待时间都要增加这些时间,除非他们要买的东西就在店里。
k4.png

      在NGINX中会发生几乎同样的情况,比如当读取一个文件的时候,如果该文件没有缓存在内存中,就要从磁盘上读取。从磁盘(特别是旋转式的磁盘)读取是很慢的,而当队列中等待的其他请求可能不需要访问磁盘时,它们也得被迫等待。导致的结果是,延迟增加并且系统资源没有得到充分利用。
k5.png

      一些操作系统为读写文件提供了异步接口,NGINX可以使用这样的接口(见AIO指令)。FreeBSD就是个很好的例子。不幸的是,我们不能在Linux上得到相同的福利。虽然Linux为读取文件提供了一种异步接口,但是存在明显的缺点。其中之一是要求文件访问和缓冲要对齐,但NGINX很好地处理了这个问题。但是,另一个缺点更糟糕。异步接口要求文件描述符中要设置O_DIRECT标记,就是说任何对文件的访问都将绕过内存中的缓存,这增加了磁盘的负载。在很多场景中,这都绝对不是最佳选择。
 
      为了有针对性地解决这一问题,在NGINX 1.7.11中引入了线程池。默认情况下,NGINX+还没有包含线程池,但是如果你想试试的话,可以联系销售,NGINX+ R6是一个已经启用了线程池的构建版本。
 
      下面,让我们走进线程池,看看它是什么以及如何工作的。


线程池


      让我们回到那个可怜的,要从大老远的仓库去配货的售货员那儿。这回,他已经变聪明了(或者也许是在一群愤怒的顾客教训了一番之后,他才变得聪明的?),雇用了一个配货服务团队。现在,当任何人要买的东西在大老远的仓库时,他不再亲自去仓库了,只需要将订单丢给配货服务,他们将处理订单,同时,我们的售货员依然可以继续为其他顾客服务。因此,只有那些要买仓库里东西的顾客需要等待配货,其他顾客可以得到即时服务。
k6.png

      对NGINX而言,线程池执行的就是配货服务的功能。它由一个任务队列和一组处理这个队列的线程组成。
      当工作进程需要执行一个潜在的长操作时,工作进程不再自己执行这个操作,而是将任务放到线程池队列中,任何空闲的线程都可以从队列中获取并执行这个任务。
k7.png

      那么,这就像我们有了另外一个队列。是这样的,但是在这个场景中,队列受限于特殊的资源。磁盘的读取速度不能比磁盘产生数据的速度快。不管怎么说,至少现在磁盘不再延误其他事件,只有访问文件的请求需要等待。
 
      "从磁盘读取"这个操作通常是阻塞操作最常见的示例,但是实际上,NGINX中实现的线程池可用于处理任何不适合在主循环中执行的任务。
 
      目前,卸载到线程池中执行的两个基本操作是大多数操作系统中的read()系统调用和Linux中的sendfile()。接下来,我们将对线程池进行测试(test)和基准测试(benchmark),在未来的版本中,如果有明显的优势,我们可能会卸载其他操作到线程池中。


基准测试


      现在让我们从理论过度到实践。我们将进行一次模拟基准测试(synthetic benchmark),模拟在阻塞操作和非阻塞操作的最差混合条件下,使用线程池的效果。
 
      另外,我们需要一个内存肯定放不下的数据集。在一台48GB内存的机器上,我们已经产生了每文件大小为4MB的随机数据,总共256GB,然后配置NGINX,版本为1.9.0。
      配置很简单,如下所示:
worker_processes 16;

events {
accept_mutex off;
}

http {
include mime.types;
default_type application/octet-stream;

access_log off;
sendfile on;
sendfile_max_chunk 512k;

server {
listen 8000;

location / {
root /storage;
}
}
}
      如上所示,为了达到更好的性能,我们调整了几个参数:禁用了loggingaccept_mutex,同时,启用了sendfile并设置了sendfile_max_chunk的大小。最后一个指令可以减少阻塞调用sendfile()所花费的最长时间,因为NGINX不会尝试一次将整个文件发送出去,而是每次发送大小为512KB的块数据。
 
      这台测试服务器有2个Intel Xeon E5645处理器(共计:12核、24超线程)和10-Gbps的网络接口。磁盘子系统是由4块西部数据WD1003FBYX 磁盘组成的RAID10阵列。所有这些硬件由Ubuntu服务器14.04.1 LTS供电。
k8.png

      客户端有2台服务器,它们的规格相同。在其中一台上,在wrk中使用Lua脚本创建了负载程序。脚本使用200个并行连接向服务器请求文件,每个请求都可能未命中缓存而从磁盘阻塞读取。我们将这种负载称作随机负载。
 
      在另一台客户端机器上,我们将运行wrk的另一个副本,使用50个并行连接多次请求同一个文件。因为这个文件将被频繁地访问,所以它会一直驻留在内存中。在正常情况下,NGINX能够非常快速地服务这些请求,但是如果工作进程被其他请求阻塞的话,性能将会下降。我们将这种负载称作恒定负载。
 
      性能将由服务器上ifstat监测的吞吐率(throughput)和从第二台客户端获取的wrk结果来度量。
 
      现在,第一次运行没有线程池将不会我们非常激动人心的结果:
% ifstat -bi eth2
eth2
Kbps in Kbps out
5531.24 1.03e+06
4855.23 812922.7
5994.66 1.07e+06
5476.27 981529.3
6353.62 1.12e+06
5166.17 892770.3
5522.81 978540.8
6208.10 985466.7
6370.79 1.12e+06
6123.33 1.07e+06
      如上所示,使用这种配置,服务器产生的总流量约为1Gbps。从下面所示的top输出,我们可以看到,工作进程的大部分时间花在阻塞I/O上(它们处于top的D状态):
top - 10:40:47 up 11 days,  1:32,  1 user,  load average: 49.61, 45.77 62.89
Tasks: 375 total, 2 running, 373 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.3 sy, 0.0 ni, 67.7 id, 31.9 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 49453440 total, 49149308 used, 304132 free, 98780 buffers
KiB Swap: 10474236 total, 20124 used, 10454112 free, 46903412 cached Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4639 vbart 20 0 47180 28152 496 D 0.7 0.1 0:00.17 nginx
4632 vbart 20 0 47180 28196 536 D 0.3 0.1 0:00.11 nginx
4633 vbart 20 0 47180 28324 540 D 0.3 0.1 0:00.11 nginx
4635 vbart 20 0 47180 28136 480 D 0.3 0.1 0:00.12 nginx
4636 vbart 20 0 47180 28208 536 D 0.3 0.1 0:00.14 nginx
4637 vbart 20 0 47180 28208 536 D 0.3 0.1 0:00.10 nginx
4638 vbart 20 0 47180 28204 536 D 0.3 0.1 0:00.12 nginx
4640 vbart 20 0 47180 28324 540 D 0.3 0.1 0:00.13 nginx
4641 vbart 20 0 47180 28324 540 D 0.3 0.1 0:00.13 nginx
4642 vbart 20 0 47180 28208 536 D 0.3 0.1 0:00.11 nginx
4643 vbart 20 0 47180 28276 536 D 0.3 0.1 0:00.29 nginx
4644 vbart 20 0 47180 28204 536 D 0.3 0.1 0:00.11 nginx
4645 vbart 20 0 47180 28204 536 D 0.3 0.1 0:00.17 nginx
4646 vbart 20 0 47180 28204 536 D 0.3 0.1 0:00.12 nginx
4647 vbart 20 0 47180 28208 532 D 0.3 0.1 0:00.17 nginx
4631 vbart 20 0 47180 756 252 S 0.0 0.1 0:00.00 nginx
4634 vbart 20 0 47180 28208 536 D 0.0 0.1 0:00.11 nginx
4648 vbart 20 0 25232 1956 1160 R 0.0 0.0 0:00.08 top
25921 vbart 20 0 121956 2232 1056 S 0.0 0.0 0:01.97 sshd
25923 vbart 20 0 40304 4160 2208 S 0.0 0.0 0:00.53 zsh
      在这种情况下,吞吐率受限于磁盘子系统,而CPU在大部分时间里是空闲的。从wrk获得的结果也非常低:
Running 1m test @ http://192.0.2.1:8000/1/1/1
12 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 7.42s 5.31s 24.41s 74.73%
Req/Sec 0.15 0.36 1.00 84.62%
488 requests in 1.01m, 2.01GB read
Requests/sec: 8.08
Transfer/sec: 34.07MB
      请记住,文件是从内存送达的!第一个客户端的200个连接创建的随机负载,使服务器端的全部的工作进程忙于从磁盘读取文件,因此产生了过大的延迟,并且无法在合理的时间内处理我们的请求。
      现在,我们的线程池要登场了。为此,我们只需在location块中添加aio threads指令:
location / {
root /storage;
aio threads;
}
      接着,执行NGINX reload重新加载配置。
      然后,我们重复上述的测试:
% ifstat -bi eth2
eth2
Kbps in Kbps out
60915.19 9.51e+06
59978.89 9.51e+06
60122.38 9.51e+06
61179.06 9.51e+06
61798.40 9.51e+06
57072.97 9.50e+06
56072.61 9.51e+06
61279.63 9.51e+06
61243.54 9.51e+06
59632.50 9.50e+06
      现在,我们的服务器产生的流量是9.5Gbps,相比之下,没有使用线程池时只有约1Gbps!

      理论上还可以产生更多的流量,但是这已经达到了机器的最大网络吞吐能力,所以在这次NGINX的测试中,NGINX受限于网络接口。工作进程的大部分时间只是休眠和等待新的事件(它们处于topS状态):
top - 10:43:17 up 11 days,  1:35,  1 user,  load average: 172.71, 93.84, 77.90
Tasks: 376 total, 1 running, 375 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.2 us, 1.2 sy, 0.0 ni, 34.8 id, 61.5 wa, 0.0 hi, 2.3 si, 0.0 st
KiB Mem: 49453440 total, 49096836 used, 356604 free, 97236 buffers
KiB Swap: 10474236 total, 22860 used, 10451376 free, 46836580 cached Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4654 vbart 20 0 309708 28844 596 S 9.0 0.1 0:08.65 nginx
4660 vbart 20 0 309748 28920 596 S 6.6 0.1 0:14.82 nginx
4658 vbart 20 0 309452 28424 520 S 4.3 0.1 0:01.40 nginx
4663 vbart 20 0 309452 28476 572 S 4.3 0.1 0:01.32 nginx
4667 vbart 20 0 309584 28712 588 S 3.7 0.1 0:05.19 nginx
4656 vbart 20 0 309452 28476 572 S 3.3 0.1 0:01.84 nginx
4664 vbart 20 0 309452 28428 524 S 3.3 0.1 0:01.29 nginx
4652 vbart 20 0 309452 28476 572 S 3.0 0.1 0:01.46 nginx
4662 vbart 20 0 309552 28700 596 S 2.7 0.1 0:05.92 nginx
4661 vbart 20 0 309464 28636 596 S 2.3 0.1 0:01.59 nginx
4653 vbart 20 0 309452 28476 572 S 1.7 0.1 0:01.70 nginx
4666 vbart 20 0 309452 28428 524 S 1.3 0.1 0:01.63 nginx
4657 vbart 20 0 309584 28696 592 S 1.0 0.1 0:00.64 nginx
4655 vbart 20 0 30958 28476 572 S 0.7 0.1 0:02.81 nginx
4659 vbart 20 0 309452 28468 564 S 0.3 0.1 0:01.20 nginx
4665 vbart 20 0 309452 28476 572 S 0.3 0.1 0:00.71 nginx
5180 vbart 20 0 25232 1952 1156 R 0.0 0.0 0:00.45 top
4651 vbart 20 0 20032 752 252 S 0.0 0.0 0:00.00 nginx
25921 vbart 20 0 121956 2176 1000 S 0.0 0.0 0:01.98 sshd
25923 vbart 20 0 40304 3840 2208 S 0.0 0.0 0:00.54 zsh
      如上所示,基准测试中还有大量的CPU资源剩余。
      wrk的结果如下:
Running 1m test @ http://192.0.2.1:8000/1/1/1
12 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 226.32ms 392.76ms 1.72s 93.48%
Req/Sec 20.02 10.84 59.00 65.91%
15045 requests in 1.00m, 58.86GB read
Requests/sec: 250.57
Transfer/sec: 0.98GB
      服务器处理4MB文件的平均时间从7.42秒降到226.32毫秒(减少了33倍),每秒请求处理数提升了31倍(250 vs 8)!

       对此,我们的解释是请求不再因为工作进程被阻塞在读文件,而滞留在事件队列中,等待处理,它们可以被空闲的进程处理掉。只要磁盘子系统能做到最好,就能服务好第一个客户端上的随机负载,NGINX可以使用剩余的CPU资源和网络容量,从内存中读取,以服务于上述的第二个客户端的请求。


仍然没有灵丹妙药


      在抛出我们对阻塞操作的担忧并给出一些令人振奋的结果后,可能大部分人已经打算在你的服务器上配置线程池了。先别着急。

      实际上,最幸运的情况是,读取和发送文件操作不去处理缓慢的硬盘驱动器。如果我们有足够多的内存来存储数据集,那么操作系统将会足够聪明地在被称作“页面缓存”的地方,缓存频繁使用的文件。

      "页面缓存"的效果很好,可以让NGINX在几乎所有常见的用例中展示优异的性能。从页面缓存中读取比较快,没有人会说这种操作是“阻塞”。而另一方面,卸载任务到一个线程池是有一定开销的。

      因此,如果内存有合理的大小并且待处理的数据集不是很大的话,那么无需使用线程池,NGINX已经工作在最优化的方式下。

      卸载读操作到线程池是一种适用于非常特殊任务的技术。只有当经常请求的内容的大小,不适合操作系统的虚拟机缓存时,这种技术才是最有用的。至于可能适用的场景,比如,基于NGINX的高负载流媒体服务器。这正是我们已经模拟的基准测试的场景。

      我们如果可以改进卸载读操作到线程池,将会非常有意义。我们只需要知道所需的文件数据是否在内存中,只有不在内存中时,读操作才应该卸载到一个单独的线程中。

      再回到售货员那个比喻的场景中,这回,售货员不知道要买的商品是否在店里,他必须要么总是将所有的订单提交给配货服务,要么总是亲自处理它们。
   
      人艰不拆,操作系统缺少这样的功能。第一次尝试是在2010年,人们试图将这一功能添加到Linux作为fincore()系统调用,但是没有成功。后来还有一些尝试,是使用RWF_NONBLOCK标记作为preadv2()系统调用来实现这一功能(详情见LWN.net上的非阻塞缓冲文件读取操作异步缓冲读操作)。但所有这些补丁的命运目前还不明朗。悲催的是,这些补丁尚没有被内核接受的主要原因,貌似是因为旷日持久的撕逼大战(bikeshedding)。
 
      另一方面,FreeBSD的用户完全不必担心。FreeBSD已经具备足够好的异步读取文件接口,我们应该用这个接口而不是线程池。


配置线程池


       所以,如果你确信在你的场景中使用线程池可以带来好处,那么现在是时候深入了解线程池的配置了。

      线程池的配置非常简单、灵活。首先,获取NGINX 1.7.11或更高版本的源代码,使用--with-threads配置参数编译。在最简单的场景中,配置看起来很朴实。我们只需要在http、 server,或者location上下文中包含aio threads指令即可:
# in the 'http', 'server', or 'location' context
aio threads;
      这是线程池的最简配置。实际上的精简版本示例如下:
# in the 'main' context
thread_pool default threads=32 max_queue=65536;

# in the 'http', 'server', or 'location' context
aio threads=default;
      这里定义了一个名为"default",包含32个线程,任务队列最多支持65536个请求的线程池。如果任务队列过载,NGINX将输出如下错误日志并拒绝请求:
thread pool "NAME" queue overflow: N tasks waiting
      错误输出意味着线程处理作业的速度有可能低于任务入队的速度了。你可以尝试增加队列的最大值,但是如果这无济于事,那么这说明你的系统没有能力处理如此多的请求了。

      正如你已经注意到的,你可以使用thread_pool指令,配置线程的数量、队列的最大值,以及线程池的名称。最后要说明的是,可以配置多个独立的线程池,将它们置于不同的配置文件中,用做不同的目的:
# in the 'main' context
thread_pool one threads=128 max_queue=0;
thread_pool two threads=32;

http {
server {
location /one {
aio threads=one;
}

location /two {
aio threads=two;
}

}

}
      如果没有指定max_queue参数的值,默认使用的值是65536。如上所示,可以设置max_queue为0。在这种情况下,线程池将使用配置中全部数量的线程,尽可能地同时处理多个任务;队列中不会有等待的任务。

      现在,假设我们有一台服务器,挂了3块硬盘,我们希望把该服务器用作“缓存代理”,缓存后端服务器的全部响应信息。预期的缓存数据量远大于可用的内存。它实际上是我们个人CDN的一个缓存节点。毫无疑问,在这种情况下,最重要的事情是发挥硬盘的最大性能。

      我们的选择之一是配置一个RAID阵列。这种方法毁誉参半,现在,有了NGINX,我们可以有其他的选择:
# 我们假设每块硬盘挂载在相应的目录中:/mnt/disk1、/mnt/disk2、/mnt/disk3

proxy_cache_path /mnt/disk1 levels=1:2 keys_zone=cache_1:256m max_size=1024G
use_temp_path=off;
proxy_cache_path /mnt/disk2 levels=1:2 keys_zone=cache_2:256m max_size=1024G
use_temp_path=off;
proxy_cache_path /mnt/disk3 levels=1:2 keys_zone=cache_3:256m max_size=1024G
use_temp_path=off;

thread_pool pool_1 threads=16;
thread_pool pool_2 threads=16;
thread_pool pool_3 threads=16;

split_clients $request_uri $disk {
33.3% 1;
33.3% 2;
* 3;
}

location / {
proxy_pass http://backend;
proxy_cache_key $request_uri;
proxy_cache cache_$disk;
aio threads=pool_$disk;
sendfile on;
}
      在这份配置中,使用了3个独立的缓存,每个缓存专用一块硬盘,另外,3个独立的线程池也各自专用一块硬盘。

      缓存之间(其结果就是磁盘之间)的负载均衡使用split_clients模块,split_clients非常适用于这个任务。

      在 proxy_cache_path指令中设置use_temp_path=off,表示NGINX会将临时文件保存在缓存数据的同一目录中。这是为了避免在更新缓存时,磁盘之间互相复制响应数据。

      这些调优将带给我们磁盘子系统的最大性能,因为NGINX通过单独的线程池并行且独立地与每块磁盘交互。每块磁盘由16个独立线程和读取和发送文件专用任务队列提供服务。

      我敢打赌,你的客户喜欢这种量身定制的方法。请确保你的磁盘也持有同样的观点。

      这个示例很好地证明了NGINX可以为硬件专门调优的灵活性。这就像你给NGINX下了一道命令,让机器和数据用最佳姿势来搞基。而且,通过NGINX在用户空间中细粒度的调优,我们可以确保软件、操作系统和硬件工作在最优模式下,尽可能有效地利用系统资源。


结论


      综上所述,线程池是一个伟大的功能,将NGINX推向了新的性能水平,除掉了一个众所周知的长期危害——阻塞——尤其是当我们真正面对大量内容的时候。

      甚至,还有更多的惊喜。正如前面提到的,这个全新的接口,有可能没有任何性能损失地卸载任何长期阻塞操作。NGINX在拥有大量的新模块和新功能方面,开辟了一方新天地。许多流行的库仍然没有提供异步非阻塞接口,此前,这使得它们无法与NGINX兼容。我们可以花大量的时间和资源,去开发我们自己的无阻塞原型库,但这么做始终都是值得的吗?现在,有了线程池,我们可以相对容易地使用这些库,而不会影响这些模块的性能。
原英文地址:Thread Pools in NGINX Boost Performance 9x!

虚拟机是怎么实现的?

大数据/云计算OpenSkill 发表了文章 • 0 个评论 • 696 次浏览 • 2015-07-25 21:55 • 来自相关话题

      1997年,斯坦福的Mendel Rosenblum带着Edouard Bugnion, Scott Devine在SOSP上发了篇论文,叫做Disco: running commodity operating systems on scalable multiprocessors (http://www.stanford.edu/class/cs240/readings/disco.pdf)。发了之后,我想他们应该是觉得这个主意太好了,就开了家公司,名叫VMWare。
 
      这篇论文起名叫Disco(迪士高)是因为虚拟机本身不是一个新的东西,大概在上世纪70年代就有了。作者们为了表示敬意,或者是显示这是一个复古的东西,就把这个项目取名为disco。这篇论文介绍了虚拟机关键技术,用来回答这个问题再合适不过了。(多年之后,OSDI上的另一篇论文(Memory Resource Management in VMware ESX Server)介绍了一些VMWare的改进。近年来论文越来越多。)
 
      当初他们为什么要做虚拟机?简单说就是,新硬件层出不穷,但是OS赶不上。当初,他们想在Stanford的ccNUMA机器上跑IRIX(一个操作系统)。可是IRIX跑不起来。他们觉得修改OS或者写一个新的OS太难了(因为一个操作系统从出生到成熟要很长的时间,无数BUG要FIX,无数的新功能要增加。。。那样人家博士要怎么毕业。。)。所以,他们决定用虚拟机。
 
      对于他们的项目,虚拟机大致有下面这些好处:1、只要对商业OS做简单地修改,就能让他们在多个VM(Virtual Machine)间共享内存。
2、Flexible。除了论文里的IRIX,实际上其他的OS也能跑。
3、扩展性好。系统可以以虚拟机为单位扩展。
4、fault-containment。每一个VM都是一个几乎独立的个体,一个坏了,不影响另一个。
5、新老软件可共存。比如,新的软件只能在Linux-3.15跑。你可以用两个VM,一个是Linux2.6,一个是Linux-3.15。      这篇文章回答下面这几个实现虚拟技术的关键问题:1、VMM(Virtual Machine Monitor, 或者叫hypervisor)是怎么管住Guest OS的?或者说,皇上(VMM)是怎么防止大臣(OS)夺权的?
2、有那么多个操作系统一起运行,内存是怎么管理的?
3、多个VM之间是怎么分享资源的?或者说,1GB内存怎么当2GB用?

VMM(Virtual Machine Monitor, 或者叫hypervisor)是怎么管住Guest OS的?或者说,皇上(VMM)是怎么防止大臣(OS)夺权的?





      要理解VMM是怎么工作的,我们得先了解没有VMM的时候,系统是怎么工作的。在没有VMM的时候,计算机系统中的”应用”可分为用户进程(比如VIM)和操作系统。他们分别运行在不同的模式中(mode)。我们用一个类比来解释系统中的模式(mode)。模式这个机制是用来限制一段指令所在的环境的权限的,它是需要处理器的支持的。MIPS结构当时有三个模式:用户模式(user mode),长官模式(supervisor mode,原谅我的翻译…)和内核模式(kernel mode)。这三种模式分别对应于人类社会里的民宅、官衙和金銮殿。显而易见,在金銮殿里的人拥有的权限最高,民宅里的最低。我们可以说,在没有VMM时,用户进程住在民宅里,县衙空着,OS住在金銮殿里(如图)。用户可以直接做一些不用什么特权的事情(unprivileged instructions),比如计算1+1。做这些事情不经过OS。但是,有些要特权才能做的事情,一定要经过OS。比如保存正在编辑的文档到硬盘。访问硬盘是特权操作是因为硬盘是共享的资源,要有人管着,不能让人乱来。试想,要是人人都能读写档案馆的档案,那不就乱套了。




      VIM(用户进程)不能直接写磁盘上的文件。VIM必须请求在金銮殿里的操作系统来做。怎么请求呢?通过系统调用(system call)。系统调用的过程是这样的:比如要调用的是write(fd, buf, len, off),首先把fd, buf, len, off放到stack里,然后再把一个write()函数对应的号码(system call number)放到stack里,最后调用一个特殊的指令使CPU进入内核模式(图中的圈1)。在x86结构中,这个指令是int(中断)。在MIPS结构中,这个指令是trap。这个指令会引导CPU执行一段代码(trap handler),依照stack里的system call number 找到对应的函数(在这里是write()的实现),然后调用这个函数(函数的参数在刚才的stack里)。在这里函数里,操作系统调用文件所在的文件系统里的write()实现,文件系统使用磁盘的驱动来最终实现。所以文件的操作完成后,操作系统调用与trap功能相反的一个指令,回到VIM程序的指令里(图中的圈2)。




      操作系统维护自己的特权的过程大概就是这样。但是这个特权等级到底是怎么实现的呢?我们可以想像CPU里有一个特权状态(privileged state bit)。状态为开(On)的时候,CPU的特权等级高,你可以做任何事,包括转到低特权状态。关(Off)的时候,你所能做的事情就所限了。那怎么从off状态转到on状态呢?你必须到执行CPU的特殊指令,这个指令会把你带到一个特定的地方执行操作系统的指令,检查你是不是有进入高特权状态的权限。这就像是在机场,你可以很容易地从登机口到售票大厅,可是你要从售票大厅到登机口,你就得过安检。另外,为什么操作系统就能有高特权呢?Hmm…因为操作系统一开始就把那占了,之后运行的应用程序就只能听它使唤了。
 
      现在,终于要说VMM(virtual machine monitor, 或者叫hypervisor)是怎么实现的了。如下图:




      现在VMM进了金銮殿,有了最高的特权。操作系统被放到了官衙里(但是它自己并不知道)。用户进程还是在民宅里住着。比如,现在用户进程VIM调用write(),会发生什么?用户进程会trap到VMM(拥有kernel mode)里去。但是,VMM并不知道如何处理write()。所以,VMM接下来会调用OS的里对应的trap handler,这个handler会执行文件系统的write(),然后用驱动来写磁盘。这一切的操作都在VMM的监视下进行。怎么监视?操作系统实际上是在虚拟CPU(Virtual CPU)上运行的。VCPU有一套自己的(假的)寄存器。VMM盯着这些寄存器。在操作系统的trap handler完成之后,它会调用trap的反操作(想返回user mode)。但是,这个操作实际上回使CPU回到VMM,由VMM最后返回到用户进程。
 
      为什么VMM能够知道操作系统的trap handler在哪?系统中先有VMM。当你在VMM上安装操作系统的时候,操作系统会尝试调用特权指令安装trap handler。因为有最高特权的VMM实际上是监视着这一切的,所以它可以记录下trap handler的位置就行了。
 
      总的说来,虚拟机占据了CPU的最高特权,使得在更低特权等级的操作系统无法进行有害操作。

有那么多个操作系统一起运行,内存是怎么管理的?

      在没有VMM的时候,系统中有两种内存地址:虚拟地址(virtual address)和物理地址(physical address)。从虚拟地址到物理地址的转换有两种方式。方式一:在TLB(translate lookside buffer,硬件实现)查找。方式二:在页表(page table)中查找,找到之后把结果放到TLB中去。系统会先尝试方式一,要是找不到(TLB miss),就用方式二。




      在有了VMM之后,系统中有三种内存地址:虚拟地址(virtual address),物理地址(physical address)和机器地址(machine address)。机器地址才是真正与内存条上的地址一一对应的。物理地址只是操作系统认为的物理地址。




      当操作系统试着要使用特权指令来完成一个虚拟地址到物理地址的转换时(TLB miss),VMM就介入了(VMM监视着所有对特权寄存器的操作)。VMM会先使用操作系统内的代码来先完成虚拟地址到物理地址的转化(因为VMM并不知道这个映射关系)。然后,操作系统认为自己已经完成了转化,尝试去更新TLB(特权操作)。这个时候,VMM会介入,用一个叫个pmap的映射表找到物理地址对应的机器地址,用机器地址替换掉物理地址,然后把TLB更新为虚拟地址到机器地址的映射。之后,所有对这个虚拟地址的访问都会被转换为对相应机器地址的访问。

多个VM之间是怎么分享资源的?或者说,1GB内存怎么当2GB用?

      我们知道,每一个虚拟机都要占用大量的内存空间。在内存有限的情况下,怎么在一台机器运行更多的虚拟机?幸运的是,不用的虚拟机之间在内存中数据可能会完全一致(比如,系统文件在内存中的缓存)。如要我们可以只在内存中保留一份数据,我们就行节省很多空间。Disco使用虚拟IO设备和虚拟网络设备来节省内存空间。




虚拟IO设备:当两个虚拟机从同一个磁盘上读同一个文件时,VMM会intercept DMA,然后就会发现这两个VM在使用同样的数据。这份数据只需要在机器内存里保存一份,然后修改pmap,使得两个VM的物理地址指向同一个机器地址就可以了。当任何一个VM更新这份数据,VMM会给它一份新的拷贝,原来的那份不做更改(copy on write机制)。虚拟网络设备:当使用NFS从VM1向VM2复制文件时,文件并没有被真正地复制。虚拟网络设备会更新VM2上的pmap,使之指向在内存中的文件,使得VM2上的操作系统认为自己已经有了这个文件。后来,VMWare还有用hash来找相同的内存页然后再共享的技术。
原文地址 查看全部
      1997年,斯坦福的Mendel Rosenblum带着Edouard Bugnion, Scott Devine在SOSP上发了篇论文,叫做Disco: running commodity operating systems on scalable multiprocessors (http://www.stanford.edu/class/cs240/readings/disco.pdf)。发了之后,我想他们应该是觉得这个主意太好了,就开了家公司,名叫VMWare。
 
      这篇论文起名叫Disco(迪士高)是因为虚拟机本身不是一个新的东西,大概在上世纪70年代就有了。作者们为了表示敬意,或者是显示这是一个复古的东西,就把这个项目取名为disco。这篇论文介绍了虚拟机关键技术,用来回答这个问题再合适不过了。(多年之后,OSDI上的另一篇论文(Memory Resource Management in VMware ESX Server)介绍了一些VMWare的改进。近年来论文越来越多。)
 
      当初他们为什么要做虚拟机?简单说就是,新硬件层出不穷,但是OS赶不上。当初,他们想在Stanford的ccNUMA机器上跑IRIX(一个操作系统)。可是IRIX跑不起来。他们觉得修改OS或者写一个新的OS太难了(因为一个操作系统从出生到成熟要很长的时间,无数BUG要FIX,无数的新功能要增加。。。那样人家博士要怎么毕业。。)。所以,他们决定用虚拟机。
 
      对于他们的项目,虚拟机大致有下面这些好处:
1、只要对商业OS做简单地修改,就能让他们在多个VM(Virtual Machine)间共享内存。
2、Flexible。除了论文里的IRIX,实际上其他的OS也能跑。
3、扩展性好。系统可以以虚拟机为单位扩展。
4、fault-containment。每一个VM都是一个几乎独立的个体,一个坏了,不影响另一个。
5、新老软件可共存。比如,新的软件只能在Linux-3.15跑。你可以用两个VM,一个是Linux2.6,一个是Linux-3.15。
      这篇文章回答下面这几个实现虚拟技术的关键问题:
1、VMM(Virtual Machine Monitor, 或者叫hypervisor)是怎么管住Guest OS的?或者说,皇上(VMM)是怎么防止大臣(OS)夺权的?
2、有那么多个操作系统一起运行,内存是怎么管理的?
3、多个VM之间是怎么分享资源的?或者说,1GB内存怎么当2GB用?


VMM(Virtual Machine Monitor, 或者叫hypervisor)是怎么管住Guest OS的?或者说,皇上(VMM)是怎么防止大臣(OS)夺权的?


k1.png

      要理解VMM是怎么工作的,我们得先了解没有VMM的时候,系统是怎么工作的。在没有VMM的时候,计算机系统中的”应用”可分为用户进程(比如VIM)和操作系统。他们分别运行在不同的模式中(mode)。我们用一个类比来解释系统中的模式(mode)。模式这个机制是用来限制一段指令所在的环境的权限的,它是需要处理器的支持的。MIPS结构当时有三个模式:用户模式(user mode),长官模式(supervisor mode,原谅我的翻译…)和内核模式(kernel mode)。这三种模式分别对应于人类社会里的民宅、官衙和金銮殿。显而易见,在金銮殿里的人拥有的权限最高,民宅里的最低。我们可以说,在没有VMM时,用户进程住在民宅里,县衙空着,OS住在金銮殿里(如图)。用户可以直接做一些不用什么特权的事情(unprivileged instructions),比如计算1+1。做这些事情不经过OS。但是,有些要特权才能做的事情,一定要经过OS。比如保存正在编辑的文档到硬盘。访问硬盘是特权操作是因为硬盘是共享的资源,要有人管着,不能让人乱来。试想,要是人人都能读写档案馆的档案,那不就乱套了。
k2.png

      VIM(用户进程)不能直接写磁盘上的文件。VIM必须请求在金銮殿里的操作系统来做。怎么请求呢?通过系统调用(system call)。系统调用的过程是这样的:比如要调用的是write(fd, buf, len, off),首先把fd, buf, len, off放到stack里,然后再把一个write()函数对应的号码(system call number)放到stack里,最后调用一个特殊的指令使CPU进入内核模式(图中的圈1)。在x86结构中,这个指令是int(中断)。在MIPS结构中,这个指令是trap。这个指令会引导CPU执行一段代码(trap handler),依照stack里的system call number 找到对应的函数(在这里是write()的实现),然后调用这个函数(函数的参数在刚才的stack里)。在这里函数里,操作系统调用文件所在的文件系统里的write()实现,文件系统使用磁盘的驱动来最终实现。所以文件的操作完成后,操作系统调用与trap功能相反的一个指令,回到VIM程序的指令里(图中的圈2)。
k3.png

      操作系统维护自己的特权的过程大概就是这样。但是这个特权等级到底是怎么实现的呢?我们可以想像CPU里有一个特权状态(privileged state bit)。状态为开(On)的时候,CPU的特权等级高,你可以做任何事,包括转到低特权状态。关(Off)的时候,你所能做的事情就所限了。那怎么从off状态转到on状态呢?你必须到执行CPU的特殊指令,这个指令会把你带到一个特定的地方执行操作系统的指令,检查你是不是有进入高特权状态的权限。这就像是在机场,你可以很容易地从登机口到售票大厅,可是你要从售票大厅到登机口,你就得过安检。另外,为什么操作系统就能有高特权呢?Hmm…因为操作系统一开始就把那占了,之后运行的应用程序就只能听它使唤了。
 
      现在,终于要说VMM(virtual machine monitor, 或者叫hypervisor)是怎么实现的了。如下图:
k4.png

      现在VMM进了金銮殿,有了最高的特权。操作系统被放到了官衙里(但是它自己并不知道)。用户进程还是在民宅里住着。比如,现在用户进程VIM调用write(),会发生什么?用户进程会trap到VMM(拥有kernel mode)里去。但是,VMM并不知道如何处理write()。所以,VMM接下来会调用OS的里对应的trap handler,这个handler会执行文件系统的write(),然后用驱动来写磁盘。这一切的操作都在VMM的监视下进行。怎么监视?操作系统实际上是在虚拟CPU(Virtual CPU)上运行的。VCPU有一套自己的(假的)寄存器。VMM盯着这些寄存器。在操作系统的trap handler完成之后,它会调用trap的反操作(想返回user mode)。但是,这个操作实际上回使CPU回到VMM,由VMM最后返回到用户进程。
 
      为什么VMM能够知道操作系统的trap handler在哪?系统中先有VMM。当你在VMM上安装操作系统的时候,操作系统会尝试调用特权指令安装trap handler。因为有最高特权的VMM实际上是监视着这一切的,所以它可以记录下trap handler的位置就行了。
 
      总的说来,虚拟机占据了CPU的最高特权,使得在更低特权等级的操作系统无法进行有害操作。


有那么多个操作系统一起运行,内存是怎么管理的?


      在没有VMM的时候,系统中有两种内存地址:虚拟地址(virtual address)和物理地址(physical address)。从虚拟地址到物理地址的转换有两种方式。方式一:在TLB(translate lookside buffer,硬件实现)查找。方式二:在页表(page table)中查找,找到之后把结果放到TLB中去。系统会先尝试方式一,要是找不到(TLB miss),就用方式二。
k5.png

      在有了VMM之后,系统中有三种内存地址:虚拟地址(virtual address),物理地址(physical address)和机器地址(machine address)。机器地址才是真正与内存条上的地址一一对应的。物理地址只是操作系统认为的物理地址。
k6.png

      当操作系统试着要使用特权指令来完成一个虚拟地址到物理地址的转换时(TLB miss),VMM就介入了(VMM监视着所有对特权寄存器的操作)。VMM会先使用操作系统内的代码来先完成虚拟地址到物理地址的转化(因为VMM并不知道这个映射关系)。然后,操作系统认为自己已经完成了转化,尝试去更新TLB(特权操作)。这个时候,VMM会介入,用一个叫个pmap的映射表找到物理地址对应的机器地址,用机器地址替换掉物理地址,然后把TLB更新为虚拟地址到机器地址的映射。之后,所有对这个虚拟地址的访问都会被转换为对相应机器地址的访问。


多个VM之间是怎么分享资源的?或者说,1GB内存怎么当2GB用?


      我们知道,每一个虚拟机都要占用大量的内存空间。在内存有限的情况下,怎么在一台机器运行更多的虚拟机?幸运的是,不用的虚拟机之间在内存中数据可能会完全一致(比如,系统文件在内存中的缓存)。如要我们可以只在内存中保留一份数据,我们就行节省很多空间。Disco使用虚拟IO设备和虚拟网络设备来节省内存空间。
k7.png

虚拟IO设备:
当两个虚拟机从同一个磁盘上读同一个文件时,VMM会intercept DMA,然后就会发现这两个VM在使用同样的数据。这份数据只需要在机器内存里保存一份,然后修改pmap,使得两个VM的物理地址指向同一个机器地址就可以了。当任何一个VM更新这份数据,VMM会给它一份新的拷贝,原来的那份不做更改(copy on write机制)。
虚拟网络设备:
当使用NFS从VM1向VM2复制文件时,文件并没有被真正地复制。虚拟网络设备会更新VM2上的pmap,使之指向在内存中的文件,使得VM2上的操作系统认为自己已经有了这个文件。
后来,VMWare还有用hash来找相同的内存页然后再共享的技术。
原文地址

优雅操作python字典

编程语言Ansible 发表了文章 • 0 个评论 • 736 次浏览 • 2015-07-25 18:20 • 来自相关话题

Python 中的字典是Python中一个键值映射的数据结构,下面介绍一下如何优雅的操作字典.

创建字典

Python有两种方法可以创建字典,第一种是使用花括号,另一种是使用内建 函数dict>>> info = {}
[quote]>> info = dict()

初始化字典

Python可以在创建字典的时候初始化字典>>> info = {"name" : 'cool'}
>>> info = dict(name = 'cool') # 更优雅很明显第二种方法更加的优雅和减少一些特殊字符的输入,但是有种情况第二种不能胜任>>> key = 'name'
>>> info = { key :'cool'} # {'name':'cool'}
>>> info = dict(key = 'cool') # {'key': 'cool'}明显第二种方法就会引发一个不容易找到的bug
 
Python字典还有一种初始化方式,就是使用字典的fromkeys方法可以从列表中获取元素作为键并用None或fromkeys方法的第二个参数初始化>>> info = {}.fromkeys(['name', 'blog'])
>>> info
{'blog': None, 'name': None}
>>> info = dict().fromkeys(['name', 'blog'])
>>> info
{'blog': None, 'name': None}
>>> info = dict().fromkeys(['name', 'blog'], 'afewbug.com')
>>> info
{'blog': 'afewbug.com', 'name': 'afewbug.com'}

优雅的获取键值

字典可以这样获取到键的值>>> info = {'name':'cool', 'blog':'afewbug.com'}
>>> info['name']
'cool'但是如果获取不存在的键的值就会触发的一个KeyError异常,字典有一个get方法,可以使用字典get方法更加优雅的获取字典>>> info = dict(name= 'cool', blog='afewbug.com')
>>> info.get('name')
'cool'
>>> info.get('blogname')
None
>>> info.get('blogname', 'afewbug')
'afewbug'
我们看到使用get方法获取不存在的键值的时候不会触发异常,同时get方法接收两个参数,当不存在该键的时候就会返回第二个参数  我们可以看到使用get更加的优雅

更新/添加

Python 字典可以使用键作为索引来访问/更新/添加值>>> info = dict()
>>> info['name'] = 'cool'
>>> info['blog'] = 'afewbug.com'
>>> info
{'blog': 'afewbug.com', 'name': 'cool'}
>>> info['name'] = 'cool night'
>>> info
{'blog': 'afewbug.com', 'name': 'cool night'}同时Python字典的update方法也可以更新和添加字典>>> info = dict(name='cool', blog='afewbug.com')
>>> info.update({'name':'cool night', 'blogname':'afewbug'})
>>> info
{'blog': 'afewbug.com', 'name': 'cool night', 'blogname': 'afewbug'}
>>> info.update(name='cool', blog='www.afewbug.com') # 更优雅
>>> info
{'blog': 'www.afewbug.com', 'name': 'cool', 'blogname': 'afewbug'}Python字典的update方法可以使用一个字典来更新字典,也可以使用参数传递类似dict函数一样的方式更新一个字典,上面代码中哦功能的第二个更加优雅,但是同样和dict函数类似,键是变量时也只取字面值

字典删除

可以调用Python内置关键字del来删除一个键值>>> info = dict(name='cool', blog='afewbug.com')
>>> info
{'blog': 'afewbug.com', 'name': 'cool'}
>>> del info['name']
>>> info
{'blog': 'afewbug.com'}同时也可以使用字典的pop方法来取出一个键值,并删除>>> info = dict(name='cool', blog='afewbug.com')
>>> info.pop('name')
'cool'
>>> info
{'blog': 'afewbug.com'}

其他操作

获取所有key>>> info = dict(name='cool', blog='afewbug.com')
>>> info.keys()
['blog', 'name']获取key,value并循环>>> info = dict(name='cool', blog='afewbug.com')
>>> for key, value in info.items():
... print key, ':', value
...
blog : afewbug.com
name : cool
[/quote] 查看全部
ipython.png
Python 中的字典是Python中一个键值映射的数据结构,下面介绍一下如何优雅的操作字典.


创建字典


Python有两种方法可以创建字典,第一种是使用花括号,另一种是使用内建 函数dict
>>> info = {}
[quote]>> info = dict()


初始化字典


Python可以在创建字典的时候初始化字典
>>> info = {"name" : 'cool'}
>>> info = dict(name = 'cool') # 更优雅
很明显第二种方法更加的优雅和减少一些特殊字符的输入,但是有种情况第二种不能胜任
>>> key = 'name'
>>> info = { key :'cool'} # {'name':'cool'}
>>> info = dict(key = 'cool') # {'key': 'cool'}
明显第二种方法就会引发一个不容易找到的bug
 
Python字典还有一种初始化方式,就是使用字典的fromkeys方法可以从列表中获取元素作为键并用None或fromkeys方法的第二个参数初始化
>>> info = {}.fromkeys(['name', 'blog'])
>>> info
{'blog': None, 'name': None}
>>> info = dict().fromkeys(['name', 'blog'])
>>> info
{'blog': None, 'name': None}
>>> info = dict().fromkeys(['name', 'blog'], 'afewbug.com')
>>> info
{'blog': 'afewbug.com', 'name': 'afewbug.com'}


优雅的获取键值


字典可以这样获取到键的值
>>> info = {'name':'cool', 'blog':'afewbug.com'}
>>> info['name']
'cool'
但是如果获取不存在的键的值就会触发的一个KeyError异常,字典有一个get方法,可以使用字典get方法更加优雅的获取字典
>>> info = dict(name= 'cool', blog='afewbug.com')
>>> info.get('name')
'cool'
>>> info.get('blogname')
None
>>> info.get('blogname', 'afewbug')
'afewbug'

我们看到使用get方法获取不存在的键值的时候不会触发异常,同时get方法接收两个参数,当不存在该键的时候就会返回第二个参数  我们可以看到使用get更加的优雅


更新/添加


Python 字典可以使用键作为索引来访问/更新/添加值
>>> info = dict()
>>> info['name'] = 'cool'
>>> info['blog'] = 'afewbug.com'
>>> info
{'blog': 'afewbug.com', 'name': 'cool'}
>>> info['name'] = 'cool night'
>>> info
{'blog': 'afewbug.com', 'name': 'cool night'}
同时Python字典的update方法也可以更新和添加字典
>>> info = dict(name='cool', blog='afewbug.com')
>>> info.update({'name':'cool night', 'blogname':'afewbug'})
>>> info
{'blog': 'afewbug.com', 'name': 'cool night', 'blogname': 'afewbug'}
>>> info.update(name='cool', blog='www.afewbug.com') # 更优雅
>>> info
{'blog': 'www.afewbug.com', 'name': 'cool', 'blogname': 'afewbug'}
Python字典的update方法可以使用一个字典来更新字典,也可以使用参数传递类似dict函数一样的方式更新一个字典,上面代码中哦功能的第二个更加优雅,但是同样和dict函数类似,键是变量时也只取字面值


字典删除


可以调用Python内置关键字del来删除一个键值
>>> info = dict(name='cool', blog='afewbug.com')
>>> info
{'blog': 'afewbug.com', 'name': 'cool'}
>>> del info['name']
>>> info
{'blog': 'afewbug.com'}
同时也可以使用字典的pop方法来取出一个键值,并删除
>>> info = dict(name='cool', blog='afewbug.com')
>>> info.pop('name')
'cool'
>>> info
{'blog': 'afewbug.com'}


其他操作


获取所有key
>>> info = dict(name='cool', blog='afewbug.com')
>>> info.keys()
['blog', 'name']
获取key,value并循环
>>> info = dict(name='cool', blog='afewbug.com')
>>> for key, value in info.items():
... print key, ':', value
...
blog : afewbug.com
name : cool
[/quote]

为什么运行docker命令返回"/var/run/docker.sock"权限拒绝?

大数据/云计算Ansible 发表了文章 • 0 个评论 • 1331 次浏览 • 2015-07-24 00:51 • 来自相关话题

/var/run/docker.sock: permission denied

# docker ps
FATA[0000] Get http:///var/run/docker.sock/v1.16/containers/json:
dial unix /var/run/docker.sock: permission denied.
Are you trying to connect to a TLS-enabled daemon without TLS?      首先你得确认/var/run/docker.sock文件是否存在# ls -l /var/run/docker.sock
srw-rw---- 1 root docker 0 sty 28 11:53 /var/run/docker.sock      解决方案现在很清楚了,通过添加你的登陆用户到docker用户组来解决这个问题,如下所示:# sudo gpasswd -a ${USER} docker      /etc/group文件内容应该可以看出变化了# cat /etc/group | grep ^docker      下面我们打开一个新的终端来检查登陆用户是否加入到了docker用户组,应该存在于如下命令结果中# groups      如果你的登陆用户还没有加入到docker用户组,你可以尝试重启机器。如果你可以正常重启docker容器,就不需要重启服务器了。# sudo service docker.io restart然后你运行docker ps应该就没有问题了! 查看全部
idocker.png


/var/run/docker.sock: permission denied


# docker ps
FATA[0000] Get http:///var/run/docker.sock/v1.16/containers/json:
dial unix /var/run/docker.sock: permission denied.
Are you trying to connect to a TLS-enabled daemon without TLS?
      首先你得确认/var/run/docker.sock文件是否存在
# ls -l /var/run/docker.sock
srw-rw---- 1 root docker 0 sty 28 11:53 /var/run/docker.sock
      解决方案现在很清楚了,通过添加你的登陆用户到docker用户组来解决这个问题,如下所示:
# sudo gpasswd -a ${USER} docker
      /etc/group文件内容应该可以看出变化了
# cat /etc/group | grep ^docker
      下面我们打开一个新的终端来检查登陆用户是否加入到了docker用户组,应该存在于如下命令结果中
# groups
      如果你的登陆用户还没有加入到docker用户组,你可以尝试重启机器。如果你可以正常重启docker容器,就不需要重启服务器了。
# sudo service docker.io restart
然后你运行docker ps应该就没有问题了!

logstash一个坑

回复

运维技术采菊篱下 发起了问题 • 1 人关注 • 0 个回复 • 1287 次浏览 • 2015-07-23 21:54 • 来自相关话题

一次被劫持挂马经历--Elasticsearch的远程执行漏洞

大数据/云计算OpenSkill 发表了文章 • 0 个评论 • 657 次浏览 • 2015-07-22 19:11 • 来自相关话题

起因:

           公司使用的是Ucloud的云主机服务,今天上午突然被告知有一台服务器的出口流量激增,对外发包量短时间内达到了100万,而且都是UDP类型的,第一感觉就是:诶呀,莫不是被黑了,被当肉鸡了呀!

探究:

           立马登录对应的服务器,首先使用iftop查看流量状况








           可以看出出口流量好吓人,1分钟内累计700M流量,查了一下这2个IP地址,一个是在美国,一个是在浙江电信;赶紧查看正在运行的进程,找出疑似进程,还真有所发现:




           [.ECC6DFE919A382]这个进程还想冒充系统进程,疑点极大,而且/tmp/freeBSD也是一个很奇怪的东西,而498这个UID对应的用户是elasticsearch,想起来昨天部署了Elasticsearch + Logstash,以实现日志统计系统,不会是ES有bug吧,继续查看原因




            疑/tmp/freeBSD就是被挂马的程序,可惜已经被删除了,无法查看了

原因:

            罪魁祸首查出来了,细致的原因还需要详查,所以现在最重要的就是解决问题,迅速kill掉相关进程,再次查看iftop发现流量迅速回落了,更加证实了我们的判断;
            接下来就需要查找被劫持挂马的原因和具体的劫持方式,以绝后患,而通过外部搜索引擎也是很快就定位了问题的原因,就是“Elasticsearch远程任意代码执行”漏洞:
[]ElasticSearch有脚本执行(scripting)的功能,可以很方便地对查询出来的数据再加工处理; ElasticSearch用的脚本引擎是MVEL,这个引擎没有做任何的防护,或者沙盒包装,所以直接可以执行任意代码。[/][]而在ElasticSearch 1.2之前的版本里,默认配置是打开动态脚本功能的,因此用户可以直接通过http请求,执行任意代码。[/][]其实官方是清楚这个漏洞的,在文档里有说明:[/][]First, you should not run Elasticsearch as the root user, as this would allow a script to access or do anything on your server, without limitations. Second, you should not expose Elasticsearch directly to users, but instead have a proxy application inbetween.            [/]
           终于找到原因,那就解决吧

解决方案:

           法一:手动关闭ES远程执行脚本的功能,即在每一个ES节点的配置文件elasticsearch.yml中添加如下一行即可script.disable_dynamic: true           然后重启ES即可.
           法二:升级ES至1.2版本以上也可,因为在ES1.2版本中已默认关闭了远程执行脚本的功能,但需考虑与Logstash的兼容性问题

后续:

[]根据官方的资料,为了保证ES的安全性,不可以root身份启动ES,且可考虑使用代理(负载均衡器也可),对外开放非9200端口(如9300),转发至内网的9200端口,可有效防止小人们的恶意端口扫描;[/][]因为已经被挂马了一次,所以在重新启用ES之前,还需全面检查被入侵的主机是否还有其它隐患,这就涉及web安全扫描的内容了,暂时小白,还未了解,故希望有经验的前辈可以多多请教![/]
           最近我也遇到了这个问题,然后搜索发现这篇文章不错,然后就想分享给大家,希望大家可以避免踩坑!
原文地址 查看全部


起因:


           公司使用的是Ucloud的云主机服务,今天上午突然被告知有一台服务器的出口流量激增,对外发包量短时间内达到了100万,而且都是UDP类型的,第一感觉就是:诶呀,莫不是被黑了,被当肉鸡了呀!


探究:


           立马登录对应的服务器,首先使用iftop查看流量状况
e1.jpg

e2.jpg

           可以看出出口流量好吓人,1分钟内累计700M流量,查了一下这2个IP地址,一个是在美国,一个是在浙江电信;赶紧查看正在运行的进程,找出疑似进程,还真有所发现:
e3.jpg

           [.ECC6DFE919A382]这个进程还想冒充系统进程,疑点极大,而且/tmp/freeBSD也是一个很奇怪的东西,而498这个UID对应的用户是elasticsearch,想起来昨天部署了Elasticsearch + Logstash,以实现日志统计系统,不会是ES有bug吧,继续查看原因
e4.jpg

            疑/tmp/freeBSD就是被挂马的程序,可惜已经被删除了,无法查看了


原因:


            罪魁祸首查出来了,细致的原因还需要详查,所以现在最重要的就是解决问题,迅速kill掉相关进程,再次查看iftop发现流量迅速回落了,更加证实了我们的判断;
            接下来就需要查找被劫持挂马的原因和具体的劫持方式,以绝后患,而通过外部搜索引擎也是很快就定位了问题的原因,就是“Elasticsearch远程任意代码执行”漏洞:
    []ElasticSearch有脚本执行(scripting)的功能,可以很方便地对查询出来的数据再加工处理; ElasticSearch用的脚本引擎是MVEL,这个引擎没有做任何的防护,或者沙盒包装,所以直接可以执行任意代码。[/][]而在ElasticSearch 1.2之前的版本里,默认配置是打开动态脚本功能的,因此用户可以直接通过http请求,执行任意代码。[/][]其实官方是清楚这个漏洞的,在文档里有说明:[/][]First, you should not run Elasticsearch as the root user, as this would allow a script to access or do anything on your server, without limitations. Second, you should not expose Elasticsearch directly to users, but instead have a proxy application inbetween.            [/]

           终于找到原因,那就解决吧


解决方案:


           法一:手动关闭ES远程执行脚本的功能,即在每一个ES节点的配置文件elasticsearch.yml中添加如下一行即可
script.disable_dynamic: true
           然后重启ES即可.
           法二:升级ES至1.2版本以上也可,因为在ES1.2版本中已默认关闭了远程执行脚本的功能,但需考虑与Logstash的兼容性问题


后续:


    []根据官方的资料,为了保证ES的安全性,不可以root身份启动ES,且可考虑使用代理(负载均衡器也可),对外开放非9200端口(如9300),转发至内网的9200端口,可有效防止小人们的恶意端口扫描;[/][]因为已经被挂马了一次,所以在重新启用ES之前,还需全面检查被入侵的主机是否还有其它隐患,这就涉及web安全扫描的内容了,暂时小白,还未了解,故希望有经验的前辈可以多多请教![/]

           最近我也遇到了这个问题,然后搜索发现这篇文章不错,然后就想分享给大家,希望大家可以避免踩坑!
原文地址

reids 故障 'I/O error trying to sync with MASTER: connection lost'

数据库OpenSkill 发表了文章 • 0 个评论 • 803 次浏览 • 2015-07-20 23:40 • 来自相关话题

现象:

业务出现告警,业务未处理数量增加,发现连接reids很慢。然后再去PING redis机器发现 内网PING redis server 延迟很高 1000ms以上.

排查过程:

[]换网线不起作用。发现网卡一直在100M左右,然后又发现网卡口协商的是百兆,可能是交换机的问题[/][]为什么会有100M的流量呢。redis 主从之间流量异常 查看redis log 的时候可以看到[/]
[2325] 25 Dec 14:55:32.400 * MASTER SLAVE sync started
[2325] 25 Dec 14:55:32.400 * Non blocking connect for SYNC fired the event.
[2325] 25 Dec 14:55:32.433 * Master replied to PING, replication can continue...
[2325] 25 Dec 14:55:32.447 * Partial resynchronization not possible (no cached master)
[2325] 25 Dec 14:55:32.457 * Full resync from master: de89c0fdb8ecf70677585245f69ad956a4275102:33404969647192
[2325] 25 Dec 14:56:37.159 * MASTER SLAVE sync: receiving 3609059211 bytes from master
[2325] 25 Dec 14:59:12.193 # I/O error trying to sync with MASTER: connection lost      3、从redis不停的去从主上同步数据,但一直lost
      4、为什么LOST呢。 google了一下client-output-buffer-limit 这个参数对slave 同步时候所用的buffer做限制了

默认值是这个 client-output-buffer-limit slave 256mb 64mb 60(这是说负责发数据给slave的client,如果buffer超过256m或者连续60秒超过64m,就会被立刻强行关闭!!! Traffic大的话一定要设大一点。否则就会出现一个很悲剧循环,Master传输一个大的RDB给Slave,Slave努力的装载,但还没装载 完,Master对client的缓存满了,再来一次。)      5、这里有个插曲。因为redis不能重启。要用命令config set client-output-buffer-limit 这个命令 因为我用的是telnet在设置config set client-output-buffer-limit ‘slave 536870912 134217728 120′ 这样一直不成功。报参数不正确

Wrong number of arguments for CONFIG SET”

用redis-cli 就正常,应该是空格的问题,不细查了。

有将近9个GB的数据redis_master,然后设置成 ‘slave 536870912 134217728 120’还是同步失败,最后设置成了confg set client-output-buffer-limit ‘slave 2036870912 1534217728 300’就成功了,所以这个设置还得根据你同步数据的多少有针对性的设定。 查看全部


现象:


业务出现告警,业务未处理数量增加,发现连接reids很慢。然后再去PING redis机器发现 内网PING redis server 延迟很高 1000ms以上.


排查过程:


    []换网线不起作用。发现网卡一直在100M左右,然后又发现网卡口协商的是百兆,可能是交换机的问题[/][]为什么会有100M的流量呢。redis 主从之间流量异常 查看redis log 的时候可以看到[/]

[2325] 25 Dec 14:55:32.400 * MASTER  SLAVE sync started
[2325] 25 Dec 14:55:32.400 * Non blocking connect for SYNC fired the event.
[2325] 25 Dec 14:55:32.433 * Master replied to PING, replication can continue...
[2325] 25 Dec 14:55:32.447 * Partial resynchronization not possible (no cached master)
[2325] 25 Dec 14:55:32.457 * Full resync from master: de89c0fdb8ecf70677585245f69ad956a4275102:33404969647192
[2325] 25 Dec 14:56:37.159 * MASTER SLAVE sync: receiving 3609059211 bytes from master
[2325] 25 Dec 14:59:12.193 # I/O error trying to sync with MASTER: connection lost
      3、从redis不停的去从主上同步数据,但一直lost
      4、为什么LOST呢。 google了一下
client-output-buffer-limit 这个参数对slave 同步时候所用的buffer做限制了

默认值是这个 client-output-buffer-limit slave 256mb 64mb 60(这是说负责发数据给slave的client,如果buffer超过256m或者连续60秒超过64m,就会被立刻强行关闭!!! Traffic大的话一定要设大一点。否则就会出现一个很悲剧循环,Master传输一个大的RDB给Slave,Slave努力的装载,但还没装载 完,Master对client的缓存满了,再来一次。)
      5、这里有个插曲。
因为redis不能重启。要用命令config set client-output-buffer-limit 这个命令 因为我用的是telnet在设置config set client-output-buffer-limit ‘slave 536870912 134217728 120′ 这样一直不成功。报参数不正确

Wrong number of arguments for CONFIG SET”

用redis-cli 就正常,应该是空格的问题,不细查了。

有将近9个GB的数据redis_master,然后设置成 ‘slave 536870912 134217728 120’还是同步失败,最后设置成了confg set client-output-buffer-limit ‘slave 2036870912 1534217728 300’就成功了,所以这个设置还得根据你同步数据的多少有针对性的设定。

关于GlusterFS的可用空间

回复

大数据/云计算OpenSkill 发起了问题 • 1 人关注 • 0 个回复 • 1003 次浏览 • 2015-07-19 11:35 • 来自相关话题

ArchSummit全球架构师峰会见闻之APM

互联网资讯Ansible 发表了文章 • 0 个评论 • 1477 次浏览 • 2015-07-18 00:27 • 来自相关话题

引言:

     近几年来是一个创客的时代,我们每天都能在各种不同的地方看到不同的人在各种不同的产品,国内已形成一种创业的热潮。媒体捧吹,政府政策支持,这年头不说自己是创业者都不好意思创业。就拿北京来说,不知道一天内有多少家创业公司兴起,有多少家创业公司倒闭。

    从2011年开始,大数据逐渐进入互联网热词行列。2012年美国硅谷投资的最热门主题就是大数据,大数据的时代的到来也造就了不少创业公司。国外的比如,大数据业务分析公司Splunk、数据服务公司Metamarkets、数据可视化公司Tableau、大数据分析公司ParAccel等。当大数据这个热词涌入国内的时候也促进国内的互联网巨头们也在纷纷布局切分蛋糕,比如阿里、百度、腾讯、金山,还有在线教育的小象学院和早期成立的数据分析专业社区炼数成金。

    进入到2013年莫过于最火的就是云计算和虚拟化技术,作为技术人员熟悉的kvm,vm,esi,cloudstack,openstack等,逐渐进入到互联网技术人员的视野。其中也不乏不少创业者看到了方向。比如基于openstack技术成立于2013年的OpenStack开源云计算公司UnitedStack,还有基于基于cloudstack市场的天云趋势等。

    2014年大家听得最多的莫过于devops和Iass这两个词语吧。devops让我们的运维同学从脚本时代走进了coding时代,因为现在越来越多的公司都要求你会python或者其他的语言,不只简简单单的会个shell脚本就行了,因为互联网在进步。从云的概念进入中国市场,越来越多的创业者看到了中国这个行业的大市场,在国内做Iass服务的,有我们熟知的阿里云,腾讯云,ucloud,青云等。

    从2014年下半年到2015年互联网创客,熟知的应该就是基于Docker容器技术的创业者们,比如DAOCLOUD,云雀,数人科技,希云,Tenxcloud等,同样APM这个词也逐渐成为创客们中的热词了,在国外有我们熟知的APM的创业公司比如:Compuware、iMaster、New Relic、AppDynamics等,而国内的创业者们也看到了中国这个大市场,大蛋糕,也不乏创业公司比如:云智慧、OneAPM、听云等。

  APM是什么鬼    应用性能管理(Application Performance Management)是一个比较新的网络管理方向,主要指对企业的关键业务应用进行监测、优化,提高企业应用的可靠性和质量,保证用户得到良好的服务,降低IT总拥有成本(TCO)。使用全业务链的敏捷APM监控,可使一个企业的关键业务应用的性能更强大,可以提高竞争力,并取得商业成功,因此,加强应用性能管理(APM)可以产生巨大商业利益。              如果你还不了解APM是什么东东,请你移驾这里一张图告诉你什么是APM,想知道什么是真正的APM看这里。

AMP见闻之云智慧
              2015的ArchSummit架构师大会可谓是空前盛况,有将近近千名的架构师们参加。不乏百度、AWS、小米、华为、腾讯等大公司的架构师参加,也有Ucloud、青云、DAOCLOUD、云智慧等新型创业公司的加盟。
 
              作为一个运维人员我可能最关心的就是我们线上的架构应该怎么部署合理和现有架构的性能在哪里的问题,所以我这次特别关心了一下APM主题的演讲,所以在这里我为大家介绍一下我在大会看到的云智慧 高级架构师 高驰涛(Neeke)演讲的"APM与高性能架构"
 
              首先我先介绍一下他在PPT中展示演讲的三个点:性能瓶颈----->瓶颈是谁----->怎么解决 ,那下面我就逐一介绍。
 
性能瓶颈
      1.用户体验            




               不管是一个网站、产品、衣服,用户体验是很重要的,因为只有公司的产品有了用户,这家公司才有前景,才有收益。我之前一个同学在小米的应用推广平台做运维,有一天他跟我说,他们今天平台的日流水要破千万了,可想而知,一个产品只有用户才是你最大的支柱,只有用户体验好了,才能留住用户,你的产品才能体现出更高的价值。所以雷军说过要把产品做到极致,而这个极致的背后就是用户体验。
 
               而用户体验的改善我们需要去从不同的角度去分析,就如上图所示的一样,从设计方面,我们设计出更符合现在用户更喜欢的UI的风格界面,从服务方面,我们需要做好技术售后的服务和海底捞式的优服务,从产品方面我们要把产品做到极致,从性能方面,我们要让用户体验的更爽,让他的抱怨更少,从架构方面,我们应该拿出GEEK的精神去部署,从交互方面,我们应该做到简约明了,而这些并不是每个公司都能做到的,我们可以通过第三方的SaaS提供商来解决这些,可以促进我们更快、更高效的解决这些问题,当这些问题不存在了,作为工程师的我们就可以坐到办公室里面喝茶了,而不是天天焦急频繁迭代去改善我们产品的这些问题,当然这是一个最理想的状态,我想不久的将来会是这么一个状态,因为我们就在做这件事。
      2.网站架构模型








                 作为技术人员我们都知道网站的典型架构模型如上所示,随着业务增长,架构也会越来越大,关系的方面很多有网站的高可用性、数据的一致性、数据存储和搜索等等一系列的问题。随着这些问题的不断产生、扩张,你觉得作为技术人员的你,还有时间喝茶吗,公司只会不停的去招人,不停的去解决这些问题,从而导致你的网站、产品的质量和体验值都会下降,所以应用系统性能对用户的体验是至关重要的!
      3.应用系统性能




                 说起流氓这个词,我想流氓会武术,谁都挡不住哦。但是在这个创客的时代,创业者们本来就是"流氓",因为创业就是这样的,你成功了你就是预言家,失败了你就是在催牛逼。




                 前不久淘宝、携程相继出现故障,我想对他们自己的业务带来了不小的影响,淘宝还好,我相信淘宝确时是因为光缆破坏导致的故障,可怜的是携程,整个业务故障时间整整有半天之久,这个对用户的体验是非常不好的。也会造成用户对公司的信任,我的个人信息是不是会被暴露等一些问题,所以说应用的性能确实很重要,直接影响到了公司财政收入啊。难怪携程故障,老板会发出话来说,谁能给我最快的速度解决问题,奖励100万呢!

瓶颈是谁
        1.环境分析




                 一个公司由不同的部门组成,又我们的技术客服、运维、开发、市场等组成。作为一个互联网公司,当公司发展的道路上,遇到了阻力,我们产品的应用性能问题,到底是谁负责,谁来解决呢?通常我们一般都会先想到我们可爱的开发者同学们身上,然后我们开发的同学就不停的加班,解决bug和问题,但是最后效果并不是很好。就如下图所示:




                 那就让我们来分析分析应用的环境吧




                 没错,如上图所示应用就是一个多技术栈复合的整合环境。我想大家看到这么一个细化的环境,你让我们可爱的开发同学,怎么去发现问题点,即使花了大部分时间找出的问题所在,这么一个环境一个人可能完成吗,需要多个开发同学配合修复,但是等你花了大部分时间来分析你应用的时候,你公司的业务进度也是停滞不前的,蛋糕也许就被别人切走了!所以这就是APM的价值所在,透视宝则孕育而生





       2.坑在哪里








                   问题出现了,作为技术人员就会去找坑,但是业务环境和系统环境都可能有问题,所以找坑成为一种苦恼,喝茶的时间自然没有,我们需要从前端cdn层、web层、缓存存、数据层等方面着手一一去分析,但是最后你不一定可以准确的找到答案。就拿我们线上一次事件来说吧,我们的业务任务调度出现了瓶颈,我们足足花了三天之久的时间,最后才有80%的把握确认瓶颈出现在缓存系统redis上面,虽然已经找到了问题所在,最后重启redis,把资源释放了,最后暂时把问题解决了,但是最后这种问题还是会发生了,所以最后我们只好扩展redis,最后选择用来豌豆荚开源出来的分布式redis系统codis得于解决。从这个案例上来看,可想而知,查找坑是多嘛痛苦的事情啊,这让我想起了一句歌词"多么痛的领悟"! 而APM正好可以帮你解决你的痛苦。
 
怎么解决
                     那我们到底应该怎么去发现和解决呢?
       1.优化方案




                      我们的分享人给出了如上图所示的一些建议。无可厚非,我们在设计架构和语言程序的选择上面,头期一定要多考虑到性能问题和可扩展和高可用的问题,要不后期随着产品和业务的增长你只能去找坑,填坑了!








                      对于监控大家当然不陌生,监控是作为一个业务增长保证的基础,因为在业务增长的同时,我们要未雨绸缪的考虑到一些性能方面的问题,而监控正好可以我们很好的做个预警工作,可以让我们有足够充裕的时间来解决问题,不至于等到问题出现,来临时抱佛脚,着急的处理。而云智慧他们有这个优势,因为他们还有一款产品监控宝, 我想大家应该都听说过吧。
     
        2.发现解决




                       如上图是云智慧产品透视宝的Smart Agent的架构图,那它的特点是什么,能干什么?




                       从上图可以看出smart agent就是类似于我们常说的一个嵌入的sdk一样,只不过这是一个比较高级的sdk,它可以自动发现你主机上面的应用程序、代码执行效率、已经整个环境的生态关系和性能指标的采集、分析数据,从而发现你这个应用系统的性能瓶颈所在。那有人,就会问了这个东西安装在我服务器上是否安全,我的信息是否会被盗取和丢失呢?




                         我想作为用户有担心是无可厚非的,但是我想做一个长久的公司,是会考虑到我们用户的感受的,看到如上图的解释,我想安全问题,应该不存在的。那这个系统实现原理是怎么样的,是怎么实现的?大会上分享人给出了一个php code执行的数据流图




                          整个系统又能解决哪些问题呢?




                          web端用户体验问题








                          作为运维工程师,经常会有客户反应公司网站慢,但是作为运维人员有不能很好的去查询预知,哪个地方的客户访问比较慢,只有客户反应过来才了解,这样就导致用户体验不好的问题,以致业务收到影响。我这里举个例子,我上家公司是做app市场推广和下载的,类似于91助手,我们公司的用户群体主要集中在北京、上海、深圳、广州等一线城市,有一天我们领导要我分别去测试评估这几个城市在我们平台用户下载速度,这可是给我出了一道难题了,我只好让朋友帮忙,测试了,然后评估一个数据了。页面详情追踪我想,为我们做web优化做出了很好的分析,可以针对相应慢的资源,做出相应的优化方案,不错觉得功能还可以,可以解决痛点!
                         后端服务事务分析








                         深入到后端可以让我们清晰的了解性能出现在哪个节点上面,代码级别可以让我们深入了解开发者的代码性能的问题,已经查询SQL性能的问题。看起来挺好高级的,但是如果能提供解决方案更好了。比如查询出来我有一个SQL执行时间过长,然后给出一个认为更优的SQL语句,来做到真正为用户考虑,尽最大力度,减小用户的痛点,就更好了,不过作为创业公司已经做的很不错了,继续加油吧!
                          应用架构




                          有一个清晰的业务应用架构,当然对解决问题是有很大帮助的。最后问题发现了,解决了,是不是可以喝茶了,balabala,happy!








                           真心要喝茶去了,因为大牛的分享结束了,真是意犹未尽啊!
下面我分享几张现场的照片和大牛的PPT给大家
PPT下载地址
































本人文笔有限,欢迎大家交流、拍砖 查看全部
a3.png

引言:


     近几年来是一个创客的时代,我们每天都能在各种不同的地方看到不同的人在各种不同的产品,国内已形成一种创业的热潮。媒体捧吹,政府政策支持,这年头不说自己是创业者都不好意思创业。就拿北京来说,不知道一天内有多少家创业公司兴起,有多少家创业公司倒闭。

    从2011年开始,大数据逐渐进入互联网热词行列。2012年美国硅谷投资的最热门主题就是大数据,大数据的时代的到来也造就了不少创业公司。国外的比如,大数据业务分析公司Splunk、数据服务公司Metamarkets、数据可视化公司Tableau、大数据分析公司ParAccel等。当大数据这个热词涌入国内的时候也促进国内的互联网巨头们也在纷纷布局切分蛋糕,比如阿里、百度、腾讯、金山,还有在线教育的小象学院和早期成立的数据分析专业社区炼数成金。

    进入到2013年莫过于最火的就是云计算和虚拟化技术,作为技术人员熟悉的kvm,vm,esi,cloudstack,openstack等,逐渐进入到互联网技术人员的视野。其中也不乏不少创业者看到了方向。比如基于openstack技术成立于2013年的OpenStack开源云计算公司UnitedStack,还有基于基于cloudstack市场的天云趋势等。

    2014年大家听得最多的莫过于devops和Iass这两个词语吧。devops让我们的运维同学从脚本时代走进了coding时代,因为现在越来越多的公司都要求你会python或者其他的语言,不只简简单单的会个shell脚本就行了,因为互联网在进步。从云的概念进入中国市场,越来越多的创业者看到了中国这个行业的大市场,在国内做Iass服务的,有我们熟知的阿里云,腾讯云,ucloud,青云等。

    从2014年下半年到2015年互联网创客,熟知的应该就是基于Docker容器技术的创业者们,比如DAOCLOUD,云雀,数人科技,希云,Tenxcloud等,同样APM这个词也逐渐成为创客们中的热词了,在国外有我们熟知的APM的创业公司比如:Compuware、iMaster、New Relic、AppDynamics等,而国内的创业者们也看到了中国这个大市场,大蛋糕,也不乏创业公司比如:云智慧、OneAPM、听云等。


  APM是什么鬼   
    应用性能管理(Application Performance Management)是一个比较新的网络管理方向,主要指对企业的关键业务应用进行监测、优化,提高企业应用的可靠性和质量,保证用户得到良好的服务,降低IT总拥有成本(TCO)。使用全业务链的敏捷APM监控,可使一个企业的关键业务应用的性能更强大,可以提高竞争力,并取得商业成功,因此,加强应用性能管理(APM)可以产生巨大商业利益。
              如果你还不了解APM是什么东东,请你移驾这里一张图告诉你什么是APM,想知道什么是真正的APM看这里。

AMP见闻之云智慧
              2015的ArchSummit架构师大会可谓是空前盛况,有将近近千名的架构师们参加。不乏百度、AWS、小米、华为、腾讯等大公司的架构师参加,也有Ucloud、青云、DAOCLOUD、云智慧等新型创业公司的加盟。
 
              作为一个运维人员我可能最关心的就是我们线上的架构应该怎么部署合理和现有架构的性能在哪里的问题,所以我这次特别关心了一下APM主题的演讲,所以在这里我为大家介绍一下我在大会看到的云智慧 高级架构师 高驰涛(Neeke)演讲的"APM与高性能架构"
 
              首先我先介绍一下他在PPT中展示演讲的三个点:性能瓶颈----->瓶颈是谁----->怎么解决 ,那下面我就逐一介绍。
 
性能瓶颈
      1.用户体验            
st1.png

               不管是一个网站、产品、衣服,用户体验是很重要的,因为只有公司的产品有了用户,这家公司才有前景,才有收益。我之前一个同学在小米的应用推广平台做运维,有一天他跟我说,他们今天平台的日流水要破千万了,可想而知,一个产品只有用户才是你最大的支柱,只有用户体验好了,才能留住用户,你的产品才能体现出更高的价值。所以雷军说过要把产品做到极致,而这个极致的背后就是用户体验。
 
               而用户体验的改善我们需要去从不同的角度去分析,就如上图所示的一样,从设计方面,我们设计出更符合现在用户更喜欢的UI的风格界面,从服务方面,我们需要做好技术售后的服务和海底捞式的优服务,从产品方面我们要把产品做到极致,从性能方面,我们要让用户体验的更爽,让他的抱怨更少,从架构方面,我们应该拿出GEEK的精神去部署,从交互方面,我们应该做到简约明了,而这些并不是每个公司都能做到的,我们可以通过第三方的SaaS提供商来解决这些,可以促进我们更快、更高效的解决这些问题,当这些问题不存在了,作为工程师的我们就可以坐到办公室里面喝茶了,而不是天天焦急频繁迭代去改善我们产品的这些问题,当然这是一个最理想的状态,我想不久的将来会是这么一个状态,因为我们就在做这件事。
      2.网站架构模型
st2.png

st3.png

                 作为技术人员我们都知道网站的典型架构模型如上所示,随着业务增长,架构也会越来越大,关系的方面很多有网站的高可用性、数据的一致性、数据存储和搜索等等一系列的问题。随着这些问题的不断产生、扩张,你觉得作为技术人员的你,还有时间喝茶吗,公司只会不停的去招人,不停的去解决这些问题,从而导致你的网站、产品的质量和体验值都会下降,所以应用系统性能对用户的体验是至关重要的!
      3.应用系统性能
st4.png

                 说起流氓这个词,我想流氓会武术,谁都挡不住哦。但是在这个创客的时代,创业者们本来就是"流氓",因为创业就是这样的,你成功了你就是预言家,失败了你就是在催牛逼。
at4.png

                 前不久淘宝、携程相继出现故障,我想对他们自己的业务带来了不小的影响,淘宝还好,我相信淘宝确时是因为光缆破坏导致的故障,可怜的是携程,整个业务故障时间整整有半天之久,这个对用户的体验是非常不好的。也会造成用户对公司的信任,我的个人信息是不是会被暴露等一些问题,所以说应用的性能确实很重要,直接影响到了公司财政收入啊。难怪携程故障,老板会发出话来说,谁能给我最快的速度解决问题,奖励100万呢!

瓶颈是谁
        1.环境分析
at5.png

                 一个公司由不同的部门组成,又我们的技术客服、运维、开发、市场等组成。作为一个互联网公司,当公司发展的道路上,遇到了阻力,我们产品的应用性能问题,到底是谁负责,谁来解决呢?通常我们一般都会先想到我们可爱的开发者同学们身上,然后我们开发的同学就不停的加班,解决bug和问题,但是最后效果并不是很好。就如下图所示:
at6.png

                 那就让我们来分析分析应用的环境吧
at7.png

                 没错,如上图所示应用就是一个多技术栈复合的整合环境。我想大家看到这么一个细化的环境,你让我们可爱的开发同学,怎么去发现问题点,即使花了大部分时间找出的问题所在,这么一个环境一个人可能完成吗,需要多个开发同学配合修复,但是等你花了大部分时间来分析你应用的时候,你公司的业务进度也是停滞不前的,蛋糕也许就被别人切走了!所以这就是APM的价值所在,透视宝则孕育而生
at8.png


       2.坑在哪里
at9.png

at10.png

                   问题出现了,作为技术人员就会去找坑,但是业务环境和系统环境都可能有问题,所以找坑成为一种苦恼,喝茶的时间自然没有,我们需要从前端cdn层、web层、缓存存、数据层等方面着手一一去分析,但是最后你不一定可以准确的找到答案。就拿我们线上一次事件来说吧,我们的业务任务调度出现了瓶颈,我们足足花了三天之久的时间,最后才有80%的把握确认瓶颈出现在缓存系统redis上面,虽然已经找到了问题所在,最后重启redis,把资源释放了,最后暂时把问题解决了,但是最后这种问题还是会发生了,所以最后我们只好扩展redis,最后选择用来豌豆荚开源出来的分布式redis系统codis得于解决。从这个案例上来看,可想而知,查找坑是多嘛痛苦的事情啊,这让我想起了一句歌词"多么痛的领悟"! 而APM正好可以帮你解决你的痛苦。
 
怎么解决
                     那我们到底应该怎么去发现和解决呢?
       1.优化方案
as5.png

                      我们的分享人给出了如上图所示的一些建议。无可厚非,我们在设计架构和语言程序的选择上面,头期一定要多考虑到性能问题和可扩展和高可用的问题,要不后期随着产品和业务的增长你只能去找坑,填坑了!
as6.png

as7.png

                      对于监控大家当然不陌生,监控是作为一个业务增长保证的基础,因为在业务增长的同时,我们要未雨绸缪的考虑到一些性能方面的问题,而监控正好可以我们很好的做个预警工作,可以让我们有足够充裕的时间来解决问题,不至于等到问题出现,来临时抱佛脚,着急的处理。而云智慧他们有这个优势,因为他们还有一款产品监控宝, 我想大家应该都听说过吧。
     
        2.发现解决
as8.png

                       如上图是云智慧产品透视宝的Smart Agent的架构图,那它的特点是什么,能干什么?
as9.png

                       从上图可以看出smart agent就是类似于我们常说的一个嵌入的sdk一样,只不过这是一个比较高级的sdk,它可以自动发现你主机上面的应用程序、代码执行效率、已经整个环境的生态关系和性能指标的采集、分析数据,从而发现你这个应用系统的性能瓶颈所在。那有人,就会问了这个东西安装在我服务器上是否安全,我的信息是否会被盗取和丢失呢?
ab1.png

                         我想作为用户有担心是无可厚非的,但是我想做一个长久的公司,是会考虑到我们用户的感受的,看到如上图的解释,我想安全问题,应该不存在的。那这个系统实现原理是怎么样的,是怎么实现的?大会上分享人给出了一个php code执行的数据流图
ab2.png

                          整个系统又能解决哪些问题呢?
ab3.png

                          web端用户体验问题
ab4.png

ab5.png

                          作为运维工程师,经常会有客户反应公司网站慢,但是作为运维人员有不能很好的去查询预知,哪个地方的客户访问比较慢,只有客户反应过来才了解,这样就导致用户体验不好的问题,以致业务收到影响。我这里举个例子,我上家公司是做app市场推广和下载的,类似于91助手,我们公司的用户群体主要集中在北京、上海、深圳、广州等一线城市,有一天我们领导要我分别去测试评估这几个城市在我们平台用户下载速度,这可是给我出了一道难题了,我只好让朋友帮忙,测试了,然后评估一个数据了。页面详情追踪我想,为我们做web优化做出了很好的分析,可以针对相应慢的资源,做出相应的优化方案,不错觉得功能还可以,可以解决痛点!
                         后端服务事务分析
ab6.png

ab7.png

                         深入到后端可以让我们清晰的了解性能出现在哪个节点上面,代码级别可以让我们深入了解开发者的代码性能的问题,已经查询SQL性能的问题。看起来挺好高级的,但是如果能提供解决方案更好了。比如查询出来我有一个SQL执行时间过长,然后给出一个认为更优的SQL语句,来做到真正为用户考虑,尽最大力度,减小用户的痛点,就更好了,不过作为创业公司已经做的很不错了,继续加油吧!
                          应用架构
ab8.png

                          有一个清晰的业务应用架构,当然对解决问题是有很大帮助的。最后问题发现了,解决了,是不是可以喝茶了,balabala,happy!
ab9.png

ab10.png

                           真心要喝茶去了,因为大牛的分享结束了,真是意犹未尽啊!
下面我分享几张现场的照片和大牛的PPT给大家
PPT下载地址
2.jpg

3.jpg

4.jpg

5.jpg

6.jpg

7.jpg

8.jpg

9.jpg

本人文笔有限,欢迎大家交流、拍砖