Версия:

Просмотр состояния сервера

Просмотр состояния сервера

Использование Tarantool’а в качестве клиента

Tarantool входит в интерактивный режим, если:

Tarantool выводит приглашение командной строки (например, «tarantool>») – и вы можете посылать запросы. Если использовать Tarantool таким образом, он может выступать клиентом для удаленного сервера, см. простые примеры в Руководстве для начинающих.

Скрипт tarantoolctl использует интерактивный режим для реализации команд «enter» и «connect».

Выполнение кода на экземпляре Tarantool’а

Можно подключиться к административной консоли экземпляра и выполнить некий Lua-код с помощью утилиты tarantoolctl:

$ # для локальных экземпляров:
  $ tarantoolctl enter my_app
  /bin/tarantoolctl: Found my_app.lua in /etc/tarantool/instances.available
  /bin/tarantoolctl: Connecting to /var/run/tarantool/my_app.control
  /bin/tarantoolctl: connected to unix/:/var/run/tarantool/my_app.control
  unix/:/var/run/tarantool/my_app.control> 1 + 1
  ---
  - 2
  ...
  unix/:/var/run/tarantool/my_app.control>

  $ # для локальных и удаленных экземпляров:
  $ tarantoolctl connect username:password@127.0.0.1:3306

Можно также использовать tarantoolctl для выполнения Lua-кода на запущенном экземпляре Tarantool-сервера, не подключаясь к его административной консоли. Например:

$ # выполнение команд напрямую из командной строки
  $ <command> | tarantoolctl eval my_app
  <...>

  $ # - ИЛИ -

  $ # выполнение команд из скрипта
  $ tarantoolctl eval my_app script.lua
  <...>

Примечание

Еще можно использовать модули console и net.box из Tarantool-сервера. Также вы можете писать свои клиентские программы с использованием любого из доступных коннекторов. Однако большинство примеров в данном документе использует или tarantoolctl connect, или Tarantool-сервер как клиент.

Проверка состояния экземпляра

Чтобы проверить статус экземпляра Tarantool-сервера, выполните команду:

$ tarantoolctl status my_app
  my_app is running (pid: /var/run/tarantool/my_app.pid)

  $ # - ИЛИ -

  $ systemctl status tarantool@my_app
  tarantool@my_app.service - Tarantool Database Server
  Loaded: loaded (/etc/systemd/system/tarantool@.service; disabled; vendor preset: disabled)
  Active: active (running)
  Docs: man:tarantool(1)
  Process: 5346 ExecStart=/usr/bin/tarantoolctl start %I (code=exited, status=0/SUCCESS)
  Main PID: 5350 (tarantool)
  Tasks: 11 (limit: 512)
  CGroup: /system.slice/system-tarantool.slice/tarantool@my_app.service
  + 5350 tarantool my_app.lua <running>

Если вы используете систему, на которой доступна утилита systemd, выполните следующую команду для проверки содержимого журнала загрузки:

$ journalctl -u tarantool@my_app -n 5
  -- Logs begin at Fri 2016-01-08 12:21:53 MSK, end at Thu 2016-01-21 21:17:47 MSK. --
  Jan 21 21:17:47 localhost.localdomain systemd[1]: Stopped Tarantool Database Server.
  Jan 21 21:17:47 localhost.localdomain systemd[1]: Starting Tarantool Database Server...
  Jan 21 21:17:47 localhost.localdomain tarantoolctl[5969]: /usr/bin/tarantoolctl: Found my_app.lua in /etc/tarantool/instances.available
  Jan 21 21:17:47 localhost.localdomain tarantoolctl[5969]: /usr/bin/tarantoolctl: Starting instance...
  Jan 21 21:17:47 localhost.localdomain systemd[1]: Started Tarantool Database Server

Более подробная информация содержится в отчетах, которые можно получить с помощью функций из следующих подмодулей:

  • box.cfg – проверка и указание всех конфигурационных параметров Tarantool-сервера,
  • box.slab – мониторинг использования и фрагментированности памяти, выделенной для хранения данных в Tarantool’е,
  • box.info – просмотр переменных Tarantool-сервера – в первую очередь тех, что относятся к репликации,
  • box.stat – просмотр статистики Tarantool’а по запросам и использованию сети,

