<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>tracing &#8211; Solr.pl</title>
	<atom:link href="https://solr.pl/tag/tracing/feed/" rel="self" type="application/rss+xml" />
	<link>https://solr.pl</link>
	<description>All things to be found - Blog related to Apache Solr &#38; Lucene projects - https://solr.apache.org</description>
	<lastBuildDate>Sat, 14 Nov 2020 12:25:45 +0000</lastBuildDate>
	<language>pl-PL</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>
	<item>
		<title>Solr i Open Tracing</title>
		<link>https://solr.pl/2020/11/02/solr-i-open-tracing/</link>
					<comments>https://solr.pl/2020/11/02/solr-i-open-tracing/#respond</comments>
		
		<dc:creator><![CDATA[Rafał Kuć]]></dc:creator>
		<pubDate>Mon, 02 Nov 2020 12:25:22 +0000</pubDate>
				<category><![CDATA[Solr]]></category>
		<category><![CDATA[tracing]]></category>
		<guid isPermaLink="false">http://sematext.solr.pl/?p=834</guid>

					<description><![CDATA[Wraz z wydaniem Solr w wersji 8.2 dostaliśmy w nasze ręce wsparcie dla Open Tracing. Niezależne od dostawców API dostarczające możliwości dodania rozproszonego tracingu do naszej aplikacji. Ważne jest także to, iż nie jesteśmy związani z żadnym szczególnym dostawcą, czy]]></description>
										<content:encoded><![CDATA[
<p>Wraz z wydaniem Solr w wersji 8.2 dostaliśmy w nasze ręce wsparcie dla Open Tracing. Niezależne od dostawców API dostarczające możliwości dodania rozproszonego tracingu do naszej aplikacji. Ważne jest także to, iż nie jesteśmy związani z żadnym szczególnym dostawcą, czy rozwiązaniem &#8211; w tej chwili jest kilka rozwiązań open-source oraz tych komercyjnych, więc jest w czym wybierać. Spójrzmy zatem jak skonfigurować Solr, aby skorzystać z Open Tracing.</p>



<span id="more-834"></span>



<h2 class="wp-block-heading">Na początek</h2>



<p>Na potrzebny tego wpisu przygotowałem sobie klaster SolrCloud zbudowany z dwóch instancji Solr działających na tej samej maszynie. Nic skomplikowanego, ale na potrzeby tego wpisu jest wystarczające.</p>



<h2 class="wp-block-heading">Open Tracing</h2>



<p>Oczywiście, aby móc skorzystać z dobrodziejstw tracingu potrzebujemy miejsca, gdzie Solr będzie wysyłać dane, które zostaną wygenerowane przy pomocy API Open Tracing. W momencie pisania tego tekstu jedynym wspieranym domyśnie przez Solr rozwiązaniem jest <a rel="noreferrer noopener" href="https://www.jaegertracing.io/" target="_blank">Jaeger</a>. Jest to rozwiązanie ze stajni <a rel="noreferrer noopener" href="https://www.cncf.io/" target="_blank">CNCF</a>, w pełni otwarte i darmowe. Dodanie innego dostawcy wspierającego API Open Tracing jest możliwe, ale nie jest to temat tego wpisu.</p>



<p>Do swoich testów wykorzystałem kontener Dockera <strong>jaegertracing/all-in-one</strong> w najnowszej wersji. Uruchomienie go jest proste i wystarczy do tego następujące polecenie:</p>



<pre class="wp-block-code"><code class="">$ docker run -d --name jaeger -p 16686:16686 -p 6831:6831/udp -p 5775:5775/udp jaegertracing/all-in-one:latest</code></pre>



<p>Uruchomiliśmy kontener pod nazwą <strong>jaeger</strong> oraz przygotowaliśmy porty <strong>16686</strong>, <strong>6831</strong> oraz <strong>5775</strong>. Port <strong>16686</strong> będzie wykorzystywany do wyświetlenia UI Jaeger, natomiast port <strong>5775</strong> będzie wykorzystany jako port agenta, czyli tam gdzie będziemy wysyłać nasze dane wyprodukowane przez API Open Tracing.</p>



<p>Aby sprawdzić, czy kontener działa wystarczy następujące polecenie:</p>



<pre class="wp-block-code"><code class="">$ docker ps</code></pre>



<h2 class="wp-block-heading">Konfiguracja Solr z Open Tracing</h2>



<p>Następną rzeczą jaką musimy zrobić to przygotowanie Solr. Na początek musimy przekopiować wszystkie biblioteki z katalogu <strong>contrib/jaegertracer-configurator/lib/</strong> oraz bibliotekę <strong>jaegertracer-configurator-8.6.0.jar</strong> z katalogu <strong>dist</strong> i umieścić je w miejscu, gdzie Solr będzie je widzieć. W moim wypadku był to katalog <strong>lib</strong> w katalogu <strong>server/solr</strong>. </p>



<p>Musimy także zmodyfikować plik <strong>solr.xml</strong> który dostępny jest w katalogu <strong>server/solr</strong>. W tym pliku musimy dodać wpis konfigurujący odpowiednie elementy Solr. W większości wypadków plik ten nie będzie pusty, wystarczy więc dodać do niego następujący wpis:</p>



<pre class="wp-block-code"><code class="">&lt;tracerConfig name="tracerConfig" class="org.apache.solr.jaeger.JaegerTracerConfigurator">
  &lt;str name="agentHost">localhost&lt;/str>
  &lt;int name="agentPort">5775&lt;/int>
  &lt;bool name="logSpans">true&lt;/bool>
  &lt;int name="flushInterval">1000&lt;/int>
  &lt;int name="maxQueueSize">10000&lt;/int>
&lt;/tracerConfig></code></pre>



<p>Powyższa konfiguracja konfiguruje Jaeger. Stwierdzamy, iż nasz agent działa lokalnie &#8211; <strong>localhost</strong> i jest dostępny na porcie <strong>5775</strong>. Dodatkowe opcje definiują czas wysyłania danych oraz wielkość kolejki. </p>



<h2 class="wp-block-heading">Klaster testowy i dane</h2>



<p>Po przygotowaniu naszych dwóch instancji w powyżej opisany sposób możemy je wreszcie uruchomić. Robimy to za pomocą następujących poleceń:</p>



<pre class="wp-block-code"><code class="">$ bin/solr start -c -f
$ bin/solr start -f -p 6883 -z localhost:9983</code></pre>



<p>Uruchomiliśmy dwie instancje Solr. Pierwsza, oprócz samego Solr uruchamia Zookeepera, natomiast druga instancja łączy się do tego Zookeepera. Razem tworzą klaster testowy.</p>



<p>Przed stworzeniem kolekcji, której będziemy używać do testów zrobiłem jedną, dodatkową rzecz. Ustawiłem próbkowanie na 100%, co oznacza, iż wszystkie dane wyprodukowane przez API Open Tracing będą dostarczane do Jaegera. Aby to zrobić wystarczy ustawić właściwość klastra o nazwie <strong>samplePercentage</strong> na wartość <strong>100</strong>. Ja zrobiłem to następującym poleceniem: </p>



<pre class="wp-block-code"><code class="">$ curl -XGET 'localhost:8983/solr/admin/collections?action=CLUSTERPROP&amp;name=samplePercentage&amp;val=100'</code></pre>



<p>Oczywiście jest to ustawienie do testów. W przypadku produkcyjnego systemu, możemy nie chcieć trzymać 100% wszystkich danych ze względu ze względu na wielkość danych. </p>



<p>Następnie stworzyłem kolekcję o nazwie <strong>test</strong> z wykorzystaniem konfiguracji <strong>_default</strong>. Do wpisu nic więcej nie potrzeba. Sama kolekcja została stworzona przy pomocy następującego polecenia:</p>



<pre class="wp-block-code"><code class="">$ curl -XPOST -H 'Content-type:application/json' 'http://localhost:8983/api/c/'  -d '{ 
  "create": { 
    "name": "test",
    "numShards": "2"
  } 
}'</code></pre>



<p>Następnie zaindeksowałem następujące dane:</p>



<pre class="wp-block-code"><code class="">$ curl -XPOST -H 'Content-type:application/json' 'localhost:8983/solr/test/update?commit=true' -d '[
 {
  "id": 1,
  "name": "Test document 1",
  "tags": [ "doc", "test" ]
 },
 {
  "id": 2,
  "name": "Test document 2",
  "tags": [ "doc", "test" ]
 },
 {
  "id": 3,
  "name": "Test document 3",
  "tags": [ "doc", "test" ]
 }
]'</code></pre>



