亲,只收二进制

总结最近半年对Elasticsearch开源项目的贡献

自从2019年对Elasticsearch项目提交过一次代码之后,开始逐渐关注社区里的新动态,并且尝试去解决一些issue,通过这个过程去理解源码从而可以深入理解Elasticsearch的实现机制。现在把最近半年(2020年1月-2020年6月)对Elasticsearch项目所做的工作进行一次总结,记录遇到的问题和解决办法。

ingest set processor增加ignore_empty_value参数

issue: #54783

PR: #57030

使用ingest set processor时, 如果对于value字段为空字符串或者null的情况不需要进行处理,当前只能通过脚本判断value是否为空字符串或者null。本次提交对set processor增加了ignore_empty_value参数,设置该参数为true后,set processor会自动规避value字段为空字符串或者null的情况, 不对文档进行任何修改,优雅的退出处理逻辑。

修复reindex api bug

issue: #52786

PR: #54901

调用reindex api,当max_docs参数<slices时,会报错max_docs为0,实际上是因为没有提前校验max_docs是否<slices,导致max_docs被设置为0。本次提交修复了这个bug,并且给出比较清晰的错误提示。

当使用date_nanos字段作为过滤条件并且使用now时,无法创建filtered alias

issue: #54315

PR: #54785

PUT date_source/_alias/date_nanos_alias
{
  "filter": {
   "range": {
      "date_nanos": {
        "gt": "now-7d/d"
      }
    }
  }
}

如上述操作,创建filtered alias时,以date_nanos字段为过滤条件,并且使用了now,会导致创建别名失败;该提交主要是修改了queryShardContext中的nowInMillis值,设置为当前时间戳。

禁止修改nested字段的include_in_root、include_in_parent参数

issue: #53792

PR: #54386

nested字段的include_in_root、include_in_parent参数,是无法进行修改的,但是当前调用PUT {index}/_mapping API进行修改时却没有报错,本次提交的改动是在修改两个参数时抛出400参数错误。

对所有处理字符串类型数据的ingest processor,支持字段值为数组

issue: #51087

PR: #53343

对Lowercase Processors、Uppercase Processors、Trim Processors等处理字符串类型数据的ingest processor, 都支持要处理的字段类型为数组类型。

修复_search/template API返回结果总量不准的bug

issue: #52801

PR: #53155

调用GET _search/template API时,如果设置了rest_total_hits_as_int为true,处理逻辑应该和GET _search API一致,trackTotalHitsUpTo变量会被设置为Integer.MAX_VALUE,因此都能够获取到准确的total hits count。但是在_search/template API的处理逻辑中,虽然rest_total_hits_as_int设置为了true, trackTotalHitsUpTo值却没有被设置,因此只能获取到最多为10000的total hits。

修复ingest pipeline simulate API异常处理bug

issue: #52833

PR: #52937

调用POST _ingest/pipeline/_simulate API时,如果传入的docs参数是空列表,则什么结果都不会返回。 Bug产生的原因是,在异步请求的ActionListener中没有对docs参数进行判空,导致始终没有响应给客户端。

修复删除enrich policy时的bug

issue: #5122.

PR: #52179

enrich policy关联的索引名称的格式为[policy_name]-*,在调用删除enrich policy的API:DELETE /_enrich/policy/时,需要删除所有的以[policy_name]开头的索引,因为代码直接通过通配符进行删除,如果设置了action.destructive_requires_name参数为true,则删除enrich policy会报错‘Wildcard expressions or all indices are not allowed’. 本次提交的改动是不直接通过通配符删除索引,获取到所有的索引名称后进行批量删除。

当因磁盘写满而导致ES自动对索引设置read_only_allow_delete block时,对http请求返回429状态码而不是403

issue: #49393

PR: #50166

这个提交有意思了,耗时也非常久,中间经过数次代码调整与优化。这个改动的初衷是因为在磁盘写满的情况下,ES会自动地把对应节点上的索引设置为只读(index.read_only_allow_delete=true), 后续有新的写入请求进来后,会直接返回403状态码拒绝进行写入。实际上,ES对所有类型的block,对应的http状态码都设置为403, 这就会导致一个问题,在部分客户端比如rest client碰到403的状态码,是不会对写入请求进行重试的,直接丢弃掉请求,导致数据丢失。所以该提交就需要针对因为index.read_only_allow_delete为true的情况,返回429状态码(429意思是TOO_MANY_REQUESTS, 请求太多,需要限流)。在提交代码之后,和社区的maintainer针对单元测试代码经过数次讨论,最终才被合并进master分支。讨论的焦点在于,6.8版本之后,如果磁盘空间释放出来,索引的只读的状态会被自动的release,有单独的线程轮询检查磁盘来确定要不要释放只读状态,所以需要对auto release机制是否开启进行随机选择。一方面,auto release开启,因为客户端接收到429状态码,写入请求经过重试后能够成功执行;另一方面,关闭auto release, 写入请求经过数次重试后仍然执行失败而报错。

