Giter VIP home page Giter VIP logo

spring-reator-microservices's Introduction

Components structures

  1. Common

Structure

└── com
    └── ms
        ├── constant : All constants values that can be used in the services
        ├── domain : Object that can be used in the services
        │   ├── external :
        │   └── product
        │       ├── model : Product model and Product AggreeGate
        │       └── repository
        ├── enums: Common Enumerate
        ├── event: DDD Events & base handler used in `publiser` and subsciber
        ├── exceptions: Common exception
        ├── filter: Centralize Filter request can be use
        ├── http:
        ├── mapper: Base mapper
        └── shared : Common class can be shared
  1. Mock-services

Mock partner service such as lazada, shopee, tiki

  1. Services 3.1. Event Service

Handle Events from Kafka.In this example every event will be store in MongoDB for late usage.Each event will have event-handler class accordingly.Below is event class diagram.

Event class diagram

Event Handler diagram Event service used Spring Cloud stream to simplyfiez the process

  spring:
  application.name: event-service
  kafka:
    consumer:
      properties:
        spring.json.trusted.packages: "*"
      value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
  cloud:
    function.definition: consumeEvent
    stream:
      bindings:
        consumeEvent-in-0.destination: ${app.events.topic}
        consumeEvent-in-0.group: eventGroup
3.2.Product Composite service

Product Composite diagram

  1. Spring Cloud 4.1 Gateway

To comunicate the services and hide the outside.The configuration as below