Можно также попробовать воспользоваться Lua-модулем tarantool/prometheus, который облегчает сбор метрик (например, использование памяти или количество запросов) с Tarantool-приложений и баз данных и их публикацию через протокол Prometheus.

Пример

Очень часто администраторам приходится вызывать функцию box.slab.info(), которая показывает подробную статистику по использованию памяти для конкретного экземпляра Tarantool’а.

tarantool> box.slab.info()
  ---
  - items_size: 228128
    items_used_ratio: 1.8%
    quota_size: 1073741824
    quota_used_ratio: 0.8%
    arena_used_ratio: 43.2%
    items_used: 4208
    quota_used: 8388608
    arena_size: 2325176
    arena_used: 1003632
  ...

Tarantool занимает память операционной системы, например, когда пользователь вставляет много данных. Можно проверить, сколько памяти занято, выполнив команду (в Linux):

ps -eo args,%mem | grep "tarantool"

Tarantool almost never releases this memory, even if the user deletes everything that was inserted, or reduces fragmentation by calling the Lua garbage collector via the collectgarbage function.

Как правило, это не влияет на производительность. Однако, чтобы заставить Tarantool высвободить память, можно вызвать box.snapshot, остановить экземпляр и перезапустить его.

Профилирование производительности

Иногда Tarantool может работать медленнее, чем обычно. Причин такого поведения может быть несколько: проблемы с диском, Lua-скрипты, активно использующие процессор, или неправильная настройка. В таких случаях в журнале Tarantool’а могут отсутствовать необходимые подробности, поэтому единственным признаком неправильного поведения является наличие в журнале записей вида W> too long DELETE: 8.546 sec. Ниже приведены инструменты и приемы, которые облегчают снятие профиля производительности Tarantool’а. Эта процедура может помочь при решении проблем с замедлением.

Примечание

Большинство инструментов, за исключением fiber.info(), предназначено для дистрибутивов GNU/Linux, но не для FreeBSD или Mac OS.

fiber.info()

Самый простой способ профилирования – это использование встроенных функций Tarantool’а. fiber.info() возвращает информацию обо всех работающих файберах с соответствующей трассировкой стека для языка C. Эти данные показывают, сколько файберов запущенно на данный момент и какие функции, написанные на C, вызываются чаще остальных.

Сначала войдите в интерактивную административную консоль вашего экземпляра Tarantool’а:

$ tarantoolctl enter NAME

После этого загрузите модуль fiber:

tarantool> fiber = require('fiber')

Теперь можно получить необходимую информацию с помощью fiber.info().

На этом шаге в вашей консоли должно выводиться следующее:

tarantool> fiber = require('fiber')
  ---
  ...
  tarantool> fiber.info()
  ---
  - 360:
      csw: 2098165
      backtrace:
      - '#0 0x4d1b77 in wal_write(journal*, journal_entry*)+487'
      - '#1 0x4bbf68 in txn_commit(txn*)+152'
      - '#2 0x4bd5d8 in process_rw(request*, space*, tuple**)+136'
      - '#3 0x4bed48 in box_process1+104'
      - '#4 0x4d72f8 in lbox_replace+120'
      - '#5 0x50f317 in lj_BC_FUNCC+52'
      fid: 360
      memory:
        total: 61744
        used: 480
      name: main
    129:
      csw: 113
      backtrace: []
      fid: 129
      memory:
        total: 57648
        used: 0
      name: 'console/unix/:'
  ...

Мы рекомендуем присваивать создаваемым файберам понятные имена, чтобы их можно было легко найти в списке, выводимом fiber.info(). В примере ниже создается файбер с именем myworker:

tarantool> fiber = require('fiber')
  ---
  ...
  tarantool> f = fiber.create(function() while true do fiber.sleep(0.5) end end)
  ---
  ...
  tarantool> f:name('myworker') <!-- присваивание имени файберу
  ---
  ...
  tarantool> fiber.info()
  ---
  - 102:
      csw: 14
      backtrace:
      - '#0 0x501a1a in fiber_yield_timeout+90'
      - '#1 0x4f2008 in lbox_fiber_sleep+72'
      - '#2 0x5112a7 in lj_BC_FUNCC+52'
      fid: 102
      memory:
        total: 57656
        used: 0
      name: myworker <!-- новый созданный фоновый файбер
    101:
      csw: 284
      backtrace: []
      fid: 101
      memory:
        total: 57656
        used: 0
      name: interactive
  ...

