Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Aplikacja typu saas - architektura
Forum PHP.pl > Forum > PHP
tczajka
Witam wszystkich.
Zaczynam pracę nad projektowaniem i pisaniem pewnej aplikacji w modelu saas gdzie przewiduję takie mniej więcej elementy:
- panel admin najwyższego rzędu gdzie będą zakładane/generowane konta klientów w skład których będa wchodzić poniższe części:
- panel admin (klienta) dla zarządzania bazą użytkowników, przydzielaniem usług, definiowaniem usług itp (wszystko w ramach jednego klienta)
- panel usera do zarządzania i do-konfigurowania przez usera założonego na poziomie wyżej
- strona usera do prezentacji treści usera (np konkretnych usług oferowanych przez usera-klienta)
Przykładem może tu być aplikacja do zarządzania hurtowniami gdzie zakładamy konta np dla Hurtowni 1, Hurtowni 2 itpp. W nich tworzeni są konta dla pracowników do zarządzania ofertą itp.

Zastanawiam się tutaj nad 3 możliwościami:
1. Tworzyć wszystko na jednym adresie, jednej bazie danych (jeden handler dla wszystkich kont) i ograniczać dostęp do poszczególnych danych odpowiednio implementując system autoryzacji itp
2. Tworzyć wszystko na jednym adresie , ale każdy klient będzie na osobnej bazie danych separując tym samym dane jednego klienta od drugiego (istotne w razie włamu)
3. Tworzyć osobną aplikację do admina adminów np na innym adresie (gdzie będą zakładani Ci duzi klienci, np hurtownie), oraz osobną dla klientów (tutaj to samo jak wyżej albo na jednej bazie wszyscy klienci albo każdy na osobnej)

Podział na osobne bazy danych rodzi tylko więcej roboty z zakładaniem kont (jakiś manager handlerów do DB). Z założenia nie będzie tam dziur ale moje rozważania wynikają głównie z obawy że podczas włamu atakujący dostanie dostęp do wszystkich klientów, podczas gdy gdyby każdy klient był na osobnej bazie szkody mogą zostać ograniczone.

Co o tym sądzicie? Które rozwiązanie wg Was jest lepsze i dlaczego lub dlaczego nie? Inne rozwiązanie?
pozdrawiam

Crozin
1. Każda aplikacja w obrębie Twojej platformy powinna działać na osobnej bazie danych.
1.1. Pomyśl tylko co by było w przypadku gdyby klient A chciał korzystać z wersji 1.0.0, a klient B 1.1.0. Utrzymywanie aplikacji polegających na innych schematach bazy danych (zakładamy, że pomiędzy wersjami coś się pozmieniało) byłoby koszmarem.
1.2. Łatwość zarządzania. Utworzenie nowej bazy danych to na dobrą sprawę dwa polecenia SQL. Jedno tworzące bazę danych i drugie tworzące jej całą strukturę wraz z wymaganymi danymi początkowymi wykonywane z poziomu odpowiednio przygotowanego wcześniej pliku (LOAD FILE). Dzięki temu operacje na bazie z poziomu samej aplikacji nie muszą uwzględniać występowania innych serwisów w tej samej bazie co musiałbyś robić przy absolutnie każdym zapytaniu, podzapytaniu czy innych procedurach i wyzwalaczach - kolejny koszmar.
1.3. Bezpieczeństwo. Łatwo możesz utworzyć dla takiej bazy danych użytkowników z odpowiednimi uprawnieniami, a w przypadku ataku na daną aplikację i wycieku jej bazy danych dane innych klientów prawdopodobnie zostaną nietknięte.
2. Aplikacja obsługująca całą platformę powinna działać jako kompletnie osobny projekt - w końcu będzie ona zajmować się zupełnie innymi sprawami i operować na innych danych.
3. Od samego początku powinieneś pomyśleć nad skalowalnością Twojej platformy. Jeżeli nie masz środków/możliwości skorzystania z własnej infrastruktury w tym celu pomyśl nad wykorzystaniem popularnych ostatnim czasy chmur.
tczajka
hej
dzięki za Twoją opinię w temacie,

