Chciałbym się z Wami podzielić rozwiązaniem, które ostatnio zastosowałem w celu zmniejszenia kosztów związanych z wykorzystania API udostępnianego przez RoyalMail. W jednym z projektów, klient poprosił o możliwość uzupełniania adresu na podstawie wpisanego kodu pocztowego. Problem dotyczył systemu działającego w Anglii, a tam na podstawie kodu pocztowego można ustalić bardzo dokładnie adres. Pozwala to przyspieszyć znacząco wprowadzanie adresu w różnego rodzaju formularzach.

Opis problemu

Rozwiązanie to działa w następujący sposób:

Technicznie, po wpisaniu każdej litery wysyłane jest zapytanie do systemu RoyalMail o listę kolejnych podpowiedzi. Jak widać rozwiązanie to działa bardzo sprawnie. Problemem jest natomiast koszt. Cennik RoyalMail jest strasznie wygórowany:

Średni koszt zapytania wynosi pomiędzy 0,04 – 0,06 GBP. Co więcej, zapytanie w tym serwisie generowane jest przy każdym wpisaniu znaku w polu tekstowym.

Oznacza to dla nas, że koszt znalezienia konkretnego adresu jest wyższy. Pojawiła się od razu potrzeba obniżenia tego kosztu.

Opis rozwiązania

Od razu do głowy przychodzi rozwiązanie polegające na cache’waniu wyników zwracanych przez wcześniejszy serwis przy zastosowaniu tańszego rozwiązania. Wybór padł na Azure Functions wraz Azure Storage Table.

W Azure Storage Table przechowywane były wyniki wyszukiwania pochodzące z RoyalMail.

Natomiast Azure Function była odpowiedzialna, za obsługę żądań pochodzących z naszej strony. W tym rozwiązaniu strona zamiast bezpośrednio komunikować się z RoyalMail, wysyłała zapytanie do naszej funkcji. Ta natomiast sprawdzała w Azure Storage Table, czy już takie żądanie miało miejsce i jeśli tak to zwracała wynik pochodzący z Azure Storage Table. W przypadku gdy zapytanie to nie zostało znalezione, albo było przeterminowanie to odpytywała serwis RoyalMail, a następnie zapisywała otrzymany wynik oraz równocześnie zwracała go do strony.

Rozwiązanie to nie spełnia wymogu pojedynczej odpowiedzialności – nasza funkcja mogłaby zostać rozdzielona na kilka mniejszych, ale uważam, że byłoby to nadmiarowe.

Wracając do kosztów rozwiązania. Przy założeniu wykorzystania najdroższego planu, czyli 15000 zapytań przy wycenie środowiska Azure należy uwzględnić:

  • 15000 wykonań funkcji (128 MB x 2 sec) – koszt 0 GBP,
  • 30000 zapytań do 1 GB Azure Storage Table – koszt 8,1 GBP (estymujemy pesymistyczny scenariusz, w którym to za każdym razem nie odnotowujemy pozytywnego trafienia do bazy danych).

Całkowity koszt chmury Azure wyniesie nas nie więcej niż 8,1 GBP / 15000 zapytań.

Wnioski

Przedstawiony przykład pokazuje jak w prosty sposób można ograniczyć koszty naszego rozwiązania. Po jego wdrożeniu nasze koszty za 15000 zapytań będą kształtowały się od 4,08 GBP, gdy wszystkie wyniki będą pobrane z naszego rozwiązania, do 583,1 GBP w momencie, gdy żaden wynik nie zostanie odnaleziony w naszej bazie.

Jak widzicie dodanie drobnego elementu do naszego systemu pozwala na dość znaczące obniżenie kosztów. Niestety wprowadza ono dodatkową zależność oraz element, który może ulec awarii. Nie jesteśmy też w stanie całkowicie oddzielić się od systemu RoyalMail ponieważ dane z tego systemu są na bieżąco odświeżane. Codziennie aktualizowanych jest 3000 rekordów. Dlatego też powinniśmy ustawić czas ważności dla danych przechowywanych w naszym systemie. Po tym czasie powinniśmy ponownie odpytać system RoyalMail o nowe dane, nawet jeśli nasza baza zawierałaby odpowiedni rekord.