2016-06-03 09:09:14 +08:00
package command
2013-12-04 15:22:26 +08:00
import (
2019-04-30 11:22:19 +08:00
"fmt"
2013-12-04 15:22:26 +08:00
"net/http"
"os"
"runtime"
2014-05-08 01:17:06 +08:00
"runtime/pprof"
2013-12-04 15:22:26 +08:00
"strconv"
"strings"
2014-03-16 14:03:49 +08:00
"sync"
2013-12-04 15:22:26 +08:00
"time"
2014-10-27 02:34:55 +08:00
2019-06-05 16:30:24 +08:00
"github.com/chrislusf/raft/protobuf"
"github.com/chrislusf/seaweedfs/weed/security"
"github.com/spf13/viper"
2016-06-03 09:09:14 +08:00
"github.com/chrislusf/seaweedfs/weed/glog"
2018-05-10 14:11:54 +08:00
"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
2016-06-03 09:09:14 +08:00
"github.com/chrislusf/seaweedfs/weed/server"
2018-10-11 15:05:54 +08:00
"github.com/chrislusf/seaweedfs/weed/util"
2014-10-27 02:34:55 +08:00
"github.com/gorilla/mux"
2017-01-10 17:01:12 +08:00
"google.golang.org/grpc/reflection"
2013-12-04 15:22:26 +08:00
)
2014-05-08 01:17:06 +08:00
type ServerOptions struct {
2019-06-18 05:51:47 +08:00
cpuprofile * string
v VolumeServerOptions
2014-05-08 01:17:06 +08:00
}
2014-03-31 11:57:25 +08:00
var (
2014-05-08 01:17:06 +08:00
serverOptions ServerOptions
2014-05-13 15:03:10 +08:00
filerOptions FilerOptions
2019-04-24 15:18:01 +08:00
s3Options S3Options
2014-03-31 11:57:25 +08:00
)
2013-12-04 15:22:26 +08:00
func init ( ) {
cmdServer . Run = runServer // break init cycle
}
var cmdServer = & Command {
2014-05-27 08:34:54 +08:00
UsageLine : "server -port=8080 -dir=/tmp -volume.max=5 -ip=server_name" ,
2019-04-24 15:25:20 +08:00
Short : "start a master server, a volume server, and optionally a filer and a S3 gateway" ,
2014-11-29 08:34:03 +08:00
Long : ` start both a volume server to provide storage spaces
2013-12-04 15:22:26 +08:00
and a master server to provide volume = > location mapping service and sequence number of file ids
2014-11-29 08:34:03 +08:00
2013-12-04 15:22:26 +08:00
This is provided as a convenient way to start both volume server and master server .
2019-04-24 15:25:20 +08:00
The servers acts exactly the same as starting them separately .
So other volume servers can connect to this master server also .
2014-04-26 13:09:42 +08:00
2019-04-24 15:25:20 +08:00
Optionally , a filer server can be started .
Also optionally , a S3 gateway can be started .
2019-04-24 15:18:01 +08:00
2013-12-04 15:22:26 +08:00
` ,
}
var (
2015-02-12 13:04:43 +08:00
serverIp = cmdServer . Flag . String ( "ip" , "localhost" , "ip or server name" )
2014-09-21 14:34:13 +08:00
serverBindIp = cmdServer . Flag . String ( "ip.bind" , "0.0.0.0" , "ip address to bind to" )
2014-03-03 14:16:54 +08:00
serverMaxCpu = cmdServer . Flag . Int ( "maxCpu" , 0 , "maximum number of CPUs. 0 means all available CPUs" )
2017-01-10 17:01:12 +08:00
serverTimeout = cmdServer . Flag . Int ( "idleTimeout" , 30 , "connection idle seconds" )
2014-03-03 14:16:54 +08:00
serverDataCenter = cmdServer . Flag . String ( "dataCenter" , "" , "current volume server's data center name" )
serverRack = cmdServer . Flag . String ( "rack" , "" , "current volume server's rack name" )
2016-08-06 05:45:48 +08:00
serverWhiteListOption = cmdServer . Flag . String ( "whiteList" , "" , "comma separated Ip addresses having write permission. No limit if empty." )
2019-03-22 07:00:46 +08:00
serverDisableHttp = cmdServer . Flag . Bool ( "disableHttp" , false , "disable http requests, only gRPC operations are allowed." )
2018-08-13 05:25:31 +08:00
serverPeers = cmdServer . Flag . String ( "master.peers" , "" , "all master nodes in comma separated ip:masterPort list" )
2018-10-15 14:12:43 +08:00
serverGarbageThreshold = cmdServer . Flag . Float64 ( "garbageThreshold" , 0.3 , "threshold to vacuum and reclaim spaces" )
2019-06-18 05:51:47 +08:00
serverMetricsAddress = cmdServer . Flag . String ( "metrics.address" , "" , "Prometheus gateway address" )
serverMetricsIntervalSec = cmdServer . Flag . Int ( "metrics.intervalSeconds" , 15 , "Prometheus push interval in seconds" )
2014-04-26 13:09:42 +08:00
masterPort = cmdServer . Flag . Int ( "master.port" , 9333 , "master server http listen port" )
masterMetaFolder = cmdServer . Flag . String ( "master.dir" , "" , "data directory to store meta data, default to same as -dir specified" )
masterVolumeSizeLimitMB = cmdServer . Flag . Uint ( "master.volumeSizeLimitMB" , 30 * 1000 , "Master stops directing writes to oversized volumes." )
2017-01-09 03:01:46 +08:00
masterVolumePreallocate = cmdServer . Flag . Bool ( "master.volumePreallocate" , false , "Preallocate disk space for volumes." )
2014-04-26 13:09:42 +08:00
masterDefaultReplicaPlacement = cmdServer . Flag . String ( "master.defaultReplicaPlacement" , "000" , "Default replication type if not specified." )
2014-03-03 14:16:54 +08:00
volumeDataFolders = cmdServer . Flag . String ( "dir" , os . TempDir ( ) , "directories to store data files. dir[,dir]..." )
2014-04-26 13:09:42 +08:00
volumeMaxDataVolumeCounts = cmdServer . Flag . String ( "volume.max" , "7" , "maximum numbers of volumes, count[,count]..." )
2018-10-11 15:04:31 +08:00
pulseSeconds = cmdServer . Flag . Int ( "pulseSeconds" , 5 , "number of seconds between heartbeats" )
2014-03-31 11:57:25 +08:00
isStartingFiler = cmdServer . Flag . Bool ( "filer" , false , "whether to start filer" )
2019-04-24 15:18:01 +08:00
isStartingS3 = cmdServer . Flag . Bool ( "s3" , false , "whether to start S3 gateway" )
2013-12-04 15:22:26 +08:00
2016-08-06 05:45:48 +08:00
serverWhiteList [ ] string
2013-12-04 15:22:26 +08:00
)
2014-03-31 11:57:25 +08:00
func init ( ) {
2014-11-29 08:34:03 +08:00
serverOptions . cpuprofile = cmdServer . Flag . String ( "cpuprofile" , "" , "cpu profile output file" )
2014-05-13 15:03:10 +08:00
filerOptions . collection = cmdServer . Flag . String ( "filer.collection" , "" , "all data will be stored in this collection" )
filerOptions . port = cmdServer . Flag . Int ( "filer.port" , 8888 , "filer server http listen port" )
2017-05-28 11:14:22 +08:00
filerOptions . publicPort = cmdServer . Flag . Int ( "filer.port.public" , 0 , "filer server public http listen port" )
2014-05-13 15:03:10 +08:00
filerOptions . defaultReplicaPlacement = cmdServer . Flag . String ( "filer.defaultReplicaPlacement" , "" , "Default replication type if not specified during runtime." )
2014-12-09 12:27:26 +08:00
filerOptions . redirectOnRead = cmdServer . Flag . Bool ( "filer.redirectOnRead" , false , "whether proxy or redirect to volume server during file GET request" )
2015-04-14 14:38:46 +08:00
filerOptions . disableDirListing = cmdServer . Flag . Bool ( "filer.disableDirListing" , false , "turn off directory listing" )
2017-09-15 23:24:30 +08:00
filerOptions . maxMB = cmdServer . Flag . Int ( "filer.maxMB" , 32 , "split files larger than the limit" )
2018-07-08 17:11:36 +08:00
filerOptions . dirListingLimit = cmdServer . Flag . Int ( "filer.dirListLimit" , 1000 , "limit sub dir listing size" )
2018-10-11 15:04:31 +08:00
serverOptions . v . port = cmdServer . Flag . Int ( "volume.port" , 8080 , "volume server http listen port" )
serverOptions . v . publicPort = cmdServer . Flag . Int ( "volume.port.public" , 0 , "volume server public port" )
2019-04-10 00:42:06 +08:00
serverOptions . v . indexType = cmdServer . Flag . String ( "volume.index" , "memory" , "Choose [memory|leveldb|leveldbMedium|leveldbLarge] mode for memory~performance balance." )
2018-11-22 08:50:42 +08:00
serverOptions . v . fixJpgOrientation = cmdServer . Flag . Bool ( "volume.images.fix.orientation" , false , "Adjust jpg orientation when uploading." )
2018-10-11 15:04:31 +08:00
serverOptions . v . readRedirect = cmdServer . Flag . Bool ( "volume.read.redirect" , true , "Redirect moved or non-local volumes." )
2019-05-04 08:22:39 +08:00
serverOptions . v . compactionMBPerSecond = cmdServer . Flag . Int ( "volume.compactionMBps" , 0 , "limit compaction speed in mega bytes per second" )
2018-10-11 15:04:31 +08:00
serverOptions . v . publicUrl = cmdServer . Flag . String ( "volume.publicUrl" , "" , "publicly accessible address" )
2019-04-24 15:18:01 +08:00
s3Options . filerBucketsPath = cmdServer . Flag . String ( "s3.filer.dir.buckets" , "/buckets" , "folder on filer to store all buckets" )
s3Options . port = cmdServer . Flag . Int ( "s3.port" , 8333 , "s3 server http listen port" )
s3Options . domainName = cmdServer . Flag . String ( "s3.domainName" , "" , "suffix of the host name, {bucket}.{domainName}" )
s3Options . tlsPrivateKey = cmdServer . Flag . String ( "s3.key.file" , "" , "path to the TLS private key file" )
s3Options . tlsCertificate = cmdServer . Flag . String ( "s3.cert.file" , "" , "path to the TLS certificate file" )
2014-03-31 11:57:25 +08:00
}
2013-12-04 15:22:26 +08:00
func runServer ( cmd * Command , args [ ] string ) bool {
2019-02-19 04:11:52 +08:00
2019-06-05 16:30:24 +08:00
util . LoadConfiguration ( "security" , false )
util . LoadConfiguration ( "master" , false )
2019-02-19 04:11:52 +08:00
2014-05-08 01:17:06 +08:00
if * serverOptions . cpuprofile != "" {
f , err := os . Create ( * serverOptions . cpuprofile )
if err != nil {
glog . Fatal ( err )
}
pprof . StartCPUProfile ( f )
defer pprof . StopCPUProfile ( )
}
2014-03-31 11:57:25 +08:00
2014-12-14 16:33:16 +08:00
if * filerOptions . redirectOnRead {
* isStartingFiler = true
}
2019-04-24 15:18:01 +08:00
if * isStartingS3 {
* isStartingFiler = true
}
2018-06-01 15:39:39 +08:00
master := * serverIp + ":" + strconv . Itoa ( * masterPort )
2019-03-15 15:32:42 +08:00
filerOptions . masters = & master
2019-05-15 14:43:40 +08:00
filerOptions . ip = serverBindIp
2018-10-11 15:04:31 +08:00
serverOptions . v . ip = serverIp
serverOptions . v . bindIp = serverBindIp
serverOptions . v . masters = & master
serverOptions . v . idleConnectionTimeout = serverTimeout
serverOptions . v . maxCpu = serverMaxCpu
serverOptions . v . dataCenter = serverDataCenter
serverOptions . v . rack = serverRack
serverOptions . v . pulseSeconds = pulseSeconds
2014-03-31 11:57:25 +08:00
2018-07-09 17:22:48 +08:00
filerOptions . dataCenter = serverDataCenter
2019-03-22 07:00:46 +08:00
filerOptions . disableHttp = serverDisableHttp
2018-07-09 17:22:48 +08:00
2019-06-18 05:51:47 +08:00
filerOptions . metricsAddress = serverMetricsAddress
filerOptions . metricsIntervalSec = serverMetricsIntervalSec
2019-06-13 17:01:51 +08:00
2019-04-24 15:18:01 +08:00
filerAddress := fmt . Sprintf ( "%s:%d" , * serverIp , * filerOptions . port )
s3Options . filer = & filerAddress
2014-05-13 15:03:10 +08:00
if * filerOptions . defaultReplicaPlacement == "" {
* filerOptions . defaultReplicaPlacement = * masterDefaultReplicaPlacement
2014-03-31 11:57:25 +08:00
}
2013-12-04 15:22:26 +08:00
if * serverMaxCpu < 1 {
* serverMaxCpu = runtime . NumCPU ( )
}
runtime . GOMAXPROCS ( * serverMaxCpu )
folders := strings . Split ( * volumeDataFolders , "," )
2019-04-09 13:32:42 +08:00
if * masterVolumeSizeLimitMB > util . VolumeSizeLimitGB * 1000 {
2017-07-17 12:40:47 +08:00
glog . Fatalf ( "masterVolumeSizeLimitMB should be less than 30000" )
}
2014-03-31 11:57:25 +08:00
if * masterMetaFolder == "" {
* masterMetaFolder = folders [ 0 ]
}
if err := util . TestFolderWritable ( * masterMetaFolder ) ; err != nil {
glog . Fatalf ( "Check Meta Folder (-mdir=\"%s\") Writable: %s" , * masterMetaFolder , err )
}
2018-12-06 15:24:25 +08:00
filerOptions . defaultLevelDbDirectory = masterMetaFolder
2014-03-31 11:57:25 +08:00
2016-08-06 05:45:48 +08:00
if * serverWhiteListOption != "" {
serverWhiteList = strings . Split ( * serverWhiteListOption , "," )
2013-12-04 15:22:26 +08:00
}
2014-03-31 11:57:25 +08:00
if * isStartingFiler {
go func ( ) {
2016-07-21 14:45:55 +08:00
time . Sleep ( 1 * time . Second )
2017-05-28 11:14:22 +08:00
2018-10-11 14:19:54 +08:00
filerOptions . startFiler ( )
2017-05-28 11:14:22 +08:00
2014-03-31 11:57:25 +08:00
} ( )
}
2014-03-31 02:28:04 +08:00
2019-04-24 15:18:01 +08:00
if * isStartingS3 {
go func ( ) {
time . Sleep ( 2 * time . Second )
s3Options . startS3Server ( )
} ( )
}
2014-03-16 14:03:49 +08:00
var volumeWait sync . WaitGroup
volumeWait . Add ( 1 )
2013-12-04 15:22:26 +08:00
go func ( ) {
r := mux . NewRouter ( )
2014-03-26 04:46:59 +08:00
ms := weed_server . NewMasterServer ( r , * masterPort , * masterMetaFolder ,
2017-01-09 03:01:46 +08:00
* masterVolumeSizeLimitMB , * masterVolumePreallocate ,
2018-10-11 15:04:31 +08:00
* pulseSeconds , * masterDefaultReplicaPlacement , * serverGarbageThreshold ,
2019-03-22 07:00:46 +08:00
serverWhiteList , * serverDisableHttp ,
2019-06-18 05:51:47 +08:00
* serverMetricsAddress , * serverMetricsIntervalSec ,
2013-12-04 15:22:26 +08:00
)
2018-12-17 09:37:10 +08:00
glog . V ( 0 ) . Infof ( "Start Seaweed Master %s at %s:%d" , util . VERSION , * serverIp , * masterPort )
2017-01-10 17:30:00 +08:00
masterListener , e := util . NewListener ( * serverBindIp + ":" + strconv . Itoa ( * masterPort ) , 0 )
2014-03-21 02:07:15 +08:00
if e != nil {
2015-01-14 09:04:41 +08:00
glog . Fatalf ( "Master startup error: %v" , e )
2013-12-04 15:22:26 +08:00
}
2013-12-10 05:27:09 +08:00
2019-01-19 06:14:47 +08:00
go func ( ) {
2019-02-19 14:38:14 +08:00
// start raftServer
2019-03-07 02:21:49 +08:00
myMasterAddress , peers := checkPeers ( * serverIp , * masterPort , * serverPeers )
2019-02-19 14:38:14 +08:00
raftServer := weed_server . NewRaftServer ( security . LoadClientTLS ( viper . Sub ( "grpc" ) , "master" ) ,
2019-03-07 02:21:49 +08:00
peers , myMasterAddress , * masterMetaFolder , ms . Topo , * pulseSeconds )
2019-02-19 14:38:14 +08:00
ms . SetRaftServer ( raftServer )
2019-03-07 04:10:45 +08:00
r . HandleFunc ( "/cluster/status" , raftServer . StatusHandler ) . Methods ( "GET" )
2019-02-19 14:38:14 +08:00
2019-01-19 06:14:47 +08:00
// starting grpc server
2019-02-19 14:38:14 +08:00
grpcPort := * masterPort + 10000
2019-05-06 23:10:18 +08:00
grpcL , err := util . NewListener ( * serverBindIp + ":" + strconv . Itoa ( grpcPort ) , 0 )
2019-01-19 06:14:47 +08:00
if err != nil {
glog . Fatalf ( "master failed to listen on grpc port %d: %v" , grpcPort , err )
}
// Create your protocol servers.
2019-05-22 13:41:20 +08:00
glog . V ( 1 ) . Infof ( "grpc config %+v" , viper . Sub ( "grpc" ) )
2019-02-19 04:11:52 +08:00
grpcS := util . NewGrpcServer ( security . LoadServerTLS ( viper . Sub ( "grpc" ) , "master" ) )
2019-01-19 06:14:47 +08:00
master_pb . RegisterSeaweedServer ( grpcS , ms )
2019-02-19 14:38:14 +08:00
protobuf . RegisterRaftServer ( grpcS , raftServer )
2019-01-19 06:14:47 +08:00
reflection . Register ( grpcS )
glog . V ( 0 ) . Infof ( "Start Seaweed Master %s grpc server at %s:%d" , util . VERSION , * serverIp , grpcPort )
grpcS . Serve ( grpcL )
} ( )
2019-02-19 14:38:14 +08:00
volumeWait . Done ( )
2017-01-10 17:01:12 +08:00
2019-01-19 06:14:47 +08:00
// start http server
2017-01-10 17:01:12 +08:00
httpS := & http . Server { Handler : r }
2019-01-19 06:14:47 +08:00
if err := httpS . Serve ( masterListener ) ; err != nil {
2017-01-10 17:01:12 +08:00
glog . Fatalf ( "master server failed to serve: %v" , err )
2013-12-04 15:22:26 +08:00
}
2017-01-10 17:01:12 +08:00
2013-12-04 15:22:26 +08:00
} ( )
2014-03-16 14:03:49 +08:00
volumeWait . Wait ( )
2013-12-10 05:27:09 +08:00
time . Sleep ( 100 * time . Millisecond )
2014-05-13 15:03:10 +08:00
2018-10-11 15:04:31 +08:00
serverOptions . v . startVolumeServer ( * volumeDataFolders , * volumeMaxDataVolumeCounts , * serverWhiteListOption )
2013-12-04 15:22:26 +08:00
return true
}