Menu
Jest wolny
rejestracja
Dom  /  Nawigatorzy/ Strona serwerowa aplikacji, jak to działa. Tworzenie aplikacji mobilnych: synchronizacja serwerów

Strona serwerowa aplikacji, jak to działa. Tworzenie aplikacji mobilnych: synchronizacja serwerów

Rozwój strony serwerowej aplikacji klient-serwer rozpoczyna się od zaprojektowania architektury. Wiele zależy od architektury: od rozszerzalności aplikacji po jej wydajność i łatwość obsługi/utrzymania.

Przede wszystkim musisz określić, w jaki sposób dane będą umieszczane na serwerze i jak będą przetwarzane żądania przychodzące od klienta. Trzeba też pomyśleć o organizacji buforowania danych na serwerze.

Niezbędne jest określenie protokołów wymiany danych oraz formatów przesyłania danych.

API (interfejs programowania aplikacji) to interfejs programowania aplikacji. Mówiąc bardziej zrozumiałym językiem, jest to zestaw żądań do serwera, który ten ostatni rozumie i może udzielić prawidłowej odpowiedzi. API definiuje funkcjonalność logiki po stronie serwera, podczas gdy API pozwala abstrahować od tego, jak dokładnie ta funkcjonalność jest zaimplementowana. Innymi słowy, API jest niezbędną częścią całej infrastruktury klient/serwer.

Porównaj JSON i XML. Podaj przykład protokołów w zależności od typu aplikacji.

Wielowątkowość

Jednym z kluczowych aspektów współczesnego programowania jest wielowątkowość. Za pomocą wielowątkowości możemy przydzielić kilka wątków w aplikacji, która będzie wykonywała jednocześnie różne zadania.

Wielowątkowość to właściwość platformy (na przykład systemu operacyjnego, maszyny wirtualnej itp.) lub aplikacji, w której proces utworzony w systemie operacyjnym może składać się z kilku wątków działających „równolegle”, to znaczy bez określonego zamówienie na czas.

Istotą wielowątkowości jest quasi-wielozadaniowość na poziomie jednego procesu wykonywalnego, czyli wszystkie wątki są wykonywane w przestrzeni adresowej procesu. Ponadto wszystkie wątki w procesie mają nie tylko wspólną przestrzeń adresową, ale także wspólne deskryptory plików. Działający proces ma co najmniej jeden (główny) wątek.

Wielowątkowości (jako doktryny programistycznej) nie należy mylić ani z wielozadaniowością, ani z wieloprocesorowością, pomimo faktu, że systemy operacyjne, które implementują wielozadaniowość, mają również tendencję do wdrażania wielowątkowości.

Do zalet wielowątkowości w programowaniu należą:

Uproszczenie programu w niektórych przypadkach dzięki wykorzystaniu wspólnej przestrzeni adresowej.

Mniej czasu spędzonego na tworzeniu strumienia w stosunku do procesu.

Zwiększenie produktywności procesu dzięki zrównolegleniu obliczeń procesora i operacji I/O.

Pływ(wątek) to zarządzana jednostka kodu wykonywalnego. W wielozadaniowym środowisku opartym na wątkach wszystkie uruchomione procesy muszą mieć wątek główny, ale może być ich więcej. Oznacza to, że wiele zadań może być wykonywanych asynchronicznie w jednym programie. Na przykład edytowanie tekstu w edytorze tekstu podczas drukowania, ponieważ te dwa zadania są wykonywane w różnych wątkach.

Na konwencjonalnym procesorze sterowanie przepływem jest obsługiwane przez system operacyjny. Wątek jest wykonywany do momentu wygaśnięcia przerwania sprzętowego, wywołania systemowego lub czasu przeznaczonego na to przez system operacyjny. Następnie procesor przełącza się na kod systemu operacyjnego, który zapisuje stan wątku (jego kontekst) lub przełącza się na stan innego wątku, który również ma przydzielony czas na wykonanie. Przy takiej wielowątkowości dość duża liczba cykli procesora jest poświęcana na kod systemu operacyjnego, który przełącza konteksty. Jeśli obsługa wątków jest zaimplementowana sprzętowo, sam procesor będzie mógł przełączać się między wątkami i, najlepiej, wykonywać kilka wątków jednocześnie dla każdego cyklu zegara.

- Tymczasowa wielowątkowość (jeden wątek)

- Jednoczesna wielowątkowość (wiele wątków jednocześnie)

Wielowątkowość, jako rozpowszechniony model programowania i wykonywania kodu, umożliwia wykonywanie wielu wątków w ramach jednego procesu. Te wątki wykonania współdzielą zasoby procesu, ale mogą również działać niezależnie. Wielowątkowy model programowania zapewnia programistom wygodną abstrakcję do wykonywania równoległego. Jednak chyba najciekawszym zastosowaniem tej technologii jest zastosowanie jej do pojedynczego procesu, co pozwala na jego równoległe wykonanie w systemie wieloprocesorowym.

Ta zaleta programu wielowątkowego pozwala mu działać szybciej na systemach komputerowych, które mają wiele procesorów, procesor z wieloma rdzeniami lub na klastrze maszyn - ponieważ wątki wykonywania programu w naturalny sposób nadają się do prawdziwie równoległego wykonywania procesów. W takim przypadku programista musi być bardzo ostrożny, aby uniknąć wyścigów i innych nieintuicyjnych zachowań. Aby prawidłowo manipulować danymi, wątki wykonania muszą często przechodzić przez procedurę spotkania, aby przetworzyć dane we właściwej kolejności. Wątki wykonania mogą również wymagać muteksów (które są często implementowane przy użyciu semaforów), aby zapobiec jednoczesnemu modyfikowaniu lub odczytywaniu udostępnionych danych podczas procesu aktualizacji. Nieostrożne używanie takich prymitywów może doprowadzić do ślepego zaułka.

Innym zastosowaniem wielowątkowości, mającym zastosowanie nawet w systemach jednoprocesorowych, jest zdolność aplikacji do reagowania na dane wejściowe. W programach jednowątkowych, jeśli główny wątek zostanie zablokowany przez długo działające zadanie, cała aplikacja może zostać zamrożona. Przenosząc takie czasochłonne zadania do wątku roboczego działającego równolegle z wątkiem głównym, możliwe staje się dalsze reagowanie aplikacji na dane wprowadzane przez użytkownika, gdy zadania działają w tle. Z drugiej strony w większości przypadków wielowątkowość nie jest jedynym sposobem na zachowanie wrażliwości programu. To samo można osiągnąć za pomocą asynchronicznych wejść / wyjść lub sygnałów w systemie UNIX.

W sumie istnieją dwa rodzaje wielozadaniowości: w oparciu o procesy oraz na podstawie strumieni... Różnica między wielozadaniowością procesową a wielozadaniową opartą na wątkach sprowadza się do następujących rzeczy: wielozadaniowość oparta na procesach jest zorganizowana do równoległego wykonywania programów, a wielozadaniowość oparta na wątkach służy do równoległego wykonywania oddzielnych części tego samego programu.

W sumie rozróżnia się dwa rodzaje strumieni:

Wątki pierwszego planu lub pierwszy plan. Domyślnie każdy wątek utworzony za pomocą metody Thread.Start() automatycznie staje się wątkiem pierwszego planu. Tego typu wątki zapewniają ochronę bieżącej aplikacji przed zakończeniem. Środowisko CLR nie zatrzyma aplikacji, dopóki wszystkie wątki pierwszego planu nie zostaną zakończone.

Wątki w tle Ten typ wątku jest również nazywany wątkiem demona i jest interpretowany przez środowisko CLR jako rozszerzalne ścieżki wykonywania, które można zignorować w dowolnym momencie. Tak więc, jeśli wszystkie wątki pierwszego planu zostaną zakończone, wszystkie wątki w tle zostaną automatycznie zniszczone, gdy domena aplikacji zostanie zwolniona. Aby utworzyć wątki w tle, ustaw właściwość IsBackground na true.

Opowiedz o stanach wątków: uruchomionych, zawieszonych, uruchomionych, ale czekających na coś.