<p>Po czym zadałem proste zapytanie:</p>



<pre class="wp-block-code"><code class="">$ curl -XGET -H 'Content-type:application/json' 'localhost:8983/solr/test/select' -d '{
  "query" : "name:document",
  "facet": {
    "tags" : {
      "terms" : {
        "field" : "tags"
      }
    }
  }	
}'</code></pre>



<h2 class="wp-block-heading">Spójrzmy na dane</h2>



<p>Po indeksowaniu oraz zadaniu zapytania powinniśmy mieć już jakieś dane dostępne w Jaeger. Aby to sprawdzić wystarczy otworzyć w przeglądarce adres&nbsp;<strong>localhost:16686</strong>&nbsp;i wybrać&nbsp;<strong>solr</strong> z listy serwisów. Na przykład to pokazał Jaeger dla zapytania Solr:</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://solr.pl/wp-content/uploads/2020/11/jaeger-query-1024x248.png" alt="" class="wp-image-4967"/></figure>



<p>Jeżeli potrzebujemy więcej danych sekcja <strong>tags</strong> może być pomocna:</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://solr.pl/wp-content/uploads/2020/11/jaeger-query-details-1024x539.png" alt="" class="wp-image-4968"/></figure>



<p>I wszystko to dostępne po dodaniu kilku bibliotek oraz kawałka konfiguracji do Solr.</p>