Для принудительного завершения файбера используется команда fiber.kill(fid):

tarantool> fiber.kill(102)
  ---
  ...
  tarantool> fiber.info()
  ---
  - 101:
      csw: 324
      backtrace: []
      fid: 101
      memory:
        total: 57656
        used: 0
      name: interactive
  ...

Если вам необходимо динамически получать информацию с помощью fiber.info(), вам может пригодиться приведенный ниже скрипт. Он каждые полсекунды подключается к экземпляру Tarantool’а, указанному в переменной NAME, выполняет команду fiber.info() и записывает ее выход в файл fiber-info.txt:

$ rm -f fiber.info.txt
  $ watch -n 0.5 "echo 'require(\"fiber\").info()' | tarantoolctl enter NAME | tee -a fiber-info.txt"

Если вы не можете самостоятельно разобраться, какой именно файбер вызывает проблемы с производительностью, запустите данный скрипт на 10-15 секунд и пришлите получившийся файл команде Tarantool’а на адрес support@tarantool.org.

Простейшие профилировщики

pstack <pid>

Чтобы использовать этот инструмент, его необходимо установить с помощью пакетного менеджера, поставляемого с вашим дистрибутивом Linux. Данная команда выводит трассировку стека выполнения для работающего процесса с соответствующим PID. При необходимости команду можно запустить несколько раз, чтобы выявить узкое место, которое вызывает падение производительности.

После установки воспользуйтесь следующей командой:

$ pstack $(pidof tarantool INSTANCENAME.lua)

Затем выполните:

$ echo $(pidof tarantool INSTANCENAME.lua)

чтобы вывести на экран PID экземпляра Tarantool’а, использующего файл INSTANCENAME.lua.

В вашей консоли должно отображаться приблизительно следующее:

Thread 19 (Thread 0x7f09d1bff700 (LWP 24173)):
  #0 0x00007f0a1a5423f2 in ?? () from /lib64/libgomp.so.1
  #1 0x00007f0a1a53fdc0 in ?? () from /lib64/libgomp.so.1
  #2 0x00007f0a1ad5adc5 in start_thread () from /lib64/libpthread.so.0
  #3 0x00007f0a1a050ced in clone () from /lib64/libc.so.6
  Thread 18 (Thread 0x7f09d13fe700 (LWP 24174)):
  #0 0x00007f0a1a5423f2 in ?? () from /lib64/libgomp.so.1
  #1 0x00007f0a1a53fdc0 in ?? () from /lib64/libgomp.so.1
  #2 0x00007f0a1ad5adc5 in start_thread () from /lib64/libpthread.so.0
  #3 0x00007f0a1a050ced in clone () from /lib64/libc.so.6
  <...>
  Thread 2 (Thread 0x7f09c8bfe700 (LWP 24191)):
  #0 0x00007f0a1ad5e6d5 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  #1 0x000000000045d901 in wal_writer_pop(wal_writer*) ()
  #2 0x000000000045db01 in wal_writer_f(__va_list_tag*) ()
  #3 0x0000000000429abc in fiber_cxx_invoke(int (*)(__va_list_tag*), __va_list_tag*) ()
  #4 0x00000000004b52a0 in fiber_loop ()
  #5 0x00000000006099cf in coro_init ()
  Thread 1 (Thread 0x7f0a1c47fd80 (LWP 24172)):
  #0 0x00007f0a1a0512c3 in epoll_wait () from /lib64/libc.so.6
  #1 0x00000000006051c8 in epoll_poll ()
  #2 0x0000000000607533 in ev_run ()
  #3 0x0000000000428e13 in main ()

gdb -ex «bt» -p <pid>

Как и в случае с pstack, перед использованием GNU-отладчик (также известный как gdb) необходимо сначала установить через пакетный менеджер, встроенный в ваш дистрибутив Linux.