Ad.1.1 Sugerujesz że dobrze by było dla każdego klienta stawianie osobnej instancji całej aplikacji? Jedna instancja nazwijmy to fizyczna (pliki) znacznie ułatwia proces aktualizacji, bo wdrożenie nowej funkcjonalności, poprawek itp automatycznie załatwi sprawę wszystkich klientów. Z kolei z punktu widzenia bezpieczeństwa już najlepiej byłoby chyba odpalanie każdej instancji na osobnym użytkowniku systemowym (terminalowym na którym działa wirtualka) ale wtedy każdy klient musiałby być odpalany na osobnej subdomenie, na osobnej wirtualce. Co o tym sądzisz?
Ad.1.2 Racja
Ad.1.3 Racja
Ad.2 Ok, przemawia to do mnie.
Ad.3 Nie ma z tym jakiegoś większego ponieważ mam dostęp do dość rozbudowanej infrastruktury serwerowej gdzie wstawienie osobnego klocka pod aplikację nie stanowi jakiegoś większego problemu
pozdrawiam
Crozin
Nie napisałem, że każdy klient musiałby korzystać z kompletnie oddzielnej instalacji aplikacji. Pisałem jedynie o bazie danych. Niemniej jednak dobrym rozwiązaniem jest utworzenie indywidualnej instalacji dla każdego klienta, która będzie wykorzystywała współdzielony przez wszystkich klientów kod aplikacji. Innymi słowy w takiej instalacji znajdzie się:
1. Jakiś tam prosty skrypt, który przekaże żądanie HTTP do już właściwego kodu (współdzielonego).
2. Jakieś pliki konfiguracyjne, logi, backupy, szablony, cache - innymi słowy, to co jest indywidualne dla danej aplikacji.
3. W sumie można tam umieścić też wszelkie wgrywane pliki (jeżeli zdecydujesz się na ich przechowywanie na tej samej maszynie co same aplikacje)
nrm
Każdy klient na osobnej bazie?!? WTF? Co to za abstrakcja? Ile chcesz mieć tych baz? 10 tysięcy, 100. tys., milion? wink.gif Narobiłem się w życiu różnych SaaSów, kolejne w produkcji ale na szczęście nikomu z kim pracowałem nie przyszedł pomysł na setki tysięcy osobnych baz wink.gif
tczajka
ok, dzięki za sugestie
pozdrawiam

Cytat(nrm @ 24.07.2013, 11:28:57 ) *
Każdy klient na osobnej bazie?!? WTF? Co to za abstrakcja? Ile chcesz mieć tych baz? 10 tysięcy, 100. tys., milion? wink.gif Narobiłem się w życiu różnych SaaSów, kolejne w produkcji ale na szczęście nikomu z kim pracowałem nie przyszedł pomysł na setki tysięcy osobnych baz wink.gif

A gdzie napisałem że tych klientów będzie nawet 10tyś? Charakter aplikacji i grupa docelowa zakłada że takich instancji powstać może maksymalnie kilkadziesiąt może kilkaset (życzyłbym sobie tego by było więcej). Klienta utożsamiam z taką wirtualną aplikacją, coś jak są tworzone wirtualne sklepy itp. Generalnie chodzi o to że można by instalować za każdym razem dla każdego klienta aplikację na osobnym serwerze u klienta, osobnej domenie, ale wolałbym mieć to scentralizowane - łatwość zarządzania, update'y, aktualizacja samego bazowego systemu (a nie że ktoś sobie zażyczy instalacje na serwerze nieaktualizowanym itp) - a także dlatego by jednak do kodu źródłowego był ograniczony dostęp przed potencjalnymi "szperaczami" lub co gorsza "konkurencją".
Crozin
@nrm, @tczajka: Jeżeli chodzi o decyzję "baza danych per użytkownik" VS "wspólna baza danych": https://www.google.com/search?q=saas+single...me&ie=UTF-8 Oba rozwiązania mają swoje plusy i minusy. W mojej ocenie wady związane z indywidualną bazą dla każdego użytkownika są zdecydowanie mniejsze niż w przypadku jednej wielkiej bazy danych.