Problem z synchronizacją wątków i współużytkowane zasoby.

Interakcja wątków

W środowisku wielowątkowym często pojawiają się problemy związane z wykorzystaniem tych samych danych lub urządzeń przez równoległe wykonywanie wątków. Do rozwiązywania takich problemów wykorzystuje się takie metody interakcji wątków jak muteksy, semafory, odcinki krytyczne i zdarzenia.

Mutex Jest obiektem synchronizacji, który jest ustawiony na specjalny stan sygnalizacji, gdy nie jest zajęty żadnym wątkiem. W danym momencie tylko jeden wątek jest właścicielem tego obiektu, stąd nazwy takich obiektów (z angielskiego wzajemnie wykluczający się dostęp) - wykluczony jest jednoczesny dostęp do współdzielonego zasobu. Po wykonaniu wszystkich niezbędnych działań, mutex zostaje zwolniony, dając innym wątkom dostęp do współdzielonego zasobu. Obiekt może obsługiwać przechwytywanie rekurencyjne po raz drugi przez ten sam wątek, zwiększając licznik bez blokowania wątku, a następnie wymagając wielu cofnięć alokacji. Jest to na przykład sekcja krytyczna w Win32. Jednak istnieją pewne implementacje, które tego nie obsługują i powodują zakleszczenie wątku podczas próby rekursywnego przechwytywania. To jest FAST_MUTEX w jądrze Windows.

Semafory to dostępne zasoby, które mogą być pozyskiwane przez wiele wątków jednocześnie, dopóki pula zasobów nie będzie pusta. Następnie dodatkowe wątki muszą czekać, aż wymagana ilość zasobów będzie ponownie dostępna. Semafory są bardzo wydajne, ponieważ umożliwiają równoczesny dostęp do zasobów.

Rozwój... Obiekt, który przechowuje 1 bit informacji „zasygnalizowany lub nie”, na którym zdefiniowane są operacje „sygnalizuj”, „resetuj do stanu niesygnalizowanego” i „czekaj”. Oczekiwanie na zasygnalizowane zdarzenie to brak operacji z natychmiastową kontynuacją wykonania wątku. Oczekiwanie na niezaznaczone zdarzenie powoduje zawieszenie wątku do momentu, gdy inny wątek (lub druga faza obsługi przerwań w jądrze systemu operacyjnego) zasygnalizuje zdarzenie. Możliwe jest oczekiwanie na kilka zdarzeń w trybie „dowolne” lub „wszystkie”. Możliwe jest również stworzenie zdarzenia, które jest automatycznie resetowane do stanu niesygnalizowanego po wybudzeniu pierwszego – i jedynego – oczekującego wątku (taki obiekt jest używany jako podstawa do realizacji obiektu „sekcja krytyczna”). Są aktywnie używane w MS Windows, zarówno w trybie użytkownika, jak iw trybie jądra. W jądrze Linuksa istnieje podobny obiekt o nazwie kwait_queue.

Sekcje krytyczne zapewniają synchronizację podobną do muteksów, z wyjątkiem tego, że obiekty reprezentujące krytyczne sekcje są dostępne w tym samym procesie. Zdarzenia, muteksy i semafory mogą być również używane w aplikacji jednoprocesowej, jednak implementacje sekcji krytycznych w niektórych systemach operacyjnych (takich jak Windows NT) zapewniają szybszy i bardziej wydajny mechanizm wzajemnie wykluczającej się synchronizacji - operacje pobierania i zwalniania na sekcja krytyczna jest zoptymalizowana dla przypadku pojedynczego wątku (brak rywalizacji) w celu uniknięcia jakichkolwiek wywołań systemowych prowadzących do jądra systemu operacyjnego. Podobnie jak muteksy, obiekt reprezentujący sekcję krytyczną może być używany tylko przez jeden wątek na raz, co czyni je niezwykle przydatnymi do ograniczania dostępu do współdzielonych zasobów.

Zmienne warunkowe(kondwary). Są podobne do zdarzeń, ale nie są obiektami zajmującymi pamięć - używany jest tylko adres zmiennej, pojęcie „zawartość zmiennej” nie istnieje, adres dowolnego obiektu może być użyty jako zmienna warunkowa . W przeciwieństwie do zdarzeń, ustawienie zmiennej warunku na stan sygnalizowany nie ma żadnych konsekwencji, jeśli obecnie nie ma wątków oczekujących na zmienną. Ustawienie zdarzenia w podobnym przypadku wiąże się z przechowywaniem stanu „zasygnalizowanego” wewnątrz samego zdarzenia, po czym kolejne wątki chcące czekać na zdarzenie kontynuują wykonywanie natychmiast bez zatrzymywania. Aby w pełni wykorzystać taki obiekt, konieczne jest również zwolnienie muteksu i atomowe oczekiwanie na zmienną warunkową. Są szeroko stosowane w systemach operacyjnych typu UNIX. Dyskusje o zaletach i wadach zdarzeń i zmiennych warunkowych są ważną częścią dyskusji o zaletach i wadach systemów Windows i UNIX.

Port zakończenia we/wy(port zakończenia IO, IOCP). Obiekt „kolejka” zaimplementowany w jądrze systemu operacyjnego i dostępny poprzez wywołania systemowe z operacjami „umieść strukturę w ogonie kolejki” i „pobierz następną strukturę z początku kolejki” - ostatnie wywołanie wstrzymuje wykonanie wątek, jeśli kolejka jest pusta i dopóki inny wątek nie wykona wywołania „put”. Najważniejszą cechą IOCP jest to, że struktury mogą być w nim umieszczane nie tylko przez jawne wywołanie systemowe z trybu użytkownika, ale także niejawnie w jądrze systemu operacyjnego w wyniku asynchronicznej operacji we/wy zakończonej na jednym z deskryptorów plików. Aby osiągnąć ten efekt, musisz użyć wywołania systemowego „powiąż deskryptor pliku z IOCP”. W tym przypadku struktura umieszczona w kolejce zawiera kod błędu operacji I/O, a także, jeśli operacja ta się powiedzie, ilość faktycznie wprowadzonych lub wyjściowych bajtów. Implementacja portu zakończenia ogranicza również liczbę wątków działających na pojedynczym procesorze / rdzeniu po umieszczeniu struktury w kolejce. Obiekt jest specyficzny dla MS Windows i umożliwia przetwarzanie przychodzących żądań połączeń i porcji danych w oprogramowaniu serwera w architekturze, w której liczba wątków może być mniejsza niż liczba klientów (nie ma potrzeby tworzenia osobnego wątku z wykorzystaniem zasobów dla każdego nowego klienta).

Pula wątków

Opowiedz o puli wątków

Wiele nowoczesnych aplikacje na platformy mobilne(iOS, Android itp.) działa w parze z serwerem. Aplikacja z nieaktualnymi danymi traci swoją użyteczność. Dlatego ważne jest, aby zapewnić aktualność danych z serwera do urządzenia. Dotyczy to aplikacji offline, które powinny działać bez Internetu. W przypadku aplikacji całkowicie online, które nie działają (lub są bezużyteczne) bez Internetu (np. Foursquare, Facebook) istnieją specyfiki, które wykraczają poza zakres tego artykułu.

Na przykładzie jednej z naszych aplikacji offline opowiem, jakie podejścia zastosowaliśmy do synchronizacji danych. W pierwszych wersjach opracowaliśmy proste algorytmy, a w przyszłości z doświadczeniem ulepszaliśmy je. Podobna kolejność została przedstawiona w artykule - od prostych, oczywistych praktyk do bardziej skomplikowanych.

Należy wyjaśnić, że artykuł dotyczy przesyłania danych tylko w jednym kierunku: z serwera na urządzenie. Tutaj serwer jest źródłem danych.

Przepisy ogólne dla wszystkich podejść