После установки воспользуйтесь следующей командой:

$ gdb -ex "set pagination 0" -ex "thread apply all bt" --batch -p $(pidof tarantool INSTANCENAME.lua)

Затем выполните:

$ echo $(pidof tarantool INSTANCENAME.lua)

чтобы вывести на экран PID экземпляра Tarantool’а, использующего файл INSTANCENAME.lua.

После использования отладчика в консоль должна выводиться следующая информация:

[Thread debugging using libthread_db enabled]
  Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

  [CUT]

  Thread 1 (Thread 0x7f72289ba940 (LWP 20535)):
  #0 _int_malloc (av=av@entry=0x7f7226e0eb20 <main_arena>, bytes=bytes@entry=504) at malloc.c:3697
  #1 0x00007f7226acf21a in __libc_calloc (n=<optimized out>, elem_size=<optimized out>) at malloc.c:3234
  #2 0x00000000004631f8 in vy_merge_iterator_reserve (capacity=3, itr=0x7f72264af9e0) at /usr/src/tarantool/src/box/vinyl.c:7629
  #3 vy_merge_iterator_add (itr=itr@entry=0x7f72264af9e0, is_mutable=is_mutable@entry=true, belong_range=belong_range@entry=false) at /usr/src/tarantool/src/box/vinyl.c:7660
  #4 0x00000000004703df in vy_read_iterator_add_mem (itr=0x7f72264af990) at /usr/src/tarantool/src/box/vinyl.c:8387
  #5 vy_read_iterator_use_range (itr=0x7f72264af990) at /usr/src/tarantool/src/box/vinyl.c:8453
  #6 0x000000000047657d in vy_read_iterator_start (itr=<optimized out>) at /usr/src/tarantool/src/box/vinyl.c:8501
  #7 0x00000000004766b5 in vy_read_iterator_next (itr=itr@entry=0x7f72264af990, result=result@entry=0x7f72264afad8) at /usr/src/tarantool/src/box/vinyl.c:8592
  #8 0x000000000047689d in vy_index_get (tx=tx@entry=0x7f7226468158, index=index@entry=0x2563860, key=<optimized out>, part_count=<optimized out>, result=result@entry=0x7f72264afad8) at /usr/src/tarantool/src/box/vinyl.c:5705
  #9 0x0000000000477601 in vy_replace_impl (request=<optimized out>, request=<optimized out>, stmt=0x7f72265a7150, space=0x2567ea0, tx=0x7f7226468158) at /usr/src/tarantool/src/box/vinyl.c:5920
  #10 vy_replace (tx=0x7f7226468158, stmt=stmt@entry=0x7f72265a7150, space=0x2567ea0, request=<optimized out>) at /usr/src/tarantool/src/box/vinyl.c:6608
  #11 0x00000000004615a9 in VinylSpace::executeReplace (this=<optimized out>, txn=<optimized out>, space=<optimized out>, request=<optimized out>) at /usr/src/tarantool/src/box/vinyl_space.cc:108
  #12 0x00000000004bd723 in process_rw (request=request@entry=0x7f72265a70f8, space=space@entry=0x2567ea0, result=result@entry=0x7f72264afbc8) at /usr/src/tarantool/src/box/box.cc:182
  #13 0x00000000004bed48 in box_process1 (request=0x7f72265a70f8, result=result@entry=0x7f72264afbc8) at /usr/src/tarantool/src/box/box.cc:700
  #14 0x00000000004bf389 in box_replace (space_id=space_id@entry=513, tuple=<optimized out>, tuple_end=<optimized out>, result=result@entry=0x7f72264afbc8) at /usr/src/tarantool/src/box/box.cc:754
  #15 0x00000000004d72f8 in lbox_replace (L=0x413c5780) at /usr/src/tarantool/src/box/lua/index.c:72
  #16 0x000000000050f317 in lj_BC_FUNCC ()
  #17 0x00000000004d37c7 in execute_lua_call (L=0x413c5780) at /usr/src/tarantool/src/box/lua/call.c:282
  #18 0x000000000050f317 in lj_BC_FUNCC ()
  #19 0x0000000000529c7b in lua_cpcall ()
  #20 0x00000000004f6aa3 in luaT_cpcall (L=L@entry=0x413c5780, func=func@entry=0x4d36d0 <execute_lua_call>, ud=ud@entry=0x7f72264afde0) at /usr/src/tarantool/src/lua/utils.c:962
  #21 0x00000000004d3fe7 in box_process_lua (handler=0x4d36d0 <execute_lua_call>, out=out@entry=0x7f7213020600, request=request@entry=0x413c5780) at /usr/src/tarantool/src/box/lua/call.c:382
  #22 box_lua_call (request=request@entry=0x7f72130401d8, out=out@entry=0x7f7213020600) at /usr/src/tarantool/src/box/lua/call.c:405
  #23 0x00000000004c0f27 in box_process_call (request=request@entry=0x7f72130401d8, out=out@entry=0x7f7213020600) at /usr/src/tarantool/src/box/box.cc:1074
  #24 0x000000000041326c in tx_process_misc (m=0x7f7213040170) at /usr/src/tarantool/src/box/iproto.cc:942
  #25 0x0000000000504554 in cmsg_deliver (msg=0x7f7213040170) at /usr/src/tarantool/src/cbus.c:302
  #26 0x0000000000504c2e in fiber_pool_f (ap=<error reading variable: value has been optimized out>) at /usr/src/tarantool/src/fiber_pool.c:64
  #27 0x000000000041122c in fiber_cxx_invoke(fiber_func, typedef __va_list_tag __va_list_tag *) (f=<optimized out>, ap=<optimized out>) at /usr/src/tarantool/src/fiber.h:645
  #28 0x00000000005011a0 in fiber_loop (data=<optimized out>) at /usr/src/tarantool/src/fiber.c:641
  #29 0x0000000000688fbf in coro_init () at /usr/src/tarantool/third_party/coro/coro.c:110