elasticsearch-croneval工具异常捕获

issue: #49642

PR: #49744

elasticsearch-croneval工具是一个社区提供的用于校验cron表达式是否正确的一个工具,放置在elasticsearch安装目录的bin目录下。该工具的执行实际上调用了项目中的CronEvalTool类的main方法,实际上在执行的过程中,因为没有正确地捕获异常,导致在对非法的cron表达式进行校验时,工具直接把整个stacktrace信息都打印出来了。针对这个issue所做的提交捕获了这个异常,并给出了较为简明的错误信息。第一次提交之后,项目的maintainer表示要对这个改动进行team-discuss, 最终讨论下来的结果是:对该工具增加一个默认关闭的命令行参数,如果用户有需要查看完整的异常信息,添加该参数即可,默认情况下只显示简短的错误信息。

自定义normalizer无法使用bug修复

issue: #48650

PR: #48866

该bug是在7.x版本引入的,因为对自定义analyzer的代码进行了重构,导致所有custom normalizer都无法正常使用。可能因为normalizer的使用者并不是很多,一直到7.5发布后才被发现,该提交在7.6版本已经发布。关于这个bug的修复,有单独一篇文章进行介绍记一次向Elasticsearch开源社区贡献代码的经历.

继续阅读 »

自从2019年对Elasticsearch项目提交过一次代码之后,开始逐渐关注社区里的新动态,并且尝试去解决一些issue,通过这个过程去理解源码从而可以深入理解Elasticsearch的实现机制。现在把最近半年(2020年1月-2020年6月)对Elasticsearch项目所做的工作进行一次总结,记录遇到的问题和解决办法。

ingest set processor增加ignore_empty_value参数

issue: #54783

PR: #57030

使用ingest set processor时, 如果对于value字段为空字符串或者null的情况不需要进行处理,当前只能通过脚本判断value是否为空字符串或者null。本次提交对set processor增加了ignore_empty_value参数,设置该参数为true后,set processor会自动规避value字段为空字符串或者null的情况, 不对文档进行任何修改,优雅的退出处理逻辑。

修复reindex api bug

issue: #52786

PR: #54901

调用reindex api,当max_docs参数<slices时,会报错max_docs为0,实际上是因为没有提前校验max_docs是否<slices,导致max_docs被设置为0。本次提交修复了这个bug,并且给出比较清晰的错误提示。

当使用date_nanos字段作为过滤条件并且使用now时,无法创建filtered alias

issue: #54315

PR: #54785

PUT date_source/_alias/date_nanos_alias
{
  "filter": {
   "range": {
      "date_nanos": {
        "gt": "now-7d/d"
      }
    }
  }
}

如上述操作,创建filtered alias时,以date_nanos字段为过滤条件,并且使用了now,会导致创建别名失败;该提交主要是修改了queryShardContext中的nowInMillis值,设置为当前时间戳。

禁止修改nested字段的include_in_root、include_in_parent参数

issue: #53792

PR: #54386

nested字段的include_in_root、include_in_parent参数,是无法进行修改的,但是当前调用PUT {index}/_mapping API进行修改时却没有报错,本次提交的改动是在修改两个参数时抛出400参数错误。

对所有处理字符串类型数据的ingest processor,支持字段值为数组

issue: #51087

PR: #53343

对Lowercase Processors、Uppercase Processors、Trim Processors等处理字符串类型数据的ingest processor, 都支持要处理的字段类型为数组类型。

修复_search/template API返回结果总量不准的bug

issue: #52801

PR: #53155

调用GET _search/template API时,如果设置了rest_total_hits_as_int为true,处理逻辑应该和GET _search API一致,trackTotalHitsUpTo变量会被设置为Integer.MAX_VALUE,因此都能够获取到准确的total hits count。但是在_search/template API的处理逻辑中,虽然rest_total_hits_as_int设置为了true, trackTotalHitsUpTo值却没有被设置,因此只能获取到最多为10000的total hits。

修复ingest pipeline simulate API异常处理bug

issue: #52833

PR: #52937

