Gossip事始め株式会社ムロドーとみたかずたか
アジェンダGossip事始めコードリーディングの準備デーモン起動起動準備デーモン初期化Gossip開始
コードリーディング下準備Eclpseでstepbystep 実行を行う。用意するもの面倒くさいのでpleiadesonGlileo を用意
ApacheCassandra0.6.3
Cassandra クラスターEclpseのセッティングstepbystep 実行の設定で結構手間取った。Ecplseを適当なディレクトリに展開し起動を行う。
EclpseのセッティングEcplseでCassandraのソースを読み込みプロジェクトを作成。Cassandraのソースディレクトリを直接指定。直接buildを行う為、要注意。Binディレクトリを吹っ飛ばしたり別途ソースを使いまわすことが不可能になります。
EclpseのセッティングCassandraのBuild。Build.xmlを右クリックし実行タブから外部ツールの構成を選択。Targetからbuildとjarを選択
EclpseのセッティングEclipse上部から実行->実行の構成を選択し構成の作成、管理画面を表示Cassandraの実行構成の設定メインクラスに「org.apache.cassandra.thrift.CassandraDaemon」を指定
EclpseのセッティングCassandraの実行構成の設定引き続き引数タブを選択引数に-Dcom.sun.management.jmxremote.port=8080-Dcom.sun.management.jmxremote.ssl=false-Dcom.sun.management.jmxremote.authenticate=false-Dcassandra-Dstorage-config="C:\Users\kazutaka\Downloads\apache-cassandra-0.6.3-src\conf"-Dcassandra-foreground=yesを設定(少なくとも「Dstorage-config」は必要なようです。
EclpseのセッティングCassandraのStepByStep実行Debugのパースペクティブを開きデバック実行
デーモン起動Main関数直後にsetupメソッドがあります。 public static void main(String[] args)    {CassandraDaemon daemon = new CassandraDaemon();        String pidFile = System.getProperty("cassandra-pidfile");        try        {   daemon.setup();203204205206207208209210211212
デーモン起動Main直後にsetupメソッドがあります。 public static void main(String[] args)    {CassandraDaemon daemon = new CassandraDaemon();        String pidFile = System.getProperty("cassandra-pidfile");        try        {   daemon.setup();203204205206207208209210211212
デーモン起動Setup内サーバー初期化まで。63    private void setup() throws IOException, TTransportException64    {~~~~69      intlistenPort = DatabaseDescriptor.getThriftPort();70      InetAddresslistenAddr = DatabaseDescriptor.getThriftAddress();~~~~92      try93      {94          SystemTable.checkHealth();95      }~~~~111     CommitLog.recover();112     CompactionManager.instance.checkAllColumnFamilies();~~~~114     // start server internals115     StorageService.instance.initServer();ローカルのIPとポートを取得システムテーブルのチェックCommitログの読み込みと内容のチェック、リカバリーなど初期化開始ここまでorg.apache.cassandra.thrift.CassandraDaemon
デーモン起動Setup内サーバー初期化まで。63    private void setup() throws IOException, TTransportException64    {~~~~69      intlistenPort = DatabaseDescriptor.getThriftPort();70      InetAddresslistenAddr = DatabaseDescriptor.getThriftAddress();~~~~92      try93      {94          SystemTable.checkHealth();95      }~~~~111     CommitLog.recover();112     CompactionManager.instance.checkAllColumnFamilies();~~~~114     // start server internals115     StorageService.instance.initServer();ローカルのIPとポートを取得システムテーブルのチェックCommitログの読み込みと内容のチェック、リカバリーなど初期化開始ここまでorg.apache.cassandra.thrift.CassandraDaemon
相互認知org.apache.cassandra.service.StorageServiceinitServer304        initialized = true;305        isClientMode = false;306        storageMetadata_ = SystemTable.initMetadata();307308        // be certain that the recorded clustername matches what the user specified309        if (!(Arrays.equals(storageMetadata_.getClusterName(),DatabaseDescriptor.getClusterName().getBytes())))310        {311            logger_.error("ClusterName mismatch: " + new String(storageMetadata_.getClusterName()) + " != " +312                    DatabaseDescriptor.getClusterName());313            System.exit(3);314        }315316        DatabaseDescriptor.createAllDirectories();最初に自分自身の初期化を行う。クラスターネーム、キースペース、トークンなどメタ情報取得など
ゴシップ開始org.apache.cassandra.service.StorageService327        logger_.info("Starting up server gossip");328329        // have to start the gossip service before we can see any info on other nodes.  this is necessary330        // for bootstrap to get the load info it needs.331        // (we won't be part of the storage ring though until we add a nodeId to our state, below.)332        Gossiper.instance.register(this);333Gossiper.instance.start(FBUtilities.getLocalAddress(), storageMetadata_.getGeneration()); // needed for node-ring gathering.「start」の最初にローカルのアドレスを取得。(FBUtilities.getLocalAddress)私たちが、他のノードの情報を見ることができる前にゴシップサービスは始めなければなりません。これは、「bootstrap」が必要とする負荷の情報を得る為に必要です。もっとも、私たちは「nodeid」を私たちのstateに追加するまでストレージ・リングの一部でなくなるでしょう。
ゴシップ開始2org.apache.cassandra.gms.Gossiper838    public void start(InetAddresslocalEndPoint, intgenerationNbr)839    {840        localEndPoint_ = localEndPoint;841        /* Get the seeds from the config and initialize them. */842        Set<InetAddress> seedHosts = DatabaseDescriptor.getSeeds();843        for (InetAddress seed : seedHosts)844        {845            if (seed.equals(localEndPoint))846                continue;847            seeds_.add(seed);848        }Seedsより自分以外のIPを取得
ゴシップ開始3org.apache.cassandra.gms.Gossiper351        /* initialize the heartbeat state for this localEndPoint */352        EndPointStatelocalState = endPointStateMap_.get(localEndPoint_);353        if ( localState == null )354        {355            HeartBeatStatehbState = new HeartBeatState(generationNbr);356            localState = new EndPointState(hbState);357            localState.isAlive(true);358            localState.isAGossiper(true);359            endPointStateMap_.put(localEndPoint_, localState);360        }自分のハートビートステータスを取得
ゴシップ開始4org.apache.cassandra.gms.Gossiper361        /* starts a timer thread */362        gossipTimer_.schedule( new GossipTimerTask(), Gossiper.intervalInMillis_, Gossiper.intervalInMillis_);GossipTimerTask起動!  public final static intintervalInMillis_ = 1000;というところで1000ミリ秒間隔でタイマー起動
GossipTimerTaskorg.apache.cassandra.gms.Gossiperprivate class GossipTimerTask extends TimerTask{    public void run()    {        try        {MessagingService.instance.waitUntilListening();            synchronized( Gossiper.instance )            {endPointStateMap_.get(localEndPoint_).getHeartBeatState().updateHeartBeat();                List<GossipDigest> gDigests = new ArrayList<GossipDigest>();Gossiper.instance.makeRandomGossipDigest(gDigests);                if ( gDigests.size() > 0 )                {                    Message message = makeGossipDigestSynMessage(gDigests);booleangossipedToSeed = doGossipToLiveMember(message);doGossipToUnreachableMember(message);                    if (!gossipedToSeed || liveEndpoints_.size() < seeds_.size())doGossipToSeed(message);                    if (logger_.isTraceEnabled())logger_.trace("Performing status check ...");doStatusCheck();                }            }        }        catch (Exception e)        {            throw new RuntimeException(e);        }    }}GossipTimerTask親abstractクラスにてRunnableのインターフェースを実装。Runにてスレッド開始1000ミリ秒ごとにハートビートを交換。

Gossip事始め