github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/docs/blog/_posts/2016-04-18-micro-architecture.md (about) 1 --- 2 layout: post 3 title: Micro architecture & design patterns for microservices 4 date: 2016-04-18 09:00:00 5 --- 6 <br> 7 We've had a lot of questions about the micro architecture and design patterns for microservices over the past few months. So today we'll try cover both. 8 9 ###### About Micro 10 11 [**Micro**](https://github.com/tickoalcantara12/micro) is a microservices toolkit. It was built to be opinionated in it's features and interfaces while 12 providing a powerful pluggable architecture allowing the underlying dependencies to be swapped out. 13 14 Micro is focused on addressing the fundamental requirements for building microservices and has looked to do this by taking a thoughtful and measured 15 approach to it's design. 16 17 If you would like to read up on the Micro toolkit check out the previous blog post [here]({{ site.baseurl }}{{ site.baseurl }}/2016/03/20/micro.html) or if you would like to learn 18 more about the concept of microservices look [here]({{ site.baseurl }}/2016/03/17/introduction.html). 19 20 We'll quickly recap on the features of Micro before delving into further architecture discussion. 21 22 ###### The Toolkit 23 24 [**Go Micro**](https://github.com/micro/go-micro) is a pluggable RPC framework for writing microservices in Go. It provides libraries for 25 service discovery, client side load balancing, encoding, synchronous and asynchronous communication. 26 27 [**Micro API**](https://github.com/tickoalcantara12/micro/tree/master/api) is an API Gateway that serves HTTP and routes requests to appropriate micro services. 28 It acts as a single entry point and can either be used as a reverse proxy or translate HTTP requests to RPC. 29 30 [**Micro Web**](https://github.com/tickoalcantara12/micro/tree/master/web) is a web dashboard and reverse proxy for micro web applications. We believe that 31 web apps should be built as microservices and therefore treated as a first class citizen in a microservice world. It behaves much the like the API 32 reverse proxy but also includes support for web sockets. 33 34 [**Micro Sidecar**](https://github.com/tickoalcantara12/micro/tree/master/car) provides all the features of go-micro as a HTTP service. While we love Go and 35 believe it's a great language to build microservices, you may also want to use other languages, so the Sidecar provides a way to integrate 36 your other apps into the Micro world. 37 38 [**Micro CLI**](https://github.com/tickoalcantara12/micro/tree/master/cli) is a straight forward command line interface to interact with your micro services. 39 It also allows you to leverage the Sidecar as a proxy where you may not want to directly connect to the service registry. 40 41 That's the quick recap. Now let's go deeper. 42 43 ###### RPC, REST, Proto... 44 45 So the first thing you might be thinking is why RPC, why not REST? Our belief is that RPC is a more appropriate choice for inter-service communication. 46 Or more specifically RPC using protobuf encoding and APIs defined with protobuf IDL. This combination allows the creation of strongly defined 47 API interfaces and an efficient message encoding format on the wire. RPC is a straight forward, no frills, protocol for communication. 48 49 We're not alone in this belief. 50 51 Google is creator protobuf, uses RPC internally and more recently open sourced gRPC, an 52 RPC framework. Hailo was also a strong advocate of RPC/Protobuf and benefited tremendously, interestingly more so in cross team development than systems performance. 53 Uber choosing their own path has gone on to develop a framing protocol for RPC called [TChannel](http://uber.github.io/tchannel/). 54 55 56 Personally we think the APIs of the future will be built using RPC because of their well defined structured format, propensity for use with efficient encoding 57 protocols such as protobuf with the combination offering strongly defined APIs and performant communication. 58 59 ###### HTTP to RPC, API... 60 61 In reality though, we're a long way from RPC on the web. While its perfect inside the datacenter, serving public facing traffic e.g websites and mobile 62 APIs, is a whole other deal. Let's face it, it's going to be a while before we move away from HTTP. This is one of the reasons why micro includes 63 an API gateway, to serve and translate HTTP requests. 64 65 The API gateway is a pattern used for microservice architectures. It acts as a single entry point for the outside world and routes to an appropriate service based 66 on the request. This allows a HTTP API itself to be composed of different microservices. 67 68 This is a powerful architecture pattern. Gone are the days where a single change to one part of your API could bring down the entire monolith. 69 70 The micro API uses path-to-service resolution so that each unique request path can be served by a different API micro service e.g. /user => user api, 71 /order => order api. 72 73 Here's an example. A request to **/customer/orders** will be sent to the API service **go.micro.api.customer** with method **Customer.Orders**. 74 75 <p align="center"> 76 <img src="{{ site.baseurl }}/blog/images/api.png" style="width: 100%; height: auto;" /> 77 </p> 78 79 You might be wondering what the heck an API service is. Now is about the right time to discuss the different types of services. 80 81 ###### Types of Services 82 83 The concept of Microservices is all about separation of concerns and borrows a lot from the unix philosophy of doing one thing and doing it well. 84 Partly for that reason we think there needs to be a logical and architectural separation between services with differing responsibilities. 85 86 I'll acknowledge right now that these concepts are nothing new but they are compelling given they've been proven in very large successful technology companies. 87 Our goals are to spread these development philosophies and guide design decisions via tooling. 88 89 So here's the types of services we currently define. 90 91 **API** - Served by the **micro api**, an API service sits at the edge of your infrastructure, most likely serving public facing traffic and your 92 mobile or web apps. You can either build it with HTTP handlers and run the micro api in reverse proxy mode or by default handle a specific RPC API request response 93 format which can be found [here](https://github.com/tickoalcantara12/micro/blob/master/api/proto/api.proto). 94 95 **Web** - Served by the **micro web**, a Web service focuses on serving html content and dashboards. The micro web reverse proxies HTTP and WebSockets. 96 These are the only protocols supported for the moment but that may be extended in the future. As mentioned before, we believe in web apps as microservices. 97 98 **SRV** - These are backend RPC based services. They're primarily focused on providing the core functionality for your system and are most likely not be 99 public facing. You can still access them via the micro api or web using the /rpc endpoint if you like but it's more likely API, Web and other SRV services use 100 the go-micro client to call them directly. 101 102 <p align="center"> 103 <img src="{{ site.baseurl }}/blog/images/arch.png" /> 104 </p> 105 106 Based on past experiences we've found this type of architecture pattern to be extremely powerful and seen it scale to many hundreds of services. 107 By building it into the Micro architecture we feel it provides a great foundation for microservice development. 108 109 ###### Namespacing 110 111 So you might wonder, what's to stop the micro api from talking to web services or the micro web talking to api services. We use logical namespacing 112 to separate these. By prefixing a namespace to a service name we clearly identify it's purpose and place in the system. It's a simple but effective 113 pattern that has served us well. 114 115 The micro api and web will compose a service name of the namespace and first path of a request path e.g. request to api **/customer** becomes **go.micro.api.customer**. 116 117 The default namespaces are: 118 119 - **API** - go.micro.api 120 - **Web** - go.micro.web 121 - **SRV** - go.micro.srv 122 123 You should set these to your domain e.g *com.example.{api, web, srv}*. The micro api and micro web can be configured at runtime to route to your namespace. 124 125 ###### Sync vs Async 126 127 You'll often hear microservices in the same sentence as reactive patterns. For many, microservices is about creating event driven architectures and designing services 128 that interact primarily through asynchronous communication. 129 130 Micro treats asynchronous communication as a first class citizen and a fundamental building block for microservices. Communicating events through asynchronous 131 messaging allows anyone to consume and act upon them. New standalone services can be built without any modification to other aspects of the system. It's a 132 powerful design pattern and for this reason we've included the [Broker](https://godoc.org/github.com/micro/go-micro/broker#Broker) interface in go-micro. 133 134 <p align="center"> 135 <img src="{{ site.baseurl }}/blog/images/pub-sub.png" /> 136 </p> 137 138 Synchronous and asynchronous communication are addressed as separate requirements in Micro. The [Transport](https://godoc.org/github.com/micro/go-micro/transport#Transport) 139 interface is used to create a point to point connection between services. The go-micro client and server build upon the transport to perform request-response RPC and provide 140 the capability of bidirectional streaming. 141 142 <p align="center"> 143 <img src="{{ site.baseurl }}/blog/images/request-response.png" /> 144 </p> 145 146 Both patterns of communication should be used when building systems but it's key to understand when and where each is appropriate. In a lot of cases there's 147 not right or wrong but instead certain tradeoffs will be made. 148 149 An example of where the broker and asynchronous communication could potentially be used is in an audit trail system for keeping track of customer event history. 150 151 <p align="center"> 152 <img src="{{ site.baseurl }}/blog/images/audit.png" style="width: 100%; height: auto;" /> 153 </p> 154 155 In this example every API or service publishes an event when some action occurs such as a customer logs in, update their profile or places an order. The audit service will 156 subscribe for these events and store them in a time series database of some kind. An admin or anyone else can then view the history of events that 157 have taken place within the system for any user. 158 159 If this was done as a synchronous call we could easily overwhelm the audit service when there's high traffic or as the number of bespoke services increases. 160 If the audit service was taken offline for some reason or a call failed we would essentially lose this history. By publishing these events to the broker 161 we can persist them asynchronously. This is a common pattern in event driven architectures and for microservices. 162 163 ###### OK wait, brief pause, but what defines a microservice? 164 165 We're covering a lot of what the Micro toolkit provides for microservices and we've defined the types of services (API, WEB, SRV) but there's nothing really 166 about what a microservice actually is. 167 168 How does it differ from any other kind of application? What gives it this special name of a "microservice". 169 170 There's varying definitions and interpretations but here's a couple that fit best in the Micro world. 171 172 173 > Loosely coupled service oriented architecture with a bounded context <br/> 174 > <sub>Adrian Cockcroft</sub> 175 176 <p/> 177 178 > An approach to developing a single application as a suite of small services, 179 each running in its own process and communicating with lightweight mechanisms <br/> 180 > <sub>Martin Fowler</sub> 181 182 And because we love the unix philosophy and feel it fits perfectly with the microservice philosophy. 183 184 > Do one thing and do it well <br/> 185 > <sub>Doug McIlroy</sub> 186 187 Our belief and the idea we build on is that a microservice is an application focused on a single type of entity or domain, which it provides access to 188 via a strongly defined API. 189 190 Let's use a real world example such as a social network. 191 192 <p align="center"> 193 <img src="{{ site.baseurl }}/blog/images/facebook.png" style="width: 100%; height: auto;" /> 194 </p> 195 196 A well defined software architecture pattern that became popular with the rise of Ruby on Rails was 197 [MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) - Model-View-Controller. 198 199 In the MVC world each entity or domain would be represented a model which in turn abstracts away the database. The model may have relationships with 200 other models such as one to many or many to many. The controller processes in coming requests, retrieves data from the models and passes it to the 201 view to be rendered to the user. 202 203 Now take the same example as a microservice architecture. Each of these models is instead a service and delivers its data through an API. User requests, 204 data gathering and rendering is handled by a number of different web services. 205 206 Each service has a single focus. When we want to add new features or entities we can simply change the one service concerned with that feature 207 or write a new service. This separation of concerns provides a pattern for scalable software development. 208 209 Now back to our regularly scheduled program. 210 211 ###### Versioning 212 213 <p align="center"> 214 <img src="{{ site.baseurl }}/blog/images/versioning.png" style="width: 100%; height: auto;" /> 215 </p> 216 217 Versioning is an important part of developing real world software. In the microservice world it's critical given the API and business logic is split 218 across many different services. For this reason its important that service versioning be part of the core tooling, allowing finer grained control over 219 updates and traffic shaping. 220 221 In go-micro a service is defined with a Name and Version. The [Registry](https://godoc.org/github.com/micro/go-micro/registry#Registry) returns a service 222 as a list, splitting the nodes by the version they were registered with. 223 224 This is our building block for version based routing. 225 226 ``` 227 type Service struct { 228 Name string 229 Version string 230 Metadata map[string]string 231 Endpoints []*Endpoint 232 Nodes []*Node 233 } 234 ``` 235 236 This in combination with the [Selector](https://godoc.org/github.com/micro/go-micro/selector#Selector), a client side load balancer, within go-micro ensures 237 that requests are distributed across versions accordingly. 238 239 The selector is a powerful interface which we're building on to provide different types of routing 240 algorithms; random (default), round robin, label based, latency based, etc. 241 242 By using the default random hashed load balancing algorithm and gradually adding instances of a new service version you can perform blue-green deployment and 243 do canary testing. 244 245 <p align="center"> 246 <img src="{{ site.baseurl }}/blog/images/selector.png" /> 247 </p> 248 249 In the future we'll look to implement a global service load balancer which ties into the selector allowing for routing decisions based on historic trends 250 within a running system. It will also be capable of adjusting the percentage of traffic sent to each version of a service at runtime and dynamically 251 adding metadata or labels to a service, which label based routing decisions can be made on. 252 253 ###### Scaling 254 255 The above commentary on versioning begins to hint at the foundational patterns for scaling a service. While the registry is used as a mechanism for storing 256 information about a service, we separate the concern of routing and load balancing using the selector. 257 258 Again the notion of separation of concerns and doing one thing well. Scaling infrastructure as well as code is very much about simplicity, strongly defined 259 APIs and a layered architecture. By creating these building blocks we allow ourselves to construct more scalable software and address higher level concerns 260 elsewhere. 261 262 This is something fundamental to the way Micro is written and how we hope to guide software development in a microservices world. 263 264 We've briefly discussed cloud architecture patterns in a previous post about [Micro on NATS]({{ site.baseurl }}/2016/04/11/micro-on-nats.html#scaling-micro-on-nats) 265 and will re-address some of the ideas here. 266 267 When deploying services in a production setting you'll be looking to build something scalable, fault tolerant and performant. Cloud computing now gives us 268 access to pretty much unlimited scale but nothing is impervious to failure. In fact failure is one of the key aspects that we look to 269 address when building distributed systems and you should take this into consideration when building your infrastructure. 270 271 In the world of the cloud, we want to be tolerant of Availability Zone (datacenter) failures and even entire Region (Multi DC) outages. In past days, we used to 272 talk about warm and cold standby systems or disaster recovery plans. Today the most advanced technology companies operate in a global manner, where multiple copies 273 of every application is running in a number datacenters across the world. 274 275 We need to learn from the likes of Google, Facebook, Netflix and Twitter. We must build systems capable of tolerating an AZ failure without any impact on the user and in 276 most cases dealing with region failures within minutes or less. 277 278 Micro enables you to build this kind of architecture. By providing pluggable interfaces we can leverage the most appropriate distributed systems for each 279 requirement of the micro toolkit. 280 281 Service discovery and the registry are the building block of Micro. It can be used to isolate and discover a set of services within an AZ or Region or any 282 configuration you so choose. The Micro API can then be used to route and balance a number of services and their instances within that topology. 283 284 <p align="center"> 285 <img src="{{ site.baseurl }}/blog/images/regions.png" style="width: 100%; height: auto;" /> 286 </p> 287 288 ###### Summary 289 290 Hopefully this blog post provides clarity on the architecture of Micro and how it enables scalable design patterns for microservices. 291 292 Microservices is first and foremost about software design patterns. We can enable certain foundational patterns through tooling while providing flexibility for 293 other patterns to emerge or be used. 294 295 Because Micro is a pluggable architecture it's a powerful enabler of a variety of design patterns and can be appropriately used in many scenarios. For 296 example if you're building video streaming infrastructure you may opt for the HTTP transport for point to point communication. If you are not latency 297 sensitive then you may choose a transport plugin such as NATS or RabbitMQ instead. 298 299 The future of software development with a tool such as Micro is very exciting. 300 301 If you want to learn more about the services we offer or microservices, check out the [blog](/), the website 302 [micro.mu](https://m3o.com) or the github [repo](https://github.com/tickoalcantara12/micro). 303 304 Follow us on Twitter at [@MicroHQ](https://twitter.com/m3ocloud) or join the [Slack](https://slack.m3o.com) 305 community [here](http://slack.m3o.com). 306