内容整理自官方开发文档

系列

自托管 Sentry

除了公开提供其源代码外,Sentry 还提供并维护了一个最小的设置,可以为简单的用例开箱即用。

该存储库还可以作为各种 Sentry 服务如何连接以进行完整设置的蓝图,这对于愿意维护更大安装的人很有用。

为简单起见,我们为此选择使用 DockerDocker Compose

以及基于 bash 的安装和升级脚本。

入门

我们的建议是下载自托管存储库的最新版本

然后在此目录中运行 ./install.sh

这个脚本会处理你开始需要的所有事情,包括一个 base-line 配置,

然后会告诉你运行 docker-compose up -d 来启动 Sentry

Sentry 默认绑定到端口 9000

您应该能够访问 http://127.0.0.1:9000 上的登录页面。

配置

您很可能希望调整 Sentry 的默认配置。这些设施可用于此目的:

  1. sentry/config.yml — 包含大多数(如果不是全部)要调整的配置选项。这个文件是在安装时从 sentry/config.example.yml 生成的。该文件本身将最常见的配置选项记录为代码注释。此文件中的一些常用设置包括:

    • system.url-prefix(我们会在安装后立即提示您在欢迎屏幕上进行设置)
    • mail.*(虽然我们提供了一个基本的 SMTP 服务器)
    • GitHubSlack 等的集成。
  2. sentry/sentry.conf.py—包含更高级的配置。这个文件是在安装过程中从 sentry/sentry.conf.example.py 生成的。

  3. 环境变量—可用的 key.env 中定义。如果您需要覆盖任何环境变量,请使用一些与系统相关的方法来设置环境变量。为避免 Git 更改,只需创建一个名为 .env.custom 的文件并在其中插入与系统相关的环境变量。为了使用它,请使用 docker-compose --env-file /path/to/.env.custom up -d

  4. Geolocation 使用自定义配置文件来符合底层技术。

注意:更改配置后,您需要通过运行 docker-compose restart web worker cron sentry-cleanup(或仅 docker-compose restart 重新启动所有内容)来重新启动所有 Sentry 服务。

配置特定主题

以下是与自托管相关的特定配置主题的更多信息:

  • 自定义 CA 根
  • Email
  • 地理位置
  • 单点登录 (SSO)

产品化

我们强烈建议在绑定到专用域或子域的 Sentry 设置前使用专用负载均衡器。

一个执行 SSL/TLS 终止的专用负载平衡器也将客户端 IP 地址转发为 Docker Compose 内部网络

(因为这几乎不可能以其他方式获得)将为您提供最佳的 Sentry 体验。

作为此设置的一部分,我们建议使用 HTTP 协议针对 /_health/ 端点配置负载均衡器运行状况检查。

如果 Sentry 启动,这将返回 200 或带有问题列表的 500

请记住,所有这些设置都对所有服务使用单节点,包括 Kafka

对于更大的负载,您需要一台具有大量 RAM 和磁盘存储空间的强大机器。

为了进一步扩展,您很可能会使用带有更复杂工具(例如 Kubernetes)的集群。

由于自托管安装的自定义性质,我们不提供任何有关扩展的建议或指导。

自托管发布和升级

Sentry 减少了自托管的定期发布,以使其尽可能接近 sentry.io

我们决定遵循使用 CalVer 版本控制方案的月度发布计划。

每个月的 15 号发布一个新版本,并在必要时进行后续发布。

您可以在我们自托管存储库的发布部分

找到最新版本

为什么选择 CalVer

升级

我们鼓励每个人定期更新他们的 Sentry 安装以获得最佳和最新的 Sentry 体验。

要升级,您需要做的就是下载或检查您想要的自托管存储库的版本,用该版本替换现有文件夹的内容,然后运行 ./install.sh

配置更新

我们可能有一些更新的配置,特别是对于新功能,因此请始终检查 sentry 目录下的示例配置文件,看看是否需要更新现有配置。我们尽最大努力自动化关键配置更新,但您应该始终在升级期间检查您的配置。

在开始升级之前,我们关闭了所有服务,然后运行了一些数据迁移,因此预计会有一些停机时间。

有一个实验性--minimize-downtime 选项可以减少升级期间的停机时间。

使用它的风险由您自己承担,并查看它在其中实施的PR以获取更多信息。

