Apache Ignite и NUMA

Дащинский Иван

me

Введение

Введение. UMA

uma

Введение. NUMA

numa

NUMA. Cистемные вызовы

NUMA. Системные вызовы

Напрямую в glibc не реализовано, необходимо использовать libnuma

NUMA. Системные вызовы

MBIND — задание memory policy для аллоцированной памяти

void *numa_alloc_interleaved(size_t size, struct bitmask* bmp)
{
    char *mem;

    mem = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
    if (mem == (char *)-1)
        return NULL;

    if (mbind(mem, size, MPOL_INTERLEAVE, bmp ? bmp->maskkp : NULL, bmp ? bmp->size + 1 : 0, 0) < 0))
        return NULL;

    return mem;
}

void numa_free(void *mem, size_t size)
{
    munmap(mem, size);
}

NUMA. API libnuma

/** Аллокация */
void *numa_alloc_interleaved_subset(size_t size, struct bitmask *nodemask);
void *numa_alloc_interleaved(size_t size);
void *numa_alloc_onnode(size_t size, int node);
void *numa_alloc_local(size_t size);
void *numa_alloc(size_t size);

/** Работа с маской узлов */
int numa_max_node();
struct bitmask *numa_bitmask_alloc(unsigned int n);
void numa_bitmask_free(struct bitmask *bmp);
struct bitmask *numa_bitmask_setbit(struct bitmask *bmp, unsigned int n);
int numa_bitmask_isbitset(const struct bitmask *bmp, unsigned int n);

NUMA. Пример использования

union region_size {
    size_t size;
    max_align_t a;
};

template<typename Func, typename ...Args>
inline void *NumaAllocHelper(Func f, size_t size, Args ...args) {
    auto ptr = static_cast<region_size *>(f(size + sizeof(region_size), args...));
    if (ptr) {
        ptr->size = size;
        ptr++;
    }
    return ptr;
}

inline region_size* ConvertPointer(void* buf) {
    if (buf) {
        auto *ptr = static_cast<region_size *>(buf);
        ptr--;
        return ptr;
    }
    return nullptr;
}

NUMA. Пример использования

void *AllocInterleaved(size_t size, const BitSet &node_set) {
    return NumaAllocHelper(numa_alloc_interleaved_subset, size, node_set.p_impl_->Raw());
}

void Free(void *buf) {
    auto ptr = ConvertPointer(buf);
    if (ptr) {
        numa_free(ptr, ptr->size + sizeof(region_size));
    }
}

NUMA и GC

NUMA и GC. Включение

  • -XX:+UseNUMA

  • Работает на всех более-менее адекватных JVM (в том числе 8)

  • Аллоцирует кучу в режиме чередования, и это дает прирост производительности, но…​

NUMA и GC. Включение

Не NUMA-aware…​.

NUMA и GC. NUMA-aware

  • ZGC (с 11 версии)

  • G1 (c 14 версии, бекпорта на 11 для openjdk нет)

NUMA и GC. NUMA-aware. Инициализация

NUMA heap init

NUMA и GC. NUMA-aware. Страницы и регионы

NUMA region page

NUMA и GC. NUMA-aware. Surviving

NUMA survivor region

NUMA и Apache Ignite

NUMA и Apache Ignite. Требования

  • Linux (достаточно свежий, amd64)

  • libnuma 2.0.x

  • Apache Ignite 2.13

NUMA и Apache Ignite. Установка

$ sudo yum install numactl
$ sudo apt-get install numactl
$ mv libs/optional/numa-allocator libs

NUMA и Apache Ignite. SimpleNumaAllocationStrategy

Аллокация с политикой по-умолчанию, void* numa_alloc(size_t)

<property name="dataStorageConfiguration">
    <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
        <property name="defaultDataRegionConfiguration">
            <bean class="org.apache.ignite.configuration.DataRegionConfiguration">
                <property name="memoryAllocator">
                    <bean class="org.apache.ignite.mem.NumaAllocator">
                        <constructor-arg>
                            <bean class="org.apache.ignite.mem.SimpleNumaAllocationStrategy"/>
                        </constructor-arg>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
</property>

NUMA и Apache Ignite. SimpleNumaAllocationStrategy

Аллокация на выбранном NUMA-узле, void* numa_alloc_onnode(size_t, int)

<property name="dataStorageConfiguration">
    <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
        <property name="defaultDataRegionConfiguration">
            <bean class="org.apache.ignite.configuration.DataRegionConfiguration">
                <property name="memoryAllocator">
                    <bean class="org.apache.ignite.mem.NumaAllocator">
                        <constructor-arg>
                            <bean class="org.apache.ignite.mem.SimpleNumaAllocationStrategy">
                                <constructor-arg name="node" value="0"/>
                            </bean>
                        </constructor-arg>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
</property>

NUMA и Apache Ignite. LocalNumaAllocationStrategy

Аллокация на локальном NUMA-узле, void* numa_alloc_onnode(size_t)

<property name="dataStorageConfiguration">
    <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
        <property name="defaultDataRegionConfiguration">
            <bean class="org.apache.ignite.configuration.DataRegionConfiguration">
                <property name="memoryAllocator">
                    <bean class="org.apache.ignite.mem.NumaAllocator">
                        <constructor-arg>
                            <constructor-arg>
                                <bean class="org.apache.ignite.mem.LocalNumaAllocationStrategy"/>
                            </constructor-arg>
                        </constructor-arg>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
</property>

NUMA и Apache Ignite. InterleavedNumaAllocationStrategy

Аллокация с чередованием по NUMA-узлам, void* numa_alloc_interleaved(size_t)

<property name="dataStorageConfiguration">
    <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
        <property name="defaultDataRegionConfiguration">
            <bean class="org.apache.ignite.configuration.DataRegionConfiguration">
                <property name="memoryAllocator">
                    <bean class="org.apache.ignite.mem.NumaAllocator">
                        <constructor-arg>
                            <bean class="org.apache.ignite.mem.InterleavedNumaAllocationStrategy"/>
                        </constructor-arg>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
</property>

NUMA и Apache Ignite. InterleavedNumaAllocationStrategy

Аллокация с чередованием по выбранным NUMA-узлам,
void* numa_alloc_interleaved_subset(size_t, struct bitmask*)

<property name="dataStorageConfiguration">
    <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
        <property name="defaultDataRegionConfiguration">
            <bean class="org.apache.ignite.configuration.DataRegionConfiguration">
                <property name="memoryAllocator">
                    <bean class="org.apache.ignite.mem.NumaAllocator">
                        <constructor-arg>
                            <bean class="org.apache.ignite.mem.InterleavedNumaAllocationStrategy">
                                <constructor-arg name="nodes">
                                    <array>
                                        <value>0</value>
                                        <value>1</value>
                                    </array>
                                </constructor-arg>
                            </bean>
                        </constructor-arg>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
</property>

Ссылки