Apache Pulsar es una plataforma de mensajería y streaming distribuida que combina colas de trabajo y registros de eventos en un mismo sistema. Separa el servicio de mensajes (brokers) del almacenamiento (Apache BookKeeper) y organiza los topics en tenants y namespaces, lo que facilita darle servicio a varios equipos o clientes con un único clúster. En este tutorial instalarás Pulsar 4 en modo standalone en Ubuntu 24.04, lo ejecutarás como servicio de systemd y usarás pulsar-admin y pulsar-client para crear tus primeros topics, publicar y consumir mensajes.

El modo standalone ejecuta el broker, BookKeeper y el almacén de metadatos en un solo proceso Java. Es ideal para desarrollo, pruebas y cargas pequeñas, pero no ofrece alta disponibilidad.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS de 64 bits, por ejemplo un VPS de CubePath, con al menos 4 GB de RAM y 2 vCPU.
  • Unos 10 GB libres en disco para los datos de BookKeeper.
  • Un usuario no root con privilegios sudo.
  • UFW activo con el acceso SSH permitido.

Pulsar frente a Kafka en pocas líneas

Si vienes de Kafka, estas son las diferencias que más se notan al empezar:

AspectoApache PulsarApache Kafka
AlmacenamientoSeparado en BookKeeper, los brokers no guardan estadoEn los propios brokers
Multi-tenantNativo: tenant, namespace y topicSin jerarquía, se simula con prefijos y ACL
Modelos de consumoExclusive, Failover, Shared y Key_SharedGrupos de consumidores por partición
Colas de trabajoSí, con suscripciones Shared y ack por mensajeLimitado al número de particiones
RetenciónConfigurable por namespace, con almacenamiento por nivelesConfigurable por topic

Paso 1: Instalar Java 21

Pulsar 4 necesita Java 21. Instala el runtime de OpenJDK sin interfaz gráfica:

sudo apt update
sudo apt install openjdk-21-jre-headless

Comprueba la versión:

java -version
openjdk version "21.0.8" 2025-07-15
OpenJDK Runtime Environment (build 21.0.8+9-Ubuntu-0ubuntu124.04.1)
OpenJDK 64-Bit Server VM (build 21.0.8+9-Ubuntu-0ubuntu124.04.1, mixed mode, sharing)

Paso 2: Descargar Pulsar

Crea un usuario de sistema sin shell para ejecutar Pulsar:

sudo useradd --system --home-dir /opt/pulsar --shell /usr/sbin/nologin pulsar

Descarga la distribución binaria y su suma SHA-512 desde el archivo de Apache. Esta guía usa la versión 4.2.4; consulta la última en la página de descargas de Pulsar y ajusta la variable si es necesario:

PULSAR_VERSION=4.2.4
cd /tmp
curl -fLO "https://archive.apache.org/dist/pulsar/pulsar-${PULSAR_VERSION}/apache-pulsar-${PULSAR_VERSION}-bin.tar.gz"
curl -fLO "https://archive.apache.org/dist/pulsar/pulsar-${PULSAR_VERSION}/apache-pulsar-${PULSAR_VERSION}-bin.tar.gz.sha512"

Verifica la integridad del archivo:

sha512sum -c "apache-pulsar-${PULSAR_VERSION}-bin.tar.gz.sha512"
./apache-pulsar-4.2.4-bin.tar.gz: OK

Descomprímelo en /opt/pulsar y asigna la propiedad al usuario pulsar:

sudo mkdir -p /opt/pulsar
sudo tar -xzf "apache-pulsar-${PULSAR_VERSION}-bin.tar.gz" -C /opt/pulsar --strip-components=1
sudo chown -R pulsar:pulsar /opt/pulsar

Comprueba el contenido con ls /opt/pulsar. Deben aparecer, entre otros, los directorios bin (herramientas como pulsar, pulsar-admin y pulsar-client), conf (configuración) y lib (las bibliotecas Java).

Paso 3: Crear el servicio de systemd

Pulsar incluye bin/pulsar-daemon, pero un servicio de systemd arranca con el sistema, se reinicia si falla y envía la salida al journal. Crea la unidad:

sudo nano /etc/systemd/system/pulsar.service
[Unit]
Description=Apache Pulsar standalone
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=pulsar
Group=pulsar
WorkingDirectory=/opt/pulsar
Environment="PULSAR_MEM=-Xms1g -Xmx1g -XX:MaxDirectMemorySize=2g"
ExecStart=/opt/pulsar/bin/pulsar standalone
Restart=on-failure
RestartSec=10
TimeoutStopSec=60
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

La variable PULSAR_MEM sustituye la configuración de memoria por defecto de conf/pulsar_env.sh (2 GB de heap y hasta 4 GB de memoria directa), que es excesiva para un servidor de 4 GB. Si tienes 8 GB o más, puedes quitar esa línea.

Recarga systemd y arranca el servicio:

sudo systemctl daemon-reload
sudo systemctl enable --now pulsar

El primer arranque tarda entre 30 y 60 segundos, porque inicializa los metadatos, BookKeeper y el namespace public/default. Sigue el progreso en el journal:

sudo journalctl -u pulsar -f

Pulsa Ctrl+C cuando dejen de aparecer mensajes de arranque. Comprueba que el broker responde en su API de administración:

curl -s http://localhost:8080/admin/v2/clusters
["standalone"]