调用POST _ingest/pipeline/_simulate API时,如果传入的docs参数是空列表,则什么结果都不会返回。 Bug产生的原因是,在异步请求的ActionListener中没有对docs参数进行判空,导致始终没有响应给客户端。

修复删除enrich policy时的bug

issue: #5122.

PR: #52179

enrich policy关联的索引名称的格式为[policy_name]-*,在调用删除enrich policy的API:DELETE /_enrich/policy/时,需要删除所有的以[policy_name]开头的索引,因为代码直接通过通配符进行删除,如果设置了action.destructive_requires_name参数为true,则删除enrich policy会报错‘Wildcard expressions or all indices are not allowed’. 本次提交的改动是不直接通过通配符删除索引,获取到所有的索引名称后进行批量删除。

当因磁盘写满而导致ES自动对索引设置read_only_allow_delete block时,对http请求返回429状态码而不是403

issue: #49393

PR: #50166

这个提交有意思了,耗时也非常久,中间经过数次代码调整与优化。这个改动的初衷是因为在磁盘写满的情况下,ES会自动地把对应节点上的索引设置为只读(index.read_only_allow_delete=true), 后续有新的写入请求进来后,会直接返回403状态码拒绝进行写入。实际上,ES对所有类型的block,对应的http状态码都设置为403, 这就会导致一个问题,在部分客户端比如rest client碰到403的状态码,是不会对写入请求进行重试的,直接丢弃掉请求,导致数据丢失。所以该提交就需要针对因为index.read_only_allow_delete为true的情况,返回429状态码(429意思是TOO_MANY_REQUESTS, 请求太多,需要限流)。在提交代码之后,和社区的maintainer针对单元测试代码经过数次讨论,最终才被合并进master分支。讨论的焦点在于,6.8版本之后,如果磁盘空间释放出来,索引的只读的状态会被自动的release,有单独的线程轮询检查磁盘来确定要不要释放只读状态,所以需要对auto release机制是否开启进行随机选择。一方面,auto release开启,因为客户端接收到429状态码,写入请求经过重试后能够成功执行;另一方面,关闭auto release, 写入请求经过数次重试后仍然执行失败而报错。

elasticsearch-croneval工具异常捕获

issue: #49642

PR: #49744

elasticsearch-croneval工具是一个社区提供的用于校验cron表达式是否正确的一个工具,放置在elasticsearch安装目录的bin目录下。该工具的执行实际上调用了项目中的CronEvalTool类的main方法,实际上在执行的过程中,因为没有正确地捕获异常,导致在对非法的cron表达式进行校验时,工具直接把整个stacktrace信息都打印出来了。针对这个issue所做的提交捕获了这个异常,并给出了较为简明的错误信息。第一次提交之后,项目的maintainer表示要对这个改动进行team-discuss, 最终讨论下来的结果是:对该工具增加一个默认关闭的命令行参数,如果用户有需要查看完整的异常信息,添加该参数即可,默认情况下只显示简短的错误信息。

自定义normalizer无法使用bug修复

issue: #48650

PR: #48866

该bug是在7.x版本引入的,因为对自定义analyzer的代码进行了重构,导致所有custom normalizer都无法正常使用。可能因为normalizer的使用者并不是很多,一直到7.5发布后才被发现,该提交在7.6版本已经发布。关于这个bug的修复,有单独一篇文章进行介绍记一次向Elasticsearch开源社区贡献代码的经历.

收起阅读 »

社区日报 第975期 (2020-06-21)

1.使用Elasticsearch,Logstash和Kibana为NGINX日志设置ELK。
http://t.cn/RBTxsci
2.API网关Kong自定义log_format的日志利用ELK进行Kibana图展示的过程。
http://t.cn/A6LCWDQK
3.10个打开了我新世界大门的 WebAPI。
http://t.cn/A6LiJ8fW
编辑:至尊宝
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
继续阅读 »
1.使用Elasticsearch,Logstash和Kibana为NGINX日志设置ELK。
http://t.cn/RBTxsci
2.API网关Kong自定义log_format的日志利用ELK进行Kibana图展示的过程。
http://t.cn/A6LCWDQK
3.10个打开了我新世界大门的 WebAPI。
http://t.cn/A6LiJ8fW
编辑:至尊宝
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 收起阅读 »

社区日报 第974期 (2020-06-20)

1.使用docker-compose和Traefik构建负载均衡的es集群

http://t.cn/A6LKhRx2

2.使用kibana进行交通数据分析(需翻墙)

http://t.cn/A6LKzaT1

3.使用spark和es构建简单推荐系统

http://t.cn/Rj8rNDe

继续阅读 »

1.使用docker-compose和Traefik构建负载均衡的es集群