@nrm: Sam również "narobiłem się tych SaaSów", jednak zawsze grupą docelową było kilka do kilkudziesięciu aplikacji. Mógłbyś przedstawić minus tego rozwiązania? Domyślam się, że mogą tutaj pojawić się argumenty mówiące o konieczności wdrażania zmian w każdej z baz danych osobno, trudności ze zbieraniem danych dotyczących wielu aplikacji równocześnie czy wypięcie się na starą dobrą regułę DRY. Jednak te problemy dosyć łatwo można zautomatyzować.
nrm
Przede wszystkim to masz racje w jednym: każda aplikacja = indywidualne podejście; trudno pisać, że jest jedne rozwiązanie dla wszystkich. Fakt. Nie mniej nie spotkałem się jeszcze z projektem aplikacji, który by wymagał takich dziwnych rozwiązań (co oczywiście, że nie znaczy, że takich nie ma).

Po drugie, zacząłbym najpierw od stwierdzenia PO CO a dopiero potem kombinował JAK. Odnośnie PO CO padł tutaj tylko jeden argument - bezpieczeństwa - który dla mnie akurat jest złudny. Jeżeli przejrzysz historię jakiś ostatnich popularnych "włamów" to zobaczysz, że na ogół kończyło się to całym dostępem roota tudzież całym wejściem na bazę, w takich sytuacjach bez znaczenia ile tych baz masz z osobna.

Po trzecie, nie wyobrażam sobie zarządzania taką aplikacją, która ma setki tysięcy osobnych baz wink.gif Poczynając od kwestii deweloperki, a kończąc na kopiach bezpieczeństwa. Czy się da? pewnie, wszystko się da wink.gif Ale czy jest sens? Oto jest pytanie wink.gif (pewnie by się znalazł taki projekt, który by mógł tego wymagać - patrz pierwszy punkt)

Autor wątku pisze "instalować za każdym razem dla każdego klienta aplikację na osobnym serwerze u klienta" - no to już SaaS NIE jest (oprogramowanie JAKO USŁUGA) i w takim wypadku faktycznie trzeba szukać innych rozwiązań ale to trzeba się zdecydować na jakiś rodzaj architektury zanim zacznie się debatować jak to wykonać wink.gif

pzdr
tczajka
Cytat(nrm @ 24.07.2013, 12:13:23 ) *
Autor wątku pisze "instalować za każdym razem dla każdego klienta aplikację na osobnym serwerze u klienta" - no to już SaaS NIE jest (oprogramowanie JAKO USŁUGA) i w takim wypadku faktycznie trzeba szukać innych rozwiązań ale to trzeba się zdecydować na jakiś rodzaj architektury zanim zacznie się debatować jak to wykonać wink.gif

@nrm Dzięki za włączenie się do tematu.
Napisałem o takim rozwiązaniu jako ew. możliwości (tak wiem że to już nie SaaS). Głównym tematem który mnie interesuje to czy dzielić na bazy czy nie, jakie to może przynieść korzyści lub problemy. Myślisz że te wszystkie systemu np wirtualnych sklepów internetowych są maksymalnie scentralizowane i wszystko chodzi na jednej bazie? Bo chodzi to własnie o tego typu aplikację pod względem struktury.
nrm
Nie znam architektury wszystkich możliwych SaaSów więc nie wiem, mogę tylko powiedzieć, że te z którymi miałem styczność od strony zaplecza nie miały baz w schemacie "baza per klient". Owszem, czasami były robione różne inne kombinacje aby poradzić sobie ze skalowalnością - jak np. "sharding" (Allegro "sharduje" dane, wyobrażasz sobie tam jedna baza per klient? wink.gif ), widziałem też kombinacje typu rozdzielenie tabel na kilka baz tzn. potworzenie baz, które miały tylko jedną (lub kilka) tabel - ale cały czas nie było to nic związanego z powielaniem struktury "baza per klient".
Crozin
Tak tylko dla upewnienia się, że rozmawiamy o tym samym. Rozważamy dwa podejścia:
  1. Proponowane przez @nrm, jedna baza danych dla wszystkich aplikacji w obrębie platformy.
    Takie podejście wiązało by się z koniecznością dodania w niemal każdej tabeli, kolumny pozwalającej na ustalenie, której aplikacji dotyczy dany wpis. Kolumna ta musiałaby być również ujęta w niemal każdym zapytaniu SQL.
    1. CREATE TABLE users (
    2. id ...,
    3. username ...,
    4. ...,
    5. application ...
    6. ) ... ;
    1. SELECT ... FROM users WHERE ... AND application = 'aplikacja #1';
    Napisałem, że w niemal każdym, ponieważ są przypadki gdzie przykładowo dane z tabeli z preferencjami użytkownika będą wybierane wyłącznie w połączeniu (JOIN) z tabelą samych użytkowników, a w tym przypadku wystarczy nam kolumna rozróżniająca jedynie w drugiej tabeli.
  2. Proponowane przeze mnie, osobna baza danych dla każdej aplikacji w platformie. Tutaj chyba nie trzeba niczego przedstawiać.


