Skip to content
This repository has been archived by the owner on Oct 29, 2021. It is now read-only.

Adds InfluxDB store. #99

Merged
merged 52 commits into from
Mar 9, 2016
Merged

Conversation

chris-ramon
Copy link
Contributor

Details

Issue: #98

  • Adds new store engine named: InfluxDBStore, which implements Store & Queryer interfaces as:
    • Collect(...) implementation:
      • Saves spans in a measurement named spans in the InfluxDB database named appdash.
      • Span.ID.Trace, Span.ID.Span & Span.ID.Parent are saved as tags - [InfluxDB indexes tags]
      • Span.Annotations are save as fields - [InfluxDB does not index fields]
      • Uses default 'ms' (milliseconds) as Point.Precision.
    • Trace(...) implementation:
      • Queries for all the spans for the given trace, then is wired and returned.
      • Builds tree trace: wires the trace to be returned to include it's children to the correct nesting.
    • Traces(...) implementation.
      • Executes two queries: first gets all root's span for the given traces, second query gets all children spans for each trace, then traces are wired and returned; only N(default: 10) traces are returned.
      • For each trace, builds a tree trace: wires it to include it's children to the correct nesting.
  • Adds tests for InfluxDBStore.
  • Adds NewInfluxDBStore:
    • Head function which runs the configuration needed for a new instance of InfluxDBStore - such as: run an InfluxDBServer, creates an InfluxDBClient, creates an admin user & appdash database with a retention policy if those do not already exist.
  • Adds authentication to InfluxDBServer.
  • Adds support to set default retention policy, which tells appdash database for how long time, data should be preserved before deleting it. (it's optional).
  • Adds new InfluxDBStore webapp example:
    • Based on examples/cmd/webapp/main.go - run it with:
    • go run examples/cmd/webapp-influxdb/main.go

Notes to consider:

Key Concepts

Measurement

The measurement acts as a container for tags, fields, and the time column, and the measurement name is the description of the data that are stored in the associated fields. Measurement names are strings, and, for any SQL users out there, a measurement is conceptually similar to a table.

Tags

Tags are optional. You don’t need to have tags in your data structure, but it’s generally a good idea to make use of them because, unlike fields, tags are indexed. This means that queries on tags are faster and that tags are ideal for storing commonly-queried metadata.

Fields

Fields are a required piece of InfluxDB’s data structure - you cannot have data in InfluxDB without fields. It’s also important to note that fields are not indexed. Queries that use field values as filters must scan all values that match the other conditions in the query. As a result, those queries are not performant relative to queries on tags (more on tags below). In general, fields should not contain commonly-queried metadata.

Retention Policy

The part of InfluxDB’s data structure that describes for how long InfluxDB keeps data (duration) and how many copies of those data are stored in the cluster (replication factor). RPs are unique per database and along with the measurement and tag set define a series. When you create a database, InfluxDB automatically creates a retention policy called default with an infinite duration and a replication factor set to the number of nodes in the cluster. See Database Management for retention policy management.

Continuous Queries

A CQ is an InfluxQL query that the system runs automatically and periodically within a database. InfluxDB stores the results of the CQ in a specified measurement. CQs require a function in the SELECT clause and must include a GROUP BY time() clause.

@chris-ramon chris-ramon force-pushed the influxdb-store branch 4 times, most recently from 86d724d to 71fae14 Compare January 27, 2016 23:07
@emidoots
Copy link
Member

I haven't had a chance to review the entire update yet -- but this is extremely awesome progress! :) Keep up the great work!

Just responding to a few key points, and I'll have more feedback tomorrow.

TODO: decide which Point.Precision should we use here.

Looking that the doc you linked to, it appears to go with ms by default -- which should be precise enough for most (all?) use cases we and others will have. I think using the default is probably fine.

Would it be easy for users to configure this to something else if they do want to change it?

Span.ID.Trace, Span.ID.Span & Span.ID.Parent are save as tags - [InfluxDB indexes tags]

We should not have Span.ID.Span or Span.ID.Parent be tags, they should be fields. Nobody will ever want to query by these, only by Span.ID.Trace -- so the indexing InfluxDB would do would be wasteful I think.

@chris-ramon
Copy link
Contributor Author

Thanks taking the time to review this one @slimsag! 👍

Looking that the doc you linked to, it appears to go with ms by default -- which should be precise enough for most (all?) use cases we and others will have. I think using the default is probably fine.

Would it be easy for users to configure this to something else if they do want to change it?

Good call, I agree we should let appdash users provide an optional config struct - we could add a new param to NewInfluxDBStore named PointConfig:

func NewInfluxDBStore(c *influxDBServer.Config, bi *influxDBServer.BuildInfo, p PointConfig) (*InfluxDBStore, error) {
  // ...
}

type PointPrecision string
type PointConfig struct {
  Precision PointPrecision
}

Perhaps we should wrap NewInfluxDBStore params within a struct called InfluxDBStoreConfig:

func NewInfluxDBStore(config InfluxDBStoreConfig) (*InfluxDBStore, error) {
  // ...
}

type InfluxDBStoreConfig struct {
  ServerConfig *influxDBServer.Config
  ServerBuildInfo *influxDBServer.BuildInfo
  PointConfig PointConfig
}

We should not have Span.ID.Span or Span.ID.Parent be tags, they should be fields. Nobody will ever want to query by these, only by Span.ID.Trace -- so the indexing InfluxDB would do would be wasteful I think.

Yes, we can only keep Span.ID.Trace as tag - current InfluxDBStore implementation relies on Span.ID.Parent to check; if value is empty then must be the root Span otherwise a children Span - but we can improve this by saving a new field named: is_root.

In regards removing Span.ID.Span I've found this method func (t *Trace) FindSpan(spanID ID) *Trace

tags := make(map[string]string, 3)
tags["trace_id"] = id.Trace.String()
tags["span_id"] = id.Span.String()
tags["parent_id"] = id.Parent.String()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be written more clearly as just:

tags := map[string]string{
    "trace_id": id.Trace.String(),
    "span_id": id.Span.String(),
    "parent_id": id.Parent.String(),
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Def agree, we should use map literals here - fixed on: 815bd39

@emidoots
Copy link
Member

Perhaps we should wrap NewInfluxDBStore params within a struct called InfluxDBStoreConfig

I like this idea a lot!

@emidoots
Copy link
Member

Thanks for the hard work on this @chris-ramon ! I left some comments inline, and everything else you have said I agree with.

Once you're satisfied with the state of this PR for having MemoryStore-like functionality, we should:

  1. Make the Queryer interface and the frontend support pagination.
  2. Start investigating how we can add AggregateStore-like functionality (N slowest traces, full trace times for last ~72/hours, +last 20000 traces for developer inspection).

Happy to chat with you more on the details about these, just wanted to provide an overview of where to go from here. I've tried out your PR locally and it's great! You've made some awesome progress here!

var isRootSpan bool
// Iterate over series(spans) to create trace children's & set trace fields.
for _, s := range result.Series {
span, err := newSpanFromRow(&s)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If possible, could you adjust the style a bit here (and in other places too)? Prefer a blank newline after comments, like this:

    trace := &Trace{}

    // GROUP BY * -> meaning group by all tags(trace_id, span_id & parent_id)
    // grouping by all tags includes those and it's values on the query response.
    q := fmt.Sprintf("SELECT * FROM spans WHERE trace_id='%s' GROUP BY *", id)
    result, err := in.executeOneQuery(q)
    if err != nil {
        return nil, err
    }

    // result.Series -> A slice containing all the spans.
    if len(result.Series) == 0 {
        return nil, errors.New("trace not found")
    }
    var isRootSpan bool

    // Iterate over series(spans) to create trace children's & set trace fields.
    for _, s := range result.Series {
        span, err := newSpanFromRow(&s)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good call, def improves readability - fixed on: 11e791d


// trace_id, span_id & parent_id are set as tags
// because InfluxDB tags are indexed & those values
// are uselater on queries.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo here. s/are uselater/are used later/g

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch! - fixed on 5fc2a65

also frontend won't crash due trying to use empty time values
@dmitshur
Copy link
Contributor

BTW, I don't think 80 char width should be considered a mandatory strict limit.

Rob Pike said it himself.

https://twitter.com/rob_pike/status/563798709868056576
https://twitter.com/rob_pike/status/563801489190043648
golang/go@a625b91

Most of my code falls within 40-140 characters wide. Sometimes longer when the stuff on the right side is not important.

@chris-ramon
Copy link
Contributor Author

Good call @shurcooL, I did revert d589fcb which follows strictly 80-chars-wide code style and preserved the one that @slimsag pointed-out above.

@emidoots
Copy link
Member

Looks great, thanks! @chris-ramon & @shurcooL :)

which is used to tell appdash database how long time preserve data before deleting it
chris-ramon added a commit to chris-ramon/appdash that referenced this pull request Mar 6, 2016
updates to reuse code from examples/cmd/webapp

rename pkg to webapp so we can import it

manuall install deps

renames influxdb pk name - see: github.com/influxdata/influxdb/issues/5388

updates to correct paths

adds Collect & Trace implementation

cleans up influxdb example

adds Traces implementation & cleanups InfluxDBStore

fixes naming clash

updates to more consistent func names

improvements on Traces implementation

now two queries are executed, one for root spans and other for children spans

use map literals instead for readability

use default point precision 'ms' & set utc time

typo

updates NewInfluxDBStore param signature, using struct instead for consistency.

improves code style

improves strategy for replace existing spans on DB

adds InfluxDBStore.findSpanPoint and removes InfluxDBStore.removeSpanIfExists since not needed anymore

improves root span checking

fields might contain empty values

so better to start annotations slice from zero size

temp fix for frontend hanging

when seeing trace detail page

typo

Revert "temp fix for frontend hanging" - Lasting fix on 7a77805

This reverts commit 38edc7b.

updates to preserve existing span fields

do not replace existing annotations saved on db, just append new ones

use ID's method instead of its implementation

we might want to move zeroID to `id.go`

set all other fields diff than Name too

updates to correct error text

improvements on span annotations updating

handles potential closing errors

if so we should return it

captures potential closing error and logs it

adds trace pagination related todo

updates to handle multiple row values & update docs

due to we already improved the strategy to remove existing span then save new one, now we just append new annotations to the existing span

docs improvements on InfluxDBStore.Collect method

adds missing whitespace

adds support to save `schemas` field to spans measurement

to keep track which schemas were saved by `Collect(...)`

Revert "adds empty time value validation"

This reverts commit 7a77805.

Reverting since not required anymore to prevent ui breaking,
There's a workaround introduced with:
6d10ff7.

adds sorting related improvements

improves comments for `InfluxDBStore`

updates influxdb related paths; fixes introduced on v0.10

therefore not changes on travis related to influxdb import path issues is required - see: influxdata/influxdb#5617

adds support for auth to `InfluxDBStore.server`

typo and fit comments into 80-char-width

updates to keep 80-chars code width limit

Revert "updates to keep 80-chars code width limit"

This reverts commit d589fcb.

adds mode(test, release) support for InfluxDBStore

test mode for running tests & release mode as default.

adds InfluxDBStore tests

tests for Collect & Trace methods

removes httptrace dependency to avoid cyclic dependencies

adds test for InfluxDBStore.Traces()

improvements on comments, unnecessary code & codestyle

adds default retention policy support

which is used to tell appdash database how long time preserve data before deleting it

improves comments readability & adds a low priority TODO

support to add sub-traces to it's trace parent

clean-up TestInfluxDBStore & adds TestFindTraceParent

code readability improvements
chris-ramon added a commit to chris-ramon/appdash that referenced this pull request Mar 6, 2016
@chris-ramon chris-ramon mentioned this pull request Mar 7, 2016
4 tasks
@emidoots
Copy link
Member

emidoots commented Mar 9, 2016

LGTM

emidoots pushed a commit that referenced this pull request Mar 9, 2016
@emidoots emidoots merged commit 7be3bd9 into sourcegraph:master Mar 9, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants