Microservices Verses Service-Oriented Architecture

Transcription

Microservices versesService-OrientedArchitectureMark Richards

Microservices verses Service-Oriented Architectureby Mark RichardsCopyright 2015This is a legal notice of some kind. You can add notes about the kind of license youare using for your book (e.g., Creative Commons), or anything else you feel youneed to specify.If your book has an ISBN or a book ID number, add it here as well.

Table of ContentsPreface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v1. The World of Service-Based Architectures. . . . . . . . . . . . . . . . . . . . . . . 7Service ContractsService AvailabilitySecurityTransactionsToo Much Complexity?8111314162. Comparing Service Characteristics. . . . . . . . . . . . . . . . . . . . . . . . . . . . 17Service TaxonomyService Ownership and CoordinationService GranularityGranularity and Pattern Selection172123253. Comparing Architecture Characteristics. . . . . . . . . . . . . . . . . . . . . . . . 27Component SharingService Orchestration and ChoreographyMiddleware vs. API LayerAccessing Remote Services283036394. Comparing Architecture Capabilities. . . . . . . . . . . . . . . . . . . . . . . . . . 41Application ScopeHeterogeneous InteroperabilityContract Decoupling4143455. Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49iii

A. About the Author. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51iv Table of Contents

PrefaceIn the mid-2000’s Service-Oriented Architecture (SOA) took the ITindustry by storm. Numerous companies adopted this new architec‐ture style as a way to bring better business functionality reuse intothe organization and to provide a foundation that allowed the ITorganization and the business to better communicate and collabo‐rate with each other. Dozens of best practices for implementing SOAemerged during this time, as well as a plethora of third-party prod‐ucts to help companies implement Service-Oriented Architec‐ture. Unfortunately, companies learned the hard way that SOA was abig, expensive, complicated architecture style that took too long todesign and implement, resulting in failed projects that drove SOAout of favor in the industry.Today Microservices is taking the IT industry by storm as the go-toarchitecture style used to develop highly scalable and modular appli‐cations. Microservices holds the promise of being able to addresssome of the problems associated with large, complex SOA architec‐tures as well as the problems found with big, over-bloated mono‐lithic applications. But how much different is Microservices fromService-Oriented Architecture? Is the industry destined to repeat thesame experience with Microservices as with SOA?In this report I will walk you through a detailed comparison of theMicroservices and SOA architecture patterns. You will learn thebasics of each of these architectures and core differences betweenthem in terms of the architecture style, architecture characteristics,service characteristics, and the capability differences between them.By using the information in this report you will gain the knowledgenecessary to know how these two architecture styles differ fromv

each other and which architecture style is best suited for your par‐ticular situation.vi Preface

CHAPTER 1The World of Service-BasedArchitecturesBoth Microservices Architecture and Service-Oriented Architecture(SOA) are considered service-based architectures, meaning they arearchitecture patterns that place a heavy emphasis on services as theprimary architecture component used to implement and performbusiness and non-business functionality. Although Microservicesand SOA are very different architecture styles, they share manycommon characteristics.One thing all service-based architectures have in common is thatthey are generally distributed architectures, meaning service compo‐nents are accessed remotely through some sort of remote accessprotocol (e.g., REST, SOAP, AMQP, JMS, MSMQ, RMI, .NETRemoting, etc.). Distributed architectures offer significant advan‐tages over monolithic and layered-based architectures, includingbetter scalability, better decoupling, and better control over develop‐ment, testing and deployment. Components within a distributedarchitecture tend to be more self-contained, allowing for betterchange control and easier maintenance, which in turn leads to morerobust and more responsive applications. Distributed architecturesalso lend themselves toward more loosely coupled and modulararchitectures.In the context of service-based architecture, modularity is the prac‐tice of encapsulating portions of your application into self-containedservices that can be individually designed, developed, tested, and7

deployed with little or no dependency on other components or serv‐ices in the application. Modular architectures also support thenotion of favoring rewrite over maintenance, allowing architecturesto be refactored or replaced in smaller pieces over time as the busi‐ness grows as opposed to replacing or refactoring an entire applica‐tion using a big-bang approach.Unfortunately, very few things in life are free, and the advantages ofdistributed architectures is no exception. The tradeoffs associatedwith those advantages are primarily increased complexity and cost.Maintaining service contracts, choosing the right remote access pro‐tocol, dealing with non-responsive or unavailable services, securingremote services, and managing distributed transactions are just afew of the many complex issues you have to address when creatingservice-based architectures. In this chapter I’ll describe some oftheses complex issues as they relate to Service-Based Architecture.Service ContractsA service contract is an agreement between a service (usuallyremote) and a service consumer (client) that specifies the inboundand outbound data along with the contract format (e.g., XML,JSON, Java Object, etc.). Creating and maintaining service contractsis a difficult task, one that should not be taken lightly or treated asan afterthought. As such, the topic of service contracts deservessome special attention in the scope of service-based architecture.In service-based architecture there are two basic types of servicecontract models you can use - service-based contracts andconsumer-driven contracts. The real difference between these con‐tract models is that of collaboration. With service-based contracts,the service is the sole owner of the contract, and is generally free toevolve and change the contract without considering the needs of theservice consumers. This model forces all service consumers to adoptnew service contract changes, regardless whether the service con‐sumers need or want the new service functionality.Consumer-driven contracts, on the other hand, are based on a closerrelationship between the service and the service consumers. Withthis model there is strong collaboration between the service ownerand the service consumers so that needs of the service consumersare taken into account in terms of the contracts between them. Thistype of model generally requires the service to know who it’s con‐8 Chapter 1: The World of Service-Based Architectures

