45
消消消消消消消消消消消消 消消消消消消消消消消消消 --- 使使使使使使使使使 web 使使使使使使

2011 06-12-why do we need the rabbit

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: 2011 06-12-why do we need the rabbit

消息队列服务在虎扑的应用 消息队列服务在虎扑的应用

--- 使用异步和队列解决 web 开发中的问题

Page 2: 2011 06-12-why do we need the rabbit

•关于虎扑– 可能是国内最棒的体育社区– 旗下有虎扑 ( 篮球 ), goalhi( 足球 ), 亮乐

( 综合体育 ),HelloF1, 卡路里 ( 商城 ) 等网站– alexa 中国前百强– PV 8 千万 / 天

Page 3: 2011 06-12-why do we need the rabbit

•关于我– ID: 轩痕– mail: [email protected]– 后端开发 , 最近正纠结于 twisted– 喜欢 python,linux

Page 4: 2011 06-12-why do we need the rabbit

话题预览 :1 我们为什么需要消息队列 ?2 理想的消息队列需要具有哪些特性 ?3 高级消息队列的模型

Page 5: 2011 06-12-why do we need the rabbit

我们为什么需要消息队列•虎扑微博的业务情况

– 如果一个体育明星用户有一万个人关注– 每条状态 会产生 一万条数据库 插入需求– 世纪大战– 高峰时每秒成千上万条插入任务

Page 6: 2011 06-12-why do we need the rabbit
Page 7: 2011 06-12-why do we need the rabbit

•遇到的问题 :• 状态丢失 • 502 错误• mysql 服务器压力很大

Page 8: 2011 06-12-why do we need the rabbit

解决方案 :1 加入新的 mysql 服务器 , 一个库 , 一张表 , 简易队列化

表结构 id server_id sql_statement2 去掉插入速度的约束3 不在这个数据库上进行不必要的查询和修改操作

Page 9: 2011 06-12-why do we need the rabbit

优化的结果•状态不丢了• 502 也没有了

但这样做有没有弊端呢 ?

Page 10: 2011 06-12-why do we need the rabbit

•弊端 : – 入队速度还不理想 , 因为要写硬盘– 数据必须持久化 , 无法选择– 后端的处理线程需要一直去取数据 , 取的频率不好确定

Page 11: 2011 06-12-why do we need the rabbit

SMS •线下约战

– 队长要通过我们的 web 系统以短信的方式通知队员约定的比赛时间 , 场地信息

– 队长发起约战请求的时候可不希望页面卡在那里半天没反应

– 但是发送短信却需要一定时间的阻塞

Page 12: 2011 06-12-why do we need the rabbit

这里会有什么问题 ?

Page 13: 2011 06-12-why do we need the rabbit

• 弊端 : 1 多线程时会出现一条消息被多次取的问题 2 需要线程定时到队列查询

期望的特性 : 1 消息一旦被取走 , 就不能被别的线程再获取 2 如果那些消费线程能够在有消息到来的时候再来取 , 或许是个不错的事情

Page 14: 2011 06-12-why do we need the rabbit

Google 分析

Page 15: 2011 06-12-why do we need the rabbit

假如

假如有这样一个服务器放在我面前 ....它有非常快的消息进出速度可以从容地处理成千上万的并发还能很容易地控制数据是否持久化有消息来的时候会主动推送给消费线程消息一旦被某消费者取走 , 其他消费者就无法再取这条消息...

Page 16: 2011 06-12-why do we need the rabbit
Page 17: 2011 06-12-why do we need the rabbit

这个理想中的消息队列服务器叫什么名字

Page 18: 2011 06-12-why do we need the rabbit

1 rabbitmq 是 AMQP 的一个实现2 完全开源3 开发语言是 erlang4 非常高的可靠性

Page 19: 2011 06-12-why do we need the rabbit

关于 erlang Erlang 是一门被设计用于编写高并发、软实时、分布式系统的语言。

Page 20: 2011 06-12-why do we need the rabbit

AMQP•高级消息队列协议 (Advanced Message

Queuing Protocol)•完全的开放协议•给力的互操作性• AMQP 模型

Page 21: 2011 06-12-why do we need the rabbit

AMQP 模型• Exchanges(交换机 )• Message Queues( 消息队列 )• Bindings (交换机 和 队列 的绑定 )• message( 消息 )

Page 22: 2011 06-12-why do we need the rabbit

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

Page 23: 2011 06-12-why do we need the rabbit

