7. Once upon a time in a far far away galaxy
country…
John wants to meet someone Ygritte wants to meet someone
8. Ygritte knows what king of John she wants
Ygritte knows what she wants for her.
She is looking for a John that match with her criterias.
$ curl –XGET https://api.meetic.fr/search?height=188&eyes=brown®ion=north&country=westeros
9. John knows nothing
John is looking for love, wherever it comes from.
(Except from Casterly Rock)
$ curl –XGET https://api.meetic.fr/search/1234/shuffle
John’s Id
10. Summary
• Let’s introduce the search microservice
• An overview of the code architecture in a microservice
• Indexing data
• What happens when Ygritte update her profile?
• John signs up on Meetic. How his profile is indexed?
• Searching people
• Overview of the advanced search feature used by Ygritte
• How does Meetic suggest profile that may interest John?
12. The search microservice
The search microservice has one responsibility and only one :
Searching Meetic users
Some Meetic features :
• Advanced Search
• Shuffle (Tinder like)
• Online profiles
• Similar Profiles
• Etc..
13. The search microservice
In order to do so, the search microservice should :
• Be responsible of the way data is stored
• Be aware of any data updates when the updates are in its scope
• Return a list of profile’s ID when calling it
16. About code structure in a
microservice @ Meetic
Don’t blame your messy code, blame the design pattern.
(or the architect, or the tech lead, or the product owner)
17. The hexagonal workflow
Request (GET)
Handler
DAO
Domain Object
Domain
Repository
Populate
Call
Implements
Infrastructure
Application
Domain
19. Design pattern hexagonal
Define the “profile” domain object
Implement the repository using Guzzle
Handle the “search” request
Define how profile should be get
Implement the repository using Doctrine
23. John signs up on Meetic
(What should be done)
Event bus
Consumer
Profile
Exposition Layer
POST
{
”id”: 1234,
“birthday”: “1989-01-12,
”picture”: “me.jpg”
}
POST
{
”id”: 1234,
“birthday”: “1989-01-12
}
POST
{
”id”: 6789,
“birthday”: “1989-01-12,
“has_photo”: true,
“paymentStatus”: “free”,
….
}
GET /1234/pictures
GET /payment-status/1234
GET …
Picture
POST
{
”id”: 1234,
“picture”: “me.jpg”
}
24. Theory vs reality
Calling microservices
+ In case of change on any databases, this workflow stay unchanged
+ Avoid duplicated business logic
- Don’t scale very well because of the number of http calls needed
- Takes a lot of time to implement
25. John signs up on Meetic
(What is really done)
Event bus
Consumer
Profile
Exposition Layer
POST
{
”id”: 1234,
“birthday”: “1989-01-12
}
POST /reload/6789
Search
SELECT * FROM PROFILE
LEFT JOIN PAYMENT
WHERE ID = 1234POST
{
”id”: 1234,
“birthday”: “1989-01-12,
“eye”: “brown”,
“paymentStatus”: “free”,
….
}
Picture
POST
{
”id”: 1234,
“birthday”: “1989-01-12,
”picture”: “me.jpg”
}
POST
{
”id”: 1234,
“picture”: “me.jpg”
}
26. Theory vs reality
Querying the database
+ The search microservice stays responsible of his data
+ Allows batch processing
- Works only because databases are not yet split
- Change on the database have to be replicated in the search
microservice
28. What does the reload query looks
like?
SELECT
ID,
BIRTHDAY,
…,
(SELECT * FROM …),
FROM MEETIC.MEMBER
INNER JOIN …
LEFT JOIN…
INNER JOIN…
LEFT JOIN…
LEFT JOIN…
INNER JOIN…
WHERE (
SELECT T FROM MEETIC.T WHERE …
)
AND …
OR…
29. Keeping the reload query maintainable
Since we chose to get data directly from the database when creating a
new document in the index, the SQL query is huge and complex.
• We need it to be easily shared, review and updated by DBAs
• We need to keep it isolated so changes in the DB schema can be
reported in a single file
• We want to be able to just copy-paste it and check if it works.
30. Managing big (SQL) queries with Symfony
#1 Step : The
application handle the
request by calling the
domain interface
31. Managing big (SQL) queries with Symfony
#2 Step : The
domain describe
how objects
should be
manipulated
32. Managing big (SQL) queries with Symfony
#3 Step : The
infrastructure actually
manipulate data.
37. Ygritte uses the search engine
Exposition Layer
Search
POST
{
“query”: {
“term”: {
”eyes”: “brown”
}
}
}
GET /search?eye=brown&hair=brown
GET /search?eye=brown&hair=brown
{
”memberId”: [
1234,
456786,
]
}
38.
39. Keeping the search logic clear
Templating ElasticSearch queries with twig
40. What does an ElasticSearch
query look like?
Most of the time the ElasticSearch query contains the larger
part of the business logic.
• Very long
• Lot of strange json key
• Lot of parameters
And yet…
41. Why not generating queries via php?
• Managing big PHP array throw if…else is quite hard
• It becomes harder to understand what actually
does the query.
42. Keeping the
business logic clear
with twig
Templating the json query using
twig let us know easily what
actually does the query
48. Building query from multiple source
Request (GET)
Handler
Enricher
Domain Object
Domain
Repository
Populate
Call
Implements
Infrastructure
Application
Domain
DAO DAO
DAO
49. Optimizing response time with Guzzle promises
Http calls take time.
Guzzle promises let us use
parallelism in order to save
precious milliseconds.
52. Search microservice in production
• 19 millions hits per day
• ~ 10 servers on 2 DC needed to be “Disaster Recovery Plan” friendly
• Search route AVG response time : ~ 163 ms
• Shuffle route AVG response time : ~ 336 ms