从早期版本升级时,您需要经历一些困难。请阅读下面的 难点 部分以获取列表。

难点

我们有三个难点,您需要通过这些步骤才能获取重大的数据库更改:

  1. 如果您来自 9.1.2 之前的版本,则首先需要升级到 9.1.2 并按照以下步骤操作:
    <your.sentry.version> -> 9.1.2 -> 21.5.0 -> 21.6.3 -> latest
  2. 如果您来自 9.1.2,首先需要升级到 21.5.0 并按照以下步骤操作:
    <your.sentry.version> -> 21.5.0 -> 21.6.3 -> latest
  3. 如果您来自 21.6.3 之前的版本,则首先需要升级到 21.6.3
    <your.sentry.version> -> 21.6.3 -> latest

任何其他情况(21.6.3+),你应该可以直接升级到最新版本。

每晚构建

我们为 Sentry 的每个新提交以及所有支持项目提供自托管存储库的 master 分支的每晚构建:

注意:这些构建通常是稳定的,但您可能偶尔会遇到损坏的版本,因为这些版本不能保证首先部署到 sentry.io。也不能保证您能够干净地升级到更高版本而不会丢失任何数据。使用每晚构建的风险自负

自托管备份和恢复

快速备份

如果您需要一种快速备份和恢复 Sentry 实例的方法,并且不需要历史事件数据,

则可以使用内置的 exportimport 命令。

这些命令将保存和加载所有项目和用户数据,但不包含任何事件数据。

备份

docker-compose run --rm -T -e SENTRY_LOG_LEVEL=CRITICAL web export > sentry/backup.json

注意:如果您省略了 -T-e SENTRY_LOG_LEVEL=CRITICAL 部分,您的备份文件将混入日志行,您必须以某种方式将其删除。

恢复

使用 export 命令备份后,恢复它的最简单方法是将其放在主 self-hosted 存储库中的 sentry 目录下,在配置文件旁边。这个目录会自动挂载到 /etc/sentry,所以你可以运行以下命令来恢复你的备份:

docker-compose run --rm -T web import /etc/sentry/backup.json

如果您没有看到任何错误并且进程以代码 0 退出,那么恭喜您,您刚刚恢复了备份。

注意:我们强烈建议您在全新安装(空数据库但运行迁移)时在 相同版本的 Sentry 上恢复备份。否则,您很可能会遇到错误并可能损坏您的数据库。

完整备份

备份和恢复 Sentry 的理想方法是备份恢复它使用的所有 Docker 卷。所有保存关键长期数据的卷在安装时都已定义为全局卷,并以 sentry- 为前缀:

  • sentry-data
  • sentry-postgres
  • sentry-redis
  • sentry-zookeeper
  • sentry-kafka
  • sentry-clickhouse
  • sentry-symbolicator

注意:只有备份和恢复这些卷才能恢复所有持久化数据。如果您还需要备份运行中的数据,我们建议备份 docker-compose 自动创建的任何特定于项目的卷,通常使用 sentry_self_hosted_sentry- 前缀。

Docker 在他们的文档中记录了如何备份和恢复卷

只要可以毫无问题地读回卷,您就可以使用不同的方法。

自托管的自定义 CA 根

从 Sentry 21.8.0 开始,如果您需要没有来自公共信任 CA 根的 TLS 证书的 Sentry 访问服务,现在可以轻松地将它们添加到容器中。

只需将证书添加到 Sentry 安装根目录内的 certificates 文件夹中,然后重新启动容器。除了公共信任的 CA 根之外,还将使用您的自定义 CA 根。

注意:虽然您可以在每个容器中运行 update-ca-certificates,但这将更新磁盘上系统的根包,但不会对内存中的任何副本执行任何操作。重新启动容器将更新包并确保它被使用。

如果给定的证书有问题,容器的日志将在开始时具有 update-ca-certificates 的输出。

具有捆绑根的依赖项

一些依赖项选择捆绑自己的 CA 根并忽略系统 CA 根。

在已知的情况下,它们已被配置为使用系统根

如果某些东西似乎忽略了系统根,请创建一个 issue

以便对其进行跟踪和修复。

覆盖的捆绑根

  • Python

    • requests
    • botocore
    • grpc

自托管 Email

