2011-07-08 19 views
5

Zajmuję się tworzeniem serwera proxy w Oszczędzanie. Mój problem polega na tym, że każde połączenie przychodzące do proxy używa tego samego wystąpienia Handler'a. Implementacja klienta proxy znajduje się w module obsługi, więc wszyscy klienci komunikują się przez to samo połączenie z serwerem końcowym.Thrift - różne egzemplarze Handler dla każdego gniazda

Mam: n klientów -> n gniazd -> 1 obsługi -> 1 gniazdo -> 1 serwer Co chcę zaimplementować: n klientów -> n gniazd -> n obsługi -> n gniazd -> 1 serwer

Problem polega na tym, że jeśli klient zmienia "lokalny" parametr (coś, co jest zdefiniowane dla każdego klienta niezależnie) na serwerze, inni klienci będą również pracować ze zmienionym środowiskiem.

shared_ptr<CassProxyHandler> handler(new CassProxyHandler(adr_s,port_s,keyspace)); 
shared_ptr<TProcessor> processor(new CassandraProcessor(handler)); 
shared_ptr<TServerTransport> serverTransport(new TServerSocket(port)); 
shared_ptr<TTransportFactory> transportFactory(new TFramedTransportFactory()); 
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory()); 
TThreadedServer server(processor, serverTransport, transportFactory, protocolFactory); 
server.serve(); 

Czy istnieje sposób, aby wdrożyć serwer, który tworzy nową instancję Handler dla każdego gniazda serwera zamiast przy użyciu tej samej procedury obsługi?

Dzięki za wszelkie sugestie i pomoc, @

Odpowiedz

4

Udało mi się rozwiązać ten problem. W Javie zostało już wdrożone rozwiązanie. Użyłem tego samego pomysłu i zaimplementowałem go w C++.

Najpierw stworzyłem TProcessorFactory zamiast klasy TTransport. To obsługuje TProcessory dla każdego połączenia. Ma strukturę mapy, więc jego funkcja get zwraca odpowiedni procesor dla każdego TTransportu. Odpowiedni (unikalny) TProcessor dla każdego klienta.

Musiałem stworzyć nowy TServer, aby mógł zaakceptować nowo utworzony parametr TProcessorFactory zamiast TProcessor. W TServer jest również konieczna zmiana wywołań funkcji para. Twoja funkcja getProcessor nie zwróci już TProcessora, ale TProcessorFactory (więc zmień typ i nazwę zmiany).

Ostatnią rzeczą, którą musisz zrobić, to zaimplementować serwer, który pozwala na utworzenie instancji klasy pochodnej TServer. Proponuję użyć TNonblockingServer (nieco trudniej zaimplementować zmianę) lub TThreadPoolServer. Musisz zmienić kilka połączeń funkcji. Użyj funkcji get na TProcessorFactory z parametrem TTransport, aby uzyskać wymagany procesor. Parametr TTransport jest unikalny dla każdego wątku, każde połączenie klienta jest obsługiwane przez jeden wątek.

Upewnij się również, że zostały usunięte stare procesory, ponieważ oszczędzanie wykorzystuje (przynajmniej z serwerem TNonblockingServer) TTransport, więc jeśli ich nie usuniesz, a klient się połączy, prawdopodobnie uzyska nieaktywną poprzednią sesję i prawdopodobnie nie nie chcę tego. Jeśli korzystasz ze współdzielonych wskaźników, po prostu usuń je ze struktury mapy, gdy klient się rozłączy, a jeśli nie będą już potrzebne dzięki oszczędności, zostaną one zniszczone.

Mam nadzieję, że pomoże to każdemu, kto napotka na ten sam problem co ja. Jeśli nie znasz wewnętrznej struktury oszczędzania, oto dobry przewodnik: http://diwakergupta.github.com/thrift-missing-guide/

Mam nadzieję, że twórcy Thrift zamierzają wdrożyć coś podobnego, ale bardziej wyrafinowane i abstrakcyjne rozwiązanie w najbliższej przyszłości.

@

+0

Czy kiedykolwiek umieszczałeś prośbę o bilet/wydanie/funkcję @ apache? Myślę, że można to również wykorzystać, aby bardzo łatwo umożliwić komunikację full-duplex/dwukierunkową. – BatteryBackupUnit

0

Zamiast swój serwer proxy rozmów zapobiegliwości, można po prostu zrobić to generic proxy TCP, który otwiera nowe połączenie TCP dla każdego połączenia przychodzącego.

+0

Myślałem o tym, jednak potrzebuję rozpakować pakiety, więc mogę przesłać pakiet na właściwy serwer w oparciu o zawarte w nim informacje. Wykonanie go bez oszczędzania byłoby ogromną pracą. –

1

Wiem, że to stary wątek, ale w przypadku jest to zawsze przydatne dla każdego, kto - ja przyczyniły się zmiany do implementacji C# z Thrift, aby rozwiązać ten problem ...

https://issues.apache.org/jira/browse/THRIFT-3397

Oprócz starej metody przechodzącą TProcessor jako pierwszy argument do serwerów gwintowanych, można teraz skonfigurować coś podobnego

new ThreadPoolServer(processorFactory,serverTransport, 
            transportFactory,protocolFactory); 

Gdzie "processorFactory" jest produktem TProcessorFactory.

Utworzyłem TPrototypeProcessorFactory < TProcessor, Handler > (Object [] handlerArgs), które byłyby powołane tak:

TProcessorFactory processorFactory = 
     new TPrototypeProcessorFactory<ThriftGenerated.Processor, MyHandlerClass>(); 

do 'MyHandlerClass' realizuje swoją ThriftGenerated.Iface. Opcjonalnie, jeśli ta klasa pobiera argumenty, można je dodać jako tablicę obiektów do fabryki procesorów. Wewnętrznie - Dla każdego nowego połączenia klienta, to fabryka procesor:

  1. Utwórz nową instancję „MyHandlerClass” używając argumentów dostarczany (przy użyciu Activator.CreateInstance)

  2. Jeśli narzędzi „MyHandlerClass” „TControllingHandler” będzie ustawić jej 'serwera właściwość rodzica TServer (np aby umożliwić kontrolę the TServer użyciu thift klient)

  3. Return nowa instancja Thrif tGenerated.Processor (handler)

Dlatego dla C# można uzyskać brak klientów -> N gniazd -> n teleskopowe -> N gniazd -> 1 serwer

Mam nadzieję, że stanie się to użyteczne dla innych ludzi - z pewnością rozwiązał problem dla mnie.

Powiązane problemy