Jako przykład rozważymy przeniesienie katalogu dań („naczyń”) do urządzenia. Przyjmiemy, że urządzenie zgłasza żądanie url „/serwis/dania/aktualizacja”, wymiana odbywa się poprzez protokół http w formacie JSON ( www.json.org). Serwer posiada tabelę „dishes” z następującymi polami: id (identyfikator rekordu), name (nazwa dania), aktualizacja (w momencie aktualizacji dania lepiej od razu zrobić obsługę stref czasowych, „RRRR-MM -DDThh: mm: ssTZD”, na przykład „1997 -07-16T19: 20: 30 + 01: 00 ”), is_deleted (znak usuniętego rekordu).

Uwaga dotycząca obecności ostatniego pola. Domyślnie jego wartość to 0. W aplikacji, w której encje są synchronizowane między klientem a serwerem, nie zaleca się fizycznego usuwania danych z serwera (aby uniknąć błędów). Dlatego dla usuniętych potraw ustawiana jest wartość is_deleted = 1. Gdy jednostka z is_deleted = 1 dociera do urządzenia, jest z niego usuwana.

Przy dowolnym podejściu, które zostanie rozważone poniżej, serwer zwraca tablicę obiektów do urządzeń JSON (może być pusta):

[
(NS: , Nazwa: , zaktualizowane: , jest usunięty: },…
]

Przykład odpowiedzi serwera:

