Slide 1

Slide 1 text

©2019 Wantedly, Inc. Troubleshoot Your RoR Microservices with Distributed Tracing RailsConf 2019 - Minneapolis May 2, 2019 - Yoshinori Kawasaki (@kawasy/@luvtechno)

Slide 2

Slide 2 text

©2019 Wantedly, Inc. Yoshinori Kawasaki Wantedly, Inc. @luvtechno @kawasyʢ೔ຊޠͰ0,ʣ

Slide 3

Slide 3 text

©2019 Wantedly, Inc. Tokyo based company. We “create a world where work drives passion,” by helping people uncover jobs they are passionate about, visit future teammates who share the same values, and meet an exciting company they’ll love working for.

Slide 4

Slide 4 text

©2019 Wantedly, Inc. ✋

Slide 5

Slide 5 text

©2019 Wantedly, Inc. Microservices — or — Monolith

Slide 6

Slide 6 text

©2019 Wantedly, Inc. Please vote and RT https://twitter.com/luvtechno/

Slide 7

Slide 7 text

©2019 Wantedly, Inc. 1. Why Distributed Tracing and how it helps 2. What OpenCensus is and how to use it In this talk…

Slide 8

Slide 8 text

©2019 Wantedly, Inc. Distributed Tracing What it is and how it helps in microservices architecture

Slide 9

Slide 9 text

©2019 Wantedly, Inc. Microservices are great, but too hard?

Slide 10

Slide 10 text

©2019 Wantedly, Inc. Monolith

Slide 11

Slide 11 text

©2019 Wantedly, Inc. Microservices

Slide 12

Slide 12 text

©2019 Wantedly, Inc. Hard to tell components involved in a single end-user request

Slide 13

Slide 13 text

©2019 Wantedly, Inc.

Slide 14

Slide 14 text

©2019 Wantedly, Inc. A B C D E G F Feature X Feature Y Dependencies

Slide 15

Slide 15 text

©2019 Wantedly, Inc. A B C D E G F Feature X Feature Y Dependencies

Slide 16

Slide 16 text

©2019 Wantedly, Inc. No code change, but new errors. Why??? When You See High Error Rate A B C D E G F Feature X Feature Y

Slide 17

Slide 17 text

©2019 Wantedly, Inc. When You See High Error Rate A B C D E G F Feature X Feature Y If you don’t know dependencies… ???? ????

Slide 18

Slide 18 text

©2019 Wantedly, Inc. When You See High Error Rate A B C D E G F Feature X Feature Y You’ll have to speculate to find a root cause ???? ????

Slide 19

Slide 19 text

©2019 Wantedly, Inc. When You See High Error Rate A B C D E G F Feature X Feature Y Even if you know dependencies…

Slide 20

Slide 20 text

©2019 Wantedly, Inc. When You See High Error Rate A B C D E G F Feature X Feature Y You still need to investigate which feature is affected

Slide 21

Slide 21 text

©2019 Wantedly, Inc. Distributed tracing helps you!

Slide 22

Slide 22 text

©2019 Wantedly, Inc. Distributed Tracing Time A C D F DB G

Slide 23

Slide 23 text

©2019 Wantedly, Inc. • A trace is a set of operations in an end-to-end request. • A trace has spans. A span represents an operation. • Spans can be nested, which represents causality. • A span has a name, and contains start and end time with other annotations. Distributed Tracing

Slide 24

Slide 24 text

©2019 Wantedly, Inc. Demo

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

©2019 Wantedly, Inc. OpenCensus What it is and how it helps in microservices architecture

Slide 29

Slide 29 text

©2019 Wantedly, Inc. OpenCensus is… a set of vendor-neutral libraries to collect and export traces and metrics.

Slide 30

Slide 30 text

©2019 Wantedly, Inc. 1. Libraries for tracing and metrics • Java, Go, Node, Python, C++, C#, PHP, Ruby, Erlang/Elixir • Focus on capturing and sending data in your app, no analysis part provided. 2. Exporter for backend(s) of your choice • Send to StackDriver, DataDog, Jaeger, Zipkin, Prometheus, etc. • Can export to multiple backends at once. 3. Out-of-box integrations • Rack middleware for inbound request, Faraday middleware for outbound request. • Instrument events like ActiveRecord database calls, ActionView renders, etc OpenCensus

Slide 31

Slide 31 text

©2019 Wantedly, Inc. • trace_id: a 16-byte unique identifier for a trace. • span_id: a 8-byte unique identifier for a span. • parent_span_id: span_id of this span's parent span. • name: a description. Can be a method name, or a file name and a line num. • kind: UNSPECIFIED, SERVER, or CLIENT. • start_time, end_time: when a span starts and ends. • attributes: a set of key-value pairs. Value can be string, integer, double or bool. • stack_trace: A stack trace at the start. • time_events: a time-stamped annotation or send/rcv message event in a span. • links: a pointer from the current to another span in the same or a different trace. • status: a finally status of the span Span See https://github.com/census-instrumentation/opencensus-proto/blob/master/src/opencensus/proto/trace/v1/trace.proto

Slide 32

Slide 32 text

©2019 Wantedly, Inc. Architecture Backend Application Logic Collector Exporter(s) Backend Application Logic Collector Exporter(s) Application Logic Collector Exporter(s) HTTP request

Slide 33

Slide 33 text

©2019 Wantedly, Inc. OpenCensus Ruby Backend Rails Collector Exporter(s) Inbound HTTP request Rack Middleware Faraday Middleware Outbound HTTP request

Slide 34

Slide 34 text

