This document provides an overview of microservices for developers experienced with monolithic applications. It discusses how microservices address modern app needs like continuous delivery and variable scaling. Key aspects covered include determining service boundaries, designing APIs, managing distributed data, and setting up platforms to support microservices. The goal is to help monolith developers understand what to expect when working on microservices projects.
2. 1
2
3
4
5
Agenda
Microservices Overview
Service and API Boundaries
Designing for Distributed Data
Managing Microservices
Demo with Azure Service Fabric
GOAL: Understand what to expect on Microservices projects
3. Impact of Modern Apps
Users expect more features without downtime
Developers have to figure out a solution
10. DDD: Bounded Context
“Bounding contexts gives team
members a clear and shared
understanding of what has to
be consistent and what can
develop independently.”
- Eric Evans, Domain-Driven Design, 2003
14. Entities & Processes
Services boundaries tend to be separated by nouns & verbs
Student
Service
Course
Service
NOUNS (Entity CRUD)
Batch
Enrollment
Search
Prospects
VERBS (Business Process)
15. Optional Monolithic Start
Bounded Contexts
Variable Scaling
Change Frequency
Business Process
Start large and break down based on:
16. EXAMPLE: EF Bounded Context
// Typical EF setup with all data models in single DB context
public class SchoolDbContext : DbContext, ISchoolDbContext
{
public DbSet<Student> Students { get; set; }
public DbSet<Course> Courses { get; set; }
public DbSet<Subject> Subjects { get; set; }
public DbSet<Faculty> Faculty { get; set; }
public DbSet<FacultyMember> FacultyMembers { get; set; }
}
17. EXAMPLE: EF Bounded Context
// Contexts grouped by entities w/ related, specific operations
public class StudentDbContext : DbContext
{
public DbSet<Student> Students { get; set; }
public DbSet<ClassSchedule> ClassSchedules { get; set; }
}
public class CourseDbContext : DbContext { }
public class FacultyDbContext : DbContext { }
24. Monolith Queries
SELECT -- Syllabus and advisor info
FROM StudentSyllabus ss
INNER JOIN Syllabus s ON ss.SyllabusId = s.Id
INNER JOIN Course c ON s.CourseId = c.Id
INNER JOIN Advisor a ON ss.AdvisorId = a.Id
INNER JOIN [User] u ON a.UserId = u.Id
WHERE ss.[Year] = @currentYear
AND ss.StudentId = @studentId
AND ss.IsActive = 1
27. Cross-Service Queries
fetch('/api/v1/students/12345/schedule/2017')
.then((response) => response.json())
.then(function(student) {
// Call the other services to get “join” data
var advisorApi = '/api/v1/faculty/members/' + student.advisorId;
var courseApis = [];
student.courses.forEach(function(course) {
courseApis.push('/api/v1/courses/' + course.id);
}, this);
// Create promises, merge results, data binding, etc.
});
29. Materialized Views
fetch('/api/v1/students/12345/syllabus/2017')
.then((response) => response.json())
.then(function(student) {
// Call the other services to get “join” data
var advisorApi = '/api/v1/faculty/members/' + student.advisorId;
var courseApis = [];
student.courses.forEach(function(course) {
courseApis.push('/api/v1/courses/' + course.id);
}, this);
// Create promises, merge results, data binding, etc.
});
// Trade-off is more backend code for event publishing
fetch('/api/v1/students/12345/schedule/2017’).then(...)
30. Monolith Commands
using (IDbContext db = _dbFactory.GetContext())
{
Syllabus syllabusDataModel = db.Syllabus.Single(s =>
s.Id == syllabusDomainModel.Id);
Mapper.MapChanges(
syllabusDataModel, syllabusDomainModel);
// Built-in transactions for related tables
db.SaveChanges();
}
40. Tools/Frameworks/Libraries
Event Stores
Eventuate
Cosmos DB Change Feed
eventstore.org
Service Discovery
Service Fabric Naming Service
Consul
Netflix Eureka
API Gateway
Azure/AWS API Management
Mulesoft
Google Apigee
Event Messaging
Azure/AWS queue services
Apache Kafka
RabbitMQ
41. More Info
Questions? lfaulkner@cardinalsolutions.com
Design patterns and technical approaches:
http://microservices.io/
https://docs.microsoft.com/en-us/azure/architecture/ (Cloud Patterns PDF)
https://martinfowler.com/articles/microservices.html
How they did it:
http://searchmicroservices.techtarget.com/ (RSS)
https://medium.com/netflix-techblog
https://blogs.msdn.microsoft.com/bharry/ (How the VSTS team does it)
Editor's Notes
Poll audience –
have used microservices;
have not but experienced with monoliths;
have just heard the buzzwords
Walk away with enough info to research on your own, so will table deep dive questions.
Users want more features, no downtime, and have other options
Microservices provides agility and flexibility to application design
Independent services, own data storage, deployed independently
This graphic really clarified microservices for me
Monoliths – Tightly integrated, changes have ripple effects to rest of app
SOA – Looser coupling, but had to be orchestrated to fit together
Microservices – Independently developed and deployed
Earlier – Mainframes
New – Serverless
Does this apply to you? Technical approaches we’re about to discuss have complexity trade-offs.
Like with any architecture, make sure to use right tool for the job
Going straight to microservices is a risk. A lot more technical complexity
What are the boundaries
DDD provides a holistic view of software design. Bounded context is one of its patterns.
Small models that support specific operations
Quote gets to the heart of what microservices
“Delimited applicability”
Group into sets that represent related, specific operations.
How micro is micro? Add, Edit as separate services would be a nanoservice. Group by related but specific operations
Independent services, own data storage, deployed independently
As mentioned in earlier slide, if bounded contexts are unknown or you’re not sure ROI there for the technical complexity trade-off, option to start as a monolith and break it down.
Illustrate breaking down monoliths with EF contexts.
Contexts grouped by specific operations/transactions.
As microservices grow, becomes difficult for web and mobile developers to understand how to use them.
Consolidate/orchestrate calls, provide single API call for consumers
Good REST design (DX, Developer Experience. API UX for web/mobile developers)
API gateway
Versioning
Isolated databases
Calling other services
Duplicated data is ok
Event-driven architecture
CQRS
Direct DB access creates a tight coupling that loses the benefit of microservices
Have to call out to other services to get “join” data
Still gain scale advantages of other endpoints
Plus, the other services might be doing their own gets. Slippery slope
Call each service and aggregate the results
Also can push aggregation to server, e.g., API Gateway, or inter-service calls
Note the use of messaging, not a tightly coupled replication feature
Also an example of CQRS
Trade off is more code for pub/sub, but less code on query
Replace the logic that aggregates results to directly calling the materialized view
That’s queries, now let’s look at commands (saves)
Switch from SQL to ORM to more easily illustrate transactions
Same deal, don’t create tight coupling by saving directly to other service db’s
2pc not an option (not all db types support it)
Event-driven, eventually consistent approach
Pros: Consistency across services
Cons: More complex, event publishing must be reliable
Use an event store
Add only, so faster and no local transaction needed
Replay events for current state
Services still subscribe
Most event stores have snapshots for performance
- Eventuate, Cosmos DB change feed
Others – transaction log tailing/mining (Linkedin w/ Oracle, AWS)
(depends on your IT setup) Teams own repos, builds, releases