spring.cloud.gateway.routes:
  - id: product-composite
    uri: http://product-composite
    predicates:
      - Path=/api/v1/products/**

  - id: oauth-server
    uri: http://${app.auth-server}
    predicates:
      - Path=/oauth/**
4.2 Authorization-Server

OAuth 2.0 Authorization Server.

Software usage

  • Spring Boot
  • Spring Reactive Webflux

Spring Framework uses Project Reactor as the base implementation of its reactive support, and also comes with a new web framework, Spring WebFlux, which supports the development of reactive, that is, non-blocking, HTTP clients and services.

  • Spring Cloud Stream Kafka Binder

Spring Cloud Stream comes with opinionated conventions on how to handle messaging

  • Docker

Deploying Our Microservices Using Docker

Running the microservices

To run the server, do:

./run.sh

or run step by step commands

./gradlew build
docker-compose build
docker-compose up

It will take a long time as downloading docker images file zookeeper,kafka,mongdodb,openjdk:12.0.2 Running unit tests on product-composite-service Create microservices images .. Below is some logs from the command (run.sh)

Status: Downloaded newer image for confluentinc/cp-zookeeper:latest
Status: Downloaded newer image for mongo:3.6.9
Creating mongodb     ... done
Creating tiki        ... done
Creating zookeeper   ... done
Creating shopee      ... done
Creating gateway     ... done
Creating auth-server ... done
Creating lazada      ... done
Creating kafka       ... done
Creating event-service     ... done
Creating product-composite ... done
Attaching to tiki, lazada, mongodb, shopee, auth-server, gateway, zookeeper, kafka, product-composite, event-service
event-service        |  value.deserializer = class org.springframework.kafka.support.serializer.JsonDeserializer
event-service        |
event-service        | 2021-01-25 15:09:50.887  INFO 1 --- [pool-3-thread-1] o.a.kafka.common.utils.AppInfoParser     : Kafka version: 2.6.0
event-service        | 2021-01-25 15:09:50.887  INFO 1 --- [pool-3-thread-1] o.a.kafka.common.utils.AppInfoParser     : Kafka commitId: 62abe01bee039651
event-service        | 2021-01-25 15:09:50.887  INFO 1 --- [pool-3-thread-1] o.a.kafka.common.utils.AppInfoParser     : Kafka startTimeMs: 1611587390887
event-service        | 2021-01-25 15:09:50.898  INFO 1 --- [pool-3-thread-1] org.apache.kafka.clients.Metadata        : [Consumer clientId=consumer-eventGroup-3, groupId=eventGroup] Cluster ID: WM2Fm9RZSx-OkgCInbcWTw
event-service        | 2021-01-25 15:09:50.922  INFO 1 --- [pool-3-thread-1] o.a.k.c.c.internals.AbstractCoordinator  : [Consumer clientId=consumer-eventGroup-3, groupId=eventGroup] Discovered group coordinator kafka:29092 (id: 2147483646 rack: null)
event-service        | 2021-01-25 15:09:50.934  INFO 1 --- [pool-3-thread-1] o.a.k.c.c.internals.ConsumerCoordinator  : [Consumer clientId=consumer-eventGroup-3, groupId=eventGroup] Found no committed offset for partition event-0
mongodb              | 2021-01-25T15:10:04.898+0000 I NETWORK  [listener] connection accepted from 127.0.0.1:60810 #5 (3 connections now open)
mongodb              | 2021-01-25T15:10:04.899+0000 I NETWORK  [conn5] received client metadata from 127.0.0.1:60810 conn5: { application: { name: "MongoDB Shell" }, driver: { name: "MongoDB Internal Client", version: "3.6.9" }, os: { type: "Linux", name: "PRETTY_NAME="Debian GNU/Linux 9 (stretch)"", architecture: "x86_64", version: "Kernel 4.19.121-linuxkit" } }
mongodb              | 2021-01-25T15:10:04.904+0000 I NETWORK  [conn5] end connection 127.0.0.1:60810 (2 connections now open)

How to used

  1. First get accessToken to perform the Search API

Once it is up, this request asks for a token with the "product:read" scope:

curl -k https://writer:secret@localhost:8443/oauth/token -d grant_type=password -d username=customer -d password=password -s | jq .

Which will respond with something like:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjdXN0b21lciIsImV4cCI6MjIxMTIxODA2MSwiYXV0aG9yaXRpZXMiOlsiUk9MRV9VU0VSIl0sImp0aSI6IldkLzVjTFo0NlFyUUtDUDhoQzl1T1BSbXV5OD0iLCJjbGllbnRfaWQiOiJ3cml0ZXIiLCJzY29wZSI6WyJwcm9kdWN0OnJlYWQiLCJwcm9kdWN0OndyaXRlIl19.GxuVD0ZRL15n9lyZKRIf-npfR-c2JVYaOJ6BaEKF4h3Nmr2aZJAgnPbYCHzoelWNCcfS4T0Z54i_VPPRHtRDrMEaIdIOi9Bv4sLbYbpEHtcom4XRg_0XHqwlLqbxa4-sjX_eXntFHLL46K05jttifEpJrWmG5Fk5ZKIMKPZmvXbLC-T1wsYSbBKCMmpUv2fUCsy_yTGnmFrwGeeGC_5MuniZm3dfjRvvz19doe2XYjkf5jV3KU_4jnacNE-8N-L40gWKlXwUEakAIFdeVAFWp58KJ2soekdebTQeO1GDzb0rahtw53H2Ib_Znd2Z36Tujz-E_uhd2ztwFNo3JqJUiQ",
  "token_type": "bearer",
  "expires_in": 599999999,
  "scope": "product:read product:write",
  "jti": "Wd/5cLZ46QrQKCP8hC9uOPRmuy8="
}

User noscope will get error 403 forbitden

curl -k https://noscopes:secret@localhost:8443/oauth/token -d grant_type=password -d username=customer -d password=password -s | jq .
  1. Call the search to get product API

The endpoint https://localhost:8443/api/v1/products used gateway to hide the services behind the outside. The gateway call the product-composite-service which comunicate with 3 external services(mock-services ) (tiki,lazada,shopee) to get the products information. Each external service has difference structure response so the system has to convert to standard response.

  • Sample curl
curl --location --request GET 'https://localhost:8443/api/v1/products?query=iphone%20XS%20MAX&sort=ASC' \
--header 'X-Request-ID: 84f240d1-cb45-410a-9661-b3d0f6dcab5d' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjdXN0b21lciIsImV4cCI6MjIxMTIxODU1NSwiYXV0aG9yaXRpZXMiOlsiUk9MRV9VU0VSIl0sImp0aSI6InZFSGlhUVRDbXRocWg3dHRubTE3d1MrS3Rpbz0iLCJjbGllbnRfaWQiOiJ3cml0ZXIiLCJzY29wZSI6WyJwcm9kdWN0OnJlYWQiLCJwcm9kdWN0OndyaXRlIl19.RMhYgu17NSf7V4xAfyRYATzzTx_9C6licrsGb6TW2it7d162hPOGoY9KVea8GyK8-aNqPLBQGd-RO-5Xk6msFgpFmr-PF94F68z15lXLyGmx56njNgy2WgZroN6VAjfdX8DA7iR_w1Wh-bMyqmvDGe2gZK7vud6vUddtDCbzZNZQf0J5xdXzQ0U-rlUUolDQKZvr5NTp5Y20n41fgpVjD1JrJbNYbYm1cPhe5e2_lEy5Iy6lUi79XlIgqHBSb_ZUbNOf-PrtX7c_-8LWvTKkXRNzjDlxnfjZZwq1EB8Nniteu5F9UKD0E5d4sohCko_eALzkHGe87Q8Q-LgLgNgbdQ'
  • Sample Response
{
    "data": {
        "products": [
            {
                "code": "867863548187882",
                "name": "iphone XS MAX",
                "description": "Small Wooden Bag",
                "price": 24.22,
                "image": "http://lorempixel.com/g/1600/1200/abstract/",
                "discountRate": 74.7112948124,
                "promotion": "StellarPrice567686",
                "category": "21F57C00",
                "brand": "Cty TNHH Cường",
                "source": "SHOPEE"
            },
            {
                "code": "442200404330468",
                "name": "iphone XS MAX",
                "description": "Incredible Steel Wallet",
                "price": 50.15,
                "image": "http://lorempixel.com/g/1366/768/technics/",
                "discountRate": 26.0570119919,
                "promotion": "GreatPromotion056006",
                "category": "29FCB5BB",
                "brand": "Công ty Ngô",
                "source": "TIKI"
            },
            {
                "code": "864731274217665",
                "name": "iphone XS MAX",
                "description": "Heavy Duty Wool Table",
                "price": 51.22,
                "image": "http://lorempixel.com/1920/1200/city/",
                "discountRate": 52.7330135874,
                "promotion": "KillerCode520332",
                "category": "4CB0DC50",
                "brand": "Cty Trinh",
                "source": "LAZADA"
            }
        ]
    },
    "meta": {
        "code": "200"
    }
}

Logs from the microservices

  1. Query the user search history
   docker-compose exec mongodb mongo event-db --quiet --eval "db.events.find()"

Sample Result

{ "_id" : ObjectId("600e9823ed6a8753c9c0526f"), "event" : { "userName" : "customer", "query" : "iphone XS MAX", "_class" : "com.ms.event.SearchEvent" }, "_class" : "com.ms.smartchoice.persistence.EventEntity" }
{ "_id" : ObjectId("600e9827ed6a8753c9c05270"), "event" : { "userName" : "customer", "query" : "iphone XS MAX", "_class" : "com.ms.event.SearchEvent" }, "_class" : "com.ms.smartchoice.persistence.EventEntity" }
{ "_id" : ObjectId("600e9829ed6a8753c9c05271"), "event" : { "userName" : "customer", "query" : "iphone XS MAX", "_class" : "com.ms.event.SearchEvent" }, "_class" : "com.ms.smartchoice.persistence.EventEntity" }

TODO

  • Apply Kubernetes & Istio as alternative deployment
  • Apply Grafana, Prometheus and Kiali ... for tracing and monitoring to easilier debug and scale.
  • Apply Grpc for internal call to get highly performant and scalable.
  • Convert from Spring boot to Quarkus to enhance the performace (CPU & Memory usage).
  • Do more testing & integration test on mock-service ,product-composite.
  • Store search result in external system such as DB/Redis cached for better perfomance and reduce cost.

spring-reator-microservices's People

Contributors

buianhtai avatar

Watchers

 avatar  avatar

Forkers

hahagioi111

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.