©2019 Wantedly, Inc. # Gemfile gem 'opencensus' # When a process starts OpenCensus.configure do |c| c.trace.middleware_placement = :begin c.trace.exporter = exporter c.trace.default_sampler = \ OpenCensus::Trace::Samplers::Probability.new(0.01) c.trace.default_max_attributes = 64 end Configure Tracing

Slide 35

Slide 35 text

©2019 Wantedly, Inc. # DataDog exporter uri = URI.parse(ENV['DATADOG_APM_AGENT_URL']) c.exporter = OpenCensus::Trace::Exporters::Datadog.new \ service: app_name, agent_hostname: uri.host, agent_port: uri.port # StackDriver exporter keyfile = Base64.strict_decode64(ENV['STACKDRIVER_JSON_KEY_BASE64']) c.exporter = OpenCensus::Trace::Exporters::Stackdriver.new \ project_id: gcp_project_id, credentials: JSON.parse(keyfile) # multiple exporters c.exporter = OpenCensus::Trace::Exporters::Multi.new(*exporters) Configure Exporter

Slide 36

Slide 36 text

©2019 Wantedly, Inc. Rails Integration # application.rb require 'opencensus/trace/integrations/rails' # <- Rails::Railtie # the toplevel configuration object is exposed as `config.opencensus` config.opencensus.trace.default_max_attributes = 64

Slide 37

Slide 37 text

©2019 Wantedly, Inc. class OpenCensus::Trace::Integrations::RackMiddleware def call env formatter = Formatters::TraceContext.new context = formatter.deserialize env[formatter.rack_header_name] Trace.start_request_trace \ trace_context: context, same_process_as_parent: false do |span_context| begin Trace.in_span get_path(env) do |span| start_request span, env @app.call(env).tap do |response| finish_request span, response end end ensure @exporter.export span_context.build_contained_spans end end end end Rack Middleware

Slide 38

Slide 38 text

©2019 Wantedly, Inc. DEFAULT_NOTIFICATION_EVENTS = [ "sql.active_record", "render_template.action_view", "send_file.action_controller", "send_data.action_controller", "deliver.action_mailer" ].freeze def setup_notifications OpenCensus::Trace.configure.notifications.events.each do |type| ActiveSupport::Notifications.subscribe(type) do |*args| event = ActiveSupport::Notifications::Event.new(*args) handle_notification_event event end end end ActiveSupport::Notification

Slide 39

Slide 39 text

©2019 Wantedly, Inc. def handle_notification_event event span_context = OpenCensus::Trace.span_context if span_context ns = OpenCensus::Trace.configure.notifications.attribute_namespace span = span_context.start_span event.name, skip_frames: 2 span.start_time = event.time span.end_time = event.end event.payload.each do |k, v| span.put_attribute "#{ns}#{k}", v.to_s end end end ActiveSupport::Notification (cont) See https://api.rubyonrails.org/classes/ActiveSupport/Notifications.html

Slide 40

Slide 40 text

©2019 Wantedly, Inc. class OpenCensus::Trace::IntegrationsFaradayMiddleware < ::Faraday::Middleware def call request_env span_context = request_env[:span_context] span_name = extract_span_name(request_env) span = span_context.start_span span_name, sampler: @sampler start_request span, request_env begin @app.call(request_env).on_complete do |response_env| finish_request span, response_env end rescue StandardError => e span.set_status 2, e.message raise ensure span_context.end_span span end end end Faraday Middleware

Slide 41

Slide 41 text

©2019 Wantedly, Inc. conn = Faraday.new(url: api_base_url) do |c| c.use OpenCensus::Trace::Integrations::FaradayMiddleware, span_name: ->(env) { env[:url].path } c.adapter Faraday.default_adapter end Faraday Middleware (cont) Recommend to do this in a private gem used in your rails apps.

Slide 42

Slide 42 text

©2019 Wantedly, Inc. Custom Span API OpenCensus::Trace.in_span "long task" do t = rand * 10 sleep t end def in_span name, kind: nil, skip_frames: 0, sampler: nil span = start_span name, kind: kind, skip_frames: skip_frames + 1, sampler: sampler begin yield span ensure end_span span end end

Slide 43

Slide 43 text

©2019 Wantedly, Inc. OpenCensus + OpenTracing Merger https://medium.com/opentracing/merging-opentracing-and-opencensus-f0fe9c7ca6f0

Slide 44

Slide 44 text

©2019 Wantedly, Inc. https://storage.googleapis.com/open-source-software/OpenConsensus%20Roadmap.jpg

Slide 45

Slide 45 text

©2019 Wantedly, Inc. Summaryʢ·ͱΊʣ

Slide 46

Slide 46 text

©2019 Wantedly, Inc. 1. Distributed tracing makes you productive in microservices architecture 2. You can easily adopt distributed tracing using OpenCensus To summarize…

Slide 47

Slide 47 text

©2019 Wantedly, Inc. Thank you! @luvtechno @kawasyʢ೔ຊޠͰ0,ʣ

Slide 48

Slide 48 text

©2019 Wantedly, Inc. w !NVOJTZTUFN w !CHQBU w !J[VNJO w !"MUFDI Special Thanks

Slide 49

Slide 49 text

©2019 Wantedly, Inc. w 1BVM4LPSVQTLBTIUUQTVOTQMBTIDPNQIPUPT,-BY-C49" w (BCSJFM4BODIF[IUUQTVOTQMBTIDPNQIPUPT'@NP,:8:D w *BO4UBVGGFSIUUQTVOTQMBTIDPNQIPUPTC)L;ZB[# Photo Credit