Запустите отладчик в цикле, чтобы собрать достаточно информации, которая поможет установить причину спада производительности Tarantool’а. Можно воспользоваться следующим скриптом:

$ rm -f stack-trace.txt
  $ watch -n 0.5 "gdb -ex 'set pagination 0' -ex 'thread apply all bt' --batch -p $(pidof tarantool INSTANCENAME.lua) | tee -a stack-trace.txt"

С точки зрения структуры и функциональности, этот скрипт идентичен тому, что используется выше с fiber.info().

Если вам не удается отыскать причину пониженной производительности, запустите данный скрипт на 10-15 секунд и пришлите получившийся файл stack-trace.txt команде Tarantool’а на адрес support@tarantool.org.

Предупреждение

Следует использовать pstack и gdb с осторожностью: каждый раз, подключаясь с работающему процессу, они приостанавливают выполнение этого процесса приблизительно на одну секунду, что может иметь серьезные последствия для высоконагруженных сервисов.

gperftools

Чтобы использовать профилировщик процессора из набора Google Performance Tools с Tarantool’ом, необходимо сначала установить зависимости:

  • Если вы используете Debian/Ubuntu, запустите эту команду:
$ apt-get install libgoogle-perftools4
  • Если вы используете RHEL/CentOS/Fedora, запустите эту команду:
$ yum install gperftools-libs

После этого установите привязки для Lua:

$ tarantoolctl rocks install gperftools

После окончания установки войдите в интерактивную административную консоль вашего экземпляра Tarantool’а:

$ tarantoolctl enter NAME

Для запуска профилировщика выполните следующий код:

tarantool> cpuprof = require('gperftools.cpu')
  tarantool> cpuprof.start('/home/<имя_пользователя>/tarantool-on-production.prof')

На сбор метрик производительности у профилировщика уходит по крайней мере пара минут. По истечении этого времени можно сохранять информацию на диск (неограниченное количество раз):

tarantool> cpuprof.flush()

Для остановки профилировщика выполните следующую команду:

tarantool> cpuprof.stop()

Теперь можно проанализировать собранные данные с помощью утилиты pprof, которая входит в пакет gperftools:

$ pprof --text /usr/bin/tarantool /home/<имя_пользователя>/tarantool-on-production.prof

