2011 06-12-why do we need the rabbit

7,538 views
7,424 views

Published on

Published in: Technology, News & Politics
0 Comments
9 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
7,538
On SlideShare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
135
Comments
0
Likes
9
Embeds 0
No embeds

No notes for slide

2011 06-12-why do we need the rabbit

  1. 1. 消息队列服务在虎扑的应用 --- 使用异步和队列解决 web 开发中的问题
  2. 2. <ul><li>关于虎扑 </li></ul><ul><ul><li>可能是国内最棒的体育社区 </li></ul></ul><ul><ul><li>旗下有虎扑 ( 篮球 ), goalhi( 足球 ), 亮乐 ( 综合体育 ),HelloF1, 卡路里 ( 商城 ) 等网站 </li></ul></ul><ul><ul><li>alexa 中国前百强 </li></ul></ul><ul><ul><li>PV 8 千万 / 天 </li></ul></ul>
  3. 3. <ul><li>关于我 </li></ul><ul><ul><li>ID: 轩痕 </li></ul></ul><ul><ul><li>mail: wpcworkstation@gmail.com </li></ul></ul><ul><ul><li>后端开发 , 最近正纠结于 twisted </li></ul></ul><ul><ul><li>喜欢 python,linux </li></ul></ul>
  4. 4. <ul><li>话题预览 : </li></ul><ul><li>1 我们为什么需要消息队列 ? </li></ul><ul><li>2 理想的消息队列需要具有哪些特性 ? </li></ul><ul><li>3 高级消息队列的模型 </li></ul>
  5. 5. 我们为什么需要消息队列 <ul><li>虎扑微博的业务情况 </li></ul><ul><ul><li>如果一个体育明星用户有一万个人关注 </li></ul></ul><ul><ul><li>每条状态 会产生 一万条数据库 插入需求 </li></ul></ul><ul><ul><li>世纪大战 </li></ul></ul><ul><ul><li>高峰时每秒成千上万条插入任务 </li></ul></ul>
  6. 7. <ul><li>遇到的问题 : </li></ul><ul><li>状态丢失 </li></ul><ul><li>502 错误 </li></ul><ul><li>mysql 服务器压力很大 </li></ul>
  7. 8. <ul><li>解决方案 : </li></ul><ul><li>1 加入新的 mysql 服务器 , 一个库 , 一张表 , 简易队列化 </li></ul><ul><ul><ul><li>表结构 id server_id sql_statement </li></ul></ul></ul><ul><ul><li>2 去掉插入速度的约束 </li></ul></ul><ul><ul><li>3 不在这个数据库上进行不必要的查询和修改操作 </li></ul></ul>
  8. 9. 优化的结果 <ul><li>状态不丢了 </li></ul><ul><li>502 也没有了 </li></ul><ul><li>但这样做有没有弊端呢 ? </li></ul>
  9. 10. <ul><li>弊端 : </li></ul><ul><ul><li>入队速度还不理想 , 因为要写硬盘 </li></ul></ul><ul><ul><li>数据必须持久化 , 无法选择 </li></ul></ul><ul><ul><li>后端的处理线程需要一直去取数据 , 取的频率不好确定 </li></ul></ul>
  10. 11. SMS <ul><li>线下约战 </li></ul><ul><ul><li>队长要通过我们的 web 系统以短信的方式通知队员约定的比赛时间 , 场地信息 </li></ul></ul><ul><ul><li>队长发起约战请求的时候可不希望页面卡在那里半天没反应 </li></ul></ul><ul><ul><li>但是发送短信却需要一定时间的阻塞 </li></ul></ul>
  11. 12. 这里会有什么问题 ?
  12. 13. <ul><li>弊端 : </li></ul><ul><li>1 多线程时会出现一条消息被多次取的问题 </li></ul><ul><li>2 需要线程定时到队列查询 </li></ul><ul><li>期望的特性 : </li></ul><ul><li>1 消息一旦被取走 , 就不能被别的线程再获取 </li></ul><ul><li>2 如果那些消费线程能够在有消息到来的时候再来取 , 或许是个不错的事情 </li></ul>
  13. 14. Google 分析
  14. 15. 假如 假如有这样一个服务器放在我面前 .... 它有非常快的消息进出速度 可以从容地处理成千上万的并发 还能很容易地控制数据是否持久化 有消息来的时候会主动推送给消费线程 消息一旦被某消费者取走 , 其他消费者 就无法再取这条消息 ...
  15. 17. <ul><li>这个理想中的消息队列服务器叫什么名字 </li></ul>
  16. 18. <ul><li>1 rabbitmq 是 AMQP 的一个实现 </li></ul><ul><li>2 完全开源 </li></ul><ul><li>3 开发语言是 erlang </li></ul><ul><li>4 非常高的可靠性 </li></ul>
  17. 19. 关于 erlang <ul><li>Erlang 是一门被设计用于编写高并发、软实时、分布式系统的语言。 </li></ul>
  18. 20. AMQP <ul><li>高级消息队列协议 (Advanced Message Queuing Protocol) </li></ul><ul><li>完全的开放协议 </li></ul><ul><li>给力的互操作性 </li></ul><ul><li>AMQP 模型 </li></ul>
  19. 21. AMQP 模型 <ul><li>Exchanges( 交换机 ) </li></ul><ul><li>Message Queues( 消息队列 ) </li></ul><ul><li>Bindings ( 交换机 和 队列 的绑定 ) </li></ul><ul><li>message( 消息 ) </li></ul>
  20. 22. http://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_MRG/1.1/html/Messaging_User_Guide/sect-Messaging_User_Guide-Introduction_to_RHM-The_AMQP_0_10_Model.html
  21. 23. (exchange) 交换机的分发机制 <ul><li>Direct( 直接传递 ) </li></ul><ul><li>Fanout( 广播 ) </li></ul><ul><li>Topic( 话题的形式 , 依赖于通配符 ) </li></ul>
  22. 24. Direct Exchange
  23. 25. Fanout Exchange
  24. 26. Topic Exchange
  25. 27. <ul><li>当消息都进入了队列 , 接下来让我们讲讲队列吧 </li></ul>
  26. 28. 传统的队列末端消费模式
  27. 29. AMQP 模式下的消息处理模式
  28. 30. 队列本身的特性 <ul><li>可以被设置为持久化 </li></ul><ul><li>队列需要与交换机绑定 , 然后从交换机接受消息 , 并且和交换机的持久性保持一致 , 不能一个持久 , 一个非持久 </li></ul><ul><li>如果被设置为私有的 , 只有声明它的消费者才可以从这个队列拿走消息 </li></ul>
  29. 31. 消息 <ul><li>分为两类 : </li></ul><ul><ul><li>消息量很大 , 而且并不怎么重要的 , 可以只放在内存中 , 不做持久化 , 不开启 ack </li></ul></ul><ul><ul><li>消息量不大 , 很重要的 , 可以设置为持久化 , 开启 ack </li></ul></ul>
  30. 32. AMQP 的其他实现 <ul><li>OpenAMQ </li></ul><ul><li>Apache ActiveMQ </li></ul><ul><li>ZeroMQ </li></ul><ul><li>AMQP Infrastructure </li></ul>
  31. 33. 使用客户端同 rabbitmq 交流 1 支持很多语言的客户端 . c,c++,php, java, ruby,python,erlang 等 2 基于 Python 的库 . pika, txamqp,celery 等等 ..
  32. 34. <ul><li>连接 </li></ul><ul><li>1 阻塞式的连接 </li></ul><ul><li>from pika.adapters import BlockingConnection </li></ul><ul><li>connection = BlockingConnection() </li></ul><ul><li>2 非阻塞式的连接 </li></ul><ul><li>import select_connection </li></ul><ul><li>select_connection.POLLER_TYPE = 'epoll' </li></ul><ul><li>connection = select_connection.SelectConnection() </li></ul>
  33. 35. 创建 队列 , 交换机 , 绑定 <ul><li>在物理连接的基础上创建一个逻辑通道 </li></ul><ul><li>channel = connection.channel() </li></ul><ul><li>由逻辑通道来声明交换机和队列 </li></ul><ul><li>channel. exchange _declare(exchange='direct_logs', type='direct') </li></ul><ul><li>result = channel. queue _declare(exclusive=True) </li></ul><ul><li>创建交换机和队列的绑定 </li></ul><ul><li>channel. queue _ bind ( exchange ='direct_logs', queue =queue_name, </li></ul><ul><li>routing_key= severity ) </li></ul>
  34. 36. <ul><li>准备工作做好了 , 我在哪里处理消息呢 ? </li></ul>
  35. 37. 按照业务进行消费 <ul><li>def callback (ch, method, properties, body): </li></ul><ul><li>print &quot; [x] %r:%r&quot; % (method.routing_key, body,) </li></ul><ul><li>print ' 我这里可以处理一些业务 ' </li></ul><ul><li>另一个绑定 : </li></ul><ul><ul><li>在队列的尾端绑定一个业务回调 </li></ul></ul><ul><li>channel.basic_ consume ( callback , </li></ul><ul><li>queue =queue_name, </li></ul><ul><li>no_ack =True) </li></ul>
  36. 38. <ul><li>如果处理消息时除了差错 , 而我又不想让这条消息丢失 . </li></ul><ul><li>怎么办 ? </li></ul>
  37. 39. 处理消息时的分支 <ul><li>1 设置 no_ack = False </li></ul><ul><li>channel. basic_consume (callback,queue=queue_name, no_ack = False ) </li></ul><ul><li>告诉兔子我处理完消息会给你反馈的 </li></ul><ul><li>2 如果消息被成功处理 , 使用 </li></ul><ul><li>channel.basic_ack(method. delivery_tag ) </li></ul><ul><li>3 如果处理消息发生了异常 , 在异常处理的代码里面使用 </li></ul><ul><li>channel.basic_reject(method. delivery_tag ) </li></ul><ul><li>让消息重回队列 , 避免丢失 </li></ul>
  38. 40. <ul><li>消息的处理速度不够快怎么办 ? </li></ul>
  39. 41. <ul><ul><ul><ul><ul><li>多线程 </li></ul></ul></ul></ul></ul>
  40. 42. <ul><li>猜想 : </li></ul><ul><li>假如队列里面有一万条消息 , 我们开启了一百个线程进行处理 , 每个线程能分配到多少条消息 ? </li></ul>
  41. 43. <ul><li>控制每个消费者最大被分配的消息量 </li></ul><ul><ul><li>channel.basic_qos( prefetch_count =1) </li></ul></ul>
  42. 44. <ul><li>处理任务的时间过长 , 会被兔子认为执行超时 , 并把任务分给别的消费者吗 ? </li></ul>
  43. 45. <ul><li>消费者挂了怎么办 ? 消息还在吗 ? </li></ul>

×