Y que escucha en sus dos puertos: 6650 para el protocolo binario de los clientes y 8080 para la API HTTP de administración:

sudo ss -tlnp | grep -E ':(6650|8080)\s'

Para no escribir la ruta completa en cada comando, añade bin al PATH de tu sesión:

export PATH="/opt/pulsar/bin:$PATH"

Verifica el estado del broker:

pulsar-admin brokers healthcheck
ok

Paso 4: Crear un tenant y un namespace

Pulsar organiza los topics en tres niveles: tenant (un equipo o cliente), namespace (una aplicación, con sus propias políticas) y topic. Crea un tenant acme autorizado en el clúster standalone:

pulsar-admin tenants create acme --allowed-clusters standalone

Crea un namespace para la aplicación de pedidos:

pulsar-admin namespaces create acme/pedidos

Por defecto, Pulsar borra los mensajes en cuanto todas las suscripciones los han confirmado. Configura una retención de 7 días o 10 GB para poder releerlos:

pulsar-admin namespaces set-retention acme/pedidos --time 7d --size 10G

Comprueba el resultado:

pulsar-admin namespaces list acme
pulsar-admin namespaces get-retention acme/pedidos
acme/pedidos
{
  "retentionTimeInMinutes" : 10080,
  "retentionSizeInMB" : 10240
}

Paso 5: Crear un topic particionado

Un topic particionado reparte la carga entre varias particiones internas, que en un clúster real se distribuyen entre brokers. Crea uno con 3 particiones:

pulsar-admin topics create-partitioned-topic persistent://acme/pedidos/eventos --partitions 3

Lista los topics particionados del namespace:

pulsar-admin topics list-partitioned-topics acme/pedidos
persistent://acme/pedidos/eventos

El prefijo persistent:// indica que los mensajes se escriben en BookKeeper antes de confirmarse al productor. Los topics non-persistent:// son más rápidos pero pierden los mensajes si el broker se reinicia.

Paso 6: Publicar y consumir mensajes

Abre una segunda sesión SSH, añade de nuevo /opt/pulsar/bin al PATH y arranca un consumidor con una suscripción Shared, en la que varios consumidores se reparten los mensajes como en una cola de trabajo. -n 0 hace que consuma indefinidamente:

pulsar-client consume persistent://acme/pedidos/eventos \
  -s procesador -t Shared -p Earliest -n 0

En la primera sesión, publica diez mensajes separados por comas:

pulsar-client produce persistent://acme/pedidos/eventos \
  --messages "$(seq -s, -f 'pedido-%g' 1 10)"
... 10 messages successfully produced

El consumidor los muestra al instante:

----- got message -----
key:[null], properties:[], content:pedido-1
----- got message -----
key:[null], properties:[], content:pedido-2
...

Si arrancas un segundo consumidor con la misma suscripción procesador, los siguientes mensajes se repartirán entre ambos. Con -t Exclusive (el valor por defecto) solo se admite un consumidor por suscripción, y con -t Failover hay uno activo y los demás esperan como reserva.

Consulta las estadísticas del topic para ver productores, suscripciones y mensajes pendientes:

pulsar-admin topics partitioned-stats persistent://acme/pedidos/eventos

En la salida JSON, msgInCounter indica los mensajes recibidos y, dentro de subscriptions.procesador, msgBacklog los que quedan por consumir.

Paso 7: Conectarse desde una aplicación Python

Las aplicaciones usan las librerías cliente oficiales. Este ejemplo publica un mensaje con el cliente de Python:

sudo apt install python3-venv
python3 -m venv ~/pulsar-venv
~/pulsar-venv/bin/pip install pulsar-client
nano ~/productor.py
import pulsar

client = pulsar.Client("pulsar://localhost:6650")
producer = client.create_producer("persistent://acme/pedidos/eventos")

msg_id = producer.send("pedido-desde-python".encode("utf-8"))
print(f"Publicado con id {msg_id}")

client.close()
~/pulsar-venv/bin/python ~/productor.py

El consumidor que dejaste abierto en el paso anterior recibirá pedido-desde-python.

Solución de problemas

  • El servicio se reinicia en bucle: revisa sudo journalctl -u pulsar -n 100 --no-pager. Si aparece UnsupportedClassVersionError, no se está usando Java 21; comprueba java -version y sudo update-alternatives --config java.
  • java.lang.OutOfMemoryError o el proceso muere por OOM: el servidor no tiene memoria suficiente para los valores de PULSAR_MEM. Redúcelos o amplía la RAM.
  • Address already in use al arrancar: otro servicio usa el puerto 8080 o 6650. Localízalo con sudo ss -tlnp | grep -E ':(6650|8080)\s'.
  • Tenant does not exist o Namespace does not exist: el nombre del topic debe seguir el formato persistent://tenant/namespace/topic. Los nombres cortos como mi-topic se resuelven a public/default.

Conclusión

Tienes Apache Pulsar 4 en modo standalone funcionando como servicio en Ubuntu 24.04, con un tenant y un namespace con retención, un topic particionado y productores y consumidores de prueba. Como siguientes pasos, puedes activar la autenticación por token JWT en conf/standalone.conf, explorar Pulsar Functions para procesar mensajes sin desplegar servicios aparte, o planificar un clúster de producción con brokers, bookies y almacén de metadatos en servidores separados.