Примечание

В дистрибутивах Debian/Ubuntu утилита pprof называется google-pprof.

В консоль должно выводиться приблизительно следующее:

Total: 598 samples
        83 13.9% 13.9% 83 13.9% epoll_wait
        54 9.0% 22.9% 102 17.1%
  vy_mem_tree_insert.constprop.35
        32 5.4% 28.3% 34 5.7% __write_nocancel
        28 4.7% 32.9% 42 7.0% vy_mem_iterator_start_from
        26 4.3% 37.3% 26 4.3% _IO_str_seekoff
        21 3.5% 40.8% 21 3.5% tuple_compare_field
        19 3.2% 44.0% 19 3.2%
  ::TupleCompareWithKey::compare
        19 3.2% 47.2% 38 6.4% tuple_compare_slowpath
        12 2.0% 49.2% 23 3.8% __libc_calloc
         9 1.5% 50.7% 9 1.5%
  ::TupleCompare::compare@42efc0
         9 1.5% 52.2% 9 1.5% vy_cache_on_write
         9 1.5% 53.7% 57 9.5% vy_merge_iterator_next_key
         8 1.3% 55.0% 8 1.3% __nss_passwd_lookup
         6 1.0% 56.0% 25 4.2% gc_onestep
         6 1.0% 57.0% 6 1.0% lj_tab_next
         5 0.8% 57.9% 5 0.8% lj_alloc_malloc
         5 0.8% 58.7% 131 21.9% vy_prepare

perf

Этот инструмент для мониторинга и анализа производительности устанавливается отдельно с помощью пакетного менеджера. Попробуйте ввести в окне консоли команду perf и следуйте подсказкам, чтобы установить необходимые пакеты.

Примечание

По умолчанию некоторые команды из пакета perf можно выполнять только с root-правами, поэтому необходимо либо зайти в систему из-под пользователя root, либо добавлять перед каждой командой sudo.

Чтобы начать сбор показателей производительности, выполните следующую команду:

$ perf record -g -p $(pidof tarantool INSTANCENAME.lua)

Эта команда сохраняет собранные данные в файл perf.data, который находится в текущей рабочей папке. Для остановки процесса (обычно через 10-15 секунд) нажмите ctrl+C. В консоли должно появиться следующее:

^C[ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.225 MB perf.data (1573 samples) ]

Затем выполните эту команду:

$ perf report -n -g --stdio | tee perf-report.txt

Она превращает содержащиеся в perf.data статистические данные в отчет о производительности, который сохраняется в файл perf-report.txt.

Получившийся отчет выглядит следующим образом:

# Samples: 14K of event 'cycles'
  # Event count (approx.): 9927346847
  #
  # Children Self Samples Command Shared Object Symbol
  # ........ ........ ............ ......... .................. .......................................
  #
      35.50% 0.55% 79 tarantool tarantool [.] lj_gc_step
              |
               --34.95%--lj_gc_step
                         |
                         |--29.26%--gc_onestep
                         | |
                         | |--13.85%--gc_sweep
                         | | |
                         | | |--5.59%--lj_alloc_free
                         | | |
                         | | |--1.33%--lj_tab_free
                         | | | |
                         | | | --1.01%--lj_alloc_free
                         | | |
                         | | --1.17%--lj_cdata_free
                         | |
                         | |--5.41%--gc_finalize
                         | | |
                         | | |--1.06%--lj_obj_equal
                         | | |
                         | | --0.95%--lj_tab_set
                         | |
                         | |--4.97%--rehashtab
                         | | |
                         | | --3.65%--lj_tab_resize
                         | | |
                         | | |--0.74%--lj_tab_set
                         | | |
                         | | --0.72%--lj_tab_newkey
                         | |
                         | |--0.91%--propagatemark
                         | |
                         | --0.67%--lj_cdata_free
                         |
                          --5.43%--propagatemark
                                    |
                                     --0.73%--gc_mark

Инструменты gperftools и perf отличаются от pstack и gdb низкой затратой ресурсов (пренебрежимо малой по сравнению с pstack и gdb): они подключаются к работающим процессам без больших задержек, а потому могут использоваться без серьезных последствий.