(exchange)交换机的分发机制 • Direct( 直接传递 )• Fanout(广播 )• Topic( 话题的形式 ,依赖于通配符 )

Page 24: 2011 06-12-why do we need the rabbit

Direct Exchange

Page 25: 2011 06-12-why do we need the rabbit

Fanout Exchange

Page 26: 2011 06-12-why do we need the rabbit

Topic Exchange

Page 27: 2011 06-12-why do we need the rabbit

当消息都进入了队列 ,接下来让我们讲讲队列吧

Page 28: 2011 06-12-why do we need the rabbit

传统的队列末端消费模式

Page 29: 2011 06-12-why do we need the rabbit

AMQP 模式下的消息处理模式

Page 30: 2011 06-12-why do we need the rabbit

队列本身的特性•可以被设置为持久化•队列需要与交换机绑定 , 然后从交换机接受消息 , 并且和交换机的持久性保持一致 ,不能一个持久 , 一个非持久

•如果被设置为私有的 ,只有声明它的消费者才可以从这个队列拿走消息

Page 31: 2011 06-12-why do we need the rabbit

消息•分为两类 :

– 消息量很大 ,而且并不怎么重要的 , 可以只放在内存中 , 不做持久化 , 不开启 ack

– 消息量不大 , 很重要的 , 可以设置为持久化 ,开启 ack

Page 32: 2011 06-12-why do we need the rabbit

AMQP 的其他实现

• OpenAMQ• Apache ActiveMQ• ZeroMQ• AMQP Infrastructure

Page 33: 2011 06-12-why do we need the rabbit

使用客户端同 rabbitmq交流

1 支持很多语言的客户端 .c,c++,php, java, ruby,python,erlang 等

2 基于 Python 的库 . pika, txamqp,celery 等等 ..

Page 34: 2011 06-12-why do we need the rabbit

连接1 阻塞式的连接from pika.adapters import BlockingConnection connection = BlockingConnection()

2 非阻塞式的连接import select_connection select_connection.POLLER_TYPE = 'epoll'connection = select_connection.SelectConnectio

n()

Page 35: 2011 06-12-why do we need the rabbit

创建 队列 ,交换机 ,绑定• 在物理连接的基础上创建一个逻辑通道• channel = connection.channel()

• 由逻辑通道来声明交换机和队列• channel.exchange_declare(exchange='direct_logs', type='direct')• result = channel.queue_declare(exclusive=True)

• 创建交换机和队列的绑定• channel.queue_bind(exchange='direct_logs', queue=queue_name,• routing_key=severity)

Page 36: 2011 06-12-why do we need the rabbit

•准备工作做好了 , 我在哪里处理消息呢 ?

Page 37: 2011 06-12-why do we need the rabbit

按照业务进行消费

• def callback(ch, method, properties, body):• print " [x] %r:%r" % (method.routing_key, body,)• print ' 我这里可以处理一些业务 '

• 另一个绑定 :– 在队列的尾端绑定一个业务回调

• channel.basic_consume(callback,• queue=queue_name,• no_ack=True)

Page 38: 2011 06-12-why do we need the rabbit

如果处理消息时除了差错 ,而我又不想让这条消息丢失 .

怎么办 ?

Page 39: 2011 06-12-why do we need the rabbit

处理消息时的分支1 设置 no_ack = False

channel.basic_consume(callback,queue=queue_name, no_ack=False)

告诉兔子我处理完消息会给你反馈的2 如果消息被成功处理 , 使用

channel.basic_ack(method.delivery_tag)

3 如果处理消息发生了异常 , 在异常处理的代码里面使用channel.basic_reject(method.delivery_tag)

让消息重回队列 ,避免丢失

Page 40: 2011 06-12-why do we need the rabbit

消息的处理速度不够快怎么办 ?

Page 41: 2011 06-12-why do we need the rabbit

多线程

Page 42: 2011 06-12-why do we need the rabbit

猜想 :

假如队列里面有一万条消息 , 我们开启了一百个线程进行处理 , 每个线程能分配到多少条消息 ?

Page 43: 2011 06-12-why do we need the rabbit

•控制每个消费者最大被分配的消息量– channel.basic_qos(prefetch_count=1)

Page 44: 2011 06-12-why do we need the rabbit

处理任务的时间过长 , 会被兔子认为执行超时 , 并把任务分给别的消费者吗 ?

Page 45: 2011 06-12-why do we need the rabbit

消费者挂了怎么办 ? 消息还在吗 ?