Версия:

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

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

Использование 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 почти никогда не освобождает эту память, даже если пользователь удалит все, что было вставлено, или уменьшит фрагментацию, вызвав сборщик мусора в Lua с помощью функции collectgarbage.

Как правило, это не влияет на производительность. Однако, чтобы заставить 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): они подключаются к работающим процессам без больших задержек, а потому могут использоваться без серьезных последствий.