Successfully reported this slideshow.

Desacoplando aplicaciones

9,191 views

Published on

Charla dada durante las Jornadas Symfony en Castellón, España. Julio 2011

Published in: Technology, Art & Photos
  • Be the first to comment

Desacoplando aplicaciones

  1. 1. Monday, July 4, 2011
  2. 2. Monday, July 4, 2011
  3. 3. About Me • Desarrollador en Liip AG • Blog: http://videlalvaro.github.com/ • Twitter: @old_soundMonday, July 4, 2011
  4. 4. About Me Escribiendo RabbitMQ in Action http://bit.ly/rabbitmqMonday, July 4, 2011
  5. 5. ¿Por qué necesito usar Mensajería?Monday, July 4, 2011
  6. 6. Veamos un ejemploMonday, July 4, 2011
  7. 7. Implementar una Galería de ImágenesMonday, July 4, 2011
  8. 8. Dos Partes:Monday, July 4, 2011
  9. 9. ¿Bastante fácil no?Monday, July 4, 2011
  10. 10. Hasta que nuevos requerimientos comienzan a llegarMonday, July 4, 2011
  11. 11. El Propietario del ProductoMonday, July 4, 2011
  12. 12. ¿Podemos notificar a los amigos del usuario sobre nuevas imágenes?Monday, July 4, 2011
  13. 13. ¿Podemos notificar a los amigos del usuario sobre nuevas imágenes? Me olvidé de decirles que lo necesito para mañanaMonday, July 4, 2011
  14. 14. El “Social Media Guru”Monday, July 4, 2011
  15. 15. Necesitamos premiar a los usuarios por cada foto que subenMonday, July 4, 2011
  16. 16. Necesitamos premiar a los usuarios por cada foto que suben y enviar notificaciones a TwitterMonday, July 4, 2011
  17. 17. El Administrador de SistemasMonday, July 4, 2011
  18. 18. ¡Dolobu! Estamos sirviendo imágenes sin achicar. ¡La cuenta de ancho de banda a triplicado!Monday, July 4, 2011
  19. 19. ¡Dolobu! Estamos sirviendo imágenes sin achicar. ¡La cuenta de ancho de banda a triplicado! ¡Necesitamos arreglar esto para mañana!Monday, July 4, 2011
  20. 20. El Desarrollador en el otro equipoMonday, July 4, 2011
  21. 21. Necesito llamar tus sistemas PHP pero desde PythonMonday, July 4, 2011
  22. 22. Necesito llamar tus sistemas PHP pero desde Python Y la semana que viene Java tambiénMonday, July 4, 2011
  23. 23. El UsuarioMonday, July 4, 2011
  24. 24. No quiero tener que esperar que tu aplicación procese la imagenMonday, July 4, 2011
  25. 25. TuMonday, July 4, 2011
  26. 26. FML!Monday, July 4, 2011
  27. 27. Veamos la evolución del códigoMonday, July 4, 2011
  28. 28. Primera implementación: %% image_controller handle(PUT, "/user/image", ReqData) -> image_handler:do_upload(ReqData:get_file()), ok.Monday, July 4, 2011
  29. 29. Segunda implementación: %% image_controller handle(PUT, "/user/image", ReqData) -> {ok, Image} = image_handler:do_upload(ReqData:get_file()), resize_image(Image), ok.Monday, July 4, 2011
  30. 30. Tercera implementación: %% image_controller handle(PUT, "/user/image", ReqData) -> {ok, Image} = image_handler:do_upload(ReqData:get_file()), resize_image(Image), notify_friends(ReqData:get_user()), ok.Monday, July 4, 2011
  31. 31. Cuarta implementación: %% image_controller handle(PUT, "/user/image", ReqData) -> {ok, Image} = image_handler:do_upload(ReqData:get_file()), resize_image(Image), notify_friends(ReqData:get_user()), add_points_to_user(ReqData:get_user()), ok.Monday, July 4, 2011
  32. 32. Implementación final: %% image_controller handle(PUT, "/user/image", ReqData) -> {ok, Image} = image_handler:do_upload(ReqData:get_file()), resize_image(Image), notify_friends(ReqData:get_user()), add_points_to_user(ReqData:get_user()), tweet_new_image(User, Image), ok.Monday, July 4, 2011
  33. 33. ¿Escala nuestro código a nuevos requerimientos?Monday, July 4, 2011
  34. 34. Qué pasaría si…Monday, July 4, 2011
  35. 35. Qué pasaría si… • Necesitamos acelerar la conversión de imágenesMonday, July 4, 2011
  36. 36. Qué pasaría si… • Necesitamos acelerar la conversión de imágenes • Las notificaciones a los usuarios tienen que ser enviadas por emailMonday, July 4, 2011
  37. 37. Qué pasaría si… • Necesitamos acelerar la conversión de imágenes • Las notificaciones a los usuarios tienen que ser enviadas por email • Tenemos que dejar de twittear sobre nuevas imágenesMonday, July 4, 2011
  38. 38. Qué pasaría si… • Necesitamos acelerar la conversión de imágenes • Las notificaciones a los usuarios tienen que ser enviadas por email • Tenemos que dejar de twittear sobre nuevas imágenes • Convertir imágenes a diferentes formatosMonday, July 4, 2011
  39. 39. ¿Podemos hacerlo mejor?Monday, July 4, 2011
  40. 40. Por supuesto. Usando Mensajería.Monday, July 4, 2011
  41. 41. Diseño Publish / Subscribe PatternMonday, July 4, 2011
  42. 42. Primera Implementación: %% image_controller handle(PUT, "/user/image", ReqData) -> {ok, Image} = image_handler:do_upload(ReqData:get_file()), Msg = #msg{user = ReqData:get_user(), image = Image}, publish_message(new_image, Msg).Monday, July 4, 2011
  43. 43. Primera Implementación: %% image_controller handle(PUT, "/user/image", ReqData) -> {ok, Image} = image_handler:do_upload(ReqData:get_file()), Msg = #msg{user = ReqData:get_user(), image = Image}, publish_message(new_image, Msg). %% friends notifier on(new_image, Msg) -> notify_friends(Msg.user, Msg.image).Monday, July 4, 2011
  44. 44. Primera Implementación: %% image_controller handle(PUT, "/user/image", ReqData) -> {ok, Image} = image_handler:do_upload(ReqData:get_file()), Msg = #msg{user = ReqData:get_user(), image = Image}, publish_message(new_image, Msg). %% friends notifier on(new_image, Msg) -> notify_friends(Msg.user, Msg.image). %% points manager on(new_image, Msg) -> add_points(Msg.user, new_image).Monday, July 4, 2011
  45. 45. Primera Implementación: %% image_controller handle(PUT, "/user/image", ReqData) -> {ok, Image} = image_handler:do_upload(ReqData:get_file()), Msg = #msg{user = ReqData:get_user(), image = Image}, publish_message(new_image, Msg). %% friends notifier on(new_image, Msg) -> notify_friends(Msg.user, Msg.image). %% points manager on(new_image, Msg) -> add_points(Msg.user, new_image). %% resizer on(new_image, Msg) -> resize_image(Msg.image).Monday, July 4, 2011
  46. 46. Segunda Implementación:Monday, July 4, 2011
  47. 47. Segunda Implementación: THIS PAGE INTENTIONALLY LEFT BLANKMonday, July 4, 2011
  48. 48. MensajeríaMonday, July 4, 2011
  49. 49. Mensajería • Compartir datos entre procesosMonday, July 4, 2011
  50. 50. Mensajería • Compartir datos entre procesos • Procesos pueden ser parte de diferentes aplicacionesMonday, July 4, 2011
  51. 51. Mensajería • Compartir datos entre procesos • Procesos pueden ser parte de diferentes aplicaciones • Aplicaciones pueden vivir en diferentes computadoresMonday, July 4, 2011
  52. 52. Mensajería • Compartir datos entre procesos • Procesos pueden ser parte de diferentes aplicaciones • Aplicaciones pueden vivir en diferentes computadores • La comunicación es asíncronaMonday, July 4, 2011
  53. 53. Conceptos PrincipalesMonday, July 4, 2011
  54. 54. Conceptos Principales • Mensajes son enviados por ProducersMonday, July 4, 2011
  55. 55. Conceptos Principales • Mensajes son enviados por Producers • Mensajes se envían a ConsumersMonday, July 4, 2011
  56. 56. Conceptos Principales • Mensajes son enviados por Producers • Mensajes se envían a Consumers • Mensajes van a través de un ChannelMonday, July 4, 2011
  57. 57. RabbitMQ y la MensajeríaMonday, July 4, 2011
  58. 58. ¿Qué es RabbitMQ?Monday, July 4, 2011
  59. 59. RabbitMQ • Sistema de Mensajería Empresarial • Código Libre MPL • Escrito en Erlang/OTP • Soporte Comercial • Mensajería via AMQPMonday, July 4, 2011
  60. 60. Features • Confiable y Altamente Escalable • Fácil de Instalar • Fácil de Clusterizar • Corre en: Windows, Solaris, Linux, OSX • AMQP 0.8 - 0.9.1Monday, July 4, 2011
  61. 61. Librerías AMQP • Java • .NET/C# • Erlang • Ruby, Python, PHP, Perl, AS3, Lisp, Scala, Clojure, HaskellMonday, July 4, 2011
  62. 62. AMQP • Advanced Message Queuing Protocol • Pensado para la Interoperabilidad • Protocolo Completamente Abierto • Protocol BinarioMonday, July 4, 2011
  63. 63. Flujo de Mensajes http://www.redhat.com/docs/en-US/Red_Hat_Enterprise_MRG/1.0/html/Messaging_Tutorial/chap-Messaging_Tutorial-Initial_Concepts.htmlMonday, July 4, 2011
  64. 64. Modelo AMQP • Exchanges • Message Queues • Bindings • Rules for binding themMonday, July 4, 2011
  65. 65. Tipos de Exchange • Fanout • Direct • TopicMonday, July 4, 2011
  66. 66. http://www.redhat.com/docs/en-US/Red_Hat_Enterprise_MRG/1.0/html/Messaging_Tutorial/sect-Messaging_Tutorial-Initial_Concepts- Fanout_Exchange.htmlMonday, July 4, 2011
  67. 67. http://www.redhat.com/docs/en-US/Red_Hat_Enterprise_MRG/1.0/html/Messaging_Tutorial/sect-Messaging_Tutorial-Initial_Concepts- Direct_Exchange.htmlMonday, July 4, 2011
  68. 68. http://www.redhat.com/docs/en-US/Red_Hat_Enterprise_MRG/1.0/html/Messaging_Tutorial/sect-Messaging_Tutorial-Initial_Concepts- Topic_Exchange.htmlMonday, July 4, 2011
  69. 69. Patrones de MensajeríaMonday, July 4, 2011
  70. 70. Les recomiendo un libro al respecto: http://www.eaipatterns.com/Monday, July 4, 2011
  71. 71. Patrones BásicosMonday, July 4, 2011
  72. 72. Competing Consumers How can a messaging client process multiple messages concurrently?Monday, July 4, 2011
  73. 73. Competing Consumers Create multiple Competing Consumers on a single channel so that the consumers can process multiple messages concurrently.Monday, July 4, 2011
  74. 74. Competing ConsumersMonday, July 4, 2011
  75. 75. Código Publisher init(Exchange, Queue) -> #exchange.declare{exchange = Exchange, type = <<"direct">>, durable = true}, #queue.declare{queue = Queue, durable = false}, #queue.bind{queue = Queue, exchange = Exchange}. publish_msg(Exchange, Payload) -> Props = #P_basic{content_type = <<"application/json">>, delivery_mode = 2}, %% persistent publish(Exchange, #amqp_msg{props = Props, payload = Payload}).Monday, July 4, 2011
  76. 76. Código Consumer init_consumer(Exchange, Queue) -> init(Exchange, Queue), #basic.consume{queue = Queue}. on(#basic.deliver{delivery_tag = DeliveryTag}, #amqp_msg{} = Msg) -> do_something_with_msg(Msg), #basic.ack{delivery_tag = DeliveryTag}.Monday, July 4, 2011
  77. 77. Publish/Subscribe How can the sender broadcast an event to all interested receivers?Monday, July 4, 2011
  78. 78. Publish/Subscribe Send the event on a Publish-Subscribe Channel, which delivers a copy of a particular event to each receiver.Monday, July 4, 2011
  79. 79. Publish/SubscribeMonday, July 4, 2011
  80. 80. Código Pulbisher init(Exchange, Queue) -> #exchange.declare{exchange = Exchange, type = <<"fanout">>, %% different type durable = true} %% same as before ... publish_msg(Exchange, Payload) -> Props = #P_basic{content_type = <<"application/json">>, delivery_mode = 2}, %% persistent publish(Exchange, #amqp_msg{props = Props, payload = Payload}).Monday, July 4, 2011
  81. 81. Código Consumer A init_consumer(Exchange, ResizeImageQueue) -> init(Exchange, ResizeImageQueue), #basic.consume{queue = ResizeImageQueue}. on(#basic.deliver{delivery_tag = DeliveryTag}, #amqp_msg{} = Msg) -> resize_message(Msg), #basic.ack{delivery_tag = DeliveryTag}.Monday, July 4, 2011
  82. 82. Código Consumer B init_consumer(Exchange, NotifyFriendsQueue) -> init(Exchange, NotifyFriendsQueue), #basic.consume{queue = NotifyFriendsQueue}. on(#basic.deliver{delivery_tag = DeliveryTag}, #amqp_msg{} = Msg) -> notify_friends(Msg), #basic.ack{delivery_tag = DeliveryTag}.Monday, July 4, 2011
  83. 83. Código Consumer C init_consumer(Exchange, LogImageUpload) -> init(Exchange, LogImageUpload), #basic.consume{queue = LogImageUpload}. on(#basic.deliver{delivery_tag = DeliveryTag}, #amqp_msg{} = Msg) -> log_image_upload(Msg), #basic.ack{delivery_tag = DeliveryTag}.Monday, July 4, 2011
  84. 84. Request/Reply When an application sends a message, how can it get a response from the receiver?Monday, July 4, 2011
  85. 85. Request/Reply Send a pair of Request-Reply messages, each on its own channel.Monday, July 4, 2011
  86. 86. Request/ReplyMonday, July 4, 2011
  87. 87. Return Address How does a replier know where to send the reply?Monday, July 4, 2011
  88. 88. Return Address The request message should contain a Return Address that indicates where to send the reply message.Monday, July 4, 2011
  89. 89. Return AddressMonday, July 4, 2011
  90. 90. Correlation Identifier How does a requestor that has received a reply know which request this is the reply for?Monday, July 4, 2011
  91. 91. Correlation Identifier Each reply message should contain a Correlation Identifier, a unique identifier that indicates which request message this reply is for.Monday, July 4, 2011
  92. 92. Correlation IdentifierMonday, July 4, 2011
  93. 93. Atando CabosMonday, July 4, 2011
  94. 94. Cliente RPC init() -> #queue.declare_ok{queue = SelfQueue} = #queue.declare{exclusive = true, auto_delete = true}, #basic.consume{queue = SelfQueue, no_ack = true}, SelfQueue.Monday, July 4, 2011
  95. 95. Cliente RPC init() -> #queue.declare_ok{queue = SelfQueue} = #queue.declare{exclusive = true, auto_delete = true}, #basic.consume{queue = SelfQueue, no_ack = true}, SelfQueue. request(Payload, RequestId) -> Props = #P_basic{correlation_id = RequestId, reply_to = SelfQueue}, publish(ServerExchange, #amqp_msg{props = Props, payload = Payload}).Monday, July 4, 2011
  96. 96. Cliente RPC init() -> #queue.declare_ok{queue = SelfQueue} = #queue.declare{exclusive = true, auto_delete = true}, #basic.consume{queue = SelfQueue, no_ack = true}, SelfQueue. request(Payload, RequestId) -> Props = #P_basic{correlation_id = RequestId, reply_to = SelfQueue}, publish(ServerExchange, #amqp_msg{props = Props, payload = Payload}). on(#basic.deliver{}, #amqp_msg{props = Props, payload = Payload}) -> CorrelationId = Props.correlation_id, do_something_with_reply(Payload).Monday, July 4, 2011
  97. 97. Servidor RPC on(#basic.deliver{}, #amqp_msg{props = Props, payload = Payload}) -> CorrelationId = Props.correlation_id, ReplyTo = Props.reply_to, Reply = process_request(Payload), NewProps = #P_basic{correlation_id = CorrelationId}, publish("", %% anonymous exchange #amqp_msg{props = NewProps, payload = Reply}, ReplyTo). %% routing keyMonday, July 4, 2011
  98. 98. Patrones AvanzadosMonday, July 4, 2011
  99. 99. Control Bus How can we effectively administer a messaging system that is distributed across multiple platforms and a wide geographic area?Monday, July 4, 2011
  100. 100. Control Bus Use a Control Bus to manage an enterprise integration system.Monday, July 4, 2011
  101. 101. Control Bus • Send Configuration Messages • Start/Stop Services • Inject Test Messages • Collect StatisticsMonday, July 4, 2011
  102. 102. Control BusMonday, July 4, 2011
  103. 103. Control Bus Make Services “Control Bus” EnabledMonday, July 4, 2011
  104. 104. Detour How can you route a message through intermediate steps to perform validation, testing or debugging functions?Monday, July 4, 2011
  105. 105. Detour Construct a Detour with a context-based router controlled via the Control Bus. In one state the router routes incoming messages through additional steps while in the other it routes messages directly to the destination channel.Monday, July 4, 2011
  106. 106. DetourMonday, July 4, 2011
  107. 107. Wire Tap How do you inspect messages that travel on a point-to-point channel?Monday, July 4, 2011
  108. 108. Wire Tap Insert a simple Recipient List into the channel that publishes each incoming message to the main channel and a secondary channel.Monday, July 4, 2011
  109. 109. Wire TapMonday, July 4, 2011
  110. 110. Smart Proxy How can you track messages on a service that publishes reply messages to the Return Address specified by the requestor?Monday, July 4, 2011
  111. 111. Smart Proxy Use a Smart Proxy to store the Return Address supplied by the original requestor and replace it with the address of the Smart Proxy. When the service sends the reply message route it to the original Return Address.Monday, July 4, 2011
  112. 112. Smart ProxyMonday, July 4, 2011
  113. 113. Créditos Imágenes y descripciones de los patrones tomadas de: http://www.eaipatterns.com/Monday, July 4, 2011
  114. 114. ¡Gracias! @old_sound http://vimeo.com/user1169087 http://www.slideshare.net/old_soundMonday, July 4, 2011

×