bp-wallet-grpc-spring
Based on Google RPC and Protocol Buffer - a multi threaded Asynchronous Application that Allows Deposit, Withdrawal and Get Balance for the users.Project consists of a Wallet server and Wallet client.The wallet server will keep track of a users monetary balance in the system. The client will emulate users depositing and withdrawing funds.
Function | Input | Output | Error | |
---|---|---|---|---|
Deposit | UserID,Amount,Currency | Success/Failure | Unknown Currency , User Unknown | |
Withdraw | UserID,Amount,Currency | Success/Failure | Unknown Currency , User Unknown | |
Get Balance | User id | The balance of the users account for each currency | User Unknown |
Currency (Values are EUR, USD, GBP)
Sub Projects
bp-wallet-client(BPWC)
- Spring BOOT based Client Which makes Concurrent Transaction Request via GRPC Stub over HTTP2 to BPWS.
- The wallet client will emulate a number of users concurrently using the wallet.
- The wallet client must connect to the wallet server over gRPC.
- The client eliminating users doing rounds (a sequence of events).
- Whenever a round is needed it is picked at random from the following list of available rounds
Round A
- Deposit 100 USD
- Withdraw 200 USD
- Deposit 100 EUR
- Get Balance
- Withdraw 100 USD
- Get Balance
- Withdraw 100 USD
Round B
- Withdraw 100 GBP
- Deposit 300 GPB
- Withdraw 100 GBP
- Withdraw 100 GBP
- Withdraw 100 GBP
- Withdraw 100 GBP
- Withdraw 100 GBP
Round C
- Get Balance
- Deposit 100 USD
- Deposit 100 USD
- Withdraw 100 USD
- Deposit 100 USD
- Get Balance
- Withdraw 200 USD
- Get Balance
The wallet client will have the following parameters:
- users (number of concurrent users emulated)
- concurrent_threads_per_user (number of concurrent requests a user will make)
- rounds_per_thread (number of rounds each thread is executing)
Number of Transactions per Request by BPWC:
K Users
Should Run Concurrently.- Each Kth User Can make
N Requests
. - Each Nth Request can Spawn
M Concurrent Operations(Rounds)
. - Each Round will have
DEPOSIT
,WITHDRAW
,BALANCE
. - Total Number of threads will K * M * N (* Average 7 Transactions per round).
bp-wallet-server(BPWS)
Records balance in user Wallet.
Expose API for Depositing Money, Withdrawing and Getting Balance in different currencies.
bp-wallet-proto(BPWP)
Has proto file(.proto), Generated Stubs and Domains shared by BPWC and BPWS.
Assumptions and Pointers:
- Server Handles Transaction on FCFS. Ideally in a solution like this the sequence of transactions must be maintained viz OOS.
-
About “Make sure the client exits when all rounds has been executed.”
- BPWC exposes SWAGGER API for Testing.
- CLI Command: Not Implemented
-
Technologies
- Java 8.
- gRPC
- MySQL and H2
- Gradle
- JUnit and Test Containers
- SLF4J
- Docker
- Hibernate
- Spring and Spring Boot.
- Swagger
- Springs Transaction.
- Junits Coverage of > 80% is OOS(Out of Scope).
- The docker containers should run via Compose/Kubernetes. OOS.
- The Client/Server Doesn’t retry failed transactions. OOS
- The user ID is Taken from Number of Users param (userID:1 for numberOfuser=1,userID:1,userID:2 for numberOfuser=2).
- Database schema has been kept Simple with One table.
- The actual applicable schema is included in
Future Aspiration Section
with SQL and Schema Diagram. - The Service Response/Request has been kept same for
RAPID (Rapid Application Development in Pro-typing)
Otherwise it should be different for each transaction type example /docs/wallet.proto. - Implements limited caching
spring-caching
although not bench-marked, it will play a crucial role with expanding user base. bp
is anapplication prefix
.
How to run BPWS
and BPWC
(run gradlew.bat build
or gradle build
in root project. first)
Database
LOCAL
If local/remote instance of MY SQL is running nothing else to do.
Replace the IP/PORT/SCHEMA in `application.yaml` in BPWS.
DOCKER
Script: start-bp-wallet-mysql-docker.bat
Run above in root folder it takes 5-10 Minutes to come up.
Execute following command to get the IP of docker-machine bash#docker-machine -ip
Make Sure MYSQL or Any DB is UP and its properties are configured in `application.yaml`
JAVA(bp-wallet-server)
LOCAL
Script: start-bp-wallet-server.bat
(Please read the comments in file for more info.)
Docker
Script: start-bp-wallet-docker.bat
JAVA(bp-wallet-client)
LOCAL
Script: start-bp-wallet-client.bat
Docker
Script: start-bp-wallet-docker.bat
Access Client using
LOCAL
http://localhost:8080/swagger-ui.html#/wallet-client-controller/executeUsingPOST
Docker
http://<dockermachine -ip>:8080/swagger-ui.html#//wallet-client-controller/executeUsingPOST
Request
{
"numberOfRequests": 1,
"numberOfRounds": 1,
"numberOfUsers": 100
}
Reponse
{
"transactions": {
"DEPOSIT": {
"TRANSACTION_SUCCESS": 146,
"TRANSACTION_FAILED": 0,
"UNRECOGNIZED": 0
},
"WITHDRAW": {
"TRANSACTION_SUCCESS": 17,
"TRANSACTION_FAILED": 0,
"UNRECOGNIZED": 0
},
"BALANCE": {
"TRANSACTION_SUCCESS": 174,
"TRANSACTION_FAILED": 0,
"UNRECOGNIZED": 0
},
"UNRECOGNIZED": {
"TRANSACTION_SUCCESS": 0,
"TRANSACTION_FAILED": 395,
"UNRECOGNIZED": 0
}
},
"timeTaken": 10
}
timeTaken in Seconds.
Note:For quick start up please import the project in STS and run BPWS
and BPWC
as spring boot app
.
Important choices in Solution
- The Whole Structure of the BP-wallet application is loosely coupled SOA.
- Each Client,Server,DB Instances are developed keeping Scalability,Elasticity and Fault tolerance in mind.
- Docker Instances make it possible to enable containerization and Helps in Deployments.
- The Performance Tuning variables are not yet externalized.
- Server Side - Connection Pooling Configurations(Depends on Given Deployment Platform).
- Client Side - Task Executor is Configurable with Concurrent Worker Threads.
- The
BPWP
is shared with Client and Server. - Synchronization or any code level locking on DB has been avoided as there can be multiple instances running.
Optimistic Locking
via@Version
annotation is implemented forConcurrency
(Which can also be configured for retry mechanism[Disabled for Now])- There are Still Some
Race Conditions
inBPWS
. - User Registration: N number User are registered with Zero Balance at application startup (This is done to avoid user not found exception and to support Integration tests. This is a bare-bone approach and only adopted due to RAPID).
- For Improved performance
Logging
has been minimized via debug or disabled inapplication.yaml
. - Some of the Decisions and choices are evident from TPS section.
Transactions Per Seconds[TPS].
Its Pandora’s Box !! Can have Numerous Permutation & Combination with each variant, and requires performance tuning and monitoring to reach a common objective or to handle any future spikes
.
Per Transaction Variant:
Application Variant : All below are 10 Concurrent Calls but they take different execution time because of their nature.
- Single user Making 10 Deposit: Corresponds to 20 DB Calls 10 for Get and 10 for Update.
- Single user Making 5 Withdraws 5 Deposit:Same.
- Single user Making 4 Withdraws 4 Deposit 2 Balance: 18 DB Calls 10 Get and 8 Update.
All of the above transactions have high chances of OptimisticLockException
due to versioning on WIP same row stale object.Can be mitigated with retry mechanism however in this kind of scenario the sequence need to be guaranteed possible with bidirectional streaming
.
Then there are other scenarios with multiple users with multiple transactions - testing is OOS.
Database Variant:
- Embedded H2 DB:only used for RAPID.
- MYSQL DB: Although mysql can handle 150+1 Connections , for that the calling system should be of very high configurations, The current application configures the Connection Pool Max Size to be 10 based
Number of Cores * 2 + Max(tX Spindle time)
- Dockerized MYSQL DB: This makes a delta of 5-10 %.
Database Connection Pooling Variant:
- HIKARI:If the number of transaction grows > 400 HCP starts getting
Connection Not Available
, to avoid this the session state was properly synced with DB using flush in finally block.The connection time out was tweaked to 3 Minutes from default.This alone is not sufficient there need to be Data replication in MYSQL with Application Caching for outstanding performance which OOS.For better performance a dynamically resizing DB connection pooling mechanism is needed ..Flexy-pool
fits here but OOS. - Apache:OOS
Platform Variant:
- Wallet Server Deployed Local Machine -(4 GB RAM 4 Cores i5):At large 100+-.
- Wallet Server Deployed on other Machines:OOS
Having said that, About 120(+-) concurrent requests per-second was achieved, Although it may very on machines, For example About 1000+- Transactions happened in about 1 second for one user deposit [On H2 DB !!].
Apart from this - there is another POC written which executes for one second so to better understand the stages of optimization.
The over all goal was to run it wit time command and check the actual CPU utilization
Memory Utilization
.
Integration Test
1. Make a withdrawal of USD 200 for user with id 1. Must return "insufficient_funds".
2. Make a deposit of USD 100 to user with id 1.
3. Check that all balances are correct
4. Make a withdrawal of USD 200 for user with id 1. Must return "insufficient_funds".
5. Make a deposit of EUR 100 to user with id 1.
6. Check that all balances are correct
7. Make a withdrawal of USD 200 for user with id 1. Must return "insufficient_funds".
8. Make a deposit of USD 100 to user with id 1.
9. Check that all balances are correct
10. Make a withdrawal of USD 200 for user with id 1. Must return "ok".
11. Check that all balances are correct
12. Make a withdrawal of USD 200 for user with id 1. Must return "insufficient_funds".
Future Aspirations.
- Cloud Ready.
- Load Ba-lancer.
- Service Discovery.
- Authentication.
- UI Client.
- Docker Images provisioning and Orchestration via compose.
- Caching enabled Entities - with Eviction and Put strategies.
- DB Schema.
- Schema File - https://github.com/Akash-Mittal/bp-wallet/blob/master/docs/db-schema.sql
POCs and Related Projects.
-
https://github.com/Akash-Mittal/jmeter-multithreaded-application
-
https://github.com/Akash-Mittal/enities-maker
-
https://github.com/Akash-Mittal/grpc-wallet
-
https://github.com/Akash-Mittal/bp-wallet
-
https://github.com/Akash-Mittal/hibernate-samples