[
(id: 5625, nazwa: "Chleb", aktualizacja: "2013-01-06 06:23:12", isDeleted: 0),
(id: 23, nazwa: „Gotowana kasza manna”, aktualizacja: „2013-02-01 14:44:21”, isDeleted: 0), (

nazwa: "Zupa rybna",

aktualizacja: "2013-08-02 07:05:19",

Zasady aktualizacji danych na urządzeniu

  1. Jeśli pojawił się element, który jest na urządzeniu i jest usunięty = 0, to jest aktualizowany
  2. Jeśli przybył element, którego nie ma na urządzeniu i jestDeleted = 0, zostanie on dodany
  3. Jeśli pojawił się element znajdujący się na urządzeniu i jestDeleted = 1, to jest usuwany
  4. Jeśli przybył element, którego nie ma na urządzeniu, a jest usunięty = 1, nic nie zostanie zrobione

Podejście 1: Wszystko jest zawsze zsynchronizowane

To najłatwiejsza metoda. Urządzenie żąda od serwera listy dań, a serwer wysyła całą listę. Za każdym razem przychodzi cała lista. Nie posortowane.

Przykładowe żądanie: null lub „()”

Zalety:

  • logika na serwerze jest prosta - zawsze dajemy z siebie wszystko
  • logika na urządzeniu jest prosta - zawsze wszystko nadpisujemy

Niedogodności:

  • jeśli często prosisz o listę (co 10 minut), będzie duży ruch w Internecie
  • jeśli rzadko poprosisz o listę (raz dziennie), wówczas aktualność danych zostanie naruszona

Obszar zastosowań:

  • do zastosowań o małym natężeniu ruchu
  • przesyłanie bardzo rzadko zmieniających się danych (lista miast, kategorie)
  • przeniesienie ustawień aplikacji
  • na początku projektu pierwszego prototypu aplikacji mobilnej

Podejście 2: synchronizuj tylko zaktualizowane

Urządzenie żąda listy dań, zaktualizowanej z poprzedniej synchronizacji. Lista jest sortowana według „aktualizacji” w porządku rosnącym (opcjonalne, ale wygodne). Urządzenie przechowuje wartość „updated” dla ostatnio wysłanej anteny i przy kolejnym żądaniu wysyła ją do serwera w parametrze „lastUpdated”. Serwer wysyła listę dań nowszych niż „lastUpdated” (aktualizacja>lastUpdated). Przy pierwszym żądaniu do serwera „lastUpdated” = null.

Przykładowe żądanie: (lastUpdated: „2013-01-01 00:00:00”)

Na diagramie: „last_updated” to wartość przechowywana na urządzeniu. Zwykle na urządzeniu tworzona jest osobna tabela do przechowywania tych „ostatnich aktualizacji” wartości dla każdej jednostki (danie, miasto, organizacja itp.)

To podejście jest odpowiednie do synchronizowania prostych list liniowych, w których reguły przybycia są takie same dla wszystkich urządzeń. Aby uzyskać bardziej selektywną synchronizację, zobacz „Podejście 5: Synchronizuj z wiedzą o tym, co jest już na urządzeniu”.

Takie podejście zwykle obejmuje większość potrzeb. Do urządzenia trafiają tylko nowe dane, można je synchronizować przynajmniej co minutę - ruch będzie niewielki. Istnieją jednak problemy związane z ograniczeniami urządzeń mobilnych. Są to pamięć i procesor.

Podejście 3: Synchronizuj w partiach

Urządzenia mobilne mają mało pamięci RAM. Jeśli w katalogu znajduje się 3000 dań, to parsowanie dużego ciągu json z serwera na obiekty na urządzeniu może spowodować brak pamięci. W takim przypadku aplikacja albo ulegnie awarii, albo nie zapisze tych 3000 potraw. Ale nawet jeśli urządzenie było w stanie przetrawić taki ciąg, to wydajność aplikacji w momentach synchronizacji w tle będzie niska (lagi interfejsu, nie płynne przewijanie itp.) Dlatego konieczne jest żądanie listy w mniejszych porcjach.

W tym celu urządzenie przekazuje jeszcze jeden parametr („kwota”), który określa wielkość porcji. Listę należy przesłać posortowaną według pola „zaktualizowane” w kolejności rosnącej. Urządzenie, podobnie jak w poprzednim podejściu, zapamiętuje wartość „updated” ostatniej wysłanej encji i przekazuje ją do pola „lastUpdated”. Jeśli serwer wysłał dokładnie taką samą liczbę encji, urządzenie kontynuuje synchronizację i ponownie wysyła żądanie, ale z zaktualizowanym „lastUpdated”. Jeżeli serwer wysłał mniej podmiotów oznacza to, że nie ma więcej nowych danych, a synchronizacja się kończy.

Na diagramie: „ostatnia_aktualizacja” i „kwota” to wartości, które są przechowywane w mobilna aplikacja... „Last_item” - ostatnia jednostka (danie) wysłana z serwera. Następna lista zostanie poproszona o nowszą wartość.

Przykładowe żądanie: (lastUpdated: „2013-01-01 00:00:00”, kwota: 100)

Zalety:

  • Urządzenie otrzymuje tyle danych, ile jest w stanie jednorazowo przetworzyć. Wielkość porcji ustalana jest na podstawie testów praktycznych. Proste jednostki mogą być synchronizowane 1000 na raz. Ale zdarza się również, że encje z dużą liczbą pól i złożoną logiką przetwarzania pamięci masowej są synchronizowane zwykle nie więcej niż 5 sztuk.

Niedogodności:

  • Jeżeli z tą samą aktualizacją jest 250 anten, to przy ilości = 100 ostatnich 150 nie zostanie wysłanych do urządzeń. Ta sytuacja jest całkiem realna i jest opisana w następującym podejściu.

Podejście 4: Prawidłowy czas wsadu

W poprzednim podejściu możliwe jest, że jeśli w tabeli znajduje się 250 dań z tym samym „zaktualizowanym” (np. „2013-01-10 12:34:56”) i porcja wynosi 100, to tylko pierwsze 100 przyjdą rekordy. Pozostałe 150 zostanie przypiętych na stałe (zaktualizowany> ostatni zaktualizowany). Dlaczego tak się stanie? Po zażądaniu pierwszych 100 rekordów parametr lastUpdated zostanie ustawiony na „2013-01-10 12:34:56”, a następne żądanie będzie miało warunek (updated>„2013-01-10 12:34:56”). Nawet złagodzenie warunku (zaktualizowane> = „2013-01-10 12:34:56”) nie pomoże, ponieważ urządzenie będzie wtedy bez końca żądać pierwszych 100 rekordów.

Sytuacja z tym samym „zaktualizowanym” nie jest tak rzadka. Na przykład podczas importowania danych z pliku tekstowego pole „zaktualizowane” zostało ustawione na TERAZ (). Zaimportowanie pliku z tysiącami wierszy może zająć mniej niż sekundę. Może się również zdarzyć, że cały katalog będzie miał taką samą „aktualizację”.

Aby to naprawić, musisz użyć jakiegoś pola dania, które będzie unikalne przynajmniej w ciągu jednej chwili („zaktualizowane”). Pole „id” jest unikalne w całej tabeli, dlatego należy go dodatkowo używać w synchronizacji.

Tak więc wdrożenie tego podejścia wygląda tak. Serwer zwraca listę posortowaną według „zaktualizowanych” i „id”, a urządzenia żądają danych za pomocą „lastUpdated” i nowego parametru „lastId”. Na serwerze warunek wyboru jest bardziej skomplikowany: ((updated> lastUpdated) LUB (updated = lastUpdated i id> lastId)).

Na diagramie: „last_updated”, „last_id” i „amount” to wartości, które są przechowywane w aplikacji mobilnej. „Last_item” - ostatnia jednostka (danie) wysłana z serwera. Następna lista zostanie poproszona o nowszą wartość.

Podejście 5: Synchronizuj z wiedzą o tym, co jest już na urządzeniu

Dotychczasowe podejścia nie uwzględniają faktu, że serwer tak naprawdę nie wie, jak skutecznie dane zostały zapisane na urządzeniu. Urządzenie mogło po prostu nie zapisać niektórych danych z powodu niewyjaśnionych błędów. Dlatego fajnie byłoby otrzymać potwierdzenie z urządzenia, że ​​wszystkie (lub nie wszystkie) naczynia zostały zachowane.

Dodatkowo użytkownik aplikacji może skonfigurować aplikację w taki sposób, że potrzebuje tylko części danych. Na przykład użytkownik chce zsynchronizować anteny tylko z 2 miast z 10. Nie można tego osiągnąć za pomocą synchronizacji opisanych powyżej.

Idea tego podejścia jest następująca. Serwer przechowuje (w osobnej tabeli „stored_item_list”) informacje o tym, jakie dania znajdują się na urządzeniu. Może to być po prostu lista par „id - zaktualizowany”. Ta tabela zawiera wszystkie listy „id - zaktualizowanych” par anten dla wszystkich urządzeń.

Urządzenie wysyła na serwer informacje o dostępnych na nim daniach (lista par „id - aktualizacja”) wraz z prośbą o synchronizację. Na żądanie serwer sprawdza, które dania powinny znajdować się na urządzeniu, a które są teraz. Różnica jest następnie wysyłana do urządzenia.

W jaki sposób serwer określa, które naczynia powinny znajdować się na urządzeniu? W najprostszym przypadku serwer wysyła żądanie, które zwróci listę par „id - zaktualizowane” wszystkich dań (np. SELECT id, zaktualizowane FROM dania). Na diagramie odbywa się to za pomocą metody „WhatShouldBeOnDeviceMethod()”. To jest wada tego podejścia - serwer musi obliczyć (czasami wykonując ciężkie zapytania sql), co powinno znajdować się na urządzeniu.

W jaki sposób serwer określa, które naczynia znajdują się na urządzeniu? Wykonuje zapytanie do tabeli „stored_item_list” dla tego urządzenia i otrzymuje listę par „id - zaktualizowane”.

Analizując te dwie listy, serwer decyduje, co należy przesłać na urządzenie, a co usunąć. Na schemacie jest to „delta_item_list”. Dlatego żądanie nie zawiera „lastUpdated” i „lastId”, ich zadanie jest realizowane przez pary „id - aktualizacja”.

Skąd serwer wie o daniach dostępnych na urządzeniu? W żądaniu do serwera dodawany jest nowy parametr „pozycje”, który zawiera listę identyfikatorów potraw, które zostały wysłane do urządzenia w ostatniej synchronizacji („device_last_storeed_item_list”). Oczywiście możesz przesłać listę id wszystkich naczyń, które znajdują się na urządzeniu i nie komplikować algorytmu. Ale jeśli na urządzeniu jest 3000 anten i wszystkie są wysyłane za każdym razem, koszty ruchu będą bardzo wysokie. W zdecydowanej większości synchronizacji parametr „pozycje” będzie pusty.

Serwer musi stale aktualizować „stored_item_list” danymi, które pochodzą z urządzenia w parametrze „items”.

Powinieneś zaimplementować mechanizm czyszczenia danych serwera w store_item_list. Na przykład po ponownej instalacji aplikacji na urządzeniu serwer założy, że urządzenie jest nadal aktualne. Dlatego podczas instalowania aplikacji urządzenie musi w jakiś sposób poinformować serwer, aby wyczyścił przechowywaną_listę_elementów dla tego urządzenia. W naszej aplikacji wysyłamy dodatkowy parametr „clearCache” = 1 w tym przypadku.

Wniosek

Tabela podsumowująca cechy tych podejść:

Podejście Natężenie ruchu(5 - duże) Pracochłonność rozwoju(5 - wysoki) Wykorzystanie pamięci urządzenia(5 - wysoki) Poprawność danych na urządzeniu(5 - wysoki) Możesz wybrać konkretne urządzenie
1 Wszystko jest zawsze zsynchronizowane 5 1 5 5 Nie
2 Tylko zaktualizowane 1 2 5 3 Nie
3 Synchronizacja w partiach 1 3 1 3 Nie
4 Prawidłowa synchronizacja w partiach 1 3 1 3 Nie
5 Synchronizacja ze znajomością tego, co jest już na urządzeniu 2 5 2 5 tak

„Poprawność danych na urządzeniu” to prawdopodobieństwo, że urządzenie zawiera wszystkie dane, które zostały przesłane przez serwer. W przypadku podejść nr 1 i nr 5 mamy 100% pewność, że urządzenie posiada wszystkie potrzebne mu dane. W innych przypadkach takiej gwarancji nie ma. Nie oznacza to, że nie można zastosować innych podejść. Tyle tylko, że jeśli część danych zostanie utracona na urządzeniu, to nie będzie można tego naprawić z serwera (a tym bardziej dowiedzieć się o tym po stronie serwera).

Być może w obliczu nieograniczonych taryf internetowych i darmowego Wi-Fi problem ograniczenia ruchu generowanego przez aplikację mobilną stanie się mniej istotny. Ale chociaż musisz skorzystać z różnego rodzaju sztuczek, wymyśl inteligentniejsze podejścia, które mogą obniżyć koszty sieci i zwiększyć wydajność aplikacji. To nie zawsze działa. Czasem „im prościej, tym lepiej”, w zależności od sytuacji. Mamy nadzieję, że z tego artykułu możesz wybrać podejście, które się przyda.

Zaskakująco mało jest opisów synchronizacji serwerów w Internecie i urządzenia mobilne... Co więcej, istnieje wiele aplikacji, które działają zgodnie z tym schematem. Dla zainteresowanych kilka linków.

Offline w przeszłości, bycie online dzisiaj jest koniecznością. Przynajmniej dla współczesnego świata biznesu. Prezentacje produktów i usług marki, zamówienia i dostawy online, utrzymanie bazy klientów, komunikacja z klientami i wiele więcej – to wszystko jest po prostu niemożliwe bez obecności w Internecie. Jeśli potrzebujesz aplikacji, musisz mieć zarówno Front-end (interfejs internetowy), jak i Back-End (back-end swojej aplikacji). A jeśli chcesz mieć możliwość edytowania zawartości swojej aplikacji bez zaangażowania programistów, potrzebujesz dobrego panelu administracyjnego.

Podczas gdy Front-end w przestrzeni aplikacji mobilnych jest budowany przy użyciu technologii takich jak X-Code i Java, Back-end, w którym będzie przechowywana baza danych i cała logika aplikacji, wymaga profesjonalnej znajomości języka programowania po stronie serwera. Dobrym przykładem jest PHP, który jest prawdopodobnie najpopularniejszym językiem programowania używanym do prawie każdego programowania po stronie serwera. To jest niekwestionowany lider.

PHP ma wiele zastosowań: strony statyczne i dynamiczne + niestandardowe systemy zarządzania treścią, media społecznościowe, specjalistyczne systemy CRM, oprogramowanie e-commerce i inne. Oczywiście dostępne są darmowe lub tanie części serwerowe i panele kontrolne. Jednak w wielu przypadkach nie zapewniają one wymaganego poziomu wygody, dostosowania i możliwości uaktualniania.

Nasi programiści pracują z technologiami, aby wdrażać szeroką gamę rozwiązań dla różnych celów biznesowych, potrzeb i wymagań. Analizujemy wymagania systemowe dla każdego projektu indywidualnie i wykorzystujemy różne specjalistyczne oprogramowanie serwerowe w celu optymalnego działania Twojej aplikacji mobilnej.

Jeśli szukasz zespołu, który poprowadzi Cię do najmądrzejszego i najbardziej opłacalnego rozwiązania do tworzenia aplikacji od podstaw lub przebudowy istniejącej, aby zapewnić doskonałe wrażenia użytkownika, nie musisz już szukać. Appsmob jest gotowy, aby pomóc Ci znaleźć najlepsze rozwiązanie dla Ciebie.

Minusem klientów mobilnych jest serwer.

Dodatkowe wymagania zależą od specyfiki aplikacji:
skalowalność serwera - dla SaaS, aplikacji społecznościowych, gdzie w idealnym przypadku spodziewany jest duży przepływ odwiedzających, warunek ten jest obowiązkowy. W przypadku aplikacji biznesowych, w których istnieją ograniczenia liczby użytkowników lub liczba jest przewidywana, ta właściwość nie jest wymagana;
interaktywność: wiele aplikacji musi być wyposażonych w mechanizm powiadomień - aby poinformować aplikację (użytkownika) o wystąpieniu określonych zdarzeń, należy wysłać wiadomość do użytkownika. Tą nieruchomość powinien posiadać np. system wymiany lub automatyczny dyspozytor taksówek.
otwarte API: zakłada się, że zewnętrzni programiści mogą korzystać z funkcjonalności systemu za pośrednictwem udokumentowanego protokołu. W końcu klientem może być aplikacja mobilna lub zewnętrzna aplikacja serwerowa.
inne wymagania ...

Komenda
Idealnie skład zespołu projektowego ds. rozwoju systemu może wyglądać następująco:
kierownik projektu: zarządza, kontroluje projekt, współpracuje bezpośrednio z klientem;
programista aplikacji serwerowych: opracowuje serwer logiki biznesowej, bazę danych, protokół sieciowy;
programista aplikacji administratora: tworzy aplikację internetową, interfejs użytkownika do konfiguracji i zarządzania aplikacją serwerową;
programista aplikacji klienckich na Androida;
programista aplikacji klienckich na iOS;
programista aplikacji klienckich dla ...
tester: testuje aplikację administracyjną i aplikacje klienckie.

Uważny czytelnik zauważy, że jeśli napiszesz aplikację po stronie serwera z interfejsem graficznym, na przykład w HTML5, możesz zaoszczędzić pieniądze. W tym przypadku tworzenie aplikacji klienckich nie jest wymagane - interfejs użytkownika zapewnia przeglądarka. Ten artykuł nie dotyczy takiego przypadku, chodzi o rozwój „natywnych” (natywnych) aplikacji na urządzenia mobilne.

Pracowałem w zespole z pełną obsadą, ale będę realistą - nie zawsze zasoby ludzkie i budżet pozwalają na zebranie takiego zespołu. A czasem trzeba połączyć role: kierownik projektu + programista aplikacji serwerowych, programista aplikacji klienckiej + tester.

Technologie, narzędzia, biblioteki
Do opracowania serwera dla klientów mobilnych zazwyczaj używam następującego stosu „darmowych” technologii:
Apache Tomcat - Kontener serwletów;
MySQL - DBMS;
Subversion to system kontroli wersji;
Maven to framework do automatyzacji kompilacji projektów;
JUnit - zapewni;
Apache Log4j - biblioteka logów;
Jenkins - system ciągłej integracji;
Hibernate - ORM (ustawienia, konfiguracja we właściwościach, plikach xml i adnotacjach);
hibernate-generic-dao - implementacja DAO od Google, implementuje podstawowe metody pracy z danymi bazy danych, upraszcza implementację filtrowania i sortowania w metodach;
- implementacja uwierzytelniania i autoryzacji (bezpieczeństwo), kontener usług i bean (konfiguracja w plikach xml oraz w adnotacjach), wykorzystujemy również przy tworzeniu testów.

W zależności od specyfiki systemu i wymagań dla niego, korzystam z jednej z 2 opcji implementacji protokołu wymiany danych.
Gdy wymagana jest wieloplatformowość, szybkość, prostota, wydajność, skalowalność, otwarte API, wtedy biorę Jersey - implementację usług RESTful Web. Ta biblioteka umożliwia korzystanie z serializacji danych JSON i / lub XML. Konfiguracja REST odbywa się za pomocą adnotacji. Do wymiany z urządzeniami mobilnymi przyjęto format JSON ze względu na to, że ma prostszą implementację po stronie klienta (z tego powodu nie korzystamy z „klasycznych” serwisów WWW), generowany jest mniejszy ruch. Jersey pozwala dostroić się do najbardziej odpowiedniego „wyglądu” JSON.
W przeciwnym razie, jeśli potrzebujesz wieloplatformowej, wysokiej wydajności, prostoty, wydajności, interaktywności, to biorę
Apache MINA to framework do budowania aplikacji sieciowych,
Protobuf Google to ustrukturyzowana biblioteka kodowania i dekodowania danych. Strukturę danych określają pliki nagłówkowe *.proto, z których kompilator generuje klasy Java (istnieje również możliwość generowania dla innych języków programowania: C++, Objective-C itp., co zapewnia wieloplatformowość własność);
java.util.concurrent - używamy standardowego pakietu.
Ta opcja może być skalowana, ale musi to być ustalone na etapie projektowania na poziomie architektury, z uwzględnieniem logiki biznesowej.

Rozważmy hipotetyczny problem na przykładzie wyboru technologii dla rzeczywistej usługi SaaS - „Aukcja usług„ Auknem ”, która pozwala ludziom złożyć zamówienie na wykonanie wymaganych usług lub prac, a organizacjom z kolei, zostaw im swoje propozycje. Domyślnie przyjmujemy wszystkie podstawowe wymagania. Ze względu na to, że rejestracja w tym systemie jest bezpłatna i bezpłatna, zdecydowanie konieczne jest dodanie do nich skalowalności. A co z interaktywnością? Fajnie byłoby poinformować kontrahentów (wykonawców) o tworzeniu nowych zamówień, a klientów o otrzymanych w tym samym momencie w aplikacji propozycjach, a nie tylko mailowo. Na tej podstawie bierzemy za implementację Apache MINA, protobuf Google. Patrzymy na kolejną właściwość - otwarte API. Usługa jest ogólnodostępna, więc załóżmy, że integracją z nią mogą być zainteresowani zewnętrzni programiści. Poczekaj minutę! Nie takie proste. Protokół oparty na Apache MINA jest dość zależny od implementacji, a integracja bez znajomości niuansów nie jest w żaden sposób przejrzysty. W takiej sytuacji będziesz musiał rozważyć, który czynnik jest ważniejszy i dokonać wyboru.

Wniosek
Chciałbym wiedzieć, jakich technologii, bibliotek używałeś przy tworzeniu serwera na urządzenia mobilne lub podobne systemy? Wszystko się zmienia, nic nie trwa wiecznie, na każdym poziomie są alternatywy z własnymi zaletami i wadami: MySQL -

UTWORZYĆ KOPIĘ ZAPASOWĄ

Dlaczego potrzebujesz kopii zapasowych na platformie mobilnej

Eksperci wiedzą, jak czasami zawodne są aplikacje mobilne na 1C: błędy mogą wystąpić w dowolnym momencie, przez co baza użytkowników po prostu się zawali. Jednocześnie mamy do czynienia z zawodnością samych urządzeń: można je zepsuć, zgubić, można je ukraść, a użytkownicy chcą zachować swoje dane. A do wersji 8.3.9 nie mieliśmy mechanizmu platformy do zapisywania kopii zapasowej.

Ponieważ użytkownicy nie mieli wcześniej przycisku „zapisz kopię”, twórcy aplikacji Boss musieli tworzyć własne kopie zapasowe. Jak to zrobiliśmy?

Dane bazy danych zapisujemy w postaci XML.

Wskazane jest zaoferowanie użytkownikowi kilku opcji przechowywania kopii - przede wszystkim jest to wygodne dla klientów, mogą wybrać najlepszą dla siebie opcję: przesłać do chmury, wysłać na pocztę, zapisać na urządzeniu.

W ten sposób deweloperzy dodatkowo się ubezpieczają. Jeśli coś poszło nie tak, a mechanizm tworzenia kopii na Google Drive lub Yandex Drive nagle się zepsuł, zawsze można powiedzieć użytkownikowi, że programista aktualnie ma do czynienia z błędem, ale na razie może zapisać dane w alternatywny sposób. A użytkownicy są zadowoleni, ponieważ mogą być spokojni o swoje dane.

Koniecznie trzeba skupić się na usługach w chmurze, ponieważ jeśli urządzenie zostanie zgubione lub zepsute, a użytkownik zapisał kopię na tym samym urządzeniu, to dane zostaną utracone.

Także my pamiętaj, aby przypomnieć użytkownikowi o konieczności tworzenia kopii zapasowych.

Jak zachować kopie w przypadku zmiany konfiguracji?

Kiedy mówimy o rozwiązaniu masowym, o aplikacji, która ciągle się zmienia, ewoluuje i udoskonala, należy wziąć pod uwagę zachowania klientów. Użytkownik może chcieć przywrócić kopię zapasową zapisaną w starej wersji aplikacji, która nie posiadała żadnych szczegółów. I wtedy pojawia się zadanie: odczytać dane, a następnie uzupełnić dane zgodnie z logiką aktualizacji ze starej wersji aplikacji. Jak to zrobić? Oprócz danych zapisz samą strukturę danych, aby później wiedzieć, jak ją odczytać.

Istnieje kilka opcji przechowywania tej struktury danych, w tym możliwość jej przechowywania w samej konfiguracji. Oznacza to, że za każdym razem, gdy zostanie wydana nowa wersja, zachowaj strukturę metadanych poprzedniej wersji w układzie w konfiguracji.

Nie zapominajmy, że w aplikacji mobilnej konfiguracja nie powinna tak po prostu rosnąć, powinniśmy docenić miejsce w niej, powinniśmy uczynić ją jak najbardziej zwartą. Ale aplikacja się rozwija, a takich układów będzie wiele, a z czasem będzie ich coraz więcej.

Dlatego w przypadku aplikacji mobilnej preferowany jest inny sposób - zapisz strukturę metadanych bezpośrednio w pliku danych... Na wyjściu otrzymujemy taki plik, w którym najpierw przechowujemy pewne dane pomocnicze - wersję konfiguracji, schemat konfiguracji, granice sekwencji, a następnie zapisujemy dane użytkownika w formacie XML. Co więcej, w sekcji „Dane pomocnicze” pliku można również przechowywać inne ważne dane, których z jakiegoś powodu nie można było zapisać w XML.

Bierzemy schemat danych, który zapisaliśmy do pliku i na jego podstawie budujemy pakiet XDTO do odczytu pliku. Tworzymy podobny obiekt w bazie danych, uzupełniamy go, wykonujemy refill podczas aktualizacji i zapisujemy gotowy już obiekt do bazy danych.

Poniżej na zdjęciu widać podpowiedź jak pięknie napisać model XDTO tych konfiguracji. Firma, która wydała aplikację Boss, eksperymentowała z tym, znalazła kilka sposobów, ale zdecydowała się na tę opcję rejestrowania schematu metadanych. Po otwarciu samego pliku danych można zobaczyć zwykły ustrukturyzowany kod XML, czytelny, który zawiera wszystkie metadane aplikacji.

// Napisz schemat konfiguracji ModelXDTO = FactoryXDTO.ExportModelsXDTO ("http://v8.1c.ru/8.1/data/enterprise/current-config"); XDTO Factory.WriteXML (Prześlij plik, model XDTO); // Odczyt schematu konfiguracji Model XDTO = Factory XDTO. Read XML (Read XML, Factory XDTO. Type ("http://v8.1c.ru/8.1/xdto", "Model")); UnloadFactory = Nowa fabryka XDTO (XDTOModel);

Aby chronić użytkownika, konieczne jest ponowne pytanie go, czy musi przywrócić kopię zapasową. Może po prostu eksperymentował i klikał wszystkie przyciski w aplikacji :) A teraz aktualne dane mogą zostać utracone. Dlatego wykonując potencjalnie „niebezpieczne” działania, zawsze określamy, czy naprawdę tego chce i jak należy to zrobić. Użytkownik musi być świadomy swoich działań.

Musi istnieć mechanizm tworzenia kopii zapasowych, gdy mówimy o rozwiązaniu autonomicznym, gdy użytkownik ma wszystkie dane przechowywane wyłącznie na urządzeniu mobilnym: użytkownik może stracić swoje urządzenie, a wtedy dane zostaną utracone. I wydawałoby się, że jeśli aplikacja nie działa autonomicznie, ale jest podłączona do centralnego serwera, to użytkownik nie powinien mieć takiego problemu, ponieważ w przypadku zgubienia urządzenia połączy się z serwerem, odbierze wszystkie swoje dane z serwera znowu i wszystko będzie ok.

Jednak użytkownicy nie zawsze używają kopii zapasowych tak, jak tego oczekujemy :) Bardzo często używają ich do po prostu „wycofywania” danych. To naprawdę bardzo dziwne zachowanie, ale użytkownicy aplikacji mobilnych są zbyt leniwi, aby zorientować się, gdzie mogli popełnić błąd podczas wprowadzania danych, i po prostu wycofują dane i ponownie wprowadzają dane z bieżącego dnia. Po przeanalizowaniu statystyk pracy z aplikacją Boss zdaliśmy sobie sprawę, że jest to normalna praktyka i takie zachowanie użytkownika jest bardziej powszechne niż mogliśmy się spodziewać.

