PRIYANKA VERGADIA: Cat-Out has concluded that their packaging
subscriber is going to receive a large number of messages.
Stay tuned to find out when and how using pub subscribers.
[MUSIC PLAYING]
So far in the series, we learned about Cloud Pub/Sub,
how it works using Cat-Out's asynchronous order processing
service.
We saw how pub/sub helps manage the interactions between order,
packaging, shipping, and notification services.
In the last episode, we learned that pub/sub supports both
push and pull message delivery.
Let's do a quick recap.
Push delivery requires the client
to be a public HTTPS endpoint.
If you don't have one, which means
your service is private or firewalls are involved,
then you would use pull.
Pull is also more efficient and minimizes latency.
So if events are generated at, say,
100 or 1,000 requests per second,
then pull is your friend.
So today, let's focus on Cat-Out's services
to learn pull subscribers.
Let's say it is the high season for Cat-Out.
Lots of people are ordering pretty cat posters,
which means the packaging service needs
to process this huge traffic with high efficiency
and low latency.
And we also know that the packaging service is internal
and does not have a public HTTPS endpoint.
Given these conditions-- large requests
per second, low latency requirements,
and no public HTTPS endpoint-- the best way to setup
our packaging subscriber is in pull mode.
The pub/sub service offers two APIs for retrieving messages
in pull mode.
There's a pull API and there is a streaming pull API.
The default is the streaming pull
API, which is the most effective way
to achieve high-volume processing asynchronously.
And for this reason, default client libraries
just use streaming pull for maximum throughput and lowest
latency.
Streaming pull is actually a lot like push,
in that it allows pub/sub to push messages to the client
as they become available.
The difference here is that the client
gets to initiate this bidirectional persistent
connection.
The protocol here is also a lot more efficient
than HTTP POST used by push.
Cat-Out's packaging service requires
high-volume processing.
And the best way to achieve high-volume processing
is by processing asynchronously.
So packaging servers should just use default client libraries
that use streaming pull API and offers
maximum throughput and low latency.
Now that we know how a message is received by pull subscriber,
let's double-click on the message itself.
The messages sent by the publisher
can contain custom attributes.
And in subscriber code, you will have
to process those attributes.
In Cat-Out's case, say we are sending the message
from order service to packaging subscriber.
There would be custom message attributes
to include, like user_id, city, and poster_id.
Let's see how to send and receive
these message attributes.
We will use the same quick start code we used in episode three.
If you've not seen it, now is the time
to check it out, and then continue on here.
We are in our Python quickstart folder.
Let's open pub.py.
In the pub method, we will add the logic
to update the message to include custom
attributes-- the user_id, city, and poster_id.
Then we open two terminals to start our packaging subscriber
in one and send the order message from the order
publisher in the other.
And we see that the message with the same message ID
is received by the packaging subscriber
with the custom attributes that were sent.
Now what if suddenly, Cat-Out becomes famous
and their order rate increases rapidly?
Since messages are being published at a higher rate
than they are being consumed, they
would have to be processed fast enough.
If this situation persists, then Cat-Out
should consider increasing the number of subscriber client
instances to process the requests in parallel.
But if this is a transient spike in messages,
say, due to Black Friday or more cat birthdays in a month,
then there could be a few possibilities.
It's possible that one client could have a backlog
of messages, but another client in the network has capacity,
but this free client cannot process those messages
because the first client maintains a lease on them.
It's also possible that the client libraries repeatedly
extend the acknowledgment deadline
for backlogged messages.
Those messages continue to consume memory, CPU,
and bandwidth resources.
And eventually, the subscriber runs out of those resources.
To mitigate these issues, you need
to use the flow control feature of the subscriber.
In this Python example, we are limiting the subscriber
to only have 10 outstanding messages at a time.
In the high-volume context, it is
important to mention that the subscriber also
support concurrency depending on the programming language.
For language implementations that support parallel threads,
such as Java and Go, the client libraries
make a default choice for the number of threads,
but this choice may not be optimal for your application.
If you find that your subscriber application is not keeping up
with the incoming message volume, but is not CPU bound,
you should increase the thread count.
And for CPU-intensive message processing operations,
reducing the number of threads might be appropriate.
Now, there could be times when you see duplicate messages
from pub/sub.
This usually happens when you acknowledge a message
before it's acknowledgment deadline has expired.
So pub/sub resends the message, leading to duplicates.
You can detect this behavior in Stackdriver
by monitoring the acknowledge operations with the expired
response code.
To reduce the duplication rate, extend the message deadline.
Some client libraries handle this automatically,
but if you are building your own client library,
then use modifyAckDeadline method
to extend it the acknowledgment deadline.
On the other hand, if you want to force
pub/sub to retry a message, just set modifyAckDeadline to zero.
Now, there are cases where you might
need to do a bit more work than just using
the asynchronous client library we've been talking about
so far.
In those cases, you would use the synchronous pull API.
It's recommended to use synchronous pull when
the application logic might rely on a polling pattern
to retrieve messages or your application
requires a precise cap on the number
of messages retrieved by it.
Streaming pull at the moment can overdeliver
before it settles down, so when you
have a spiky load of very small messages,
it can get you in trouble.
Those applications are better off using synchronous pull.
Or in the third case, if you're using a language framework,
like PHP for example, that does not
support gRPC and require HTTP REST API,
then you have no choice but to use synchronous pull.
If we focus our attention on our Cat-Out application,
due to some resource constraints,
the notification service is designed so it can receive
a batch of messages in a single HTTP request and the number
of messages cannot exceed, say, 10.
Based on what we just learned, Cat-Out
should use synchronous pull API in this specific scenario.
All right, so today, we learned how
to receive messages using pull method.
We looked at message flow control,
concurrency, streaming pull API, and dealing
with duplicate messages.
Join us next time as we take on the next topic,
receiving messages using push.
Until then, give us a like, subscribe,
and let us know what you want to learn about Cloud Pub/Sub.
[MUSIC PLAYING]