http://t.cn/A6LKhRx2

2.使用kibana进行交通数据分析(需翻墙)

http://t.cn/A6LKzaT1

3.使用spark和es构建简单推荐系统

http://t.cn/Rj8rNDe

收起阅读 »

社区日报 第973期 (2020-06-19)

1、Elastic Stack 7.8.0 重磅发布
https://t.cn/A6LXwACd
2、Elasticsearch 7.8.0 新特性
https://t.cn/A6LXwAHK
3、选型必备:clickhouse VS Elasticsearch
https://t.cn/A6LXZsM2

编辑:铭毅天下
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
 
继续阅读 »
1、Elastic Stack 7.8.0 重磅发布
https://t.cn/A6LXwACd
2、Elasticsearch 7.8.0 新特性
https://t.cn/A6LXwAHK
3、选型必备:clickhouse VS Elasticsearch
https://t.cn/A6LXZsM2

编辑:铭毅天下
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
  收起阅读 »

社区日报 第972期 (2020-06-18)

1.总结最近半年对Elasticsearch开源项目的贡献
https://t.cn/A6LxYp8k
2.记录一次Flink作业异常的排查过程
https://t.cn/A6LxYOg9
3.Logstash:运用 Elasticsearch 过滤器来丰富数据
https://t.cn/A6LxYlE1

编辑:金桥
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
继续阅读 »
1.总结最近半年对Elasticsearch开源项目的贡献
https://t.cn/A6LxYp8k
2.记录一次Flink作业异常的排查过程
https://t.cn/A6LxYOg9
3.Logstash:运用 Elasticsearch 过滤器来丰富数据
https://t.cn/A6LxYlE1

编辑:金桥
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 收起阅读 »

Elastic Certified Analyst 徽章到手!

Update!
关于认证考试的内容,我做了一次直播分享,感兴趣的可以来这里查看!

https://www.yuque.com/elastictalk/blog/et26
 
 
 Elastic 最近推出了新的认证考试,Elastic Certified Analyst,主要是考察大家对 Kibana 的掌握程度。
https://www.elastic.co/trainin ... -exam

我上周参加了下,顺利拿到徽章,题目还是比较有意思的,周末找时间直播和大家聊一聊!
 

Elastic_Certified_Analyst.png

 
继续阅读 »
Update!
关于认证考试的内容,我做了一次直播分享,感兴趣的可以来这里查看!

https://www.yuque.com/elastictalk/blog/et26
 
 
 Elastic 最近推出了新的认证考试,Elastic Certified Analyst,主要是考察大家对 Kibana 的掌握程度。
https://www.elastic.co/trainin ... -exam

我上周参加了下,顺利拿到徽章,题目还是比较有意思的,周末找时间直播和大家聊一聊!
 

Elastic_Certified_Analyst.png

  收起阅读 »

Elastic日报 第970期 (2020-06-16)

1、 使用Elasticsearch和Spark设计一个推荐系统。
https://t.cn/A6LtN6Ya
2、(自带梯子)Elasticsearch和Nodejs实现分页功能。
https://t.cn/A6LtNaaT
3、Elasticsearch入门到实战合计,带思维导图。
https://t.cn/A6LtNoXG

编辑:叮咚光军
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
继续阅读 »
1、 使用Elasticsearch和Spark设计一个推荐系统。
https://t.cn/A6LtN6Ya
2、(自带梯子)Elasticsearch和Nodejs实现分页功能。
https://t.cn/A6LtNaaT
3、Elasticsearch入门到实战合计,带思维导图。
https://t.cn/A6LtNoXG

编辑:叮咚光军
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 收起阅读 »

社区日报 第969期 (2020-06-15)

1、谈一谈elasticsearch的优势和限制
http://t.cn/A6LbIGAI

2、如何有惊无险入门 Elasticsearch 
http://t.cn/A6LbI9Zq

3、Bulk 异常引发的 Elasticsearch 内存泄漏排查
http://t.cn/RFBHC1p

编辑:cyberdak
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
继续阅读 »
1、谈一谈elasticsearch的优势和限制
http://t.cn/A6LbIGAI

2、如何有惊无险入门 Elasticsearch 
http://t.cn/A6LbI9Zq

3、Bulk 异常引发的 Elasticsearch 内存泄漏排查
http://t.cn/RFBHC1p

编辑:cyberdak
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 收起阅读 »

社区日报 第968期 (2020-06-14)

1.如何在Kubernetes上部署ELK。
http://t.cn/A6L2ZAza
2.如何将EFK堆栈部署到Kubernetes。
http://t.cn/A6L2ZG1d
3.什么是区块链。
http://t.cn/Ai1MifUn

