RABBITMQ Communication between Micro services
MicroServices are independent of each other, unlike individual engineering modules can be directly through the method call to achieve communication, mutual independent service direct general communication is to use HTTP协议
, rpc协议
or use message middleware such as RabbitMQ``Kafka
Image
In this article using Golang and MongoDB to build MicroServices has implemented a microservices application, in the article has implemented the direct communication of the various services, is the form of use HTTP
, how the various services through the RabbitMQ
message communication, we now have to implement a function, is a user to book movie ticket interface, need to service User Service (port 8000) and services Booking service (port 8003) communication between the user after booking, the booking information to write to in the booking database
InstallationRabbitMQ
Before installation, RabbitMQ
you need to install the Erlang environment, and then download the installation RABBITMQ, please select the corresponding version, after the installation is completed, RABBITMQ on Windows as a service in the background to run, about RabbitMQ
the interface how to use, please refer to the official website of the tutorial, There are various mainstream language implementations we are using a Go
version, please download the corresponding implementation interfacego get github.com/streadway/amqp
The RabbitMQ
interface to do a simple package
messaging/message.go
type IMessageClient interface { ConnectToBroker(connectionStr string) error PublishToQueue(data []byte, queueName string) error SubscribeToQueue(queueName string, handlerFunc func(amqp.Delivery)) error Close()}type MessageClient struct { conn *amqp.Connection}
func (m *MessageClient) ConnectToBroker(connectionStr string) error { if connectionStr == "" { panic("the connection str mustnt be null") } var err error m.conn, err = amqp.Dial(connectionStr) return err}
- Publish Message interface
func (m *MessageClient) PublishToQueue(body []byte, queueName string) error { if m.conn == nil { panic("before publish you must connect the RabbitMQ first") } ch, err := m.conn.Channel() defer ch.Close() failOnError(err, "Failed to open a channel") q, err := ch.QueueDeclare( queueName, false, false, false, false, nil, ) failOnError(err, "Failed to declare a queue") err = ch.Publish( "", q.Name, false, false, amqp.Publishing{ ContentType: "application/json", Body: body, }, ) failOnError(err, "Failed to publish a message") return nil}
- Subscribe to the Messaging interface
func (m *MessageClient) SubscribeToQueue(queueName string, handlerFunc func(amqp.Delivery)) error { ch, err := m.conn.Channel() //defer ch.Close() failOnError(err, "Failed to open a channel") q, err := ch.QueueDeclare( queueName, false, false, false, false, nil, ) failOnError(err, "Failed to declare a queue") msgs, err := ch.Consume( q.Name, "", true, false, false, false, nil, ) failOnError(err, "Failed to register a consumer") go consumeLoop(msgs, handlerFunc) return nil}
Achieve communication
A new interface is defined in the user Service , which POST
implements the /user/{name}/booking
subscriber's booking function, and after the reservation, RabbitMQ
a message is issued to
Booking Service, after theBooking service receives the message, does the corresponding processing (writes the database)
User Service
- Initialization
MessageClient
users/controllers/user.go
var client messaging.IMessageClientfunc init() { client = &messaging.MessageClient{} err := client.ConnectToBroker("amqp://guest:guest@localhost:5672/") if err != nil { fmt.Println("connect to rabbitmq error", err) }}
- Add a new route and implementation
routes.go
register("POST", "/user/{name}/booking", controllers.NewBooking, nil)
users/controllers/user.go
func NewBooking(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) user_name := params["name"] defer r.Body.Close() var bookings models.Booking body, _ := ioutil.ReadAll(r.Body) err := json.Unmarshal(body, &bookings) if err != nil { fmt.Println("the format body error ", err) } fmt.Println("user name:", user_name, bookings) go notifyMsg(body)}
- Implement the publication of a message with a single process
func notifyMsg(body []byte) { err := client.PublishToQueue(body, "new_booking") if err != nil { fmt.Println("Failed to publis message", err) }}
Booking Service
var client messaging.IMessageClientfunc initMessage() { client = &messaging.MessageClient{} err := client.ConnectToBroker("amqp://guest:guest@localhost:5672/") if err != nil { fmt.Println("Failed to connect to RabbitMQ", err) } err = client.SubscribeToQueue("new_booking", getBooking) if err != nil { fmt.Println("Failed to comsuer the msg", err) }}
Start before the Web service
func main() { initMessage() r := routes.NewRouter() http.ListenAndServe(":8003", r)}
- Post-Receive Message processing
func getBooking(delivery amqp.Delivery) { var booking models.Booking json.Unmarshal(delivery.Body, &booking) booking.Id = bson.NewObjectId().Hex() dao.Insert("Booking", "BookModel", booking) fmt.Println("the booking msg", booking)}
Verify that the User service and Booking service need to be started
Use Postman
to send corresponding data
post 127.0.0.1:8000/user/kevin_woo/booking{ "name":"kevin_woo", "books":[ { "date":"20180727", "movies":["5b4c45d49d5e3e33c4a5b97a"] }, { "date":"20180810", "movies":["5b4c45ea9d5e3e33c4a5b97b"] } ]}
You can see that the database already has a new booking information
Note that my post data is the structure of the booking database, the actual need to encapsulate the data, in the post data, the data is not validated,
In the actual development process need to do the corresponding validation of the data, here is mainly to see the process of RABBITMQ message delivery processing
SOURCE Github