注意:请记住,一旦更改设置,您就需要重新启动所有 Sentry 服务。有关更多信息,请参阅配置部分。

出站 Email

自托管 Sentry 附带一个由 exim4 提供支持的内置外发 SMTP server

默认配置设置为使用此服务器。您需要做的就是为 config.yml 中的 mail.from 设置设置一个有效地址,

并为 .env 中的 SENTRY_MAIL_HOST 设置 Sentry 实例的 FQDN

请记住,如果您开始向公共地址发送过多电子邮件,您的新服务器可能会被标记为垃圾邮件发送者并被禁止。

如果您想使用外部 SMTP server,您可以在 config.yml 文件中设置相关的 mail.* 设置并忽略内置的 SMTP server

有关每个设置的含义和作用的所有详细信息,请参阅我们的电子邮件服务文档

由于配置的分层方式,如果您通过 Web 界面更新 mail 设置,您还需要注释掉 config.yml 中的 mail.host: 'smtp' 默认值,以便选择所需的设置。

入站 Email

Sentry 通过 Mailgun 提供的入站 mail 支持非常有限。

您可以在我们的入站 email 服务文档中找到有关如何进行设置的所有信息。

自托管地理定位

Sentry 可以使用 MaxMind 的免费 GeoLite2-City 数据库来对 IP 地址进行地理定位,

为已知最终用户 IP 地址的错误事件以及登录 Sentry 安装的用户的会话历史记录提供额外的上下文。

为此,我们捆绑了 MaxMindgeoipupdate 工具。

为了利用服务器端 IP 地址地理定位,您必须首先将 IP 地址发送到 Sentry。

默认情况下,较新的 SDK 不会执行此操作

要启用服务器端 IP 地址地理定位,请注册一个免费的 MaxMind 帐户

然后通过将您的 MaxMind 配置文件放在 geoip/GeoIP.conf 来告诉 Sentry 您的凭据。

AccountID 012345
LicenseKey foobarbazbuz
EditionIDs GeoLite2-City

有了这个配置文件,Sentryinstall.sh 的后续运行将刷新 IP 地址地理定位数据库。

下次您重新启动自托管的 Sentry 实例(特别是 relayweb 服务)时,您应该会看到最新的数据。

以下是确认它是否正常工作的方法:

  1. 对于 relay 服务:Dashboards > Errors by Country 上应该有一些紫色。

  2. 对于 web 服务:User Settings > Security > Session History 应在表中的 IP 地址下方显示国家代码和地区(例如,"US (CA)")。

启动后不久看到 sentry_self_hosted_geoipupdate_1 容器退出是正常的,因为更新地理定位数据库是一次性的批处理过程,而不是长时间运行的 job

升级

使用 GeoLite2-City.mmdb 文件的服务需要知道在哪里可以找到它。新安装将自动设置此设置,但如果您要升级,则需要在重新启动 Sentry 之前手动设置以下内容。

relay/config.yml 中(示例):

processing:
geoip_path: "/geoip/GeoLite2-City.mmdb"

sentry/sentry.conf.py 中(示例):

GEOIP_PATH_MMDB = '/geoip/GeoLite2-City.mmdb'

自托管单点登录 (SSO)

Sentry 中的 SSO 以两种方式之一处理:

  • 通过处理上游代理的中间件来指示经过身份验证的用户
  • 通过实现身份验证管道的第三方服务

使用中间件代理 (SAML2)

Sentry 20.6.0 开始,自托管 Sentry 内置了对 SAML2 和某些身份验证提供程序的支持。

对于旧版本,您需要在运行 ./install.sh 之前将以下行添加到 sentry/requirements.txt

sentry-auth-saml2@https://github.com/getsentry/sentry-auth-saml2/archive/master.zip#egg=sentry-auth-saml2

您可以设置它的方式与 sentry.io 相同,除了您需要为文档中提到的 URL 使用自己实例的 url-prefix

有关所有详细信息,请参阅我们的主要 SAML 文档

使用 OAuth 的单点登录

注意:启用 SSO 后,这将是登录到自托管实例的唯一方法。如果您需要与 SSO 一起免费注册,您可以在 GitHub PR 上对此发表评论。

Google Auth

Sentry 9.1 开始,自托管的 Sentry 带有内置的 Google Auth 支持。

