-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
1 lines (1 loc) · 95 KB
/
index.html
File metadata and controls
1 lines (1 loc) · 95 KB
1
<!DOCTYPE html><html lang="zh"><head><meta charset="utf-8"><title>码农想种地</title><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta name="description" content="资浅互联网攻城狮,搞过Java,python,熟悉数据库,NOSQL,可以使用js,bootstrap,总之,我就是块砖,哪里需要哪里搬,自己搭建这个博客,来记录码农的点点滴滴,博客名字就叫做:码农想种地,确实,我想有块自己的地,种点花花草草,这个世道,也就花花草草还能一尘不染吧"><meta property="og:type" content="website"><meta property="og:title" content="码农想种地"><meta property="og:url" content="http://trytofix.com/index.html"><meta property="og:site_name" content="码农想种地"><meta property="og:description" content="资浅互联网攻城狮,搞过Java,python,熟悉数据库,NOSQL,可以使用js,bootstrap,总之,我就是块砖,哪里需要哪里搬,自己搭建这个博客,来记录码农的点点滴滴,博客名字就叫做:码农想种地,确实,我想有块自己的地,种点花花草草,这个世道,也就花花草草还能一尘不染吧"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="码农想种地"><meta name="twitter:description" content="资浅互联网攻城狮,搞过Java,python,熟悉数据库,NOSQL,可以使用js,bootstrap,总之,我就是块砖,哪里需要哪里搬,自己搭建这个博客,来记录码农的点点滴滴,博客名字就叫做:码农想种地,确实,我想有块自己的地,种点花花草草,这个世道,也就花花草草还能一尘不染吧"><link rel="icon" href="http://7xiego.com1.z0.glb.clouddn.com/static/favicon.png"><link rel="stylesheet" href="http://apps.bdimg.com/libs/fontawesome/4.0.3/css/font-awesome.min.css"><link rel="stylesheet" href="http://7xiego.com1.z0.glb.clouddn.com/vendor/open-sans/styles.css"><link rel="stylesheet" href="http://7xiego.com1.z0.glb.clouddn.com/vendor/source-code-pro/styles.css"><link rel="stylesheet" href="http://7xiego.com1.z0.glb.clouddn.com/css/style.css"><script src="http://apps.bdimg.com/libs/jquery/2.1.3/jquery.min.js"></script><script>var _hmt=_hmt||[];!function(){var e=document.createElement("script");e.src="//hm.baidu.com/hm.js?29dcecae8156730f7ba3298ce35249df";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)}()</script></head></html><body><div id="container"><header id="header"><div id="header-main" class="header-inner"><div class="outer"><a href="/" id="logo"><i class="logo"></i> <span class="site-title">码农想种地</span></a><nav id="main-nav"><a class="main-nav-link" href="/.">Home</a> <a class="main-nav-link" href="/archives/">Archives</a> <a class="main-nav-link" href="/categories/">Categories</a> <a class="main-nav-link" href="/tags/">Tags</a> <a class="main-nav-link" href="/about/">About</a></nav><nav id="sub-nav"><div class="profile" id="profile-nav"><a id="profile-anchor" href="javascript:;"><img class="avatar" src="http://7xiego.com1.z0.glb.clouddn.com/static/imagekakaxi.jpg"> <i class="fa fa-caret-down"></i></a></div></nav><div id="search-form-wrap"><form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="搜索"><button type="submit" class="search-form-submit"></button><input type="hidden" name="sitesearch" value="http://trytofix.com"></form></div></div></div><div id="main-nav-mobile" class="header-sub header-inner"><table class="menu outer"><tr><td><a class="main-nav-link" href="/.">Home</a></td><td><a class="main-nav-link" href="/archives/">Archives</a></td><td><a class="main-nav-link" href="/categories/">Categories</a></td><td><a class="main-nav-link" href="/tags/">Tags</a></td><td><a class="main-nav-link" href="/about/">About</a></td><td><form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="搜索"><input type="hidden" name="sitesearch" value="http://trytofix.com"></form></td></tr></table></div></header><div class="outer"><aside id="profile"><div class="inner profile-inner"><div class="base-info profile-block"><img id="avatar" src="http://7xiego.com1.z0.glb.clouddn.com/static/imagekakaxi.jpg"><h2 id="name">brian.yang</h2><h3 id="title">努力的Coder</h3><span id="location"><i class="fa fa-map-marker"></i>Beijing, China</span> <a id="follow" target="_blank" href="https://github.com/trytofix/" rel="external nofollow">关注我</a></div><div class="article-info profile-block"><div class="article-info-block">78 <span>文章</span></div><div class="article-info-block">48 <span>标签</span></div></div><div class="profile-block social-links"><table><tr><td><a href="http://github.com/trytofix" target="_blank" title="github" rel="external nofollow"><i class="fa fa-github"></i></a></td><td><a href="/atom.xml" target="_blank" title="rss"><i class="fa fa-rss"></i></a></td></tr></table></div></div></aside><section id="main"><article id="post-Celery-Tornado-Supervisor构建和谐的分布式框架" class="article article-type-post" itemscope="" itemprop="blogPost"><div class="article-inner"><header class="article-header"><h1 itemprop="name"><a class="article-title" href="/2016/07/07/Celery-Tornado-Supervisor构建和谐的分布式框架/">Celery,Tornado,Supervisor构建和谐的分布式系统</a></h1><div class="article-meta"><div class="article-date"><i class="fa fa-calendar"></i> <a href="/2016/07/07/Celery-Tornado-Supervisor构建和谐的分布式框架/"><time datetime="2016-07-07T08:29:18.000Z" itemprop="datePublished">2016-07-07</time></a></div><div class="article-category"><i class="fa fa-folder"></i> <a class="article-category-link" href="/categories/python/">python</a></div><div class="article-tag"><i class="fa fa-tag"></i> <a class="tag-link" href="/tags/python/">python</a></div></div></header><div class="article-entry" itemprop="articleBody"><h1 id="Celery-分布式的任务队列"><a href="#Celery-分布式的任务队列" class="headerlink" title="Celery 分布式的任务队列"></a><a href="http://docs.celeryproject.org/en/latest/index.html#" rel="external nofollow" target="_blank">Celery</a> 分布式的任务队列</h1><h3 id="与rabbitmq消息队列的区别与联系:"><a href="#与rabbitmq消息队列的区别与联系:" class="headerlink" title="与rabbitmq消息队列的区别与联系:"></a>与rabbitmq消息队列的区别与联系:</h3><ul><li>rabbitmq 调度的是消息,而Celery调度的是任务.</li><li>Celery调度任务时,需要传递参数信息,传输载体可以选择rabbitmq.</li><li>利用rabbitmq的持久化和ack特性,Celery可以保证任务的可靠性.</li></ul><h3 id="优点"><a href="#优点" class="headerlink" title="优点:"></a>优点:</h3><ul><li>轻松构建分布式的Service Provider。</li><li>高可扩展性,增加worker也就是增加了队列的consumer。</li><li>可靠性,利用消息队列的durable和ack,可以尽可能降低消息丢失的概率,当worker崩溃后,未处理的消息会重新进入消费队列。</li><li>用户友好,利用flower提供的管理工具可以轻松的管理worker。<br><img src="http://ww3.sinaimg.cn/large/b8b708a7gw1f5lbun7w3sj211p0fk41t" alt="flower"></li><li>使用tornado-celery,结合tornado异步非阻塞结构,可以提高吞吐量,轻松创建分布式服务框架。</li><li>学习成本低,可快速入门</li></ul><h3 id="快速入门"><a href="#快速入门" class="headerlink" title="快速入门"></a>快速入门</h3><p>定义一个celery实例main.py:<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">from celery import Celery</span><br><span class="line">app = Celery('route_check', include=['check_worker_path'], </span><br><span class="line"> broker='amqp://user:password@rabbitmq_host:port//')</span><br><span class="line">app.config_from_object('celeryconfig')</span><br></pre></td></tr></table></figure><p></p><p>include指的是需要celery扫描是否有任务定义的模块路径。例如<code>add_task</code> 就是扫描add_task.py中的任务</p><p>celery的配置文件可以从文件、模块中读取,这里是从模块中读取,celeryconfig.py为:<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line">from multiprocessing import cpu_count</span><br><span class="line"></span><br><span class="line">from celery import platforms</span><br><span class="line">from kombu import Exchange, Queue</span><br><span class="line"></span><br><span class="line">CELERYD_POOL_RESTARTS = False</span><br><span class="line">CELERY_RESULT_BACKEND = 'redis://:password@redis_host:port/db'</span><br><span class="line">CELERY_QUEUES = (</span><br><span class="line"> Queue('default', Exchange('default'), routing_key='default'),</span><br><span class="line"> Queue('common_check', Exchange('route_check'), routing_key='common_check'),</span><br><span class="line"> Queue('route_check', Exchange('route_check'), routing_key='route_check', delivery_mode=2),</span><br><span class="line"> Queue('route_check_ignore_result', Exchange('route_check'), routing_key='route_check_ignore_result',</span><br><span class="line"> delivery_mode=2)</span><br><span class="line">)</span><br><span class="line">CELERY_ROUTES = {</span><br><span class="line"> 'route_check_task.check_worker.common_check': {'queue': 'common_check'},</span><br><span class="line"> 'route_check_task.check_worker.check': {'queue': 'route_check'},</span><br><span class="line"> 'route_check_task.check_worker.check_ignore_result': {'queue': 'route_check_ignore_result'}</span><br><span class="line">}</span><br><span class="line">CELERY_DEFAULT_QUEUE = 'default'</span><br><span class="line">CELERY_DEFAULT_EXCHANGE = 'default'</span><br><span class="line">CELERY_DEFAULT_EXCHANGE_TYPE = 'direct'</span><br><span class="line">CELERY_DEFAULT_ROUTING_KEY = 'default'</span><br><span class="line"># CELERY_MESSAGE_COMPRESSION = 'gzip'</span><br><span class="line">CELERY_ACKS_LATE = True</span><br><span class="line">CELERYD_PREFETCH_MULTIPLIER = 1</span><br><span class="line">CELERY_DISABLE_RATE_LIMITS = True</span><br><span class="line">CELERY_TIMEZONE = 'Asia/Shanghai'</span><br><span class="line">CELERY_ENABLE_UTC = True</span><br><span class="line">CELERYD_CONCURRENCY = cpu_count() / 2</span><br><span class="line">CELERY_TASK_SERIALIZER = 'json'</span><br><span class="line">CELERY_RESULT_SERIALIZER = 'json'</span><br><span class="line">CELERY_TASK_PUBLISH_RETRY = True</span><br><span class="line">CELERY_TASK_PUBLISH_RETRY_POLICY = {</span><br><span class="line"> 'max_retries': 3,</span><br><span class="line"> 'interval_start': 10,</span><br><span class="line"> 'interval_step': 5,</span><br><span class="line"> 'interval_max': 20</span><br><span class="line">}</span><br><span class="line">platforms.C_FORCE_ROOT = True</span><br></pre></td></tr></table></figure><p></p><p>这里面是一些celery的<a href="http://docs.celeryproject.org/en/latest/configuration.html" rel="external nofollow" target="_blank">配置参数</a>。</p><p>在上面include的add_task.py定义如下:<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">#encoding:utf8</span><br><span class="line"></span><br><span class="line">from main import app</span><br><span class="line"></span><br><span class="line">@app.task</span><br><span class="line">def add(x,y):</span><br><span class="line"> return x+y</span><br></pre></td></tr></table></figure><p></p><p>启动celery<br><code>celery -A main worker -l info -Ofair</code></p><ul><li>-A 后面是包含celery定义的模块,我们在main.py中定义了<code>app = Celery...</code><br>测试celery:</li><li>-l 日志打印的级别,这里是info</li><li>-<a href="http://docs.celeryproject.org/en/latest/whatsnew-3.1.html" rel="external nofollow" target="_blank">Ofair</a> 这个参数可以让Celery更好的调度任务</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"># encoding:utf8</span><br><span class="line">__author__ = 'brianyang'</span><br><span class="line"></span><br><span class="line">import add_task</span><br><span class="line"></span><br><span class="line">result = add_task.add.apply_async((1,2))</span><br><span class="line">print type(result)</span><br><span class="line">print result.ready()</span><br><span class="line">print result.get()</span><br><span class="line">print result.ready()</span><br></pre></td></tr></table></figure><p>输出是<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><class 'celery.result.AsyncResult'></span><br><span class="line">False</span><br><span class="line">3</span><br><span class="line">True</span><br></pre></td></tr></table></figure><p></p><p>当调用result.get()时,如果还没有返回结果,将会阻塞直到结果返回。这里需要注意的是,如果需要返回worker执行的结果,必须在之前的config中配置<code>CELERY_RESULT_BACKEND</code>这个参数,一般推荐使用Redis来保存执行结果,如果不关心worker执行结果,设置<code>CELERY_IGNORE_RESULT=True</code>就可以了,关闭缓存结果可以提高程序的执行速度。<br>在上面的测试程序中,如果修改为:<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"># encoding:utf8</span><br><span class="line">__author__ = 'brianyang'</span><br><span class="line"></span><br><span class="line">import add_task</span><br><span class="line"></span><br><span class="line">result = add_task.add.(1,2)</span><br><span class="line">print type(result)</span><br><span class="line">print result</span><br></pre></td></tr></table></figure><p></p><p>输出结果为:<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><type 'int'></span><br><span class="line">3</span><br></pre></td></tr></table></figure><p></p><p>相当于直接本地调用了add方法,并没有走Celery的调度。<br>通过flower的dashbord可以方便的监控任务的执行情况:<br><img src="http://ww3.sinaimg.cn/large/b8b708a7gw1f5ld0lp454j211e07p427" alt="task list"><br><img src="http://ww3.sinaimg.cn/large/b8b708a7gw1f5ld11kqvyj20v20dhn0k" alt="task detail"><br>还可以对worker进行重启,关闭之类的操作<br><img src="http://ww3.sinaimg.cn/large/b8b708a7gw1f5ld1nfw5uj210p0a1tb0" alt="taks_op"><br>使用Celery将一个集中式的系统拆分为分布式的系统大概步骤就是:</p><ul><li>根据功能将耗时的模块拆分出来,通过注解的形式让Celery管理</li><li>为拆分的模块设置独立的消息队列</li><li>调用者导入需要的模块或方法,使用apply_async进行异步的调用并根据需求关注结果。</li><li>根据性能需要可以添加机器或增加worker数量,方便弹性管理。</li></ul><p>需要注意的是:</p><blockquote><ul><li>尽量为不同的task分配不同的queue,避免多个功能的请求堆积在同一个queue中。</li><li><code>celery -A main worker -l info -Ofair -Q add_queue</code>启动Celery时,可以通过参数Q加queue_name来指定该worker只接受指定queue中的tasks.这样可以使不同的worker各司其职。</li><li><code>CELERY_ACKS_LATE</code>可以让你的Celery更加可靠,只有当worker执行完任务后,才会告诉MQ,消息被消费。</li><li><code>CELERY_DISABLE_RATE_LIMITS</code> Celery可以对任务消费的速率进行限制,如果你没有这个需求,就关闭掉它吧,有益于会加速你的程序。</li></ul></blockquote><h3 id="tornado-celery"><a href="#tornado-celery" class="headerlink" title="tornado-celery"></a>tornado-celery</h3><p>tornado应该是python中最有名的异步非阻塞模型的web框架,它使用的是单进程轮询的方式处理用户请求,通过epoll来关注文件状态的改变,只扫描文件状态符发生变化的FD(文件描述符)。<br>由于tornado是单进程轮询模型,那么就不适合在接口请求后进行长时间的耗时操作,而是应该接收到请求后,将请求交给背后的worker去干,干完活儿后在通过修改FD告诉tornado我干完了,结果拿走吧。很明显,Celery与tornado很般配,而tornado-celery是celery官方推荐的结合两者的一个模块。<br>整合两者很容易,首先需要安装:</p><ul><li>tornado-celery</li><li>tornado-redis<br>tornado代码如下:</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"># encoding:utf8</span><br><span class="line">__author__ = 'brianyang'</span><br><span class="line"></span><br><span class="line">import tcelery</span><br><span class="line">import tornado.gen</span><br><span class="line">import tornado.web</span><br><span class="line"></span><br><span class="line">from main import app</span><br><span class="line">import add_task</span><br><span class="line"></span><br><span class="line">tcelery.setup_nonblocking_producer(celery_app=app)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">class CheckHandler(tornado.web.RequestHandler):</span><br><span class="line"> @tornado.web.asynchronous</span><br><span class="line"> @tornado.gen.coroutine</span><br><span class="line"> def get(self):</span><br><span class="line"> x = int(self.get_argument('x', '0'))</span><br><span class="line"> y = int(self.get_argument('y', '0'))</span><br><span class="line"> response = yield tornado.gen.Task(add_task.add.apply_async, args=[x, y])</span><br><span class="line"> self.write({'results': response.result})</span><br><span class="line"> self.finish</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">application = tornado.web.Application([</span><br><span class="line"> (r"/add", CheckHandler),</span><br><span class="line">])</span><br><span class="line"></span><br><span class="line">if __name__ == "__main__":</span><br><span class="line"> application.listen(8889)</span><br><span class="line"> tornado.ioloop.IOLoop.instance().start()</span><br></pre></td></tr></table></figure><p>在浏览器输入:<code>http://127.0.0.1:8889/add?x=1&y=2</code><br>结果为:<br><img src="http://ww3.sinaimg.cn/large/b8b708a7gw1f5ldt3fclhj20ap04h3yx" alt=""></p><p>通过tornado+Celery可以显著的提高系统的吞吐量。</p><h3 id="Benchmark"><a href="#Benchmark" class="headerlink" title="Benchmark"></a>Benchmark</h3><p>使用Jmeter进行压测,60个进程不间断地的访问服务器:<br>接口单独访问响应时间一般在200~400ms</p><ul><li>uwsgi + Flask方案:<br>uwsgi关键配置:<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">processes = 10</span><br><span class="line">threads = 3</span><br></pre></td></tr></table></figure></li></ul><p>Flask负责接受并处理请求,压测结果:<br>qps是46,吞吐量大概是2700/min<br><img src="http://ww3.sinaimg.cn/large/b8b708a7gw1f5ldw47khbj20zz02i75i" alt="uwsgi+Flask"></p><ul><li>tornado+Celery方案:<br>Celery配置:<br><code>CELERYD_CONCURRENCY = 10</code>也就是10个worker(进程),压测结果:<br>qps是139,吞吐量大概是8300/min<br><img src="http://ww3.sinaimg.cn/large/b8b708a7gw1f5le2vh8kpj210d0270tw" alt="tornado+Celery"><br>从吞吐量和接口相应时间各方面来看,使用tornado+Celery都能带来更好的性能。</li></ul><h3 id="Supervisor"><a href="#Supervisor" class="headerlink" title="Supervisor"></a>Supervisor</h3><ul><li>什么是supervisor<br>supervisor俗称Linux后台进程管理器</li><li>适合场景<br>– 需要长期运行程序,除了nohup,我们有更好的supervisor<br>– 程序意外挂掉,需要重启,让supervisor来帮忙<br>– 远程管理程序,不想登陆服务器,来来来,supervisor提供了高大上(屁~)的操作界面.<br>之前启动Celery命令是<code>celery -A main worker -l info -Ofair -Q common_check</code>,当你有10台机器的时候,每次更新代码后,都需要登陆服务器,然后更新代码,最后再杀掉Celery进程重启,恶不恶心,简直恶心死了。<br>让supervisor来,首先需要安装:<br><code>pip install supervisor</code><br>配置文件示例:</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line">[unix_http_server]</span><br><span class="line">file=/tmp/supervisor.sock ; path to your socket file</span><br><span class="line">chmod=0777</span><br><span class="line">username=admin</span><br><span class="line">password=admin</span><br><span class="line"></span><br><span class="line">[inet_http_server]</span><br><span class="line">port=0.0.0.0:2345</span><br><span class="line">username=admin</span><br><span class="line">password=admin</span><br><span class="line"></span><br><span class="line">[supervisord]</span><br><span class="line">logfile=/var/log/supervisord.log ; supervisord log file</span><br><span class="line">logfile_maxbytes=50MB ; maximum size of logfile before rotation</span><br><span class="line">logfile_backups=10 ; number of backed up logfiles</span><br><span class="line">loglevel=info ; info, debug, warn, trace</span><br><span class="line">pidfile=/var/run/supervisord.pid ; pidfile location</span><br><span class="line">nodaemon=false ; run supervisord as a daemon</span><br><span class="line">minfds=1024 ; number of startup file descriptors</span><br><span class="line">minprocs=200 ; number of process descriptors</span><br><span class="line">user=root ; default user</span><br><span class="line">childlogdir=/var/log/ ; where child log files will live</span><br><span class="line"></span><br><span class="line">[rpcinterface:supervisor]</span><br><span class="line">supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface</span><br><span class="line"></span><br><span class="line">[supervisorctl]</span><br><span class="line">serverurl=unix:///tmp/supervisor.sock ; use unix:// schem for a unix sockets.</span><br><span class="line">username=admin</span><br><span class="line">password=admin</span><br><span class="line">[program:celery]</span><br><span class="line">command=celery -A main worker -l info -Ofair</span><br><span class="line"></span><br><span class="line">directory=/home/q/celeryTest</span><br><span class="line">user=root</span><br><span class="line">numprocs=1</span><br><span class="line">stdout_logfile=/var/log/worker.log</span><br><span class="line">stderr_logfile=/var/log/worker.log</span><br><span class="line">autostart=true</span><br><span class="line">autorestart=true</span><br><span class="line">startsecs=10</span><br><span class="line"></span><br><span class="line">; Need to wait for currently executing tasks to finish at shutdown.</span><br><span class="line">; Increase this if you have very long running tasks.</span><br><span class="line">stopwaitsecs = 10</span><br><span class="line"></span><br><span class="line">; When resorting to send SIGKILL to the program to terminate it</span><br><span class="line">; send SIGKILL to its whole process group instead,</span><br><span class="line">; taking care of its children as well.</span><br><span class="line">killasgroup=true</span><br><span class="line"></span><br><span class="line">; Set Celery priority higher than default (999)</span><br><span class="line">; so, if rabbitmq is supervised, it will start first.</span><br><span class="line">priority=1000</span><br></pre></td></tr></table></figure><p>示例文件很长,不要怕,只需要复制下来,改改就可以<br>比较关键的几个地方是:<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[inet_http_server]</span><br><span class="line">port=0.0.0.0:2345</span><br><span class="line">username=admin</span><br><span class="line">password=admin</span><br></pre></td></tr></table></figure><p></p><p>这个可以让你通过访问<code>http://yourhost:2345</code> ,验证输入admin/admin的方式远程管理supervisor,效果如下:<br><img src="http://ww3.sinaimg.cn/large/b8b708a7gw1f5leiy45vuj20vq0a0774" alt="remote supervisor"><br><code>[program:flower]</code>这里就是你要托管给supervisor的程序的一些配置,其中<code>autorestart=true</code>可以在程序崩溃时自动重启进程,不信你用kill试试看。<br>剩下的部分就是一些日志位置的设置,当前工作目录设置等,so esay~</p><p>supervisor优点:</p><ul><li>管理进程简单,再也不用nohup & kill了。</li><li>再也不用担心程序挂掉了</li><li>web管理很方便</li></ul><p>缺点:</p><ul><li>web管理虽然方便,但是每个页面只能管理本机的supervisor,如果我有一百台机器,那就需要打开100个管理页面,很麻烦.</li></ul><p>怎么办~</p><h3 id="supervisor-easy闪亮登场"><a href="#supervisor-easy闪亮登场" class="headerlink" title="supervisor-easy闪亮登场"></a><a href="https://github.com/trytofix/supervisor-easy" rel="external nofollow" target="_blank">supervisor-easy</a>闪亮登场</h3><p>通过rpc调用获取配置中的每一个supervisor程序的状态并进行管理,可以分组,分机器进行批量/单个的管理。方便的不要不要的。来两张截图:</p><ul><li>分组管理:<br><img src="http://ww3.sinaimg.cn/large/b8b708a7gw1f5lerqg160j20vr0cetbm" alt="group"></li><li>分机器管理:<br><img src="http://ww3.sinaimg.cn/large/b8b708a7gw1f5letuuixfj20vw0bpgod" alt="server"><br>通过简单的配置,可以方便的进行管理。</li></ul></div><footer class="article-footer"><div>转载请注明来源: /</div><div class="share-container"><div class="bdsharebuttonbox"><a href="#" class="bds_more" data-cmd="more">分享到:</a> <a href="#" class="bds_evernotecn" data-cmd="evernotecn" title="保存到印象笔记">印象笔记</a> <a href="#" class="bds_youdao" data-cmd="youdao" title="分享到有道云笔记">有道云笔记</a> <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a> <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a> <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a></div><script>with(window._bd_share_config={common:{bdSnsKey:{},bdText:"",bdMini:"2",bdMiniList:!1,bdPic:"",bdStyle:"0",bdSize:"16"},share:{bdSize:16}},document)0[(getElementsByTagName("head")[0]||body).appendChild(createElement("script")).src="http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion="+~(-new Date/36e5)]</script><style>.bdshare_popup_box{border-radius:4px;border:#e1e1e1 solid 1px}.bdshare-button-style0-16 .bds_more,.bdshare-button-style0-16 a{padding-left:20px;margin:6px 10px 6px 0}.bdshare_dialog_list a,.bdshare_popup_bottom a,.bdshare_popup_list a{font-family:'Microsoft Yahei'}.bdshare_popup_top{display:none}.bdshare_popup_bottom{height:auto;padding:5px}</style></div><a href="http://trytofix.com/2016/07/07/Celery-Tornado-Supervisor构建和谐的分布式框架/#comments" class="article-comment-link ds-thread-count" data-thread-key="2016/07/07/Celery-Tornado-Supervisor构建和谐的分布式框架/">评论</a></footer></div></article><article id="post-supervisor-easy使用指南" class="article article-type-post" itemscope="" itemprop="blogPost"><div class="article-inner"><header class="article-header"><h1 itemprop="name"><a class="article-title" href="/2016/06/28/supervisor-easy使用指南/">supervisor-easy使用指南</a></h1><div class="article-meta"><div class="article-date"><i class="fa fa-calendar"></i> <a href="/2016/06/28/supervisor-easy使用指南/"><time datetime="2016-06-28T13:43:29.000Z" itemprop="datePublished">2016-06-28</time></a></div><div class="article-category"><i class="fa fa-folder"></i> <a class="article-category-link" href="/categories/supervisor/">supervisor</a></div><div class="article-tag"><i class="fa fa-tag"></i> <a class="tag-link" href="/tags/supervisor/">supervisor</a></div></div></header><div class="article-entry" itemprop="articleBody"><p>supervisor是一个python实现的可以对进程进行管理的程序,可以对托管的程序方便的进行类似重启,查看日志之类的操作,并提供了一个简单的操作界面.<br><img src="http://ww3.sinaimg.cn/large/b8b708a7gw1f5b87cx8nij20mm07k3zl" alt=""><br>但是在生产中可能会在上百台不同的服务器上通过supervisor部署程序,而supervisor默认提供的web管理工具是不能跨平台进行管理的,这对于程序的维护将会是致命的。</p><p><a href="https://github.com/trytofix/supervisor-easy" rel="external nofollow" target="_blank">supervisor-easy</a>是一个可以集中管理supervisor程序的项目。</p><p>这个项目用到了:</p><ul><li>Flask web server</li><li>bootstrap + jquery UI</li></ul><p>工具的主要特点包括:</p><ul><li>方便部署:</li></ul><p>不需要额外的数据库,缓存,仅仅需要python环境以及安装了Flask.</p><ul><li>将任何程序进行分组管理。例如可以将不同机器上执行相同功能的应用放在一个组里,可以对真个组进行管理,比如:重启,开始,停止等操作。需要做的仅仅是按照规则修改config.py文件.</li></ul><p><img src="http://ww3.sinaimg.cn/large/b8b708a7gw1f5b8krfyrcj219b0da77l" alt=""></p><ul><li>显示所有配置的主机以及他们所包含的应用。</li></ul><p>同样的,这些应用也可以批量的进行管理。</p><p><img src="http://ww3.sinaimg.cn/large/b8b708a7gw1f5b8n8i0t3j21990cb77r" alt=""></p><p>##用法</p><ul><li>git clone <a href="https://github.com/trytofix/supervisor-easy.git" rel="external nofollow" target="_blank">https://github.com/trytofix/supervisor-easy.git</a></li><li>edit config.py</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">from Server import Server</span><br><span class="line"></span><br><span class="line">SERVERS = [</span><br><span class="line"> Server(</span><br><span class="line"> name='celery1',</span><br><span class="line"> host='127.0.0.1',</span><br><span class="line"> port=12345,</span><br><span class="line"> user='admin',</span><br><span class="line"> password='admin'</span><br><span class="line"> ),</span><br><span class="line"> Server(</span><br><span class="line"> name='celery2',</span><br><span class="line"> host='remote.supervisor.com',</span><br><span class="line"> port=12345,</span><br><span class="line"> user='admin',</span><br><span class="line"> password='admin'</span><br><span class="line"> )</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line">GROUPS = [</span><br><span class="line"> {</span><br><span class="line"> 'name': 'celery',</span><br><span class="line"> 'apps': ['celery1.test:celery', 'celery2.test:celery']</span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> 'name': 'flower',</span><br><span class="line"> 'apps': ['celery1.flower']</span><br><span class="line"> }</span><br><span class="line">]</span><br></pre></td></tr></table></figure><p>上述配置中,一个Server对应的就是一个服务器上的supervisor实例,Server中的name是方便人来看的名字。</p><blockquote><p>Notice: name必须是唯一的。不能重复。</p></blockquote><p>下面是一个supervisor程序的配置文件。<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">[program:test]</span><br><span class="line">command=celery -A main worker -l info -Ofair -Q test</span><br><span class="line"></span><br><span class="line">directory=/home/q/celeryTest</span><br><span class="line">user=brianyang</span><br><span class="line">numprocs=1</span><br><span class="line">stdout_logfile=/var/log/common.log</span><br><span class="line">stderr_logfile=/var/log/common_err.log</span><br><span class="line">autostart=true</span><br><span class="line">autorestart=true</span><br><span class="line">startsecs=10</span><br><span class="line"></span><br><span class="line">killasgroup=true</span><br><span class="line"></span><br><span class="line">priority=1000</span><br><span class="line"></span><br><span class="line">[group:group1]</span><br><span class="line">programs=celery,test</span><br></pre></td></tr></table></figure><p></p><p>对照这个配置文件来讲解GROUPS</p><ul><li><em>GROUPS</em> 可以将任何的应用分到一组进行批量管理.</li><li><em>apps</em> 是分组中要包含应用的列表.</li><li>‘apps’中的每个字符串的定义为 <code>server_name.group_name:application_name</code>.</li><li><em>application_name</em> 对应supervisord.conf中’[program:test]’ 里的’test’.</li><li><em>group_name</em>对应supervisord.conf中’[group:group1]’ 中的’group1’.</li><li><em>server_name</em> 就是之前在SERVERS中定义的某个Server的name.</li></ul><h2 id="运行-python-webui-py测试项目。"><a href="#运行-python-webui-py测试项目。" class="headerlink" title="运行: python webui.py测试项目。"></a>运行: <code>python webui.py</code>测试项目。</h2><blockquote><p>不要在生产环境中使用 <code>python webui.py</code> 。 更好的做法是使用一种常用的uwsgi服务器,例如uwsgi.</p></blockquote><h2 id="下一步要做的"><a href="#下一步要做的" class="headerlink" title="下一步要做的"></a>下一步要做的</h2><ul><li>性能提升</li><li>UI提升</li><li>异常处理</li></ul></div><footer class="article-footer"><div>转载请注明来源: /</div><div class="share-container"><div class="bdsharebuttonbox"><a href="#" class="bds_more" data-cmd="more">分享到:</a> <a href="#" class="bds_evernotecn" data-cmd="evernotecn" title="保存到印象笔记">印象笔记</a> <a href="#" class="bds_youdao" data-cmd="youdao" title="分享到有道云笔记">有道云笔记</a> <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a> <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a> <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a></div><script>with(window._bd_share_config={common:{bdSnsKey:{},bdText:"",bdMini:"2",bdMiniList:!1,bdPic:"",bdStyle:"0",bdSize:"16"},share:{bdSize:16}},document)0[(getElementsByTagName("head")[0]||body).appendChild(createElement("script")).src="http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion="+~(-new Date/36e5)]</script><style>.bdshare_popup_box{border-radius:4px;border:#e1e1e1 solid 1px}.bdshare-button-style0-16 .bds_more,.bdshare-button-style0-16 a{padding-left:20px;margin:6px 10px 6px 0}.bdshare_dialog_list a,.bdshare_popup_bottom a,.bdshare_popup_list a{font-family:'Microsoft Yahei'}.bdshare_popup_top{display:none}.bdshare_popup_bottom{height:auto;padding:5px}</style></div><a href="http://trytofix.com/2016/06/28/supervisor-easy使用指南/#comments" class="article-comment-link ds-thread-count" data-thread-key="2016/06/28/supervisor-easy使用指南/">评论</a></footer></div></article><article id="post-RabbitMQ浅读" class="article article-type-post" itemscope="" itemprop="blogPost"><div class="article-inner"><header class="article-header"><h1 itemprop="name"><a class="article-title" href="/2016/05/12/RabbitMQ浅读/">RabbitMQ浅读</a></h1><div class="article-meta"><div class="article-date"><i class="fa fa-calendar"></i> <a href="/2016/05/12/RabbitMQ浅读/"><time datetime="2016-05-12T02:45:29.000Z" itemprop="datePublished">2016-05-12</time></a></div><div class="article-category"><i class="fa fa-folder"></i> <a class="article-category-link" href="/categories/RabbitMQ/">RabbitMQ</a></div></div></header><div class="article-entry" itemprop="articleBody"><p></p><h1 id="消息分发策略"><a href="#消息分发策略" class="headerlink" title="消息分发策略"></a>消息分发策略</h1><p>当有多个消费者时,RabbitMQ将会轮流的将消息发送给消费者.这种分发消息的方式称为’round-robin’<br>看例子<br>sender.py<br></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># encoding:utf8</span></span><br><span class="line">__author__ = <span class="string">'brianyang'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> pika</span><br><span class="line"></span><br><span class="line">connection = pika.BlockingConnection(pika.ConnectionParameters(host=<span class="string">'localhost'</span>))</span><br><span class="line"></span><br><span class="line">channel = connection.channel()</span><br><span class="line"></span><br><span class="line">channel.queue_declare(queue=<span class="string">'hello'</span>)</span><br><span class="line"></span><br><span class="line">channel.basic_publish(exchange=<span class="string">''</span>,</span><br><span class="line"> routing_key=<span class="string">'hello'</span>,</span><br><span class="line"> body=sys.argv[<span class="number">1</span>])</span><br><span class="line"></span><br><span class="line"><span class="keyword">print</span> <span class="string">'send done'</span></span><br><span class="line">connection.close()</span><br></pre></td></tr></table></figure><p></p><p>receiver.py<br></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># encoding:utf8</span></span><br><span class="line">__author__ = <span class="string">'brianyang'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> pika</span><br><span class="line"></span><br><span class="line">connection = pika.BlockingConnection(pika.ConnectionParameters(host=<span class="string">'localhost'</span>))</span><br><span class="line">channel = connection.channel()</span><br><span class="line"></span><br><span class="line">channel.queue_declare(<span class="string">'hello'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">callback</span><span class="params">(ch, method, prop, body)</span>:</span></span><br><span class="line"> <span class="keyword">print</span> body</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">channel.basic_consume(callback, queue=<span class="string">'hello'</span>, no_ack=<span class="keyword">True</span>)</span><br><span class="line">channel.start_consuming()</span><br><span class="line">connection.close()</span><br></pre></td></tr></table></figure><p></p><p>运行两个消费者<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">shell1$ python receiver.py</span><br></pre></td></tr></table></figure><p></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">shell2$ python receiver.py</span><br></pre></td></tr></table></figure><p>发送消息<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">python sender.py msg1</span><br><span class="line">python sender.py msg2</span><br><span class="line">python sender.py msg3</span><br><span class="line">python sender.py msg4</span><br><span class="line">python sender.py msg5</span><br><span class="line">python sender.py msg6</span><br></pre></td></tr></table></figure><p></p><p>生产者收到的内容为<br>receiver1<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">shell1$ msg1</span><br><span class="line">shell1$ msg3</span><br><span class="line">shell1$ msg5</span><br></pre></td></tr></table></figure><p></p><p>receiver2<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">shell1$ msg2</span><br><span class="line">shell1$ msg4</span><br><span class="line">shell1$ msg6</span><br></pre></td></tr></table></figure><p></p><p></p><p class="article-more-link"><a href="/2016/05/12/RabbitMQ浅读/#more">查看更多</a></p></div><footer class="article-footer"><div>转载请注明来源: /</div><div class="share-container"><div class="bdsharebuttonbox"><a href="#" class="bds_more" data-cmd="more">分享到:</a> <a href="#" class="bds_evernotecn" data-cmd="evernotecn" title="保存到印象笔记">印象笔记</a> <a href="#" class="bds_youdao" data-cmd="youdao" title="分享到有道云笔记">有道云笔记</a> <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a> <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a> <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a></div><script>with(window._bd_share_config={common:{bdSnsKey:{},bdText:"",bdMini:"2",bdMiniList:!1,bdPic:"",bdStyle:"0",bdSize:"16"},share:{bdSize:16}},document)0[(getElementsByTagName("head")[0]||body).appendChild(createElement("script")).src="http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion="+~(-new Date/36e5)]</script><style>.bdshare_popup_box{border-radius:4px;border:#e1e1e1 solid 1px}.bdshare-button-style0-16 .bds_more,.bdshare-button-style0-16 a{padding-left:20px;margin:6px 10px 6px 0}.bdshare_dialog_list a,.bdshare_popup_bottom a,.bdshare_popup_list a{font-family:'Microsoft Yahei'}.bdshare_popup_top{display:none}.bdshare_popup_bottom{height:auto;padding:5px}</style></div><a href="http://trytofix.com/2016/05/12/RabbitMQ浅读/#comments" class="article-comment-link ds-thread-count" data-thread-key="2016/05/12/RabbitMQ浅读/">评论</a></footer></div></article><article id="post-Flask中使用装饰器遇到的问题AssertionError-View-function-mapping-is-overwriting-an-existing-endpoint-function" class="article article-type-post" itemscope="" itemprop="blogPost"><div class="article-inner"><header class="article-header"><h1 itemprop="name"><a class="article-title" href="/2016/05/05/Flask中使用装饰器遇到的问题AssertionError-View-function-mapping-is-overwriting-an-existing-endpoint-function/">Flask中使用装饰器遇到的问题AssertionError: View function mapping is overwriting an existing endpoint function</a></h1><div class="article-meta"><div class="article-date"><i class="fa fa-calendar"></i> <a href="/2016/05/05/Flask中使用装饰器遇到的问题AssertionError-View-function-mapping-is-overwriting-an-existing-endpoint-function/"><time datetime="2016-05-05T07:43:25.000Z" itemprop="datePublished">2016-05-05</time></a></div><div class="article-category"><i class="fa fa-folder"></i> <a class="article-category-link" href="/categories/python/">python</a></div><div class="article-tag"><i class="fa fa-tag"></i> <a class="tag-link" href="/tags/Flask/">Flask</a></div></div></header><div class="article-entry" itemprop="articleBody"><p></p><p>在生产中有几个api需要用户认证才可以访问,最初的做法是在每个方法最前面写一段相同的代码来验证身份,这种通用的功能更适合提炼出来而不是在每个方法中都粘贴一份.</p><p>python支持的装饰器可以扮演拦截器的角色,将验证身份的代码放入到装饰器中,并为需要的方法添加装饰器是一个更好的做法.</p><p>首先定义一个装饰器auth_util.py<br></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">check_auth_wrapper</span><span class="params">(self, func)</span>:</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">wrapper</span><span class="params">(*args, **kwargs)</span>:</span></span><br><span class="line"> uid = checkuserislogin(request)</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> uid:</span><br><span class="line"> <span class="keyword">return</span> make_redirect(request)</span><br><span class="line"> admin = self.check_auth(uid)</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> admin:</span><br><span class="line"> <span class="keyword">return</span> make_redirect(request, url=<span class="string">'/'</span>)</span><br><span class="line"> <span class="keyword">return</span> func(*args, **kwargs)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> wrapper</span><br></pre></td></tr></table></figure><p></p><p>使用时<br></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@web_api.route("/alert/<alert_id>/delete")</span></span><br><span class="line"><span class="meta">@auth_util.check_auth_wrapper</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">alert_delete</span><span class="params">(alert_id)</span>:</span></span><br><span class="line"> del_alert(alert_id)</span><br><span class="line"> <span class="keyword">return</span> <span class="string">'delete success'</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@web_api.route('/alert/')</span></span><br><span class="line"><span class="meta">@auth_util.check_auth_wrapper</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">alert_index</span><span class="params">()</span>:</span></span><br><span class="line"> <span class="keyword">return</span> render_template(<span class="string">'alert_index.html'</span>)</span><br></pre></td></tr></table></figure><p></p><p>启动程序时会报错<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">Traceback (most recent call last):</span><br><span class="line"> File "/home/q/www/api/all_webui.py", line 22, in <module></span><br><span class="line"> app.register_blueprint(routecheck_api)</span><br><span class="line"> File "/usr/local/lib/python2.7/dist-packages/Flask-0.10.1-py2.7.egg/flask/app.py", line 62, in wrapper_func</span><br><span class="line"> return f(self, *args, **kwargs)</span><br><span class="line"> File "/usr/local/lib/python2.7/dist-packages/Flask-0.10.1-py2.7.egg/flask/app.py", line 889, in register_blueprint</span><br><span class="line"> blueprint.register(self, options, first_registration)</span><br><span class="line"> File "/usr/local/lib/python2.7/dist-packages/Flask-0.10.1-py2.7.egg/flask/blueprints.py", line 153, in register</span><br><span class="line"> deferred(state)</span><br><span class="line"> File "/usr/local/lib/python2.7/dist-packages/Flask-0.10.1-py2.7.egg/flask/blueprints.py", line 172, in <lambda></span><br><span class="line"> s.add_url_rule(rule, endpoint, view_func, **options))</span><br><span class="line"> File "/usr/local/lib/python2.7/dist-packages/Flask-0.10.1-py2.7.egg/flask/blueprints.py", line 76, in add_url_rule</span><br><span class="line"> view_func, defaults=defaults, **options)</span><br><span class="line"> File "/usr/local/lib/python2.7/dist-packages/Flask-0.10.1-py2.7.egg/flask/app.py", line 62, in wrapper_func</span><br><span class="line"> return f(self, *args, **kwargs)</span><br><span class="line"> File "/usr/local/lib/python2.7/dist-packages/Flask-0.10.1-py2.7.egg/flask/app.py", line 984, in add_url_rule</span><br><span class="line"> 'existing endpoint function: %s' % endpoint)</span><br><span class="line">AssertionError: View function mapping is overwriting an existing endpoint function: /home/q/www/route_web/apis/routecheck/routecheck_webui.pyc.wrapper</span><br></pre></td></tr></table></figure><p></p><p></p><p class="article-more-link"><a href="/2016/05/05/Flask中使用装饰器遇到的问题AssertionError-View-function-mapping-is-overwriting-an-existing-endpoint-function/#more">查看更多</a></p></div><footer class="article-footer"><div>转载请注明来源: /</div><div class="share-container"><div class="bdsharebuttonbox"><a href="#" class="bds_more" data-cmd="more">分享到:</a> <a href="#" class="bds_evernotecn" data-cmd="evernotecn" title="保存到印象笔记">印象笔记</a> <a href="#" class="bds_youdao" data-cmd="youdao" title="分享到有道云笔记">有道云笔记</a> <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a> <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a> <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a></div><script>with(window._bd_share_config={common:{bdSnsKey:{},bdText:"",bdMini:"2",bdMiniList:!1,bdPic:"",bdStyle:"0",bdSize:"16"},share:{bdSize:16}},document)0[(getElementsByTagName("head")[0]||body).appendChild(createElement("script")).src="http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion="+~(-new Date/36e5)]</script><style>.bdshare_popup_box{border-radius:4px;border:#e1e1e1 solid 1px}.bdshare-button-style0-16 .bds_more,.bdshare-button-style0-16 a{padding-left:20px;margin:6px 10px 6px 0}.bdshare_dialog_list a,.bdshare_popup_bottom a,.bdshare_popup_list a{font-family:'Microsoft Yahei'}.bdshare_popup_top{display:none}.bdshare_popup_bottom{height:auto;padding:5px}</style></div><a href="http://trytofix.com/2016/05/05/Flask中使用装饰器遇到的问题AssertionError-View-function-mapping-is-overwriting-an-existing-endpoint-function/#comments" class="article-comment-link ds-thread-count" data-thread-key="2016/05/05/Flask中使用装饰器遇到的问题AssertionError-View-function-mapping-is-overwriting-an-existing-endpoint-function/">评论</a></footer></div></article><article id="post-PG语法汇总" class="article article-type-post" itemscope="" itemprop="blogPost"><div class="article-inner"><header class="article-header"><h1 itemprop="name"><a class="article-title" href="/2016/05/05/PG语法汇总/">PG语法汇总</a></h1><div class="article-meta"><div class="article-date"><i class="fa fa-calendar"></i> <a href="/2016/05/05/PG语法汇总/"><time datetime="2016-05-05T06:43:08.000Z" itemprop="datePublished">2016-05-05</time></a></div><div class="article-category"><i class="fa fa-folder"></i> <a class="article-category-link" href="/categories/数据库/">数据库</a></div><div class="article-tag"><i class="fa fa-tag"></i> <a class="tag-link" href="/tags/PostgreSQL/">PostgreSQL</a></div></div></header><div class="article-entry" itemprop="articleBody"><p>假如test表中type字段的格式xxxx:yyyy:zzzz,需要取到以’:’为分隔符将type字段进行分割后的第一部分也就是xxxx的内容进行分组并排序<br></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> split_part(<span class="keyword">type</span>,<span class="string">':'</span>,<span class="number">1</span>) <span class="keyword">as</span> atype, <span class="keyword">count</span>(<span class="number">1</span>) <span class="keyword">as</span> <span class="keyword">count</span> <span class="keyword">from</span> <span class="keyword">test</span> <span class="keyword">group</span> <span class="keyword">by</span> atype <span class="keyword">order</span> <span class="keyword">by</span> <span class="keyword">count</span> <span class="keyword">desc</span></span><br></pre></td></tr></table></figure><p></p><p>替换type中的xxxx:yyyy:zzzz为xxxx,yyyy,zzzz<br></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="keyword">replace</span>(<span class="keyword">type</span>,<span class="string">':'</span>, <span class="string">','</span>) <span class="keyword">as</span> <span class="keyword">type</span> <span class="keyword">from</span> <span class="keyword">test</span>;</span><br></pre></td></tr></table></figure><p></p><p>依此计算返回式的值,遇到非null值就返回<br></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="keyword">coalesce</span>(<span class="literal">null</span>, <span class="keyword">type</span>) <span class="keyword">from</span> <span class="keyword">type</span> <span class="keyword">from</span> <span class="keyword">test</span>;</span><br></pre></td></tr></table></figure><p></p></div><footer class="article-footer"><div>转载请注明来源: /</div><div class="share-container"><div class="bdsharebuttonbox"><a href="#" class="bds_more" data-cmd="more">分享到:</a> <a href="#" class="bds_evernotecn" data-cmd="evernotecn" title="保存到印象笔记">印象笔记</a> <a href="#" class="bds_youdao" data-cmd="youdao" title="分享到有道云笔记">有道云笔记</a> <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a> <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a> <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a></div><script>with(window._bd_share_config={common:{bdSnsKey:{},bdText:"",bdMini:"2",bdMiniList:!1,bdPic:"",bdStyle:"0",bdSize:"16"},share:{bdSize:16}},document)0[(getElementsByTagName("head")[0]||body).appendChild(createElement("script")).src="http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion="+~(-new Date/36e5)]</script><style>.bdshare_popup_box{border-radius:4px;border:#e1e1e1 solid 1px}.bdshare-button-style0-16 .bds_more,.bdshare-button-style0-16 a{padding-left:20px;margin:6px 10px 6px 0}.bdshare_dialog_list a,.bdshare_popup_bottom a,.bdshare_popup_list a{font-family:'Microsoft Yahei'}.bdshare_popup_top{display:none}.bdshare_popup_bottom{height:auto;padding:5px}</style></div><a href="http://trytofix.com/2016/05/05/PG语法汇总/#comments" class="article-comment-link ds-thread-count" data-thread-key="2016/05/05/PG语法汇总/">评论</a></footer></div></article><article id="post-solr查询语法积累" class="article article-type-post" itemscope="" itemprop="blogPost"><div class="article-inner"><header class="article-header"><h1 itemprop="name"><a class="article-title" href="/2016/05/05/solr查询语法积累/">solr查询语法积累</a></h1><div class="article-meta"><div class="article-date"><i class="fa fa-calendar"></i> <a href="/2016/05/05/solr查询语法积累/"><time datetime="2016-05-05T06:31:02.000Z" itemprop="datePublished">2016-05-05</time></a></div><div class="article-category"><i class="fa fa-folder"></i> <a class="article-category-link" href="/categories/Solr/">Solr</a></div><div class="article-tag"><i class="fa fa-tag"></i> <a class="tag-link" href="/tags/搜索引擎/">搜索引擎</a></div></div></header><div class="article-entry" itemprop="articleBody"><h3 id="查询某个字段包含某个关键字"><a href="#查询某个字段包含某个关键字" class="headerlink" title="查询某个字段包含某个关键字"></a>查询某个字段包含某个关键字</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">q=cities:北京</span><br></pre></td></tr></table></figure><h3 id="查询某个字段不包含某些关键字"><a href="#查询某个字段不包含某些关键字" class="headerlink" title="查询某个字段不包含某些关键字"></a>查询某个字段不包含某些关键字</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">q=cities:* NOT 上海 NOT 北京 NOT 黔南 NOT 三亚</span><br></pre></td></tr></table></figure><h3 id="分组查询"><a href="#分组查询" class="headerlink" title="分组查询"></a>分组查询</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://localhost/searchapi/search_engine/select?q=name:brian*&fl=id,name&rows=5000&wt=json&indent=true&group=true&group.field=groupid&group.offset=5&group.limit=10&group.ngroups=true&group.sort=feed_time%20desc</span><br></pre></td></tr></table></figure></div><footer class="article-footer"><div>转载请注明来源: /</div><div class="share-container"><div class="bdsharebuttonbox"><a href="#" class="bds_more" data-cmd="more">分享到:</a> <a href="#" class="bds_evernotecn" data-cmd="evernotecn" title="保存到印象笔记">印象笔记</a> <a href="#" class="bds_youdao" data-cmd="youdao" title="分享到有道云笔记">有道云笔记</a> <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a> <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a> <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a></div><script>with(window._bd_share_config={common:{bdSnsKey:{},bdText:"",bdMini:"2",bdMiniList:!1,bdPic:"",bdStyle:"0",bdSize:"16"},share:{bdSize:16}},document)0[(getElementsByTagName("head")[0]||body).appendChild(createElement("script")).src="http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion="+~(-new Date/36e5)]</script><style>.bdshare_popup_box{border-radius:4px;border:#e1e1e1 solid 1px}.bdshare-button-style0-16 .bds_more,.bdshare-button-style0-16 a{padding-left:20px;margin:6px 10px 6px 0}.bdshare_dialog_list a,.bdshare_popup_bottom a,.bdshare_popup_list a{font-family:'Microsoft Yahei'}.bdshare_popup_top{display:none}.bdshare_popup_bottom{height:auto;padding:5px}</style></div><a href="http://trytofix.com/2016/05/05/solr查询语法积累/#comments" class="article-comment-link ds-thread-count" data-thread-key="2016/05/05/solr查询语法积累/">评论</a></footer></div></article><article id="post-xclip操作剪切板" class="article article-type-post" itemscope="" itemprop="blogPost"><div class="article-inner"><header class="article-header"><h1 itemprop="name"><a class="article-title" href="/2016/05/05/xclip操作剪切板/">xclip操作剪切板</a></h1><div class="article-meta"><div class="article-date"><i class="fa fa-calendar"></i> <a href="/2016/05/05/xclip操作剪切板/"><time datetime="2016-05-05T05:53:25.000Z" itemprop="datePublished">2016-05-05</time></a></div><div class="article-category"><i class="fa fa-folder"></i> <a class="article-category-link" href="/categories/Linux/">Linux</a></div><div class="article-tag"><i class="fa fa-tag"></i> <a class="tag-link" href="/tags/Command-Line/">Command Line</a></div></div></header><div class="article-entry" itemprop="articleBody"><blockquote><p>Reads from standard in, or from one or more files, and makes the data<br>available as an X selection for pasting into X applications. Prints<br>current X selection to standard out.</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get install xclip</span><br></pre></td></tr></table></figure><p>使用xclip可以从标准输入,文件读取内容存入到剪切板中,也可以将剪切板中的内容输出到标准输出中.</p><p>例子:</p><ul><li><p>将当前系统运行状态复制到剪切板(默认是xlip的剪切板,不是系统剪切板,所以使用ctrl+v无效</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uptime | xclip</span><br></pre></td></tr></table></figure></li><li><p>输出剪切板中的内容</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xclip -o</span><br></pre></td></tr></table></figure></li><li><p>将当前系统运行状态复制到系统剪切板中</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">uptime | xclip -selection clipboard</span><br><span class="line">uptime | xclip -selection clip</span><br></pre></td></tr></table></figure></li><li><p>从系统剪切板中获取内容ctrl+v或者</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">xclip -o -selection clipboard</span><br><span class="line">xclip -o -selection clip</span><br></pre></td></tr></table></figure></li><li><p>将文件复制到剪切板</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xclip /etc/profile</span><br></pre></td></tr></table></figure></li><li><p>将剪切板中的图片保存到文件</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xclip -selection clip -t image/png -o > /tmp/snapshot.png</span><br></pre></td></tr></table></figure></li><li><p>指定文件只允许被复制十次</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xclip -l 10 -verbose -selection clip /etc/profile</span><br></pre></td></tr></table></figure></li></ul></div><footer class="article-footer"><div>转载请注明来源: /</div><div class="share-container"><div class="bdsharebuttonbox"><a href="#" class="bds_more" data-cmd="more">分享到:</a> <a href="#" class="bds_evernotecn" data-cmd="evernotecn" title="保存到印象笔记">印象笔记</a> <a href="#" class="bds_youdao" data-cmd="youdao" title="分享到有道云笔记">有道云笔记</a> <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a> <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a> <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a></div><script>with(window._bd_share_config={common:{bdSnsKey:{},bdText:"",bdMini:"2",bdMiniList:!1,bdPic:"",bdStyle:"0",bdSize:"16"},share:{bdSize:16}},document)0[(getElementsByTagName("head")[0]||body).appendChild(createElement("script")).src="http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion="+~(-new Date/36e5)]</script><style>.bdshare_popup_box{border-radius:4px;border:#e1e1e1 solid 1px}.bdshare-button-style0-16 .bds_more,.bdshare-button-style0-16 a{padding-left:20px;margin:6px 10px 6px 0}.bdshare_dialog_list a,.bdshare_popup_bottom a,.bdshare_popup_list a{font-family:'Microsoft Yahei'}.bdshare_popup_top{display:none}.bdshare_popup_bottom{height:auto;padding:5px}</style></div><a href="http://trytofix.com/2016/05/05/xclip操作剪切板/#comments" class="article-comment-link ds-thread-count" data-thread-key="2016/05/05/xclip操作剪切板/">评论</a></footer></div></article><article id="post-Linux-Gnome下录制Gif动图" class="article article-type-post" itemscope="" itemprop="blogPost"><div class="article-inner"><header class="article-header"><h1 itemprop="name"><a class="article-title" href="/2016/05/05/Linux-Gnome下录制Gif动图/">Linux Gnome下录制Gif动图</a></h1><div class="article-meta"><div class="article-date"><i class="fa fa-calendar"></i> <a href="/2016/05/05/Linux-Gnome下录制Gif动图/"><time datetime="2016-05-05T04:02:07.000Z" itemprop="datePublished">2016-05-05</time></a></div><div class="article-category"><i class="fa fa-folder"></i> <a class="article-category-link" href="/categories/Linux/">Linux</a></div><div class="article-tag"><i class="fa fa-tag"></i> <a class="tag-link" href="/tags/Command-Line/">Command Line</a></div></div></header><div class="article-entry" itemprop="articleBody"><p>安装</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get install byzanz</span><br></pre></td></tr></table></figure><p>使用</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">#录制全屏,时间为35秒,保存到byzanz-demo.gif中</span><br><span class="line">byzanz-record -d 35 -x 0 -y 0 byzanz-demo.gif</span><br></pre></td></tr></table></figure><ul><li>-d 录制时间</li><li>-x 左上角x轴坐标</li><li>-y 左上角y轴坐标</li><li>-w 录制区域的宽度</li><li>-h 录制区域的高度</li><li>-c 记录鼠标指针</li></ul><p>更多用法参照:<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">man byzanz-record</span><br></pre></td></tr></table></figure><p></p></div><footer class="article-footer"><div>转载请注明来源: /</div><div class="share-container"><div class="bdsharebuttonbox"><a href="#" class="bds_more" data-cmd="more">分享到:</a> <a href="#" class="bds_evernotecn" data-cmd="evernotecn" title="保存到印象笔记">印象笔记</a> <a href="#" class="bds_youdao" data-cmd="youdao" title="分享到有道云笔记">有道云笔记</a> <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a> <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a> <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a></div><script>with(window._bd_share_config={common:{bdSnsKey:{},bdText:"",bdMini:"2",bdMiniList:!1,bdPic:"",bdStyle:"0",bdSize:"16"},share:{bdSize:16}},document)0[(getElementsByTagName("head")[0]||body).appendChild(createElement("script")).src="http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion="+~(-new Date/36e5)]</script><style>.bdshare_popup_box{border-radius:4px;border:#e1e1e1 solid 1px}.bdshare-button-style0-16 .bds_more,.bdshare-button-style0-16 a{padding-left:20px;margin:6px 10px 6px 0}.bdshare_dialog_list a,.bdshare_popup_bottom a,.bdshare_popup_list a{font-family:'Microsoft Yahei'}.bdshare_popup_top{display:none}.bdshare_popup_bottom{height:auto;padding:5px}</style></div><a href="http://trytofix.com/2016/05/05/Linux-Gnome下录制Gif动图/#comments" class="article-comment-link ds-thread-count" data-thread-key="2016/05/05/Linux-Gnome下录制Gif动图/">评论</a></footer></div></article><article id="post-gnome-screenshot-ubuntu-gnome截图" class="article article-type-post" itemscope="" itemprop="blogPost"><div class="article-inner"><header class="article-header"><h1 itemprop="name"><a class="article-title" href="/2016/05/05/gnome-screenshot-ubuntu-gnome截图/">gnome-screenshot ubuntu gnome截图</a></h1><div class="article-meta"><div class="article-date"><i class="fa fa-calendar"></i> <a href="/2016/05/05/gnome-screenshot-ubuntu-gnome截图/"><time datetime="2016-05-05T03:37:10.000Z" itemprop="datePublished">2016-05-05</time></a></div><div class="article-category"><i class="fa fa-folder"></i> <a class="article-category-link" href="/categories/Linux/">Linux</a></div><div class="article-tag"><i class="fa fa-tag"></i> <a class="tag-link" href="/tags/Command-Line/">Command Line</a></div></div></header><div class="article-entry" itemprop="articleBody"><p>首先看下官方说明</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">gnome-screenshot is a GNOME utility for taking screenshots of the</span><br><span class="line">entire screen, a window or an user-defined area of the screen, with</span><br><span class="line">optional beautifying border effects</span><br></pre></td></tr></table></figure><p>在gnome桌面的应用程序->附件->截图使用的就是gnome-screenshot.</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">gnome-screenshot -a #截取一个区域</span><br><span class="line">gnome-screenshot -a -c #截取一个区域并保存到剪切板</span><br><span class="line">gnome-screenshot -w -c #截取当前活动窗口并保存到剪切板</span><br><span class="line">gnome-screenshot -w -p #截取当前活动窗口并保存鼠标指针</span><br><span class="line">gnome-screenshot -i #弹出交互式的窗体</span><br><span class="line">gnome-screenshot -a -f /tmp/test.png #截取一个区域保存到/tmp/test.png中.</span><br></pre></td></tr></table></figure><p>-c 与 -f 同时使用时只会保存到剪切板中(ubuntu14.04亲测)</p><p>更多用法参见</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">man gnome-screenshot</span><br></pre></td></tr></table></figure></div><footer class="article-footer"><div>转载请注明来源: /</div><div class="share-container"><div class="bdsharebuttonbox"><a href="#" class="bds_more" data-cmd="more">分享到:</a> <a href="#" class="bds_evernotecn" data-cmd="evernotecn" title="保存到印象笔记">印象笔记</a> <a href="#" class="bds_youdao" data-cmd="youdao" title="分享到有道云笔记">有道云笔记</a> <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a> <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a> <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a></div><script>with(window._bd_share_config={common:{bdSnsKey:{},bdText:"",bdMini:"2",bdMiniList:!1,bdPic:"",bdStyle:"0",bdSize:"16"},share:{bdSize:16}},document)0[(getElementsByTagName("head")[0]||body).appendChild(createElement("script")).src="http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion="+~(-new Date/36e5)]</script><style>.bdshare_popup_box{border-radius:4px;border:#e1e1e1 solid 1px}.bdshare-button-style0-16 .bds_more,.bdshare-button-style0-16 a{padding-left:20px;margin:6px 10px 6px 0}.bdshare_dialog_list a,.bdshare_popup_bottom a,.bdshare_popup_list a{font-family:'Microsoft Yahei'}.bdshare_popup_top{display:none}.bdshare_popup_bottom{height:auto;padding:5px}</style></div><a href="http://trytofix.com/2016/05/05/gnome-screenshot-ubuntu-gnome截图/#comments" class="article-comment-link ds-thread-count" data-thread-key="2016/05/05/gnome-screenshot-ubuntu-gnome截图/">评论</a></footer></div></article><article id="post-markdown使用截图以及图床优化写作体验" class="article article-type-post" itemscope="" itemprop="blogPost"><div class="article-inner"><header class="article-header"><h1 itemprop="name"><a class="article-title" href="/2016/05/04/markdown使用截图以及图床优化写作体验/">markdown使用截图以及图床优化写作体验</a></h1><div class="article-meta"><div class="article-date"><i class="fa fa-calendar"></i> <a href="/2016/05/04/markdown使用截图以及图床优化写作体验/"><time datetime="2016-05-04T09:39:07.000Z" itemprop="datePublished">2016-05-04</time></a></div><div class="article-category"><i class="fa fa-folder"></i> <a class="article-category-link" href="/categories/Linux/">Linux</a></div><div class="article-tag"><i class="fa fa-tag"></i> <a class="tag-link" href="/tags/Command-Line/">Command Line</a>, <a class="tag-link" href="/tags/hexo/">hexo</a>, <a class="tag-link" href="/tags/markdown/">markdown</a></div></div></header><div class="article-entry" itemprop="articleBody"><p></p><p>使用方法,截图+粘贴</p><p>在之前,使用markdown插入截图时,通常需要:</p><ul><li>使用截图工具,截图并保存</li><li>将截图保存到工作目录</li><li>使用markdown语法引入图片<br>如果需要图床,需要将图片上传到图床,再将图床的url引入markdown</li></ul><p>使用优化后的方法仅仅需要:</p><ul><li>截图</li><li>随意粘贴图床地址/图片本地路径<p></p><p class="article-more-link"><a href="/2016/05/04/markdown使用截图以及图床优化写作体验/#more">查看更多</a></p></li></ul></div><footer class="article-footer"><div>转载请注明来源: /</div><div class="share-container"><div class="bdsharebuttonbox"><a href="#" class="bds_more" data-cmd="more">分享到:</a> <a href="#" class="bds_evernotecn" data-cmd="evernotecn" title="保存到印象笔记">印象笔记</a> <a href="#" class="bds_youdao" data-cmd="youdao" title="分享到有道云笔记">有道云笔记</a> <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a> <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a> <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a></div><script>with(window._bd_share_config={common:{bdSnsKey:{},bdText:"",bdMini:"2",bdMiniList:!1,bdPic:"",bdStyle:"0",bdSize:"16"},share:{bdSize:16}},document)0[(getElementsByTagName("head")[0]||body).appendChild(createElement("script")).src="http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion="+~(-new Date/36e5)]</script><style>.bdshare_popup_box{border-radius:4px;border:#e1e1e1 solid 1px}.bdshare-button-style0-16 .bds_more,.bdshare-button-style0-16 a{padding-left:20px;margin:6px 10px 6px 0}.bdshare_dialog_list a,.bdshare_popup_bottom a,.bdshare_popup_list a{font-family:'Microsoft Yahei'}.bdshare_popup_top{display:none}.bdshare_popup_bottom{height:auto;padding:5px}</style></div><a href="http://trytofix.com/2016/05/04/markdown使用截图以及图床优化写作体验/#comments" class="article-comment-link ds-thread-count" data-thread-key="2016/05/04/markdown使用截图以及图床优化写作体验/">评论</a></footer></div></article><nav id="page-nav"><span class="page-number current">1</span><a class="page-number" href="/page/2/">2</a><a class="page-number" href="/page/3/">3</a><span class="space">…</span><a class="page-number" href="/page/8/">8</a><a class="extend next" rel="next" href="/page/2/">下一页 »</a></nav></section><aside id="sidebar"><div class="widget-wrap"><h3 class="widget-title">分类</h3><div class="widget"><ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/AngularJs/">AngularJs</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Git/">Git</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Java/">Java</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Linux/">Linux</a><span class="category-list-count">15</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Nginx/">Nginx</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/NoSQL/">NoSQL</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/RabbitMQ/">RabbitMQ</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Solr/">Solr</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/hexo/">hexo</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/python/">python</a><span class="category-list-count">34</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/supervisor/">supervisor</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/前端/">前端</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/工具/">工具</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/数据库/">数据库</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/框架/">框架</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/测试/">测试</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/生活/">生活</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/随手记/">随手记</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/项目总结/">项目总结</a><span class="category-list-count">1</span></li></ul></div></div><div class="widget-wrap"><h3 class="widget-title">标签云</h3><div class="widget tagcloud"><a href="/tags/http/" style="font-size:10px">$http</a> <a href="/tags/404/" style="font-size:10px">404</a> <a href="/tags/Command-Line/" style="font-size:16px">Command Line</a> <a href="/tags/DDL/" style="font-size:10px">DDL</a> <a href="/tags/FTP/" style="font-size:10px">FTP</a> <a href="/tags/Flask/" style="font-size:18px">Flask</a> <a href="/tags/Hexo系列/" style="font-size:10px">Hexo系列</a> <a href="/tags/Jedis/" style="font-size:10px">Jedis</a> <a href="/tags/Jinja2/" style="font-size:12px">Jinja2</a> <a href="/tags/Linux-Command/" style="font-size:20px">Linux Command</a> <a href="/tags/MIME/" style="font-size:10px">MIME</a> <a href="/tags/MySQL/" style="font-size:12px">MySQL</a> <a href="/tags/Nginx/" style="font-size:10px">Nginx</a> <a href="/tags/PostgreSQL/" style="font-size:14px">PostgreSQL</a> <a href="/tags/Redis/" style="font-size:12px">Redis</a> <a href="/tags/SQL/" style="font-size:10px">SQL</a> <a href="/tags/SQLAlchemy/" style="font-size:10px">SQLAlchemy</a> <a href="/tags/Tomcat/" style="font-size:10px">Tomcat</a> <a href="/tags/cdn加速/" style="font-size:10px">cdn加速</a> <a href="/tags/fabric/" style="font-size:10px">fabric</a> <a href="/tags/hexo/" style="font-size:10px">hexo</a> <a href="/tags/hexo一键部署/" style="font-size:10px">hexo一键部署</a> <a href="/tags/jackson/" style="font-size:10px">jackson</a> <a href="/tags/jmeter/" style="font-size:10px">jmeter</a> <a href="/tags/json/" style="font-size:12px">json</a> <a href="/tags/lambda/" style="font-size:10px">lambda</a> <a href="/tags/markdown/" style="font-size:10px">markdown</a> <a href="/tags/md5/" style="font-size:10px">md5</a> <a href="/tags/optparse/" style="font-size:10px">optparse</a> <a href="/tags/pipeline/" style="font-size:10px">pipeline</a> <a href="/tags/python/" style="font-size:10px">python</a> <a href="/tags/supervisor/" style="font-size:10px">supervisor</a> <a href="/tags/uwsgi/" style="font-size:10px">uwsgi</a> <a href="/tags/vim/" style="font-size:10px">vim</a> <a href="/tags/传输文件/" style="font-size:10px">传输文件</a> <a href="/tags/前端积累/" style="font-size:14px">前端积累</a> <a href="/tags/压力测试/" style="font-size:10px">压力测试</a> <a href="/tags/多进程/" style="font-size:10px">多进程</a> <a href="/tags/并行/" style="font-size:10px">并行</a> <a href="/tags/微博登陆/" style="font-size:10px">微博登陆</a> <a href="/tags/性能/" style="font-size:10px">性能</a> <a href="/tags/性能优化/" style="font-size:10px">性能优化</a> <a href="/tags/搜索引擎/" style="font-size:10px">搜索引擎</a> <a href="/tags/新浪图床/" style="font-size:10px">新浪图床</a> <a href="/tags/正则表达式/" style="font-size:12px">正则表达式</a> <a href="/tags/编码/" style="font-size:10px">编码</a> <a href="/tags/问题及解决/" style="font-size:10px">问题及解决</a> <a href="/tags/随手记/" style="font-size:10px">随手记</a></div></div><div class="widget-wrap"><h3 class="widget-title">最新文章</h3><div class="widget"><ul id="recent-post" class="no-thumbnail"><li><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/python/">python</a></p><p class="item-title"><a href="/2016/07/07/Celery-Tornado-Supervisor构建和谐的分布式框架/" class="title">Celery,Tornado,Supervisor构建和谐的分布式系统</a></p><p class="item-date"><time datetime="2016-07-07T08:29:18.000Z" itemprop="datePublished">2016-07-07</time></p></div></li><li><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/supervisor/">supervisor</a></p><p class="item-title"><a href="/2016/06/28/supervisor-easy使用指南/" class="title">supervisor-easy使用指南</a></p><p class="item-date"><time datetime="2016-06-28T13:43:29.000Z" itemprop="datePublished">2016-06-28</time></p></div></li><li><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/RabbitMQ/">RabbitMQ</a></p><p class="item-title"><a href="/2016/05/12/RabbitMQ浅读/" class="title">RabbitMQ浅读</a></p><p class="item-date"><time datetime="2016-05-12T02:45:29.000Z" itemprop="datePublished">2016-05-12</time></p></div></li><li><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/python/">python</a></p><p class="item-title"><a href="/2016/05/05/Flask中使用装饰器遇到的问题AssertionError-View-function-mapping-is-overwriting-an-existing-endpoint-function/" class="title">Flask中使用装饰器遇到的问题AssertionError: View function mapping is overwriting an existing endpoint function</a></p><p class="item-date"><time datetime="2016-05-05T07:43:25.000Z" itemprop="datePublished">2016-05-05</time></p></div></li><li><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/数据库/">数据库</a></p><p class="item-title"><a href="/2016/05/05/PG语法汇总/" class="title">PG语法汇总</a></p><p class="item-date"><time datetime="2016-05-05T06:43:08.000Z" itemprop="datePublished">2016-05-05</time></p></div></li></ul></div></div><div class="widget-wrap"><h3 class="widget-title">归档</h3><div class="widget"><ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/07/">七月 2016</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/06/">六月 2016</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/05/">五月 2016</a><span class="archive-list-count">8</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/04/">四月 2016</a><span class="archive-list-count">14</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/03/">三月 2016</a><span class="archive-list-count">22</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/01/">一月 2016</a><span class="archive-list-count">17</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/12/">十二月 2015</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/11/">十一月 2015</a><span class="archive-list-count">5</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/10/">十月 2015</a><span class="archive-list-count">6</span></li></ul></div></div><div class="widget-wrap widget-list"><h3 class="widget-title">链接</h3><div class="widget"><ul><li><a href="http://blog.trytofix.com" rel="external nofollow" target="_blank">老版博客</a></li><li><a href="http://git.trytofix.com" rel="external nofollow" target="_blank">git课件</a></li></ul></div></div><div id="toTop" class="fa fa-chevron-up"></div></aside></div><footer id="footer"><div class="outer"><div id="footer-info" class="inner">© 2016 brian.yang<br>Powered by <a href="http://hexo.io/" target="_blank" rel="external nofollow">Hexo</a>. Theme by <a href="http://github.com/ppoffice" rel="external nofollow" target="_blank">PPOffice</a></div></div></footer><script type="text/javascript">var duoshuoQuery={short_name:"trytofix"};!function(){var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src=("https:"==document.location.protocol?"https:":"http:")+"//static.duoshuo.com/embed.js",t.charset="UTF-8",(document.getElementsByTagName("head")[0]||document.getElementsByTagName("body")[0]).appendChild(t)}()</script><script src="http://7xiego.com1.z0.glb.clouddn.com/js/main.js"></script></div></body>