<h2 class="wp-block-heading">Krok dalej &#8211; tracing poza Solr</h2>



<p>Oczywiście tracing uruchomiony tylko w ramach Solr to nie jest idealne rozwiżanie i chcielibyśmy mieć cały kod odpowiedniego przygotowany. </p>



<p>Na przykład, jeżeli mamy bardzo prostą aplikację odpytującą Solr możemy skorzystać z Open Tracing i samemu przygotować odpowiednie elementy typu <strong>span</strong>, które zostaną wysłane do Jaeger, tego samego, do którego wysyłane są dane z API Open Tracing w Solr. Przykładowy kod realizujący takie założenia może wyglądać następująco (cały projekt dostępny jest na <a href="https://github.com/solrpl/blog/tree/master/posts/tracing" target="_blank" rel="noreferrer noopener">Githubie</a>):</p>



<pre class="wp-block-code"><code class="">public class App {
    private JaegerTracer tracer;
    private HttpSolrClient solrClient;

    public static void main(String[] args) throws Exception {
        App app = new App();
        app.initTracer();
        app.initSolrClient();
        app.start();
    }

    public void start() throws Exception {
        Span span = tracer.buildSpan("example query").start();

        final Map&lt;String, String> query = new HashMap&lt;>();
        query.put("q", "*:*");
        MapSolrParams queryParams = new MapSolrParams(query);

        final QueryResponse queryResponse = solrClient.query("test", queryParams);
        final SolrDocumentList documents = queryResponse.getResults();

        sleep(10);
        processDocumentsSlow(documents, span, 100);

        span.finish();
    }

    private void processDocumentsSlow(SolrDocumentList documents, Span rootSpan, long sleepTime) {
        Span span = tracer
            .buildSpan("process documents")
            .asChildOf(rootSpan)
            .start();

        processDocumentsSlowNext(documents, span, 300);
        sleep(sleepTime);

        span.finish();
    }

    private void processDocumentsSlowNext(SolrDocumentList documents, Span rootSpan, long sleepTime) {
        Span span = tracer
            .buildSpan("process documents next")
            .asChildOf(rootSpan)
            .start();

        sleep(sleepTime);

        span.finish();
    }

    private void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (Exception ex) {}
    }

    public void initTracer() {
        if (this.tracer == null) {
            Configuration.SamplerConfiguration samplerConfiguration = new Configuration
                .SamplerConfiguration()
                .withType(ConstSampler.TYPE)
                .withParam(1);

            Configuration.ReporterConfiguration reporterConfiguration = Configuration
                .ReporterConfiguration
                .fromEnv();

            Configuration.SenderConfiguration senderConfig = reporterConfiguration
                .getSenderConfiguration()
                .withAgentHost("localhost")
                .withAgentPort(5775);

            reporterConfiguration
                .withLogSpans(true)
                .withSender(senderConfig);

            Configuration configuration = new Configuration("Jaeger with Solr")
                .withSampler(samplerConfiguration)
                .withReporter(reporterConfiguration);

            this.tracer = configuration.getTracer();
        }
    }

    public void initSolrClient() {
        if (this.solrClient == null) {
            this.solrClient = new HttpSolrClient
                .Builder("http://localhost:8983/solr")
                .build();
        }
    }
}</code></pre>