Cytat
Odnośnie PO CO padł tutaj tylko jeden argument - bezpieczeństwa - który dla mnie akurat jest złudny. Jeżeli przejrzysz historię jakiś ostatnich popularnych "włamów" to zobaczysz, że na ogół kończyło się to całym dostępem roota tudzież całym wejściem na bazę, w takich sytuacjach bez znaczenia ile tych baz masz z osobna.
Oczywiście, w przypadku gdy włamywacz uzyskuje dostęp do roota, uprawnienia poszczególnych użytkowników nie mają już znaczenia. Jednak zdarzają się sytuacje, gdzie włamywacz uzyskuje dostęp jedynie do lokalnego użytkownika (nie wiem, które z nich są częstsze), a tutaj taka forma zabezpieczenia jest już bez wątpienia przydatna. Nie nazwałbym tego zabezpieczenia złudnym. Co najwyżej powiedziałbym, że chroni w określonych przypadkach i raczej nigdy nie szkodzi.
Cytat
Po trzecie, nie wyobrażam sobie zarządzania taką aplikacją, która ma setki tysięcy osobnych baz
Jak rozumiem, chodziło Ci o zarządzanie całą platformą (która posiada wiele aplikacji i wiele baz), nie pojedynczą aplikacją (która posiada jedną bazę), tak? Tutaj właściwie jedyny problem jaki widzę to zbieranie informacji z wielu aplikacji na raz, przykładowo "łączna ilość użytkowników we wszystkich aplikacjach", albo "najczęściej używana domena w adresach email we wszystkich aplikacjach" - czyli głównie dane statystyczne. Tutaj jedna baza danych dla wszystkich faktycznie ułatwia życie (zwykłe, pojedyncze zapytanie ignorujące kolumnę application, bez żadnego dodatkowego przetwarzania danych). W przypadku wielu baz danych musielibyśmy osobno pobrać dane z każdej z baz i dopiero na końcu - mając już wszystkie dane - jeszcze raz je przetworzyć w celu uzyskania finalnych wyników. Jest też drugie rozwiązanie jakie na szybko przychodzi mi do głowy, tj. każda z aplikacji samodzielnie publikuje te dane, po czym aplikacja od zarządzania całą platformą sczytuje jedynie te dane.
Cytat
Poczynając od kwestii deweloperki, a kończąc na kopiach bezpieczeństwa.
Jeżeli chodzi o deweloperkę to szczerze nie rozumiem w czym problem. Niezależnie od tego, które rozwiązanie wybierzemy będziemy potrzebowali osobnej kopii bazy danych z przykładowymi danymi (w przypadku rozwiązania #1) bądź kilku w przypadku punktu (chociaż w przypadku rozwiązania #2 i tak większość czasu będziemy pracowali wyłącznie z jedną bazą). Tutaj zapewne chodziło Ci o problem przy wprowadzaniu zmian w strukturze bazy danych. Powiedzmy, że chcemy dodać dodatkową kolumnę do jakiejś tabeli. W przypadku pierwszego rozwiązania odpalamy po prostu w konsoli bazy danych ALTER TABLE ..., w przypadku drugiego wpisujemy to do jakiegoś pliku i odpalamy bardzo prosty skrypt synchronizujący to pomiędzy wszystkimi deweloperskimi bazami - na prawdę nie jest to zbyt duży nakład pracy, a przy okazji mamy rozwiązany problem wersjonowania bazy danych. wink.gif Jeżeli chodzi o kopie bezpieczeństwa również nie wiem gdzie może leżeć problem.

Teraz chciałbym jeszcze przedstawić na szybko kilka wad i zalet każdego rozwiązania.

  • Rozwiązanie #1 - jedna baza danych.
    • Zalety:
      1. łatwiejsze operowanie na danych dot. wielu aplikacji
      2. jedna baza danych to jeden problem na głowie, nie trzeba przygotowywać skryptów do instalacji nowych; nadal trzeba przygotować takowe dla instalacji samej aplikacji - więc nie jest to jakiś wielki postęp,
      3. ?
  • Wady:
    1. brak możliwości ustawienia indywidualnych "ficzerów" dla konkretnej aplikacji - przykładowo klient A chciałby za dopłatą korzystać z bardziej stabilnej bazy danych, która ma włączoną replikację na wiele serwerów, podczas gdy klientowi B nie zależy na czymś takim; innym przykładem może być konieczność dodania jakiejś procedury/wyzwalacza, która pracuje na tabelach dostępnych dla wszystkich klientów oraz tabelach dostępnych tylko dla niektórych użytkowników, którzy wykupili jakąś usługę dodatkową - w takim przypadku trzeba albo się solidnie nagimnastykować przy implementacji tego, albo wykonywać to dla wszystkich, a użytkownikom bez dodatkowej usługi po prostu nie wyświetlać pewnych danych/informacji - to może nieść za sobą duże koszty,
    2. wszystkie aplikacje muszą muszą korzystać z dokładnie tej samej struktury bazy danych,
    3. trzeba w bardzo wielu miejscach uwzględniać tą nieszczęsną kolumnę rozróżniającą aplikacje,
    4. konieczność wyłączenia wszystkich aplikacji w platformie w przypadku jakichkolwiek modyfikacji bazy danych, a to potrafi przy dużych bazach danych trwać naprawdę długo - ogromny minus
  • Rozwiązanie #2 - wiele baz danych., to właściwie to odwrotność powyższej listy.
    • Zalety:
      1. możliwość nieograniczonego "customizowania" poszczególnych baz danych - jednak trzeba tutaj pamiętać o zachowaniu rozsądku, inaczej może się to przerodzić w wadę
      2. możliwość modyfikowania kolejnych baz danych bez konieczności wyłączania całej platformy
      3. nieco zwiększone bezpieczeństwo
      4. łatwiejsza praca na poziomie aplikacji (klienta)
      5. bezproblemowa możliwość wykorzystaniu wielu maszyn do obsługi baz danych w obrębie platformy
  • Wady:
    1. konieczność przygotowania pewnych narzędzi pozwalających nanieść zmiany na wszystkie bazy danych
    2. trudniejsza praca na poziomie aplikacji do obsługi platformy
    3. przy ilości baz danych liczonych w dziesiątkach tysięcy zapewne pojawią się problemy przy zarządzaniu tym, ale myślę, że mniejsze niż w przypadku jednej gigantycznej bazie, której rozmiar liczony byłby w setkach GiB czy nawet TiB


  • Wygląda na to, że autor jednak nie będzie miał do czynienia z SaaS, nie mniej jednak chciałbym pociągnąć ten wątek. wink.gif
    nrm
    Cytat(Crozin @ 24.07.2013, 11:23:38 ) *
    Tak tylko dla upewnienia się, że rozmawiamy o tym samym. Rozważamy dwa podejścia:[list=1]
    [*]Proponowane przez @nrm, jedna baza danych dla wszystkich aplikacji w obrębie platformy.
    Takie podejście wiązało by się z koniecznością dodania w niemal każdej tabeli, kolumny pozwalającej na ustalenie, której aplikacji dotyczy dany wpis.

    Nie wiem czy o tym samym bo nie rozumiem czym dla Ciebie są "osobne aplikacje", przeczytałem jeszcze raz wpis autora i nie znalazłem informacji, że to zbiór jakiś niezależnych od siebie aplikacji. Tak samo nie mogę się odnieść do wad #1 bo zupełnie nie rozumiem kwestii "osobnych aplikacji". Ja w tym nie widzę żadnego problemu, możliwe, że mamy inną definicje czym jest taka aplikacja i stąd problemy interpretacyjne.

    Co do problemu autora: to faktycznie, jeżeli chce stworzyć taką hybrydę, że jest to SaaS i w prosty sposób przenoszony na osobny serwer klienta, a w dodatku z niewielką liczbą klientów to może rozważyć "baza per klient" jeżeli tylko ułatwi mu to zarządzanie tym wszystkim w niewielkiej skali.
    Crozin
    Już tłumaczę: przez osobną aplikację mam tutaj na myśli, konkretne kopie usługi w obrębie platformy. Przykładowo, zarejestrowanych masz dwóch klientów, Klient A oraz Klient B, a każdy z nich ma wykupioną jedną lub więcej usług systemu CRM. firma-1.klient-a.pl, firma-2.klient-a.pl, firma-1.klient-b.pl. Każda z tych trzech usług/stron/systemów CRM korzysta z tego samego kodu źródłowego, lecz każda z nich działa jako kompletnie niezależna usługa/aplikacja. Cała dyskusja dotyczy tego, czy każda z tych trzech stron powinna korzystać z własnej bazy danych czy wspólnej.
    tczajka
    Analizując powyższe przypadki aplikacji byłoby maksymalnie 2. Tj. główna do zarządzania/tworzenia tych głównych kont/instancji wirtualnych/aplikacji wirtualnych sprzedawanych klientom "dużym" (tak jak zaproponował @Crozin) oraz właściwa na której pracują już klienci.

    Kolejnym przykładem tej aplikacji jest system do zarządzania klientami u operatora internetowego. Klienci (wirtualne instancje) to operatorzy którzy mają w ramach swojego dostępu możliwość zarządzania użytkownikami, usługami czy fakturami a także np swoją stroną www (ostatni element z wymienionych w moim pierwszym poście). Klienci nie mogą widzieć nic spoza danych dodanych przez nich samych (czyli nie widzą i nie mogą mieć dostępu do żadnych danych innego klienta). Dostęp do tej nadrzędnej aplikacji miałby tylko właściciel całego projektu, usługodawca, a do tej drugiej poszczególni klienci. Każdy klient może założyć dowolną ilość kont w ramach swojej usługi dla swoich pracowników obsługujących system. Czyli chodzi mi o aplikację typu SaaS bo nie chcę kopiować plików aplikacji osobno do każdego klienta tylko świadczyć im takie aplikacje w chmurze. Innym przykładem tego typu są wszystkie te internetowe systemy do prowadzenia firmy (iFirmy, iFaktury itp...)
    pozdr

    @Crozin: dokładnie to o co mi chodzi smile.gif
    nrm
    Kumam. I podtrzymuje swoja opinię: gdybym ja to robił i miał podobne wymagania j.w. opisane to prawdopodobnie nie łądowałbym się w osobne bazy per klient. Także nie zgadzam się z punktami wad:
    1. - nie widzę żadnego problemu w posiadaniu "rożnych ficzerów per klient",
    2 - nie do końca rozumiem,
    3 - nie trzeba żadnych kolumn, wystarczy w konfigu mieć zapisane do czego dany klient ma dostęp, to tak jakby twierdzić, że trzeba miec osobne bazy dla klientów z abonamentem1, abo 2 czy abo 3 wink.gif
    4 - taka wada trochę na siłę wszak róznego rodzaju "przerwy techniczne" są nieuniknione bez względu na rozwiązania bazowe i dotyczą wszelkich mozliwych warstw (od serwerowych po aplikacyjne).

    To wszystko co teraz wymienił @tczajka to jest dla mnie jeden projekt, jedna aplikacja, dla mnie nie ma znaczenia, że ona ma częśc do zarządzania głównymi klientami, a ci z kolei jako klienci zarządzają swoim kurnikiem. Obojętne mi to wink.gif To jakby podzielić Wordpressa MU (tego wieloinstancyjnego) na kilka części ze względu na zastosowanie wink.gif

    ----

    Podam wam przykład jednego SaaSa, który generuje nam kosmiczne ilości danych. Klient w nim może mieć podużytkowników z dostępem (ustawia jak daleko idącym), aplikacja zbiera pewne dane, w ogromnych ilościach. Są one rozdzielone na kilka baz z kluczem "pewien typ danych - osobna baza". Każdy klient ma do wyboru co zbiera więc można powiedzieć, że nie wiemy ile i jakie komponenty wybierze - wybiera co mu pasuje. Stąd jedne bazy zapełniają się szybciej, inne wolniej - w zależności od popularności danego komponentu.
    To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
    Invision Power Board © 2001-2025 Invision Power Services, Inc.