要启用,您需要为您的 Google App 创建一个 client ID 和 secret

然后将这些值分别输入到您的 sentry/config.yaml 文件中:

auth-google.client-id: '<client id>'
auth-google.client-secret: '<client secret>'

注意:请记住,一旦更改设置,您就需要重新启动所有 Sentry 服务。有关更多信息,请参阅配置部分。

GitHub Auth

Sentry 10 开始,

自托管 Sentry 带有内置的 GitHub Auth 支持。要启用,您需要在您的组织下创建一个新的 GitHub App 并安装它。

为 SSO & integration 创建 GitHub App

GitHub App 名称不得包含任何空格。

如果上面的表单对您不起作用,您需要为您的 GitHub 应用程序进行以下设置:

Setting Value
Homepage URL ${urlPrefix}
User authorization callback URL ${urlPrefix}/auth/sso/
Setup URL (optional) ${urlPrefix}/extensions/github/setup/
Webhook URL ${urlPrefix}/extensions/github/webhook/

不要忘记将所有出现的 {'${urlPrefix}'} 替换为您自己的 url 前缀。

当提示输入权限时,请选择以下选项:

Permission Setting
Organization permissions / members Read-only
User permissions / Email addresses Read-only
Repository administration Read-only
Repository contents Read-only
Issues Read & write
Pull requests Read & write
Repository webhooks Read & write
使用您的 GitHub App 信息更新您的配置

然后,您需要设置以下配置值:

sentry/sentry.conf.py

GITHUB_APP_ID="<App ID>"
GITHUB_API_SECRET="<Client secret>"
GITHUB_REQUIRE_VERIFIED_EMAIL = True # Optional but recommended # Only if you are using GitHub Enterprise
#GITHUB_BASE_DOMAIN = "git.example.com"
#GITHUB_API_DOMAIN = "api.git.example.com"

sentry/config.yaml

# github-app.id: <App ID>
# github-app.name: '<GitHub App name>'
# github-app.webhook-secret: '<Webhook secret>' # Use only if configured in GitHub
# github-app.client-id: '<Client ID>'
# github-app.client-secret: '<Client secret>'
# github-app.private-key: |
# -----BEGIN RSA PRIVATE KEY-----
# privatekeyprivatekeyprivatekeyprivatekey
# privatekeyprivatekeyprivatekeyprivatekey
# privatekeyprivatekeyprivatekeyprivatekey
# privatekeyprivatekeyprivatekeyprivatekey
# privatekeyprivatekeyprivatekeyprivatekey
# -----END RSA PRIVATE KEY-----

这还将为您的实例启用 GitHub Integration

注意:请记住,一旦更改设置,您就需要重新启动所有 Sentry 服务。有关更多信息,请参阅配置部分。

自定义 Provider

目前,API 被认为是不稳定的,可能会发生变化。事情可能不会有太大变化,但有一些地方需要清理。

考虑到这一点,如果您想构建自己的,请查看上面的参考实现之一。

自托管故障排除

请记住,自托管存储库面向中低负载,并考虑到了简单性。

需要更大设置或有事件高峰的人们可以根据他们的特定需求和环境从这里扩展。

常见

您可以通过运行 docker-compose logs <service_name> 来查看每个服务的日志。

您可以使用 -f 标志来 "follow" 进入的日志,并使用 -t 标志作为时间戳。

如果您不传递任何服务名称,您将获得所有正在运行的服务的日志。

有关详细信息,请参阅 logs 命令的参考

Kafka

最有可能导致问题的事情之一是 Kafka。最常报告的错误是

Exception: KafkaError{code=OFFSET_OUT_OF_RANGE,val=1,str="Broker: Offset out of range"}

这发生在 Kafkaconsumer 不同步的地方。可能的原因有:

  1. 磁盘空间或内存不足
  2. 持续的事件峰值会导致很长的处理时间,导致 Kafka 在超过保留时间时丢弃消息
  3. 由于重新启动或 suspend/resume(暂停/恢复) 循环导致的 Date/time(日期/时间) 不同步问题

恢复

正确的解决方案

