Kiến trúc Microservice ngày càng trở nên phổ biến và trở thành lựa chọn hàng đầu trong quá trình phát triển phần mềm. Trong kiến trúc microservice, ứng dụng monolithic truyền thống được chia nhỏ ra thành các thành phần có thể deploy độc lập. Một ứng dụng dần trở thành một nhóm các microservice, khi bạn có hàng trăm, hàng ngàn các microservice nhỏ cùng hoạt động, sẽ không dễ dàng cho bạn nắm được các service nào đang gọi đến nhau, một request đang đi từ services nào đến service nào.
Để giải quyết vấn đề này, một kỹ thuật được đưa ra là Distributed Tracing
. Distributed Tracing
là một phương thức để profile và monitor ứng dụng, đặc biệt là những ứng dụng sử dụng kiến trúc microservices. Nó giúp xác định chính xác service nào khi nó xảy ra lỗi và điều gì đang gây ảnh hưởng tới performance của ứng dụng.
Jaeger Tracing
là một hệ thống distributed tracing được phát triển bởi Uber
. Nó được sử dụng để giám sát và xử lý sự cố.
Triển khai trên Docker Swarm
Bộ Jaeger Tracing backend gồm 3 thành phần chính là:
- Jaeger Agent
- Jaeger Collector: Collector sẽ thu thập từ Agent về và lưu vào DB ( Ở đây chúng ta dùng Elasticsearch, và Jaeger mới chỉ support sử dụng Elasticsearch ver 6.x)
- Jaeger Query/ UI
File cấu hình jaeger-stack.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
<span class="token punctuation">---</span> <span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">'3'</span> <span class="token key atrule">services</span><span class="token punctuation">:</span> <span class="token key atrule">elasticsearch</span><span class="token punctuation">:</span> <span class="token key atrule">image</span><span class="token punctuation">:</span> docker.elastic.co/elasticsearch/elasticsearch<span class="token punctuation">:</span>6.8.4 <span class="token key atrule">hostname</span><span class="token punctuation">:</span> elasticsearch <span class="token key atrule">networks</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> elastic<span class="token punctuation">-</span>jaeger <span class="token key atrule">deploy</span><span class="token punctuation">:</span> <span class="token key atrule">mode</span><span class="token punctuation">:</span> replicated <span class="token key atrule">replicas</span><span class="token punctuation">:</span> <span class="token number">1</span> <span class="token key atrule">restart_policy</span><span class="token punctuation">:</span> <span class="token key atrule">condition</span><span class="token punctuation">:</span> on<span class="token punctuation">-</span>failure <span class="token key atrule">environment</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> bootstrap.memory_lock=true <span class="token punctuation">-</span> ES_JAVA_OPTS=<span class="token punctuation">-</span>Xms512m <span class="token punctuation">-</span>Xmx512m <span class="token key atrule">ports</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token string">"9200:9200"</span> <span class="token key atrule">volumes</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> esdata1<span class="token punctuation">:</span>/usr/share/elasticsearch/data <span class="token punctuation">-</span> eslog<span class="token punctuation">:</span>/usr/share/elasticsearch/logs <span class="token punctuation">-</span> ./config/elasticsearch.yml<span class="token punctuation">:</span>/usr/share/elasticsearch/config/elasticsearch.yml <span class="token key atrule">jaeger-collector</span><span class="token punctuation">:</span> <span class="token key atrule">image</span><span class="token punctuation">:</span> jaegertracing/jaeger<span class="token punctuation">-</span>collector <span class="token key atrule">ports</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token string">"14267:14267"</span> <span class="token punctuation">-</span> <span class="token string">"14268:14268"</span> <span class="token punctuation">-</span> <span class="token string">"9411:9411"</span> <span class="token punctuation">-</span> <span class="token string">"14250:14250"</span> <span class="token key atrule">hostname</span><span class="token punctuation">:</span> jaeger<span class="token punctuation">-</span>collector <span class="token key atrule">deploy</span><span class="token punctuation">:</span> <span class="token key atrule">mode</span><span class="token punctuation">:</span> replicated <span class="token key atrule">replicas</span><span class="token punctuation">:</span> <span class="token number">1</span> <span class="token key atrule">restart_policy</span><span class="token punctuation">:</span> <span class="token key atrule">condition</span><span class="token punctuation">:</span> on<span class="token punctuation">-</span>failure <span class="token key atrule">networks</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> elastic<span class="token punctuation">-</span>jaeger <span class="token key atrule">command</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"--es.server-urls=http://elasticsearch:9200"</span><span class="token punctuation">]</span> <span class="token key atrule">environment</span><span class="token punctuation">:</span> <span class="token key atrule">SPAN_STORAGE_TYPE</span><span class="token punctuation">:</span> <span class="token string">"elasticsearch"</span> <span class="token key atrule">depends_on</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> elasticsearch <span class="token key atrule">jaeger-agent</span><span class="token punctuation">:</span> <span class="token key atrule">image</span><span class="token punctuation">:</span> jaegertracing/jaeger<span class="token punctuation">-</span>agent <span class="token key atrule">ports</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token string">"5775:5775/udp"</span> <span class="token punctuation">-</span> <span class="token string">"5778:5778"</span> <span class="token punctuation">-</span> <span class="token string">"6831:6831/udp"</span> <span class="token punctuation">-</span> <span class="token string">"6832:6832/udp"</span> <span class="token key atrule">depends_on</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> jaeger<span class="token punctuation">-</span>collector <span class="token punctuation">-</span> elasticsearch <span class="token key atrule">deploy</span><span class="token punctuation">:</span> <span class="token key atrule">mode</span><span class="token punctuation">:</span> replicated <span class="token key atrule">replicas</span><span class="token punctuation">:</span> <span class="token number">1</span> <span class="token key atrule">restart_policy</span><span class="token punctuation">:</span> <span class="token key atrule">condition</span><span class="token punctuation">:</span> on<span class="token punctuation">-</span>failure <span class="token key atrule">hostname</span><span class="token punctuation">:</span> jaeger<span class="token punctuation">-</span>agent <span class="token key atrule">networks</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> elastic<span class="token punctuation">-</span>jaeger <span class="token key atrule">command</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"--collector.host-port=jaeger-collector:14267"</span><span class="token punctuation">]</span> <span class="token key atrule">jaeger-query</span><span class="token punctuation">:</span> <span class="token key atrule">image</span><span class="token punctuation">:</span> jaegertracing/jaeger<span class="token punctuation">-</span>query<span class="token punctuation">:</span><span class="token number">1.8</span> <span class="token key atrule">ports</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token string">"16686:16686"</span> <span class="token key atrule">depends_on</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> jaeger<span class="token punctuation">-</span>collector <span class="token punctuation">-</span> elasticsearch <span class="token key atrule">deploy</span><span class="token punctuation">:</span> <span class="token key atrule">mode</span><span class="token punctuation">:</span> replicated <span class="token key atrule">replicas</span><span class="token punctuation">:</span> <span class="token number">1</span> <span class="token key atrule">restart_policy</span><span class="token punctuation">:</span> <span class="token key atrule">condition</span><span class="token punctuation">:</span> on<span class="token punctuation">-</span>failure <span class="token key atrule">networks</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> elastic<span class="token punctuation">-</span>jaeger <span class="token key atrule">environment</span><span class="token punctuation">:</span> <span class="token key atrule">SPAN_STORAGE_TYPE</span><span class="token punctuation">:</span> <span class="token string">"elasticsearch"</span> <span class="token key atrule">QUERY_BASE_PATH</span><span class="token punctuation">:</span> <span class="token string">"/ui"</span> <span class="token key atrule">command</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"--es.server-urls=http://elasticsearch:9200"</span><span class="token punctuation">,</span> <span class="token string">"--es.sniffer=false"</span><span class="token punctuation">,</span> <span class="token string">"--log-level=debug"</span><span class="token punctuation">]</span> <span class="token key atrule">volumes</span><span class="token punctuation">:</span> <span class="token key atrule">esdata1</span><span class="token punctuation">:</span> <span class="token key atrule">eslog</span><span class="token punctuation">:</span> <span class="token key atrule">networks</span><span class="token punctuation">:</span> <span class="token key atrule">elastic-jaeger</span><span class="token punctuation">:</span> |
File cấu hình cho Elasticsearch
config/elasticsearch.yml
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
<span class="token comment">################################### Production Configuration ###################################</span> <span class="token comment">### Author: Greg Dooper</span> <span class="token comment">### Description: Parameters recommended from documentation</span> <span class="token key atrule">network</span> <span class="token punctuation">:</span> <span class="token key atrule">host</span> <span class="token punctuation">:</span> 0.0.0.0 <span class="token comment">################################### Cluster ###################################</span> <span class="token comment"># Cluster name identifies your cluster for auto-discovery. If you're running</span> <span class="token comment"># multiple clusters on the same network, make sure you're using unique names.</span> <span class="token comment">#</span> <span class="token key atrule">cluster.name</span><span class="token punctuation">:</span> opentrace <span class="token comment">#################################### Paths ####################################</span> <span class="token comment"># Path to directory containing configuration (this file and logging.yml):</span> <span class="token comment">#</span> <span class="token comment">#path.conf: /path/to/conf</span> <span class="token comment"># Path to directory where to store index data allocated for this node.</span> <span class="token comment">#</span> <span class="token key atrule">path.data</span><span class="token punctuation">:</span> /usr/share/elasticsearch/data/ <span class="token comment"># Path to where plugins are installed:</span> <span class="token comment">#</span> <span class="token comment">#path.plugins: /path/to/plugins</span> <span class="token comment">################################## Discovery ##################################</span> <span class="token comment"># Discovery infrastructure ensures nodes can be found within a cluster</span> <span class="token comment"># and master node is elected. Multicast discovery is the default.</span> <span class="token comment"># Set to ensure a node sees N other master eligible nodes to be considered</span> <span class="token comment"># operational within the cluster. This should be set to a quorum/majority of </span> <span class="token comment"># the master-eligible nodes in the cluster.</span> <span class="token comment">#</span> <span class="token key atrule">discovery.type</span><span class="token punctuation">:</span> single<span class="token punctuation">-</span>node <span class="token key atrule">discovery.zen.ping.unicast.hosts</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"0.0.0.0"</span><span class="token punctuation">]</span> <span class="token key atrule">discovery.zen.minimum_master_nodes</span><span class="token punctuation">:</span> <span class="token number">1</span> <span class="token comment">################################## Documentation Recommended Parameters ################################</span> <span class="token key atrule">indices.fielddata.cache.size</span><span class="token punctuation">:</span> 40% <span class="token comment">################################## Security ################################</span> <span class="token comment"># Uncomment if you want to enable JSONP as a valid return transport on the</span> <span class="token comment"># http server. With this enabled, it may pose a security risk, so disabling</span> <span class="token comment"># it unless you need it is recommended (it is disabled by default).</span> <span class="token comment">#</span> <span class="token comment">#http.jsonp.enable: true</span> <span class="token comment">################################## Shield ##################################</span> <span class="token comment"># This grants anonymous users superuser access to Elasticsearch</span> <span class="token comment"># THIS SHOULD ONLY BE USED FOR DEVELOPMENT</span> <span class="token key atrule">xpack.security.enabled</span><span class="token punctuation">:</span> <span class="token boolean important">false</span> |
Deploy thông qua Docker stack sử dụng command
1 2 |
docker stack deploy --compose-file=jaeger-stack.yaml jaeger |
Jaeger Collector
Jaeger Collector
nhận các trace từ Jaeger Agent
và đưa đúng qua một pipeline. Trong pipeline
sẽ xác mình trace, đánh chỉ mục chúng, thực hiện việc chuyển đổi trace đó sang dạng thông tin có giá trị hơn và cuối cùng lưu chúng vào Elasticsearch
.
Container Jaeger Collector sẽ expose ra các cổng tới máy host để các service khác sử dụng.
1 2 3 4 5 6 |
<span class="token key atrule">ports</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token string">"14267:14267"</span> <span class="token punctuation">-</span> <span class="token string">"14268:14268"</span> <span class="token punctuation">-</span> <span class="token string">"9411:9411"</span> <span class="token punctuation">-</span> <span class="token string">"14250:14250"</span> |
Tuy nhiên bên trong network elastic-jaeger, các service vẫn giao tiếp với nhau qua cổng mặc định của chúng.
Do chúng ta sử dụng Elasticsearch để làm DB nên khi dựng container lên phải define rõ --es.server-urls
.
1 2 |
<span class="token key atrule">command</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"--es.server-urls=http://elasticsearch:9200"</span><span class="token punctuation">]</span> |
Jaeger Agent
Jaeger Agent
là một network daemon
có nhiệm vụ nhận các log được gửi thông qua UDP từ ứng dụng và gửi nó tới Collector
. Nó được thiết kế để triển khai trên tất các các máy chủ như một thành phần của infrastructure. Jaeger Agent
tóm tắt các routing và phát hiện các nút thắt từ phía client.
Đây là service chính tương tác với phần Client để nhận thông tin của ứng dụng nên nó sẽ expose ra các cổng
1 2 3 4 5 6 |
ports: - "5775:5775/udp" - "5778:5778" - "6831:6831/udp" - "6832:6832/udp" |
1 2 |
<span class="token key atrule">command</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"--collector.host-port=jaeger-collector:14267"</span><span class="token punctuation">]</span> |
Config dùng để thông báo tới Agent host-port của Jaeger Collector.
Jaeger Query
Là nơi tương tác với DB để lấy dữ liệu và hiển thị lên UI.
Sử dụng Jaeger UI
Truy cập http://127.0.0.1:16686/ui/search => Chon dự án cần trace và chọn Find traces