编辑:至尊宝
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
继续阅读 »
1.如何在Kubernetes上部署ELK。
http://t.cn/A6L2ZAza
2.如何将EFK堆栈部署到Kubernetes。
http://t.cn/A6L2ZG1d
3.什么是区块链。
http://t.cn/Ai1MifUn

编辑:至尊宝
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 收起阅读 »

社区日报 第967期 (2020-06-13)

1.es与zabbix对接

http://t.cn/A6LADTFW

2.post_filter的用法

http://t.cn/A6L2v9Ww

3.es结合transformer进行问答搜索

http://t.cn/A6PushY3

继续阅读 »

1.es与zabbix对接

http://t.cn/A6LADTFW

2.post_filter的用法

http://t.cn/A6L2v9Ww

3.es结合transformer进行问答搜索

http://t.cn/A6PushY3

收起阅读 »

社区日报 第966期 (2020-06-12)

1.Elasticsearch自定义评分的N种方法
https://t.cn/A6LZqQDa
2.使用 Filebeat 进行日志结构化
https://t.cn/A6LZqQDa
3.使用Filebeat传送多行日志
https://t.cn/A6LZqQDa

编辑:wt
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
继续阅读 »
1.Elasticsearch自定义评分的N种方法
https://t.cn/A6LZqQDa
2.使用 Filebeat 进行日志结构化
https://t.cn/A6LZqQDa
3.使用Filebeat传送多行日志
https://t.cn/A6LZqQDa

编辑:wt
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 收起阅读 »

社区日报 第965期 (2020-06-11)

1.Vega可视化入门
https://t.cn/A6Lvnttu
2.基于Go+MySQL+ES实现一个Tag API服务
https://t.cn/A6LvnVu0
3.如何设计实时数据平台
https://t.cn/A6LvninJ

编辑:金桥
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
继续阅读 »
1.Vega可视化入门
https://t.cn/A6Lvnttu
2.基于Go+MySQL+ES实现一个Tag API服务
https://t.cn/A6LvnVu0
3.如何设计实时数据平台
https://t.cn/A6LvninJ

编辑:金桥
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 收起阅读 »

社区日报 第964期 (2020-06-10)

1、Elasticsearch mapping 不能更新解决方案
https://blog.cocktail1024.top/archives/121.html
2、Elasticsearch 爬坑日记
https://blog.cocktail1024.top/archives/119.html
3、腾讯万亿级 Elasticsearch 内存效率提升解密
https://t.cn/A62sJX4Y
 
编辑:江水
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
 
继续阅读 »
1、Elasticsearch mapping 不能更新解决方案
https://blog.cocktail1024.top/archives/121.html
2、Elasticsearch 爬坑日记
https://blog.cocktail1024.top/archives/119.html
3、腾讯万亿级 Elasticsearch 内存效率提升解密
https://t.cn/A62sJX4Y
 
编辑:江水
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
  收起阅读 »

社区日报 第963期 (2020-06-09)

1、 完美避坑!记一次Elasticsearch集群迁移架构实战。
http://tinyurl.com/yccx8xck
2、重新认识一下Elasticsearch7.7的新鲜事务。
http://tinyurl.com/ycanvumw
3、DB 与 Elasticsearch混合应用之数据离线同步。
http://tinyurl.com/y77tds75

编辑:叮咚光军
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
继续阅读 »
1、 完美避坑!记一次Elasticsearch集群迁移架构实战。
http://tinyurl.com/yccx8xck
2、重新认识一下Elasticsearch7.7的新鲜事务。
http://tinyurl.com/ycanvumw
3、DB 与 Elasticsearch混合应用之数据离线同步。
http://tinyurl.com/y77tds75

编辑:叮咚光军
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 收起阅读 »

社区日报 第962期 (2020-06-08)

1.使用elastic workplace search进行google网盘搜索;
https://t.cn/A62d5s5P
2.兼容elasticsearch的轻量级自然语言处理引擎;
https://t.cn/A62mLc1f
3.如何给一个SQL应用添加强大搜索功能?
https://t.cn/A62d5sKd

编辑:wt
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
继续阅读 »
1.使用elastic workplace search进行google网盘搜索;
https://t.cn/A62d5s5P
2.兼容elasticsearch的轻量级自然语言处理引擎;
https://t.cn/A62mLc1f
3.如何给一个SQL应用添加强大搜索功能?
https://t.cn/A62d5sKd

编辑:wt
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 收起阅读 »