// Start architecture func Start(a *archV0r1) { var r string if archaius.Conf.Population < 1 { log.Fatal("architecture: can't create less than 1 microservice") } else { log.Printf("architecture: scaling to %v%%", archaius.Conf.Population) } asgard.CreateChannels() asgard.CreateEureka() // service registries for each zone for _, s := range a.Services { log.Printf("Starting: %v\n", s) r = asgard.Create(s.Name, s.Gopackage, s.Regions*archaius.Conf.Regions, s.Count*archaius.Conf.Population/100, s.Dependencies...) } asgard.Run(r, a.Victim) // run the last service in the list, and point chaos monkey at the victim }
// main handles command line flags and starts up an architecture func main() { flag.StringVar(&archaius.Conf.Arch, "a", "netflixoss", "Architecture to create or read, fsm, migration, or read from json_arch/<arch>_arch.json") flag.IntVar(&archaius.Conf.Population, "p", 100, "Pirate population for fsm or scale factor % for other architectures") flag.IntVar(&duration, "d", 10, "Simulation duration in seconds") flag.IntVar(&archaius.Conf.Regions, "w", 1, "Wide area regions to replicate architecture into, defaults based on 6 AWS region names") flag.BoolVar(&graphmlEnabled, "g", false, "Enable GraphML logging of nodes and edges to gml/<arch>.graphml") flag.BoolVar(&graphjsonEnabled, "j", false, "Enable GraphJSON logging of nodes and edges to json/<arch>.json") flag.BoolVar(&neo4jEnabled, "n", false, "Enable Neo4j logging of nodes and edges") flag.BoolVar(&archaius.Conf.Msglog, "m", false, "Enable console logging of every message") flag.BoolVar(&reload, "r", false, "Reload graph from json/<arch>.json to setup architecture") flag.BoolVar(&archaius.Conf.Collect, "c", false, "Collect metrics and flows to json_metrics csv_metrics neo4j and via http: extvars") flag.IntVar(&archaius.Conf.StopStep, "s", 0, "Sequence number to create multiple runs for ui to step through in json/<arch><s>.json") flag.StringVar(&archaius.Conf.EurekaPoll, "u", "1s", "Polling interval for Eureka name service, increase for large populations") flag.StringVar(&archaius.Conf.Keyvals, "kv", "", "Configuration key:value - chat:10ms sets default message insert rate") flag.BoolVar(&archaius.Conf.Filter, "f", false, "Filter output names to simplify graph by collapsing instances to services") flag.IntVar(&cpucount, "cpus", runtime.NumCPU(), "Number of CPUs for Go runtime") runtime.GOMAXPROCS(cpucount) var cpuprofile = flag.String("cpuprofile", "", "Write cpu profile to file") var confFile = flag.String("config", "", "Config file to read from json_arch/<config>_conf.json. This config overrides any other command-line arguments.") var saveConfFile = flag.Bool("saveconfig", false, "Save config file to json_arch/<arch>_conf.json, using the arch name from -a.") flag.Parse() if *confFile != "" { archaius.ReadConf(*confFile) } if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } if archaius.Conf.Collect { collect.Serve(8123) // start web server at port } if graphjsonEnabled || graphmlEnabled || neo4jEnabled { if graphjsonEnabled { archaius.Conf.GraphjsonFile = archaius.Conf.Arch } if graphmlEnabled { archaius.Conf.GraphmlFile = archaius.Conf.Arch } if neo4jEnabled { if archaius.Conf.Filter { log.Fatal("Neo4j cannot be used with filtered names option -f") } pw := os.Getenv("NEO4JPASSWORD") url := os.Getenv("NEO4JURL") if pw == "" { log.Fatal("Neo4j requires environment variable NEO4JPASSWORD is set") } if url == "" { archaius.Conf.Neo4jURL = "localhost:7474" } else { archaius.Conf.Neo4jURL = url } log.Println("Graph will be written to Neo4j via NEO4JURL=" + archaius.Conf.Neo4jURL) } // make a big buffered channel so logging can start before edda is scheduled edda.Logchan = make(chan gotocol.Message, 1000) } archaius.Conf.RunDuration = time.Duration(duration) * time.Second if *saveConfFile { archaius.WriteConf() } // start up the selected architecture go edda.Start(archaius.Conf.Arch + ".edda") // start edda first if reload { asgard.Run(asgard.Reload(archaius.Conf.Arch), "") } else { switch archaius.Conf.Arch { case "fsm": fsm.Start() case "migration": migration.Start() // step by step from lamp to netflixoss default: a := architecture.ReadArch(archaius.Conf.Arch) if a == nil { log.Fatal("Architecture " + archaius.Conf.Arch + " isn't recognized") } else { architecture.Start(a) } } } log.Println("spigo: complete") // stop edda if it's running and wait for edda to flush messages if edda.Logchan != nil { close(edda.Logchan) } edda.Wg.Wait() flow.Shutdown() }
// Start lamp to netflixoss step by step migration func Start() { regions := archaius.Conf.Regions if archaius.Conf.Population < 1 { log.Fatal("migration: can't create less than 1 microservice") } else { log.Printf("migration: scaling to %v%%", archaius.Conf.Population) } // Build the configuration step by step // start mysql data store layer, which connects to itself mysqlcount := 2 sname := "rds-mysql" // start memcached layer, only one per region mname := "memcache" mcount := 1 if archaius.Conf.StopStep >= 3 { // start evcache layer, one per zone mname = "evcache" mcount = 3 } // priam managed Cassandra cluster, turtle because it's used to configure other clusters priamCassandracount := 12 * archaius.Conf.Population / 100 cname := "cassTurtle" // staash data access layer connects to mysql master and slave, and evcache staashcount := 6 * archaius.Conf.Population / 100 tname := "turtle" // php business logic, we can create a network of simple services from the karyon package phpcount := 9 * archaius.Conf.Population / 100 pname := "php" // some node microservice logic, we can create a network of simple services from the karyon package nodecount := 9 * archaius.Conf.Population / 100 nname := "node" // zuul api proxies and insert between elb and php zuulcount := 9 * archaius.Conf.Population / 100 zuname := "wwwproxy" // AWS elastic load balancer elbname := "www-elb" // DNS endpoint dns := "www" switch archaius.Conf.StopStep { case 0: // basic LAMP asgard.CreateChannels() asgard.CreateEureka() // service registries for each zone asgard.Create(sname, StorePkg, regions, mysqlcount, sname) asgard.Create(pname, MonolithPkg, regions, phpcount, sname) asgard.Create(elbname, ElbPkg, regions, 0, pname) case 1: // basic LAMP with memcache asgard.CreateChannels() asgard.CreateEureka() // service registries for each zone asgard.Create(sname, StorePkg, regions, mysqlcount, sname) asgard.Create(mname, StorePkg, regions, mcount) asgard.Create(pname, MonolithPkg, regions, phpcount, sname, mname) asgard.Create(elbname, ElbPkg, regions, 0, pname) case 2: // LAMP with zuul and memcache asgard.CreateChannels() asgard.CreateEureka() // service registries for each zone asgard.Create(sname, StorePkg, regions, mysqlcount, sname) asgard.Create(mname, StorePkg, regions, mcount) asgard.Create(pname, MonolithPkg, regions, phpcount, sname, mname) asgard.Create(zuname, ZuulPkg, regions, zuulcount, pname) asgard.Create(elbname, ElbPkg, regions, 0, zuname) case 3: // LAMP with zuul and staash and evcache asgard.CreateChannels() asgard.CreateEureka() // service registries for each zone asgard.Create(sname, StorePkg, regions, mysqlcount, sname) asgard.Create(mname, StorePkg, regions, mcount) asgard.Create(tname, StaashPkg, regions, staashcount, sname, mname) asgard.Create(pname, KaryonPkg, regions, phpcount, tname) asgard.Create(zuname, ZuulPkg, regions, zuulcount, pname) asgard.Create(elbname, ElbPkg, regions, 0, zuname) case 4: // added node microservice asgard.CreateChannels() asgard.CreateEureka() // service registries for each zone asgard.Create(sname, StorePkg, regions, mysqlcount, sname) asgard.Create(mname, StorePkg, regions, mcount) asgard.Create(tname, StaashPkg, regions, staashcount, sname, mname, cname) asgard.Create(pname, KaryonPkg, regions, phpcount, tname) asgard.Create(nname, KaryonPkg, regions, nodecount, tname) asgard.Create(zuname, ZuulPkg, regions, zuulcount, pname, nname) asgard.Create(elbname, ElbPkg, regions, 0, zuname) case 5: // added cassandra alongside mysql asgard.CreateChannels() asgard.CreateEureka() // service registries for each zone asgard.Create(cname, PriamCassandraPkg, regions, priamCassandracount, cname) asgard.Create(sname, StorePkg, regions, mysqlcount, sname) asgard.Create(mname, StorePkg, regions, mcount) asgard.Create(tname, StaashPkg, regions, staashcount, sname, mname, cname) asgard.Create(pname, KaryonPkg, regions, phpcount, tname) asgard.Create(nname, KaryonPkg, regions, nodecount, tname) asgard.Create(zuname, ZuulPkg, regions, zuulcount, pname, nname) asgard.Create(elbname, ElbPkg, regions, 0, zuname) case 6: // removed mysql so that multi-region will work properly asgard.CreateChannels() asgard.CreateEureka() // service registries for each zone asgard.Create(cname, PriamCassandraPkg, regions, priamCassandracount, cname) asgard.Create(mname, StorePkg, regions, mcount) asgard.Create(tname, StaashPkg, regions, staashcount, mname, cname) asgard.Create(pname, KaryonPkg, regions, phpcount, tname) asgard.Create(nname, KaryonPkg, regions, nodecount, tname) asgard.Create(zuname, ZuulPkg, regions, zuulcount, pname, nname) asgard.Create(elbname, ElbPkg, regions, 0, zuname) case 7: // set two regions with disconnected priamCassandra regions = 2 archaius.Conf.Regions = regions asgard.CreateChannels() asgard.CreateEureka() // service registries for each zone asgard.Create(cname, PriamCassandraPkg, regions, priamCassandracount, cname) asgard.Create(mname, StorePkg, regions, mcount) asgard.Create(tname, StaashPkg, regions, staashcount, mname, cname) asgard.Create(pname, KaryonPkg, regions, phpcount, tname) asgard.Create(nname, KaryonPkg, regions, nodecount, tname) asgard.Create(zuname, ZuulPkg, regions, zuulcount, pname, nname) asgard.Create(elbname, ElbPkg, regions, 0, zuname) case 8: // set two regions with connected priamCassandra regions = 2 archaius.Conf.Regions = regions asgard.CreateChannels() asgard.CreateEureka() // service registries for each zone asgard.Create(cname, PriamCassandraPkg, regions, priamCassandracount, "eureka", cname) asgard.Create(mname, StorePkg, regions, mcount) asgard.Create(tname, StaashPkg, regions, staashcount, mname, cname) asgard.Create(pname, KaryonPkg, regions, phpcount, tname) asgard.Create(nname, KaryonPkg, regions, nodecount, tname) asgard.Create(zuname, ZuulPkg, regions, zuulcount, pname, nname) asgard.Create(elbname, ElbPkg, regions, 0, zuname) case 9: // set three regions with disconnected priamCassandra regions = 3 archaius.Conf.Regions = regions asgard.CreateChannels() asgard.CreateEureka() // service registries for each zone asgard.Create(cname, PriamCassandraPkg, regions, priamCassandracount, "eureka", cname) asgard.Create(mname, StorePkg, regions, mcount) asgard.Create(tname, StaashPkg, regions, staashcount, mname, cname) asgard.Create(pname, KaryonPkg, regions, phpcount, tname) asgard.Create(nname, KaryonPkg, regions, nodecount, tname) asgard.Create(zuname, ZuulPkg, regions, zuulcount, pname, nname) asgard.Create(elbname, ElbPkg, regions, 0, zuname) } dnsname := asgard.Create(dns, DenominatorPkg, 0, 0, elbname) asgard.Run(dnsname, "") }