Hi Fineract community,

Would just like to get you inputs on the business logic of post interest to
savings batch.

Thank you!

Joseph

On Wed, Dec 4, 2019 at 10:49 PM Joseph Cabral <joseph.cabra...@gmail.com>
wrote:

> Hi Fineract community,
>
> Sorry for the very late reply. We have been trying different things to
> improve the batch run time for post interest to savings job but to no avail.
>
> We have tried various things like upgrading Spring Boot, migrating to
> Hibernate, using SpringJPA instead of OpenJPA so we can use Java Stream or
> ScrollableResultSet but it does not seem to have any effect on the
> performance. We also tried modifying the batch_size feature of Hibernate to
> use its batch insert and update. Some of the techniques we tried even
> worsened the performance as compared to before.
>
> One thing that worked for us is the use of the official MySQL driver
> instead of Drizzle. This improved performance by around 20%. However we are
> still not near our target of 1 to 2 hours.
>
> Hi Nayan, Avik,
>
> Noted and thank you very much for your recommendations. We will try them
> out.
>
> Regarding your comment on the Fineract version, we are currently testing
> on the develop branch so we should have the latest changes of v1.2 to v1.4.
>
> How do we test multithreading? How do we set this up or configure this?
>
> We have some questions on the business logic for the post interest to
> savings batch job.
>
>    1. The SavingsAccount postInterest() method iterates a lot through the
>    SavingsAccountTransaction and PostingPeriod lists for each SavingsAccount.
>    This seems to be a possible cause of slowdown as the batch can get slower
>    as the number of transactions increases. This also results in O(N2) 
> complexity.
>    Do you agree with this? Will multithreading help here?
>    2. For the updateSummary() method, it iterates through all the
>    SavingsAccountTransactions of each SavingsAccount to compute the total
>    deposits, total withdrawals etc. It does this for every call to
>    postInterest method. Our question here is why does it need to do this? Is
>    it to make sure that the total values are accurate? Why does it not just
>    add the latest SavingsAccountTransaction to the previously computed total
>    deposits, total withdrawals?
>
> We are very hesitant to do any code change in the business logic, but we
> think that it can be a possible cause of slowdowns. Please correct us if
> you think otherwise.
>
> Also can we get some of the results you  had in your own load testing?
>
> Thank you!
>
> Joseph
>
> On Mon, Nov 11, 2019 at 10:59 AM Avik Ganguly <a...@fynarfin.io> wrote:
>
>> Hey Joseph,
>>
>> Are you using Fineract v1.2 or above? The core jobs are multithreaded in
>> that version and fetch / commit batch sizes can be configured.
>>
>> K2, can you confirm if the JMeter scripts you used to test were merged
>> and available in Fineract v1.2?
>>
>> We are using a 4vCPU 128GB server to do the load testing. Our target for
>>> 1.2M savings accounts is less than 1 hour.
>>
>> We were able to reduce the post interest to savings schedule job run time
>>> from 15-20 hours to 6 hours with these modifications.
>>
>>  Applying the same fix on top of Fineract 1.2 might bring it down to less
>> than 2 hours in that case.
>>
>> @Ed Cable <edca...@mifos.org>
>>
>> and start a collaborative effort to carry out these performance and load
>>> testing exercises on a regular basis and a group of contributors focused on
>>> identifying and fixing the issues to improve performance.
>>
>>
>> Please find a list of items not specific to interest posting job but more
>> about transactions in general    :-
>>
>>
>> Code Change :-
>>
>> 1. OptimisticLockException fix for concurrent transactions affecting the
>> same account.
>> 2. (Suggested by Nayan) Use Spring Retry to restart the txn for
>> LockWaitTimeouts where the LockWaits are unavoidable.
>> 3. Remove reliance from txn_running_balance (it anyways reflects wrong
>> values on doing concurrent txns on same account).
>> 4. Move officially to MySQL 5.7 if it's not official yet. Whether to
>> change queries to support default only full group by or to change the SQL
>> mode.
>> 5. Archival & Partition Strategy for transactions. (I think this should
>> be the highest priority item as it will have a positive cascading effect on
>> almost all core API calls, batch jobs and reports)
>> 6. Selectively change read API redirects to replica DB. Consult DB admin
>> for the right replication and clustering configuration to make this
>> feasible based on usage, replication lag, etc.
>> 7. Use Hystrix for short circuit failing integration touchpoints.
>> 8. Separate the modules at a very high level (different discussion).
>> 9. Multi node EhCache has some issues.
>> 10. Traffic shaping / congestion control - control bandwidth and
>> burstiness at an API level.
>> 11. Ensure most indexes are in read replica store and OLTP db does not
>> have indexes used by reports.
>>
>> Configuration Change / Ship Configuration Profiles :-
>>
>> 1. Different profiles for tenant_server_connections thread pool config
>> 2. my.cnf configuration for optimizing DB performance for already
>> available hardware resources.
>> 3. Tenants DB thread pool size in web Server configuration file
>> 4. Include profiles for clustering - Percona, Aurora, Galera?
>> 5. Include config for reverse proxy - Nginx?
>> 6. Include Tomcat 8 NIO server config file?
>>
>> Infra Setup :-
>>
>> 1. Infra setup - Establish network latency isn't the case - install mysql
>> client CLI on your app server, connect to DB server using mysql client and
>> see how many ms a super simple query takes. Not an infra expert but please
>> find a common misconfiguration example.
>> Ex :-
>> select id from m_code where id = 1;
>> AWS - Same subnet - 0.3 ms
>> AWS - Same VPCs - 6ms
>> AWS - Across VPCs - 300ms
>>
>> Behaviour Change (Customizing Mifos for use cases Mifos wasn't designed
>> for) :-
>>
>> 1. Txn API TPS - Review how Fineract features can be used to solve
>> business use cases. Ex:- Separating one single collection account into
>> different accounts at merchants / offices / virtual offices / regions
>> level. You can tag the collection use case with a payment type as well.
>>
>>
>> Identifying / Reporting Issues :-
>>
>> 1. How to debug / Get relevant logs (bit subjective) - Bit aimed towards
>> correctly reporting the issue (if not including a test case to reproduce
>> the issue) :-
>> 1a. Slow queries in write txn APIs standing out in production server logs.
>> 1b. Local application debug (connect to QA env db if reproduction steps
>> are highly data dependent)
>> 1c. Switch show queries to true to flood the logs with all queries
>> generated by JPA. Notice repetitive (self references (Ex :- Office entity
>> eagerly fetching parent and list of children)  and highly propagating
>> (eager fetches) queries by clearing logs before and after txn.
>> 1d. Profile or put timers at critical lines of DB interaction and
>> subtract with previous timer value to notice bottleneck queries.
>> 1e. Remote debug two concurrent API calls together. Put a breakpoint at
>> the start of the relevant service and bring both threads forward one at a
>> time till one thread reaches lock acquiring query and other thread goes
>> into wait. See what DB operations are remaining after that to get an idea
>> of how long that lock will be held. Minimize the amount of time it's
>> holding on to the lock to minimize the chances of LockWaitTimeout
>> exceptions.
>> 2. Review indexes on core tables. Did someone put an index on a timestamp
>> column? Did that index addition go through a PR or was it executed directly
>> on environment? Tighten control to prevent users directly changing DB (DDL
>> statements at least). Introduce more indexes?
>>
>>
>> Test Suite Development :-
>>
>> 1. Add more JMeter test scripts and integrate it with a CI cum load
>> testing server and catch regressions on code change.
>>
>> Commercial Tools :-
>>
>> 1. APM tool (New Relic, Dynatrace, Nagios, AppDynamics) - easy to do
>> operational review of queries with highest counts (rather than the longest
>> running queries in slow query log) - when DB is choking on a low resource
>> server, all queries will perform much worse than in normal conditions.
>> 2. DB monitoring tool - Percona Monitoring and Management.
>> 3. Nginx Plus or HAProxy
>>
>>
>> With best regards,
>> Avik.
>> ᐧ
>>
>>
>> On Tue, Oct 22, 2019 at 1:38 AM Ed Cable <edca...@mifos.org> wrote:
>>
>>> Nayan,
>>>
>>> Thanks for assisting Joseph with those suggestions and Joseph thanks for
>>> sharing the initial results of improvements after indexing. I'm happy you
>>> emailed about this as performance testing and improving performance for
>>> high scalability environments is a topic of wide importance for many
>>> members of the current ecosystem and a number of prospective new adopters
>>> that are looking at the stack.
>>>
>>> As evident from your searching and the input you have received thus far
>>> on the thread what's publicly out there on performance statistics and
>>> fine-tuning performance is limited. Yet, many of our implementers have run
>>> Mifos/Fineract in high load environments and have a lot of wisdom and
>>> experience to share.
>>>
>>> @Avik Ganguly <a...@fynarfin.io> based on your experiences, are you
>>> able to give some additional suggestions on top of what Nayan has already
>>> provided.
>>>
>>> I will get a separate email thread going to start a collaborative effort
>>> across the community to get in place a set of reproducible tools to do
>>> ongoing performance testing on Fineract and Fineract CN, and start a
>>> collaborative effort to carry out these performance and load testing
>>> exercises on a regular basis and a group of contributors focused on
>>> identifying and fixing the issues to improve performance.
>>>
>>> We welcome your contributions to those efforts
>>>
>>> Ed
>>>
>>>
>>>
>>> On Mon, Oct 21, 2019 at 7:14 AM Joseph Cabral <joseph.cabra...@gmail.com>
>>> wrote:
>>>
>>>> Hi everyone,
>>>>
>>>> I would like to share the initial results of our testing and get your
>>>> feedback.
>>>>
>>>> We modified the code for the post interest to savings scheduler job,
>>>> specifically the findByStatus method in SavingsRepositoryWrapper where it
>>>> queries the active savings accounts. We noticed that it the current design
>>>> depended on lazy load fetching to populate the transactions and charges
>>>> list of each savings accounts. From previous experience with  other systems
>>>> this has been a cause of various slow downs so we focused on modifying this
>>>> part. We decided to query the savings transaction and charges in bulk to
>>>> reduce the number of database calls. See below for our implementation.
>>>>
>>>> We also removed the CascadeType.ALL and FetchType.Lazy settings for the
>>>> transactions and charges list of the SavingsAccount entity as we are
>>>> already manually fetching their contents. We will do further testing as
>>>> this may have an impact in other modules.
>>>>
>>>> @Transactional(readOnly=true)
>>>>     public Page<SavingsAccount> findByStatus(Integer status, Pageable 
>>>> pageable) {
>>>>         logger.info("findByStatus - Start querying savings account");
>>>>         Page<SavingsAccount> accounts = 
>>>> this.repository.findByStatus(status, pageable);
>>>>         List<Long> idList = new ArrayList<Long>();
>>>>         Map<Long, SavingsAccount> accountsMap = new HashMap<Long, 
>>>> SavingsAccount>();
>>>>         if(accounts != null) {
>>>>             for(SavingsAccount account : accounts) {
>>>>                 account.setCharges(new HashSet<>());
>>>>                 account.setTransactions(new ArrayList<>());
>>>>
>>>>                 idList.add(account.getId());
>>>>                 accountsMap.put(account.getId(), account);
>>>>             }
>>>>             List<SavingsAccountTransaction> savingsAccountTransactionList 
>>>> = savingsAccountTransactionRepository.findBySavingsAccountIdList(idList);
>>>>             if(savingsAccountTransactionList != null) {
>>>>                 for(SavingsAccountTransaction transaction : 
>>>> savingsAccountTransactionList) {
>>>>                     SavingsAccount account = 
>>>> accountsMap.get(transaction.getSavingsAccount().getId());
>>>>                     account.getTransactions().add(transaction);
>>>>                 }
>>>>             }
>>>>
>>>>             Set<SavingsAccountCharge> savingsAccountChargeList = 
>>>> savingsAccountChargeRepository.findBySavingsAccountIdList(idList);
>>>>             if(savingsAccountChargeList != null) {
>>>>                 for(SavingsAccountCharge charges : 
>>>> savingsAccountChargeList) {
>>>>                     SavingsAccount account = 
>>>> accountsMap.get(charges.savingsAccount().getId());
>>>>                     account.getCharges().add(charges);
>>>>                 }
>>>>             }
>>>>         }
>>>>         logger.info("findByStatus - Finished querying savings account");// 
>>>>        loadLazyCollections(accounts);
>>>>         return accounts;
>>>>     }
>>>>
>>>>
>>>> We were able to reduce the post interest to savings schedule job run
>>>> time from 15-20 hours to 6 hours with these modifications. After this we
>>>> will look at how to reduce the run time for the saving/updating part.
>>>>
>>>> I would like to ask if anyone has any alternative solutions or if you
>>>> have any feedback on how we implemented it?
>>>>
>>>> Regards,
>>>>
>>>> Joseph
>>>>
>>>> On Sun, Oct 20, 2019 at 11:02 PM Joseph Cabral <
>>>> joseph.cabra...@gmail.com> wrote:
>>>>
>>>>> Hi Michael,
>>>>>
>>>>> Of course, we will give feedback if we are able to make improvements
>>>>> to our scheduler job run time.
>>>>>
>>>>> But if anyone else has any experience in load testing or running
>>>>> Fineract in high load environments I am open to suggestions.
>>>>>
>>>>> Thanks!
>>>>>
>>>>> Joseph
>>>>>
>>>>> On Sun, Oct 20, 2019 at 7:32 PM Michael Vorburger <m...@vorburger.ch>
>>>>> wrote:
>>>>>
>>>>>> Joseph,
>>>>>>
>>>>>> On Sun, 20 Oct 2019, 00:28 Joseph Cabral, <joseph.cabra...@gmail.com>
>>>>>> wrote:
>>>>>>
>>>>>>> Hi Nayan,
>>>>>>>
>>>>>>> Thank you for the tips! I tried asking for advice here first because
>>>>>>> we are wary of doing any code change since we were under the assumption
>>>>>>> that Fineract had already been used in many high load situations in
>>>>>>> production and we have just set it up wrong or there are some settings 
>>>>>>> we
>>>>>>> could change.
>>>>>>>
>>>>>>> We will first try adding some indexes to the database but it looks
>>>>>>> like we have to do some code change for this.
>>>>>>>
>>>>>>
>>>>>> Will you be contributing any performance related improvements you
>>>>>> make back to the community?
>>>>>>
>>>>>> Thanks again!
>>>>>>>
>>>>>>> Joseph
>>>>>>>
>>>>>>> On Sun, Oct 20, 2019 at 2:21 AM Nayan Ambali <nayan.amb...@gmail.com>
>>>>>>> wrote:
>>>>>>>
>>>>>>>> Joseph,
>>>>>>>>
>>>>>>>> Previously I had done Mifos platform load testing for the
>>>>>>>> community, based on my experience below are my recommendations
>>>>>>>>
>>>>>>>> *without code change*
>>>>>>>> 1. Use SSD/High IOPS storage for Database
>>>>>>>> 2. If you are on AWS, go for Aurora instead of MySQL
>>>>>>>> 3. Look at database usage for this batch job and see if there is
>>>>>>>> opportunity index some columns for better performance
>>>>>>>>
>>>>>>>> *with code change*
>>>>>>>> 1. Process the data parallel either on with multi threading on
>>>>>>>> single node or we can go for multiple nodes
>>>>>>>> 2. Query optimisation
>>>>>>>> 3. Data fetch and commit batch size
>>>>>>>> there are many other opportunities to improve the same
>>>>>>>>
>>>>>>>> -
>>>>>>>> at your service
>>>>>>>>
>>>>>>>> Nayan Ambali
>>>>>>>> +91 9591996042
>>>>>>>> skype: nayangambali
>>>>>>>>
>>>>>>>>
>>>>>>>> On Sat, Oct 19, 2019 at 2:20 PM Joseph Cabral <
>>>>>>>> joseph.cabra...@gmail.com> wrote:
>>>>>>>>
>>>>>>>>> Hi Everyone,
>>>>>>>>>
>>>>>>>>> I would like to ask if anyone has done load testing of the
>>>>>>>>> MifosX/Fineract scheduler jobs? Specifically the post interest to 
>>>>>>>>> savings
>>>>>>>>> job.
>>>>>>>>>
>>>>>>>>> We created a new Savings Product (ADB Monthly - 10% Interest) with
>>>>>>>>> the following settings:
>>>>>>>>> Nominal interest rate (annual): 10%
>>>>>>>>> Balance required for interest calculation: $1,000.00
>>>>>>>>> Interest compounding period: Monthly
>>>>>>>>> Interest posting period: Monthly
>>>>>>>>> Interested calculated using: Average Daily Balance
>>>>>>>>>
>>>>>>>>> We populated the m_savings_account table using the savings product
>>>>>>>>> above with 1.2M new savings accounts which we then deposited an 
>>>>>>>>> initial
>>>>>>>>> balance of $10,000 each. We then edited the post interest to savings 
>>>>>>>>> job to
>>>>>>>>> post the interest even though it is not yet the end of the month.
>>>>>>>>>
>>>>>>>>> On consecutive tests, we averaged around 15 to 20 hours to
>>>>>>>>> complete the job.
>>>>>>>>>
>>>>>>>>> We are using a 4vCPU 128GB server to do the load testing. We
>>>>>>>>> deployed MifosX/Fineract in a docker container with Tomcat 7. The 
>>>>>>>>> MySQL
>>>>>>>>> database is deployed in a separate docker container on the same 
>>>>>>>>> machine.
>>>>>>>>>
>>>>>>>>> Any tips or ideas on what we can do to improve the run time of the
>>>>>>>>> job? Our target for 1.2M savings accounts is less than 1 hour.
>>>>>>>>>
>>>>>>>>> Regards,
>>>>>>>>>
>>>>>>>>> Joseph
>>>>>>>>>
>>>>>>>>
>>>
>>> --
>>> *Ed Cable*
>>> President/CEO, Mifos Initiative
>>> edca...@mifos.org | Skype: edcable | Mobile: +1.484.477.8649
>>>
>>> *Collectively Creating a World of 3 Billion Maries | *http://mifos.org
>>> <http://facebook.com/mifos>  <http://www.twitter.com/mifos>
>>>
>>>
_______________________________________________
Mifos-users mailing list
Mifos-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mifos-users

Reply via email to