A jeśli korzystasz z synchronizacji z innymi urządzeniami, musisz sobie z tym poradzić. Jest tu kilka rozwiązań:

  • zerwać połączenie z serwerem, określając, że dane na nim pozostaną bez zmian, a kopia zostanie przywrócona dopiero na urządzeniu użytkownika;
  • lepiej, aby użytkownik pozwolił mu od razu przywrócić kopię na wszystkich urządzeniach, po wcześniejszym zaleceniu takich mechanizmów.

Jest jeszcze jedna rzecz. Do tej pory sami zapisywaliśmy kopie zapasowe, kontrolowaliśmy cały proces, wyłapywaliśmy działania użytkownika bezpośrednio w kodzie, gdy naciskał przycisk „zapisz kopię”. Wszystko to można przetworzyć później. W platformie 8.3.9 stało się możliwe zapisywanie kopii zapasowych właśnie za pomocą platformy. A użytkownik robi to bez naszej wiedzy. Jeżeli wykorzystywana jest synchronizacja z centralną bazą danych, to taki scenariusz musi być obsłużony. Musimy jakoś dowiedzieć się na naszym serwerze, że użytkownik przywrócił wcześniej zapisaną kopię i musi dać mu jakieś rozwiązanie. Nie możemy sobie pozwolić na brak synchronizacji danych.

