ПриватБанк

Depozit Application

Our aim was to provide web-banking app to serve customers' deposit accounts with the best possible functionality/codesize rate. We've created fast and robust responsive web application that can fit any devices and provides modern secure features over the fast WebSocket channel.

Minimal

When we are talking about enterprise solutions we always talk about giants, like CLR/JVM virtual machines and SAP/Oracle warehouses. However systems needn't to be complex and technologies like K langauge and Erlang provide enough declarative expressivness for business applications. Having some experience in building banking software we provide smallest possible processing infrastructure to be easily verified and managed while being robust at the same time.

The application is built using Erlang libraries from synrc and spawnproc GitHub organizations. Consumer appliaction hosts custom rules depending protocol or server module. E.g. your business application defines a set of business processes which are driven by BPE server, this application usually called ACT, from "activity server". N2O-based web application usually called WEB or SPA. See Picture 1.

The architecture is based on spawnproc processing applications and relies on synrc Erlang stack and N2O protocol. It is run using voxoz development tools. The application can be distributed as a single file, is able to run on Windows, Linux and Mac and fits to 2.88MB diskette. For processing opening application database consumes 2K per record.

Despite small size of application, it can operate hundred of millions records in KVS database. All banking "big-data" of transaction chains can be managed withing a single diskette. That is top-key feature of spawnproc application stack.

Picture 1. Erlang/OTP applications
KVS 1029 128K REST database secondary indexes DYNAMO, FRAG Riak, Mnesia, Redis DBS 230 60K SpawnProc Intermediary Bank Schema MQS 347 32K Pub/Sub access message bus AMQP, GPROC TPS 874 108K transactional processing system RIAK CORE IBAN, EMV UPL PLAIN TEXT English Universal Processing Language N2O 4274 528K WebSocket protocol BERT JavsScript CSS single page apps nitrogen DSL WEB 3163 252K PrivatBank Deposit Application SERVICES 3079 496K PrivatBank Service Bridge BPE 591 68K BPMN 2.0 protocol XML/DSL process management FORMS 1626 188K SpawnProc Intermediary Bank Form Set ACT 1417 176K PrivatBank Deposit Processes

Responsive

Our aim was to provide smallest possible minimalistic application for PrivatBank customers, who are using deposit accounts. We've created fast and robust responsive web application that can fit any devices and provides modern secure features over the fast WebSocket channel.

Fact: SSL page load is about 380ms from AWS ELB. The uncompressed size of SPA static assests is also hyperoptmized:

$ cloc js css htm Language files blank comment code ------------------------------------------------ Erlang 69 605 169 4800 HTML 4 60 23 394 Javascript 9 246 123 1884 CSS 1 32 11 176
Picture 1. Responsiveness across Mobiles, Pads and Desktops

Performant

Fact: the size is 2.1MB and boot time is 2s

$ ls -lh deposits -rwxr--r-- 1 5HT staff 2.1M Feb 21 04:07 deposits $ date && ./deposits Sun Mar 1 01:53:42 EET 2015 Eshell V6.2 (abort with ^G) 1> =INFO REPORT==== 1-Mar-2015::01:53:44 === deposits_sup:Deposits WebSocket Server is started.

Fact: it is easy to hold 20Mbps to the small AWS instance.

$ tcpkali -T10s -r 10000 -c 50 --first-message "N2O," \ -m PING --ws deposits.privat.bank/ws/static/app/open.htm Ramped up to 50 connections. Total data sent: 20.4 MiB (21390904 bytes) Total data received: 3.4 MiB (3602222 bytes) Bandwidth per channel: 0.399 Mbps, 49.9 kBps Aggregate bandwidth: 2.878↓, 17.093↑ Mbps Test duration: 10.0116 s.

Fact: 3M of records consume 6GB of storage. This is enought to put everything on ARM LING VM using 32GB SD-card for storing 2.1MB of application bundle and 5MB or LING image. The memory consumption could be limited to 8GB of RAM per 3M records.

> kvs:dump(). name storage_type memory size account disc_copies 120442109 3205762 process disc_copies 20274 26 history disc_copies 4190 111 . . . . . . . . Snapshot taken: {{2015,3,3},{17,39,34}} ok $ du -hs [email protected] 5861M

Business Processes

