ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Sentry 混合云(Hybrid Cloud)本地开发完全指南:Control Silo 与 Region Silo 的搭建、运行与调试

Sentry 混合云(Hybrid Cloud)本地开发完全指南:Control Silo 与 Region Silo 的搭建、运行与调试 Sentry 混合云Hybrid Cloud本地开发完全指南Control Silo 与 Region Silo 的搭建、运行与调试【免费下载链接】sentryDeveloper-first error tracking and performance monitoring项目地址: https://gitcode.com/GitHub_Trending/sen/sentry导读本文以 Sentry 仓库中的 src/sentry/silo/README.md 为核心系统讲解 Sentry 混合云Hybrid Cloud架构下的 Silo筒仓概念以及如何在本地以 Control Silo Region Silo 双实例形态运行整套开发环境。读完本文你将掌握数据库拆分bin/split-silo-database、双 Silo 进程启动sentry devserver --silo...、端口规划与各启动选项的真实语义并能借助 ngrok 在真实域名下联调多区域环境同时会从源码层理解 Silo 的路由、限流装饰器与安全签名机制为后续二次开发与排障打下基础。一、Silo 背景为什么需要把 Sentry 拆成两个实例历史上Sentry 后端无论运行在哪里都拥有对所有模型Model与接口Endpoint的读写权限。对于自托管Self-hosted用户这一简化部署模型将一直得到支持社区称其为Monolith单体模式。而对SaaS 部署而言Sentry 需要引入敏感数据驻留data residency能力这正是 Hybrid Cloud 项目的目标将系统拆成两类可相互通信的独立实例Control Silo控制筒仓存放对 Sentry SaaS 全局通用universal的数据全系统仅一份Single Instance。Region Silo区域筒仓存放仅与某个 Sentry 区域相关、且只属于该区域的客户数据。Region Silo 之间互不通信Multiple Instances。在代码层面这一设计由 src/sentry/silo/base.py 中的SiloMode枚举承载class SiloMode(Enum): MONOLITH MONOLITH # 默认单体模式可访问全部表与端点 CONTROL CONTROL # 控制筒仓 CELL REGION # 区域筒仓代码中以 Cell 命名SiloMode.get_current_mode()会依次读取settings.SILO_MODE与单进程上下文状态SingleProcessSiloModeState是判断当前进程属于哪个 Silo的权威入口。值得注意的是settings.SILO_MODE来自环境变量SENTRY_SILO_MODE因此通过环境变量即可在启动时决定进程角色见 src/sentry/conf/server.py。二、源码视角Model 与 Endpoint 的 Silo 归属是如何声明的理解了两种 Silo之后需要回答一个关键问题某个模型或接口到底属于哪个 Silo答案是仓库内的两类装饰器。2.1 模型的 Silo 归属control_silo_model/cell_silo_model在 src/sentry/db/models/base.py 中定义了两个模型装饰器control_silo_model ModelSiloLimit(SiloMode.CONTROL) cell_silo_model ModelSiloLimit(SiloMode.CELL)control_silo_model用于被多个组织共享、或需要与 Control Silo 其他资源强一致的模型cell_silo_model用于属于单个组织、或需要与 Region Silo 其他资源强一致的模型。装饰器会把silo_limit写入模型的_meta并对其objectsManager 及所有标记alters_data的方法创建条件覆盖create_override从而在非所属 Silo 上调用时抛出AvailabilityError详见 base.py。split-silo-database脚本正是通过读取model._meta.silo_limit.modes来判定每张表应落入 control 还是 region 数据库的。2.2 接口的 Silo 归属control_silo_endpoint/cell_silo_endpoint在 src/sentry/api/base.py 中端点装饰器把 Silo 边界延伸到了 HTTP 层control_silo_endpoint EndpointSiloLimit(SiloMode.CONTROL) cell_silo_endpoint CellSiloEndpoint()当请求命中一个端点而其装饰器声明的 Silo 与当前进程模式不符时服务端返回 404可配置settings.FAIL_ON_UNAVAILABLE_API_CALL改为直接抛出AvailabilityError。这意味着 Region Silo 进程只暴露区域端点Control Silo 只暴露控制端点形成真正的进程级隔离。例如 accept_organization_invite.py 就通过control_silo_endpoint声明其归属。2.3 数据库路由SiloRouter 如何把表路由到正确的库SiloRouter见 src/sentry/db/router.py是这一切落地的关键。它支持两种配置Monolith所有表都在同一个数据库Siloedcontrol 表与 region 表物理分离其中又分为两种形态simulated模拟配置了control与default两个连接如测试环境、拆分后应用尚未分离的过渡期isolated隔离没有 control/region 连接default连接直接充当当前 Silo 的数据库另一侧视为不可达。对于没有 Silo 注解的 Django 内置表django_admin_log、django_session、auth_user等SiloRouter.contrib_models显式将它们归入 control 库。三、本地前置条件创建数据库并执行拆分要在一台机器上同时跑起 Control Silo 与 Region Silo需要先把单体数据库劈成两个独立库。按 README 的步骤共三步创建拆分后的两个数据库执行make create-db该目标同时承担 CLI 测试等任务见 Makefile执行拆分脚本bin/split-silo-database删除devlocal.py或sentry.conf.py中的DATABASES自定义设置因为这些配置会覆盖数据库路由阻止模型正确路由到对应库。3.1 拆分脚本的真实行为README 给出了脚本运行的示例输出$ bin/split-silo-database Could not find silo assignment for django_admin_log Could not find silo assignment for auth_permission Could not find silo assignment for auth_group Could not find silo assignment for django_content_type Could not find silo assignment for django_session Could not find silo assignment for django_site 8 OrganizationMapping record(s) have been updated from --monolith-- to us Dumping tables from sentry database Building control database from dump file Dumping tables from sentry database Building region database from dump file对照 bin/split-silo-database 源码可以解读出以下几点前几行 Could not find silo assignment ... 是 Django 内置表的提示它们在代码中通过region_tables/control_tables两个白名单手工定义如django_migrations、django_content_type同时在两个库django_admin_log、auth_*等仅进 control并非错误OrganizationMapping record(s) have been updated 对应revise_organization_mappings()把旧的--monolith--cell 映射批量改写为settings.SENTRY_FALLBACK_CELL指向的新区域Dumping tables ... Building ... database 对应split_database()脚本实际是在 Docker 的postgres-postgres-1容器内调用pg_dump导出指定表再通过psql导入目标库并自动执行CREATE EXTENSION IF NOT EXISTS citext整个过程不会修改原始sentry库脚本 docstring 明确说明 This operation will not modify the original source database。3.2 脚本可用参数参数默认值作用--databasesentry从哪个源库提取拆分数据--resetFalseflag导入前先 drop 并重建目标库dropdb --if-existscreatedb--verboseFalseflag打印实际执行的容器内命令--legacy-region-name--monolith--在 OrganizationMapping 中待覆盖的旧 cell 名四、运行双 Silo两条 devserver 命令与端口规划拆分数据库后用两条命令分别启动两个 Silosentry devserver --silocontrol --task-scheduler --workers sentry devserver --siloregion --task-scheduler --workers --ingest启动后暴露以下端口端口用途Silo8000Webpack前端开发服务器Control8001HTTP APIControl8010HTTP APIRegion端口映射逻辑可以在 src/sentry/runner/commands/devserver.py 中看到webpack port、server port 1、region.server port 10Region 进程通过SENTRY_BACKEND_PORT环境变量获得 8010 端口。同时--silo选项只接受control或region两个取值见 devserver.py。4.1 各启动选项的真实语义--task-scheduler启动任务调度器taskworker-scheduler用于周期性定时任务--workers启动 taskworker 子进程。注意在 control silo 上--workers只会追加一个 taskworker 服务见 devserver.py--ingest仅应传给 Region Silo。源码中有两处关键逻辑当--ingest与--workers同时满足时若在 control silo 上会打印--ingest has no effect on the control silo, ignoring在 region 上则打印--ingest was provided, implicitly enabling --workers并强制打开 workers见 devserver.py。这正是 README 所述--ingest隐式启用--workers的出处之所以不能把--ingest传给 controlingest 消费者永远不会在 control silo 启动该标志只会额外加一个 taskworker而这个 worker 连的是默认 broker端口 50051承载 region 任务它会把save_event这类只能在REGION模式运行的任务认领下来并以AvailabilityError失败——与此同时 region 的 taskworker 也在竞争同一批任务导致事件随机丢失而非每次都丢。SENTRY_USE_RELAY如果你启用了--ingest但发现 relay 没有被启动请检查settings.SENTRY_USE_RELAY是否为真。该开关默认关闭src/sentry/conf/server.py它控制 devserver 是否拉起 Relay、Kafka 及若干 ingest worker把 store 流量导向 Relay 摄取管线启用后 devserver 会自动追加ingest-events、ingest-attachments、ingest-transactions、ingest-monitors等 Kafka 消费者见 devserver.py。4.2 进程内部发生了什么devserver --silo...不只是改端口。对照 devserver.py 与 conf/server.pyRegion 进程会设置SENTRY_SILO_MODEREGION、SENTRY_REGIONus、SENTRY_SILO_DEVSERVER1Control 进程设置SENTRY_SILO_MODECONTROL在SILO_DEVSERVER模式下DATABASES[control]指向control库DATABASES[default]指向region库并注册DATABASE_ROUTERS (sentry.db.router.SiloRouter,)同时注入一个名为us的本地 cellSENTRY_CELLS、RPC_SHARED_SECRET、SENTRY_SUBNET_SECRET等跨进程通信凭据并把SENTRY_CONTROL_ADDRESS指向 control API 端口。这就是两个进程 两个数据库 共享 Kafka/Redis的本地混合云形态。五、进阶结合 ngrok 使用 Silo 开发环境由于 Cookie 无法跨 localhost 子域共享Silo 模式下 devserver 会自动把client_hostname从localhost切换到dev.getsentry.net见 devserver.py。若要在真实 HTTPS 域名下联调例如验证跨域登录、多区域 URL 模板README 推荐配合 ngrok。假设你的 ngrok 域名是acme先为两个隧道创建 ngrok 配置文件--ngrok预设假定你已经在跑 ngrokversion: 2 authtoken: YOUR-NGROK-AUTHTOKEN tunnels: control-silo: proto: http hostname: acme.ngrok.io host_header: rewrite addr: 8000 region-silo: proto: http hostname: us.acme.ngrok.io addr: 8010 host_header: rewrite然后同时拉起两条隧道ngrok start --all最后以 ngrok 模式启动两个 Silo注意 hostname 不带协议前缀sentry devserver --ngrokacme.ngrok.dev --silocontrol sentry devserver --ngrokacme.ngrok.dev --siloregion--ngrok选项在 devserver.py 中定义为你正把 ngrok 转发到 devserver 的主机名并在启动时写入环境变量SENTRY_DEVSERVER_NGROK。对应地conf/server.py 会据此调整system.url-prefix与SENTRY_BASE_HOSTNAME指向https://ngrok_hostCSRF_TRUSTED_ORIGINS、ALLOWED_HOSTS、SESSION_COOKIE_DOMAIN、CSRF_COOKIE_DOMAIN、SUDO_COOKIE_DOMAIN统一放宽到该域名及其子域在SILO_DEVSERVER同时开启时SENTRY_REGION_API_URL_TEMPLATE被设为https://{{region}}.ngrok_host见 conf/server.py从而让前端能按us.acme.ngrok.dev这样的模板拼接区域 API 地址。六、Silo 之间的安全与一致性机制源码补充了解运行方式之后再补充三个支撑 Silo 隔离的底层机制帮助你在排查跨 Silo 问题时快速定位。6.1 事务级强制silo_aware_transaction_patchSilo 边界不能只靠装饰器自觉遵守。src/sentry/silo/patches/silo_aware_transaction_patch.py 中的patch_silo_aware_atomic()会全局替换transaction.atomic、transaction.on_commit、transaction.get_connection使其在调用前执行validate_transaction_using_for_silo_mode()当 control 库与 cell 库路由到不同数据库、且当前模式非 MONOLITH 时任何在错误模式下发起的跨库事务都会抛出MismatchedSiloTransactionError。这保证了control 数据只能在 Control 模式改、cell 数据只能在 Cell 模式改。6.2 outbox 安全写unguarded_write 与 fencing 查询src/sentry/silo/safety.py 提供了unguarded_write上下文管理器用于包裹基于 outbox 记录做变更是安全的代码块生产环境它为空操作测试环境中它会在事务开始/结束时发出start_role_override_n/end_role_override_n这样的 fencing 查询供测试框架审计sentry.testutils.silo.validate_protected_queries确认测试期间没有绕过 outbox 的非法直写。6.3 跨 Silo 代理与子网签名跨 Silo 的 HTTP 通信通过 src/sentry/silo/util.py 定义的X-Sentry-Subnet-*头实现encode_subnet_signature()使用settings.SENTRY_SUBNET_SECRET对base_url path identifier request_body计算 HMAC-SHA256 签名v0...verify_subnet_signature()用hmac.compare_digest常数时间校验client.py 中的CellSiloClient则负责把入站请求原样代理到目标 Silo并过滤掉 Host、Content-Length 等不安全头clean_proxy_headers。这些机制共同构成了 Hybrid Cloud 跨实例通信的认证与防篡改基线。6.4 测试如何验证双 Silo 行为仓库在 src/sentry/testutils/silo.py 提供SiloModeTestDecorator通过control_silo_test、region_silo_test等装饰器修饰测试类会在模块中动态生成对应模式的测试类让同一套用例在不同 Silo 模式下重复执行SingleProcessSiloModeState的测试实现monkey_patch_single_process_silo_mode_state则允许在单进程内模拟进程边界用于验收测试中验证多端点跨进程行为。这些机制保证了拆分后应用仍能通过既有测试这一核心诉求。七、常见问题与排障要点模型没有路由到正确数据库检查devlocal.py/sentry.conf.py是否残留自定义DATABASES它们会绕过SiloRouter确认SILO_DEVSERVER模式下DATABASES[control]与DATABASES[default]region都指向了拆分后的库。事件随机丢失而非每次都失败确认没有把--ingest传给 control siloRegion 的 ingest 消费者才是save_event等任务的合法执行者。启动 workers 报错devserver在拉起 taskworker 前会检查TASKWORKER_ALWAYS_EAGER如被开启会直接抛出ClickException见 devserver.py请先关闭该设置。relay 没有启动确认settings.SENTRY_USE_RELAY True否则--ingest相关消费者不会被注册。ngrok 下登录/跨域异常确认使用了--ngrokhost形式且不带协议前缀并保持两个隧道control:8000、region:8010与两条 devserver 命令同时运行。结语Hybrid Cloud 是 Sentry 从单体走向多区域 SaaS 部署的关键架构Control Silo 承载全局数据、Region Silo 承载区域数据二者通过数据库路由、Silo 装饰器、跨进程代理与事务级校验实现物理与逻辑的双重隔离而bin/split-silo-database与sentry devserver --silo...则让开发者得以在一台机器上完整复现这套形态。本文的启动命令与参数说明可直接照搬实践更深层的路由与安全实现可继续阅读 src/sentry/silo/base.py、src/sentry/db/router.py 与 src/sentry/conf/server.py 中 Hybrid cloud multi-silo configuration 一节结合源码理解每一处配置的落点。【免费下载链接】sentryDeveloper-first error tracking and performance monitoring项目地址: https://gitcode.com/GitHub_Trending/sen/sentry创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表