<p>Oprócz metody <strong>initTracer</strong>, która konfiguje Jaegera interesująca część kodu znajduje się w metodzie <strong>start</strong>. Tworzymy <strong>span</strong>, a następnie budujemy zapyatnie do Solr, wykonujemy je i pobieramy wyniki wyszukiwania. Następnie symulujemy opóźnienia wykonywania i wywołujemy metodę <strong>processDocumentsSlow</strong>, a w niej <strong>processDocumentsSlowNext</strong>. Każda z tym metod tworzy <strong>span</strong> oraz korzysta z metody <strong>asChildOf</strong>, aby poinformować, iż <strong>span</strong> jest częścią dłuższego wywołania logiki. To wszystko, w Jaeger, wygląda następująco:</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://solr.pl/wp-content/uploads/2020/11/jaeger-with-code-1024x215.png" alt="" class="wp-image-4969"/></figure>



<p>W tym momencie mamy wgląd nie tylko w Solr, ale także w naszą aplikację. </p>



<h2 class="wp-block-heading">Następne kroki</h2>



<p>Cała siła rozproszonego tracingu widoczna jest wtedy, kiedy cały kod jest odpowiednio przygotowany, a my mamy możliwość śledzenia wywołań metod i funkcji oraz obserwacji z tym związanych. Open Tracing wspiera nie tylko język Java, ale także JavaScript, Go, Python, PHP, Objective-C, C++, C# i Ruby. A zatem jeżeli Twoja aplikacja korzysta z wymienionych języków instrumentalizacja kodu nie powinna być problemem. </p>



<p>Ważne jest także to, iż Open Tracing jest tylko zbiorem API, które nie jest związane z żadnym dostawcą, czy rozwiązaniem. Korzystając z API Open Tracing możemy wybrać dowolnego dostawcę lub rozwiązanie, które będzie dla nas odpowiednie, czy to komercyjne, czy w pełni otwarte. Warto o tym pomyśleć jeżeli chcemy dodać rozproszony tracing do naszej aplikacji i oprócz logów i metryk mieć także dostęp do tracingu. </p>
]]></content:encoded>
					
					<wfw:commentRss>https://solr.pl/2020/11/02/solr-i-open-tracing/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
