• cassandra 服务启动流程


    cassandra 服务启动流程

    1.  setup

    1)   CassandraDaemon ->main

     publicstaticvoidmain(String[]args)

       {

            instance.activate();

       }

    2)   系统參数初始化

        配置文件的读取和解析都是在org.apache.cassandra.config.DatabaseDescriptor 类中完毕的,这个类的作用很easy。就是读取配置文件里各个配置项所定义的值,经过简单的验证,符合条件就将其值赋给 DatabaseDescriptor 的私有静态常量。

    详细的实现步骤例如以下:

    DatabaseDescriptor.hasLargeAddressSpace() //载入了系统设置,静态变量,载入了系统的默认參数:

    ->applyConfig(loadConfig());

    以下是获取系统须要的表格。

    ->// Hardcoded system keyspaces

      List<KSMetaData> systemKeyspaces =Arrays.asList(KSMetaData.systemKeyspace());

           assert systemKeyspaces.size() == Schema.systemKeyspaceNames.size();

           for (KSMetaData ksmd : systemKeyspaces)

                Schema.instance.load(ksmd);

        ->每个表格写入到Schema

           /**

         *Load specific keyspace into Schema

         *

         *@param keyspaceDef The keyspace to load up

         *

         *@return self to support chaining calls

        */

       public Schema load(KSMetaData keyspaceDef)

        {

           for (CFMetaData cfm : keyspaceDef.cfMetaData().values())

               load(cfm);

           setKeyspaceDefinition(keyspaceDef);

           return this;

        }

    最后的cfm都是存放到:private final ConcurrentBiMap<Pair<String,String>, UUID> cfIdMap = new ConcurrentBiMap<>();

    上面的这段代码获取到系统须要默认的表格,可是这边还没有创建表格。

    3)  keyspacemeta

    a)        for(MemoryPoolMXBean pool:ManagementFactory.getMemoryPoolMXBeans())

    logger.info("{} {}: {}",pool.getName(), pool.getType(), pool.getPeakUsage());//输出cassandra jvm的全部pool的信息

    输出结果例如以下:

    INFO 07:20:32 Heap size: 124780544/954728448

    INFO 07:21:12 Code Cache Non-heap memory: init = 2555904(2496K) used =828800(809K) committed = 2555904(2496K) max = 50331648(49152K)

    INFO 07:21:28 PS Eden Space Heap memory: init = 33030144(32256K) used =33030144(32256K) committed = 33030144(32256K) max = 347602944(339456K)

    INFO 07:21:29 PS Survivor Space Heap memory: init = 5242880(5120K) used =5227632(5105K) committed = 5242880(5120K) max = 5242880(5120K)

    INFO 07:22:43 PS Old Gen Heap memory: init = 86507520(84480K) used =351840(343K) committed = 86507520(84480K) max = 715653120(698880K)

    INFO 07:22:49 PS Perm Gen Non-heap memory: init = 22020096(21504K) used =16674864(16284K) committed = 22020096(21504K) max = 85983232(83968K)

    b)        检查文件夹是否存在和权限

    c)        启动内存初始化

    private CacheService()

     {

    ............................................

           keyCache = initKeyCache();

           //keycache初始化

           rowCache = initRowCache();

            // rowCache初始化

           counterCache = initCounterCache();

          // counterCache处理化

       }

    以下我们分析keycache处理化的实现过程:

    private AutoSavingCache<KeyCacheKey,RowIndexEntry> initKeyCache() {

      longkeyCacheInMemoryCapacity = DatabaseDescriptor.getKeyCacheSizeInMB() * 1024 *1024;

      ICache<KeyCacheKey,RowIndexEntry> kc;

      kc =ConcurrentLinkedHashCache.create(keyCacheInMemoryCapacity);

     AutoSavingCache<KeyCacheKey,RowIndexEntry> keyCache = new AutoSavingCache<>(kc,CacheType.KEY_CACHE, new KeyCacheSerializer());

    int keyCacheKeysToSave =DatabaseDescriptor.getKeyCacheKeysToSave();

    keyCache.scheduleSaving(DatabaseDescriptor.getKeyCacheSavePeriod(),keyCacheKeysToSave);

           return keyCache;

       }

    分析ConcurrentLinkedHashCache.create(keyCacheInMemoryCapacity)实现过程:

    创建了一个:ConcurrentLinkedHashMap<K, V> map;存储所用cache。

    详细的创建步骤例如以下:

    ConcurrentLinkedHashMap<K, V> map =new ConcurrentLinkedHashMap.Builder<K, V>()

                                               .weigher(entryWeiger)

                                               .maximumWeightedCapacity(weightedCapacity)

                                               .concurrencyLevel(DEFAULT_CONCURENCY_LEVEL)

                                               .build();

    d)        initialize keyspaces

            for (String keyspaceName :Schema.instance.getKeyspaces())

            {

                if (logger.isDebugEnabled())

                    logger.debug("openingkeyspace {}", keyspaceName);

                // disable auto compaction untilcommit log replay ends

                for (ColumnFamilyStore cfs :Keyspace.open(keyspaceName).getColumnFamilyStores())

                {

                    for (ColumnFamilyStore store :cfs.concatWithIndexes())

                    {

                       store.disableAutoCompaction();//关闭完以后。关闭自己主动compaction功能

                    }

                }

            }

    4)  commlogrecover

    代码入口:CommitLog.instance.recover();

        为了保证系统出现异常情况。如今系统选择从系统默认的commitlog恢复日志。这里主要完毕这几个操作,发现是否有没有被写到磁盘的数据,恢复这个数据,构建新的日志文件。

    CommitLog 日志文件的恢复策略是,在头文件里发现没有被序列化的最新的ColumnFamily Id,然后取出这个这个被序列化 RowMutation 对象的起始地址。反序列化成为 RowMutation 对象,后面的操作和新添一条数据的流程是一样的。假设这个 RowMutation 对象中的数据被成功写到磁盘中。那么会在 CommitLog 去掉已经被持久化的 ColumnFamily Id。关于 CommitLog 日志文件的存储格式以及数据怎样写到 CommitLog 文件里。

    5)   auto compaction

    在启动过程中。须要让每一个keyspace去compaction。sstable的数据的也将flush到磁盘。全部假设在集群重新启动以后。这里会提交compact。

    详细的实现代码例如以下:

       if(store.getCompactionStrategy().shouldBeEnabled())

                           store.enableAutoCompaction();

    6)  GCInspectorregister

         GCInspector.instance.start 服务。主要是统计统计当前系统中资源的使用情况。将这个信息记录到日志文件里。这个能够作为系统的监控日志使用。

    7)  StorageService.instance.initServer()

    Ø  init StorageProxy

    Class.forName("org.apache.cassandra.service.StorageProxy");

    Ø  init IndexSummaryManager

    Class.forName("org.apache.cassandra.io.sstable.IndexSummaryManager");

    Ø  从系统peers获取该节点的ring和hostid;

    Ø  启动gossipservice,保证能够与其它节点通信;关于gossip怎么样通信。后面会具体分析其通信过程。

    Ø  HintedHandOffManager.instance.start();

    Ø  BatchlogManager.instance.start();

    Ø  MessagingService.instance().listen(FBUtilities.getLocalAddress());

    Ø  LoadBroadcaster.instance.startBroadcasting();

    Ø  Thift  init

    Ø  native transport int

    2.  start

    启动过程主要包括2个步骤:

    1)        nativeServer.start();

    2)        thriftServer.start();

       务启动工作已经setup步骤完毕;以下专门分析nativeServer的启动过程。nativeServer使用了netty的通信模型,Netty提供异步的、事件驱动的网络应用程序框架和工具,用以高速开发高性能、高可靠性的网络server和client程序。

    本文第四小节的代码是使用netty

    的example。读者感兴趣能够调试。

     nativeserver 详细设置例如以下:

    eventExecutorGroup = newRequestThreadPoolExecutor();

    workerGroup= newNioEventLoopGroup();

    ServerBootstrapbootstrap

     = new ServerBootstrap().group(workerGroup)

                         .channel(NioServerSocketChannel.class)

                         .childOption(ChannelOption.TCP_NODELAY,true)

                         .childOption(ChannelOption.SO_KEEPALIVE,DatabaseDescriptor.getRpcKeepAlive())

                          .childOption(ChannelOption.ALLOCATOR,CBUtil.allocator)

                          .childOption(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK,32 * 1024)

                          .childOption(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK,8 * 1024);

    在执行过程中,会对channel进行操作注冊:

    protected voidinitChannel(Channel channel) throws Exception

            {

                ChannelPipeline pipeline =channel.pipeline();

                //pipeline.addLast("debug",new LoggingHandler());

               pipeline.addLast("frameDecoder", newFrame.Decoder(server.connectionFactory));

                pipeline.addLast("frameEncoder",frameEncoder);

                pipeline.addLast("frameDecompressor",frameDecompressor);

                pipeline.addLast("frameCompressor",frameCompressor);

               pipeline.addLast("messageDecoder", messageDecoder);

                pipeline.addLast("messageEncoder",messageEncoder);

                pipeline.addLast(server.eventExecutorGroup,"executor", dispatcher);

            }

    3.  接受ConcurrentLinkedHashMap数据结构

    Cassandra 源代码里面具体该数据结构。实现了能够用来实现一个基于LRU策略的缓存。

    1)    linkedHashMap

    import java.util.HashMap;

    import java.util.Iterator;

    import java.util.LinkedHashMap;

    import java.util.Map;

    public class TestLinkedHashMap {

      public static void main(String args[])

      {

       System.out.println("*************************LinkedHashMap*************");

       Map<Integer,String>map = new LinkedHashMap<Integer,String>();

       map.put(6, "apple");

       map.put(3, "banana");

       map.put(2,"pear");

       for (Iterator it = map.keySet().iterator();it.hasNext();)

       {

        Objectkey = it.next();

        System.out.println(key+"="+ map.get(key));

       }

       System.out.println("*************************HashMap*************");

       Map<Integer,String>map1 = new  HashMap<Integer,String>();

       map1.put(6, "apple");

       map1.put(3, "banana");

       map1.put(2,"pear");

       for (Iterator it = map1.keySet().iterator();it.hasNext();)

       {

        Objectkey = it.next();

        System.out.println(key+"="+ map1.get(key));

       }

      }

    }

    输出:

    执行结果例如以下:

    *************************LinkedHashMap*************
    6=apple
    3=banana
    2=pear
    *************************HashMap**************************
    2=pear
    6=apple
    3=banana

    分析:

    l   LinkedHashmap的特点是put进去的对象位置未发生变化,HashMap会发生变化;

    l   LinkedHashMap非线程安全 须要採用googleConcurrentLinkedHashMaphttps://code.google.com/p/concurrentlinkedhashmap/

    l   能够实现last recently used 功能

    2)    ConcurrentLinkedHashMap

    ConcurrentHashMap的封装。能够用来实现一个基于LRU策略的缓存.

    public static voidmain(String[] args) {

    ConcurrentLinkedHashMap<Integer,Integer> map = new

    ConcurrentLinkedHashMap.Builder<Integer,Integer>().maximumWeightedCapacity(2);

    weigher(Weighers.singleton()).build();

    map.put(1, 1); 

    map.put(2, 2); 

    map.put(3, 3); 

    System.out.println(map.get(1));//null已经失效了 

    System.out.println(map.get(2));

    }

    3)    总体架构

    l  它本质是额外维护了一个双向链表。每次读和写都要改变对应节点的位置。将其移至队列头;

    l  什么时候推断easy已经满了,是依据weight。每一个元素都有一个weight,每添加一个元素。weight累计。

    l  当达到最大值的时候,就须要剔除最少操作的那个元素了,而且触发相关的事件;


  • 相关阅读:
    python3安装 MAC
    MacOS三个比较接地气实用的终端命令
    maya界面字体怎么设置大小?
    Mac 下 Android Studio 连 夜神模拟器 调试以及真机调试方法
    [macOS] Mojave10.14 夜神安卓模拟器启动问题
    解决MAC电脑系统设置的安全性与隐私下通用没有任何来源选项
    一个分析“文件夹”选择框实现方法的过程
    windows下nginx+php简单配置
    使用windbg抓取崩溃文件和分析的过程
    解决工作中遇到的一个"打开,保存"文件框的bug的过程
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5099144.html
Copyright © 2020-2023  润新知