In business process management the key feature of is a compact process definitions. Here is example of Deposit Opening process definition in simple and clean BPMN 2.0 aware language. The web application is an client to ACT business process server, which hosts business process context. All the processes can be executed in attached console without web application.

deposit_app() -> #process { name = 'Create Deposit Account', flows = [ #sequenceFlow{source='Init', target='Payment'}, #sequenceFlow{source='Payment', target='Signatory'}, #sequenceFlow{source='Payment', target='Process'}, #sequenceFlow{source='Process', target='Final'}, #sequenceFlow{source='Signatory', target='Process'}, #sequenceFlow{source='Signatory', target='Final'} ], tasks = [ #userTask { name='Init', module = deposit }, #userTask { name='Signatory', module = deposit}, #serviceTask { name='Payment', module = deposit}, #serviceTask { name='Process', module = deposit}, #endEvent { name='Final'} ], beginEvent = 'Init', endEvent = 'Final', events = [ #messageEvent{name="PaymentReceived"} ] }.

Thanks to compact process context the 1 million records of process states consume only 1GB of storage.

Heart System Capacity

Having measured the capacity of WebSocket front-end, we also state that performance of BPE engine and all PrivatBank service stack is outstanding. Here is sample business process that involves most external heavy services.

EKBID = wf:qp(<<"ekbid">>,Req), Phone = #phone { number = "+38000000000" }, Sid = #sid { sid = "15080" }, Client = #client { phone = "+38000000000", ekb_id = EKBID, names = <<"Тест"/utf8>>, surnames = <<"Тест"/utf8>> }, Deposit = #deposit_app { program = <<"DE00">>, currency = <<"980">>, rate = [{rate,24},{bonus,0},{renewal_bonus,0.5}], duration = 12, type = <<"TEST">>, amount = 2, chargeDeposit = card, cardForCharge = #card{pan = <<"0000000000000000">>} }, {ok,Pid} = bpe:start(deposit:def(), [ {dep_atom,'DE00_12_uah'}, {notification, self()}, {lang, ru}, {channel,p24}]), {complete,'CheckSession'} = bpe:amend(Pid, [Phone,Deposit,Client,Sid]), {complete,'CheckClient'} = bpe:complete(Pid), {complete,'AcquireApp'} = bpe:complete(Pid), {complete,'PrepareAccount'} = bpe:complete(Pid), {complete,'CreateAccount'} = bpe:complete(Pid), {complete,'CardPayment'} = bpe:complete(Pid), {complete,'Payment'} = bpe:complete(Pid), Sid1 = bpe:doc(#sid{}, bpe:process(Pid)), {complete,'PaymentComplete'} = bpe:amend(Pid, Sid1#sid{web_pid= self()}), 'AcquireApp' = bpe:complete(Pid),

For storm we are using wrk utility that can go far beyond siege, httperf, ab and jmeter abilities. BPE engine is settled as external REST service through our rest application. BPE along with PrivatBank services can pass all steps for 500 customers in 1 second on single Depository Application node.

$ wrk -c750 -d10s "http://processes.privat.bank/service/?ekbid=001" Running 10s test @ http://processes.privat.bank/service/?ekbid=001 2 threads and 750 connections Thread Stats Avg Stdev Max +/- Stdev Latency 1.09s 391.52ms 2.00s 71.95% Req/Sec 277.85 188.50 1.11k 70.69% 4925 requests in 10.08s, 860.91KB read Socket errors: connect 0, read 0, write 0, timeout 102 Requests/sec: 588.78 Transfer/sec: 85.44KB Table 1. Run test for each C for 1 minute +---------------+------------+-------------+ | Connections | Finished | Timeouts | +---------------+------------+-------------+ | 200 | 200 | 0 | | 225 | 225 | 0 | | 250 | 250 | 0 | | 275 | 275 | 0 | | 300 | 300 | 0 | | 325 | 325 | 0 | | 350 | 350 | 0 | | 375 | 375 | 0 | | 400 | 400 | 0 | | 425 | 425 | 0 | | 450 | 450 | 0 | | 475 | 475 | 0 | | 500 | 500 | 0 | | 525 | 525 | 0 | | 550 | 523 | 27 | | 575 | 554 | 21 | | 600 | 567 | 33 | | 625 | 580 | 45 | +---------------+------------+-------------+