sumers are and how the service is used by each service consumer.Service consumers are free to suggest changes to the service con‐tract, which the service may either adopt or reject depending onhow it affects other service consumers. In a perfect scenario serviceconsumers deliver tests to the service owner so that if one consumersuggests a change, tests can be executed to see if the change breaksanother service consumer. Open source tools such as Pact (https://github.com/realestate-com-au/pact) and Pacto (http://thought‐works.github.io/pacto) can help with maintaining and testingconsumer-driven contracts.Another critical topic within the context of service contracts is thatof contract versioning. Let’s face it - at some point the contracts bind‐ing your services and service consumers are bound to change. Thedegree and magnitude of this change is largely dependent on howthose changes affect each service consumer and the backward com‐patibility supported by the service with respect to the contractchanges.Contract versioning allows you to roll out new service features thatinvolve contract changes while at the same time providing back‐wards compatibility for service consumers that are still using priorcontracts. Perhaps one of the most important words of advice in thischapter is to plan for contract versioning from the very start of yourdevelopment effort, even if you don’t think you’ll need it - becauseeventually you will. While there are several open source and com‐mercial frameworks available to help you manage and implementcontract versioning strategies, there are two basic techniques youcan use to implement your own custom contract versioning strategy- homogeneous versioning and heterogeneous versioning.Homogeneous versioning involves using contract version numbersin the same service contract. Notice in Figure 1-1 that the contractused by service consumer A and service consumer B are both thesame circle shape (signifying the same contract) but contain differ‐ent version numbers. A simple example of this might be an XMLbased contract that represents an order for some goods with acontract version number 1.0. Let’s say a newer version (version 1.1)is released containing an additional field used to provide deliveryinstructions in the event the person is not at home when the order isdelivered. In this case the original contract (version 1.0) can remainbackwards compatible by making the new delivery instructions fieldoptional.Service Contracts 9

Figure 1-1. Contract Version NumbersHeterogeneous versioning involves supporting multiple types ofcontracts. This technique is closer to the concept of consumerdriver contracts described earlier in this section. With this techni‐que, as new features are introduced, new contracts are introduced aswell that support that new functionality. Notice the differencebetween Figure 1-1 and Figure 1-2 in terms of the service contractshape. In Figure 1-2, service consumer A communicates using a con‐tract represented by a circle, whereas service consumer B uses anentirely different contract represented by the triangle. In this casebackwards compatibility is supplied by different contracts ratherthan versions of the same contract. This is a common practice inmany JMS-based messaging systems, particularly those leveragingthe ObjectMessage message type. For instance, a Java-based receivercan interrogate the payload object sent through the message usingthe instanceof keyword and take appropriate action based on theobject type. Alternatively, XML payload can be sent through a JMSTextMessage that contains entirely different XML schema for eachcontract, with a message property indicating the correspondingXML schema associated with the XML payload.Figure 1-2. Multiple Contracts10 Chapter 1: The World of Service-Based Architectures

Providing backwards compatibility is the real goal of contract ver‐sioning. Maintaining a mindset that services must support multipleversions of a contract (or multiple contracts) will allow your devel‐opment teams to quickly deploy new features and other changeswithout fear of breaking the existing contracts with other serviceconsumers. Keep in mind that it is also possible to combine thesetwo techniques by supporting multiple version numbers for differ‐ent contract types.One last thing about service contracts with respect to contractchanges - be sure to have a solid service consumer communicationstrategy in place from the start so that service consumers knowwhen a contract changes or a particular version or contract type isno longer supported. In many circumstances this may not be feasi‐ble due to a large number of internal and/or external service con‐sumers. In this situation an integration hub (i.e., messagingmiddleware) can help by providing an abstraction layer to transformservice contracts between services and service consumers. I’ll betalking more about this capability later in this report under the Con‐tract Decoupling section in Chapter 3.Service AvailabilityService availability and service responsiveness are two other consid‐erations common to all service-based architectures. While both ofthese topics relate to the ability of the service consumer to commu‐nicate with a remote service, they have slightly different meaningsand are addressed by service consumers in different ways.Service availability refers to the ability of a remote service to acceptrequests in a timely manner (e.g., establishing a connection to theremote service). Service responsiveness, on the other hand, refers tothe ability of the service consumer to receive a timely response fromthe service. The diagram in figure 1-3 illustrates this difference.Service Availability 11

Figure 1-3. Service Availability and ResponsivenessAlthough the end result of these error conditions is the same (theservice request cannot be processed), they are handled in differentways. Since service availability is related to service connectivity,there is not much a service consumer can do except to retry the con‐nection for a set number of times or queue the request for later pro‐cessing if possible.Service responsiveness, on the other hand, is much more difficult toaddress. Once you successfully send a request to a service, how longshould you wait for a response? Is the service just slow, or did some‐thing happen in the service preventing the response from beingsent?Addressing timeout conditions is perhaps one of the most challeng‐ing aspects of remote service connectivity. A common way of deter‐mining reasonable timeout values is to first establish benchmarksunder load to get the maximum response time, and then add extratime to account for variable load conditions. For example, let’s sayyou run some benchmarks and find that the maximum responsetime for a particular service request is 2000 milliseconds . In thiscase you might double that value to account for high load condi‐tions, resulting in a timeout value of 4000 milliseconds.While this may seem like a reasonable solution to calculate a serviceresponse timeout, it is riddled with problems. First of all, if the ser‐vice really is down and not running, every request must wait 4 sec‐onds before determining that the service is not responding. This isinefficient and annoying to the end user of the service request. Theother problem is that your benchmarks may not have been accurate,and under heavy load the service response is actually averaging 5seconds rather than the 4 seconds you calculated. In this case the12 Chapter 1: The World of Service-Based Architectures

service is in fact responding, but the service consumer will rejectevery request due to the timeout value being set too low.A popular technique to address this issue is to use the circuit breakerpattern. If the service is not responding in a timely manner (or notat all), a software circuit breaker will be thrown so that service con‐sumers don’t have to waste time waiting for timeout values to occur.The cool thing is that unlike a physical circuit breaker, this patterncan be implemented to reset itself when the service starts respond‐ing or becomes available. There are numerous open-source imple‐mentations of the circuit breaker pattern, including Ribbon fromNetflix. You can read more about the circuit breaker pattern inMichael Nygard’s book Release It!.When dealing with timeout values try to avoid the use of globaltimeout values for every request. Instead, consider using contextbased timeout values and always make these externally configurableso that you can respond quickly for varying load conditions withouthaving to rebuild or redeploy the application. Another option is tocreate “smart timeout values” embedded in your code that canadjust themselves based on varying load conditions. For example,the application could automatically increase the timeout value inresponse to heavy load or network issues. As load decreases andresponse times become faster, the application could then calculatethe average response time for a particular request and lower thetimeout value accordingly.SecurityBecause services are generally accessed remotely in service-basedarchitectures, it is important to make sure the service consumer isallowed to access a particular service. Depending on your situation,service consumers may need to be both authenticated and author‐ized. Authentication refers to whether the service consumer canconnect to the service, usually through sign-on credentials using ausername and password. In some cases authentication is not enough- just because a service consumer can connect to a service doesn’tnecessarily mean they can access all of the functionality in that ser‐vice. Authorization refers to whether or not a service consumer isallowed to access specific business functionality within a service.Security was a major issue with early Service-Oriented Architectureimplementations. Functionality that used to be located in a secureSecurity 13

silo-based application was suddenly available globally to the entireenterprise. This issue created a major shift in how we think aboutservices and how to protect them from consumers who should nothave access to them.With Microservices, security becomes a challenge primarily due tothe lack of a middleware component to handle security-based func‐tionality. Instead, each service must handle security on its own, or insome cases the API layer can be made more intelligent to handle thesecurity aspects of the application. One security design I have seenimplemented in Microservices that works well is to delegate authen‐tication to a separate service and place the responsibility for authori‐zation in the service itself. While this design could be modified todelegate both authentication and authorization to a separate securityservice, I prefer encapsulating the authorization in the service itselfto avoid chattiness with a remote security service and to create astronger bounded context with fewer external dependencies.TransactionsTransaction management is a big challenge in service-based archi‐tectures. Most of the time when we talk about transactions we arereferring to the ACID transactions (atomicity, consistency, isolation,and durability) found in most business applications. ACID transac‐tion are used to maintain database consistency by coordinating mul‐tiple database updates within a single request so that if an erroroccurs during processing, all database updates are rolled back forthat request.Given that service-based architectures are generally distributedarchitectures, it is extremely difficult to propagate and maintain atransaction context across multiple remote services. As illustrated inFigure 1-4, a single service request (represented by the box next tothe red X) may need to call multiple remote services to complete therequest. The red X in the diagram indicates that it is not feasible touse an ACID transaction in this scenario.14 Chapter 1: The World of Service-Based Architectures

Figure 1-4. Service Transaction ManagementTransaction issues are much more prevalent in Service-OrientedArchitecture because, unlike Microservices architecture, multipleservices are typically used to perform a single business request. I dis‐cuss this in more detail in the Service Orchestration section of Chap‐ter 3.Rather than use ACID transactions, service-based architectures relyon something called BASE transactions. BASE is a family of stylesthat include basic availability, soft state, and eventual consistency.Distributed applications relying on BASE transactions strive foreventual consistency in the database rather than consistency at everytransaction. A classic example of BASE transactions is making adeposit into an AT

CHAPTER 1 The World of Service-Based Architectures Both Microservices Architecture and Service-Oriented Architecture (SOA) are considered service-based architectures, meaning they are architecture patterns that place a heavy emphasis on services as the primary architecture component used to implement and perform