WYMIENIAĆ SIĘ

Kiedy mówimy o prywatnym rozwiązaniu na platformę mobilną, zazwyczaj mamy klienta, który np. chce wykorzystać platformę mobilną dla swoich agentów sprzedaży i tak, aby wymieniali dane z centralną bazą danych. Tutaj wszystko jest proste: jedna baza danych, kilka urządzeń, podnosisz serwer, konfigurujesz z nim komunikację. Tak więc problem wymiany między urządzeniami jest łatwy do rozwiązania.

Ale jeśli mówimy o aplikacji masowej, gdzie istnieje wiele baz danych, z których każda ma bardzo dużą liczbę użytkowników, sytuacja staje się bardziej skomplikowana. Użytkownicy pobrali aplikację z rynku i chcą się ze sobą zsynchronizować. Na przykład mąż pobrał aplikację do rozliczania finansów osobistych, a teraz chce, aby jego żona też się połączyła i pracowali razem w tej samej aplikacji. Jest wielu użytkowników, aplikacja się rozwija, rośnie i istnieje potrzeba dużej, dużej liczby baz danych. Jak to wszystko zorganizować? Użytkownicy nie będą osobiście kontaktować się z programistami, aby utworzyć dla nich oddzielną bazę danych i umożliwić synchronizację. Chcą wcisnąć przycisk i sprawić, by od razu zadziałało. W tym samym momencie.

