This is a
continuation of an article that describes
operational considerations for hosting solutions on Azure public cloud.
There are
several references to best practices throughout the series of articles we wrote
from the documentation for the Azure Public Cloud. The previous article focused
on the antipatterns to avoid, specifically the Chatty I/O antipattern. This one focuses on improper
instantiation antipattern
When new
instances of classes are continually created instead of once, they can have a
significant impact on performance and responsiveness. Connections and clients
are significantly costly resources to setup. They must be created once and
reused. Each connection or client instantiation requires server handshakes
which not only incur network delay but also involve memory usage, and the
cumulative effect of numerous setup requests can slow down the system. There
are some common causes of improper instantiation which include:
Connections
and clients are created for the purpose of a data access request. When they are
scoped to one request for the sake of cleanup, they involve the server to
respond. Reading and writing individual records to a
database as distinct requests – When records are often fetched one at a time,
then a series of queries are run one after the other to get the information. It
is exacerbated when the shared libraries use hides this behavior and each
access request recreates a connection or a client. The same might happen on
write requests.
Implementing
a single logical operation as a series of data access requests. This occurs
when objects use wrappers for connections and clients and they are scoped to
methods invoking them which results in connections and clients to be disposed
often. The code appears as if a wrapper is used locally when in fact every
instantiation of the wrapper is coming with at least the cost of the RTT. When
there are many networks round trips, the cost is cumulative and even
prohibitive. It is easily observable when a wrapper has many instantiations,
and each time it creates a connection or client. In such case, there is also
the requirement to perform validation after every access.
Reading and
writing to a file on disk – File I/O also hides the distributed nature of
interconnected file systems. Every byte
written to a file on a mount must be relayed to the original on the remote
server. When the writes are several, the cost accumulates quickly. It is even
more noticeable when the writes are only a few bytes and frequent. If each access requires its own
connection or client, the application might not even know the high number of
connections it is making.
There are
several ways to fix the problem. They are about detection and remedy. When the
number of server handshakes are many, they can be batched into reused
connections via shared clients or connection pooling. The database can be read
with a shared and reusable connection pool rather than a single connection. It
also provides an opportunity for the database to free up memory corresponding
to client connections. Web APIs can be designed with the REST best practices.
Instead of separate GET method for different properties there can be single GET
method for the resource representing the object.
When more
information is retrieved via fewer connection and client instantiations, there
is a risk of falling into the extraneous fetching antipattern by trying to
prefetch more than is necessary. The right tradeoff depends on the usages. It
is also important to read only as much as necessary to avoid both the size and
the frequency of connections. Sometimes, connections and clients can also be
involving a mixed mode, shared for accounts with most requests and dedicated
for everything else. When connection is reused from a shared pool, they need
not be locked at too large a scope or for longer duration.
No comments:
Post a Comment