Пример #1
0
// Reload the network from a file
func Reload(arch string) string {
	root := ""
	g := graphjson.ReadArch(arch)
	archaius.Conf.Population = 0 // just to make sure
	// count how many nodes there are
	for _, element := range g.Graph {
		if element.Node != "" {
			archaius.Conf.Population++
		}
	}
	CreateChannels()
	CreateEureka()
	// eureka and edda aren't recorded in the json file to simplify the graph
	// Start all the services
	cass := make(map[string]chan gotocol.Message) // for token distribution
	for _, element := range g.Graph {
		if element.Node != "" {
			name := element.Node
			StartNode(name, "")
			if names.Package(name) == DenominatorPkg {
				root = name
			}
			if names.Package(name) == "priamCassandra" {
				cass[name] = noodles[name] // remember the nodes
			}
		}
	}
	if len(cass) > 0 { // currently doesn't handle multiple priamCassandra per arch
		priamCassandra.Distribute(cass) // returns a string if it needs logging
	}
	// Make all the connections
	for _, element := range g.Graph {
		if element.Edge != "" && element.Source != "" && element.Target != "" {
			Connect(element.Source, element.Target)
		}
	}
	// run for a while
	if root == "" {
		log.Fatal("No denominator root microservice specified")
	}
	return root
}
Пример #2
0
// Start edda, to listen for logging data from services
func Start(name string) {
	// use a waitgroup so whoever starts edda can tell the logs have been flushed
	Wg.Add(1)
	defer Wg.Done()
	if Logchan == nil {
		return
	}
	var msg gotocol.Message
	microservices := make(map[string]bool, archaius.Conf.Dunbar)
	edges := make(map[string]bool, archaius.Conf.Dunbar)
	var ok bool
	hist := collect.NewHist(name)
	log.Println(name + ": starting")
	if archaius.Conf.GraphmlFile != "" {
		graphml.Setup(archaius.Conf.GraphmlFile)
	}
	if archaius.Conf.GraphjsonFile != "" {
		graphjson.Setup(archaius.Conf.GraphjsonFile)
	}
	if archaius.Conf.Neo4jURL != "" {
		graphneo4j.Setup(archaius.Conf.Neo4jURL)
	}
	for {
		msg, ok = <-Logchan
		collect.Measure(hist, time.Since(msg.Sent))
		if !ok {
			break // channel was closed
		}
		if archaius.Conf.Msglog {
			log.Printf("%v(backlog %v): %v\n", name, len(Logchan), msg)
		}
		switch msg.Imposition {
		case gotocol.Inform:
			edge := names.FilterEdge(msg.Intention)
			if edges[edge] == false { // only log an edge once
				edges[edge] = true
				graphml.WriteEdge(edge)
				graphjson.WriteEdge(edge, msg.Sent)
				graphneo4j.WriteEdge(strings.Replace(msg.Intention, "-", "_", -1), msg.Sent)
			}
		case gotocol.Put:
			node := names.FilterNode(msg.Intention)
			if microservices[node] == false { // only log a node once
				microservices[node] = true
				graphml.WriteNode(node + " " + names.Package(msg.Intention))
				graphjson.WriteNode(node+" "+names.Package(msg.Intention), msg.Sent)
				graphneo4j.WriteNode(strings.Replace(msg.Intention, "-", "_", -1)+" "+names.Package(msg.Intention), msg.Sent)
			}
		case gotocol.Forget: // forget the edge
			// problem here in that edges may be reported multiple times from several sources
			// however after filtering all matching edges are reported as forgotten when the first is
			// need to maintain the full model and a filtered model with counts
			edge := names.FilterEdge(msg.Intention)
			if edges[edge] == true { // only remove an edge once
				edges[edge] = false
				graphjson.WriteForget(edge, msg.Sent)
			}
		case gotocol.Delete: // remove the node
			node := names.FilterNode(msg.Intention)
			if microservices[node] == true { // only remove nodes that exist, and only log it once
				microservices[node] = false
				graphjson.WriteDone(node, msg.Sent)
			}
		}
	}
	log.Println(name + ": closing")
	graphml.Close()
	graphjson.Close()
	graphneo4j.Close()
}
Пример #3
0
// Start a node using the named package, and connect it to any dependencies
func StartNode(name string, dependencies ...string) {
	if names.Package(name) == EurekaPkg {
		eurekachan[name] = make(chan gotocol.Message, archaius.Conf.Population/len(archaius.Conf.ZoneNames)) // buffer sized to a zone
		go eureka.Start(eurekachan[name], name)
		return
	} else {
		noodles[name] = make(chan gotocol.Message)
	}
	// start the service and tell it it's name
	switch names.Package(name) {
	case PiratePkg:
		go pirate.Start(noodles[name])
	case ElbPkg:
		go elb.Start(noodles[name])
	case DenominatorPkg:
		go denominator.Start(noodles[name])
	case ZuulPkg:
		go zuul.Start(noodles[name])
	case KaryonPkg:
		go karyon.Start(noodles[name])
	case MonolithPkg:
		go monolith.Start(noodles[name])
	case StaashPkg:
		go staash.Start(noodles[name])
	case RiakPkg:
		fallthrough // fake Riak using priamCassandra
	case PriamCassandraPkg:
		go priamCassandra.Start(noodles[name])
	case CachePkg:
		fallthrough // fake memcache using store
	case VolumePkg:
		fallthrough // fake disk volume using store
	case StorePkg:
		go store.Start(noodles[name])
	default:
		log.Fatal("asgard: unknown package: " + names.Package(name))
	}
	noodles[name] <- gotocol.Message{gotocol.Hello, listener, time.Now(), gotocol.NilContext, name}
	// there is a eureka service registry in each zone, so in-zone services just get to talk to their local registry
	// elb are cross zone, so need to see all registries in a region
	// denominator are cross region so need to see all registries globally
	// priamCassandra depends explicitly on eureka for cross region clusters
	crossregion := false
	for _, d := range dependencies {
		if d == "eureka" {
			crossregion = true
		}
	}
	for n, ch := range eurekachan {
		if names.Region(name) == "*" || crossregion {
			// need to know every eureka in all zones and regions
			gotocol.Send(noodles[name], gotocol.Message{gotocol.Inform, ch, time.Now(), gotocol.NilContext, n})
		} else {
			if names.Zone(name) == "*" && names.Region(name) == names.Region(n) {
				// need every eureka in my region
				gotocol.Send(noodles[name], gotocol.Message{gotocol.Inform, ch, time.Now(), gotocol.NilContext, n})
			} else {
				if names.RegionZone(name) == names.RegionZone(n) {
					// just the eureka in this specific zone
					gotocol.Send(noodles[name], gotocol.Message{gotocol.Inform, ch, time.Now(), gotocol.NilContext, n})
				}
			}
		}
	}
	//log.Println(dependencies)
	// pass on symbolic dependencies without channels that will be looked up in Eureka later
	for _, dep := range dependencies {
		if dep != "" && dep != "eureka" { // ignore special case of eureka in dependency list
			//log.Println(name + " depends on " + dep)
			gotocol.Send(noodles[name], gotocol.Message{gotocol.NameDrop, nil, time.Now(), gotocol.NilContext, dep})
		}
	}
}
Пример #4
0
// Start store, all configuration and state is sent via messages
func Start(listener chan gotocol.Message) {
	// remember the channel to talk to microservices
	microservices := ribbon.MakeRouter()
	dependencies := make(map[string]time.Time) // dependent services and time last updated
	store := make(map[string]string, 4)        // key value store
	store["why?"] = "because..."
	var netflixoss chan gotocol.Message                                           // remember creator and how to talk back to incoming requests
	var name string                                                               // remember my name
	eureka := make(map[string]chan gotocol.Message, len(archaius.Conf.ZoneNames)) // service registry per zone
	hist := collect.NewHist("")
	ep, _ := time.ParseDuration(archaius.Conf.EurekaPoll)
	eurekaTicker := time.NewTicker(ep)
	for {
		select {
		case msg := <-listener:
			flow.Instrument(msg, name, hist)
			switch msg.Imposition {
			case gotocol.Hello:
				if name == "" {
					// if I don't have a name yet remember what I've been named
					netflixoss = msg.ResponseChan // remember how to talk to my namer
					name = msg.Intention          // message body is my name
					hist = collect.NewHist(name)
				}
			case gotocol.Inform:
				eureka[msg.Intention] = handlers.Inform(msg, name, listener)
			case gotocol.NameDrop: // cross zone = true
				handlers.NameDrop(&dependencies, microservices, msg, name, listener, eureka, true)
			case gotocol.Forget:
				// forget a buddy
				handlers.Forget(&dependencies, microservices, msg)
			case gotocol.GetRequest:
				// return any stored value for this key
				outmsg := gotocol.Message{gotocol.GetResponse, listener, time.Now(), msg.Ctx, store[msg.Intention]}
				flow.AnnotateSend(outmsg, name)
				outmsg.GoSend(msg.ResponseChan)
			case gotocol.GetResponse:
				// return path from a request, send payload back up (not currently used)
			case gotocol.Put:
				// set a key value pair and replicate to other stores
				var key, value string
				fmt.Sscanf(msg.Intention, "%s%s", &key, &value)
				if key != "" && value != "" {
					store[key] = value
					// duplicate the request on to all connected store nodes with the same package name as this one
					for _, n := range microservices.All(names.Package(name)).Names() {
						outmsg := gotocol.Message{gotocol.Replicate, listener, time.Now(), msg.Ctx.NewParent(), msg.Intention}
						flow.AnnotateSend(outmsg, name)
						outmsg.GoSend(microservices.Named(n))
					}
				}
			case gotocol.Replicate:
				// Replicate is used between store nodes
				// end point for a request
				var key, value string
				fmt.Sscanf(msg.Intention, "%s%s", &key, &value)
				// log.Printf("store: %v:%v", key, value)
				if key != "" && value != "" {
					store[key] = value
				}
			case gotocol.Goodbye:
				gotocol.Message{gotocol.Goodbye, nil, time.Now(), gotocol.NilContext, name}.GoSend(netflixoss)
				return
			}
		case <-eurekaTicker.C: // check to see if any new dependencies have appeared
			for dep, _ := range dependencies {
				for _, ch := range eureka {
					ch <- gotocol.Message{gotocol.GetRequest, listener, time.Now(), gotocol.NilContext, dep}
				}
			}
		}
	}
}