Jak postępować? I tu z pomocą przychodzi mechanizm udostępniania danych. Pozwala na zorganizowanie jednej bazy danych, w której istnieje jedna wspólna konfiguracja, ale jednocześnie w jednej wspólnej bazie danych przechowywana jest nieograniczona liczba baz użytkowników.

Najlepsze jest to, że możesz dodawać użytkowników dynamicznie, programowo, bez naszego udziału. W rzeczywistości użytkownicy po prostu klikają przycisk „zarejestruj się na serwerze” i wszystko dzieje się samo: na serwerze tworzona jest dla niego osobista baza danych, z której może od razu zacząć pracować.

Jak to zrobić? Pierwszym i najprostszym rozwiązaniem jest napisanie własnej bazy serwerów z tym mechanizmem. Kiedy nasza firma zaczęła tworzyć aplikację Boss i w niej giełdy, w pierwszej wersji zrobiliśmy właśnie to: napisaliśmy serwerową bazę danych z mechanizmem udostępniania danych. Wszystko działało, zwłaszcza, że ​​nie było nic skomplikowanego - separator bazowy to częsty rekwizyt.

Ale potem zdaliśmy sobie sprawę, że wymyślamy koło na nowo :) W rzeczywistości istnieje gotowe rozwiązanie, które już uwzględniało punkty, o których jeszcze nawet nie pomyśleliśmy. To jest 1C: Świeże.

Tutaj przemyślana jest skalowalność usługi: co zrobić, gdy danych i baz danych będzie dużo, jak się z tym wszystkim rozwijać. Jest sens tworzenia kopii zapasowych obszarów danych: to znaczy, że nie tworzymy kopii zapasowej tylko jednej wspólnej bazy danych, robimy kopie konkretnego użytkownika. Co więcej, mechanizm jest taki, że kopie są wykonywane tylko wtedy, gdy są naprawdę potrzebne. Jeśli użytkownik nie wszedł do bazy przez tydzień, to nie robimy jego kopii, bo nic się tam nie zmieniło. Kolejną cechą Fresh jest to, że usługa implementuje mechanizm zmniejszający obciążenie serwera, co jest bardzo ważne, gdy masz dużo baz danych.

Generalnie Fresh to dla nas coś nowego i ciekawego. Stopniowo staramy się to rozgryźć, ale w większości jesteśmy po prostu zadowoleni z jego pracy.

Transfer danych. Jak wdrożyć go do wymiany między urządzeniami?

Platforma udostępnia dwa mechanizmy - usługi SOAP i http. Istnieją pewne niuanse, jak uzyskać dostęp do tych usług, gdy zaangażowany jest mechanizm udostępniania danych. W szczególności musisz dodać parametry, które wskazują konkretny numer obszaru, do którego uzyskujesz dostęp, ponieważ platforma nie może określić, do której bazy danych chcesz uzyskać dostęp po nazwie użytkownika. Dodatkowo jeden i ten sam użytkownik może pracować z kilkoma bazami danych w ramach jednej bazy danych (patrz rysunek).

Jeśli chodzi o usługi, aplikacja Boss realizuje natychmiastową wymianę: jeden użytkownik wprowadza dane, a drugi je otrzymuje. Użytkownicy aplikacji mobilnych są przyzwyczajeni do tego, że wszystko dzieje się błyskawicznie, dlatego pomyśleliśmy, z której usługi lepiej skorzystać - SOAP czy http. Kluczową rolę odegrała szybkość połączenia. W http prędkość połączenia jest znacznie wyższa, a łącząc się przez SOAP otrzymujemy opis usługi, która jest ciężka i długo się ładuje. Platforma ma możliwość przechowywania opisu usługi, ale ze względu na parametry, które dodajemy dynamicznie, nie możemy korzystać z referencji WS. Ponadto z naszego doświadczenia wynika, że ​​dostęp do usług http jest wygodniejszy i bardziej elastyczny.

Dlatego naszym celem jest wdrożenie wymiany w czasie rzeczywistym. Oznacza to, że staramy się nie zmuszać użytkownika do pójścia gdzieś, kliknięcia przycisku, zastanowienia się, jak istotne są jego dane, czy powinien je zaktualizować ... Dane powinny zawsze być istotne dla użytkowników. Są tak przyzwyczajeni do pracy w komunikatorach internetowych – jeden wysłał dane, drugi od razu je odebrał. Wszystko dzieje się natychmiast. To samo dotyczy wniosków związanych z biznesem: jeden sprzedawca wystawił sprzedaż, drugi musi natychmiast zobaczyć aktualną sytuację bez podejmowania jakichkolwiek działań.

Dlatego aplikacja Boss wykorzystuje zadania w tle do wymiany. Po zapisaniu wszystkich danych w bazie danych uruchamiane jest zadanie w tle, które inicjuje wymianę. Pierwsza część to przesłanie danych na serwer. Wtedy inne urządzenia muszą wiedzieć, że pojawiły się nowe dane. W tym celu używamy powiadomień PUSH. Ten schemat już działa i działa wystarczająco szybko.

Ale chcieliśmy jeszcze szybciej, ponieważ pracujemy w czasie rzeczywistym i zwykle mamy mało danych. Mamy mały XML, ale jednocześnie wysyłamy wiadomość z tymi danymi z pierwszego urządzenia na serwer, serwer wysyła PUSH do innego urządzenia, a następnie drugie urządzenie po otrzymaniu PUSH inicjuje wymianę ze swojej strony, adresuje serwer i żąda danych, odbiera te dane, a następnie wysyła odpowiedź, że dane zostały odebrane. To długo, ale same dane były bardzo małe.

Zastanawialiśmy się, jak można przyspieszyć ten proces.

Aby to zrobić, dowiedzieliśmy się, co zawiera PUSH, w jaki sposób można go nadal używać. Okazało się, że PUSH zawiera pola takie jak dane i tekst. Dokumentacja iOS i Android zawiera ograniczenia dotyczące rozmiaru wiadomości PUSH, ale wydawało nam się to niewystarczające i chcieliśmy to rozgryźć empirycznie. Sprawdziliśmy, że suma prawidłowych znaków to 981 znaków dla iOS i 3832 znaków dla Androida. W tym drugim przypadku jest całkiem możliwe zastosowanie ograniczenia: jeden lub kilka obiektów podstawowych można upchnąć w takiej objętości. A potem twórcy firmy nieco zmienili schemat. Gdy danych jest mało, wysyłamy je z jednego urządzenia, odbieramy na serwerze, pakujemy tam w PUSH i wysyłamy bezpośrednio do innego w nim urządzenia. Schemat stał się krótszy, a wymiana zaczęła następować jeszcze szybciej :)

Ważnym punktem korzystania z PUSH jest nie irytowanie użytkowników.

Bardzo łatwo jest pozbyć się tej sytuacji: po prostu nie wysyłaj wielu wiadomości PUSH do użytkownika :) Jeśli teraz pracuje w aplikacji, możesz wysłać dużo wiadomości. Gdy platforma jest uruchomiona, użytkownik nie widzi PUSH, wszystko dzieje się dla niego automatycznie. Ale kiedy aplikacja jest zamknięta, klient ma wiele nieprzeczytanych wiadomości. Dlatego w żadnym wypadku nie należy wysyłać kolejnego PUSH do momentu otrzymania odpowiedzi z urządzenia, że ​​aplikacja jest uruchomiona, aktywna, a poprzedni PUSH został już przetworzony.

Kolejnym niuansem wymiany jest praca przez Internet. Musimy jak najlepiej wykorzystać asynchronię. Nie możesz pracować jak zwykle - napisz kod - wywołaj funkcję - poczekaj na jej wykonanie - uzyskaj odpowiedź - i wszystko jest w porządku. Jeśli pracujesz w sieci, nadal będziesz mieć do czynienia z pewnymi ograniczeniami, na przykład niestabilnym Internetem, wyzwalanymi limitami czasu podczas wykonywania długich operacji. Dlatego konieczne jest wcześniejsze przemyślenie architektury.

Spójrzmy na przykład rejestracji urządzenia, co dzieje się w aplikacji, gdy użytkownik chce się zarejestrować. Przez jakiś czas prowadzi ewidencję, wprowadził dużo danych, ale potem chce, aby sprzedawca również pracował z tą bazą danych. Użytkownik klika przycisk „zarejestruj się”. Na początku wszystko było bardzo proste: wzięli jego dane, zapisali je na serwerze i proszę, możesz pracować i łączyć użytkowników. Ale potem natknęliśmy się na sytuację, w której dla niektórych użytkowników bazy danych na urządzeniu do czasu rejestracji już znacznie się rozrosły. I ten schemat już nie działał, ponieważ podczas gdy cała baza danych była zapisywana na serwerze, nastąpiło przekroczenie limitu czasu połączenia lub po prostu przerwano połączenie z Internetem. Dlatego zastąpiliśmy jedno wywołanie synchroniczne wieloma krótkimi. Teraz dane są udostępniane, a nie przesyłane w całości naraz. W żaden sposób nie czekamy, aż serwer przetworzy i zarejestruje dane. Wysłaliśmy dane, otrzymaliśmy odpowiedź, że dane zostały odebrane, zamknęliśmy połączenie. Okresowo trzeba odpytywać serwer, co się tam dzieje i jak, aw międzyczasie na serwerze działa zadanie w tle, które rejestruje otrzymane dane. W ten sposób otrzymujemy dużo połączeń serwerowych, ale mamy gwarancję, że wszystko pójdzie dobrze. Ani limity czasu, ani niestabilność Internetu nie przeszkodzą w załadowaniu wszystkich danych na serwer.

AKTUALIZACJE

Wymiana między urządzeniami z różnymi wersjami aplikacji

Ponieważ mówimy o masowej aplikacji, która jest wypuszczana na rynki, musimy wziąć pod uwagę niektóre cechy procesu aktualizacji i wymiany danych.

Jeśli wydałeś aplikację dla jednego przedsiębiorstwa i zdecydowałeś się ją zaktualizować, to zazwyczaj po prostu wydajesz polecenie, aby wszyscy pracownicy wspólnie instalowali nową aplikację. Nie można tego zrobić w przypadku użytkowników, którzy pobrali aplikację z rynku. W ogóle nie możesz im powiedzieć, co mają robić. Na przykład pracują w aplikacji i nie chcą jej aktualizować ani teraz, ani kiedykolwiek. Nie posiadają automatycznej aktualizacji, więc jest to dość powszechna sytuacja, gdy do centralnej bazy podłączonych jest kilka urządzeń i wszystkie są w różnych wersjach. Inną przyczyną tego zjawiska jest czas publikacji na rynkach: jest inny dla iOS i Androida. Często wdrażamy kluczowe rzeczy, na przykład naprawiamy krytyczne błędy, a nie chcemy czekać, aż iOS sprawdzi nową wersję przez dwa tygodnie, chcemy przynajmniej tylko dla Androida, ale aktualizację już teraz.

Nie mamy prawa rozkazywać użytkownikom. Jeśli chcą, są aktualizowane, a jeśli nie, to nic nie robią. Zdjęcie przedstawia stosunek instalacji aplikacji Boss do wersji w GooglePlay, a także statystyki z naszego serwera - rzeczywisty stosunek wersji aplikacji, które są instalowane na urządzeniach, które w ciągu ostatniego tygodnia wymieniały dane z serwerem. Oto zestaw do pracy. To są różne wersje i różne metadane. A w tym samym czasie musimy zorganizować normalną wymianę :)

Deweloperzy stają przed następującymi zadaniami:

  • Wszystko to musi działać. Użytkownicy nie powinni odczuwać dyskomfortu, że zapomnieli zaktualizować. W ogóle nie powinni tego zauważać. Zaktualizowano - jest lepiej, dobrze i dobrze.
  • Musimy zapewnić bezpieczeństwo danych. Na przykład jeden użytkownik ma katalog i nowe właściwości, a inny jeszcze nie. Co więcej, jeśli użytkownik, który nie ma nowych danych, zmieni coś na swoim urządzeniu, dane na innych urządzeniach nie powinny zostać utracone.
  • Musimy upewnić się, że dane są aktualizowane podczas aktualizacji do nowej wersji. Gdy użytkownik zdecyduje, że jest gotowy do aktualizacji, powinien automatycznie mieć wszystkie nowe informacje, których nie miał tylko dlatego, że miał starą wersję.

Jak to zrobiliśmy?

1. Na serwerze korzystamy z 2 planów wymiany. Pierwszy służy do udostępniania między urządzeniami, a drugi do aktualizacji. Na przykład wysłaliśmy instrukcję do użytkownika, ale nie ma on jednostek miary, czyli niekompletnych danych. Musimy o tym pamiętać. A kiedy zostanie zaktualizowany, musimy przesłać mu wszystkie informacje, których nie miał. Po to jest drugi plan wymiany.

2. Do zapisu i odczytu obiektów wykorzystujemy ten sam mechanizm, który jest używany przy kopiach zapasowych, czyli zapisujemy wersję metadanych. W tym przypadku pracujemy z serwerem i możemy sobie pozwolić na dodanie wszystkiego, co chcemy bezpośrednio do konfiguracji, więc po prostu dodajemy schematy metadanych do konfiguracji w postaci układów w miarę rozwoju aplikacji.

Jak monitorować ogromne błędy podczas wymiany i na serwerze?

Najpierw musisz kontrolować dostępność samego serwera. Dzieje się tak z serwerami - upadają. Nie wymyśliliśmy nic specjalnego do monitorowania, po prostu znaleźliśmy w telegramie bota, który krzyczy, jeśli coś jest nie tak. Co minutę sprawdza wydajność serwera, a jeśli serwer jest nagle niedostępny, zaczyna krzyczeć, admini to widzą i podnoszą serwer.

Z dziennika zbieramy również dziennik błędów. Również nic nadprzyrodzonego - po prostu zbieramy dziennik błędów co trzy godziny, wysyłamy je na pocztę i okresowo je przeglądamy. Pomaga to dostrzec typowe problemy i wyjątkowe sytuacje. Nie jest trudno czytać pocztę, śledzić i szybko naprawiać błędy. Pozwala to jednak szybko identyfikować i rozwiązywać problemy, które mogą narastać wraz ze wzrostem bazy danych.

Kolejny ważny punkt - pamiętaj, aby dać użytkownikowi możliwość „złożenia skargi”. Poprawia nasz status w ich oczach i nas ratuje. Są użytkownicy, jak ich nazywamy „histerycy”, którzy przy najmniejszym błędzie zaczynają wysyłać nam garść wiadomości pocztą, że nic nie działa, baza danych się nie ładuje, wszystko jest strasznie złe. Ale czasami naprawdę nas ratują, bo czasami znajdują takie błędy, których inni cudem nie znaleźli, poważne błędy.

Użytkownik nie może się bać. Nie przerażające wiadomości, nic więcej. Muszą wszystko pięknie wyjaśnić i złożyć skargę. I obiecujemy rozwiązać wszystko. Wtedy użytkownicy są zadowoleni, bo widzą, że są pod opieką i od razu wierzą, że otrzymają pomoc :)

Artykuł powstał na podstawie wyników raportu odczytanego na konferencji INFOSTART EVENT 2016 DEVELOPER. Więcej artykułów można przeczytać.

W 2020 roku zapraszamy wszystkich do wzięcia udziału w 7 spotkaniach regionalnych, a także jubileuszowym INFOSTART EVENT 2020 w Moskwie.