正确 的解决方案如下 (reported by @rmisyurev):

  1. 接收消费者列表:
    docker-compose run --rm kafka kafka-consumer-groups --bootstrap-server kafka:9092 --list
  2. 获取群组信息:
    docker-compose run --rm kafka kafka-consumer-groups --bootstrap-server kafka:9092 --group snuba-consumers -describe
  3. 使用试运行(可选)观察 offset 会发生什么:
    docker-compose run --rm kafka kafka-consumer-groups --bootstrap-server kafka:9092 --group snuba-consumers --topic events --reset-offsets --to-latest --dry-run
  4. offset 设置为最新并执行:
    docker-compose run --rm kafka kafka-consumer-groups --bootstrap-server kafka:9092 --group snuba-consumers --topic events --reset-offsets --to-latest --execute

您可以在需要时将 snuba-consumers 替换为其他 consumer groups 或其他 topics 的 events

硬核选项

硬核选项 是删除所有与 Kafka 相关的卷并重新创建它们,这将导致数据丢失。删除这些卷后,任何挂起的数据都_将_消失。

  1. 停止实例:

    docker-compose down --volumes
  2. 删除 Kafka & Zookeeper 相关卷:

    docker volume rm sentry-kafka
    docker volume rm sentry-zookeeper
  3. 再次运行安装脚本:

    ./install.sh
  4. 启动实例:

    docker-compose up -d

减少磁盘使用

如果你想减少 Kafka 使用的磁盘空间,你需要仔细计算你摄取的数据量,你可以容忍的数据丢失量,

然后按照这个很棒的 StackOverflow 帖子

我们社区论坛上的帖子中的建议进行操作。

Redis

在自托管设置中,Redis 既用作事务数据存储又用作 Celery 的工作队列。

出于这个原因,它可能会在事件高峰期间不堪重负。

从版本 20.10.1 开始,我们对此进行了一些重大改进。

如果您仍然遇到问题,您可以考虑扩展 Redis 本身或切换到不同的 Celery broker,例如 RabbitMQ

Workers

如果您看到错误,例如

Background workers haven’t checked in recently. It seems that you have a backlog of 200 tasks. Either your workers aren’t running or you need more capacity.

您可能会从使用额外的专职工作人员中受益。

这是通过在 docker-compose.override.yml 中创建新的 worker 服务并使用 -Q queue_name 参数将它们绑定到特定队列来实现的。 一个例子是:

worker1:
<< : *sentry_defaults
command: run worker -Q events.process_event

要查看更完整的示例,请参阅我们社区论坛上的示例解决方案

Postgres

Postgres 用于主数据存储,以及用于存储 key/value 数据的 nodestore

node_nodestore 表可以快速增长,尤其是在大量使用性能监控功能时,因为跟踪数据存储在该表中。

node_nodestore 表作为 cleanup 任务的一部分被清理,

但是 Postgres 可能没有机会清理表(尤其是在重载情况下),所以即使行可能被删除,它们仍然会占用磁盘空间。

您可以使用 pg-repack,它通过创建一个新表并在删除旧表之前复制数据来重新打包一个表。

您需要在清理脚本之后运行它,并注意它在创建表时,磁盘使用量会在回落之前激增

下面是一个脚本示例:

# Only keep the last 7 days of nodestore data. We heavily use performance monitoring.
docker-compose run -T web cleanup --days 7 -m nodestore -l debug
# This ensures pg-repack exists before running as the container gets recreated on upgrades
docker-compose run -T postgres bash -c "apt update && apt install -y --no-install-recommends postgresql-9.6-repack && su postgres -c 'pg_repack -E info -t nodestore_node'"

其他

如果您仍然遇到问题,您可以随时访问我们的社区论坛以搜索现有主题或创建新主题并寻求帮助。

请记住,我们希望社区能够帮助自己,并且 Sentry 员工也会在有时间时尝试监控和回答论坛问题。

报告问题或在论坛上提问时共享您的安装日志、服务日志和 Sentry 版本将为您和试图帮助您的人节省时间和精力。

Sentry 监控 - 私有 Docker Compose 部署与故障排除详解的更多相关文章

  1. Docker Compose 部署 Redis 及原理讲解 | 懒人屋

    原文:Docker Compose 部署 Redis 及原理讲解 | 懒人屋 Docker Compose 部署 Redis 及原理讲解  4.4k  字    16  分钟    2019-10-1 ...

  2. 使用Docker Compose部署基于Sentinel的高可用Redis集群

    使用Docker Compose部署基于Sentinel的高可用Redis集群 https://yq.aliyun.com/articles/57953 Docker系列之(五):使用Docker C ...

  3. Docker Compose 部署前后端分离应用

    部署前后端分离应用 容器化 Abp 应用 关于 Abp 应用的容器化,其实和普通的 ASP.NET Core 应用差不多,大家可以参考我此前的文章. 唯一需要注意的是:因为 Abp 解决方案中有多个项 ...

  4. Docker Compose部署项目到容器-基于Tomcat和mysql的项目yml配置文件代码

    场景 Docker-Compose简介与Ubuntu Server 上安装Compose: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...

  5. 在Windows Server 2019通过Docker Compose部署Asp.Net Core

    一.安装Docker Enterprise 安装文档是: https://docs.docker.com/install/windows/docker-ee/ 安装完成后,如下图 二.首先,拉取一个W ...

  6. 使用Docker Compose 部署Nexus后初次登录账号密码不正确,并且在nexus-data下没有admin,password

    场景 Ubuntu Server 上使用Docker Compose 部署Nexus(图文教程): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/ ...

  7. Ubuntu Server 上使用Docker Compose 部署Nexus(图文教程)

    场景 Docker-Compose简介与Ubuntu Server 上安装Compose: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...

  8. Docker Compose部署Nexus3时的docker-compose,yml代码

    场景 Docker-Compose简介与Ubuntu Server 上安装Compose: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...

  9. Docker Compose部署GitLab服务,搭建自己的代码托管平台(图文教程)

    场景 Docker-Compose简介与Ubuntu Server 上安装Compose: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...

随机推荐

  1. C#与dotNET项目想要另存为一个新项目sln文件丢了怎么办

    如下图所示,我想要另存一个工程,把 V4.4整个的项目另存为V4.5,我可以把解决方案文件(.sln)改名字,但是我没法把文件夹改名字,改了打开sln就说找不到. 很简单的一个思路是反正sln是多余的 ...

  2. Redis集群与高可用

    Redis集群 redis cluster 是redis官方提供的分布式解决方案,在3.0版本后推出的,有效地解决了redis分布式的需求,当一个redis节点挂了可以快速的切换到另一个节点.当遇到单 ...

  3. nginx 支持websocket

    nginx 反向代理websocket nginx配置 请求地址及路径:ws://x.x.x.x/web/springws/websocket.ws 解析 map 指令 上面 nginx.conf 配 ...

  4. 花了30天才肝出来,史上最全面Java设计模式总结,看完再也不会忘

    本文所有内容均节选自<设计模式就该这样学> 序言 Design Patterns: Elements of Reusable Object-Oriented Software(以下简称&l ...

  5. 基于Docker搭建Maven私服Nexus,Nexus详解

    备注:首先在linux环境安装Java环境和Docker,私服需要的服务器性能和硬盘存储要高一点,内存不足可能到时启动失败,这里以4核8GLinux服务器做演示 一:基于Docker安装nexus3 ...

  6. 最小生成树(MST)详解+题目

    原因 回顾一下旧知识 概况 在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集(即)且为无 ...

  7. CF611F New Year and Cleaning

    题意 CF611F New Year and Cleaning 想法 这个题是\(NOIP2020\)的弱化版.. 我们把所有在二维上的点都一起考虑,那么所有点对于一个步骤的移动是相当于这些所有点所组 ...

  8. 【Matrix-tree Theorem学习笔记】

    定义度数矩阵\(D(G)\): 定义邻接矩阵\(C(G)\): 定义\(Laplace\)矩阵\(A\) \( A(G) = D(G) - C(G) \) 记图\(G\)的所有生成树权值和为\(t(G ...

  9. VSCode + PicGo + Github + jsDelivr 搭建稳定快速高效图床

    VSCode + PicGo + Github + jsDelivr 搭建稳定快速高效图床 目录 前言 准备 配置 验证 前言 所谓图床,就是将图片储存到第三方静态资源库中,其返回给你一个 URL 进 ...

  10. dlang 安装

    刷论坛看到TIOBE排行榜,排名靠前的基本是C.C++.java.python之类的语言,常用的R语言近几年排名一路走高,前20基本变化不大. 后面发现第二十九位居然有个叫做D的语言,看了下和C语法很 ...