文章采集api

文章采集api

解决方案:Serverless在游戏运营行业进行数据采集分析的最佳实践

采集交流优采云 发表了文章 • 0 个评论 • 93 次浏览 • 2022-11-07 16:58 • 来自相关话题

  解决方案:Serverless在游戏运营行业进行数据采集分析的最佳实践
  • 触发器名称:defaultTrigger
  • 身份验证方法:匿名(即无需身份验证)
  • 请求方法:GET、POST
  创建函数后,我们通过在线编辑器编写代码:
  # -*- coding: utf-8 -*-
import logging
import json
import urllib.parse
HELLO_WORLD = b'Hello world!\n'
def handler(environ, start_response):
logger = logging.getLogger()
context = environ['fc.context']
request_uri = environ['fc.request_uri']
for k, v in environ.items():
if k.startswith('HTTP_'):
# process custom request headers
pass
try:
request_body_size = int(environ.get('CONTENT_LENGTH', 0))
except (ValueError):
request_body_size = 0
# 接收回传的数据
request_body = environ['wsgi.input'].read(request_body_size)
request_body_str = urllib.parse.unquote(request_body.decode("GBK"))
request_body_obj = json.loads(request_body_str)
logger.info(request_body_obj["action"])
logger.info(request_body_obj["articleAuthorId"])
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return [HELLO_WORLD]
  这时候的代码很简单,就是要接收用户的参数,我们可以调用接口进行验证:
  您可以在函数的日志查询中看到此调用的日志:
  同时,我们还可以查看函数的link trace来分析每一步的调用时间,比如函数接收请求的过程→冷启动(没有活动实例时)→准备代码→执行初始化方法→执行入口函数逻辑:
  从调用链接图中可以看出,之前的请求收录了冷启动时间,因为当时没有活动实例,整个过程耗时418毫秒,入口函数代码的实际执行时间为8毫秒。
  再次调用该接口时,可以看到直接执行了入口函数的逻辑,因为此时已经有一个实例在运行,整个时间只有2.3毫秒:
  2. 处理数据的函数
  第一个函数是通过函数计算控制台在界面上创建的,运行环境选择Python3。我们可以在官方文档中查看预设的Python3运行环境中构建了哪些模块,因为第二个功能需要操作Kafka和RDS,所以需要确认对应的模块。
  从文档中可以看出,内置模块包括RDS的SDK模块,但没有Kafka的SDK模块。这时候我们需要手动安装Kafka SDK模块,创建功能也会使用另一种方式。
  Funcraft
  Funcraft是一款支持Serverless应用部署的命令行工具,可以帮助我们方便的管理函数计算、API网关、日志服务等资源。它通过资源配置文件(template.yml)帮助我们进行开发、构建和部署。
  所以第二个函数我们需要用Fun来操作,整个操作分为四步:
  • 安装有趣的工具。
  • 编写template.yml 模板文件来描述函数。
  • 安装我们需要的第 3 方依赖项。
  • 上传部署功能。
  安装乐趣
  Fun提供了三种安装方式:
  • 通过npm 包管理安装- 适用于所有平台(Windows/Mac/Linux)上预装npm 的开发人员。
  • 通过下载二进制文件安装- 适用于所有平台(Windows/Mac/Linux)。
  • 通过 Homebrew 包管理器安装——适用于 Mac 平台,更符合 MacOS 开发者习惯。
  文例环境是Mac,所以使用npm安装,很简单,一行命令搞定:
  sudo npm install @alicloud/fun -g
  安装完成后。在控制终端输入fun命令查看版本信息:
  $ fun --version
3.6.20
  第一次使用fun前,需要执行fun config命令进行配置,按照提示依次配置Account ID、Access Key Id、Secret Access Key、Default Region Name。Account ID 和 Access Key Id 可以在函数计算控制台首页右上角获取:
  有趣的配置
  ? 阿里云账号ID 01
  ? 阿里云Access Key ID qef6j
  ? 阿里云Access Key Secret ***UFJG
  ? 默认地域名称 cn-hangzhou
  ? 每个 SDK 客户端调用的超时时间(秒) 60
  ? 每个 SDK 客户端的最大重试次数 3
  编写模板.yml
  创建一个新目录,并在此目录中创建一个名为 template.yml 的 YAML 文件。该文件主要描述了要创建的函数的配置。说白了,函数计算控制台上配置的配置信息是用 YAML 格式写的。在文件中:
  ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
FCBigDataDemo:
Type: 'Aliyun::Serverless::Service'
Properties:
Description: 'local invoke demo'
VpcConfig:
VpcId: 'vpc-xxxxxxxxxxx'
VSwitchIds: [ 'vsw-xxxxxxxxxx' ]
SecurityGroupId: 'sg-xxxxxxxxx'
LogConfig:
Project: fcdemo
Logstore: fc_demo_store
dataToKafka:
Type: 'Aliyun::Serverless::Function'
Properties:
Initializer: index.my_initializer
Handler: index.handler
CodeUri: './'
Description: ''
Runtime: python3
  我们来解析一下上面文件的核心内容:
  • FCBigDataDemo:自定义服务名称。该服务由以下Type属性表示,即Aliyun::Serverless::Service。
  • 属性:属性下的属性都是服务的配置项。
  • VpcConfig:服务的VPC配置,包括:
  
  VpcId:VPC ID。VSwitchIds:交换机ID,这里是一个数组,可以配置多个交换机。SecurityGroupId:安全组 ID。
  • LogConfig:服务绑定日志服务 (SLS) 配置,包括:
  项目:日志服务项目。日志存储:日志存储名称。
  • dataToKafka:该服务下用户定义的函数名。该函数由以下Type属性表示,即Aliyun::Serverless::Function。
  • 属性:属性下的属性都是该功能的配置项。
  • Initializer:配置初始化函数。
  • Handler:配置入口函数。
  • 运行时:函数运行时环境。
  目录结构为:
  安装第三方依赖
  在创建了服务和功能的模板之后,让我们安装我们需要使用的第三方依赖项。在本例的场景中,第二个功能需要用到Kafka SDK,所以可以通过fun工具结合Python包管理工具pip来安装:
  有趣的安装 --runtime python3 --package-type pip kafka-python
  执行命令后,出现如下提示信息:
  此时我们会发现目录下会生成一个.fun文件夹,我们安装的依赖都在这个目录下:
  部署功能
  现在模板文件写好了,我们需要的Kafka SDK也安装好了,我们需要添加我们的代码文件index.py。代码内容如下:
  # -*- coding: utf-8 -*-
import logging
import json
import urllib.parse
from kafka import KafkaProducer
producer = None
def my_initializer(context):
logger = logging.getLogger()
logger.info("init kafka producer")
global producer
producer = KafkaProducer(bootstrap_servers='XX.XX.XX.XX:9092,XX.XX.XX.XX:9092,XX.XX.XX.XX:9092')
def handler(event, context):
logger = logging.getLogger()
# 接收回传的数据
event_str = json.loads(event)
event_obj = json.loads(event_str)
logger.info(event_obj["action"])
logger.info(event_obj["articleAuthorId"])
# 向Kafka发送消息
global producer
producer.send('ikf-demo', json.dumps(event_str).encode('utf-8'))
producer.close()
return 'hello world'
  代码很简单,这里简单分析一下:
  • my_initializer:当函数实例被拉起时,会先执行函数,然后再执行handler函数。当函数实例运行时,后续请求不会执行 my_initializer 函数。一般用于各种连接的初始化。初始化Kafka Producer的方法放在这里,避免重复初始化Producer。
  • handler:这个函数只有两个逻辑,接收返回的数据和将数据发送到Kafka的指定topic。
  让我们使用 fun deploy 命令来部署函数,它做了两件事:
  • 根据template.yml 中的配置创建服务和功能。
  • 将 index.py 和 .fun 上传到函数中。
  登录函数计算控制台,可以看到通过 fun 命令部署的服务和函数:
  进入函数,还可以清晰的看到第三方依赖包的目录结构:
  3.函数之间的调用
  目前,这两个功能都已创建。下面的工作就是在第一个函数接收到数据后,拉起第二个函数向Kafka发送消息。我们只需要对第一个函数进行一些更改:
  # -*- coding: utf-8 -*-
import logging
import json
import urllib.parse
import fc2
HELLO_WORLD = b'Hello world!\n'
client = None
def my_initializer(context):
logger = logging.getLogger()
logger.info("init fc client")
global client
client = fc2.Client(
endpoint="http://your_account_id.cn-hang ... ot%3B,
accessKeyID="your_ak",
accessKeySecret="your_sk"
)
def handler(environ, start_response):
logger = logging.getLogger()
context = environ['fc.context']
request_uri = environ['fc.request_uri']
for k, v in environ.items():
if k.startswith('HTTP_'):
# process custom request headers
pass
try:
request_body_size = int(environ.get('CONTENT_LENGTH', 0))
except (ValueError):
request_body_size = 0
# 接收回传的数据
request_body = environ['wsgi.input'].read(request_body_size)
request_body_str = urllib.parse.unquote(request_body.decode("GBK"))
request_body_obj = json.loads(request_body_str)
logger.info(request_body_obj["action"])
logger.info(request_body_obj["articleAuthorId"])
global client
client.invoke_function(
'FCBigDataDemo',
'dataToKafka',
payload=json.dumps(request_body_str),
headers = {'x-fc-invocation-type': 'Async'}
)
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
<p>
return [HELLO_WORLD]</p>
  如上代码所示,对第一个函数的代码做了三处改动:
  • 导入函数计算的库:import fc2
  • 添加创建函数计算客户端的初始化方法:
  def my_initializer(context):
logger = logging.getLogger()
logger.info("init fc client")
global client
client = fc2.Client(
endpoint="http://your_account_id.cn-hang ... ot%3B,
accessKeyID="your_ak",
accessKeySecret="your_sk"
)
  这里需要注意的是,我们在代码中添加初始化方法时,需要在函数配置中指定初始化方法的入口:
  • 通过函数计算客户端调用第二个函数:
  global client
client.invoke_function(
&#39;FCBigDataDemo&#39;,
&#39;dataToKafka&#39;,
payload=json.dumps(request_body_str),
headers = {&#39;x-fc-invocation-type&#39;: &#39;Async&#39;}
)
  invoke_function 函数有四个参数:
  • 第一个参数:调用函数的服务的名称。
  • 第二个参数:调用函数的函数名。
  • 第三个参数:传递给调用函数的数据。
  • 第四个参数:调用第二个函数Request Header 信息。这里x-fc-invocation-type的key用来设置是同步调用还是异步调用。这里 Async 设置为异步调用。
  通过这个设置,我们可以验证请求是通过第一个函数提供的HTTP接口发起的→采集数据→调用第二个函数→将数据作为消息传递给Kafka。
  使用两个函数的目的
  这里有同学可能会有疑问,为什么需要两个函数而不是第一个函数直接向Kafka发送数据呢?我们先来看这张图:
  当我们使用异步调用函数时,请求的数据会在函数内部默认放入消息队列进行第一次削峰填谷,然后每个队列会通过对应的函数实例的弹性拉起多个实例函数实例。进行第二次削峰填谷。所以这也是这个架构能够稳定承载大并发请求的核心原因之一。
  4.配置卡夫卡
  在游戏运营场景中,数据量比较大,所以对Kafka的性能要求比较高。与开源自建相比,使用云上的Kafka节省了大量的运维操作,例如:
  • 我们不再需要维护Kafka 集群的各个节点。
  • 无需关心主从节点之间的数据同步。
  • 可快速动态扩展Kafka集群规格,动态增加topic,动态增加partition数量。
  • 完善的指标监控功能和消息查询功能。
  一般来说,所有的SLA都被云端覆盖了,我们只需要关注消息发送和消息消费即可。
  因此,我们可以打开Kafka激活界面,根据实际场景需要一键激活Kafka实例,激活Kafka后登录控制台,在基本信息中查看Kafka接入点:
  • 默认接入点:VPC 内网场景的接入点。
  • SSL 接入点:公网场景中的接入点。
  您可以将默认接入点配置到函数计算的第二个功能中。
  ....
producer = KafkaProducer(bootstrap_servers=&#39;XX.XX.XX.XX:9092,XX.XX.XX.XX:9092,XX.XX.XX.XX:9092&#39;)
....
  然后点击左侧控制台的Topic Management,创建一个Topic:
  将创建的 Topic 配置到函数计算的第二个函数中。
  ...
# 第一个参数为Topic名称
producer.send(&#39;ikf-demo&#39;, json.dumps(event_str).encode(&#39;utf-8&#39;))
...
  上面已经列出了云上 Kafka 的优势,比如动态增加一个主题的分区数,我们可以在主题列表中动态调整一个主题的分区数:
  单个主题最多支持360个分区,这是开源自建无法实现的。
  接下来,点击控制台左侧的Consumer Group Management,创建一个Consumer Group:
  至此,云上的Kafka就配置好了,即Producer可以向刚刚创建的topic发送消息,Consumer可以设置刚刚创建的GID订阅该Topic进行消息的接收和消费。
  Flink 卡夫卡消费者
  在这种场景下,Kafka 后面往往会跟着 Flink,所以这里简单介绍一下如何在 Flink 中创建 Kafka Consumer 和消费数据。代码片段如下:
  final ParameterTool parameterTool = ParameterTool.fromArgs(args);
String kafkaTopic = parameterTool.get("kafka-topic","ikf-demo");
String brokers = parameterTool.get("brokers", "XX.XX.XX.XX:9092,XX.XX.XX.XX:9092,XX.XX.XX.XX:9092");
Properties kafkaProps = new Properties();
kafkaProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, brokers);
kafkaProps.put(ConsumerConfig.GROUP_ID_CONFIG, "ikf-demo");
FlinkKafkaConsumer kafka = new FlinkKafkaConsumer(kafkaTopic, new UserBehaviorEventSchema(), kafkaProps);
kafka.setStartFromLatest();
kafka.setCommitOffsetsOnCheckpoints(false);
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource dataStreamByEventTime = env.addSource(kafka);
  以上是构建 Flink Kafka Consumer 并添加 Kafka Source 的代码片段,非常简单。
  压力测试验证
  至此,整个数据采集的架构已经搭建完成。接下来,我们将通过压力测试来测试整个架构的性能。这里使用阿里云PTS进行压力测试。
  创建压力测试场景
  打开PTS控制台,点击左侧菜单创建压力测试/创建PTS场景:
  在场景配置中,使用第一个函数计算函数暴露的HTTP接口作为串口,如下图所示:
  接口配置好之后,我们来配置压力:
  • 压力模式:
  • 并发模式:指定有多少并发用户同时发出请求。
  • RPS 模式:指定每秒有多少请求。
  • 增量模式:在压力测量过程中,可以手动调节压力,也可以按百分比自动增加压力。
  • 最大并发:有多少虚拟用户可以同时发起请求。
  • 增量百分比:如果是自动增量,则在此处按百分比增量。
  • 单级持续时间:当未完全达到全压时,每一级梯度的压力保持持续时间。
  • 压力测试总持续时间:压力测试的总持续时间。
  这里由于资源成本的原因,将并发用户数设置为2500进行验证。
  从上图压测的情况来看,TPS已经达到2w上限,549w+请求,99.99%的请求成功,369异常也可以点击查看,都是请求超时造成的的压力测试工具。
  总结
  至此,整个基于serverless的大数据采集传输架构搭建完成,并进行了压力测试,验证整体性能也不错,整个架构非常简单易懂。这种架构不仅适用于游戏运营行业,其实任何大数据采集传输场景都适用。目前,已经有很多客户在基于serverless架构的生产环境中运行,或者正在对serverless架构进行改造。在途中。
  解决方案:模拟手工采集美团网商家的数据采集产品详细介绍-美团商家
  模拟手动采集美团商户数据采集软件,可以采集指定城市,指定关键词商户信息,包括姓名、地址、电话、来源网址、等等
  美团商户数据采集产品详情
  一、软件功能
  1.基于美团网公开数据采集。
  2.内置数据库保存采集的数据,支持数十万条数据,支持库内去重,即采集到数据库的数据不会被删除重复。
  3. 多种采集算法采集更多数据。
  
  4.数据记忆功能商务手机采集器,意外关机或下次开机数据还在。
  5、一键导出为CSV、EXCEL、VCF等文件。
  6.可将VCF文件导入手机通讯录,方便快捷。
  7.实时采集,而不是查看自己的数据库。
  8.支持Win XP、Win7和Win10等操作系统
  
  2.使用帮助
  1.手动选择城市商务电话的电话号码软件采集器采集,可以选择多个。
  2.软件采集过程中,为了效率,软件界面只显示不超过3000条数据。软件内置数据库保存采集的数据,支持数十万条数据。
  3、关于杀毒软件的误报,部分杀毒软件会因为软件保护原因误报误报。如果它被阻止,请允许它。建议使用或金山毒霸。
  4.支持导出到VCF文件。VCF文件是标准的手机通讯录格式文件,可以导入到手机通讯录中。方法是通过qq将vcf文件传输到手机,点击打开vcf文件,选择用手机通讯录打开,按照提示导入即可。
  5. 搜索关键词最好按行业关键词。一次输入一个单词,不带标点符号。6. 选择城市和关键词后,点击“开始采集”按钮。美团商户数据采集-数据采集软件-顺鑫科技官网|百度地图数据采集器|高德地图数据采集器|抖音快手数据采集器 查看全部

  解决方案:Serverless在游戏运营行业进行数据采集分析的最佳实践
  • 触发器名称:defaultTrigger
  • 身份验证方法:匿名(即无需身份验证)
  • 请求方法:GET、POST
  创建函数后,我们通过在线编辑器编写代码:
  # -*- coding: utf-8 -*-
import logging
import json
import urllib.parse
HELLO_WORLD = b&#39;Hello world!\n&#39;
def handler(environ, start_response):
logger = logging.getLogger()
context = environ[&#39;fc.context&#39;]
request_uri = environ[&#39;fc.request_uri&#39;]
for k, v in environ.items():
if k.startswith(&#39;HTTP_&#39;):
# process custom request headers
pass
try:
request_body_size = int(environ.get(&#39;CONTENT_LENGTH&#39;, 0))
except (ValueError):
request_body_size = 0
# 接收回传的数据
request_body = environ[&#39;wsgi.input&#39;].read(request_body_size)
request_body_str = urllib.parse.unquote(request_body.decode("GBK"))
request_body_obj = json.loads(request_body_str)
logger.info(request_body_obj["action"])
logger.info(request_body_obj["articleAuthorId"])
status = &#39;200 OK&#39;
response_headers = [(&#39;Content-type&#39;, &#39;text/plain&#39;)]
start_response(status, response_headers)
return [HELLO_WORLD]
  这时候的代码很简单,就是要接收用户的参数,我们可以调用接口进行验证:
  您可以在函数的日志查询中看到此调用的日志:
  同时,我们还可以查看函数的link trace来分析每一步的调用时间,比如函数接收请求的过程→冷启动(没有活动实例时)→准备代码→执行初始化方法→执行入口函数逻辑:
  从调用链接图中可以看出,之前的请求收录了冷启动时间,因为当时没有活动实例,整个过程耗时418毫秒,入口函数代码的实际执行时间为8毫秒。
  再次调用该接口时,可以看到直接执行了入口函数的逻辑,因为此时已经有一个实例在运行,整个时间只有2.3毫秒:
  2. 处理数据的函数
  第一个函数是通过函数计算控制台在界面上创建的,运行环境选择Python3。我们可以在官方文档中查看预设的Python3运行环境中构建了哪些模块,因为第二个功能需要操作Kafka和RDS,所以需要确认对应的模块。
  从文档中可以看出,内置模块包括RDS的SDK模块,但没有Kafka的SDK模块。这时候我们需要手动安装Kafka SDK模块,创建功能也会使用另一种方式。
  Funcraft
  Funcraft是一款支持Serverless应用部署的命令行工具,可以帮助我们方便的管理函数计算、API网关、日志服务等资源。它通过资源配置文件(template.yml)帮助我们进行开发、构建和部署。
  所以第二个函数我们需要用Fun来操作,整个操作分为四步:
  • 安装有趣的工具。
  • 编写template.yml 模板文件来描述函数。
  • 安装我们需要的第 3 方依赖项。
  • 上传部署功能。
  安装乐趣
  Fun提供了三种安装方式:
  • 通过npm 包管理安装- 适用于所有平台(Windows/Mac/Linux)上预装npm 的开发人员。
  • 通过下载二进制文件安装- 适用于所有平台(Windows/Mac/Linux)。
  • 通过 Homebrew 包管理器安装——适用于 Mac 平台,更符合 MacOS 开发者习惯。
  文例环境是Mac,所以使用npm安装,很简单,一行命令搞定:
  sudo npm install @alicloud/fun -g
  安装完成后。在控制终端输入fun命令查看版本信息:
  $ fun --version
3.6.20
  第一次使用fun前,需要执行fun config命令进行配置,按照提示依次配置Account ID、Access Key Id、Secret Access Key、Default Region Name。Account ID 和 Access Key Id 可以在函数计算控制台首页右上角获取:
  有趣的配置
  ? 阿里云账号ID 01
  ? 阿里云Access Key ID qef6j
  ? 阿里云Access Key Secret ***UFJG
  ? 默认地域名称 cn-hangzhou
  ? 每个 SDK 客户端调用的超时时间(秒) 60
  ? 每个 SDK 客户端的最大重试次数 3
  编写模板.yml
  创建一个新目录,并在此目录中创建一个名为 template.yml 的 YAML 文件。该文件主要描述了要创建的函数的配置。说白了,函数计算控制台上配置的配置信息是用 YAML 格式写的。在文件中:
  ROSTemplateFormatVersion: &#39;2015-09-01&#39;
Transform: &#39;Aliyun::Serverless-2018-04-03&#39;
Resources:
FCBigDataDemo:
Type: &#39;Aliyun::Serverless::Service&#39;
Properties:
Description: &#39;local invoke demo&#39;
VpcConfig:
VpcId: &#39;vpc-xxxxxxxxxxx&#39;
VSwitchIds: [ &#39;vsw-xxxxxxxxxx&#39; ]
SecurityGroupId: &#39;sg-xxxxxxxxx&#39;
LogConfig:
Project: fcdemo
Logstore: fc_demo_store
dataToKafka:
Type: &#39;Aliyun::Serverless::Function&#39;
Properties:
Initializer: index.my_initializer
Handler: index.handler
CodeUri: &#39;./&#39;
Description: &#39;&#39;
Runtime: python3
  我们来解析一下上面文件的核心内容:
  • FCBigDataDemo:自定义服务名称。该服务由以下Type属性表示,即Aliyun::Serverless::Service。
  • 属性:属性下的属性都是服务的配置项。
  • VpcConfig:服务的VPC配置,包括:
  
  VpcId:VPC ID。VSwitchIds:交换机ID,这里是一个数组,可以配置多个交换机。SecurityGroupId:安全组 ID。
  • LogConfig:服务绑定日志服务 (SLS) 配置,包括:
  项目:日志服务项目。日志存储:日志存储名称。
  • dataToKafka:该服务下用户定义的函数名。该函数由以下Type属性表示,即Aliyun::Serverless::Function。
  • 属性:属性下的属性都是该功能的配置项。
  • Initializer:配置初始化函数。
  • Handler:配置入口函数。
  • 运行时:函数运行时环境。
  目录结构为:
  安装第三方依赖
  在创建了服务和功能的模板之后,让我们安装我们需要使用的第三方依赖项。在本例的场景中,第二个功能需要用到Kafka SDK,所以可以通过fun工具结合Python包管理工具pip来安装:
  有趣的安装 --runtime python3 --package-type pip kafka-python
  执行命令后,出现如下提示信息:
  此时我们会发现目录下会生成一个.fun文件夹,我们安装的依赖都在这个目录下:
  部署功能
  现在模板文件写好了,我们需要的Kafka SDK也安装好了,我们需要添加我们的代码文件index.py。代码内容如下:
  # -*- coding: utf-8 -*-
import logging
import json
import urllib.parse
from kafka import KafkaProducer
producer = None
def my_initializer(context):
logger = logging.getLogger()
logger.info("init kafka producer")
global producer
producer = KafkaProducer(bootstrap_servers=&#39;XX.XX.XX.XX:9092,XX.XX.XX.XX:9092,XX.XX.XX.XX:9092&#39;)
def handler(event, context):
logger = logging.getLogger()
# 接收回传的数据
event_str = json.loads(event)
event_obj = json.loads(event_str)
logger.info(event_obj["action"])
logger.info(event_obj["articleAuthorId"])
# 向Kafka发送消息
global producer
producer.send(&#39;ikf-demo&#39;, json.dumps(event_str).encode(&#39;utf-8&#39;))
producer.close()
return &#39;hello world&#39;
  代码很简单,这里简单分析一下:
  • my_initializer:当函数实例被拉起时,会先执行函数,然后再执行handler函数。当函数实例运行时,后续请求不会执行 my_initializer 函数。一般用于各种连接的初始化。初始化Kafka Producer的方法放在这里,避免重复初始化Producer。
  • handler:这个函数只有两个逻辑,接收返回的数据和将数据发送到Kafka的指定topic。
  让我们使用 fun deploy 命令来部署函数,它做了两件事:
  • 根据template.yml 中的配置创建服务和功能。
  • 将 index.py 和 .fun 上传到函数中。
  登录函数计算控制台,可以看到通过 fun 命令部署的服务和函数:
  进入函数,还可以清晰的看到第三方依赖包的目录结构:
  3.函数之间的调用
  目前,这两个功能都已创建。下面的工作就是在第一个函数接收到数据后,拉起第二个函数向Kafka发送消息。我们只需要对第一个函数进行一些更改:
  # -*- coding: utf-8 -*-
import logging
import json
import urllib.parse
import fc2
HELLO_WORLD = b&#39;Hello world!\n&#39;
client = None
def my_initializer(context):
logger = logging.getLogger()
logger.info("init fc client")
global client
client = fc2.Client(
endpoint="http://your_account_id.cn-hang ... ot%3B,
accessKeyID="your_ak",
accessKeySecret="your_sk"
)
def handler(environ, start_response):
logger = logging.getLogger()
context = environ[&#39;fc.context&#39;]
request_uri = environ[&#39;fc.request_uri&#39;]
for k, v in environ.items():
if k.startswith(&#39;HTTP_&#39;):
# process custom request headers
pass
try:
request_body_size = int(environ.get(&#39;CONTENT_LENGTH&#39;, 0))
except (ValueError):
request_body_size = 0
# 接收回传的数据
request_body = environ[&#39;wsgi.input&#39;].read(request_body_size)
request_body_str = urllib.parse.unquote(request_body.decode("GBK"))
request_body_obj = json.loads(request_body_str)
logger.info(request_body_obj["action"])
logger.info(request_body_obj["articleAuthorId"])
global client
client.invoke_function(
&#39;FCBigDataDemo&#39;,
&#39;dataToKafka&#39;,
payload=json.dumps(request_body_str),
headers = {&#39;x-fc-invocation-type&#39;: &#39;Async&#39;}
)
status = &#39;200 OK&#39;
response_headers = [(&#39;Content-type&#39;, &#39;text/plain&#39;)]
start_response(status, response_headers)
<p>
return [HELLO_WORLD]</p>
  如上代码所示,对第一个函数的代码做了三处改动:
  • 导入函数计算的库:import fc2
  • 添加创建函数计算客户端的初始化方法:
  def my_initializer(context):
logger = logging.getLogger()
logger.info("init fc client")
global client
client = fc2.Client(
endpoint="http://your_account_id.cn-hang ... ot%3B,
accessKeyID="your_ak",
accessKeySecret="your_sk"
)
  这里需要注意的是,我们在代码中添加初始化方法时,需要在函数配置中指定初始化方法的入口:
  • 通过函数计算客户端调用第二个函数:
  global client
client.invoke_function(
&#39;FCBigDataDemo&#39;,
&#39;dataToKafka&#39;,
payload=json.dumps(request_body_str),
headers = {&#39;x-fc-invocation-type&#39;: &#39;Async&#39;}
)
  invoke_function 函数有四个参数:
  • 第一个参数:调用函数的服务的名称。
  • 第二个参数:调用函数的函数名。
  • 第三个参数:传递给调用函数的数据。
  • 第四个参数:调用第二个函数Request Header 信息。这里x-fc-invocation-type的key用来设置是同步调用还是异步调用。这里 Async 设置为异步调用。
  通过这个设置,我们可以验证请求是通过第一个函数提供的HTTP接口发起的→采集数据→调用第二个函数→将数据作为消息传递给Kafka。
  使用两个函数的目的
  这里有同学可能会有疑问,为什么需要两个函数而不是第一个函数直接向Kafka发送数据呢?我们先来看这张图:
  当我们使用异步调用函数时,请求的数据会在函数内部默认放入消息队列进行第一次削峰填谷,然后每个队列会通过对应的函数实例的弹性拉起多个实例函数实例。进行第二次削峰填谷。所以这也是这个架构能够稳定承载大并发请求的核心原因之一。
  4.配置卡夫卡
  在游戏运营场景中,数据量比较大,所以对Kafka的性能要求比较高。与开源自建相比,使用云上的Kafka节省了大量的运维操作,例如:
  • 我们不再需要维护Kafka 集群的各个节点。
  • 无需关心主从节点之间的数据同步。
  • 可快速动态扩展Kafka集群规格,动态增加topic,动态增加partition数量。
  • 完善的指标监控功能和消息查询功能。
  一般来说,所有的SLA都被云端覆盖了,我们只需要关注消息发送和消息消费即可。
  因此,我们可以打开Kafka激活界面,根据实际场景需要一键激活Kafka实例,激活Kafka后登录控制台,在基本信息中查看Kafka接入点:
  • 默认接入点:VPC 内网场景的接入点。
  • SSL 接入点:公网场景中的接入点。
  您可以将默认接入点配置到函数计算的第二个功能中。
  ....
producer = KafkaProducer(bootstrap_servers=&#39;XX.XX.XX.XX:9092,XX.XX.XX.XX:9092,XX.XX.XX.XX:9092&#39;)
....
  然后点击左侧控制台的Topic Management,创建一个Topic:
  将创建的 Topic 配置到函数计算的第二个函数中。
  ...
# 第一个参数为Topic名称
producer.send(&#39;ikf-demo&#39;, json.dumps(event_str).encode(&#39;utf-8&#39;))
...
  上面已经列出了云上 Kafka 的优势,比如动态增加一个主题的分区数,我们可以在主题列表中动态调整一个主题的分区数:
  单个主题最多支持360个分区,这是开源自建无法实现的。
  接下来,点击控制台左侧的Consumer Group Management,创建一个Consumer Group:
  至此,云上的Kafka就配置好了,即Producer可以向刚刚创建的topic发送消息,Consumer可以设置刚刚创建的GID订阅该Topic进行消息的接收和消费。
  Flink 卡夫卡消费者
  在这种场景下,Kafka 后面往往会跟着 Flink,所以这里简单介绍一下如何在 Flink 中创建 Kafka Consumer 和消费数据。代码片段如下:
  final ParameterTool parameterTool = ParameterTool.fromArgs(args);
String kafkaTopic = parameterTool.get("kafka-topic","ikf-demo");
String brokers = parameterTool.get("brokers", "XX.XX.XX.XX:9092,XX.XX.XX.XX:9092,XX.XX.XX.XX:9092");
Properties kafkaProps = new Properties();
kafkaProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, brokers);
kafkaProps.put(ConsumerConfig.GROUP_ID_CONFIG, "ikf-demo");
FlinkKafkaConsumer kafka = new FlinkKafkaConsumer(kafkaTopic, new UserBehaviorEventSchema(), kafkaProps);
kafka.setStartFromLatest();
kafka.setCommitOffsetsOnCheckpoints(false);
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource dataStreamByEventTime = env.addSource(kafka);
  以上是构建 Flink Kafka Consumer 并添加 Kafka Source 的代码片段,非常简单。
  压力测试验证
  至此,整个数据采集的架构已经搭建完成。接下来,我们将通过压力测试来测试整个架构的性能。这里使用阿里云PTS进行压力测试。
  创建压力测试场景
  打开PTS控制台,点击左侧菜单创建压力测试/创建PTS场景:
  在场景配置中,使用第一个函数计算函数暴露的HTTP接口作为串口,如下图所示:
  接口配置好之后,我们来配置压力:
  • 压力模式:
  • 并发模式:指定有多少并发用户同时发出请求。
  • RPS 模式:指定每秒有多少请求。
  • 增量模式:在压力测量过程中,可以手动调节压力,也可以按百分比自动增加压力。
  • 最大并发:有多少虚拟用户可以同时发起请求。
  • 增量百分比:如果是自动增量,则在此处按百分比增量。
  • 单级持续时间:当未完全达到全压时,每一级梯度的压力保持持续时间。
  • 压力测试总持续时间:压力测试的总持续时间。
  这里由于资源成本的原因,将并发用户数设置为2500进行验证。
  从上图压测的情况来看,TPS已经达到2w上限,549w+请求,99.99%的请求成功,369异常也可以点击查看,都是请求超时造成的的压力测试工具。
  总结
  至此,整个基于serverless的大数据采集传输架构搭建完成,并进行了压力测试,验证整体性能也不错,整个架构非常简单易懂。这种架构不仅适用于游戏运营行业,其实任何大数据采集传输场景都适用。目前,已经有很多客户在基于serverless架构的生产环境中运行,或者正在对serverless架构进行改造。在途中。
  解决方案:模拟手工采集美团网商家的数据采集产品详细介绍-美团商家
  模拟手动采集美团商户数据采集软件,可以采集指定城市,指定关键词商户信息,包括姓名、地址、电话、来源网址、等等
  美团商户数据采集产品详情
  一、软件功能
  1.基于美团网公开数据采集。
  2.内置数据库保存采集的数据,支持数十万条数据,支持库内去重,即采集到数据库的数据不会被删除重复。
  3. 多种采集算法采集更多数据。
  
  4.数据记忆功能商务手机采集器,意外关机或下次开机数据还在。
  5、一键导出为CSV、EXCEL、VCF等文件。
  6.可将VCF文件导入手机通讯录,方便快捷。
  7.实时采集,而不是查看自己的数据库。
  8.支持Win XP、Win7和Win10等操作系统
  
  2.使用帮助
  1.手动选择城市商务电话的电话号码软件采集器采集,可以选择多个。
  2.软件采集过程中,为了效率,软件界面只显示不超过3000条数据。软件内置数据库保存采集的数据,支持数十万条数据。
  3、关于杀毒软件的误报,部分杀毒软件会因为软件保护原因误报误报。如果它被阻止,请允许它。建议使用或金山毒霸。
  4.支持导出到VCF文件。VCF文件是标准的手机通讯录格式文件,可以导入到手机通讯录中。方法是通过qq将vcf文件传输到手机,点击打开vcf文件,选择用手机通讯录打开,按照提示导入即可。
  5. 搜索关键词最好按行业关键词。一次输入一个单词,不带标点符号。6. 选择城市和关键词后,点击“开始采集”按钮。美团商户数据采集-数据采集软件-顺鑫科技官网|百度地图数据采集器|高德地图数据采集器|抖音快手数据采集器

分享的内容:采集文章图片,上传到本地或者七牛云

采集交流优采云 发表了文章 • 0 个评论 • 85 次浏览 • 2022-11-06 09:21 • 来自相关话题

  分享的内容:采集文章图片,上传到本地或者七牛云
  &gt; &gt; 采集文章图片,上传到本地或七牛云
  采集文章图片,上传到本地或七牛云
  开发技术开发技术2022-10-23 浏览量
  最近写了一个新需求,需求是文章 from 采集,图片换成自己的url,可以选择保存在本地或者七牛云
  七牛云原来的解决方案是下载到本地,但是如果不能获取,可以停止,使用七牛云的异步第三方资源抓取解决方案。
  请参考具体代码
<p> 查看全部

  分享的内容:采集文章图片,上传到本地或者七牛云
  &gt; &gt; 采集文章图片,上传到本地或七牛云
  采集文章图片,上传到本地或七牛云
  开发技术开发技术2022-10-23 浏览量
  最近写了一个新需求,需求是文章 from 采集,图片换成自己的url,可以选择保存在本地或者七牛云
  七牛云原来的解决方案是下载到本地,但是如果不能获取,可以停止,使用七牛云的异步第三方资源抓取解决方案。
  请参考具体代码
<p>

背后的故事:快收藏,一小时教你装逼采集网易云音乐5亿首歌

采集交流优采云 发表了文章 • 0 个评论 • 230 次浏览 • 2022-11-04 18:28 • 来自相关话题

  背后的故事:快收藏,一小时教你装逼采集网易云音乐5亿首歌
  本期为极客系列的第三期。第二期由于客户论文重复的问题,暂时不开放源码。第二期比第三期有点长,最近有很多事情发生。本期使用的语言是java,创建多线程,支持断点采集,URL去重,广度优先+深度组合,如何使用已经搭建好的轮子快速开发发力。好了,吹完了,现在我们进入教程阶段。
  爬虫
  本期目标: 本期工具:采集结果:
  采集结果写入excel
  WebCollector 简介
  WebCollector是一个无需配置,方便二次开发的JAVA爬虫框架。它提供了精简的API,只需少量代码即可实现强大的爬虫。WebCollector-Hadoop 是支持分布式爬取的 WebCollector 的 Hadoop 版本。并且在2.x版本中提供了selenium,可以处理javascript生成的数据。我们先来看WebCollector的核心架构图:
  爬虫架构图
  
  不过,我们不用那么麻烦使用WebCollector来写爬虫。我们只需要在爬虫框架中集成BreadthCrawler类,重写访问方法即可。我们来看看官网上的例子:
  官网示例
  节目说明:
  访问()方法
  在整个爬取过程中,只要抓到一个复合页面,wc就会回调这个方法,传入一个收录所有页面信息的页面对象。
  添加种子()
  添加种子,在爬虫启动前,种子链接会添加到上述爬取信息中,并标记为未爬取。这个过程称为注入。
  添加正则表达式
  对于url正则表达式,过滤掉.js .jpg .css等不必要的链接,或者指定抓取链接的规则。比如我在使用的时候,有一个正则模式:[0-9]+.html,那么我的爬虫只会爬取域名下2015-01-16日期以.html结尾的链接。
  
  开始()
  表示启动爬虫,传入参数5表示抓取5层(深度为5)。如何理解5的深度?当只添加一个种子时,抓取这个种子链接作为第一层,根据规则解析种子链接页面,过滤出想要的链接,保存到待爬取的记录中。然后第二层就是抓取第一层保存的记录,解析并保存新的记录,以此类推。
  Web云音乐页面分析:
  我们先看下网易云音乐的歌曲页面链接:#/album?id=2884361,观察这个url,发现是查询平台。通过查询id可以得到不同的歌曲,这样就可以遍历整个网易云音乐,通过提取与上面url类似的网页就可以得到网易云音乐的所有歌曲。
  这时,我们遇到了第二个问题。得到歌曲的页面后,如何才能得到音乐的真实地址呢?我们通过抓包分析发现网易云音乐有一个api接口,可以得到歌曲的真实地址,api地址:,这个接口有几个参数:
  然后访问api得到一段json,里面收录了歌曲几个版本的音源地址。至于如何捕获和分析地址,下一篇教程将为您提供。
  不多说,在代码上,所有的核心代码都进行了注释,整个爬虫思路是这样的:
  网络爬虫源代码
  附上 Github 地址:. 欢迎关注极客科学,学习遵循有趣的技巧。
  分享的内容:外链平台有哪些,外链发展情况介绍
  众所周知,网站的外链是网站的SEO优化的重要组成部分。当然,分析竞争对手的外部链接也很重要。所谓“知己知彼”,就是千方百计的战斗,只要你知道对手的外链是怎么做的。,那么你就可以在外链上超越竞争对手。当然,在这种情况下,网站的综合排名也可以随意超越竞争对手。那么如何使用SEO工具准确查询竞争对手的反向链接呢?
  1. 站长工具
  站长工具是每个人都经常使用的软件。输入自己的网址,会有网站权重、页面收录、网站外链等数字。点击外链数量会跳转到百度网盘页面,可以看到自己的网站外链。
  优点:查询速度快
  缺点:查询质量差,假外链多。仅查询文本链接
  
  2.百度站长平台
  百度站长平台在过去两年一直是百度的主要站长工具。百度站长平台优化维护页面有外链分析。点击外链分析可以看到你的网站的外链主域和总链接数。
  优点:可靠
  缺点:时效性差,数据往往是一个月前的(这个主要看百度站长平台的数据更新时间)
  3. Majesticseo 外链查询工具
  一个国外的SEO查询工具网站,直接看图:
  
  图1
  图1准确显示了SEO的外部链接是否知道网站,并给出了对应的参考域名、参考IP等。
  图二
  图 2 反向链接的分割 区分网站的图片链接或文本链接,图表清晰地展示了链接到该域/子域/URL的不同类型的反向链接;在锚文本部分,您可以清楚地看到 网站 占主要外部链接中锚文本的分配量。在这里,您可以深入分析每个 关键词 以找出使用此 关键词 反向链接的引用域和外部链接。
  一般情况下,使用百度站长平台和majesticseo查询可以充分分析竞争对手的外链,然后我们可以通过观察竞争对手发布的外链数量来预测我们需要发布的外链数量。,让我们的SEO工作更有针对性,可以通过观察竞争对手的外链来寻找一些优质的外链资源。
  做SEO是关于毅力的。网站 的外部链接对于网站 来说是一个非常重要的因素。因此,作为站长,我们必须积累优质有效的外链。几乎每个优秀的站长手头都会有大量的资源。这些资源就是站长财富和排名的秘密。所以,大部分站长都不会随便透露。因此,外链资源的积累任重而道远! 查看全部

  背后的故事:快收藏,一小时教你装逼采集网易云音乐5亿首歌
  本期为极客系列的第三期。第二期由于客户论文重复的问题,暂时不开放源码。第二期比第三期有点长,最近有很多事情发生。本期使用的语言是java,创建多线程,支持断点采集,URL去重,广度优先+深度组合,如何使用已经搭建好的轮子快速开发发力。好了,吹完了,现在我们进入教程阶段。
  爬虫
  本期目标: 本期工具:采集结果:
  采集结果写入excel
  WebCollector 简介
  WebCollector是一个无需配置,方便二次开发的JAVA爬虫框架。它提供了精简的API,只需少量代码即可实现强大的爬虫。WebCollector-Hadoop 是支持分布式爬取的 WebCollector 的 Hadoop 版本。并且在2.x版本中提供了selenium,可以处理javascript生成的数据。我们先来看WebCollector的核心架构图:
  爬虫架构图
  
  不过,我们不用那么麻烦使用WebCollector来写爬虫。我们只需要在爬虫框架中集成BreadthCrawler类,重写访问方法即可。我们来看看官网上的例子:
  官网示例
  节目说明:
  访问()方法
  在整个爬取过程中,只要抓到一个复合页面,wc就会回调这个方法,传入一个收录所有页面信息的页面对象。
  添加种子()
  添加种子,在爬虫启动前,种子链接会添加到上述爬取信息中,并标记为未爬取。这个过程称为注入。
  添加正则表达式
  对于url正则表达式,过滤掉.js .jpg .css等不必要的链接,或者指定抓取链接的规则。比如我在使用的时候,有一个正则模式:[0-9]+.html,那么我的爬虫只会爬取域名下2015-01-16日期以.html结尾的链接。
  
  开始()
  表示启动爬虫,传入参数5表示抓取5层(深度为5)。如何理解5的深度?当只添加一个种子时,抓取这个种子链接作为第一层,根据规则解析种子链接页面,过滤出想要的链接,保存到待爬取的记录中。然后第二层就是抓取第一层保存的记录,解析并保存新的记录,以此类推。
  Web云音乐页面分析:
  我们先看下网易云音乐的歌曲页面链接:#/album?id=2884361,观察这个url,发现是查询平台。通过查询id可以得到不同的歌曲,这样就可以遍历整个网易云音乐,通过提取与上面url类似的网页就可以得到网易云音乐的所有歌曲。
  这时,我们遇到了第二个问题。得到歌曲的页面后,如何才能得到音乐的真实地址呢?我们通过抓包分析发现网易云音乐有一个api接口,可以得到歌曲的真实地址,api地址:,这个接口有几个参数:
  然后访问api得到一段json,里面收录了歌曲几个版本的音源地址。至于如何捕获和分析地址,下一篇教程将为您提供。
  不多说,在代码上,所有的核心代码都进行了注释,整个爬虫思路是这样的:
  网络爬虫源代码
  附上 Github 地址:. 欢迎关注极客科学,学习遵循有趣的技巧。
  分享的内容:外链平台有哪些,外链发展情况介绍
  众所周知,网站的外链是网站的SEO优化的重要组成部分。当然,分析竞争对手的外部链接也很重要。所谓“知己知彼”,就是千方百计的战斗,只要你知道对手的外链是怎么做的。,那么你就可以在外链上超越竞争对手。当然,在这种情况下,网站的综合排名也可以随意超越竞争对手。那么如何使用SEO工具准确查询竞争对手的反向链接呢?
  1. 站长工具
  站长工具是每个人都经常使用的软件。输入自己的网址,会有网站权重、页面收录、网站外链等数字。点击外链数量会跳转到百度网盘页面,可以看到自己的网站外链。
  优点:查询速度快
  缺点:查询质量差,假外链多。仅查询文本链接
  
  2.百度站长平台
  百度站长平台在过去两年一直是百度的主要站长工具。百度站长平台优化维护页面有外链分析。点击外链分析可以看到你的网站的外链主域和总链接数。
  优点:可靠
  缺点:时效性差,数据往往是一个月前的(这个主要看百度站长平台的数据更新时间)
  3. Majesticseo 外链查询工具
  一个国外的SEO查询工具网站,直接看图:
  
  图1
  图1准确显示了SEO的外部链接是否知道网站,并给出了对应的参考域名、参考IP等。
  图二
  图 2 反向链接的分割 区分网站的图片链接或文本链接,图表清晰地展示了链接到该域/子域/URL的不同类型的反向链接;在锚文本部分,您可以清楚地看到 网站 占主要外部链接中锚文本的分配量。在这里,您可以深入分析每个 关键词 以找出使用此 关键词 反向链接的引用域和外部链接。
  一般情况下,使用百度站长平台和majesticseo查询可以充分分析竞争对手的外链,然后我们可以通过观察竞争对手发布的外链数量来预测我们需要发布的外链数量。,让我们的SEO工作更有针对性,可以通过观察竞争对手的外链来寻找一些优质的外链资源。
  做SEO是关于毅力的。网站 的外部链接对于网站 来说是一个非常重要的因素。因此,作为站长,我们必须积累优质有效的外链。几乎每个优秀的站长手头都会有大量的资源。这些资源就是站长财富和排名的秘密。所以,大部分站长都不会随便透露。因此,外链资源的积累任重而道远!

总结:埋点,数据产品经理必备的技能

采集交流优采云 发表了文章 • 0 个评论 • 65 次浏览 • 2022-11-04 18:28 • 来自相关话题

  总结:埋点,数据产品经理必备的技能
  数据是数据产品的基础,埋点是数据的起点;如果没有埋点,数据产品就是被动水。
  可以说,埋没是互联网行业遇到的一个关键且无法回避的问题。
  以下是企业不同岗位学员的内部操作系统:
  商科同学不知道埋什么,也不知道埋什么;所以他们经常做功能但不做掩埋。需要数据分析的时候,他们去找数据组要数据,数据组会反问:“你埋了吗?”
  对于数据产品来说,由于对业务没有深入的了解,经常会出现遗漏、误葬的情况,最终导致无数理想的结果。
  业务开发,本质上就是解决业务相关的问题,而数据开发对他们来说是额外的工作,所以他们的开发成本会随着埋点需求的增加而增加,也可能伴随着项目延期的风险;隐藏的开发需求也可能导致代码冗余。
  对于数据分析,他们更多地使用数据,找不到数据埋藏的规律,从而无法通过数据驱动很好地进行分析。
  1、data采集的过程是什么?数据从何而来
  外部数据交互:如API数据的传输、数据文件的传输等。目前某平台的大数据标注系统就是通过这种方式传输完成企业的人群标注。
  从整个数据链路来看,数据产品基本上可以分为以下几个流程:
  首先数据采集我们需要从不同的终端获取不同的数据采集,然后进行数据清洗和处理(ETL),然后聚合到数据仓库中进行用户分析,用户画像、精准营销等;
  在我们知道了data采集和data embedding的重要性之后,在提出实际的业务功能需求的时候,一定要提到相关的embedding需求,那么接下来我们就需要关注如何让data采集是什么样的了过程?
  业务方确认功能并发起跟踪需求:提交页面、触发控件、触发场景等;专门的跟踪团队将进行系统验证以确保命名约定和一致性,BI将审查跟踪应用程序和统计要求是否合理或缺失等;审查后,嵌入点采集框架的设计开发与实现,嵌入点的开发,嵌入点完成后的测试;测试预写可以覆盖所有场景的业务场景,测试通过更新需求状态;业务验证、数据开发和数据分析;
  以上环节缺一不可,归根结底只有标准化的流程才能找到正确的现状问题。
  
  二、如何选择埋点方案?
  目前,互联网行业主流的埋地解决方案主要分为四种:
  1、第一类:代码嵌入,分为前端嵌入和后端嵌入;前端嵌入是通过前端代码嵌入来监控用户触发页面的数据采集
  前端嵌入点优势很明显,但劣势也很明显。因为前端嵌入点的数据是通过延迟上报机制上报的,比如用户点击页面上的按钮,不会立即上报,而是累计到一定值后才会累计。批量工作受到当前网络条件的限制。如果出现网络拥塞等问题,数据包就会丢失。所以前端埋点的丢包率比较高,一般在5%~10%。
  而如果前端埋点缺失或埋错,则必须通过app发布进行优化,客户端发布需要较长时间。
  2.第二种:服务器端埋点:在API接口中植入埋点代码段
  好处是每次用户触发这个请求,都会触发嵌入代码进行数据统计,所以不需要发布版本,及时触发及时更新。
  缺点是服务端埋点需要依赖服务请求,无法覆盖所有前端交互,对于用户路径采集来说比较弱。
  3、第三种:全埋;这是在互联网上增加用户资本的公司提出的一个埋葬想法。通过地埋SDK的接入,实现了页面上所有采集页面元素的浏览和点击行为。统一采集,不​​是按时间和需求采集,而是全部提前采集
  优点是开发成本高,SDK接入后维护成本低,埋藏过程也很简单;采集 先定义再定义,在一定程度上可以避免错位错位。
  缺点是数据冗余,使得很多数据无用,而数据采集的范围只是页面的可见元素,比如曝光,无法采集访问;数据的准确性也存在问题。
  4、第四类:可视化埋点;也是连接埋点SDK,但不是随时随地采集,而是按需采集,通过视觉圈选触发埋点采集
  优点是操作简单,按需埋点不会采集无效数据,开发成本比较低;并且数据埋点可以支持undo操作,一般来说数据量会比全埋点小很多。
  缺点:历史数据无法恢复,因为我们圈选动作之前的数据不能是采集;统计范围只支持页面最前面的动作,比如曝光,不能是采集采集。
  3、了解了各种埋地方案后,在实际工作中如何选择埋地方案?
  
  选择埋点方案的参考主要基于三点:
  业务发展阶段:开发投入成本、业务迭代速度业务属性:交互应用、业务交易分析深度:用户行为分析、业务分析、业务应用
  例如,我们可以根据业务发展的阶段来决定。比如现在业务发展迅速,版本迭代速度快,开发投入成本高。那么就不适合我们做client-side和server-side embedding,因为可能不是这样。版本更新需要多长时间,所以full embedding和visual embedding比较合适;
  对于比较强的业务数据分析场景,需要增加前端客户端嵌入点;并且需要考虑分析的深度。如果只是想看用户的前端行为路径,那么全嵌入点和视觉嵌入点都可以满足需求。,但如果分析整个业务流程,则必须配合代码埋点。
  我推荐全埋点+代码埋点的组合,服务端怎么做,服务端优先,这样数据准确率会更高。
  4、确定埋点选择后,开始详细设计埋点。
  事件是跟踪点中最重要的元素。如果要明确定位跟踪点,就必须从六个维度进行定义。我们可以将其概括为谁、何时、何地、什么、为什么和如何;这些元素用于构建事件的基本元素。
  事件主要分为三种类型:
  互动事件:浏览、点击、采集、支付、曝光、关闭;系统事件:APP启动、APP崩溃;业务状态:支付成功、用户续费等(这很大程度上取决于服务器的返回)。
  通过以上,我们基本可以判断出我们需要记录用户什么行为,什么数据采集,后续分析什么。
  写在最后,在我的工作生活中,过去的坑告诉我一个好的跟踪管理平台是多么重要。
  首先,流程是在线的。我们经常会迷失在一封来自埋点的电子邮件中,但如果是在线申请,申请、处理、访问、验证和测试都非常方便快捷,避免了信息交流。失踪;
  其次,可以标准化管理,埋点统一管理,信息集中管理,便于后期分析使用;
  最重要的是实现实时监控,减少泄漏和误埋。
  当然,如果您没有跟踪管理平台,确定一个标准化的跟踪流程,选择适合您当前业务的跟踪解决方案,相信您也可以做好跟踪,通过数据完成丰富的场景分析!
  作者:晚安;聚焦用户、产品等运营领域。
  本文由@Goodnight 发布。原创 每个人都是产品经理。未经许可禁止复制
  题图来自Unsplash,基于CC0协议
  解决方案:全自动易企CMS采集,一站式采集发布(图文详解)
  易企cms采集,当网站发布时,面临的最大问题是网站内容不足或更新不及时。网站越大,维护能力就越大,网站运营商长期以来一直在寻求以最大的成本降低实现最高质量的网站内容。依托高效强大的网络信息采集与整合,E-企业cms采集与网站对接后,持续为网站提供优质、实时的数据,节省人工投入和更大的人力,随时随地寻找文章资源。
  如果网站位于专用网络范围内,则网站
  将陷入网络扩展和内容补充,只能依靠人工采集互联网上的相关信息,然后复制到内网导入位于专网的网站。有了电商cms采集,现在就不用那么繁琐了,它可以自动采集发布编辑,让网站管理者可以专注于内容质量审查,网站整体SEO。
  
  E-Enterprisecms采集预设30多个插件来提高网站排名,通过这些插件对发布的内容进行排名和优化,从而在很长一段时间内提高网站的排名。您可以根据网站所在的行业,从发布到网站的每条内容中自动提取“长尾词”,并自动调整已发布内容的关键词密度。自动创建已发布图片的alt属性,并根据发布的内容自动生成内容中图片的匹配alt描述。
  电子商务cms采集具有4种高效的网络信息采集功能。在专题采集中,只需输入关键字即可采集符合网站专题设置要求的网络信息,不再需要手动搜索。定向采集可以与其他类似网站同步,只需输入目标网站的地址,即可自动采集同网站的信息进行过滤。
  
  易企cms采集再通过定向采集,这样就无需在新闻源平台上手动采集有关行业的文章,通过定向采集功能,只需目标网站的地址和关键词即可。采集配置中,网站可以设置要采集的信息源深度,以确保数据内容采集准确、完整,并满足您的网站要求。
  易企业cms采集通过5层网络信息过滤,使网站不会产生垃圾内容链接。数据过滤由指向目标网站原创信息源的链接的通道和链接类型执行。此外,通过对采集数据源的标题进行关键字区分和标题重复检查来执行标题筛选。内容筛选,通过将 HASH 算法应用于采集数据内容,以确保采集内容不重复。
  结合字段筛选
  ,可以对采集内容的字段值进行筛选和比较,以确保每个字段内容采集满足要求。组合过滤:对采集内容的多个字段值进行组合过滤和比较,确保多个字段组合后的内容符合要求。 查看全部

  总结:埋点,数据产品经理必备的技能
  数据是数据产品的基础,埋点是数据的起点;如果没有埋点,数据产品就是被动水。
  可以说,埋没是互联网行业遇到的一个关键且无法回避的问题。
  以下是企业不同岗位学员的内部操作系统:
  商科同学不知道埋什么,也不知道埋什么;所以他们经常做功能但不做掩埋。需要数据分析的时候,他们去找数据组要数据,数据组会反问:“你埋了吗?”
  对于数据产品来说,由于对业务没有深入的了解,经常会出现遗漏、误葬的情况,最终导致无数理想的结果。
  业务开发,本质上就是解决业务相关的问题,而数据开发对他们来说是额外的工作,所以他们的开发成本会随着埋点需求的增加而增加,也可能伴随着项目延期的风险;隐藏的开发需求也可能导致代码冗余。
  对于数据分析,他们更多地使用数据,找不到数据埋藏的规律,从而无法通过数据驱动很好地进行分析。
  1、data采集的过程是什么?数据从何而来
  外部数据交互:如API数据的传输、数据文件的传输等。目前某平台的大数据标注系统就是通过这种方式传输完成企业的人群标注。
  从整个数据链路来看,数据产品基本上可以分为以下几个流程:
  首先数据采集我们需要从不同的终端获取不同的数据采集,然后进行数据清洗和处理(ETL),然后聚合到数据仓库中进行用户分析,用户画像、精准营销等;
  在我们知道了data采集和data embedding的重要性之后,在提出实际的业务功能需求的时候,一定要提到相关的embedding需求,那么接下来我们就需要关注如何让data采集是什么样的了过程?
  业务方确认功能并发起跟踪需求:提交页面、触发控件、触发场景等;专门的跟踪团队将进行系统验证以确保命名约定和一致性,BI将审查跟踪应用程序和统计要求是否合理或缺失等;审查后,嵌入点采集框架的设计开发与实现,嵌入点的开发,嵌入点完成后的测试;测试预写可以覆盖所有场景的业务场景,测试通过更新需求状态;业务验证、数据开发和数据分析;
  以上环节缺一不可,归根结底只有标准化的流程才能找到正确的现状问题。
  
  二、如何选择埋点方案?
  目前,互联网行业主流的埋地解决方案主要分为四种:
  1、第一类:代码嵌入,分为前端嵌入和后端嵌入;前端嵌入是通过前端代码嵌入来监控用户触发页面的数据采集
  前端嵌入点优势很明显,但劣势也很明显。因为前端嵌入点的数据是通过延迟上报机制上报的,比如用户点击页面上的按钮,不会立即上报,而是累计到一定值后才会累计。批量工作受到当前网络条件的限制。如果出现网络拥塞等问题,数据包就会丢失。所以前端埋点的丢包率比较高,一般在5%~10%。
  而如果前端埋点缺失或埋错,则必须通过app发布进行优化,客户端发布需要较长时间。
  2.第二种:服务器端埋点:在API接口中植入埋点代码段
  好处是每次用户触发这个请求,都会触发嵌入代码进行数据统计,所以不需要发布版本,及时触发及时更新。
  缺点是服务端埋点需要依赖服务请求,无法覆盖所有前端交互,对于用户路径采集来说比较弱。
  3、第三种:全埋;这是在互联网上增加用户资本的公司提出的一个埋葬想法。通过地埋SDK的接入,实现了页面上所有采集页面元素的浏览和点击行为。统一采集,不​​是按时间和需求采集,而是全部提前采集
  优点是开发成本高,SDK接入后维护成本低,埋藏过程也很简单;采集 先定义再定义,在一定程度上可以避免错位错位。
  缺点是数据冗余,使得很多数据无用,而数据采集的范围只是页面的可见元素,比如曝光,无法采集访问;数据的准确性也存在问题。
  4、第四类:可视化埋点;也是连接埋点SDK,但不是随时随地采集,而是按需采集,通过视觉圈选触发埋点采集
  优点是操作简单,按需埋点不会采集无效数据,开发成本比较低;并且数据埋点可以支持undo操作,一般来说数据量会比全埋点小很多。
  缺点:历史数据无法恢复,因为我们圈选动作之前的数据不能是采集;统计范围只支持页面最前面的动作,比如曝光,不能是采集采集。
  3、了解了各种埋地方案后,在实际工作中如何选择埋地方案?
  
  选择埋点方案的参考主要基于三点:
  业务发展阶段:开发投入成本、业务迭代速度业务属性:交互应用、业务交易分析深度:用户行为分析、业务分析、业务应用
  例如,我们可以根据业务发展的阶段来决定。比如现在业务发展迅速,版本迭代速度快,开发投入成本高。那么就不适合我们做client-side和server-side embedding,因为可能不是这样。版本更新需要多长时间,所以full embedding和visual embedding比较合适;
  对于比较强的业务数据分析场景,需要增加前端客户端嵌入点;并且需要考虑分析的深度。如果只是想看用户的前端行为路径,那么全嵌入点和视觉嵌入点都可以满足需求。,但如果分析整个业务流程,则必须配合代码埋点。
  我推荐全埋点+代码埋点的组合,服务端怎么做,服务端优先,这样数据准确率会更高。
  4、确定埋点选择后,开始详细设计埋点。
  事件是跟踪点中最重要的元素。如果要明确定位跟踪点,就必须从六个维度进行定义。我们可以将其概括为谁、何时、何地、什么、为什么和如何;这些元素用于构建事件的基本元素。
  事件主要分为三种类型:
  互动事件:浏览、点击、采集、支付、曝光、关闭;系统事件:APP启动、APP崩溃;业务状态:支付成功、用户续费等(这很大程度上取决于服务器的返回)。
  通过以上,我们基本可以判断出我们需要记录用户什么行为,什么数据采集,后续分析什么。
  写在最后,在我的工作生活中,过去的坑告诉我一个好的跟踪管理平台是多么重要。
  首先,流程是在线的。我们经常会迷失在一封来自埋点的电子邮件中,但如果是在线申请,申请、处理、访问、验证和测试都非常方便快捷,避免了信息交流。失踪;
  其次,可以标准化管理,埋点统一管理,信息集中管理,便于后期分析使用;
  最重要的是实现实时监控,减少泄漏和误埋。
  当然,如果您没有跟踪管理平台,确定一个标准化的跟踪流程,选择适合您当前业务的跟踪解决方案,相信您也可以做好跟踪,通过数据完成丰富的场景分析!
  作者:晚安;聚焦用户、产品等运营领域。
  本文由@Goodnight 发布。原创 每个人都是产品经理。未经许可禁止复制
  题图来自Unsplash,基于CC0协议
  解决方案:全自动易企CMS采集,一站式采集发布(图文详解)
  易企cms采集,当网站发布时,面临的最大问题是网站内容不足或更新不及时。网站越大,维护能力就越大,网站运营商长期以来一直在寻求以最大的成本降低实现最高质量的网站内容。依托高效强大的网络信息采集与整合,E-企业cms采集与网站对接后,持续为网站提供优质、实时的数据,节省人工投入和更大的人力,随时随地寻找文章资源。
  如果网站位于专用网络范围内,则网站
  将陷入网络扩展和内容补充,只能依靠人工采集互联网上的相关信息,然后复制到内网导入位于专网的网站。有了电商cms采集,现在就不用那么繁琐了,它可以自动采集发布编辑,让网站管理者可以专注于内容质量审查,网站整体SEO。
  
  E-Enterprisecms采集预设30多个插件来提高网站排名,通过这些插件对发布的内容进行排名和优化,从而在很长一段时间内提高网站的排名。您可以根据网站所在的行业,从发布到网站的每条内容中自动提取“长尾词”,并自动调整已发布内容的关键词密度。自动创建已发布图片的alt属性,并根据发布的内容自动生成内容中图片的匹配alt描述。
  电子商务cms采集具有4种高效的网络信息采集功能。在专题采集中,只需输入关键字即可采集符合网站专题设置要求的网络信息,不再需要手动搜索。定向采集可以与其他类似网站同步,只需输入目标网站的地址,即可自动采集同网站的信息进行过滤。
  
  易企cms采集再通过定向采集,这样就无需在新闻源平台上手动采集有关行业的文章,通过定向采集功能,只需目标网站的地址和关键词即可。采集配置中,网站可以设置要采集的信息源深度,以确保数据内容采集准确、完整,并满足您的网站要求。
  易企业cms采集通过5层网络信息过滤,使网站不会产生垃圾内容链接。数据过滤由指向目标网站原创信息源的链接的通道和链接类型执行。此外,通过对采集数据源的标题进行关键字区分和标题重复检查来执行标题筛选。内容筛选,通过将 HASH 算法应用于采集数据内容,以确保采集内容不重复。
  结合字段筛选
  ,可以对采集内容的字段值进行筛选和比较,以确保每个字段内容采集满足要求。组合过滤:对采集内容的多个字段值进行组合过滤和比较,确保多个字段组合后的内容符合要求。

通用解决方案:API(接口)是什么

采集交流优采云 发表了文章 • 0 个评论 • 265 次浏览 • 2022-11-03 11:37 • 来自相关话题

  通用解决方案:API(接口)是什么
  什么是 API(接口)?举个常见的例子,在京东下单并付款后,商户选择顺丰快递发货,然后就可以在京东上实时查看当前物流信息。京东和顺丰作为两家独立的公司,可以在京东上实时看到顺丰的快递信息。这需要 API。在查看自己的快递信息时,京东可以使用顺丰提供的API接口进行实时检索。信息单独呈现网站。此外,您还可以在快递100上输入订单号查询快递信息。只要有合作或许可,其他公司可以通过顺丰提供的API接口检索快递信息。由于有多个调用,
  我们来看看百度是如何给出API的定义的:
  API(应用程序编程接口)是预定义的函数,旨在为应用程序和开发人员提供访问基于软件或硬件的一组例程的能力,而无需访问源代码或了解该机制的内部工作细节。
  从百度的定义来看,我们首先关注:功能,提供应用和开发者,无需访问源代码,例程。注意这四个短语。其中,例程是系统对外提供的功能接口或服务的集合。本文重点介绍API的数据服务功能接口。
  首先,在下面的文章中,我将首先演示如何使用浏览器,无需编程,无需访问源代码,调用免费的API接口,让您使用最简单的接口;
  然后,将演示如何通过编程调用接口;
  最后,演示启动WEB服务,编写一个简单的API接口来体现API的功能(y=f(x))。
  您也可以尝试复制代码。通过自己的实验,你会学到一些关于后端、前端的知识,加深你对 API 的理解。那么开始吧,我们先来一张图:通过API提供信息(数据)的功能,看看数据是如何流动的。如果您为 API 指定特定位置,它将位于下图的中心。
  为了改变理解,我穿插了一个故事人物。假设世界太大了,你想在非洲大陆看到它,成为一名水手,在一次航行中被一位著名的航海家带走(你有船上唯一的卫星计算机),你会不可避免地成为途中的领航员。它将让您确定下一个城市的纬度和经度。这时候导航器让你确定深圳的经纬度。
  1.你是个人肉API
  这时候,你可以想到一个简单的方法就是去百度搜索。除了领航员,船上的高级水手和大副很可能会问你。这时候你其实就是一个接口,大家来找你获取地理位置信息。作为一个接口,你自己不产生信息,你只是信息的采集器和传递者,提供人肉数据服务。
  2.使用免费的经纬API接口
  在百度搜索过程中,很多网友给出的经纬度不一致,要反复对比才能辨别真伪。时间长了,你可能会觉得大家都在问位置,太烦人了。我的人肉API效率太慢了。有没有更快的方法。
  这时候,你发现了一个阿里云的免费API接口:深圳。您在浏览器的地址栏中输入此 URL,即可获得正确的纬度和经度。你把网址里的深圳换成别的城市,就可以找到了。这时候,通过这个界面,就可以大大提高为大家确定位置的效率。
  3.您对此不满意
  你觉得这个接口很好,你就是懂Python,为什么不写点代码,注意这个时候你的角色变了:你已经从人类API变成了开发者(注意这是百度里的API定义关键词),你现在的目标是编写可以自动获取这个地方的经纬度的代码。
  #python
import requests
r = requests.get("http://gc.ditu.aliyun.com/geocoding?a=深圳")
loc = r.json()
print loc
#打印出的结果:{u&#39;alevel&#39;: 4, u&#39;lon&#39;: 114.05786, u&#39;level&#39;: 2, u&#39;cityName&#39;: u&#39;&#39;, u&#39;address&#39;: u&#39;&#39;, u&#39;lat&#39;: 22.54309}
# 与在浏览器输入地址的结果一致
print "深圳的经度是%s,纬度是%s" % (loc["lon"], loc["lat"])
#打印出的结果是:深圳的经度是114.05786,纬度是22.54309
  至此,我们来回顾一下百度对API的定义。目前,作为开发者,您只需编写几行代码即可访问“阿里巴巴云经纬度接口”。您无需访问此 API 的源代码,也无需了解此 API 是如何制作的。也就是说,无论是通过浏览器还是编程语言,您现在已经在使用简单的 API。
  4.使用简单的API接口后,进一步想知道它的内部机制是什么
  基于可以使用的知识,API的源代码及其内部机制是什么?目前可以调用经纬度API,单纯获取位置是不够的。你可能想自己写一个API接口,而不是紧紧地提供位置信息,同时添加对城市的介绍。
  使用 Python 的 tornado 模块构建 Web 服务。让我们创建一个脚本空文件 web_server.py 并将以下代码复制到其中
  # -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding(&#39;utf-8&#39;)
import tornado.ioloop
import tornado.web
import json
import requests
lists = {u"深圳": "是经济特区,紧邻广州,接壤香港,人口约1200万",
u"青岛": "旅游城市,濒临黄海,特产啤酒,人口约920万"
}
def get_loc(city):
r = requests.get("http://gc.ditu.aliyun.com/geocoding?a=%s" % city.encode(&#39;UTF-8&#39;))
<p>
loc = r.json()
return "经度是%s,纬度是%s" % (loc["lon"], loc["lat"])
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
return self.get_secure_cookie("user")
class MainHandler(BaseHandler):
def get(self):
if self.request.arguments.has_key("id"):
greeting = self.get_argument(&#39;id&#39;, &#39;Hello&#39;)
if greeting in lists:
self.write(greeting + ": " + str(get_loc(greeting)) + "," + str(lists[greeting]))
else:
self.write("none")
settings = dict(cookie_secret="P1/V61oETzdkLmGeJJFuYh7Eo5KXQAGaYgEQnp2XdTo=", debug=True)
application = tornado.web.Application([(r"/", MainHandler), ], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.current().start()</p>
  执行web_server.py,执行后会启动一个web服务
  接下来我们在浏览器中输入192.168.199.204:8888/?id=Shenzhen
  注意我自己电脑的局域网IP是192.168.199.204,需要换成自己电脑(或者虚拟机)的ip。
  从上图中,我们实现了和“阿里巴巴云经纬度界面”一样的功能,得到了除了经纬度之外的城市的简要描述。随着航次越来越多,您让船上的每个人不仅了解地理信息,还了解每个城市的经济和文化状况。随着信息和数据的增加,特别需要能够先保存数据,使用时直接调用API的东西。
  5.数据存储,按需调整
  上面,我们模仿阿里云的API,搭建了一个Web服务,提供更详细的API地理位置信息服务。现在想想,我们代码里只有深圳和青岛两个城市,还有很多城市没有提到。此外,城市还有经济发展、饮食文化等。我们将深圳和青岛的城市信息存储到mysql中。
  保存后,我们直接从mysql中获取数据,通过API直接展示给浏览器。更改 web_server.py 脚本
  # -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding(&#39;utf-8&#39;)
import tornado.ioloop
import tornado.web
import json
import requests
import MySQLdb.constants
def get_mysql(sql_string):
conn = MySQLdb.connect(host=&#39;localhost&#39;, port = 3306, user = &#39;root&#39;, passwd = &#39;123456&#39;, db = &#39;test&#39;, charset = &#39;utf8&#39;)
cursor = conn.cursor()
cursor.execute(sql_string)
resultList = {}
for data in cursor.fetchall():
<p>
city_name = data[0]
city_introduce = data[1]
resultList[city_name] = city_introduce
return resultList
cursor.close()
conn1.close()
def get_loc(city):
r = requests.get("http://gc.ditu.aliyun.com/geocoding?a=%s" % city.encode(&#39;UTF-8&#39;))
loc = r.json()
return "经度是%s,纬度是%s" % (loc["lon"], loc["lat"])
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
return self.get_secure_cookie("user")
class MainHandler(BaseHandler):
def get(self):
if self.request.arguments.has_key("id"):
greeting = self.get_argument(&#39;id&#39;, &#39;Hello&#39;)
lists = get_mysql("select name,introduce from test.city where name =&#39;%s&#39; " % greeting.encode(&#39;UTF-8&#39;)) #直接从mysql里读取城市信息,特别注意这里的SQL
if greeting in lists:
self.write(greeting + ": " + str(get_loc(greeting)) + "," + str(lists[greeting]))
else:
self.write("none")
settings = dict(cookie_secret="P1/V61oETzdkLmGeJJFuYh7Eo5KXQAGaYgEQnp2XdTo=", debug=True)
application = tornado.web.Application([(r"/", MainHandler), ], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.current().start()
</p>
  保存web_server.py后,再次执行重启,在浏览器地址输入192.168.199.204:8888/?id=Shenzhen,出现与步骤4相同的结果,不过这次是从mysql中取数据,通过API显示界面浏览器。至此,你不仅会用到API,还会通过tornado打开web服务,打开一个API查询接口。
  最后,总结一下,从上面的文章,我先画了一张图,结合数据流向,描述了API的位置,然后用了一个信息采集器的故事,如何使用现有的接口,去提供更好的界面。当然,这太简单了。但我认为它也可以解释 API 的基本含义。生产环境中API的复杂性涉及数据复杂性、接口稳定性、高可用性和安全性。
  (本文结束,如有疑问请留言)
  推荐链接:
  1.知乎上API的答案
  /question/38594466/answer/228418422
  /question/38594466/answer/215257117
  API的作用:
  - 对于软件提供者,可以留出API供其他应用调用,形成生态系统,让软件发挥最大价值,变得更有生命力。(同时其他人看不到代码,不伤商业机密。)(可以顺丰京东为例)
  - 对于应用开发者来说,通过开放的API,可以直接调用多家公司制作的功能,制作自己的应用,无需自己动手,节省能源。
  /question/21691705/answer/26406216
  API(应用程序编程接口)
  翻译成中文是“应用程序接口”,其实这个翻译不好,应该说是“程序通信接口”。
  翻译成接口,顾名思义,就是用来沟通两种不同的东西,通常由一组函数库组成。
  同一平台下的两个不同的事物(程序或系统),为了访问彼此的功能等,
  因此,一个 X 程序编写了一组函数,以允许同一平台上的其他程序访问该 X 程序的函数。
  那套函数可以说是X程序对外开放的API。
  整套解决方案:wangmarket: 网市场云建站系统
  方法二:使用serverless版本快速做网站(建议先试试这个方法,毕竟不用花钱买服务器)
  做网站,不用买服务器,一年几毛钱的流量费和html文件存储费。对于只做一个或几个网站的朋友,这是首选,强烈推荐。毕竟只是做几个网站,谁愿意承担增加一台服务器的费用。
  下载链接:
  方法三:上线,华为云服务器,花1元快速部署上线使用
  根据本站开户、选台服务器,在线部署和使用网市云建站系统仅需一元,无需其他额外费用!
  (这个版本可能是5.2的镜像,有点旧,但是正常使用没问题,建议参与以下活动,我们会帮你安装最新版本)
  方式四:自定义部署,比如部署到私服、阿里云、腾讯云等(这种方式用得最多)
  参考:
  如果您要部署到服务器,建议您这样做。
  配套软件:Pa网站工具、模板计算工具
  看哪个网站,拉出来做个模板。我看到的 网站 可以被我使用!/mail_osc/templatespider
  系统二次开发目前使用的开源框架介绍
  SpringBoot2.6.1、Shiro、Redis5、Mysql5.7(必须是这个版本)、ElasticSearch 7.10.1、
  前端信息提示msg.js,客服代理kefu.js,网站管理后台Layui
  开发前注意事项
  用Java开发,有两种数据库,默认使用sqlite 3,也可以配置使用mysql。
  
  一定要注意版本号不要写错,jdk1.8和mysql用的是5.7,重要的事情说三遍
  另外,请使用 Eclipse 进行开发。我们从来没有使用过idea。如果idea出现异常,可以自行百度搜索解决方法,因为idea还有其他的朋友,很多都可以正常运行,但是我们没用过idea。如果您有想法 如果出现问题,我们将无法提供任何帮助。
  以下是一些入门步骤:
  本地环境和git导入项目配置Mysql数据库(可选,不做这一步完全可以运行) 代码起来后,通过安装向导,安装系统三分钟导入模板快速创建自己的网站
  从网市云建站系统v5.0版本中,我们提取了网市云建站系统底层基础支持,如常用工具、权限控制等,并调整打包了一套集成开发框架。叫它wm。也就是说,在网上市场搭建云站点的基本操作都收录在wm文档中。wm的基础开发文档包括数据库操作、文件操作、日志操作、短信发送、ajax请求等最基本的功能模块。通过它,软件系的应届毕业生可以在一个月内快速进入开发状态,具备项目开发能力。点击这里查看wm开发文档
  当前目录结构
  wangmarket 项目
├─src 项目源代码 ( Maven )
├─pom.xml 项目源代码 pom ( Maven )
├─else 其他的杂七杂八相关文件,一般用不到
│ ├─wangmarket.sql 项目运行所需要的数据库文件( Mysql数据库,默认sqlite3)
└─README.md 说明
  进行二次开发
  在二次开发过程中,我们不建议您直接在本项目中进行更改,否则您将失去跟随我们版本升级的能力。众所周知的织梦cms也被称为安全漏洞,因为版本未升级而失去维护。
  我们建议您可以扩展这个项目,开发您想要的模块和功能,以及一些原创功能和页面更改。例如,登陆页面的重写。
  当我们市场有新版本时,只需直接更新WEB-INF/lib/wangmarket-xxx.jar即可完成版本升级
  
  云模板库
  您的时间非常宝贵!它不会让你一接触就学会自己制作模板。我们自带云模板库,点击查看
  虽然模板不多,只有几百套,但创建网站后一键导入,直接使用!一键导入后,会自动创建栏目和页面。您只需要更改栏目名称,更改文字和图片,即可达到成本网站交付标准!作为一个早期的你,这足以服务客户并熟悉整个系统!另外,我们模板库的模板会不断增加。你看到的任何 网站 都可以被我使用 - 无限模板计划
  项目经验
  网市云建站系统,2009年开始使用php开发wap系统建站。用java重构后,2010年底发布了第一版Java版建站系统。历经十余年不断更新迭代,功能完善...
  活动,免费帮助安装+调试/发送授权/发送代理
  微信扫码关注公众号,花10分钟参与提示活动,即可换取我们在安装、调试、授权、代理等方面的帮助。
  作者的话
  我们支持白人卖淫,但我们不想做无意义的卖淫!很多工作室和小微公司想要生存下来,赚到一些钱,实属不易。在资本积累方面,如果你购买牌照,你显然会有很大的负担。如果您属于该领域,建议您参与我们的活动并关注微信公众号。“wangmarket”可以看到活动,不花钱用我们的开源很不容易,还得赚钱养家糊口。我们的精力真的很有限,所以我们只能把时间花在真正想用它的朋友身上。如果你能花10分钟参加活动,不管你能不能用,至少你有一个想法,愿意投入一点点去做,我们也愿意帮助您。联系微信:xnx3com
  常见问题-Q&amp;A 安装后只有一个网站,或者有代理后台可以打开多个网站
  安装功能齐全,包括代理后端。这样安装之后,其实就是你自己私有部署的一个SAAS云建站系统。代理后台的使用请参考:
  可以一键生成html网页吗?或伪静态
  是一键生成的html网页,是真静态,不是伪静态
  网站 如何与手机匹配?
  在我们模板库的数百个模板中,大部分模板都支持手机和电脑同时访问。其实这个问题与我们的建站系统无关。如何适配手机取决于你制作的模板中CSS样式是怎么写的,是否响应式适配手机。
  其他【帮助文档、系统使用帮助说明】()模板文档、模板开发说明、模板标签 查看全部

  通用解决方案:API(接口)是什么
  什么是 API(接口)?举个常见的例子,在京东下单并付款后,商户选择顺丰快递发货,然后就可以在京东上实时查看当前物流信息。京东和顺丰作为两家独立的公司,可以在京东上实时看到顺丰的快递信息。这需要 API。在查看自己的快递信息时,京东可以使用顺丰提供的API接口进行实时检索。信息单独呈现网站。此外,您还可以在快递100上输入订单号查询快递信息。只要有合作或许可,其他公司可以通过顺丰提供的API接口检索快递信息。由于有多个调用,
  我们来看看百度是如何给出API的定义的:
  API(应用程序编程接口)是预定义的函数,旨在为应用程序和开发人员提供访问基于软件或硬件的一组例程的能力,而无需访问源代码或了解该机制的内部工作细节。
  从百度的定义来看,我们首先关注:功能,提供应用和开发者,无需访问源代码,例程。注意这四个短语。其中,例程是系统对外提供的功能接口或服务的集合。本文重点介绍API的数据服务功能接口。
  首先,在下面的文章中,我将首先演示如何使用浏览器,无需编程,无需访问源代码,调用免费的API接口,让您使用最简单的接口;
  然后,将演示如何通过编程调用接口;
  最后,演示启动WEB服务,编写一个简单的API接口来体现API的功能(y=f(x))。
  您也可以尝试复制代码。通过自己的实验,你会学到一些关于后端、前端的知识,加深你对 API 的理解。那么开始吧,我们先来一张图:通过API提供信息(数据)的功能,看看数据是如何流动的。如果您为 API 指定特定位置,它将位于下图的中心。
  为了改变理解,我穿插了一个故事人物。假设世界太大了,你想在非洲大陆看到它,成为一名水手,在一次航行中被一位著名的航海家带走(你有船上唯一的卫星计算机),你会不可避免地成为途中的领航员。它将让您确定下一个城市的纬度和经度。这时候导航器让你确定深圳的经纬度。
  1.你是个人肉API
  这时候,你可以想到一个简单的方法就是去百度搜索。除了领航员,船上的高级水手和大副很可能会问你。这时候你其实就是一个接口,大家来找你获取地理位置信息。作为一个接口,你自己不产生信息,你只是信息的采集器和传递者,提供人肉数据服务。
  2.使用免费的经纬API接口
  在百度搜索过程中,很多网友给出的经纬度不一致,要反复对比才能辨别真伪。时间长了,你可能会觉得大家都在问位置,太烦人了。我的人肉API效率太慢了。有没有更快的方法。
  这时候,你发现了一个阿里云的免费API接口:深圳。您在浏览器的地址栏中输入此 URL,即可获得正确的纬度和经度。你把网址里的深圳换成别的城市,就可以找到了。这时候,通过这个界面,就可以大大提高为大家确定位置的效率。
  3.您对此不满意
  你觉得这个接口很好,你就是懂Python,为什么不写点代码,注意这个时候你的角色变了:你已经从人类API变成了开发者(注意这是百度里的API定义关键词),你现在的目标是编写可以自动获取这个地方的经纬度的代码。
  #python
import requests
r = requests.get("http://gc.ditu.aliyun.com/geocoding?a=深圳")
loc = r.json()
print loc
#打印出的结果:{u&#39;alevel&#39;: 4, u&#39;lon&#39;: 114.05786, u&#39;level&#39;: 2, u&#39;cityName&#39;: u&#39;&#39;, u&#39;address&#39;: u&#39;&#39;, u&#39;lat&#39;: 22.54309}
# 与在浏览器输入地址的结果一致
print "深圳的经度是%s,纬度是%s" % (loc["lon"], loc["lat"])
#打印出的结果是:深圳的经度是114.05786,纬度是22.54309
  至此,我们来回顾一下百度对API的定义。目前,作为开发者,您只需编写几行代码即可访问“阿里巴巴云经纬度接口”。您无需访问此 API 的源代码,也无需了解此 API 是如何制作的。也就是说,无论是通过浏览器还是编程语言,您现在已经在使用简单的 API。
  4.使用简单的API接口后,进一步想知道它的内部机制是什么
  基于可以使用的知识,API的源代码及其内部机制是什么?目前可以调用经纬度API,单纯获取位置是不够的。你可能想自己写一个API接口,而不是紧紧地提供位置信息,同时添加对城市的介绍。
  使用 Python 的 tornado 模块构建 Web 服务。让我们创建一个脚本空文件 web_server.py 并将以下代码复制到其中
  # -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding(&#39;utf-8&#39;)
import tornado.ioloop
import tornado.web
import json
import requests
lists = {u"深圳": "是经济特区,紧邻广州,接壤香港,人口约1200万",
u"青岛": "旅游城市,濒临黄海,特产啤酒,人口约920万"
}
def get_loc(city):
r = requests.get("http://gc.ditu.aliyun.com/geocoding?a=%s" % city.encode(&#39;UTF-8&#39;))
<p>
loc = r.json()
return "经度是%s,纬度是%s" % (loc["lon"], loc["lat"])
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
return self.get_secure_cookie("user")
class MainHandler(BaseHandler):
def get(self):
if self.request.arguments.has_key("id"):
greeting = self.get_argument(&#39;id&#39;, &#39;Hello&#39;)
if greeting in lists:
self.write(greeting + ": " + str(get_loc(greeting)) + "," + str(lists[greeting]))
else:
self.write("none")
settings = dict(cookie_secret="P1/V61oETzdkLmGeJJFuYh7Eo5KXQAGaYgEQnp2XdTo=", debug=True)
application = tornado.web.Application([(r"/", MainHandler), ], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.current().start()</p>
  执行web_server.py,执行后会启动一个web服务
  接下来我们在浏览器中输入192.168.199.204:8888/?id=Shenzhen
  注意我自己电脑的局域网IP是192.168.199.204,需要换成自己电脑(或者虚拟机)的ip。
  从上图中,我们实现了和“阿里巴巴云经纬度界面”一样的功能,得到了除了经纬度之外的城市的简要描述。随着航次越来越多,您让船上的每个人不仅了解地理信息,还了解每个城市的经济和文化状况。随着信息和数据的增加,特别需要能够先保存数据,使用时直接调用API的东西。
  5.数据存储,按需调整
  上面,我们模仿阿里云的API,搭建了一个Web服务,提供更详细的API地理位置信息服务。现在想想,我们代码里只有深圳和青岛两个城市,还有很多城市没有提到。此外,城市还有经济发展、饮食文化等。我们将深圳和青岛的城市信息存储到mysql中。
  保存后,我们直接从mysql中获取数据,通过API直接展示给浏览器。更改 web_server.py 脚本
  # -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding(&#39;utf-8&#39;)
import tornado.ioloop
import tornado.web
import json
import requests
import MySQLdb.constants
def get_mysql(sql_string):
conn = MySQLdb.connect(host=&#39;localhost&#39;, port = 3306, user = &#39;root&#39;, passwd = &#39;123456&#39;, db = &#39;test&#39;, charset = &#39;utf8&#39;)
cursor = conn.cursor()
cursor.execute(sql_string)
resultList = {}
for data in cursor.fetchall():
<p>
city_name = data[0]
city_introduce = data[1]
resultList[city_name] = city_introduce
return resultList
cursor.close()
conn1.close()
def get_loc(city):
r = requests.get("http://gc.ditu.aliyun.com/geocoding?a=%s" % city.encode(&#39;UTF-8&#39;))
loc = r.json()
return "经度是%s,纬度是%s" % (loc["lon"], loc["lat"])
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
return self.get_secure_cookie("user")
class MainHandler(BaseHandler):
def get(self):
if self.request.arguments.has_key("id"):
greeting = self.get_argument(&#39;id&#39;, &#39;Hello&#39;)
lists = get_mysql("select name,introduce from test.city where name =&#39;%s&#39; " % greeting.encode(&#39;UTF-8&#39;)) #直接从mysql里读取城市信息,特别注意这里的SQL
if greeting in lists:
self.write(greeting + ": " + str(get_loc(greeting)) + "," + str(lists[greeting]))
else:
self.write("none")
settings = dict(cookie_secret="P1/V61oETzdkLmGeJJFuYh7Eo5KXQAGaYgEQnp2XdTo=", debug=True)
application = tornado.web.Application([(r"/", MainHandler), ], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.current().start()
</p>
  保存web_server.py后,再次执行重启,在浏览器地址输入192.168.199.204:8888/?id=Shenzhen,出现与步骤4相同的结果,不过这次是从mysql中取数据,通过API显示界面浏览器。至此,你不仅会用到API,还会通过tornado打开web服务,打开一个API查询接口。
  最后,总结一下,从上面的文章,我先画了一张图,结合数据流向,描述了API的位置,然后用了一个信息采集器的故事,如何使用现有的接口,去提供更好的界面。当然,这太简单了。但我认为它也可以解释 API 的基本含义。生产环境中API的复杂性涉及数据复杂性、接口稳定性、高可用性和安全性。
  (本文结束,如有疑问请留言)
  推荐链接:
  1.知乎上API的答案
  /question/38594466/answer/228418422
  /question/38594466/answer/215257117
  API的作用:
  - 对于软件提供者,可以留出API供其他应用调用,形成生态系统,让软件发挥最大价值,变得更有生命力。(同时其他人看不到代码,不伤商业机密。)(可以顺丰京东为例)
  - 对于应用开发者来说,通过开放的API,可以直接调用多家公司制作的功能,制作自己的应用,无需自己动手,节省能源。
  /question/21691705/answer/26406216
  API(应用程序编程接口)
  翻译成中文是“应用程序接口”,其实这个翻译不好,应该说是“程序通信接口”。
  翻译成接口,顾名思义,就是用来沟通两种不同的东西,通常由一组函数库组成。
  同一平台下的两个不同的事物(程序或系统),为了访问彼此的功能等,
  因此,一个 X 程序编写了一组函数,以允许同一平台上的其他程序访问该 X 程序的函数。
  那套函数可以说是X程序对外开放的API。
  整套解决方案:wangmarket: 网市场云建站系统
  方法二:使用serverless版本快速做网站(建议先试试这个方法,毕竟不用花钱买服务器)
  做网站,不用买服务器,一年几毛钱的流量费和html文件存储费。对于只做一个或几个网站的朋友,这是首选,强烈推荐。毕竟只是做几个网站,谁愿意承担增加一台服务器的费用。
  下载链接:
  方法三:上线,华为云服务器,花1元快速部署上线使用
  根据本站开户、选台服务器,在线部署和使用网市云建站系统仅需一元,无需其他额外费用!
  (这个版本可能是5.2的镜像,有点旧,但是正常使用没问题,建议参与以下活动,我们会帮你安装最新版本)
  方式四:自定义部署,比如部署到私服、阿里云、腾讯云等(这种方式用得最多)
  参考:
  如果您要部署到服务器,建议您这样做。
  配套软件:Pa网站工具、模板计算工具
  看哪个网站,拉出来做个模板。我看到的 网站 可以被我使用!/mail_osc/templatespider
  系统二次开发目前使用的开源框架介绍
  SpringBoot2.6.1、Shiro、Redis5、Mysql5.7(必须是这个版本)、ElasticSearch 7.10.1、
  前端信息提示msg.js,客服代理kefu.js,网站管理后台Layui
  开发前注意事项
  用Java开发,有两种数据库,默认使用sqlite 3,也可以配置使用mysql。
  
  一定要注意版本号不要写错,jdk1.8和mysql用的是5.7,重要的事情说三遍
  另外,请使用 Eclipse 进行开发。我们从来没有使用过idea。如果idea出现异常,可以自行百度搜索解决方法,因为idea还有其他的朋友,很多都可以正常运行,但是我们没用过idea。如果您有想法 如果出现问题,我们将无法提供任何帮助。
  以下是一些入门步骤:
  本地环境和git导入项目配置Mysql数据库(可选,不做这一步完全可以运行) 代码起来后,通过安装向导,安装系统三分钟导入模板快速创建自己的网站
  从网市云建站系统v5.0版本中,我们提取了网市云建站系统底层基础支持,如常用工具、权限控制等,并调整打包了一套集成开发框架。叫它wm。也就是说,在网上市场搭建云站点的基本操作都收录在wm文档中。wm的基础开发文档包括数据库操作、文件操作、日志操作、短信发送、ajax请求等最基本的功能模块。通过它,软件系的应届毕业生可以在一个月内快速进入开发状态,具备项目开发能力。点击这里查看wm开发文档
  当前目录结构
  wangmarket 项目
├─src 项目源代码 ( Maven )
├─pom.xml 项目源代码 pom ( Maven )
├─else 其他的杂七杂八相关文件,一般用不到
│ ├─wangmarket.sql 项目运行所需要的数据库文件( Mysql数据库,默认sqlite3)
└─README.md 说明
  进行二次开发
  在二次开发过程中,我们不建议您直接在本项目中进行更改,否则您将失去跟随我们版本升级的能力。众所周知的织梦cms也被称为安全漏洞,因为版本未升级而失去维护。
  我们建议您可以扩展这个项目,开发您想要的模块和功能,以及一些原创功能和页面更改。例如,登陆页面的重写。
  当我们市场有新版本时,只需直接更新WEB-INF/lib/wangmarket-xxx.jar即可完成版本升级
  
  云模板库
  您的时间非常宝贵!它不会让你一接触就学会自己制作模板。我们自带云模板库,点击查看
  虽然模板不多,只有几百套,但创建网站后一键导入,直接使用!一键导入后,会自动创建栏目和页面。您只需要更改栏目名称,更改文字和图片,即可达到成本网站交付标准!作为一个早期的你,这足以服务客户并熟悉整个系统!另外,我们模板库的模板会不断增加。你看到的任何 网站 都可以被我使用 - 无限模板计划
  项目经验
  网市云建站系统,2009年开始使用php开发wap系统建站。用java重构后,2010年底发布了第一版Java版建站系统。历经十余年不断更新迭代,功能完善...
  活动,免费帮助安装+调试/发送授权/发送代理
  微信扫码关注公众号,花10分钟参与提示活动,即可换取我们在安装、调试、授权、代理等方面的帮助。
  作者的话
  我们支持白人卖淫,但我们不想做无意义的卖淫!很多工作室和小微公司想要生存下来,赚到一些钱,实属不易。在资本积累方面,如果你购买牌照,你显然会有很大的负担。如果您属于该领域,建议您参与我们的活动并关注微信公众号。“wangmarket”可以看到活动,不花钱用我们的开源很不容易,还得赚钱养家糊口。我们的精力真的很有限,所以我们只能把时间花在真正想用它的朋友身上。如果你能花10分钟参加活动,不管你能不能用,至少你有一个想法,愿意投入一点点去做,我们也愿意帮助您。联系微信:xnx3com
  常见问题-Q&amp;A 安装后只有一个网站,或者有代理后台可以打开多个网站
  安装功能齐全,包括代理后端。这样安装之后,其实就是你自己私有部署的一个SAAS云建站系统。代理后台的使用请参考:
  可以一键生成html网页吗?或伪静态
  是一键生成的html网页,是真静态,不是伪静态
  网站 如何与手机匹配?
  在我们模板库的数百个模板中,大部分模板都支持手机和电脑同时访问。其实这个问题与我们的建站系统无关。如何适配手机取决于你制作的模板中CSS样式是怎么写的,是否响应式适配手机。
  其他【帮助文档、系统使用帮助说明】()模板文档、模板开发说明、模板标签

技术分享:爬虫 | 如何构建技术文章聚合平台(二)

采集交流优采云 发表了文章 • 0 个评论 • 82 次浏览 • 2022-11-02 17:22 • 来自相关话题

  技术分享:爬虫 | 如何构建技术文章聚合平台(二)
  作者 | 张马文
  来源 | 掘金
  上一篇文章《教你如何用Crawlab搭建技术文章聚合平台(一)》介绍了如何使用和搭建Crawlab运行环境,并将Puppeteer与Crawlab集成,对掘金很有帮助, SegmentFault , CSDN 爬取技术文章,最后可以查看爬取结果。本文文章将继续讲解如何使用Flask+Vue编写一个精简的聚合平台来展示捕获到的文章内容。
  文章内容爬虫
  首先,我们需要对爬虫部分做一个小的补充。在上一篇文章中,我们只写了一个爬取文章网址的爬虫。我们还需要爬取文章内容,所以也需要编写爬虫这部分。上次爬虫的结果集合全部改成results,文章的内容会保存在数据库的content字段中。
  经过分析,我们知道每个技术网站的文章页面都有一个固定的标签,抓取这个标签下的所有HTML就可以了。具体代码分析就不展开了,这里贴出具体代码。
  <p>const puppeteer = require('puppeteer');
  const MongoClient = require('mongodb').MongoClient;
  (async => {
  // browser
  const browser = await (puppeteer.launch({
  headless: true
  }));
  // page
  const page = await browser.newPage;
  // open database connection
  const client = await MongoClient.connect('mongodb://192.168.99.100:27017');
  let db = await client.db('crawlab_test');
  const colName = process.env.CRAWLAB_COLLECTION || 'results';
  const col = db.collection(colName);
  const col_src = db.collection('results');
  const results = await col_src.find({content: {$exists: false}}).toArray;
  for (let i = 0; i < results.length; i++) {
  let item = results[i];
  // define article anchor
  let anchor;
  if (item.source === 'juejin') {
  anchor = '.article-content';
  } else if (item.source === 'segmentfault') {
  anchor = '.article';
  } else if (item.source === 'csdn') {
  anchor = '#content_views';
  } else {
  continue;
  }
  console.log(`anchor: ${anchor}`);
  // navigate to the article
  try {
  await page.goto(item.url, {waitUntil: 'domcontentloaded'});
  await page.waitFor(2000);
  } catch (e) {
  console.error(e);
  continue;
  }
  // scrape article content
  item.content = await page.$eval(anchor, el => el.innerHTML);
  // save to database
  await col.save(item);
  console.log(`saved item: ${JSON.stringify(item)}`)
  }
  // close mongodb
  client.close;
  // close browser
  browser.close;
  });</p>
  然后按照上一篇文章的步骤部署运行爬虫,就可以采集到详细的文章内容了。
  文章内容爬虫的代码已经更新到Github了。
  接下来,我们可以开始对这些 文章 做 文章。
  前后分离
  从目前的技术发展来看,前后端分离已经成为主流:一是前端技术越来越复杂,需要模块化和工程化;第二,前后端分离,让前后端团队分工协作,更高效地开发应用。由于本文的聚合平台是一个轻量级的应用,所以我们使用Python的轻量级Web应用框架Flask来编写后端界面,而我们使用的是近年来非常流行的Vue,前端也很容易上手-结尾。
  烧瓶
  Flask全称为Micro Framework,可见其轻量级,几行代码就能写出一个Web应用。它依赖扩展插件来扩展其特定功能,例如登录身份验证、RESTful、数据模型等。在本节中,我们将构建一个 RESTful 后端 API 应用程序。
  安装
  首先安装相关的依赖。
  <p>pip install flask flask_restful flask_cors pymongo</p>
  基本应用
  安装完成后,我们可以新建一个app.py文件,输入如下代码
  <p>from flask import Flask
  from flask_cors import CORS
  from flask_restful import Api
  # 生成Flask App实例
  app = Flask(__name__)
  # 生成API实例
  api = Api(app)
  # 支持CORS跨域
  CORS(app, supports_credentials=True)
  if __name__ == '__main__':
  app.run</p>
  这个基本的 Flask 应用程序可以通过在命令行输入 python app.py 来运行。
  编写 API
  接下来,我们需要编写获取文章的接口。首先,让我们简要分析一下需求。
  这个 Flask 应用程序要实现的功能是:
  从数据库中获取捕获的文章,并将文章ID、标题、摘要、捕获时间返回给前端,作为文章列表使用;
  
  对于给定的 文章ID,从数据库中返回相应的 文章 内容,以供前端用作详细信息页面。
  因此,我们需要实现上述两个API。让我们开始编写界面。
  列表界面
  在 app.py 中添加如下代码作为列表界面。
  <p>class ListApi(Resource):
  def get(self):
  # 查询
  items = col.find({'content': {'$exists': True}}).sort('_id', DESCENDING).limit(40)
  data =
  for item in items:
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  data.append({
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S')
  })
  return data</p>
  详情界面
  同样,在 app.py 中输入以下代码。
  <p>class DetailApi(Resource):
  def get(self, id):
  item = col.find_one({'_id': ObjectId(id)})
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  return {
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S'),
  'content': _item['content']
  }</p>
  映射接口
  编写好接口后,我们需要将它们映射到相应的 URL。
  <p>api.add_resource(ListApi, '/results')
  api.add_resource(DetailApi, '/results/')</p>
  完整代码
  下面是完整的Flask应用代码,非常简单,实现了文章list和文章details两个功能。接下来,我们将开始开发前端部分。
  <p>import json
  from bson import json_util, ObjectId
  from flask import Flask, jsonify
  from flask_cors import CORS
  from flask_restful import Api, Resource
  from pymongo import MongoClient, DESCENDING
  # 生成Flask App实例
  app = Flask(__name__)
  # 生成MongoDB实例
  mongo = MongoClient(host='192.168.99.100')
  db = mongo['crawlab_test']
  col = db['results']
  # 生成API实例
  api = Api(app)
  # 支持CORS跨域
  CORS(app, supports_credentials=True)
  class ListApi(Resource):
  def get(self):
  # 查询
  items = col.find({}).sort('_id', DESCENDING).limit(20)
  data =
  for item in items:
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  data.append({
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S')
  })
  return data
  class DetailApi(Resource):
  def get(self, id):
  item = col.find_one({'_id': ObjectId(id)})
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  return {
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S'),
  'content': _item['content']
  }
  api.add_resource(ListApi, '/results')
  api.add_resource(DetailApi, '/results/')
  if __name__ == '__main__':
  app.run</p>
  运行 python app.py 运行后台接口服务器。
  Vue
  Vue这几年非常火。它已经在 Github 上超越 React,成为三大开源框架(React、Vue 和 Angular)中 Star 最多的项目。与 React 和 Angular 相比,Vue 非常容易上手。您可以使用双向绑定数据快速开始构建简单的应用程序,也可以使用 Vuex 单向数据传输构建大型应用程序。这种灵活性是它受到大多数开发人员欢迎的原因之一。
  为了构建一个简单的 Vue 应用程序,我们将使用 vue-cli3,一个 Vue 项目的脚手架。首先,我们从 npm 安装脚手架。
  安装 vue-cli3
  <p>yarn add @vue/cli</p>
  如果你还没有安装yarn,执行下面的命令安装。
  <p>npm i -g yarn</p>
  创建项目
  接下来,我们需要使用 vue-cli3 构建一个项目。执行以下命令。
  <p>vue create frontend</p>
  命令行会弹出以下选项,选择默认即可。
  
  <p>? Please pick a preset: (Use arrow keys)
  ❯ default (babel, eslint)
  preset (vue-router, vuex, node-sass, babel, eslint, unit-jest)
  Manually select features </p>
  然后 vue-cli3 将开始准备必要的依赖项来构建项目并生成项目结构。
  此外,我们还需要安装完成其他功能所需的包。
  <p>yarn add axios</p>
  文章列表页面
  在 views 目录中创建一个 List.vue 文件,内容如下。
  <p>
  {{article.title}}
  
  {{article.ts}}
  import axios from 'axios'
  export default {
  name: 'List',
  data {
  return {
  list:
  }
  },
  methods: {
  showArticle (id) {
  this.$router.push(`/${id}`)
  }
  },
  created {
  axios.get('http://localhost:5000/results')
  .then(response => {
  this.list = response.data
  })
  }
  }
  .list {
  display: flex;
  }
  .left {
  flex-basis: 20%;
  }
  .right {
  flex-basis: 20%;
  }
  .article-list {
  text-align: left;
  list-style: none;
  }
  .article-item {
  background: #c3edfb;
  border-radius: 5px;
  padding: 5px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
  }
  .title {
  flex-basis: auto;
  color: #58769d;
  }
  .time {
  font-size: 10px;
  text-align: right;
  flex-basis: 180px;
  }</p>
  其中,ajax与API交互引用axios,这里获取list接口。该布局用于经典的双圣杯布局。methods中的showArticle方法接收到id参数,跳转到详情页。
  文章详情页面
  在views目录下,创建一个Detail.vue文件,输入如下内容。
  <p>{{article.title}}
  import axios from 'axios'
  export default {
  name: 'Detail',
  data {
  return {
  article: {}
  }
  },
  computed: {
  id {
  return this.$route.params.id
  }
  },
  created {
  axios.get(`http://localhost:5000/results/${this.id}`)
  .then(response => {
  this.article = response.data
  })
  }
  }
  .detail {
  display: flex;
  }
  .left {
  flex-basis: 20%;
  }
  .right {
  flex-basis: 20%;
  }
  .center {
  flex-basis: 60%;
  text-align: left;
  }
  .title {
  }</p>
  这个页面也是经典的双圣杯布局,中间占40%。API获取的文章内容输出到content,并通过v-html绑定。其实这里可以做进一步的CSS优化,只是作者太懒了,这个任务留给读者自己去完成。
  添加路线
  编辑 router.js 文件并将其修改为以下内容。
  <p>import Vue from 'vue'
  import Router from 'vue-router'
  import List from './views/List'
  import Detail from './views/Detail'
  Vue.use(Router)
  export default new Router({
  mode: 'hash',
  base: process.env.BASE_URL,
  routes: [
  {
  path: '/',
  name: 'List',
  component: List
  },
  {
  path: '/:id',
  name: 'Detail',
  component: Detail
  }
  ]
  })</p>
  运行前端
  在命令行中输入以下命令,打开:8080可以看到文章的列表。
  <p>npm run serve</p>
  最终效果
  最终聚合平台效果截图如下,可以看到基本样式已经出来了。
  总结
  本文在上一篇文章《教你如何用Crawlab搭建技术文章聚合平台(一)》的基础上,介绍了Flask+Vue的使用方法以及之前抓取的文章数据,搭建一个简单的技术文章聚合平台。使用的技术非常基础。当然,肯定还有很大的优化和改进空间。这是留给读者和大人物的。
  直观:通过网络爬虫采集大数据
  2021-07-02
  网络数据采集是指通过网络爬虫或网站公共API从网站获取数据信息。该方法可以从网页中提取非结构化数据,存储为统一的本地数据文件,并以结构化的方式存储。支持图片、音频、视频等文件或附件的采集,附件可以自动与文本关联。
  在互联网时代,网络爬虫主要为搜索引擎提供最全面、最新的数据。
  本节首先简要介绍网络爬虫的原理和工作流程,然后讨论网络爬虫的爬取策略,最后介绍典型的网络工具。
  网络爬虫的原理
  网络爬虫是根据一定的规则自动爬取网络信息的程序或脚本。
  网络爬虫可以自动采集所有可以访问的页面内容,为搜索引擎和大数据分析提供数据源。从功能上来说,爬虫一般具有数据采集、处理和存储三个功能,如图1所示。
  图1 网络爬虫示意图
  除了供用户阅读的文字信息外,网页还收录一些超链接信息。
  网络爬虫系统正是通过网页中的超链接信息不断获取网络上的其他网页。网络爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL。在爬取网页的过程中,不断地从当前页面中提取新的 URL 并放入队列中,直到满足系统的某些停止条件。
  网络爬虫系统一般会选择一些比较重要的、出度(网页链接出的超链接数)网站较大的URL作为种子URL集。
  网络爬虫系统使用这些种子集作为初始 URL 来开始数据爬取。因为网页中收录链接信息,所以会通过已有网页的URL获取一些新的URL。
  网页之间的指向结构可以看成一片森林,每个种子URL对应的网页就是森林中一棵树的根节点,这样网络爬虫系统就可以按照广度优先搜索算法遍历所有信息或深度优先搜索算法。网页。
  由于深度优先搜索算法可能导致爬虫系统陷入网站内部,不利于搜索距离网站首页比较近的网页信息,因此广度优先搜索算法一般使用采集网页。
  网络爬虫系统首先将种子 URL 放入下载队列,简单地从队列头部取一个 URL 下载其对应的网页,获取网页内容并存储,然后解析链接信息网页以获取一些新的 URL。
  其次,根据一定的网页分析算法,过滤掉与主题无关的链接,保留有用的链接,放入待抓取的URL队列中。
  最后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。
  网络爬虫工作流程
  如图 2 所示,网络爬虫的基本工作流程如下。
  1) 首先选择种子 URL 的一部分。
  2)将这些网址放入待抓取的网址队列中。
  3)从待爬取URL队列中取出待爬取URL,解析DNS,获取主机IP地址,下载该URL对应的网页,存入下载的网页库中。此外,将这些 URL 放入 Crawl URLs 队列。
  4)分析URL队列中已经爬取的URL,分析其中的其他URL,将这些URL放入待爬取的URL队列,从而进入下一个循环。
  图2 网络爬虫基本工作流程
  网络爬虫抓取策略
  谷歌、百度等常见搜索引擎抓取的网页数量通常以数十亿计。那么,面对如此多的网页,网络爬虫如何才能尽可能的遍历所有网页呢?如果您对大数据开发感兴趣,想系统地学习大数据,可以加入大数据技术学习交流群:458号345号782获取学习资源,从而扩大网页信息的覆盖范围可能,这是网络爬虫系统面临的一个非常关键的问题。在网络爬虫系统中,爬取策略决定了网页被爬取的顺序。
  本节首先简要介绍网络爬取策略中使用的基本概念。
  1)网页之间的关系模型
  从互联网的结构来看,网页通过各种超链接相互连接,形成一个巨大而复杂的相互关联的有向图。
  
  如图3所示,如果把网页看成图中的一个节点,把网页中其他网页的链接看成这个节点到其他节点的边,那么我们就可以轻松查看整个互联网网页被建模为有向图。
  理论上,通过遍历算法对图进行遍历,几乎可以访问互联网上的任何网页。
  图3 网页关系模型图
  2)网页分类
  从爬虫的角度来划分互联网,可以将互联网的所有页面分为5个部分:已下载未过期网页、已下载已过期网页、待下载网页、已知网页和未知网页,如图4.
  本地爬取的网页实际上是互联网内容的镜像和备份。互联网正在动态变化。当互联网的一部分内容发生变化时,本地抓取的网页就会失效。因此,下载的网页分为两类:下载的未过期网页和下载的过期网页。
  图4 网页分类
  要下载的页面是 URL 队列中要抓取的页面。
  可以看出,网页是指尚未被爬取且不在待爬取URL队列中的网页,但可以通过分析爬取的页面或待爬取URL对应的页面得到。
  还有一些网页是网络爬虫无法直接爬取下载的,称为不可知网页。
  下面重点介绍几种常见的爬取策略。
  1.万能网络爬虫
  通用网络爬虫也称为全网爬虫。爬取对象从一些种子URL延伸到整个网络,主要针对门户网站搜索引擎和大型网络服务商采集数据。
  为了提高工作效率,一般的网络爬虫都会采用一定的爬取策略。常用的爬取策略有深度优先策略和广度优先策略。
  1) 深度优先策略
  深度优先策略意味着网络爬虫将从起始页面开始,并逐个链接地跟踪它,直到无法再深入为止。
  完成一个爬取分支后,网络爬虫返回上一个链接节点,进一步搜索其他链接。当所有的链接都遍历完后,爬取任务结束。
  这种策略比较适合垂直搜索或者站内搜索,但是在抓取页面内容比较深的网站时会造成巨大的资源浪费。
  以图3为例,遍历的路径为1→2→5→6→3→7→4→8。
  在深度优先策略中,当搜索一个节点时,该节点的子节点和子节点的后继节点都在该节点的兄弟节点之前,深度优先策略在搜索空间中。有时,它会尝试尽可能深入,并且仅在找不到节点的后继节点时才考虑其兄弟节点。
  这样的策略决定了深度优先策略不一定能找到最优解,甚至由于深度的限制而无法找到解。
  如果不加以限制,它将沿着一条路径无限扩展,这将“捕获”成大量数据。一般来说,使用深度优先策略会选择一个合适的深度,然后反复搜索直到找到一个解,这样会降低搜索的效率。因此,当搜索数据量较小时,一般采用深度优先策略。
  2) 广度优先策略
  广度优先策略根据网页内容目录层次的深度对页面进行爬取,较浅的目录层次的页面先爬取。当同一级别的页面被爬取时,爬虫进入下一级继续爬取。
  还是以图3为例,遍历的路径是1→2→3→4→5→6→7→8
  由于广度优先策略是在第 N 层的节点扩展完成后进入第 N+1 层,保证了通过最短路径找到解。
  该策略可以有效控制页面的爬取深度,避免遇到无限深分支时无法结束爬取的问题。易于实现,不需要存储大量的中间节点。缺点是爬到更深的目录级别需要很长时间。页。
  如果搜索的分支太多,即节点的后继节点太多,算法就会耗尽资源,在可用空间中找不到解。
  2.专注于网络爬虫
  聚焦网络爬虫,也称为主题网络爬虫,是选择性地爬取与预定义主题相关的页面的网络爬虫。
  
  1)基于内容评价的爬取策略
  DeBra 将文本相似度的计算方法引入网络爬虫,提出了 Fish Search 算法。
  该算法以用户输入的查询词为主题,将收录查询词的页面视为与该主题相关的页面,其局限性在于无法评估该页面与该主题的相关性。
  Herseovic 对 Fish Search 算法进行了改进,提出了 Shark Search 算法,该算法使用空间向量模型来计算页面和主题之间的相关度。
  通过采用基于连续值计算链接值的方法,我们不仅可以计算出哪些捕获的链接与主题相关,而且可以得到相关性的量化大小。
  2)基于链接结构评估的爬取策略
  与普通文本不同,网页是收录大量结构化信息的半结构化文档。
  网页不是单独存在的。页面中的链接表示页面之间的关系。基于链接结构的搜索策略模式利用这些结构特征来评估页面和链接的重要性,从而确定搜索顺序。其中,PageRank算法就是这种搜索策略模式的代表。
  PageRank算法的基本原理是,如果一个网页被多次引用,它可能是一个重要的网页;如果一个网页没有被多次引用,而是被一个重要网页引用,那么它也可能是一个重要网页。一个网页的重要性同样传递给它所指的网页。
  链接页面的PageRank是通过将某个页面的PageRank除以该页面上存在的前向链接,并将得到的值分别与前向链接所指向的页面的PageRank相加得到。
  如图 5 所示,PageRank 为 100 的页面将其重要性平等地传递给它所引用的两个页面,每个页面获得 50,而 PageRank 为 9 的同一页面将其重要性传递给它所引用的三个页面。页面的每一页都传递一个值 3。
  PageRank 为 53 的页面的值源自引用它的两个页面传递的值。
  ,
  图5 PageRank算法示例
  3)基于强化学习的爬取策略
  Rennie 和 McCallum 将强化学习引入聚焦爬虫,使用贝叶斯分类器根据整个网页文本和链接文本对超链接进行分类,并计算每个链接的重要性以确定链接被访问的顺序。
  4)基于上下文图的爬取策略
  勤勉等人。提出了一种爬取策略,通过构建上下文图来学习网页之间的相关性。该策略可以训练一个机器学习系统,通过该系统可以计算当前页面到相关网页的距离。中的链接具有优先访问权。
  3.增量网络爬虫
  增量网络爬虫是指对下载的网页进行增量更新,只爬取新生成或更改的网页的爬虫。可以在一定程度上保证爬取的页面尽可能的新。
  增量网络爬虫有两个目标:
  为了实现第一个目标,增量网络爬虫需要通过重访网页来更新本地页面集中的页面内容。常用的方法有统一更新法、个体更新法和分类更新法。
  为了实现第二个目标,增量网络爬虫需要对网页的重要性进行排名。常见的策略包括广度优先策略和PageRank优先策略。
  4. 深网爬虫
  网页按存在方式可分为表层网页和深层网页。
  深网爬虫架构由六个基本功能模块(爬取控制器、解析器、表单分析器、表单处理器、响应分析器、LVS控制器)和两个爬虫内部数据结构(URL列表和LVS表)组成。
  其中,LVS(LabelValueSet)表示标签和值的集合,用来表示填写表格的数据源。在爬取过程中,最重要的部分是表单填写,包括基于领域知识的表单填写和基于网页结构分析的表单填写。
  分类:
  技术要点:
  相关文章: 查看全部

  技术分享:爬虫 | 如何构建技术文章聚合平台(二)
  作者 | 张马文
  来源 | 掘金
  上一篇文章《教你如何用Crawlab搭建技术文章聚合平台(一)》介绍了如何使用和搭建Crawlab运行环境,并将Puppeteer与Crawlab集成,对掘金很有帮助, SegmentFault , CSDN 爬取技术文章,最后可以查看爬取结果。本文文章将继续讲解如何使用Flask+Vue编写一个精简的聚合平台来展示捕获到的文章内容。
  文章内容爬虫
  首先,我们需要对爬虫部分做一个小的补充。在上一篇文章中,我们只写了一个爬取文章网址的爬虫。我们还需要爬取文章内容,所以也需要编写爬虫这部分。上次爬虫的结果集合全部改成results,文章的内容会保存在数据库的content字段中。
  经过分析,我们知道每个技术网站的文章页面都有一个固定的标签,抓取这个标签下的所有HTML就可以了。具体代码分析就不展开了,这里贴出具体代码。
  <p>const puppeteer = require('puppeteer');
  const MongoClient = require('mongodb').MongoClient;
  (async => {
  // browser
  const browser = await (puppeteer.launch({
  headless: true
  }));
  // page
  const page = await browser.newPage;
  // open database connection
  const client = await MongoClient.connect('mongodb://192.168.99.100:27017');
  let db = await client.db('crawlab_test');
  const colName = process.env.CRAWLAB_COLLECTION || 'results';
  const col = db.collection(colName);
  const col_src = db.collection('results');
  const results = await col_src.find({content: {$exists: false}}).toArray;
  for (let i = 0; i < results.length; i++) {
  let item = results[i];
  // define article anchor
  let anchor;
  if (item.source === 'juejin') {
  anchor = '.article-content';
  } else if (item.source === 'segmentfault') {
  anchor = '.article';
  } else if (item.source === 'csdn') {
  anchor = '#content_views';
  } else {
  continue;
  }
  console.log(`anchor: ${anchor}`);
  // navigate to the article
  try {
  await page.goto(item.url, {waitUntil: 'domcontentloaded'});
  await page.waitFor(2000);
  } catch (e) {
  console.error(e);
  continue;
  }
  // scrape article content
  item.content = await page.$eval(anchor, el => el.innerHTML);
  // save to database
  await col.save(item);
  console.log(`saved item: ${JSON.stringify(item)}`)
  }
  // close mongodb
  client.close;
  // close browser
  browser.close;
  });</p>
  然后按照上一篇文章的步骤部署运行爬虫,就可以采集到详细的文章内容了。
  文章内容爬虫的代码已经更新到Github了。
  接下来,我们可以开始对这些 文章 做 文章。
  前后分离
  从目前的技术发展来看,前后端分离已经成为主流:一是前端技术越来越复杂,需要模块化和工程化;第二,前后端分离,让前后端团队分工协作,更高效地开发应用。由于本文的聚合平台是一个轻量级的应用,所以我们使用Python的轻量级Web应用框架Flask来编写后端界面,而我们使用的是近年来非常流行的Vue,前端也很容易上手-结尾。
  烧瓶
  Flask全称为Micro Framework,可见其轻量级,几行代码就能写出一个Web应用。它依赖扩展插件来扩展其特定功能,例如登录身份验证、RESTful、数据模型等。在本节中,我们将构建一个 RESTful 后端 API 应用程序。
  安装
  首先安装相关的依赖。
  <p>pip install flask flask_restful flask_cors pymongo</p>
  基本应用
  安装完成后,我们可以新建一个app.py文件,输入如下代码
  <p>from flask import Flask
  from flask_cors import CORS
  from flask_restful import Api
  # 生成Flask App实例
  app = Flask(__name__)
  # 生成API实例
  api = Api(app)
  # 支持CORS跨域
  CORS(app, supports_credentials=True)
  if __name__ == '__main__':
  app.run</p>
  这个基本的 Flask 应用程序可以通过在命令行输入 python app.py 来运行。
  编写 API
  接下来,我们需要编写获取文章的接口。首先,让我们简要分析一下需求。
  这个 Flask 应用程序要实现的功能是:
  从数据库中获取捕获的文章,并将文章ID、标题、摘要、捕获时间返回给前端,作为文章列表使用;
  
  对于给定的 文章ID,从数据库中返回相应的 文章 内容,以供前端用作详细信息页面。
  因此,我们需要实现上述两个API。让我们开始编写界面。
  列表界面
  在 app.py 中添加如下代码作为列表界面。
  <p>class ListApi(Resource):
  def get(self):
  # 查询
  items = col.find({'content': {'$exists': True}}).sort('_id', DESCENDING).limit(40)
  data =
  for item in items:
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  data.append({
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S')
  })
  return data</p>
  详情界面
  同样,在 app.py 中输入以下代码。
  <p>class DetailApi(Resource):
  def get(self, id):
  item = col.find_one({'_id': ObjectId(id)})
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  return {
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S'),
  'content': _item['content']
  }</p>
  映射接口
  编写好接口后,我们需要将它们映射到相应的 URL。
  <p>api.add_resource(ListApi, '/results')
  api.add_resource(DetailApi, '/results/')</p>
  完整代码
  下面是完整的Flask应用代码,非常简单,实现了文章list和文章details两个功能。接下来,我们将开始开发前端部分。
  <p>import json
  from bson import json_util, ObjectId
  from flask import Flask, jsonify
  from flask_cors import CORS
  from flask_restful import Api, Resource
  from pymongo import MongoClient, DESCENDING
  # 生成Flask App实例
  app = Flask(__name__)
  # 生成MongoDB实例
  mongo = MongoClient(host='192.168.99.100')
  db = mongo['crawlab_test']
  col = db['results']
  # 生成API实例
  api = Api(app)
  # 支持CORS跨域
  CORS(app, supports_credentials=True)
  class ListApi(Resource):
  def get(self):
  # 查询
  items = col.find({}).sort('_id', DESCENDING).limit(20)
  data =
  for item in items:
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  data.append({
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S')
  })
  return data
  class DetailApi(Resource):
  def get(self, id):
  item = col.find_one({'_id': ObjectId(id)})
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  return {
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S'),
  'content': _item['content']
  }
  api.add_resource(ListApi, '/results')
  api.add_resource(DetailApi, '/results/')
  if __name__ == '__main__':
  app.run</p>
  运行 python app.py 运行后台接口服务器。
  Vue
  Vue这几年非常火。它已经在 Github 上超越 React,成为三大开源框架(React、Vue 和 Angular)中 Star 最多的项目。与 React 和 Angular 相比,Vue 非常容易上手。您可以使用双向绑定数据快速开始构建简单的应用程序,也可以使用 Vuex 单向数据传输构建大型应用程序。这种灵活性是它受到大多数开发人员欢迎的原因之一。
  为了构建一个简单的 Vue 应用程序,我们将使用 vue-cli3,一个 Vue 项目的脚手架。首先,我们从 npm 安装脚手架。
  安装 vue-cli3
  <p>yarn add @vue/cli</p>
  如果你还没有安装yarn,执行下面的命令安装。
  <p>npm i -g yarn</p>
  创建项目
  接下来,我们需要使用 vue-cli3 构建一个项目。执行以下命令。
  <p>vue create frontend</p>
  命令行会弹出以下选项,选择默认即可。
  
  <p>? Please pick a preset: (Use arrow keys)
  ❯ default (babel, eslint)
  preset (vue-router, vuex, node-sass, babel, eslint, unit-jest)
  Manually select features </p>
  然后 vue-cli3 将开始准备必要的依赖项来构建项目并生成项目结构。
  此外,我们还需要安装完成其他功能所需的包。
  <p>yarn add axios</p>
  文章列表页面
  在 views 目录中创建一个 List.vue 文件,内容如下。
  <p>
  {{article.title}}
  
  {{article.ts}}
  import axios from 'axios'
  export default {
  name: 'List',
  data {
  return {
  list:
  }
  },
  methods: {
  showArticle (id) {
  this.$router.push(`/${id}`)
  }
  },
  created {
  axios.get('http://localhost:5000/results')
  .then(response => {
  this.list = response.data
  })
  }
  }
  .list {
  display: flex;
  }
  .left {
  flex-basis: 20%;
  }
  .right {
  flex-basis: 20%;
  }
  .article-list {
  text-align: left;
  list-style: none;
  }
  .article-item {
  background: #c3edfb;
  border-radius: 5px;
  padding: 5px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
  }
  .title {
  flex-basis: auto;
  color: #58769d;
  }
  .time {
  font-size: 10px;
  text-align: right;
  flex-basis: 180px;
  }</p>
  其中,ajax与API交互引用axios,这里获取list接口。该布局用于经典的双圣杯布局。methods中的showArticle方法接收到id参数,跳转到详情页。
  文章详情页面
  在views目录下,创建一个Detail.vue文件,输入如下内容。
  <p>{{article.title}}
  import axios from 'axios'
  export default {
  name: 'Detail',
  data {
  return {
  article: {}
  }
  },
  computed: {
  id {
  return this.$route.params.id
  }
  },
  created {
  axios.get(`http://localhost:5000/results/${this.id}`)
  .then(response => {
  this.article = response.data
  })
  }
  }
  .detail {
  display: flex;
  }
  .left {
  flex-basis: 20%;
  }
  .right {
  flex-basis: 20%;
  }
  .center {
  flex-basis: 60%;
  text-align: left;
  }
  .title {
  }</p>
  这个页面也是经典的双圣杯布局,中间占40%。API获取的文章内容输出到content,并通过v-html绑定。其实这里可以做进一步的CSS优化,只是作者太懒了,这个任务留给读者自己去完成。
  添加路线
  编辑 router.js 文件并将其修改为以下内容。
  <p>import Vue from 'vue'
  import Router from 'vue-router'
  import List from './views/List'
  import Detail from './views/Detail'
  Vue.use(Router)
  export default new Router({
  mode: 'hash',
  base: process.env.BASE_URL,
  routes: [
  {
  path: '/',
  name: 'List',
  component: List
  },
  {
  path: '/:id',
  name: 'Detail',
  component: Detail
  }
  ]
  })</p>
  运行前端
  在命令行中输入以下命令,打开:8080可以看到文章的列表。
  <p>npm run serve</p>
  最终效果
  最终聚合平台效果截图如下,可以看到基本样式已经出来了。
  总结
  本文在上一篇文章《教你如何用Crawlab搭建技术文章聚合平台(一)》的基础上,介绍了Flask+Vue的使用方法以及之前抓取的文章数据,搭建一个简单的技术文章聚合平台。使用的技术非常基础。当然,肯定还有很大的优化和改进空间。这是留给读者和大人物的。
  直观:通过网络爬虫采集大数据
  2021-07-02
  网络数据采集是指通过网络爬虫或网站公共API从网站获取数据信息。该方法可以从网页中提取非结构化数据,存储为统一的本地数据文件,并以结构化的方式存储。支持图片、音频、视频等文件或附件的采集,附件可以自动与文本关联。
  在互联网时代,网络爬虫主要为搜索引擎提供最全面、最新的数据。
  本节首先简要介绍网络爬虫的原理和工作流程,然后讨论网络爬虫的爬取策略,最后介绍典型的网络工具。
  网络爬虫的原理
  网络爬虫是根据一定的规则自动爬取网络信息的程序或脚本。
  网络爬虫可以自动采集所有可以访问的页面内容,为搜索引擎和大数据分析提供数据源。从功能上来说,爬虫一般具有数据采集、处理和存储三个功能,如图1所示。
  图1 网络爬虫示意图
  除了供用户阅读的文字信息外,网页还收录一些超链接信息。
  网络爬虫系统正是通过网页中的超链接信息不断获取网络上的其他网页。网络爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL。在爬取网页的过程中,不断地从当前页面中提取新的 URL 并放入队列中,直到满足系统的某些停止条件。
  网络爬虫系统一般会选择一些比较重要的、出度(网页链接出的超链接数)网站较大的URL作为种子URL集。
  网络爬虫系统使用这些种子集作为初始 URL 来开始数据爬取。因为网页中收录链接信息,所以会通过已有网页的URL获取一些新的URL。
  网页之间的指向结构可以看成一片森林,每个种子URL对应的网页就是森林中一棵树的根节点,这样网络爬虫系统就可以按照广度优先搜索算法遍历所有信息或深度优先搜索算法。网页。
  由于深度优先搜索算法可能导致爬虫系统陷入网站内部,不利于搜索距离网站首页比较近的网页信息,因此广度优先搜索算法一般使用采集网页。
  网络爬虫系统首先将种子 URL 放入下载队列,简单地从队列头部取一个 URL 下载其对应的网页,获取网页内容并存储,然后解析链接信息网页以获取一些新的 URL。
  其次,根据一定的网页分析算法,过滤掉与主题无关的链接,保留有用的链接,放入待抓取的URL队列中。
  最后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。
  网络爬虫工作流程
  如图 2 所示,网络爬虫的基本工作流程如下。
  1) 首先选择种子 URL 的一部分。
  2)将这些网址放入待抓取的网址队列中。
  3)从待爬取URL队列中取出待爬取URL,解析DNS,获取主机IP地址,下载该URL对应的网页,存入下载的网页库中。此外,将这些 URL 放入 Crawl URLs 队列。
  4)分析URL队列中已经爬取的URL,分析其中的其他URL,将这些URL放入待爬取的URL队列,从而进入下一个循环。
  图2 网络爬虫基本工作流程
  网络爬虫抓取策略
  谷歌、百度等常见搜索引擎抓取的网页数量通常以数十亿计。那么,面对如此多的网页,网络爬虫如何才能尽可能的遍历所有网页呢?如果您对大数据开发感兴趣,想系统地学习大数据,可以加入大数据技术学习交流群:458号345号782获取学习资源,从而扩大网页信息的覆盖范围可能,这是网络爬虫系统面临的一个非常关键的问题。在网络爬虫系统中,爬取策略决定了网页被爬取的顺序。
  本节首先简要介绍网络爬取策略中使用的基本概念。
  1)网页之间的关系模型
  从互联网的结构来看,网页通过各种超链接相互连接,形成一个巨大而复杂的相互关联的有向图。
  
  如图3所示,如果把网页看成图中的一个节点,把网页中其他网页的链接看成这个节点到其他节点的边,那么我们就可以轻松查看整个互联网网页被建模为有向图。
  理论上,通过遍历算法对图进行遍历,几乎可以访问互联网上的任何网页。
  图3 网页关系模型图
  2)网页分类
  从爬虫的角度来划分互联网,可以将互联网的所有页面分为5个部分:已下载未过期网页、已下载已过期网页、待下载网页、已知网页和未知网页,如图4.
  本地爬取的网页实际上是互联网内容的镜像和备份。互联网正在动态变化。当互联网的一部分内容发生变化时,本地抓取的网页就会失效。因此,下载的网页分为两类:下载的未过期网页和下载的过期网页。
  图4 网页分类
  要下载的页面是 URL 队列中要抓取的页面。
  可以看出,网页是指尚未被爬取且不在待爬取URL队列中的网页,但可以通过分析爬取的页面或待爬取URL对应的页面得到。
  还有一些网页是网络爬虫无法直接爬取下载的,称为不可知网页。
  下面重点介绍几种常见的爬取策略。
  1.万能网络爬虫
  通用网络爬虫也称为全网爬虫。爬取对象从一些种子URL延伸到整个网络,主要针对门户网站搜索引擎和大型网络服务商采集数据。
  为了提高工作效率,一般的网络爬虫都会采用一定的爬取策略。常用的爬取策略有深度优先策略和广度优先策略。
  1) 深度优先策略
  深度优先策略意味着网络爬虫将从起始页面开始,并逐个链接地跟踪它,直到无法再深入为止。
  完成一个爬取分支后,网络爬虫返回上一个链接节点,进一步搜索其他链接。当所有的链接都遍历完后,爬取任务结束。
  这种策略比较适合垂直搜索或者站内搜索,但是在抓取页面内容比较深的网站时会造成巨大的资源浪费。
  以图3为例,遍历的路径为1→2→5→6→3→7→4→8。
  在深度优先策略中,当搜索一个节点时,该节点的子节点和子节点的后继节点都在该节点的兄弟节点之前,深度优先策略在搜索空间中。有时,它会尝试尽可能深入,并且仅在找不到节点的后继节点时才考虑其兄弟节点。
  这样的策略决定了深度优先策略不一定能找到最优解,甚至由于深度的限制而无法找到解。
  如果不加以限制,它将沿着一条路径无限扩展,这将“捕获”成大量数据。一般来说,使用深度优先策略会选择一个合适的深度,然后反复搜索直到找到一个解,这样会降低搜索的效率。因此,当搜索数据量较小时,一般采用深度优先策略。
  2) 广度优先策略
  广度优先策略根据网页内容目录层次的深度对页面进行爬取,较浅的目录层次的页面先爬取。当同一级别的页面被爬取时,爬虫进入下一级继续爬取。
  还是以图3为例,遍历的路径是1→2→3→4→5→6→7→8
  由于广度优先策略是在第 N 层的节点扩展完成后进入第 N+1 层,保证了通过最短路径找到解。
  该策略可以有效控制页面的爬取深度,避免遇到无限深分支时无法结束爬取的问题。易于实现,不需要存储大量的中间节点。缺点是爬到更深的目录级别需要很长时间。页。
  如果搜索的分支太多,即节点的后继节点太多,算法就会耗尽资源,在可用空间中找不到解。
  2.专注于网络爬虫
  聚焦网络爬虫,也称为主题网络爬虫,是选择性地爬取与预定义主题相关的页面的网络爬虫。
  
  1)基于内容评价的爬取策略
  DeBra 将文本相似度的计算方法引入网络爬虫,提出了 Fish Search 算法。
  该算法以用户输入的查询词为主题,将收录查询词的页面视为与该主题相关的页面,其局限性在于无法评估该页面与该主题的相关性。
  Herseovic 对 Fish Search 算法进行了改进,提出了 Shark Search 算法,该算法使用空间向量模型来计算页面和主题之间的相关度。
  通过采用基于连续值计算链接值的方法,我们不仅可以计算出哪些捕获的链接与主题相关,而且可以得到相关性的量化大小。
  2)基于链接结构评估的爬取策略
  与普通文本不同,网页是收录大量结构化信息的半结构化文档。
  网页不是单独存在的。页面中的链接表示页面之间的关系。基于链接结构的搜索策略模式利用这些结构特征来评估页面和链接的重要性,从而确定搜索顺序。其中,PageRank算法就是这种搜索策略模式的代表。
  PageRank算法的基本原理是,如果一个网页被多次引用,它可能是一个重要的网页;如果一个网页没有被多次引用,而是被一个重要网页引用,那么它也可能是一个重要网页。一个网页的重要性同样传递给它所指的网页。
  链接页面的PageRank是通过将某个页面的PageRank除以该页面上存在的前向链接,并将得到的值分别与前向链接所指向的页面的PageRank相加得到。
  如图 5 所示,PageRank 为 100 的页面将其重要性平等地传递给它所引用的两个页面,每个页面获得 50,而 PageRank 为 9 的同一页面将其重要性传递给它所引用的三个页面。页面的每一页都传递一个值 3。
  PageRank 为 53 的页面的值源自引用它的两个页面传递的值。
  ,
  图5 PageRank算法示例
  3)基于强化学习的爬取策略
  Rennie 和 McCallum 将强化学习引入聚焦爬虫,使用贝叶斯分类器根据整个网页文本和链接文本对超链接进行分类,并计算每个链接的重要性以确定链接被访问的顺序。
  4)基于上下文图的爬取策略
  勤勉等人。提出了一种爬取策略,通过构建上下文图来学习网页之间的相关性。该策略可以训练一个机器学习系统,通过该系统可以计算当前页面到相关网页的距离。中的链接具有优先访问权。
  3.增量网络爬虫
  增量网络爬虫是指对下载的网页进行增量更新,只爬取新生成或更改的网页的爬虫。可以在一定程度上保证爬取的页面尽可能的新。
  增量网络爬虫有两个目标:
  为了实现第一个目标,增量网络爬虫需要通过重访网页来更新本地页面集中的页面内容。常用的方法有统一更新法、个体更新法和分类更新法。
  为了实现第二个目标,增量网络爬虫需要对网页的重要性进行排名。常见的策略包括广度优先策略和PageRank优先策略。
  4. 深网爬虫
  网页按存在方式可分为表层网页和深层网页。
  深网爬虫架构由六个基本功能模块(爬取控制器、解析器、表单分析器、表单处理器、响应分析器、LVS控制器)和两个爬虫内部数据结构(URL列表和LVS表)组成。
  其中,LVS(LabelValueSet)表示标签和值的集合,用来表示填写表格的数据源。在爬取过程中,最重要的部分是表单填写,包括基于领域知识的表单填写和基于网页结构分析的表单填写。
  分类:
  技术要点:
  相关文章:

解决方案:Python使用xslt提取网页数据

采集交流优采云 发表了文章 • 0 个评论 • 74 次浏览 • 2022-11-01 14:22 • 来自相关话题

  解决方案:Python使用xslt提取网页数据
  1 简介
  在 Python 网络爬虫内容提取器一文中,我们详细讲解了核心组件:可插拔内容提取器类 gsExtractor。本文记录了在确定gsExtractor技术路线过程中所做的编程实验。这是第一部分,尝试使用xslt方法提取静态网页内容并一次性转换为xml格式。
  2.使用lxml库提取网页内容
  lxml是python的一个库,可以快速灵活地处理XML。它支持 XML 路径语言 (XPath) 和可扩展样式表语言转换 (XSLT),并实现通用的 ElementTree API。
  这2天,我在python中测试了通过xslt提取网页内容,记录如下:
  2.1、抓取目标
  假设要提取jisoke官网老论坛的帖子标题和回复数,如下图,需要提取整个列表并保存为xml格式
  2.2、源码1:只抓取当前页面,结果显示在控制台
  Python的优势在于它可以用少量的代码解决一个问题。请注意,以下代码看起来很长。其实python函数调用的并不多。xslt 脚本占用了很大的空间。在这段代码中,只是一个长字符串。至于为什么选择 xslt 而不是离散的 xpath 或令人头疼的正则表达式,请参考《Python Instant Web Crawler Project Startup Instructions》。我们期望使用这种架构可以将程序员的时间节省一半以上。
  可以复制运行以下代码(windows10下测试,python3.2通过):
  from urllib import request
from lxml import etree
url="http://www.gooseeker.com/cn/forum/7"
conn=request.urlopen(url)
doc = etree.HTML(conn.read())
xslt_root = etree.XML("""\
<p>
""")
transform = etree.XSLT(xslt_root)
result_tree = transform(doc)
print(result_tree)</p>
  源码可以从文末的 GitHub 源码下载。
  2.3、抓取结果
  得到的爬取结果如下:
  2.4、源码2:翻页取取,结果存入文件
  我们对2.2的代码做了进一步的修改,增加了翻页和保存结果文件的功能。代码如下:
  from urllib import request
from lxml import etree
import time
xslt_root = etree.XML("""\
<p>
""")
baseurl="http://www.gooseeker.com/cn/forum/7"
basefilebegin="jsk_bbs_"
basefileend=".xml"
count=1
while (count  查看全部

  解决方案:Python使用xslt提取网页数据
  1 简介
  在 Python 网络爬虫内容提取器一文中,我们详细讲解了核心组件:可插拔内容提取器类 gsExtractor。本文记录了在确定gsExtractor技术路线过程中所做的编程实验。这是第一部分,尝试使用xslt方法提取静态网页内容并一次性转换为xml格式。
  2.使用lxml库提取网页内容
  lxml是python的一个库,可以快速灵活地处理XML。它支持 XML 路径语言 (XPath) 和可扩展样式表语言转换 (XSLT),并实现通用的 ElementTree API。
  这2天,我在python中测试了通过xslt提取网页内容,记录如下:
  2.1、抓取目标
  假设要提取jisoke官网老论坛的帖子标题和回复数,如下图,需要提取整个列表并保存为xml格式
  2.2、源码1:只抓取当前页面,结果显示在控制台
  Python的优势在于它可以用少量的代码解决一个问题。请注意,以下代码看起来很长。其实python函数调用的并不多。xslt 脚本占用了很大的空间。在这段代码中,只是一个长字符串。至于为什么选择 xslt 而不是离散的 xpath 或令人头疼的正则表达式,请参考《Python Instant Web Crawler Project Startup Instructions》。我们期望使用这种架构可以将程序员的时间节省一半以上。
  可以复制运行以下代码(windows10下测试,python3.2通过):
  from urllib import request
from lxml import etree
url="http://www.gooseeker.com/cn/forum/7"
conn=request.urlopen(url)
doc = etree.HTML(conn.read())
xslt_root = etree.XML("""\
<p>
""")
transform = etree.XSLT(xslt_root)
result_tree = transform(doc)
print(result_tree)</p>
  源码可以从文末的 GitHub 源码下载。
  2.3、抓取结果
  得到的爬取结果如下:
  2.4、源码2:翻页取取,结果存入文件
  我们对2.2的代码做了进一步的修改,增加了翻页和保存结果文件的功能。代码如下:
  from urllib import request
from lxml import etree
import time
xslt_root = etree.XML("""\
<p>
""")
baseurl="http://www.gooseeker.com/cn/forum/7"
basefilebegin="jsk_bbs_"
basefileend=".xml"
count=1
while (count 

最新版:轻量级云原生日志收集方案 Loki 中文入门指南

采集交流优采云 发表了文章 • 0 个评论 • 112 次浏览 • 2022-10-31 15:50 • 来自相关话题

  最新版:轻量级云原生日志收集方案 Loki 中文入门指南
  公众号关注“精彩Linux世界”
  把它定为“明星”,带你享受Linux每一天!
  您好,很高兴为您介绍掘金开发者平台上的轻量级kubernetes日志采集解决方案。我自己在生产环境中使用过这个解决方案。令我惊讶的是,与 ELK 方案相比,它在 Kubernetes 中占用的资源确实微不足道。那就跟着这个文章开始学习吧……
  为什么使用 Loki
  本文章重点介绍grafana开发的loki日志采集应用。Loki 是一个轻量级的日志采集和分析应用程序。它使用 promtail 获取日志内容并将其发送到 loki 进行存储。最后在grafana的数据源中添加一个数据源,用于日志展示和查询。
  Loki 的持久化存储支持 azure、gcs、s3、swift、local 5 种类型,其中 s3 和 local 比较常用。此外,它还支持多种类型的日志采集,比如最常用的logstash和fluentbit也在官方支持列表中。
  那么它有哪些优势呢?各个日志采集组件的优势,简单比较按名称安装的组件
  麋鹿/EFK
  弹性搜索、logstash、kibana、filebeat、kafka/redis
  支持自定义grok定期分析复杂日志内容;仪表盘支持丰富的可视化展示
  洛基
  格拉法纳,洛基,promtail
  占地面积小;原生支持 grafana;查询速度快;
  Loki 的工作原理 日志解析格式
  从上图我们可以看出,它在解析日志的时候,主要是基于index。index 包括 pod 的时间戳和部分标签(其他标签是文件名、容器等),剩下的就是日志内容。具体查询效果如下:
  {app="loki",namespace="kube-public"} 是索引。
  日志采集架构模式
  在使用过程中,官方推荐使用promtail作为代理,以DaemonSet方式部署在kubernetes的worker节点上进行日志采集。此外,您还可以使用上面提到的其他日志采集工具进行采集。这个文章最后会附上其他工具的配置方法。
  Loki 部署模式有哪些?
  Loki 是用许多组件微服务构建的,有 5 个微服务组件。在这 5 个中添加缓存,将数据放在一起以加快查询速度。数据放置在共享存储中,并且配置了 memberlist_config 部分,并在实例之间共享状态,从而允许 Loki 无限扩展。配置 memberlist_config 部分后,使用轮询方法查找数据。为了使用方便,官方将所有微服务编译成二进制,可以通过命令行参数-target控制,支持all、read、write。我们可以在部署时根据日志卷的大小指定不同的模式。
  全部(读写模式)
  服务启动后,我们所做的所有数据查询和数据写入都来自这个节点。请参见下图:
  读/写(读写分离模式)
  在读写拆分模式下运行时,前端查询查询将流量转发到读取节点。querier、ruler、fronted在读节点上保留,distributor和ingester在写节点上保留。
  以微服务模式运行
  在微服务模式下,通过不同的配置参数启动不同的角色,每个进程引用其目标角色服务。
  组件名称功能
  分销商/调度器(分销商)
  验证数据合规性;数据排序;哈希一致性;QPS 限制;转发;数据拷贝保证不丢失
  采集器(摄取器)
  时间戳排序;文件系统支持;WAL 预写;
  查询前端
  提供页面操作,向后端存储发送数据查询;query-queueing 可以防止在大容量查询时触发OOM;query-split 可以拆分大批量查询,最后进行数据聚合
  查询者
  使用logql语言查询后端存储中的日志
  缓存
  将查询到的日志缓存起来以备后用,如果数据不全,重新查询丢失的数据
  大显身手的服务器端部署
  
  上面我们已经谈了很多关于 loki 及其工作模式的内容。您还必须预料到它将如何部署,对吧?!关于如何部署,在哪里部署,部署后如何使用的问题,都会浮现在你的脑海中。部署前需要准备一个 k8s 集群。那就好,那就耐心的往下看吧……
  应用图像
  洛基
  格拉法纳/洛基:2.5.0
  促销
  格拉法纳/promtail:2.5.0
  AllInOne部署方式①k8s部署
  我们从github下载的程序没有配置文件,需要提前准备一份文件。此处提供了完整的 allInOne 配置文件,并进行了一些优化。
  配置文件内容如下
  auth_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />target: all<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ballast_bytes: 20480<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />server:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_listen_port: 9095<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_listen_port: 3100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  graceful_shutdown_timeout: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_listen_address: "0.0.0.0"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_listen_network: "tcp"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_server_max_concurrent_streams: 100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_server_max_recv_msg_size: 4194304<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_server_max_send_msg_size: 4194304<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_server_idle_timeout: 2m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_listen_address: "0.0.0.0"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_listen_network: "tcp"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_server_read_timeout: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_server_write_timeout: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_source_ips_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## http_path_prefix如果需要更改,在推送日志的时候前缀都需要加指定的内容<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## http_path_prefix: "/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  register_instrumentation: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_format: json<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_level: info<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />distributor:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_timeout: 3s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: collectors/<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      ## 需要提前创建好consul集群<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##   consul:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     http_client_timeout: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     consistent_reads: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     host: 127.0.0.1:8500<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     watch_burst_size: 2<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     watch_rate_limit: 2<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />querier:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  engine:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_look_back_period: 20s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    timeout: 3m0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  extra_query_delay: 100ms <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_concurrent: 10 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  multi_tenant_queries_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_ingester_only: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_ingesters_within: 3h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_store_only: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_timeout: 5m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  tail_max_duration: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />query_scheduler:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_outstanding_requests_per_tenant: 2048<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_client_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_recv_msg_size: 104857600<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_send_msg_size: 16777216<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    grpc_compression: gzip<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    rate_limit: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    rate_limit_burst: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    backoff_on_ratelimits: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    backoff_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      min_period: 50ms<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_period: 15s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_retries: 5 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  use_scheduler_ring: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  scheduler_ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: "collectors/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_period: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_timeout: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## 默认第一个网卡的名称<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_interface_names<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_addr: 127.0.0.1<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## 默认server.grpc-listen-port<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    instance_port: 9095<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />frontend:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_outstanding_per_tenant: 4096<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  querier_forget_delay: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  compress_responses: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_queries_longer_than: 2m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_body_size: 104857600<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_stats_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  scheduler_dns_lookup_period: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  scheduler_worker_concurrency: 15<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />query_range:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  align_queries_with_step: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  cache_results: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  parallelise_shardable_queries: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_retries: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  results_cache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    cache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      enable_fifocache: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      default_validity: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      background:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        writeback_buffer: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      redis:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        endpoint: 127.0.0.1:6379<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        timeout: 1s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        expiration: 0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        db: 9<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        pool_size: 128 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        password: 1521Qyx6^<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        idle_timeout: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        max_connection_age: 8h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ruler:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  enable_api: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  enable_sharding: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  alertmanager_refresh_interval: 1m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  disable_rule_group_label: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  evaluation_interval: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  flush_period: 3m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  for_grace_period: 20m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  for_outage_tolerance: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  notification_queue_capacity: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  notification_timeout: 4s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  poll_interval: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_stats_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  remote_write:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    config_refresh_period: 10s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  resend_delay: 2m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  rule_path: /rulers<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  search_pending_for: 5m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  storage:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    local:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      directory: /data/loki/rulers<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    type: configdb<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  sharding_strategy: default<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  wal_cleaner:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    period:  240h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    min_age: 12h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  wal:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    dir: /data/loki/ruler_wal<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_age: 4h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    min_age: 5m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    truncate_frequency: 1h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: "collectors/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_period: 5s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_timeout: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_addr: "127.0.0.1"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_id: "miyamoto.en0"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_interface_names: ["en0","lo0"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    instance_port: 9500<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    num_tokens: 100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ingester_client:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  pool_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    health_check_ingesters: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    client_cleanup_period: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    remote_timeout: 3s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  remote_timeout: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ingester:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  autoforget_unhealthy: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_encoding: gzip<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_target_size: 1572864<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_transfer_retries: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  sync_min_utilization: 3.5<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  sync_period: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  flush_check_period: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  flush_op_timeout: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_retain_period: 1m30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_block_size: 262144<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_idle_period: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_returned_stream_errors: 20<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  concurrent_flushes: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  index_shards: 32<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_chunk_age: 2h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_store_max_look_back_period: 3h30m30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  wal:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    dir: /data/loki/wal <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    flush_on_shutdown: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    checkpoint_duration: 15m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    replay_memory_ceiling: 2GB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  lifecycler:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        prefix: "collectors/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      heartbeat_timeout: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      replication_factor: 1<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    num_tokens: 128<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_period: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    join_after: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    observe_period: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## interface_names: ["en0","lo0"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    final_sleep: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    min_ready_duration: 15s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />storage_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  boltdb:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    directory: /data/loki/boltdb <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  boltdb_shipper:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    active_index_directory: /data/loki/active_index<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    build_per_tenant_index: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    cache_location: /data/loki/cache <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    cache_ttl: 48h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    resync_interval: 5m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    query_ready_num_days: 5<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    index_gateway_client:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      grpc_client_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  filesystem:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    directory: /data/loki/chunks<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />chunk_store_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_cache_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_fifocache: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    default_validity: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    background:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      writeback_buffer: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    redis:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      endpoint: 192.168.3.56:6379<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      timeout: 1s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      expiration: 0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      db: 8 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      pool_size: 128 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      password: 1521Qyx6^<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      idle_timeout: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_connection_age: 8h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    fifocache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      ttl: 1h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      validity: 30m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_items: 2000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_bytes: 500MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  write_dedupe_cache_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_fifocache: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    default_validity: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    background:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      writeback_buffer: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    redis:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      endpoint: 127.0.0.1:6379<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      timeout: 1s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      expiration: 0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      db: 7<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      pool_size: 128 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      password: 1521Qyx6^<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      idle_timeout: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_connection_age: 8h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    fifocache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      ttl: 1h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      validity: 30m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_items: 2000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_bytes: 500MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  cache_lookups_older_than: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## 压缩碎片索引<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />compactor:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  shared_store: filesystem<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  shared_store_key_prefix: index/<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  working_directory: /data/loki/compactor<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  compaction_interval: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_delete_delay: 2h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_delete_worker_count: 150<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  delete_request_cancel_period: 24h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_compaction_parallelism: 2<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## compactor_ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />frontend_worker:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  match_max_concurrent: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  parallelism: 10<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  dns_lookup_duration: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## runtime_config 这里没有配置任何信息<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## runtime_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />common:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  storage:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    filesystem:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      chunks_directory: /data/loki/chunks<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      fules_directory: /data/loki/rulers<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  replication_factor: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  persist_tokens: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## instance_interface_names: ["en0","eth0","ens33"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />analytics:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  reporting_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />limits_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ingestion_rate_strategy: global<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ingestion_rate_mb: 100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ingestion_burst_size_mb: 18<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_label_name_length: 2096<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_label_value_length: 2048<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_label_names_per_series: 60<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  enforce_metric_name: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_entries_limit_per_query: 5000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  reject_old_samples: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  reject_old_samples_max_age: 168h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  creation_grace_period: 20m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_global_streams_per_user: 5000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  unordered_writes: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_chunks_per_query: 200000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_length: 721h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_parallelism: 64 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_series: 700<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  cardinality_limit: 100000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_streams_matchers_per_query: 1000 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_concurrent_tail_requests: 10 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_evaluation_delay_duration: 3s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_max_rules_per_rule_group: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_max_rule_groups_per_tenant: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_period: 700h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  per_tenant_override_period: 20s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_cache_freshness_per_query: 2m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_queriers_per_tenant: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  per_stream_rate_limit: 6MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  per_stream_rate_limit_burst: 50MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_lookback: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_remote_write_disabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  min_sharding_lookback: 0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  split_queries_by_interval: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_line_size: 30mb<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_line_size_truncate: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_streams_per_user: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" /><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## memberlist_conig模块配置gossip用于在分发服务器、摄取器和查询器之间发现和连接。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## 所有三个组件的配置都是唯一的,以确保单个共享环。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## 至少定义了1个join_members配置后,将自动为分发服务器、摄取器和ring 配置memberlist类型的kvstore<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />memberlist:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  randomize_node_name: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  stream_timeout: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retransmit_factor: 4<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  join_members:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  - 'loki-memberlist'<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  abort_if_cluster_join_fails: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  advertise_addr: 0.0.0.0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  advertise_port: 7946<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  bind_addr: ["0.0.0.0"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  bind_port: 7946<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  compression_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  dead_node_reclaim_time: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  gossip_interval: 100ms<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  gossip_nodes: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  gossip_to_dead_nodes_time: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## join:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  leave_timeout: 15s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  left_ingesters_timeout: 3m0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_join_backoff: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_join_retries: 5<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  message_history_buffer_bytes: 4096<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  min_join_backoff: 2s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## node_name: miyamoto<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  packet_dial_timeout: 5s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  packet_write_timeout: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  pull_push_interval: 100ms<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  rejoin_interval: 10s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />schema_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  configs:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  - from: "2020-10-24"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    index:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      period: 24h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: index_<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    object_store: filesystem<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    schema: v11<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    store: boltdb-shipper<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    chunks:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      period: 168h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    row_shards: 32<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />table_manager:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_deletes_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_period: 0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  throughput_updates_disabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  poll_interval: 3m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  creation_grace_period: 20m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  index_tables_provisioning:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    provisioned_write_throughput: 1000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    provisioned_read_throughput: 500<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_write_throughput: 4<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_read_throughput: 300<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_write_scale_lastn: 50 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_inactive_throughput_on_demand_mode: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_ondemand_throughput_mode: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_read_scale_lastn: 10 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    查看全部

  最新版:轻量级云原生日志收集方案 Loki 中文入门指南
  公众号关注“精彩Linux世界”
  把它定为“明星”,带你享受Linux每一天!
  您好,很高兴为您介绍掘金开发者平台上的轻量级kubernetes日志采集解决方案。我自己在生产环境中使用过这个解决方案。令我惊讶的是,与 ELK 方案相比,它在 Kubernetes 中占用的资源确实微不足道。那就跟着这个文章开始学习吧……
  为什么使用 Loki
  本文章重点介绍grafana开发的loki日志采集应用。Loki 是一个轻量级的日志采集和分析应用程序。它使用 promtail 获取日志内容并将其发送到 loki 进行存储。最后在grafana的数据源中添加一个数据源,用于日志展示和查询。
  Loki 的持久化存储支持 azure、gcs、s3、swift、local 5 种类型,其中 s3 和 local 比较常用。此外,它还支持多种类型的日志采集,比如最常用的logstash和fluentbit也在官方支持列表中。
  那么它有哪些优势呢?各个日志采集组件的优势,简单比较按名称安装的组件
  麋鹿/EFK
  弹性搜索、logstash、kibana、filebeat、kafka/redis
  支持自定义grok定期分析复杂日志内容;仪表盘支持丰富的可视化展示
  洛基
  格拉法纳,洛基,promtail
  占地面积小;原生支持 grafana;查询速度快;
  Loki 的工作原理 日志解析格式
  从上图我们可以看出,它在解析日志的时候,主要是基于index。index 包括 pod 的时间戳和部分标签(其他标签是文件名、容器等),剩下的就是日志内容。具体查询效果如下:
  {app="loki",namespace="kube-public"} 是索引。
  日志采集架构模式
  在使用过程中,官方推荐使用promtail作为代理,以DaemonSet方式部署在kubernetes的worker节点上进行日志采集。此外,您还可以使用上面提到的其他日志采集工具进行采集。这个文章最后会附上其他工具的配置方法。
  Loki 部署模式有哪些?
  Loki 是用许多组件微服务构建的,有 5 个微服务组件。在这 5 个中添加缓存,将数据放在一起以加快查询速度。数据放置在共享存储中,并且配置了 memberlist_config 部分,并在实例之间共享状态,从而允许 Loki 无限扩展。配置 memberlist_config 部分后,使用轮询方法查找数据。为了使用方便,官方将所有微服务编译成二进制,可以通过命令行参数-target控制,支持all、read、write。我们可以在部署时根据日志卷的大小指定不同的模式。
  全部(读写模式)
  服务启动后,我们所做的所有数据查询和数据写入都来自这个节点。请参见下图:
  读/写(读写分离模式)
  在读写拆分模式下运行时,前端查询查询将流量转发到读取节点。querier、ruler、fronted在读节点上保留,distributor和ingester在写节点上保留。
  以微服务模式运行
  在微服务模式下,通过不同的配置参数启动不同的角色,每个进程引用其目标角色服务。
  组件名称功能
  分销商/调度器(分销商)
  验证数据合规性;数据排序;哈希一致性;QPS 限制;转发;数据拷贝保证不丢失
  采集器(摄取器)
  时间戳排序;文件系统支持;WAL 预写;
  查询前端
  提供页面操作,向后端存储发送数据查询;query-queueing 可以防止在大容量查询时触发OOM;query-split 可以拆分大批量查询,最后进行数据聚合
  查询者
  使用logql语言查询后端存储中的日志
  缓存
  将查询到的日志缓存起来以备后用,如果数据不全,重新查询丢失的数据
  大显身手的服务器端部署
  
  上面我们已经谈了很多关于 loki 及其工作模式的内容。您还必须预料到它将如何部署,对吧?!关于如何部署,在哪里部署,部署后如何使用的问题,都会浮现在你的脑海中。部署前需要准备一个 k8s 集群。那就好,那就耐心的往下看吧……
  应用图像
  洛基
  格拉法纳/洛基:2.5.0
  促销
  格拉法纳/promtail:2.5.0
  AllInOne部署方式①k8s部署
  我们从github下载的程序没有配置文件,需要提前准备一份文件。此处提供了完整的 allInOne 配置文件,并进行了一些优化。
  配置文件内容如下
  auth_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />target: all<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ballast_bytes: 20480<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />server:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_listen_port: 9095<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_listen_port: 3100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  graceful_shutdown_timeout: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_listen_address: "0.0.0.0"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_listen_network: "tcp"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_server_max_concurrent_streams: 100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_server_max_recv_msg_size: 4194304<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_server_max_send_msg_size: 4194304<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_server_idle_timeout: 2m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_listen_address: "0.0.0.0"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_listen_network: "tcp"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_server_read_timeout: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_server_write_timeout: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_source_ips_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## http_path_prefix如果需要更改,在推送日志的时候前缀都需要加指定的内容<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## http_path_prefix: "/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  register_instrumentation: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_format: json<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_level: info<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />distributor:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_timeout: 3s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: collectors/<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      ## 需要提前创建好consul集群<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##   consul:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     http_client_timeout: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     consistent_reads: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     host: 127.0.0.1:8500<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     watch_burst_size: 2<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     watch_rate_limit: 2<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />querier:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  engine:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_look_back_period: 20s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    timeout: 3m0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  extra_query_delay: 100ms <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_concurrent: 10 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  multi_tenant_queries_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_ingester_only: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_ingesters_within: 3h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_store_only: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_timeout: 5m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  tail_max_duration: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />query_scheduler:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_outstanding_requests_per_tenant: 2048<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_client_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_recv_msg_size: 104857600<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_send_msg_size: 16777216<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    grpc_compression: gzip<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    rate_limit: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    rate_limit_burst: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    backoff_on_ratelimits: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    backoff_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      min_period: 50ms<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_period: 15s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_retries: 5 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  use_scheduler_ring: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  scheduler_ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: "collectors/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_period: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_timeout: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## 默认第一个网卡的名称<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_interface_names<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_addr: 127.0.0.1<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## 默认server.grpc-listen-port<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    instance_port: 9095<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />frontend:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_outstanding_per_tenant: 4096<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  querier_forget_delay: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  compress_responses: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_queries_longer_than: 2m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_body_size: 104857600<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_stats_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  scheduler_dns_lookup_period: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  scheduler_worker_concurrency: 15<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />query_range:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  align_queries_with_step: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  cache_results: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  parallelise_shardable_queries: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_retries: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  results_cache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    cache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      enable_fifocache: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      default_validity: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      background:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        writeback_buffer: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      redis:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        endpoint: 127.0.0.1:6379<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        timeout: 1s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        expiration: 0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        db: 9<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        pool_size: 128 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        password: 1521Qyx6^<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        idle_timeout: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        max_connection_age: 8h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ruler:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  enable_api: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  enable_sharding: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  alertmanager_refresh_interval: 1m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  disable_rule_group_label: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  evaluation_interval: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  flush_period: 3m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  for_grace_period: 20m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  for_outage_tolerance: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  notification_queue_capacity: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  notification_timeout: 4s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  poll_interval: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_stats_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  remote_write:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    config_refresh_period: 10s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  resend_delay: 2m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  rule_path: /rulers<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  search_pending_for: 5m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  storage:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    local:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      directory: /data/loki/rulers<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    type: configdb<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  sharding_strategy: default<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  wal_cleaner:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    period:  240h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    min_age: 12h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  wal:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    dir: /data/loki/ruler_wal<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_age: 4h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    min_age: 5m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    truncate_frequency: 1h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: "collectors/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_period: 5s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_timeout: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_addr: "127.0.0.1"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_id: "miyamoto.en0"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_interface_names: ["en0","lo0"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    instance_port: 9500<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    num_tokens: 100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ingester_client:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  pool_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    health_check_ingesters: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    client_cleanup_period: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    remote_timeout: 3s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  remote_timeout: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ingester:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  autoforget_unhealthy: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_encoding: gzip<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_target_size: 1572864<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_transfer_retries: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  sync_min_utilization: 3.5<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  sync_period: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  flush_check_period: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  flush_op_timeout: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_retain_period: 1m30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_block_size: 262144<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_idle_period: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_returned_stream_errors: 20<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  concurrent_flushes: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  index_shards: 32<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_chunk_age: 2h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_store_max_look_back_period: 3h30m30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  wal:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    dir: /data/loki/wal <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    flush_on_shutdown: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    checkpoint_duration: 15m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    replay_memory_ceiling: 2GB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  lifecycler:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        prefix: "collectors/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      heartbeat_timeout: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      replication_factor: 1<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    num_tokens: 128<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_period: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    join_after: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    observe_period: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## interface_names: ["en0","lo0"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    final_sleep: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    min_ready_duration: 15s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />storage_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  boltdb:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    directory: /data/loki/boltdb <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  boltdb_shipper:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    active_index_directory: /data/loki/active_index<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    build_per_tenant_index: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    cache_location: /data/loki/cache <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    cache_ttl: 48h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    resync_interval: 5m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    query_ready_num_days: 5<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    index_gateway_client:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      grpc_client_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  filesystem:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    directory: /data/loki/chunks<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />chunk_store_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_cache_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_fifocache: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    default_validity: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    background:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      writeback_buffer: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    redis:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      endpoint: 192.168.3.56:6379<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      timeout: 1s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      expiration: 0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      db: 8 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      pool_size: 128 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      password: 1521Qyx6^<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      idle_timeout: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_connection_age: 8h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    fifocache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      ttl: 1h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      validity: 30m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_items: 2000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_bytes: 500MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  write_dedupe_cache_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_fifocache: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    default_validity: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    background:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      writeback_buffer: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    redis:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      endpoint: 127.0.0.1:6379<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      timeout: 1s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      expiration: 0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      db: 7<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      pool_size: 128 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      password: 1521Qyx6^<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      idle_timeout: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_connection_age: 8h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    fifocache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      ttl: 1h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      validity: 30m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_items: 2000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_bytes: 500MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  cache_lookups_older_than: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## 压缩碎片索引<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />compactor:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  shared_store: filesystem<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  shared_store_key_prefix: index/<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  working_directory: /data/loki/compactor<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  compaction_interval: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_delete_delay: 2h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_delete_worker_count: 150<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  delete_request_cancel_period: 24h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_compaction_parallelism: 2<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## compactor_ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />frontend_worker:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  match_max_concurrent: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  parallelism: 10<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  dns_lookup_duration: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## runtime_config 这里没有配置任何信息<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## runtime_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />common:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  storage:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    filesystem:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      chunks_directory: /data/loki/chunks<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      fules_directory: /data/loki/rulers<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  replication_factor: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  persist_tokens: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## instance_interface_names: ["en0","eth0","ens33"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />analytics:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  reporting_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />limits_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ingestion_rate_strategy: global<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ingestion_rate_mb: 100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ingestion_burst_size_mb: 18<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_label_name_length: 2096<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_label_value_length: 2048<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_label_names_per_series: 60<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  enforce_metric_name: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_entries_limit_per_query: 5000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  reject_old_samples: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  reject_old_samples_max_age: 168h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  creation_grace_period: 20m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_global_streams_per_user: 5000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  unordered_writes: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_chunks_per_query: 200000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_length: 721h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_parallelism: 64 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_series: 700<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  cardinality_limit: 100000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_streams_matchers_per_query: 1000 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_concurrent_tail_requests: 10 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_evaluation_delay_duration: 3s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_max_rules_per_rule_group: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_max_rule_groups_per_tenant: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_period: 700h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  per_tenant_override_period: 20s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_cache_freshness_per_query: 2m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_queriers_per_tenant: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  per_stream_rate_limit: 6MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  per_stream_rate_limit_burst: 50MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_lookback: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_remote_write_disabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  min_sharding_lookback: 0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  split_queries_by_interval: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_line_size: 30mb<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_line_size_truncate: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_streams_per_user: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" /><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## memberlist_conig模块配置gossip用于在分发服务器、摄取器和查询器之间发现和连接。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## 所有三个组件的配置都是唯一的,以确保单个共享环。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## 至少定义了1个join_members配置后,将自动为分发服务器、摄取器和ring 配置memberlist类型的kvstore<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />memberlist:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  randomize_node_name: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  stream_timeout: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retransmit_factor: 4<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  join_members:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  - 'loki-memberlist'<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  abort_if_cluster_join_fails: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  advertise_addr: 0.0.0.0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  advertise_port: 7946<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  bind_addr: ["0.0.0.0"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  bind_port: 7946<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  compression_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  dead_node_reclaim_time: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  gossip_interval: 100ms<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  gossip_nodes: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  gossip_to_dead_nodes_time: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## join:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  leave_timeout: 15s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  left_ingesters_timeout: 3m0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_join_backoff: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_join_retries: 5<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  message_history_buffer_bytes: 4096<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  min_join_backoff: 2s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## node_name: miyamoto<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  packet_dial_timeout: 5s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  packet_write_timeout: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  pull_push_interval: 100ms<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  rejoin_interval: 10s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />schema_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  configs:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  - from: "2020-10-24"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    index:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      period: 24h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: index_<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    object_store: filesystem<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    schema: v11<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    store: boltdb-shipper<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    chunks:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      period: 168h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    row_shards: 32<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />table_manager:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_deletes_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_period: 0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  throughput_updates_disabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  poll_interval: 3m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  creation_grace_period: 20m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  index_tables_provisioning:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    provisioned_write_throughput: 1000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    provisioned_read_throughput: 500<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_write_throughput: 4<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_read_throughput: 300<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_write_scale_lastn: 50 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_inactive_throughput_on_demand_mode: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_ondemand_throughput_mode: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_read_scale_lastn: 10 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />   

分享:可能吧的文章是如何排版的?

采集交流优采云 发表了文章 • 0 个评论 • 55 次浏览 • 2022-10-31 15:49 • 来自相关话题

  分享:可能吧的文章是如何排版的?
  Achan Jason Ng
  阅读这篇文章
  大约
  6 分钟
  我发现不管我写了哪篇文章文章,读者总是会在评论区问我用什么编辑器来排版我的文章,我的回答是,市面上的微信排版器我两者都不要使用,不是因为它们设计不好,而是因为所有排字机都不符合书写规则。
  这个 文章 会告诉你我的 文章 是如何排版的。
  1
  排版不仅仅是锦上添花
  我在 2006 年开始写博客,我相信内容是核心,排版并不重要。但在阅读了 2008 年有关屏幕阅读体验的一些研究后,我开始关注排版,并开始在我的博客上尝试不同的排版。我不能说我的排版是最好看的,但是在一个小圈子里,它被注意到了。如果你在 Google 上搜索“也许排版”,你会发现很多 文章 人都在研究我当时是如何打字的。
  好的排版不仅赏心悦目,更重要的是,我们可以适当调整排版,使内容的呈现符合用户在屏幕上的阅读习惯。
  我在“可能学院”开设了讲座课程“微信内容运营”。在本课程中,我定义了一个新职位:内容管理员。
  产品经理关注用户需求,根据用户需求开发功能。产品经理不是什么都专精,但是什么都懂一点。内容管理者不再是传统意义上的记者或编辑,而是专注于内容生产管道之上的角色。他们根据读者的需求制作内容。他们似乎对所有事情都不专业,但他们对所有事情都了解一点。
  注意上面提到的“生产”二字。在关注读者需求的时代,内容不是单纯的写作,而是“生产”。在“制作”的过程中,阅读体验和阅读习惯是内容管理者必须关心的环节。它们不是锦上添花,而是整个内容生产线中不可或缺的一部分。
  2
  写作规则是什么?
  我的文章一般比较长,比如""有8000多个字符,""有6000多个字符。这些文章都是一口气写完的,前者我写了5个小时左右,后者4个小时。
  但是,写作的时间并不是主要的,主要的时间都花在了材料的采集上。比如写这篇文章文章之前,我既阅读了微信公众平台的API文档,也阅读了Google PWA文档,在谷歌采集了很多资料,最后才开始写。
  把所有的材料采集起来放在脑海里后,我开始闭关写作。
  写作是一口气完成的。
  意思是我采集了足够的材料,把自己放在别人不能打扰的空间里,比如家,比如咖啡店,比如酒店,从第一个字到最后一个字,放文章完毕。
  我尝试写了太多次文章,但我并不满意,因为它使文章 在情感上不连贯。比如今天觉得支付宝脑子进了屎,就写了半篇文章,第二天可能觉得还行,他们就下水了。这样一来,文章前后的情绪就会不一致。这样的 文章 会让读者感到困惑。
  所以,我习惯性地一口气写一个文章。相信大部分作家也有这样的习惯。
  3
  为什么我不用微信排版?
  微信公众平台的编辑功能确实很弱,使用其默认功能很难做出优秀的排版。所以很多公司都开发了微信排字机。
  几乎所有的微信排版机,页面结构类似于下面的排版机:
  用户选择左侧的内容类型,然后选择样式,编辑器中会出现收录该样式的卡片,然后用户将在卡片中填充内容。
  我不使用任何排版机的原因包括:
  容易撞衫:你使用的款式也会被其他公众号使用,没有什么特别之处。
  
  不够精致:大部分排字机的样式,从颜色的使用、行距、字体大小等,都没有特别精心设计。
  不遵守写作规则
  第3点是重点。
  写作是一个一站式的过程,但大多数微信排版人人为地拆分了一站式过程。本来,你写完字幕,就应该马上把内容打出来,但是在这些排字机里,你需要先选择一个模板,然后在模板里填写内容。你必须打断你的写作,把你的手从键盘移到鼠标上,然后再移回来。
  对我来说,体验很糟糕。
  有人可能会说,你可以先写在平板上,然后在排版器中逐个部分粘贴,这样就可以一口气写完,然后“专心”排版?
  想想看,《不要开发应用程序》的文章文章文章有8000字,10到20个二级标题和三级标题,我需要多少努力才能完成排版?
  对我来说,体验仍然很糟糕。
  4
  文章 怎么可能是排版的?
  昨天,一个可能性学院的学生问我每次写文章都花多少时间排版。我的回答是,快时 1 秒,但一般是 10-20 秒。
  这就是我写作和排版的方式。
  4.1
  开始在安静的编辑器中输入
  在 Mac 和 iPhone 上,我都买了 Ulysses,我认为它是最好的书写工具,因为它足够安静:
  如上图所示,我经常全屏写,文章 一口气写完。
  4.2
  使用降价
  Markdown 是专为作家设计的排版语言。它不是一种编程语言。学习 Markdown 通常只需要 5-10 分钟。
  使用 Markdown 的好处是,当您需要输入文本时,您无需将手从键盘上移开。比如需要写二级标题,在正文前面加两个#号,三级标题后面加三个#号。要使文本变为粗体,请在文本的两侧添加两个星号。
  就像上图一样简单。
  你可以在 Google 上轻松找到各种 Markdown 教程,相信我,只需 5-10 分钟即可学会。
  4.3
  书写文章的一键排版
  使用 Markdown 和 Ulysses 编写的好处是完成后的 文章 可以直接输出为 HTML 格式。所以我写了一个脚本,用我的排版样式批量替换 HTML 中的标签。整个过程在1秒内完成。
  例如,我会把段落标记
  批量替换为字体大小为 15px、字距为 1px、行距为 28px 的文本。
  再举个例子,我自己定义了标记,批量替换时,这个标题会被替换为文章顶部的阅读时间块。
  对我来说,写作必须一口气完成,排版不能打断写作。在流水线上,排版是在写作之后。
  4.4
  将排版文章粘贴到微信编辑器中
  
  一键替换后,文章仍然是HTML格式。如果在浏览器中打开,全选复制粘贴到微信编辑器中,可能会出现样式混乱。
  我的做法是复制HTML文件的源码,将源码粘贴到​​在线CKEditor编辑器中,然后复制到微信编辑器中,这样样式就不会乱了。
  5
  问题是,如何一键排版?
  没做过个人主页或者没有技术背景的人看之前的排版流程,可能会有些迷茫。其实不难,我不是技术出身,也不是设计师出身,所有的设计排版代码都是通过google学习和尝试的。
  如果你根本不懂 HTML 和 CSS,你有两种选择:
  5.1
  选一个
  这是最好的选择。
  从公司找一位设计师为您设计一种或多种排版样式。
  找公司的前端工程师帮你把这些设计好的样式写成HTML和CSS。需要注意的是,微信并不支持所有的 CSS 代码。
  还在找这个前端工程师,让他帮你写个脚本,批量替换纯HTML为排版样式。‍
  5.2
  选项二
  这是我的路径,你可以参考一下。
  花半天时间学习 HTML 标记。
  花 2 天时间学习常见的 CSS 标签。
  在公众号后台写一篇文章文章,发给自己预览,在电脑上用Chrome打开。
  打开 Chrome 的开发者工具,找到你要调整的元素,写下你学过的 CSS 标记,调整到你觉得好看为止。
  记下要替换的样式 H2、H3、P 和其他标签。
  花 1 天时间学习如何编写一个收录替换函数的简单 Python 脚本。
  将要替换的元素写入此 Python 脚本。
  一键排版。
  不要被这 8 个“复杂”的步骤吓倒。在电脑上调试样式时,浏览器不会崩溃或死机。关键是多尝试,用谷歌查找学习资料和解决方案。
  6
  不要依赖模板化的教程
  以上是我的布局方法。
  我不会在这个文章中,也不会在以后的文章中告诉你,应该取多少字号,用什么颜色,行距应该多高。
  其实网上很容易找到各种(微信)排版教程,告诉你应该使用16px的字体大小,#888的字体颜色,1.2 rem的行距等。
  不要把这些教程当作铁律。如果有人告诉你 16px 字号最适合微信排版,请不要相信。所有基于模板的教程都是教学示例。好在你按照这些例子,会得到很多启发,但是不要照搬,因为不同的公众号,不同的内容类型对排版的要求是不一样的。的。
  关键是要多尝试。谷歌是我们尝试一切的好帮手。还有,不管你怎么试,电脑都不会坏,你还怕什么?
  顺便说一句,关于“不要开发应用程序”的话题,我们邀请了在微信公众号中做得很好的Yoli,与可能性学院分享。点击阅读原文报名本次分享。
  干货内容:公众号原创文章效果放大10倍的秘诀,茅塞顿开!(马上实操)
  这些爆文也很容易找到,这些平台都会展示出来。排名靠前的 文章 都是具有 100,000 个读数的 爆文。如果您正在寻找一个类别,请选择相应的类别。比如你是年轻女性,时尚娱乐八卦文章都可以选择。
  找到文章后,把爆文的标题复制到搜狗微信搜索中搜索,就可以找到所有发布过这个文章的公众号,而这些号也是你的目标,它们是都有这个需要。
  按照上面的方法,找到大量的账目,做个表格做汇总。然后进行第二步。
  2 账户初步筛选
  在找到大量目标账户并制作表格后,需要进行初步筛选,以免磨刀时误伤木工。这一步是必要的。
  我们需要找到一些属性真正匹配、阅读量不错、质量相对较高的账号。关键是他们确实经常转载​​文章。
  可以使用微信、新帮、西瓜助手、青博等分析工具查看他们的历史文章阅读量,并对公众号文章的发布情况做一个简单的观察,看看是否有转载足够大。
  然后移除一些不符合标准的公众号,留下确定为主动授权的公众号。
  3 批量开启白名单
  经过简单的筛选,他们开始主动将这些公众号加入白名单。
  前期需要一个个添加公众号给他们授权文章,但是授权一次后,可以直接全选,一键批量授权。
  一次100,一次100,直接一天500,真的是授权狂人。
  
  在这个阶段,还需要注意的是所有的操作也需要同步表,哪些号码被授权,什么时候被授权,都需要收录在表中。
  4 统计
  定期统计这些主动授权的公众号是否转载了你的文章,一定要做好统计,否则会失明。
  您可以在公众号原创文章的管理中查看转载详情,统计文章对应的公众号有哪些转载。如下:
  这是必须要做的,没有统计数据就无法进行下一步的优化。我们要的不是数据,而是数据背后的结果。
  5 用操作思维优化筛选
  我们需要用操作的思维来做这件事,包括上一步的每一步的表统计,以便更好的放大授权效果。
  仅对已找到的目标账户进行直接授权是不够的。我们需要在后期继续优化和过滤。例如:
  哪些账户运作良好,哪些账户运作不佳;
  一周中的什么时间最适合全天授权;
  一天之内,授权在什么时候总体上运作良好;
  这些必须有意识地进行测试,在一周的不同时间刻意授权,在一天中的不同时间刻意授权,看看效果如何变化。
  统计所有运营数据,然后通过对比分析,找到最佳授权时间,找到最佳授权类型,筛选出效果最好的公众号,删除几乎没用的账号。补新一批号,以此类推,不断放大授权效果。
  这里还有一点,我们在操作公众号的时候一定要有数据思维,不需要很复杂的分析,但是一定要知道你操作前后关键指标有没有变化,否则我们会盲目操作,走运。
  
  另外,对于效果特别好的目标账号,还可以拉群或者加编辑到微信中,进行长线推送。
  总的来说,就是不断优化,循环运行。
  以上就是变身狂魔的正确姿势。
  有一瞬间,我犹豫要不要和你分享。
  但我很快就清醒过来了,当然我必须把它写出来,因为我知道我没有分享它,这不是我的风格,也不是我一直在谈论的想法。
  反正只要你想看,我感觉我还是可以写的。
  想起老罗在发布会上说的一句话:感觉自己的精神状态还是可以用一百年来形容的。
  我没有那么大的感觉。
  只要,
  一点点触动。
  木木老贼(公众号:mumuseo)
  这是一个无所不谈的营销运营公众号,新鲜有趣,信息量大。多一些真诚,少一些套路,给在理想道路上努力奋斗的营销人员更多的燃料。 查看全部

  分享:可能吧的文章是如何排版的?
  Achan Jason Ng
  阅读这篇文章
  大约
  6 分钟
  我发现不管我写了哪篇文章文章,读者总是会在评论区问我用什么编辑器来排版我的文章,我的回答是,市面上的微信排版器我两者都不要使用,不是因为它们设计不好,而是因为所有排字机都不符合书写规则。
  这个 文章 会告诉你我的 文章 是如何排版的。
  1
  排版不仅仅是锦上添花
  我在 2006 年开始写博客,我相信内容是核心,排版并不重要。但在阅读了 2008 年有关屏幕阅读体验的一些研究后,我开始关注排版,并开始在我的博客上尝试不同的排版。我不能说我的排版是最好看的,但是在一个小圈子里,它被注意到了。如果你在 Google 上搜索“也许排版”,你会发现很多 文章 人都在研究我当时是如何打字的。
  好的排版不仅赏心悦目,更重要的是,我们可以适当调整排版,使内容的呈现符合用户在屏幕上的阅读习惯。
  我在“可能学院”开设了讲座课程“微信内容运营”。在本课程中,我定义了一个新职位:内容管理员。
  产品经理关注用户需求,根据用户需求开发功能。产品经理不是什么都专精,但是什么都懂一点。内容管理者不再是传统意义上的记者或编辑,而是专注于内容生产管道之上的角色。他们根据读者的需求制作内容。他们似乎对所有事情都不专业,但他们对所有事情都了解一点。
  注意上面提到的“生产”二字。在关注读者需求的时代,内容不是单纯的写作,而是“生产”。在“制作”的过程中,阅读体验和阅读习惯是内容管理者必须关心的环节。它们不是锦上添花,而是整个内容生产线中不可或缺的一部分。
  2
  写作规则是什么?
  我的文章一般比较长,比如""有8000多个字符,""有6000多个字符。这些文章都是一口气写完的,前者我写了5个小时左右,后者4个小时。
  但是,写作的时间并不是主要的,主要的时间都花在了材料的采集上。比如写这篇文章文章之前,我既阅读了微信公众平台的API文档,也阅读了Google PWA文档,在谷歌采集了很多资料,最后才开始写。
  把所有的材料采集起来放在脑海里后,我开始闭关写作。
  写作是一口气完成的。
  意思是我采集了足够的材料,把自己放在别人不能打扰的空间里,比如家,比如咖啡店,比如酒店,从第一个字到最后一个字,放文章完毕。
  我尝试写了太多次文章,但我并不满意,因为它使文章 在情感上不连贯。比如今天觉得支付宝脑子进了屎,就写了半篇文章,第二天可能觉得还行,他们就下水了。这样一来,文章前后的情绪就会不一致。这样的 文章 会让读者感到困惑。
  所以,我习惯性地一口气写一个文章。相信大部分作家也有这样的习惯。
  3
  为什么我不用微信排版?
  微信公众平台的编辑功能确实很弱,使用其默认功能很难做出优秀的排版。所以很多公司都开发了微信排字机。
  几乎所有的微信排版机,页面结构类似于下面的排版机:
  用户选择左侧的内容类型,然后选择样式,编辑器中会出现收录该样式的卡片,然后用户将在卡片中填充内容。
  我不使用任何排版机的原因包括:
  容易撞衫:你使用的款式也会被其他公众号使用,没有什么特别之处。
  
  不够精致:大部分排字机的样式,从颜色的使用、行距、字体大小等,都没有特别精心设计。
  不遵守写作规则
  第3点是重点。
  写作是一个一站式的过程,但大多数微信排版人人为地拆分了一站式过程。本来,你写完字幕,就应该马上把内容打出来,但是在这些排字机里,你需要先选择一个模板,然后在模板里填写内容。你必须打断你的写作,把你的手从键盘移到鼠标上,然后再移回来。
  对我来说,体验很糟糕。
  有人可能会说,你可以先写在平板上,然后在排版器中逐个部分粘贴,这样就可以一口气写完,然后“专心”排版?
  想想看,《不要开发应用程序》的文章文章文章有8000字,10到20个二级标题和三级标题,我需要多少努力才能完成排版?
  对我来说,体验仍然很糟糕。
  4
  文章 怎么可能是排版的?
  昨天,一个可能性学院的学生问我每次写文章都花多少时间排版。我的回答是,快时 1 秒,但一般是 10-20 秒。
  这就是我写作和排版的方式。
  4.1
  开始在安静的编辑器中输入
  在 Mac 和 iPhone 上,我都买了 Ulysses,我认为它是最好的书写工具,因为它足够安静:
  如上图所示,我经常全屏写,文章 一口气写完。
  4.2
  使用降价
  Markdown 是专为作家设计的排版语言。它不是一种编程语言。学习 Markdown 通常只需要 5-10 分钟。
  使用 Markdown 的好处是,当您需要输入文本时,您无需将手从键盘上移开。比如需要写二级标题,在正文前面加两个#号,三级标题后面加三个#号。要使文本变为粗体,请在文本的两侧添加两个星号。
  就像上图一样简单。
  你可以在 Google 上轻松找到各种 Markdown 教程,相信我,只需 5-10 分钟即可学会。
  4.3
  书写文章的一键排版
  使用 Markdown 和 Ulysses 编写的好处是完成后的 文章 可以直接输出为 HTML 格式。所以我写了一个脚本,用我的排版样式批量替换 HTML 中的标签。整个过程在1秒内完成。
  例如,我会把段落标记
  批量替换为字体大小为 15px、字距为 1px、行距为 28px 的文本。
  再举个例子,我自己定义了标记,批量替换时,这个标题会被替换为文章顶部的阅读时间块。
  对我来说,写作必须一口气完成,排版不能打断写作。在流水线上,排版是在写作之后。
  4.4
  将排版文章粘贴到微信编辑器中
  
  一键替换后,文章仍然是HTML格式。如果在浏览器中打开,全选复制粘贴到微信编辑器中,可能会出现样式混乱。
  我的做法是复制HTML文件的源码,将源码粘贴到​​在线CKEditor编辑器中,然后复制到微信编辑器中,这样样式就不会乱了。
  5
  问题是,如何一键排版?
  没做过个人主页或者没有技术背景的人看之前的排版流程,可能会有些迷茫。其实不难,我不是技术出身,也不是设计师出身,所有的设计排版代码都是通过google学习和尝试的。
  如果你根本不懂 HTML 和 CSS,你有两种选择:
  5.1
  选一个
  这是最好的选择。
  从公司找一位设计师为您设计一种或多种排版样式。
  找公司的前端工程师帮你把这些设计好的样式写成HTML和CSS。需要注意的是,微信并不支持所有的 CSS 代码。
  还在找这个前端工程师,让他帮你写个脚本,批量替换纯HTML为排版样式。‍
  5.2
  选项二
  这是我的路径,你可以参考一下。
  花半天时间学习 HTML 标记。
  花 2 天时间学习常见的 CSS 标签。
  在公众号后台写一篇文章文章,发给自己预览,在电脑上用Chrome打开。
  打开 Chrome 的开发者工具,找到你要调整的元素,写下你学过的 CSS 标记,调整到你觉得好看为止。
  记下要替换的样式 H2、H3、P 和其他标签。
  花 1 天时间学习如何编写一个收录替换函数的简单 Python 脚本。
  将要替换的元素写入此 Python 脚本。
  一键排版。
  不要被这 8 个“复杂”的步骤吓倒。在电脑上调试样式时,浏览器不会崩溃或死机。关键是多尝试,用谷歌查找学习资料和解决方案。
  6
  不要依赖模板化的教程
  以上是我的布局方法。
  我不会在这个文章中,也不会在以后的文章中告诉你,应该取多少字号,用什么颜色,行距应该多高。
  其实网上很容易找到各种(微信)排版教程,告诉你应该使用16px的字体大小,#888的字体颜色,1.2 rem的行距等。
  不要把这些教程当作铁律。如果有人告诉你 16px 字号最适合微信排版,请不要相信。所有基于模板的教程都是教学示例。好在你按照这些例子,会得到很多启发,但是不要照搬,因为不同的公众号,不同的内容类型对排版的要求是不一样的。的。
  关键是要多尝试。谷歌是我们尝试一切的好帮手。还有,不管你怎么试,电脑都不会坏,你还怕什么?
  顺便说一句,关于“不要开发应用程序”的话题,我们邀请了在微信公众号中做得很好的Yoli,与可能性学院分享。点击阅读原文报名本次分享。
  干货内容:公众号原创文章效果放大10倍的秘诀,茅塞顿开!(马上实操)
  这些爆文也很容易找到,这些平台都会展示出来。排名靠前的 文章 都是具有 100,000 个读数的 爆文。如果您正在寻找一个类别,请选择相应的类别。比如你是年轻女性,时尚娱乐八卦文章都可以选择。
  找到文章后,把爆文的标题复制到搜狗微信搜索中搜索,就可以找到所有发布过这个文章的公众号,而这些号也是你的目标,它们是都有这个需要。
  按照上面的方法,找到大量的账目,做个表格做汇总。然后进行第二步。
  2 账户初步筛选
  在找到大量目标账户并制作表格后,需要进行初步筛选,以免磨刀时误伤木工。这一步是必要的。
  我们需要找到一些属性真正匹配、阅读量不错、质量相对较高的账号。关键是他们确实经常转载​​文章。
  可以使用微信、新帮、西瓜助手、青博等分析工具查看他们的历史文章阅读量,并对公众号文章的发布情况做一个简单的观察,看看是否有转载足够大。
  然后移除一些不符合标准的公众号,留下确定为主动授权的公众号。
  3 批量开启白名单
  经过简单的筛选,他们开始主动将这些公众号加入白名单。
  前期需要一个个添加公众号给他们授权文章,但是授权一次后,可以直接全选,一键批量授权。
  一次100,一次100,直接一天500,真的是授权狂人。
  
  在这个阶段,还需要注意的是所有的操作也需要同步表,哪些号码被授权,什么时候被授权,都需要收录在表中。
  4 统计
  定期统计这些主动授权的公众号是否转载了你的文章,一定要做好统计,否则会失明。
  您可以在公众号原创文章的管理中查看转载详情,统计文章对应的公众号有哪些转载。如下:
  这是必须要做的,没有统计数据就无法进行下一步的优化。我们要的不是数据,而是数据背后的结果。
  5 用操作思维优化筛选
  我们需要用操作的思维来做这件事,包括上一步的每一步的表统计,以便更好的放大授权效果。
  仅对已找到的目标账户进行直接授权是不够的。我们需要在后期继续优化和过滤。例如:
  哪些账户运作良好,哪些账户运作不佳;
  一周中的什么时间最适合全天授权;
  一天之内,授权在什么时候总体上运作良好;
  这些必须有意识地进行测试,在一周的不同时间刻意授权,在一天中的不同时间刻意授权,看看效果如何变化。
  统计所有运营数据,然后通过对比分析,找到最佳授权时间,找到最佳授权类型,筛选出效果最好的公众号,删除几乎没用的账号。补新一批号,以此类推,不断放大授权效果。
  这里还有一点,我们在操作公众号的时候一定要有数据思维,不需要很复杂的分析,但是一定要知道你操作前后关键指标有没有变化,否则我们会盲目操作,走运。
  
  另外,对于效果特别好的目标账号,还可以拉群或者加编辑到微信中,进行长线推送。
  总的来说,就是不断优化,循环运行。
  以上就是变身狂魔的正确姿势。
  有一瞬间,我犹豫要不要和你分享。
  但我很快就清醒过来了,当然我必须把它写出来,因为我知道我没有分享它,这不是我的风格,也不是我一直在谈论的想法。
  反正只要你想看,我感觉我还是可以写的。
  想起老罗在发布会上说的一句话:感觉自己的精神状态还是可以用一百年来形容的。
  我没有那么大的感觉。
  只要,
  一点点触动。
  木木老贼(公众号:mumuseo)
  这是一个无所不谈的营销运营公众号,新鲜有趣,信息量大。多一些真诚,少一些套路,给在理想道路上努力奋斗的营销人员更多的燃料。

经验:我所读过的最好的一篇分布式技术文章

采集交流优采云 发表了文章 • 0 个评论 • 63 次浏览 • 2022-10-31 15:48 • 来自相关话题

  经验:我所读过的最好的一篇分布式技术文章
  (点击上方公众号快速关注)。
  资料来源:foreach_break,
  前言
  这是一份学习笔记。
  该材料来自Jay Kreps关于Log的博客文章。
  原文很长,但我坚持阅读,收获颇丰,对 Jay 的技术能力、架构能力和对分布式系统的深刻理解印象深刻。同时,他有点沾沾自喜,因为他的一些理解与周杰伦的观点相吻合。
  Jay Kreps是LinkedIn的前首席参谋工程师,现在是Confluent的联合创始人兼首席执行官,也是Kafka和Samza的主要作者。
  所谓笔记,就是读文章做笔记,因为周杰伦哥自己在这一章里组织得太好了,他自己的科学素养和哲学素养也很高,所以他认为突出的也不会省略。
  一、来源
  日志:每个软件工程师都应该知道的关于实时数据的统一抽象()
  二、注意事项
  2.1 日志的值
  1)日志是以下系统的核心:
  2)日志可能与计算机一样古老,是分布式数据系统和实时计算系统的核心。
  3)日志有很多名称:
  4)不了解日志就无法完全理解日志
  2.2 什么是日志?
  2.2.1 概述
  记录的顺序定义了这样一个概念:时间。
  因为离记录越远,记录得越早。
  的概念
  条目的序列号可以用作时间戳,记录顺序作为时间的概念可能看起来很奇怪,但您很快就会发现,将“时间”与任何特定的物理时钟分离很容易。
  日志与普通文件和表没有太大区别。
  这样,你可能会觉得日志这么简单,还有需要讨论的吗?
  其实日志的核心含义是:
  日志记录发生了什么以及何时发生。
  而这个通常是分布式系统最核心的东西。
  请注意,这里有必要澄清几个概念:
  2.2.2 数据库中的日志
  Log的起源未知,就像发明二进制搜索的人一样,很难意识到这项发明是一项发明。
  日志记录早在IBM的System R中就出现了。
  在数据库中,您需要在数据库崩溃时保持不同的数据结构和索引同步。
  为了确保原子性和持久性,数据库需要在提交对数据结构和索引的更改之前记录要修改的内容。
  因此,日志记录了何时发生的情况,每个表和索引本身就是此历史信息的映射。
  由于日志会立即持久化,因此它们成为在发生崩溃时还原其他持久性结构的可靠来源。
  日志已从 ACID 特征的实现演变为数据库之间的数据复制方式。
  显然,数据库中发生的一系列数据更改成为保持数据库之间同步的最需要的信息。
  Oracle,MySQL和PostgreSQL都收录一个日志传输协议,该协议将日志的一部分发送到用于维护复制的从属数据库。
  Oracle的XStreams和GoldenState使用日志作为通用数据订阅机制来提供非Oracle数据库订阅数据。
  MySQL和PostgreSQL提供了类似的组件,这些组件是数据系统架构的核心。
  面向机器的日志不仅可以用于数据库,还可以用于:
  2.2.3 分布式系统中的日志
  日志解决了分布式数据系统中的两个重要问题:
  1) 有序数据更改
  2) 数据分发
  所谓的状态机复制原理
  如果两个确定性过程(以相同的状态和相同的顺序开始)接收相同的输入,则它们将产生相同的输出并以相同的状态结束。
  这
  所谓确定性是指处理过程与时间无关,其处理结果不受额外输入的影响。
  可以通过非确定性示例来理解:
  所谓状态可以是机器上的任何数据,无论是在机器的内存中还是经过处理后的磁盘上。值得注意的是,相同的
  输入以相同的顺序产生相同的结果,这就是为什么日志如此重要的原因,这是一个直观的概念:如果你将相同的日志输入两个确定性程序,它们将产生相同的输出。
  在分布式系统的构建中,意识到这一点可以:
  让所有机器都做同样的事情,协议是:
  构建分布式、一致的日志系统,为所有处理系统提供输入。
  日志系统的作用是消除所有输入流的不确定性,并确保处理相同输入的所有复制节点保持同步。
  此方法的最佳部分是,您可以将索引日志的时间戳视为所有复制节点的时钟:通过使用复制节点处理的日志
  中最大的时间戳作为复制节点的唯一 ID,时间戳与日志相结合可以唯一地表示该节点的整个状态。
  应用此方法的方法也有很多:
  从理论上讲,我们可以记录一系列机器指令,或者被调用方法的名称和参数,只要数据处理过程的行为相同,这些过程就可以保证节点之间的一致性。
  经常玩数据库的人会以不同的方式处理逻辑日志和物理日志:
  对于分布式系统,通常有两种方法来处理复制和数据处理:
  1) 状态机模型(主动 – 主动)
  2) 主回模型(主动 – 被动)
  如下图所示:
  为了理解上述两种方式之间的区别,让我们看一个简单的例子:
  现在,集群需要提供一个简单的服务来执行算术运算,例如加法和乘法。最初,维护一个数字,例如 0。
  上面的例子还揭示了为什么顺序是复制节点之间一致性的关键因素,如果这些操作的顺序被打乱,将获得不同的结果。
  分布式日志,可以作为某些一致性算法的数据结构:
  表示有关下一个值的一系列决策的日志。
  2.2.4 更新日志
  从数据库的角度来看,记录数据更改的一组更改日志和表是双重且可互操作的。
  1)根据记录数据变化的日志,可以重构处于某种状态的表(也可以是非关系存储系统中带有键的记录)。
  2)相反,如果表发生变化,则可以在日志中计算更改。
  这正是您想要近乎实时复制的地方!
  这与版本控制的作用非常相似:管理分布式、并发和状态修改。
  版本控制工具维护反映更改的修补程序,该修补程序实际上是一个日志,并且您与分支的签出快照进行交互,该快照等效于数据库中的表。您会发现,在版本控制和分布式系统中,复制都是基于日志的:更新版本时,只需提取反映版本更改的修补程序并将其应用于当前分支快照。
  2.3 数据集成
  2.3.1 数据集成的含义
  数据集成是来自组织中所有服务和系统的数据。
  事实上,数据的有效利用非常符合马斯洛的层次需求理论。
  在金字塔的底部,数据被采集并集成到应用程序中(无论是实时计算引擎、文本文件还是 Python 脚本)。
  这些数据需要转换,以保持易于阅读和处理的统一、标准化和干净的格式。
  当满足上述要求时,就可以开始考虑各种数据处理方法,如map-reduce或实时查询系统。
  显然,如果没有可靠、完整的数据流,Hadoop 只是一个昂贵的、难以集成的加热器(集群是否昂贵?)。
  相反,如果可以确保数据流可靠、可用且完整,则可以考虑更高级的游戏玩法、更好的数据模型以及一致、更易于理解的语义。
  然后,重点可以转移到可视化、报告、算法和预测(挖掘深度)。
  2.3.2 数据集成的两种复杂性
  事件事件
  数据记录事件是如何发生的,而不仅仅是发生了什么,通常被视为应用程序日志,因为它通常由应用程序系统写入。但这实际上混淆了日志的功能。
  事实上,谷歌的财富是由建立在(用户)点击流和好恶(体验)上的关联管道产生的,点击流和展示是事件。
  各类专业数据系统的爆炸式增长
  这些系统存在的原因:
  显然,将数据集成到这样的系统中是极其困难的。
  2.3.3 基于日志结构的数据流
  每个逻辑数据源都可以根据日志进行建模。
  数据源可以是记录事件(命中和 PV)的应用程序,也可以是接受更改的数据库表。
  每个订阅服务器都会尽快从这些数据源生成的日志中获取新记录,将其应用于本地存储系统,并增加其在日志中的读取偏移量。订阅者可以是任何数据系统,例如缓存、Hadoop、另一个站点的数据库或搜索引擎。
  登录
  事实上,提供了一个逻辑时钟,可以测量不同订阅者响应数据变化的状态,因为这些订阅者在日志中具有不同且独立的读取偏移量,这就像时间意义上的“时刻”。
  
  考虑这样一个示例、数据库和一些缓存服务器:
  日志提供了同步所有缓存服务器并推送其“时刻”的能力。
  假设我们写了一个数字为 X 的日志,想要从缓存服务器读取数据,为了不读取旧数据,我们只需要确保在缓存服务器将数据(同步)复制到 X 位置之前,我们不会从这个缓存中读取任何内容。
  此外,log 还提供了充当缓冲区的功能,以异步方式支持生产者和使用者行为。
  支持异步的最关键原因之一是订阅系统可能会崩溃,脱机进行维护,然后重新联机,在这种情况下,每个订阅者都按照自己的节奏使用数据。
  批处理系统(如 Hadoop 或数据仓库)使用数据
  以小时或数天为单位,而实时系统通常在几秒钟内消耗数据。
  数据源或日志不知道使用数据的订阅者的任何信息,因此有必要在管道中无缝添加订阅者和删除订阅者。
  更重要的是,订阅者只需要知道日志,而不是他们使用的数据源,无论该数据源是RDBMS,Hadoop还是新流行的K-V数据库等。之所以说日志,而不是消息系统,是因为不同的消息系统
  保证了不同的特性,而使用word消息系统,很难全面准确地表达某种语义,因为消息系统更重要的重定向消息。
  但是,日志可以理解为提供持久性保证和强序语义的消息系统,这在通信系统中称为原子广播。
  2.4 LinkedIn
  LinkedIn目前的主要系统包括(注:2013年):
  每个系统在其专业领域都提供专门的高级功能。
  (这一段太长太长了,周杰伦哥很有口才,所以挑重点记住!
  1)引入数据流的概念,是因为需要在Oracle数据库的表之上建立一个抽象的缓存层,为搜索引擎索引构建和社交图谱更新提供扩展能力。
  2)为了更好的处理LinkedIn的一些推荐算法,我们开始构建Hadoop集群,但团队在这方面的经验还很浅,所以走了不少弯路。
  3)一开始,这只是一个粗略的想法,只是将数据从Oracle数据仓库中提取出来并将其扔到Hadoop中就可以了。首先,从 Oracle 数据仓库快速导出数据是一场噩梦;其次,也是更糟糕的是,数据仓库中的一些数据没有得到正确处理,导致Hadoop批处理任务无法按预期产生结果,并且通过Hadoop批处理执行任务通常是不可逆的,尤其是在报告发布之后。
  4)最后,团队放弃了将数据从数据仓库中提取出来的方式,直接进入数据库和日志作为数据源。然后建造了一个轮子:K-V 存储(伏地魔)。
  5)即使是数据复制这样的小任务,也会占用团队大量的时间来处理它,更糟糕的是,一旦数据处理管道中出现了一个点,Hadoop立即变得浪费,因为无论算法在错误的数据上运行多么出色,只有一个后果,那就是生成更多错误的数据。
  6)即使团队构建了一些具有高度抽象的东西,它也需要为每个数据源进行特定的配置,这是许多错误和失败的根源。7)大量的程序员想要
  跟进,每个程序员都有大量的想法,集成这个系统,添加这个功能,集成这个功能,或者想要自定义数据源。
  8)周杰伦弟兄开始意识到:
  首先,他们建造的管道仍然粗糙,但非常有价值。即使解决数据在Hadoop等新系统中可用的问题,也可以解锁大量可能性。以前困难的计算开始成为可能。只需从其他系统解锁数据并集成它们,即可轻松制作新产品和分析。其次,很明显,可靠的数据加载
  需要更坚实的支持,如果可以捕获所有结构,Hadoop数据加载就可以完全自动化,而无需添加新数据源或手动修改数据模式。数据神奇地出现在 HDFS 中,当添加新数据源时,Hive 的表会自动生成,并使用适当的列自适应地生成。
  第三,数据覆盖面远远不够。因为很难处理很多新的数据源。
  9)为了解决新数据源加入后的数据加载问题,团队开始了这样的尝试:
  很快,他们发现这行不通,因为发布和订阅,生产和消费,数据流通常仍然是双向的,这变成了O(n^2)问题。
  所以,他们需要的是这样的模型:
  每个使用者都需要与数据源隔离,理想情况下只与一个数据存储库进行交互,该存储库为他们提供对任意数据的访问权限。
  10)消息系统+日志=卡夫卡,卡夫卡诞生了。
  2.5 日志ETL与数据仓库的关系
  2.5.1 数据仓库
  1) 一个干净、结构化、集成的数据存储库,用于分析。
  2)虽然这个想法很棒,但获取数据的方式有点过时了:定期从数据库中获取数据并将其转换为更易读的格式。
  3)以前的数据仓库问题是干净数据和数据仓库的高度耦合。
  数据仓库应该是查询功能的集合,服务于上报、搜索、AD热分析,包括计数、聚合、过滤等操作,所以应该是批处理系统。
  但是干净数据和这样的批处理系统的高度耦合意味着这些数据不能被实时系统消费,例如搜索引擎索引构建、实时计算和实时监控系统等。
  2.5.2 ETL
  Jay弟兄认为ETL只做两件事:
  1)提取并清理数据以从特定系统中解锁数据
  2)重构数据,以便可以通过数据仓库进行查询。例如,将数据类型更改为关系数据库的类型,将架构转换为星形或雪花模式,或将其分解为面向列的存储格式。
  但是将这两件事结合在一起是一个大问题,因为集成的、干净的数据应该被其他实时系统、索引构建系统和低延迟处理系统使用。
  数据仓库团队是
  负责采集和清理数据,但这些数据的生成者经常输出难以提取和清理的数据,因为他们不清楚数据仓库团队的数据处理需求。
  同时,由于核心业务团队对跟上公司其他部门的步伐不敏感,真正可以处理的数据覆盖率低,数据流脆弱,难以快速响应变化。
  因此,更好的方法是:
  如果要在干净的数据集上做一些搜索、实时监控趋势图和实时告警,不宜使用原创数据仓库或 Hadoop 集群作为基础设施。更糟糕的是,ETL为数据仓库构建了一个数据加载系统,该系统对其他(实时)系统几乎没有用处。最好的模型是在数据发布者发布
  数据之前清理数据,因为只有发布者最了解其数据的外观。在此阶段完成的所有操作都应该是无损和可逆的。
  所有丰富的语义或附加值的实时转换都应在原创日志发布后进行后处理,包括为事件数据建立会话或添加一些感兴趣的字段。原创日志仍然可以单独使用,但此类实时应用程序也会派生新的参数化日志。
  最后,只有与特定目标系统对应的数据聚合操作才应作为数据加载的一部分执行,例如转换为星型或雪花型架构,以便在数据仓库中进行分析和报告。因为这个阶段,就像传统的ETL一样,由于非常干净和规范的数据流,(带有日志)现在非常简单。
  2.6 日志文件和事件
  以日志为中心的架构还有一个额外的好处,即易于实现非耦合的事件驱动系统。
  捕获用户活动和系统更改的传统方法是将此信息写入文本日志,然后将其提取到数据仓库或Hadoop集群中进行聚合和处理,这类似于前面描述的数据仓库和ETL问题:数据与数据仓库高度耦合。
  在LinkedIn,它构建了一个基于kafka的事件数据处理系统。为各种操作定义了数百种事件类型,从 PV、用户广告展示、搜索到服务呼叫和应用程序异常等。
  要了解上述事件驱动系统的好处,请看一个简单的事件示例
  在“职业”页面上,提供机会。此页面应仅负责如何呈现机会,不应收录太多其他逻辑。但是,您会发现,在相当大的网站中执行此操作很容易涉及越来越多的逻辑,而这些逻辑与展示的机会无关。
  例如,我们要集成以下系统功能:
  1)我们需要将数据发送到Hadoop和数据仓库进行离线处理。
  2)我们需要计算页面浏览量,以确保某些视图不是用于抓取Web内容或任何东西。
  3) 我们需要汇总有关此页面的浏览信息,以便在业务机会发布者的分析页面上显示。
  4)我们需要记录一个用户浏览这个页面的历史记录,以确保我们向这个用户提供任何有价值的、有适合这个用户的良好体验的工作机会,而不是一遍又一遍地为这个用户重复一个机会(想想只有老婆不在家的时候才能玩的游戏, 红绿蓝闪烁的特效,配上爆炸性的DJ风格舞曲,或是摇摆专注的事业巅峰和Qi X短裙的女生,再点进去才发现是标题派对的广告!)。
  5)我们的推荐系统需要记录此页面的浏览历史记录,以便正确跟踪此工作机会的受欢迎程度。
  很快,仅显示机会的页面逻辑变得复杂。虽然我们也增加了这个机会在移动设备上的展示,但我们也必须迁移逻辑,这增加了复杂性。还没有,困难的部分是在此页面上工作的工程师需要了解其他系统,以确保上述功能正确集成。
  这只是一个极其简单的例子,在实践中,情况只会更加复杂。
  事件驱动可以使这变得容易。负责展示机会的
  页面只需要展示机会并记录一些与演示相关的因素,例如与工作机会相关的属性、查看页面的人员以及与演示文稿相关的其他有用信息。页面不需要维护其他系统的知识和知识,例如推荐系统、安全系统、机会发布者分析系统和数据仓库,所有这些系统只需要订阅者、订阅事件,然后独立处理它们,而呈现机会的页面不需要在新订阅者或消费者加入时进行修改。
  2.7 构建可扩展日志
  分离发布者和订阅者并不是什么新鲜事,但日志系统很难确保多个订阅者可以实时处理消息,同时确保可扩展性。
  如果日志不是构建
  速度快,开销低,可扩展性强,那么在这个日志系统上构建的所有美妙之处就不多说了。
  许多人可能认为日志系统在分布式系统中是一项缓慢而昂贵的工作,并且仅用于处理 ZooKeeper 更适合的一些信息,例如元数据。
  但是现在LinkedIn(注:2013年)每天在kafka中处理600亿次不同的消息写入(如果算上数据中心镜像,则为数千亿次写入)。
  周杰伦兄弟,他们是怎么做到的?
  1) 对日志进行分区
  2) 通过批量读取和写入优化吞吐量
  3) 避免不必要的数据复制
  通过将日志切片为多个分区来提供可扩展性:
  1)每个分区都是有序日志,但分区之间没有全局顺序。
  2)将消息写入哪个分区完全由编写器控制,通过某种类型的键(例如user_id)对其进行拆分。
  3)分段允许在分片之间不协调的情况下执行额外的日志操作,并确保系统的吞吐量与Kafka集群的大小呈线性相关。
  4)虽然没有提供全局订单(有
  实际上是成千上万的消费者或订阅者,讨论它们的全局顺序通常没有什么价值),Kafka 提供了一个保证,即发送方以什么顺序将消息发送到分区,消息以什么顺序(以什么顺序,以什么顺序)从该分区传递。
  5)每个分区按照配置的编号进行复制,如果一个领导节点挂断,其他节点将成为新的主节点。
  6)一个日志,和文件系统一样,线性读写模式可以优化,小的读写日志可以形成更大的、高吞吐量的操作。卡夫卡正在激烈地做这件事。批处理用于各种场景,例如客户端向服务器发送数据、将数据写入磁盘、服务器之间的数据复制、向消费者传输数据、确认提交数据等。
  7)最后,Kafka对内存日志、磁盘日志和通过网络发送的日志采用了非常简单的二进制格式,以方便使用各种优化技术,例如零拷贝数据传输。
  许多优化技术相结合,允许您以磁盘或网络可以提供的最大容量读取和写入数据,即使内存已满也是如此。
  2.8 日志和实时处理
  你认为周杰伦提供了一种如此漂亮的方法来复制数据并复制它吗?
  你!错!完成!日志是
  流式处理的另一种说法,日志是流处理的核心。
  2.8.1 什么是流处理
  周杰伦哥认为:
  1)流处理是连续数据处理的基础设施。
  2)流处理的计算模型,如MapReduce或其他分布式处理框架,只需要保证低延迟。
  3)批量数据采集模式导致批量数据处理模式。
  4)采集数据的连续模式导致连续的数据处理模式。
  5)杰伊弟兄谈到了美国人口普查局解释批处理的方式。
  在LinkedIn,活动数据和数据库中的变化是连续的。
  
  每天批处理数据,连续计算将窗口设置为一天以重合。
  因此,流处理是一个这样的过程:
  6)在处理数据时,有了时间的概念,不需要维护数据的静态快照,因此可以按照用户定义的频率输出结果,而无需等待数据集达到某个“结束”状态。
  7)从这个意义上说,流处理是批处理的泛化,鉴于实时数据的普及,这是一个极其重要的泛化。
  8)许多商业公司无法构建流处理引擎,通常是因为他们无法构建流数据采集引擎。
  9) 流处理弥合了实时响应服务和离线批处理基础设施之间的差距。
  10)日志系统解决了流处理模式下的许多关键问题,其中最大的问题是如何在实时多订阅者模式下提供可用数据(流数据采集)。
  2.9 数据流图
  关于流处理最有趣的事情是它扩展了源的概念。
  无论是日志、源还是事件,逐行数据记录,都来自应用程序的活动。
  但是,流处理还允许我们处理来自其他源的数据,这些数据与原创数据到使用者没有什么不同,并且这些派生源可以收录任何程度的复杂性。
  流处理任务应如下所示:从日志中读取数据并将输出写入日志或其他系统。
  作为输入和输出日志,将这些进程本身与其他进程连接起来,形成一个图形。
  事实上,以日志为中心的系统允许您将组织中的数据捕获、转换和数据流视为日志和写入它们的处理的组合。
  流处理程序不必很大:它可以是一个进程或一组进程,但它可以提供一些额外的基础结构和支持,以便更轻松地管理用于处理的代码。
  引入日志有两个目的:
  1)确保数据集可以支持多种订阅者模式,并且有序。
  2)可以用作应用程序的缓冲区。这很重要,因为在异步数据处理过程中,如果上游生产者可以更快地生成数据,而使用者无法跟上,在这种情况下,要么处理过程被阻塞,要么引入缓冲区,要么删除数据。
  丢弃数据似乎不是一个好的选择,阻塞处理过程会导致所有数据流的处理图中的处理过程卡住。另一方面,Log 是一个大的、超大的、非常大的缓冲区,它允许重新启动处理进程,以便在进程失败后,它不会影响流处理图中的其他进程。这对于大型组织扩展数据流至关重要,因为不同的团队有不同的处理任务,显然整个流处理过程不会因为一个任务中的错误而卡住。
  Storm 和 Samza 就是这样的流处理引擎,它们都使用 kafka 或其他类似的系统作为它们的日志系统。
  (注:周杰伦哥哥挺凶悍的,卡夫卡在前,萨马扎在后。
  2.10 有状态实时处理
  许多流处理
  引擎是无状态的,一次记录,但许多用例需要在一定大小的特定时间窗口内进行复杂的计数、聚合和联接操作,以进行流处理。
  例如,在点击流中,联接用户信息。
  然后,这种用例需要状态支持。在处理数据时,需要维护一段数据的状态。
  问题是,当处理器可能挂断时,如何保持正确?
  在内存中维护状态可能是最简单的,但它经不起崩溃。
  如果仅在某个时间窗口内保持状态,当发生挂断或故障时,则可以将处理直接重播到窗口的开头,但如果窗口长达 1 小时,这可能不起作用。
  另一种简单的解决方案是将状态存储在远程存储系统或数据库中,但这会丢失数据的局部性并产生大量的网络往返。
  回想一下上面提到的数据库中表和日志的双重性。
  可以使用本地存储或索引维护状态的流处理组件:
  通过记录有关本地索引的更改日志,它用于在崩溃后还原状态。此机制实际上揭示了一种通用状态,该状态可以存储为任意索引类型,并与输入流同时进行共分区。
  当处理进程崩溃时,它可以从更改日志中恢复索引,更改日志充当角色,将本地状态转换为基于基于时间的备份的某种增量记录。
  这种机制还提供了将进程本身的状态记录为日志的优雅功能,其他进程显然可以订阅该日志。
  结合数据库中的日志技术,对于数据集成的场景,往往可以做非常强大的事情:
  通过从数据库中提取日志并在各种流处理系统中为它们编制索引,可以加入不同的事件流。
  2.11 日志合并
  显然,不可能使用日志来记录全时状态更改信息。
  Kafka 使用日志合并或日志垃圾回收
  1) 对于事件数据,Kafka 只保留一个时间窗口(可以按时间配置为天或按空间配置)。
  2)对于键控更新,Kafka使用压缩技术。这种类型的日志可用于通过另一个系统中的重放技术重建源系统的状态。
  如果始终保留完整的日志数量,数据会随着时间的推移变得越来越大,重放过程也会越来越长。
  Kafka 不是简单地丢弃旧的日志消息,而是通过合并来丢弃过时的记录,例如,如果消息的主键最近已更新。
  2.12 系统构建
  2.12.1 分布式系统
  日志,在分布式数据库的数据流系统中所扮演的角色是一致的:
  您可以将组织中的应用程序和数据流视为单个分布式数据库。
  将面向查询的独立系统(如 Redis、SOLR、Hive 表等)视为特殊的顶级数据索引。
  将 Storm 和 Samza 等流处理系统视为设计良好的触发器或具体化视图机制。
  各种数据系统的爆发式涌现,其实这种复杂性早已存在。在关系数据库
  的辉煌时期(鼎盛时期),公司或组织有多种关系数据库。
  显然,不可能将所有内容都放入Hadoop集群并期望它解决所有问题。那么,如何构建一个好的系统,可能是这样的:
  构建一个分布式系统,其中每个组件都是一个小集群,每个组件不一定提供完整的安全性、性能隔离或良好的可扩展性,但每个问题都可以(专业地)解决。
  Jay认为,各种系统之所以爆炸式增长,是因为构建一个强大的分布式系统非常困难。如果将用例限制为简单的场景(例如查询),则每个系统都有足够的能力来解决问题,但很难集成这些系统。
  Jay认为未来构建系统有三种可能性
  1)维持现状。在这种情况下,数据集成仍然是最大的问题,因此外部日志系统很重要(kafka!
  2)一个强大的(如辉煌时期的关系数据库)似乎不太可能解决所有问题。
  3)新一代系统大多是开源的,这就揭示了第三种可能:数据基础设施可以离散化成一组服务,还有面向应用的系统API,各种服务各做各司其职,每一种都不完整,但可以专业解决专门的问题,其实现有的Java技术栈可见一斑:
  从某种角度来看,构建这样的分布式系统就像某种版本的乐高积木。这显然与更关心API的最终用户没有太大关系,但它揭示了构建健壮系统并保持简单状态的途径:
  显然,如果构建分布式系统的时间从数年减少到数周,那么自行构建大型系统的复杂性将消失,而这一定是由于出现了更可靠、更灵活的“构建块”。
  2.12.2 登录系统构建状态
  如果系统受外部日志系统支持,
  那么每个独立的系统都可以通过共享一个日志来降低自身的复杂性,Jay 认为日志的作用是:
  1)处理数据一致性。通过序列化节点上的并发操作可以实现即时和最终一致性。
  2) 提供节点间的数据复制。
  3)提供“提交”的语义。例如,如果您认为写入操作不会丢失,则为操作确认。
  4) 提供可由外部系统订阅的源。
  5) 提供在节点因故障而丢失数据时恢复或重建新复制节点的功能。
  6) 处理节点之间的负载均衡。
  以上,可能是应该在完整的分布式系统中提供的大部分功能(Jay brother真的很喜欢Log!其余的是客户端的 API 和构建索引之类的东西,例如需要提取所有分区的全文索引,以及针对只需要提取分区中的数据的主键的查询。
  (那就解释其余的,周杰伦哥哥很厉害!
  该系统可以分为两个逻辑组件(这是强大的理解和技能):
  1) 日志层
  2) 服务层
  日志层以序列化和有序的方式捕获状态更改,而服务层存储外部查询所需的索引,例如可能需要 B 树和稳定索引的 K-V 存储,以及需要倒排索引的搜索服务。
  写入操作可以直接输入到日志层中,也可以通过服务层代理。写入日志会生成逻辑时间戳(日志的索引),例如数字 ID,如果系统已分区,则服务层和日志层将具有相同的分区(但它们各自的计算机编号可能不同)。
  服务层订阅日志层,以
  最快的速度按照日志存储的顺序追逐日志,将数据和状态变化同步到自己的本地索引中。
  客户端将获得读写语义:
  通过携带查询时任何节点写入时间的时间戳,服务的节点
  Layer 接收此查询,将时间戳与其本地索引进行比较,如有必要,为了防止返回过期的旧数据,将请求的执行推迟到服务节点的索引与时间戳同步。
  服务层的节点可能需要也可能不需要知道领导者的概念。在许多简单的用例中,服务层无法构建领导节点,因为日志是事实的来源。
  还有一个问题是如何处理节点故障后的恢复。为此,可以在日志中保留固定大小的时间窗口,同时维护数据的快照。您也可以让日志保留数据的完整备份,并使用日志合并技术完成日志本身的垃圾回收。这种方法将服务层的大部分复杂性转移到日志层,因为服务层是特定于系统的,并且日志层可以是通用的。
  基于日志系统,可以提供一套完整的API供开发和使用,可以作为其他系统的ETL数据源,供其他系统订阅。
  全栈 ! :
  显然,以日志为核心的分布式系统立即成为可以为其他系统提供数据加载支持和数据流处理的角色。同样,流处理系统也可以同时使用多个数据流,并通过索引这些数据流然后输出另一个系统来向外界提供服务。
  构建系统
  基于日志层和服务层,使查询相关因素与系统的可用性和一致性脱钩。
  也许很多人认为在日志中单独备份数据,尤其是制作数据的完整副本,太浪费和奢侈,但事实并非如此:
  1)LinkedIn(注:2013)Kafka生产集群每个数据中心维护75TB的数据,应用程序集群比kafka集群需要更高的存储空间和存储条件(SSD+更多内存)。
  2)全文搜索索引最好加载到内存中,日志都可以使用,因为它们都是线性读写,所以可以使用廉价的大容量磁盘。
  3)由于Kafka集群实际上是在多订阅者模式下运行的,多个系统消耗数据,因此日志集群的成本是摊销的。
  4)由于上述所有原因,外部日志系统(kafka或类似系统)的开销变得非常小。
  2.13 结论
  最后,周杰伦哥不仅大方地留下了大量有价值的学术和工程论文和参考链接,还虚心留下了这样一句话:
  如果你做到了这一步,你就知道我对日志的大部分了解。
  发现这篇文章对您有帮助吗?请与更多人分享
  关注“进口新品”,看科技干货
  事实:要大量文章,内容伪原创工具哪个好用?
  1.我使用的文章伪原创工具是ATM AI批量写入工具。
  功能:在线伪原创、批量伪原创、自定义文本替换等。
  优点:伪原创之后的文章可读性强,文章流畅,原创率高,伪原创易操作,伪原创文章 速度快,免费使用
  此外,ATM AI 批写助手公众号近日观察到,3.0 版本将会更新。似乎在之前版本的基础上增加了更多的功能。有兴趣的朋友可以了解一下。
  1.在线伪原创:
  
  
  2. 批处理 伪原创:
  
  2.我使用的文章采集工具是优采云采集器和优采云
  1. 优采云采集
  功能:网站各类网站的大部分内容都可以实现采集,采集中的文章支持本地编辑,也支持在线发布到网站
  优点:文章采集速度不错,可以抓取各种网站数据采集,这个采集工具功能非常多,喜欢的朋友需要它可以自己研究。
  
  
  2. 优采云采集
  与上面提到的优采云采集相比,这个优采云采集工具操作起来更简单,设置的地方也不多,相当有一个傻瓜式采集工具,采集的文章速度一样快,文章的内容干净(文本模式下不会出现多余的标签码)在优采云,需要自己设置是否保留标签,比设置复杂一点。
  功能:静态页面内容采集
  优点:采集速度快,操作简单,采集的文章干净(优采云采集不支持在线发布,但是优采云还有各种网站内容更新器,需要另外下载)
   查看全部

  经验:我所读过的最好的一篇分布式技术文章
  (点击上方公众号快速关注)。
  资料来源:foreach_break,
  前言
  这是一份学习笔记。
  该材料来自Jay Kreps关于Log的博客文章。
  原文很长,但我坚持阅读,收获颇丰,对 Jay 的技术能力、架构能力和对分布式系统的深刻理解印象深刻。同时,他有点沾沾自喜,因为他的一些理解与周杰伦的观点相吻合。
  Jay Kreps是LinkedIn的前首席参谋工程师,现在是Confluent的联合创始人兼首席执行官,也是Kafka和Samza的主要作者。
  所谓笔记,就是读文章做笔记,因为周杰伦哥自己在这一章里组织得太好了,他自己的科学素养和哲学素养也很高,所以他认为突出的也不会省略。
  一、来源
  日志:每个软件工程师都应该知道的关于实时数据的统一抽象()
  二、注意事项
  2.1 日志的值
  1)日志是以下系统的核心:
  2)日志可能与计算机一样古老,是分布式数据系统和实时计算系统的核心。
  3)日志有很多名称:
  4)不了解日志就无法完全理解日志
  2.2 什么是日志?
  2.2.1 概述
  记录的顺序定义了这样一个概念:时间。
  因为离记录越远,记录得越早。
  的概念
  条目的序列号可以用作时间戳,记录顺序作为时间的概念可能看起来很奇怪,但您很快就会发现,将“时间”与任何特定的物理时钟分离很容易。
  日志与普通文件和表没有太大区别。
  这样,你可能会觉得日志这么简单,还有需要讨论的吗?
  其实日志的核心含义是:
  日志记录发生了什么以及何时发生。
  而这个通常是分布式系统最核心的东西。
  请注意,这里有必要澄清几个概念:
  2.2.2 数据库中的日志
  Log的起源未知,就像发明二进制搜索的人一样,很难意识到这项发明是一项发明。
  日志记录早在IBM的System R中就出现了。
  在数据库中,您需要在数据库崩溃时保持不同的数据结构和索引同步。
  为了确保原子性和持久性,数据库需要在提交对数据结构和索引的更改之前记录要修改的内容。
  因此,日志记录了何时发生的情况,每个表和索引本身就是此历史信息的映射。
  由于日志会立即持久化,因此它们成为在发生崩溃时还原其他持久性结构的可靠来源。
  日志已从 ACID 特征的实现演变为数据库之间的数据复制方式。
  显然,数据库中发生的一系列数据更改成为保持数据库之间同步的最需要的信息。
  Oracle,MySQL和PostgreSQL都收录一个日志传输协议,该协议将日志的一部分发送到用于维护复制的从属数据库。
  Oracle的XStreams和GoldenState使用日志作为通用数据订阅机制来提供非Oracle数据库订阅数据。
  MySQL和PostgreSQL提供了类似的组件,这些组件是数据系统架构的核心。
  面向机器的日志不仅可以用于数据库,还可以用于:
  2.2.3 分布式系统中的日志
  日志解决了分布式数据系统中的两个重要问题:
  1) 有序数据更改
  2) 数据分发
  所谓的状态机复制原理
  如果两个确定性过程(以相同的状态和相同的顺序开始)接收相同的输入,则它们将产生相同的输出并以相同的状态结束。
  这
  所谓确定性是指处理过程与时间无关,其处理结果不受额外输入的影响。
  可以通过非确定性示例来理解:
  所谓状态可以是机器上的任何数据,无论是在机器的内存中还是经过处理后的磁盘上。值得注意的是,相同的
  输入以相同的顺序产生相同的结果,这就是为什么日志如此重要的原因,这是一个直观的概念:如果你将相同的日志输入两个确定性程序,它们将产生相同的输出。
  在分布式系统的构建中,意识到这一点可以:
  让所有机器都做同样的事情,协议是:
  构建分布式、一致的日志系统,为所有处理系统提供输入。
  日志系统的作用是消除所有输入流的不确定性,并确保处理相同输入的所有复制节点保持同步。
  此方法的最佳部分是,您可以将索引日志的时间戳视为所有复制节点的时钟:通过使用复制节点处理的日志
  中最大的时间戳作为复制节点的唯一 ID,时间戳与日志相结合可以唯一地表示该节点的整个状态。
  应用此方法的方法也有很多:
  从理论上讲,我们可以记录一系列机器指令,或者被调用方法的名称和参数,只要数据处理过程的行为相同,这些过程就可以保证节点之间的一致性。
  经常玩数据库的人会以不同的方式处理逻辑日志和物理日志:
  对于分布式系统,通常有两种方法来处理复制和数据处理:
  1) 状态机模型(主动 – 主动)
  2) 主回模型(主动 – 被动)
  如下图所示:
  为了理解上述两种方式之间的区别,让我们看一个简单的例子:
  现在,集群需要提供一个简单的服务来执行算术运算,例如加法和乘法。最初,维护一个数字,例如 0。
  上面的例子还揭示了为什么顺序是复制节点之间一致性的关键因素,如果这些操作的顺序被打乱,将获得不同的结果。
  分布式日志,可以作为某些一致性算法的数据结构:
  表示有关下一个值的一系列决策的日志。
  2.2.4 更新日志
  从数据库的角度来看,记录数据更改的一组更改日志和表是双重且可互操作的。
  1)根据记录数据变化的日志,可以重构处于某种状态的表(也可以是非关系存储系统中带有键的记录)。
  2)相反,如果表发生变化,则可以在日志中计算更改。
  这正是您想要近乎实时复制的地方!
  这与版本控制的作用非常相似:管理分布式、并发和状态修改。
  版本控制工具维护反映更改的修补程序,该修补程序实际上是一个日志,并且您与分支的签出快照进行交互,该快照等效于数据库中的表。您会发现,在版本控制和分布式系统中,复制都是基于日志的:更新版本时,只需提取反映版本更改的修补程序并将其应用于当前分支快照。
  2.3 数据集成
  2.3.1 数据集成的含义
  数据集成是来自组织中所有服务和系统的数据。
  事实上,数据的有效利用非常符合马斯洛的层次需求理论。
  在金字塔的底部,数据被采集并集成到应用程序中(无论是实时计算引擎、文本文件还是 Python 脚本)。
  这些数据需要转换,以保持易于阅读和处理的统一、标准化和干净的格式。
  当满足上述要求时,就可以开始考虑各种数据处理方法,如map-reduce或实时查询系统。
  显然,如果没有可靠、完整的数据流,Hadoop 只是一个昂贵的、难以集成的加热器(集群是否昂贵?)。
  相反,如果可以确保数据流可靠、可用且完整,则可以考虑更高级的游戏玩法、更好的数据模型以及一致、更易于理解的语义。
  然后,重点可以转移到可视化、报告、算法和预测(挖掘深度)。
  2.3.2 数据集成的两种复杂性
  事件事件
  数据记录事件是如何发生的,而不仅仅是发生了什么,通常被视为应用程序日志,因为它通常由应用程序系统写入。但这实际上混淆了日志的功能。
  事实上,谷歌的财富是由建立在(用户)点击流和好恶(体验)上的关联管道产生的,点击流和展示是事件。
  各类专业数据系统的爆炸式增长
  这些系统存在的原因:
  显然,将数据集成到这样的系统中是极其困难的。
  2.3.3 基于日志结构的数据流
  每个逻辑数据源都可以根据日志进行建模。
  数据源可以是记录事件(命中和 PV)的应用程序,也可以是接受更改的数据库表。
  每个订阅服务器都会尽快从这些数据源生成的日志中获取新记录,将其应用于本地存储系统,并增加其在日志中的读取偏移量。订阅者可以是任何数据系统,例如缓存、Hadoop、另一个站点的数据库或搜索引擎。
  登录
  事实上,提供了一个逻辑时钟,可以测量不同订阅者响应数据变化的状态,因为这些订阅者在日志中具有不同且独立的读取偏移量,这就像时间意义上的“时刻”。
  
  考虑这样一个示例、数据库和一些缓存服务器:
  日志提供了同步所有缓存服务器并推送其“时刻”的能力。
  假设我们写了一个数字为 X 的日志,想要从缓存服务器读取数据,为了不读取旧数据,我们只需要确保在缓存服务器将数据(同步)复制到 X 位置之前,我们不会从这个缓存中读取任何内容。
  此外,log 还提供了充当缓冲区的功能,以异步方式支持生产者和使用者行为。
  支持异步的最关键原因之一是订阅系统可能会崩溃,脱机进行维护,然后重新联机,在这种情况下,每个订阅者都按照自己的节奏使用数据。
  批处理系统(如 Hadoop 或数据仓库)使用数据
  以小时或数天为单位,而实时系统通常在几秒钟内消耗数据。
  数据源或日志不知道使用数据的订阅者的任何信息,因此有必要在管道中无缝添加订阅者和删除订阅者。
  更重要的是,订阅者只需要知道日志,而不是他们使用的数据源,无论该数据源是RDBMS,Hadoop还是新流行的K-V数据库等。之所以说日志,而不是消息系统,是因为不同的消息系统
  保证了不同的特性,而使用word消息系统,很难全面准确地表达某种语义,因为消息系统更重要的重定向消息。
  但是,日志可以理解为提供持久性保证和强序语义的消息系统,这在通信系统中称为原子广播。
  2.4 LinkedIn
  LinkedIn目前的主要系统包括(注:2013年):
  每个系统在其专业领域都提供专门的高级功能。
  (这一段太长太长了,周杰伦哥很有口才,所以挑重点记住!
  1)引入数据流的概念,是因为需要在Oracle数据库的表之上建立一个抽象的缓存层,为搜索引擎索引构建和社交图谱更新提供扩展能力。
  2)为了更好的处理LinkedIn的一些推荐算法,我们开始构建Hadoop集群,但团队在这方面的经验还很浅,所以走了不少弯路。
  3)一开始,这只是一个粗略的想法,只是将数据从Oracle数据仓库中提取出来并将其扔到Hadoop中就可以了。首先,从 Oracle 数据仓库快速导出数据是一场噩梦;其次,也是更糟糕的是,数据仓库中的一些数据没有得到正确处理,导致Hadoop批处理任务无法按预期产生结果,并且通过Hadoop批处理执行任务通常是不可逆的,尤其是在报告发布之后。
  4)最后,团队放弃了将数据从数据仓库中提取出来的方式,直接进入数据库和日志作为数据源。然后建造了一个轮子:K-V 存储(伏地魔)。
  5)即使是数据复制这样的小任务,也会占用团队大量的时间来处理它,更糟糕的是,一旦数据处理管道中出现了一个点,Hadoop立即变得浪费,因为无论算法在错误的数据上运行多么出色,只有一个后果,那就是生成更多错误的数据。
  6)即使团队构建了一些具有高度抽象的东西,它也需要为每个数据源进行特定的配置,这是许多错误和失败的根源。7)大量的程序员想要
  跟进,每个程序员都有大量的想法,集成这个系统,添加这个功能,集成这个功能,或者想要自定义数据源。
  8)周杰伦弟兄开始意识到:
  首先,他们建造的管道仍然粗糙,但非常有价值。即使解决数据在Hadoop等新系统中可用的问题,也可以解锁大量可能性。以前困难的计算开始成为可能。只需从其他系统解锁数据并集成它们,即可轻松制作新产品和分析。其次,很明显,可靠的数据加载
  需要更坚实的支持,如果可以捕获所有结构,Hadoop数据加载就可以完全自动化,而无需添加新数据源或手动修改数据模式。数据神奇地出现在 HDFS 中,当添加新数据源时,Hive 的表会自动生成,并使用适当的列自适应地生成。
  第三,数据覆盖面远远不够。因为很难处理很多新的数据源。
  9)为了解决新数据源加入后的数据加载问题,团队开始了这样的尝试:
  很快,他们发现这行不通,因为发布和订阅,生产和消费,数据流通常仍然是双向的,这变成了O(n^2)问题。
  所以,他们需要的是这样的模型:
  每个使用者都需要与数据源隔离,理想情况下只与一个数据存储库进行交互,该存储库为他们提供对任意数据的访问权限。
  10)消息系统+日志=卡夫卡,卡夫卡诞生了。
  2.5 日志ETL与数据仓库的关系
  2.5.1 数据仓库
  1) 一个干净、结构化、集成的数据存储库,用于分析。
  2)虽然这个想法很棒,但获取数据的方式有点过时了:定期从数据库中获取数据并将其转换为更易读的格式。
  3)以前的数据仓库问题是干净数据和数据仓库的高度耦合。
  数据仓库应该是查询功能的集合,服务于上报、搜索、AD热分析,包括计数、聚合、过滤等操作,所以应该是批处理系统。
  但是干净数据和这样的批处理系统的高度耦合意味着这些数据不能被实时系统消费,例如搜索引擎索引构建、实时计算和实时监控系统等。
  2.5.2 ETL
  Jay弟兄认为ETL只做两件事:
  1)提取并清理数据以从特定系统中解锁数据
  2)重构数据,以便可以通过数据仓库进行查询。例如,将数据类型更改为关系数据库的类型,将架构转换为星形或雪花模式,或将其分解为面向列的存储格式。
  但是将这两件事结合在一起是一个大问题,因为集成的、干净的数据应该被其他实时系统、索引构建系统和低延迟处理系统使用。
  数据仓库团队是
  负责采集和清理数据,但这些数据的生成者经常输出难以提取和清理的数据,因为他们不清楚数据仓库团队的数据处理需求。
  同时,由于核心业务团队对跟上公司其他部门的步伐不敏感,真正可以处理的数据覆盖率低,数据流脆弱,难以快速响应变化。
  因此,更好的方法是:
  如果要在干净的数据集上做一些搜索、实时监控趋势图和实时告警,不宜使用原创数据仓库或 Hadoop 集群作为基础设施。更糟糕的是,ETL为数据仓库构建了一个数据加载系统,该系统对其他(实时)系统几乎没有用处。最好的模型是在数据发布者发布
  数据之前清理数据,因为只有发布者最了解其数据的外观。在此阶段完成的所有操作都应该是无损和可逆的。
  所有丰富的语义或附加值的实时转换都应在原创日志发布后进行后处理,包括为事件数据建立会话或添加一些感兴趣的字段。原创日志仍然可以单独使用,但此类实时应用程序也会派生新的参数化日志。
  最后,只有与特定目标系统对应的数据聚合操作才应作为数据加载的一部分执行,例如转换为星型或雪花型架构,以便在数据仓库中进行分析和报告。因为这个阶段,就像传统的ETL一样,由于非常干净和规范的数据流,(带有日志)现在非常简单。
  2.6 日志文件和事件
  以日志为中心的架构还有一个额外的好处,即易于实现非耦合的事件驱动系统。
  捕获用户活动和系统更改的传统方法是将此信息写入文本日志,然后将其提取到数据仓库或Hadoop集群中进行聚合和处理,这类似于前面描述的数据仓库和ETL问题:数据与数据仓库高度耦合。
  在LinkedIn,它构建了一个基于kafka的事件数据处理系统。为各种操作定义了数百种事件类型,从 PV、用户广告展示、搜索到服务呼叫和应用程序异常等。
  要了解上述事件驱动系统的好处,请看一个简单的事件示例
  在“职业”页面上,提供机会。此页面应仅负责如何呈现机会,不应收录太多其他逻辑。但是,您会发现,在相当大的网站中执行此操作很容易涉及越来越多的逻辑,而这些逻辑与展示的机会无关。
  例如,我们要集成以下系统功能:
  1)我们需要将数据发送到Hadoop和数据仓库进行离线处理。
  2)我们需要计算页面浏览量,以确保某些视图不是用于抓取Web内容或任何东西。
  3) 我们需要汇总有关此页面的浏览信息,以便在业务机会发布者的分析页面上显示。
  4)我们需要记录一个用户浏览这个页面的历史记录,以确保我们向这个用户提供任何有价值的、有适合这个用户的良好体验的工作机会,而不是一遍又一遍地为这个用户重复一个机会(想想只有老婆不在家的时候才能玩的游戏, 红绿蓝闪烁的特效,配上爆炸性的DJ风格舞曲,或是摇摆专注的事业巅峰和Qi X短裙的女生,再点进去才发现是标题派对的广告!)。
  5)我们的推荐系统需要记录此页面的浏览历史记录,以便正确跟踪此工作机会的受欢迎程度。
  很快,仅显示机会的页面逻辑变得复杂。虽然我们也增加了这个机会在移动设备上的展示,但我们也必须迁移逻辑,这增加了复杂性。还没有,困难的部分是在此页面上工作的工程师需要了解其他系统,以确保上述功能正确集成。
  这只是一个极其简单的例子,在实践中,情况只会更加复杂。
  事件驱动可以使这变得容易。负责展示机会的
  页面只需要展示机会并记录一些与演示相关的因素,例如与工作机会相关的属性、查看页面的人员以及与演示文稿相关的其他有用信息。页面不需要维护其他系统的知识和知识,例如推荐系统、安全系统、机会发布者分析系统和数据仓库,所有这些系统只需要订阅者、订阅事件,然后独立处理它们,而呈现机会的页面不需要在新订阅者或消费者加入时进行修改。
  2.7 构建可扩展日志
  分离发布者和订阅者并不是什么新鲜事,但日志系统很难确保多个订阅者可以实时处理消息,同时确保可扩展性。
  如果日志不是构建
  速度快,开销低,可扩展性强,那么在这个日志系统上构建的所有美妙之处就不多说了。
  许多人可能认为日志系统在分布式系统中是一项缓慢而昂贵的工作,并且仅用于处理 ZooKeeper 更适合的一些信息,例如元数据。
  但是现在LinkedIn(注:2013年)每天在kafka中处理600亿次不同的消息写入(如果算上数据中心镜像,则为数千亿次写入)。
  周杰伦兄弟,他们是怎么做到的?
  1) 对日志进行分区
  2) 通过批量读取和写入优化吞吐量
  3) 避免不必要的数据复制
  通过将日志切片为多个分区来提供可扩展性:
  1)每个分区都是有序日志,但分区之间没有全局顺序。
  2)将消息写入哪个分区完全由编写器控制,通过某种类型的键(例如user_id)对其进行拆分。
  3)分段允许在分片之间不协调的情况下执行额外的日志操作,并确保系统的吞吐量与Kafka集群的大小呈线性相关。
  4)虽然没有提供全局订单(有
  实际上是成千上万的消费者或订阅者,讨论它们的全局顺序通常没有什么价值),Kafka 提供了一个保证,即发送方以什么顺序将消息发送到分区,消息以什么顺序(以什么顺序,以什么顺序)从该分区传递。
  5)每个分区按照配置的编号进行复制,如果一个领导节点挂断,其他节点将成为新的主节点。
  6)一个日志,和文件系统一样,线性读写模式可以优化,小的读写日志可以形成更大的、高吞吐量的操作。卡夫卡正在激烈地做这件事。批处理用于各种场景,例如客户端向服务器发送数据、将数据写入磁盘、服务器之间的数据复制、向消费者传输数据、确认提交数据等。
  7)最后,Kafka对内存日志、磁盘日志和通过网络发送的日志采用了非常简单的二进制格式,以方便使用各种优化技术,例如零拷贝数据传输。
  许多优化技术相结合,允许您以磁盘或网络可以提供的最大容量读取和写入数据,即使内存已满也是如此。
  2.8 日志和实时处理
  你认为周杰伦提供了一种如此漂亮的方法来复制数据并复制它吗?
  你!错!完成!日志是
  流式处理的另一种说法,日志是流处理的核心。
  2.8.1 什么是流处理
  周杰伦哥认为:
  1)流处理是连续数据处理的基础设施。
  2)流处理的计算模型,如MapReduce或其他分布式处理框架,只需要保证低延迟。
  3)批量数据采集模式导致批量数据处理模式。
  4)采集数据的连续模式导致连续的数据处理模式。
  5)杰伊弟兄谈到了美国人口普查局解释批处理的方式。
  在LinkedIn,活动数据和数据库中的变化是连续的。
  
  每天批处理数据,连续计算将窗口设置为一天以重合。
  因此,流处理是一个这样的过程:
  6)在处理数据时,有了时间的概念,不需要维护数据的静态快照,因此可以按照用户定义的频率输出结果,而无需等待数据集达到某个“结束”状态。
  7)从这个意义上说,流处理是批处理的泛化,鉴于实时数据的普及,这是一个极其重要的泛化。
  8)许多商业公司无法构建流处理引擎,通常是因为他们无法构建流数据采集引擎。
  9) 流处理弥合了实时响应服务和离线批处理基础设施之间的差距。
  10)日志系统解决了流处理模式下的许多关键问题,其中最大的问题是如何在实时多订阅者模式下提供可用数据(流数据采集)。
  2.9 数据流图
  关于流处理最有趣的事情是它扩展了源的概念。
  无论是日志、源还是事件,逐行数据记录,都来自应用程序的活动。
  但是,流处理还允许我们处理来自其他源的数据,这些数据与原创数据到使用者没有什么不同,并且这些派生源可以收录任何程度的复杂性。
  流处理任务应如下所示:从日志中读取数据并将输出写入日志或其他系统。
  作为输入和输出日志,将这些进程本身与其他进程连接起来,形成一个图形。
  事实上,以日志为中心的系统允许您将组织中的数据捕获、转换和数据流视为日志和写入它们的处理的组合。
  流处理程序不必很大:它可以是一个进程或一组进程,但它可以提供一些额外的基础结构和支持,以便更轻松地管理用于处理的代码。
  引入日志有两个目的:
  1)确保数据集可以支持多种订阅者模式,并且有序。
  2)可以用作应用程序的缓冲区。这很重要,因为在异步数据处理过程中,如果上游生产者可以更快地生成数据,而使用者无法跟上,在这种情况下,要么处理过程被阻塞,要么引入缓冲区,要么删除数据。
  丢弃数据似乎不是一个好的选择,阻塞处理过程会导致所有数据流的处理图中的处理过程卡住。另一方面,Log 是一个大的、超大的、非常大的缓冲区,它允许重新启动处理进程,以便在进程失败后,它不会影响流处理图中的其他进程。这对于大型组织扩展数据流至关重要,因为不同的团队有不同的处理任务,显然整个流处理过程不会因为一个任务中的错误而卡住。
  Storm 和 Samza 就是这样的流处理引擎,它们都使用 kafka 或其他类似的系统作为它们的日志系统。
  (注:周杰伦哥哥挺凶悍的,卡夫卡在前,萨马扎在后。
  2.10 有状态实时处理
  许多流处理
  引擎是无状态的,一次记录,但许多用例需要在一定大小的特定时间窗口内进行复杂的计数、聚合和联接操作,以进行流处理。
  例如,在点击流中,联接用户信息。
  然后,这种用例需要状态支持。在处理数据时,需要维护一段数据的状态。
  问题是,当处理器可能挂断时,如何保持正确?
  在内存中维护状态可能是最简单的,但它经不起崩溃。
  如果仅在某个时间窗口内保持状态,当发生挂断或故障时,则可以将处理直接重播到窗口的开头,但如果窗口长达 1 小时,这可能不起作用。
  另一种简单的解决方案是将状态存储在远程存储系统或数据库中,但这会丢失数据的局部性并产生大量的网络往返。
  回想一下上面提到的数据库中表和日志的双重性。
  可以使用本地存储或索引维护状态的流处理组件:
  通过记录有关本地索引的更改日志,它用于在崩溃后还原状态。此机制实际上揭示了一种通用状态,该状态可以存储为任意索引类型,并与输入流同时进行共分区。
  当处理进程崩溃时,它可以从更改日志中恢复索引,更改日志充当角色,将本地状态转换为基于基于时间的备份的某种增量记录。
  这种机制还提供了将进程本身的状态记录为日志的优雅功能,其他进程显然可以订阅该日志。
  结合数据库中的日志技术,对于数据集成的场景,往往可以做非常强大的事情:
  通过从数据库中提取日志并在各种流处理系统中为它们编制索引,可以加入不同的事件流。
  2.11 日志合并
  显然,不可能使用日志来记录全时状态更改信息。
  Kafka 使用日志合并或日志垃圾回收
  1) 对于事件数据,Kafka 只保留一个时间窗口(可以按时间配置为天或按空间配置)。
  2)对于键控更新,Kafka使用压缩技术。这种类型的日志可用于通过另一个系统中的重放技术重建源系统的状态。
  如果始终保留完整的日志数量,数据会随着时间的推移变得越来越大,重放过程也会越来越长。
  Kafka 不是简单地丢弃旧的日志消息,而是通过合并来丢弃过时的记录,例如,如果消息的主键最近已更新。
  2.12 系统构建
  2.12.1 分布式系统
  日志,在分布式数据库的数据流系统中所扮演的角色是一致的:
  您可以将组织中的应用程序和数据流视为单个分布式数据库。
  将面向查询的独立系统(如 Redis、SOLR、Hive 表等)视为特殊的顶级数据索引。
  将 Storm 和 Samza 等流处理系统视为设计良好的触发器或具体化视图机制。
  各种数据系统的爆发式涌现,其实这种复杂性早已存在。在关系数据库
  的辉煌时期(鼎盛时期),公司或组织有多种关系数据库。
  显然,不可能将所有内容都放入Hadoop集群并期望它解决所有问题。那么,如何构建一个好的系统,可能是这样的:
  构建一个分布式系统,其中每个组件都是一个小集群,每个组件不一定提供完整的安全性、性能隔离或良好的可扩展性,但每个问题都可以(专业地)解决。
  Jay认为,各种系统之所以爆炸式增长,是因为构建一个强大的分布式系统非常困难。如果将用例限制为简单的场景(例如查询),则每个系统都有足够的能力来解决问题,但很难集成这些系统。
  Jay认为未来构建系统有三种可能性
  1)维持现状。在这种情况下,数据集成仍然是最大的问题,因此外部日志系统很重要(kafka!
  2)一个强大的(如辉煌时期的关系数据库)似乎不太可能解决所有问题。
  3)新一代系统大多是开源的,这就揭示了第三种可能:数据基础设施可以离散化成一组服务,还有面向应用的系统API,各种服务各做各司其职,每一种都不完整,但可以专业解决专门的问题,其实现有的Java技术栈可见一斑:
  从某种角度来看,构建这样的分布式系统就像某种版本的乐高积木。这显然与更关心API的最终用户没有太大关系,但它揭示了构建健壮系统并保持简单状态的途径:
  显然,如果构建分布式系统的时间从数年减少到数周,那么自行构建大型系统的复杂性将消失,而这一定是由于出现了更可靠、更灵活的“构建块”。
  2.12.2 登录系统构建状态
  如果系统受外部日志系统支持,
  那么每个独立的系统都可以通过共享一个日志来降低自身的复杂性,Jay 认为日志的作用是:
  1)处理数据一致性。通过序列化节点上的并发操作可以实现即时和最终一致性。
  2) 提供节点间的数据复制。
  3)提供“提交”的语义。例如,如果您认为写入操作不会丢失,则为操作确认。
  4) 提供可由外部系统订阅的源。
  5) 提供在节点因故障而丢失数据时恢复或重建新复制节点的功能。
  6) 处理节点之间的负载均衡。
  以上,可能是应该在完整的分布式系统中提供的大部分功能(Jay brother真的很喜欢Log!其余的是客户端的 API 和构建索引之类的东西,例如需要提取所有分区的全文索引,以及针对只需要提取分区中的数据的主键的查询。
  (那就解释其余的,周杰伦哥哥很厉害!
  该系统可以分为两个逻辑组件(这是强大的理解和技能):
  1) 日志层
  2) 服务层
  日志层以序列化和有序的方式捕获状态更改,而服务层存储外部查询所需的索引,例如可能需要 B 树和稳定索引的 K-V 存储,以及需要倒排索引的搜索服务。
  写入操作可以直接输入到日志层中,也可以通过服务层代理。写入日志会生成逻辑时间戳(日志的索引),例如数字 ID,如果系统已分区,则服务层和日志层将具有相同的分区(但它们各自的计算机编号可能不同)。
  服务层订阅日志层,以
  最快的速度按照日志存储的顺序追逐日志,将数据和状态变化同步到自己的本地索引中。
  客户端将获得读写语义:
  通过携带查询时任何节点写入时间的时间戳,服务的节点
  Layer 接收此查询,将时间戳与其本地索引进行比较,如有必要,为了防止返回过期的旧数据,将请求的执行推迟到服务节点的索引与时间戳同步。
  服务层的节点可能需要也可能不需要知道领导者的概念。在许多简单的用例中,服务层无法构建领导节点,因为日志是事实的来源。
  还有一个问题是如何处理节点故障后的恢复。为此,可以在日志中保留固定大小的时间窗口,同时维护数据的快照。您也可以让日志保留数据的完整备份,并使用日志合并技术完成日志本身的垃圾回收。这种方法将服务层的大部分复杂性转移到日志层,因为服务层是特定于系统的,并且日志层可以是通用的。
  基于日志系统,可以提供一套完整的API供开发和使用,可以作为其他系统的ETL数据源,供其他系统订阅。
  全栈 ! :
  显然,以日志为核心的分布式系统立即成为可以为其他系统提供数据加载支持和数据流处理的角色。同样,流处理系统也可以同时使用多个数据流,并通过索引这些数据流然后输出另一个系统来向外界提供服务。
  构建系统
  基于日志层和服务层,使查询相关因素与系统的可用性和一致性脱钩。
  也许很多人认为在日志中单独备份数据,尤其是制作数据的完整副本,太浪费和奢侈,但事实并非如此:
  1)LinkedIn(注:2013)Kafka生产集群每个数据中心维护75TB的数据,应用程序集群比kafka集群需要更高的存储空间和存储条件(SSD+更多内存)。
  2)全文搜索索引最好加载到内存中,日志都可以使用,因为它们都是线性读写,所以可以使用廉价的大容量磁盘。
  3)由于Kafka集群实际上是在多订阅者模式下运行的,多个系统消耗数据,因此日志集群的成本是摊销的。
  4)由于上述所有原因,外部日志系统(kafka或类似系统)的开销变得非常小。
  2.13 结论
  最后,周杰伦哥不仅大方地留下了大量有价值的学术和工程论文和参考链接,还虚心留下了这样一句话:
  如果你做到了这一步,你就知道我对日志的大部分了解。
  发现这篇文章对您有帮助吗?请与更多人分享
  关注“进口新品”,看科技干货
  事实:要大量文章,内容伪原创工具哪个好用?
  1.我使用的文章伪原创工具是ATM AI批量写入工具。
  功能:在线伪原创、批量伪原创、自定义文本替换等。
  优点:伪原创之后的文章可读性强,文章流畅,原创率高,伪原创易操作,伪原创文章 速度快,免费使用
  此外,ATM AI 批写助手公众号近日观察到,3.0 版本将会更新。似乎在之前版本的基础上增加了更多的功能。有兴趣的朋友可以了解一下。
  1.在线伪原创:
  
  
  2. 批处理 伪原创:
  
  2.我使用的文章采集工具是优采云采集器和优采云
  1. 优采云采集
  功能:网站各类网站的大部分内容都可以实现采集,采集中的文章支持本地编辑,也支持在线发布到网站
  优点:文章采集速度不错,可以抓取各种网站数据采集,这个采集工具功能非常多,喜欢的朋友需要它可以自己研究。
  
  
  2. 优采云采集
  与上面提到的优采云采集相比,这个优采云采集工具操作起来更简单,设置的地方也不多,相当有一个傻瓜式采集工具,采集的文章速度一样快,文章的内容干净(文本模式下不会出现多余的标签码)在优采云,需要自己设置是否保留标签,比设置复杂一点。
  功能:静态页面内容采集
  优点:采集速度快,操作简单,采集的文章干净(优采云采集不支持在线发布,但是优采云还有各种网站内容更新器,需要另外下载)
  

技巧:红蓝对抗之域名搜集方法总结

采集交流优采云 发表了文章 • 0 个评论 • 104 次浏览 • 2022-10-31 15:45 • 来自相关话题

  技巧:红蓝对抗之域名搜集方法总结
  腾讯蓝军实习生
  jax, yhy, A1oe
  前言
  在以往的HW、红蓝对抗、渗透测试项目中,外网信息的采集是一个至关重要的环节。外网信息采集全面,可能有四、两种拨号效果,直接突破外网边界,进入内网。
  最近,我们三人加入了腾讯蓝军,学习渗透技能。讲师要求我们对域名资产的采集方法进行全面的研究。子域是域名信息采集的重要组成部分。在防御措施严密的情况下,我们不能直接拿下主域名,所以可以采取迂回战术,拿下子域名,然后无限接近主域名。
  方法原理介绍
  1. 收获具有证书透明度的子域
  原则
  引用谷歌的项目介绍:“为了给用户提供加密流量,网站必须先向可信的证书颁发机构(CA)申请一个证书。然后,当用户尝试访问对应的网站时,这个证书提供给浏览器以验证 网站。近年来,由于 HTTPS 证书系统的结构缺陷,证书以及颁发证书的 CA 很容易受到黑客攻击和操纵。Google 的证书透明项目( ) 旨在通过提供一个用于监控和审核 HTTPS 证书的开放框架来保护证书颁发过程。”
  那么,通过像这样的证书透明项目,我们可以从中获得一些有价值的域名。
  执行:
  访问以下链接,搜索您需要查询的域名,如:
  (1)crtsh:
  (2) 脸书:
  (3)委托:
  (4) 证书检测器:
  (5) 窥探:
  (6) 中央统计局:
  (7) 谷歌:
  2. 例行检查采集子域
  2.1 域名转移
  原则
  区域转移操作是指备服务器查询主服务器以刷新其区域数据库以确保数据一致性。此操作的目的是防止主名称服务器由于意外故障而变得不可用的全局影响。通常,只有在网络中有备用域名 DNS 服务器时,才需要进行 DNS 区域传输操作。一旦 DNS 服务器被错误配置为向任何发出请求的人提供区域数据库的副本,它就可能被攻击者利用。
  执行
  1.挖掘命令
  作为挖掘@axfr
  是提供数据的服务器,是要传输的关键字,axfr是区域传输选项。
  2.python中的dns库
  xfr = dns.query.xfr(where=server,zone=self.domain,timeout=5.0,lifetime=10.0)
  zone = dns.zone.from_xfr(xfr)
  这儿存在一个问题
  一般来说,如果DNS服务器配置正确、DNS传输被禁用或设置了白名单,漏洞利用成功的概率很低。
  2.2 站点配置文件
  原则
  信息泄露的主要问题是某个域名下的一些文件会存储一些相关的域名,比如子域。此类文件包括跨域策略文件crossdomain.xml、站点地图文件。
  执行
  创建文件列表,拼接域名后直接访问,判断修改后的文件是否存在。如果存在则提取数据,如果不存在则跳过。
  1.crossdomain.xml文件
  直接访问crossdomain.xml路径
  2.站点地图文件
  直接访问 sitemap.xml、sitemap.txt、sitemap.html、sitemapindex.xml、sitemapindex.xml 路径
  这儿存在一个问题
  文件往往不存在,即使存在,域名信息也不充分或不完整。
  2.3 检查内容安全策略
  原则
  内容安全策略 (CSP) 是一种声明性安全机制,它使 网站 操作员能够控制符合 CSP 的用户代理(通常是浏览器)的行为。通过控制启用哪些功能以及从何处下载内容,您可以减少 网站 的攻击面。CSP 的主要目的是防御跨站点脚本 (XSS) 攻击。例如,CSP 可以完全禁止内联 JavaScript 并控制从何处加载外部代码。它还可以禁用动态代码执行。禁用所有攻击源后,XSS 攻击变得更加困难。CSP 中的关键字是 default-src、img-src、object-src 和 script-src。其中,*-src 可能收录域名信息。
  执行
  1.手动抓包
  HTTP 标头的 Content-Security-Policy 属性
  2. Python的Requests获取
  导入请求
  res = requests.post(url=url, headers=headers, data=data, allow_redirects=False)
  如果不是 res.headers['Content-Security-Policy']:
  print("标头中没有 Content-Security-Policy")
  别的:
  # 进程主体代码
  2.4 使用DNS查询采集子域
  原则
  子域srv是通过枚举常见的SRV记录并进行查询来采集的,子域是通过查询域名的DNS记录中的MX、NS、SOA、TXT记录来采集的。
  SRV 记录
  这是在添加服务记录服务器时添加的服务记录,SRV记录哪台计算机提供了哪项服务。格式为:服务名称。协议的类型(例如:example-server.tcp)。
  以下命令枚举给定域名的 SRV 记录:
  nmap --script dns-srv-enum.nse --script-args "dns-srv-enum.domain=''"
  MX 记录
  要创建邮件服务,它会指向邮件服务器地址,并且需要设置 MX 记录。创建邮件地址时,一般根据邮件服务商提供的MX记录填写此记录。
  NS 记录
  域名解析服务器记录。如果要指定域名服务器解析子域,需要设置NS记录。
  SOA 记录
  
  SOA 称为起始权限记录,NS 用于标识多个域名解析服务器,SOA 记录用于标识众多 NS 记录中哪一个是主服务器。
  TXT 记录
  可以任意填写,可以为空。这个项目一般在做一些验证记录的时候用到,比如:SPF(anti-spam)记录。
  3. 利用 DNS 数据集采集子域
  使用 DNS 记录公开数据采集
  *注:将需要的{domain}替换为需要查询的域名,目标是我们认为更有效的。
  (1) ip138:
  {域}/domain.htm
  (2)百度云观察:
  {领域}
  (3) 黑客目标:
  (4) 谜语人:
  :{领域}
  (5) 缓冲:
  {领域}
  (6) dnsdb:
  {领域}
  (7) ipv4info:
  (8) 罗布特斯:
  (9)中国:
  (10) 网络技术:
  (11) dnsdumpster:
  (12) 网站档案:
  (13) 查找子域:
  4. 利用威胁情报平台数据采集子域
  *注:将需要的{domain}替换为需要查询的域名,以下平台需要注册,注册后免费试用
  (1) {domain}/{section}
  {section} 指其他命令和动作,API 的使用请参考文档。
  (2) {domain}/子域
  (3) {域名}
  API:域
  (4)
  {领域}
  (5) {domain}/子域
  或 {domain}/关系
  (6)
  #
  5.使用搜索引擎发现子域
  5.1 谷歌搜索语法——站点
  当使用站点提交查询时,Google 会将查询限制在某个网站/某个域。这个时候最好配合其他指令。例如,使用减号“-”排除不需要的数据。域名。
  5.2 站点:xxx *(目标IP)
  当我们得到子域的真实IP后,可以尝试搜索site:xxx*进行C段搜索,也可以通过这种方法找到很多其他有价值的相关域名。经过笔者的尝试,这种方法在搜狗和谷歌搜索引擎上都有效,谷歌搜索引擎效果更好。
  如图所示:
  6. 域名注册与资产归集
  原则
  在采集一些大型目标的信息时,您还可以通过查找域名注册信息,找到具有相同记录的其他域名资产。比如在采集qq的子域时,最常用的方法就是采集子域。此时,其他顶级域名资产将被遗漏。
  搜索网站:
  如上图所示,通过查看网站的记录/许可号,再逆向查看,可以找到其他具有相同记录的顶级域名资产。
  通过域名注册搜索具有相同记录的其他域名资产,可以更全面地采集目标资产信息,增加发现漏洞的概率。
  7.whois查询和关联查询
  工具:网站管理员工具
  这里我们将演示如何执行whois查询和反向检查
  7.1 查询whois
  7.2 查看whois
  **&amp;ddlSearchMode=1&amp;domain=
  获取相关域信息。
  8. 领域爆炸
  爆破的原理其实是通过枚举实现的,通过不断拼接字典的内容来枚举域名的A记录,但是这种方式一般需要解决泛解析的问题。
  比如开源工具oneforall会先随机访问一个不存在的域,通过返回结果来判断是否有泛解析。确认有泛解析后,程序会开始连续循环生成随机域名,去服务器查询,每次查询都会返回服务器。记录IP和TTL,直到大部分IP地址出现两次以上,IP黑名单采集结束。拿到IP黑名单后,oneforall再将其字典中的每一项与指定要查询的域名进行拼接。爆破过程中根据IP黑名单过滤。
  但是,这种广泛的过滤很容易导致漏报,因此 oneforall 也将 TTL 作为黑名单规则的一部分。判断依据是:在权威DNS中,泛解析记录的TTL必须相同。如果子域记录相同,但 TTL 不同,那么这条记录可以说绝对不是泛解析记录。
  优秀的开源工具
  我们研究了市面上的各种开源子域采集工具,列举了很多优秀工具的功能和优势。这是一个采集其子域的示例。简单比较每个工具的性能和效果。
  工具名称:oneforall
  
  项目地址:
  工具说明:
  oneforall 是近年来出现的比较好的子域采集工具之一,并且还在不断的更新和优化中。这个工具整合了各种域名信息采集的“姿势”,手段可谓非常全面。包括使用证书透明、例行检查、使用网络爬虫(进行中)、DNS数据集、DNS查询、威胁情报平台、搜索引擎等,但笔者发现其对域名泛解析的处理是不是特别理想,而且有很多错误。同时也存在消耗时间长等缺点。
  工具名称:SubdomainBrute
  项目地址:
  工具说明:
  李洁洁的SubdomainBrute是业内比较知名的子域名采集工具。该工具使用协程加速爆破速度,使用114DNS、百度DNS、阿里DNS查询快速可靠的公共DNS。精度高,效果更好。但是泛解析的处理规则是:如果超过10个域名指向同一个IP,则发现指向该IP的其他域名将被丢弃。这个方法可能会被误删,但不可否认,这个规则在一定程度上是有的。简单有效。
  工具名称:ESD
  项目地址:
  工具说明:
  ESD的爆破速度极快。62万条数据只需要4分30秒左右。该工具的缺点之一是它具有很高的性能要求。1G2核心服务器CPU使用率达到100%。另外,输出结果也比较不稳定。在同一网络下采集同一个域名时,结果的数量会出现数倍的变化。
  工具名称:子查找器
  项目地址:
  工具说明:
  使用subfinder采集子域信息,输出结果多,基数大,速度快,输出格式多,便于后续处理(oneforall也有同样的优点)。
  美中不足的是这个工具没有爆破功能,被动源比其他工具少。
  各种工具的效果比较
  每种工具的优缺点比较如下:
  *注:由于各个工具提供的默认字典不同,字典往往需要自己定义才能发挥更大的作用,所以各个工具下载后不修改,使用自己的默认字典进行爆破。使用单个域名测试并不通用,爆破结果仅供参考。
  从上图来看,单从数据层面来看,OneForAll在四大工具中表现突出,李洁洁的subdomainBrute也很优秀。可访问子域的百分比和时间非常好。域名相对较少。
  子域采集常见问题
  1.DNS缓存问题
  不同的DNS服务器可能有不同的缓存策略,也可能有不同的缓存结果,导致域名查询时解析结果没有及时更新。通常,解决上述问题需要多次 DNS 查询来强制 DNS 服务器刷新缓存以获得正确的结果。这无疑增加了泛分辨率判断和子域爆破的难度。
  事实上,这个问题在 OneForAll 中并没有得到很好的解决。在判断是否存在一般解析问题时,OneForAll 使用了函数detect_wildcard(domain, ns_ip_list)。在该函数中,OneForAll 使用不存在的子域名进行查询,判断是否有通用解析。但是只做一次决定是不够准确的,可能会导致误判。
  2.“刚性”词典
  爆破是子域采集方法的重要组成部分。对于这些工具中的大多数,字典的质量决定了最终的爆破效果。但大多数字典只是遍历字符集,使用常见的高频词,没有及时更新。当字典文件过大时,爆破速度变得很慢,效率低下的字典即使再大也达不到预期的效果。
  在实际的域名爆破中,能够自动更新的字典无疑会比普通的字典更好。在这里,我们提出了一种自动字典更新的方案。
  动态词典
  在本节中,我们更详细地描述自动字典更新的方案,可以分为三个步骤:更新词的权重➡️删除原创字典中权重低的词➡️从数据集中提取高频词和将它们添加到字典中,以更新字典。
  测试工具:Subdomainbrute
  流程图如下:
  1.体重更新
  首先使用工具subdomainbrute及其默认字典对子域进行爆破,并使用如下脚本对得到的结果进行进一步的批量检测,判断该域名是否可以被外网访问,并保存可以访问的域名一般是从外网到success.txt。
  接下来将mydic中单词的权重全部初始化为0。然后对比success.txt中的三级域名,mydic中对应单词的权重加1,其他单词的权重不变。另外,需要记录本次查询的域名。以后查询同一个域名时,mydic中词的权重不会重复更新。
  *注:mydic用于记录字典中的单词和对应的权重,格式如www,0
  2.单词删除
  使用字典爆破不同域名n次(例如20次)后,更新字典,即删除字典中的单词。具体步骤如下:
  首先,使用record_num.txt文件记录字典的使用次数。当record_num.txt文件不存在时,会生成。使用不同域名的每个查询+1。同一个域名的重复查询只算一次。
  每次程序运行后,判断是否需要reset mydic。如果需要更新,先删除record_num.txt文件,然后根据权重大小对mydic中的数据进行排序,排序后删除后30%的数据。
  3.词典更新
  删除原字典中30%的值后,需要向字典中添加新值。我们解析公共 DNS 记录以更新我们自己的字典。由于下载的数据集大小一般为几十G,直接处理比较困难,所以我们先对数据进行切分,降低处理难度。
  首先将数据集划分为每个100MB左右的数据文件,然后从这些数据文件中随机抽取一部分,将其中的所有子域提取出来,拼接到字典的“数据源”中. 对提取的子域数据进行词频分析,按照频率降序对内容进行排序。选择最频繁出现的值并将其添加到字典中,直到新字典与旧字典的大小相同。最后,新字典中所有值的权重需要清零。
  总结
  1.除了使用爆破工具,采集子域的方法还有很多。比如域名转移漏洞、DNS查询等常规手段,以及证书透明化、DNS数据集、威胁情报平台、搜索引擎、域名注册和whois查询的使用。总而言之,威胁情报平台在这些方法中表现最好,其次是证书透明度和 DNS 数据集。
  2.在这篇文章文章中,我们也研究和比较了几个业内优秀的工具。在子域的采集测试中,subfinder 和 OneForAll 表现更为突出。
  3.子域采集中的一些主要问题是域名泛解析,不同线路不同IP的解析,子域爆破时字典效率低。
  4、针对词典问题,提出了词典自动更新方案。
  网上采集子域的方法和工具有很多,但在实际使用中效果并不理想和全面。为了得到一个高效且有价值的子域列表,我们需要结合不同的方法,使用工具来合理的采集它们。
  为了方便在实战环境中使用,我们整理了大部分常用的方法,整合到这个文章中。作为学习记录,本文可能存在一些错误。如果有任何错误,请纠正我。希望大家和我们一起探索更多更高效的采集子域的方法,共同学习,共同进步。
  最后,还要感谢Leon和Xiaowu导师的帮助和指导。
  附录
  Google 证书透明度项目
  枚举子域
  DNS域名转移漏洞
  史上最全的子域采集方法:
  我们是台橡
  互联网安全卫士
  用户数据安全的捍卫者
  我们发现漏洞,检查入侵,防止攻击
  携手安防行业精英共建互联网生态安全
  期待您与我们的正能量联盟!
  seo站长工具 方法和技巧:SEO新手如何学起?
  SEO新手学习框架
  作为新手,起步阶段主要是搭建SEO基础知识的框架。而这些都可以通过各大搜索引擎初学者的指南文档获得。
  初学者指南
  百度搜索优化知识
  Google SEO 初学者指南
  掌握了这些基础知识体系之后,接下来就是通过实践来检验各种知识点的使用,还需要使用一些基础的SEO工具,包括各大搜索引擎百度、谷歌、必应等主流的站长工具,Yandex 、Naver等小语言;衍生产品插件:5118、爱站、Semrush、Moz、Ahrefs等。
  这可以通过在有SEO团队的公司中加入基础职位来完成,实战是检验知识的唯一标准。自建网站也是一种方式,毕竟搭建个人小网站的成本(包括资金投入和技术投入)已经很低了。
  同时,我们要时刻关注搜索引擎的发展变化和技术更新,不断更新自己的系统认知。
  各大引擎算法的历史和各大白皮书也应该熟悉和掌握。这就是大道所在,能在意识上形成正确的战略方向。
  算法更新历史和白皮书
  算法更新历史
  
  白皮书
  谷歌搜索中心
  百度白皮书:
  百度搜索页面质量标准规范
  百度APP移动搜索登陆页面体验白皮书5.0
  当然,一些灰帽子和黑帽子的技术也应该知道,也可以在自己的资源中做一些实验。但在服务型公司,除非公司有明确要求做黑帽,否则其他人坚决不尝试,毕竟SEO不是一日之功,这样做风险太大。
  竞品的研究也需要不断跟进,这会给你在SEO策略方案上一些启发。
  最后,SEO要成为高级点,必须经过几轮算法循环,对网站进行过多的操作。
  但归根结底,SEO只是一种吸引流量的手段,用它为服务公司和自身带来价值增长才是硬道理。但是SEO思维对我们有很大的积极影响。
  如果你喜欢SEO,就应该时刻保持好奇,不断学习,加强沟通,多做实战。
  以下谷歌seo信息学习博客供参考
  谷歌搜索最新消息
  
  搜索引擎期刊 SEO 专栏
  搜索引擎登陆SEO专栏
  SE圆桌
  以上就是整个SEO新手系统学习SEO的框架。
  为公司建立独立站做外贸的SEO新手
  在本节中,您可以先完善独立站基础SEO标签的基础SEO信息。你可以参考SEO新手指南,按照步骤练习。
  再次重申,关键词这个阶段的研究也很重要,可以使用指南配合google ads、Semrush等一些关键词研究工具配合竞争对手研究(可以搜索核心谷歌搜索中独立网站产品的词)排名前 20 位研究的结果)
  对整个独立站结构进行细化,站内部分首页列表页包括详情页。在选词策略上,关注首页列表页的核心词,详情页的长尾词。具体的内容结构侧重于对产品的理解和用户的需求。内容部署是其中之一,其二是看同类竞品词排名靠前的页面结构部署(意思是引擎通过user确定了用户最需要什么样的内容结构和内容行为),初步内容先做这个,然后根据用户反馈数据做进一步的调整。
  性能方面,可以参考站长工具后台网站的核心指标和人性化的体验进行相应的优化。
  我是Jesse,一个喜欢SEO研究的SEOer,一直在路上,欢迎交流。 查看全部

  技巧:红蓝对抗之域名搜集方法总结
  腾讯蓝军实习生
  jax, yhy, A1oe
  前言
  在以往的HW、红蓝对抗、渗透测试项目中,外网信息的采集是一个至关重要的环节。外网信息采集全面,可能有四、两种拨号效果,直接突破外网边界,进入内网。
  最近,我们三人加入了腾讯蓝军,学习渗透技能。讲师要求我们对域名资产的采集方法进行全面的研究。子域是域名信息采集的重要组成部分。在防御措施严密的情况下,我们不能直接拿下主域名,所以可以采取迂回战术,拿下子域名,然后无限接近主域名。
  方法原理介绍
  1. 收获具有证书透明度的子域
  原则
  引用谷歌的项目介绍:“为了给用户提供加密流量,网站必须先向可信的证书颁发机构(CA)申请一个证书。然后,当用户尝试访问对应的网站时,这个证书提供给浏览器以验证 网站。近年来,由于 HTTPS 证书系统的结构缺陷,证书以及颁发证书的 CA 很容易受到黑客攻击和操纵。Google 的证书透明项目( ) 旨在通过提供一个用于监控和审核 HTTPS 证书的开放框架来保护证书颁发过程。”
  那么,通过像这样的证书透明项目,我们可以从中获得一些有价值的域名。
  执行:
  访问以下链接,搜索您需要查询的域名,如:
  (1)crtsh:
  (2) 脸书:
  (3)委托:
  (4) 证书检测器:
  (5) 窥探:
  (6) 中央统计局:
  (7) 谷歌:
  2. 例行检查采集子域
  2.1 域名转移
  原则
  区域转移操作是指备服务器查询主服务器以刷新其区域数据库以确保数据一致性。此操作的目的是防止主名称服务器由于意外故障而变得不可用的全局影响。通常,只有在网络中有备用域名 DNS 服务器时,才需要进行 DNS 区域传输操作。一旦 DNS 服务器被错误配置为向任何发出请求的人提供区域数据库的副本,它就可能被攻击者利用。
  执行
  1.挖掘命令
  作为挖掘@axfr
  是提供数据的服务器,是要传输的关键字,axfr是区域传输选项。
  2.python中的dns库
  xfr = dns.query.xfr(where=server,zone=self.domain,timeout=5.0,lifetime=10.0)
  zone = dns.zone.from_xfr(xfr)
  这儿存在一个问题
  一般来说,如果DNS服务器配置正确、DNS传输被禁用或设置了白名单,漏洞利用成功的概率很低。
  2.2 站点配置文件
  原则
  信息泄露的主要问题是某个域名下的一些文件会存储一些相关的域名,比如子域。此类文件包括跨域策略文件crossdomain.xml、站点地图文件。
  执行
  创建文件列表,拼接域名后直接访问,判断修改后的文件是否存在。如果存在则提取数据,如果不存在则跳过。
  1.crossdomain.xml文件
  直接访问crossdomain.xml路径
  2.站点地图文件
  直接访问 sitemap.xml、sitemap.txt、sitemap.html、sitemapindex.xml、sitemapindex.xml 路径
  这儿存在一个问题
  文件往往不存在,即使存在,域名信息也不充分或不完整。
  2.3 检查内容安全策略
  原则
  内容安全策略 (CSP) 是一种声明性安全机制,它使 网站 操作员能够控制符合 CSP 的用户代理(通常是浏览器)的行为。通过控制启用哪些功能以及从何处下载内容,您可以减少 网站 的攻击面。CSP 的主要目的是防御跨站点脚本 (XSS) 攻击。例如,CSP 可以完全禁止内联 JavaScript 并控制从何处加载外部代码。它还可以禁用动态代码执行。禁用所有攻击源后,XSS 攻击变得更加困难。CSP 中的关键字是 default-src、img-src、object-src 和 script-src。其中,*-src 可能收录域名信息。
  执行
  1.手动抓包
  HTTP 标头的 Content-Security-Policy 属性
  2. Python的Requests获取
  导入请求
  res = requests.post(url=url, headers=headers, data=data, allow_redirects=False)
  如果不是 res.headers['Content-Security-Policy']:
  print("标头中没有 Content-Security-Policy")
  别的:
  # 进程主体代码
  2.4 使用DNS查询采集子域
  原则
  子域srv是通过枚举常见的SRV记录并进行查询来采集的,子域是通过查询域名的DNS记录中的MX、NS、SOA、TXT记录来采集的。
  SRV 记录
  这是在添加服务记录服务器时添加的服务记录,SRV记录哪台计算机提供了哪项服务。格式为:服务名称。协议的类型(例如:example-server.tcp)。
  以下命令枚举给定域名的 SRV 记录:
  nmap --script dns-srv-enum.nse --script-args "dns-srv-enum.domain=''"
  MX 记录
  要创建邮件服务,它会指向邮件服务器地址,并且需要设置 MX 记录。创建邮件地址时,一般根据邮件服务商提供的MX记录填写此记录。
  NS 记录
  域名解析服务器记录。如果要指定域名服务器解析子域,需要设置NS记录。
  SOA 记录
  
  SOA 称为起始权限记录,NS 用于标识多个域名解析服务器,SOA 记录用于标识众多 NS 记录中哪一个是主服务器。
  TXT 记录
  可以任意填写,可以为空。这个项目一般在做一些验证记录的时候用到,比如:SPF(anti-spam)记录。
  3. 利用 DNS 数据集采集子域
  使用 DNS 记录公开数据采集
  *注:将需要的{domain}替换为需要查询的域名,目标是我们认为更有效的。
  (1) ip138:
  {域}/domain.htm
  (2)百度云观察:
  {领域}
  (3) 黑客目标:
  (4) 谜语人:
  :{领域}
  (5) 缓冲:
  {领域}
  (6) dnsdb:
  {领域}
  (7) ipv4info:
  (8) 罗布特斯:
  (9)中国:
  (10) 网络技术:
  (11) dnsdumpster:
  (12) 网站档案:
  (13) 查找子域:
  4. 利用威胁情报平台数据采集子域
  *注:将需要的{domain}替换为需要查询的域名,以下平台需要注册,注册后免费试用
  (1) {domain}/{section}
  {section} 指其他命令和动作,API 的使用请参考文档。
  (2) {domain}/子域
  (3) {域名}
  API:域
  (4)
  {领域}
  (5) {domain}/子域
  或 {domain}/关系
  (6)
  #
  5.使用搜索引擎发现子域
  5.1 谷歌搜索语法——站点
  当使用站点提交查询时,Google 会将查询限制在某个网站/某个域。这个时候最好配合其他指令。例如,使用减号“-”排除不需要的数据。域名。
  5.2 站点:xxx *(目标IP)
  当我们得到子域的真实IP后,可以尝试搜索site:xxx*进行C段搜索,也可以通过这种方法找到很多其他有价值的相关域名。经过笔者的尝试,这种方法在搜狗和谷歌搜索引擎上都有效,谷歌搜索引擎效果更好。
  如图所示:
  6. 域名注册与资产归集
  原则
  在采集一些大型目标的信息时,您还可以通过查找域名注册信息,找到具有相同记录的其他域名资产。比如在采集qq的子域时,最常用的方法就是采集子域。此时,其他顶级域名资产将被遗漏。
  搜索网站:
  如上图所示,通过查看网站的记录/许可号,再逆向查看,可以找到其他具有相同记录的顶级域名资产。
  通过域名注册搜索具有相同记录的其他域名资产,可以更全面地采集目标资产信息,增加发现漏洞的概率。
  7.whois查询和关联查询
  工具:网站管理员工具
  这里我们将演示如何执行whois查询和反向检查
  7.1 查询whois
  7.2 查看whois
  **&amp;ddlSearchMode=1&amp;domain=
  获取相关域信息。
  8. 领域爆炸
  爆破的原理其实是通过枚举实现的,通过不断拼接字典的内容来枚举域名的A记录,但是这种方式一般需要解决泛解析的问题。
  比如开源工具oneforall会先随机访问一个不存在的域,通过返回结果来判断是否有泛解析。确认有泛解析后,程序会开始连续循环生成随机域名,去服务器查询,每次查询都会返回服务器。记录IP和TTL,直到大部分IP地址出现两次以上,IP黑名单采集结束。拿到IP黑名单后,oneforall再将其字典中的每一项与指定要查询的域名进行拼接。爆破过程中根据IP黑名单过滤。
  但是,这种广泛的过滤很容易导致漏报,因此 oneforall 也将 TTL 作为黑名单规则的一部分。判断依据是:在权威DNS中,泛解析记录的TTL必须相同。如果子域记录相同,但 TTL 不同,那么这条记录可以说绝对不是泛解析记录。
  优秀的开源工具
  我们研究了市面上的各种开源子域采集工具,列举了很多优秀工具的功能和优势。这是一个采集其子域的示例。简单比较每个工具的性能和效果。
  工具名称:oneforall
  
  项目地址:
  工具说明:
  oneforall 是近年来出现的比较好的子域采集工具之一,并且还在不断的更新和优化中。这个工具整合了各种域名信息采集的“姿势”,手段可谓非常全面。包括使用证书透明、例行检查、使用网络爬虫(进行中)、DNS数据集、DNS查询、威胁情报平台、搜索引擎等,但笔者发现其对域名泛解析的处理是不是特别理想,而且有很多错误。同时也存在消耗时间长等缺点。
  工具名称:SubdomainBrute
  项目地址:
  工具说明:
  李洁洁的SubdomainBrute是业内比较知名的子域名采集工具。该工具使用协程加速爆破速度,使用114DNS、百度DNS、阿里DNS查询快速可靠的公共DNS。精度高,效果更好。但是泛解析的处理规则是:如果超过10个域名指向同一个IP,则发现指向该IP的其他域名将被丢弃。这个方法可能会被误删,但不可否认,这个规则在一定程度上是有的。简单有效。
  工具名称:ESD
  项目地址:
  工具说明:
  ESD的爆破速度极快。62万条数据只需要4分30秒左右。该工具的缺点之一是它具有很高的性能要求。1G2核心服务器CPU使用率达到100%。另外,输出结果也比较不稳定。在同一网络下采集同一个域名时,结果的数量会出现数倍的变化。
  工具名称:子查找器
  项目地址:
  工具说明:
  使用subfinder采集子域信息,输出结果多,基数大,速度快,输出格式多,便于后续处理(oneforall也有同样的优点)。
  美中不足的是这个工具没有爆破功能,被动源比其他工具少。
  各种工具的效果比较
  每种工具的优缺点比较如下:
  *注:由于各个工具提供的默认字典不同,字典往往需要自己定义才能发挥更大的作用,所以各个工具下载后不修改,使用自己的默认字典进行爆破。使用单个域名测试并不通用,爆破结果仅供参考。
  从上图来看,单从数据层面来看,OneForAll在四大工具中表现突出,李洁洁的subdomainBrute也很优秀。可访问子域的百分比和时间非常好。域名相对较少。
  子域采集常见问题
  1.DNS缓存问题
  不同的DNS服务器可能有不同的缓存策略,也可能有不同的缓存结果,导致域名查询时解析结果没有及时更新。通常,解决上述问题需要多次 DNS 查询来强制 DNS 服务器刷新缓存以获得正确的结果。这无疑增加了泛分辨率判断和子域爆破的难度。
  事实上,这个问题在 OneForAll 中并没有得到很好的解决。在判断是否存在一般解析问题时,OneForAll 使用了函数detect_wildcard(domain, ns_ip_list)。在该函数中,OneForAll 使用不存在的子域名进行查询,判断是否有通用解析。但是只做一次决定是不够准确的,可能会导致误判。
  2.“刚性”词典
  爆破是子域采集方法的重要组成部分。对于这些工具中的大多数,字典的质量决定了最终的爆破效果。但大多数字典只是遍历字符集,使用常见的高频词,没有及时更新。当字典文件过大时,爆破速度变得很慢,效率低下的字典即使再大也达不到预期的效果。
  在实际的域名爆破中,能够自动更新的字典无疑会比普通的字典更好。在这里,我们提出了一种自动字典更新的方案。
  动态词典
  在本节中,我们更详细地描述自动字典更新的方案,可以分为三个步骤:更新词的权重➡️删除原创字典中权重低的词➡️从数据集中提取高频词和将它们添加到字典中,以更新字典。
  测试工具:Subdomainbrute
  流程图如下:
  1.体重更新
  首先使用工具subdomainbrute及其默认字典对子域进行爆破,并使用如下脚本对得到的结果进行进一步的批量检测,判断该域名是否可以被外网访问,并保存可以访问的域名一般是从外网到success.txt。
  接下来将mydic中单词的权重全部初始化为0。然后对比success.txt中的三级域名,mydic中对应单词的权重加1,其他单词的权重不变。另外,需要记录本次查询的域名。以后查询同一个域名时,mydic中词的权重不会重复更新。
  *注:mydic用于记录字典中的单词和对应的权重,格式如www,0
  2.单词删除
  使用字典爆破不同域名n次(例如20次)后,更新字典,即删除字典中的单词。具体步骤如下:
  首先,使用record_num.txt文件记录字典的使用次数。当record_num.txt文件不存在时,会生成。使用不同域名的每个查询+1。同一个域名的重复查询只算一次。
  每次程序运行后,判断是否需要reset mydic。如果需要更新,先删除record_num.txt文件,然后根据权重大小对mydic中的数据进行排序,排序后删除后30%的数据。
  3.词典更新
  删除原字典中30%的值后,需要向字典中添加新值。我们解析公共 DNS 记录以更新我们自己的字典。由于下载的数据集大小一般为几十G,直接处理比较困难,所以我们先对数据进行切分,降低处理难度。
  首先将数据集划分为每个100MB左右的数据文件,然后从这些数据文件中随机抽取一部分,将其中的所有子域提取出来,拼接到字典的“数据源”中. 对提取的子域数据进行词频分析,按照频率降序对内容进行排序。选择最频繁出现的值并将其添加到字典中,直到新字典与旧字典的大小相同。最后,新字典中所有值的权重需要清零。
  总结
  1.除了使用爆破工具,采集子域的方法还有很多。比如域名转移漏洞、DNS查询等常规手段,以及证书透明化、DNS数据集、威胁情报平台、搜索引擎、域名注册和whois查询的使用。总而言之,威胁情报平台在这些方法中表现最好,其次是证书透明度和 DNS 数据集。
  2.在这篇文章文章中,我们也研究和比较了几个业内优秀的工具。在子域的采集测试中,subfinder 和 OneForAll 表现更为突出。
  3.子域采集中的一些主要问题是域名泛解析,不同线路不同IP的解析,子域爆破时字典效率低。
  4、针对词典问题,提出了词典自动更新方案。
  网上采集子域的方法和工具有很多,但在实际使用中效果并不理想和全面。为了得到一个高效且有价值的子域列表,我们需要结合不同的方法,使用工具来合理的采集它们。
  为了方便在实战环境中使用,我们整理了大部分常用的方法,整合到这个文章中。作为学习记录,本文可能存在一些错误。如果有任何错误,请纠正我。希望大家和我们一起探索更多更高效的采集子域的方法,共同学习,共同进步。
  最后,还要感谢Leon和Xiaowu导师的帮助和指导。
  附录
  Google 证书透明度项目
  枚举子域
  DNS域名转移漏洞
  史上最全的子域采集方法:
  我们是台橡
  互联网安全卫士
  用户数据安全的捍卫者
  我们发现漏洞,检查入侵,防止攻击
  携手安防行业精英共建互联网生态安全
  期待您与我们的正能量联盟!
  seo站长工具 方法和技巧:SEO新手如何学起?
  SEO新手学习框架
  作为新手,起步阶段主要是搭建SEO基础知识的框架。而这些都可以通过各大搜索引擎初学者的指南文档获得。
  初学者指南
  百度搜索优化知识
  Google SEO 初学者指南
  掌握了这些基础知识体系之后,接下来就是通过实践来检验各种知识点的使用,还需要使用一些基础的SEO工具,包括各大搜索引擎百度、谷歌、必应等主流的站长工具,Yandex 、Naver等小语言;衍生产品插件:5118、爱站、Semrush、Moz、Ahrefs等。
  这可以通过在有SEO团队的公司中加入基础职位来完成,实战是检验知识的唯一标准。自建网站也是一种方式,毕竟搭建个人小网站的成本(包括资金投入和技术投入)已经很低了。
  同时,我们要时刻关注搜索引擎的发展变化和技术更新,不断更新自己的系统认知。
  各大引擎算法的历史和各大白皮书也应该熟悉和掌握。这就是大道所在,能在意识上形成正确的战略方向。
  算法更新历史和白皮书
  算法更新历史
  
  白皮书
  谷歌搜索中心
  百度白皮书:
  百度搜索页面质量标准规范
  百度APP移动搜索登陆页面体验白皮书5.0
  当然,一些灰帽子和黑帽子的技术也应该知道,也可以在自己的资源中做一些实验。但在服务型公司,除非公司有明确要求做黑帽,否则其他人坚决不尝试,毕竟SEO不是一日之功,这样做风险太大。
  竞品的研究也需要不断跟进,这会给你在SEO策略方案上一些启发。
  最后,SEO要成为高级点,必须经过几轮算法循环,对网站进行过多的操作。
  但归根结底,SEO只是一种吸引流量的手段,用它为服务公司和自身带来价值增长才是硬道理。但是SEO思维对我们有很大的积极影响。
  如果你喜欢SEO,就应该时刻保持好奇,不断学习,加强沟通,多做实战。
  以下谷歌seo信息学习博客供参考
  谷歌搜索最新消息
  
  搜索引擎期刊 SEO 专栏
  搜索引擎登陆SEO专栏
  SE圆桌
  以上就是整个SEO新手系统学习SEO的框架。
  为公司建立独立站做外贸的SEO新手
  在本节中,您可以先完善独立站基础SEO标签的基础SEO信息。你可以参考SEO新手指南,按照步骤练习。
  再次重申,关键词这个阶段的研究也很重要,可以使用指南配合google ads、Semrush等一些关键词研究工具配合竞争对手研究(可以搜索核心谷歌搜索中独立网站产品的词)排名前 20 位研究的结果)
  对整个独立站结构进行细化,站内部分首页列表页包括详情页。在选词策略上,关注首页列表页的核心词,详情页的长尾词。具体的内容结构侧重于对产品的理解和用户的需求。内容部署是其中之一,其二是看同类竞品词排名靠前的页面结构部署(意思是引擎通过user确定了用户最需要什么样的内容结构和内容行为),初步内容先做这个,然后根据用户反馈数据做进一步的调整。
  性能方面,可以参考站长工具后台网站的核心指标和人性化的体验进行相应的优化。
  我是Jesse,一个喜欢SEO研究的SEOer,一直在路上,欢迎交流。

详细描述:将ApiBoot Logging采集的日志上报到Admin

采集交流优采云 发表了文章 • 0 个评论 • 102 次浏览 • 2022-10-31 05:15 • 来自相关话题

  详细描述:将ApiBoot Logging采集的日志上报到Admin
  每个请求的详细信息可以通过 ApiBoot Logging 获取。在分布式部署方式中,一个请求可能会经过多个服务。如果每个服务独立保存请求日志信息,我们就无法实现统一控制。,并且会出现日志数据库和业务数据库不一致的情况(可能会使用多个数据源配置),因为这个问题,ApiBoot Logging提供了一个Admin概念,将客户端收到的每一条消息都转换成采集日志上报给管理员,管理员分析保存。
  创建一个日志管理项目
  由于ApiBoot Logging Admin可以汇总各个业务服务的请求日志(ApiBoot Logging),所以我们需要将各个业务服务采集订单的日志上报给Admin,所以应该独立部署。创建一个服务来专门采集请求日志并保存它们。
  初始化 Logging Admin 项目依赖项
  使用idea创建一个SpringBoot项目,pom.xml配置文件中的依赖如下:
  


org.springframework.boot
spring-boot-starter-web



org.minbox.framework
api-boot-starter-logging-admin



mysql
mysql-connector-java


com.zaxxer
HikariCP



org.minbox.framework
api-boot-starter-mybatis-enhance

  我们需要将采集的请求日志保存到数据库中,所以需要在项目中添加数据库驱动和数据库连接池相关的依赖。ApiBoot Logging Admin 通过 DataSource 操作数据,可以使用 ApiBoot MyBatis Enhance 的依赖。自动创建DataSource,摆脱手动创建,加入Spring IOC容器。
  添加 ApiBoot 统一版本依赖
  



org.minbox.framework
api-boot-dependencies
2.1.4.RELEASE
import
pom


  最新版本的 ApiBoot,请访问::api-boot-dependencies 查询。
  启用日志记录管理员
  添加 ApiBoot Logging Admin 依赖后,无法完全使用 Admin 功能。我们需要通过@EnableLoggingAdmin 注解来启用它,它会自动将Logging Admin 中需要的一些类注册到Spring IOC。将注解添加到入口类,如下所示:
  /**
* ApiBoot Logging Admin入口类
*/
@SpringBootApplication
@EnableLoggingAdmin
public class ApibootReportLogsByLoggingToAdminApplication {
public static void main(String[] args) {
SpringApplication.run(ApibootReportLogsByLoggingToAdminApplication.class, args);
}
}
  配置日志数据源
  application.yml配置文件中的数据源配置如下:
  # 服务名称
spring:
application:
name: apiboot-report-logs-by-logging-to-admin
# 数据源相关配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456
type: com.zaxxer.hikari.HikariDataSource
<p>
# 服务端口号
server:
port: 8081</p>
  控制台打印报告日志
  ApiBoot Logging Admin 可以通过配置文件控制是否将请求日志信息采集打印到控制台。在 application.yml 配置文件中添加以下内容:
  api:
boot:
logging:
# Logging Admin相关配置
admin:
# 控制台显示采集的日志信息
show-console-report-log: true
  注意:不要将此与 ApiBoot Logging 提供的 api.boot.logging.show-console-log 配置混淆。
  美化控制台打印的报表日志
  api:
boot:
logging:
# Logging Admin相关配置
admin:
# 控制台输出时美化采集到的日志
format-console-log-json: true
  注意:不要将此与 api.boot.logging.format-console-log-json 配置混淆。
  初始化日志表结构
  ApiBoot Logging Admin 使用固定的表结构来存储请求日志和服务信息。建表语句如下:
  SET NAMES utf8mb4 ;
--
-- Table structure for table `logging_request_logs`
--
CREATE TABLE `logging_request_logs` (
`lrl_id` varchar(36) COLLATE utf8mb4_general_ci NOT NULL COMMENT &#39;主键,UUID&#39;,
`lrl_service_detail_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;服务详情编号,关联logging_service_details主键&#39;,
`lrl_trace_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;链路ID&#39;,
`lrl_parent_span_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;上级跨度ID&#39;,
`lrl_span_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;跨度ID&#39;,
`lrl_start_time` mediumtext COLLATE utf8mb4_general_ci COMMENT &#39;请求开始时间&#39;,
`lrl_end_time` mediumtext COLLATE utf8mb4_general_ci COMMENT &#39;请求结束时间&#39;,
`lrl_http_status` int(11) DEFAULT NULL COMMENT &#39;请求响应状态码&#39;,
`lrl_request_body` longtext COLLATE utf8mb4_general_ci COMMENT &#39;请求主体内容&#39;,
`lrl_request_headers` text COLLATE utf8mb4_general_ci COMMENT &#39;请求头信息&#39;,
`lrl_request_ip` varchar(30) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;发起请求客户端的IP地址&#39;,
`lrl_request_method` varchar(10) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;请求方式&#39;,
`lrl_request_uri` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;请求路径&#39;,
`lrl_response_body` longtext COLLATE utf8mb4_general_ci COMMENT &#39;响应内容&#39;,
`lrl_response_headers` text COLLATE utf8mb4_general_ci COMMENT &#39;响应头信息&#39;,
`lrl_time_consuming` int(11) DEFAULT NULL COMMENT &#39;请求耗时&#39;,
`lrl_create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT &#39;日志保存时间&#39;,
`lrl_request_params` text COLLATE utf8mb4_general_ci,
`lrl_exception_stack` text COLLATE utf8mb4_general_ci,
PRIMARY KEY (`lrl_id`),
KEY `logging_request_logs_LRL_SERVICE_DETAIL_ID_index` (`lrl_service_detail_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT=&#39;请求日志信息表&#39;;
--
-- Table structure for table `logging_service_details`
--
CREATE TABLE `logging_service_details` (
`lsd_id` varchar(36) COLLATE utf8mb4_general_ci NOT NULL,
`lsd_service_id` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;上报服务的ID,对应spring.application.name配置值&#39;,
`lsd_service_ip` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;上报服务的IP地址&#39;,
`lsd_service_port` int(11) DEFAULT NULL COMMENT &#39;上报服务的端口号&#39;,
`lsd_last_report_time` timestamp NULL DEFAULT NULL COMMENT &#39;最后一次上报时间,每次上报更新&#39;,
`lsd_create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT &#39;首次上报时创建时间&#39;,
PRIMARY KEY (`lsd_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT=&#39;上报日志的客户端服务详情&#39;;
  到目前为止,ApiBoot Logging Admin 已准备就绪。接下来,我们需要修改业务服务,将请求日志上报给 Logging Admin。
  向指定的日志记录管理员报告日志
  我们将修改使用ApiBoot Logging统一管理请求日志的源码文章,在application.yml中添加Logging Admin的地址,如下图:
  api:
boot:
# ApiBoot Logging 日志组件配置
<p>
logging:
# 配置Logging Admin地址
admin:
server-address: 127.0.0.1:8081</p>
  api.boot.logging.admin-service-address的配置格式为:Ip:Port。我们只需要修改这个地方,其他的工作交给ApiBoot Logging内部完成。
  测试
  我们以Application的形式启动ApiBoot Logging Admin和业务服务。
  使用 curl 访问测试地址如下:
  ~ curl http://localhost:8080/test\?name\=admin
你好:admin
  我们查看 ApiBoot Logging 管理控制台日志如下:
  Receiving Service: 【apiboot-unified-manage-request-logs -> 127.0.0.1】, Request Log Report,Logging Content:[
{
"endTime":1571641723779,
"httpStatus":200,
"requestBody":"",
"requestHeaders":{
"server-region":"JiNan",
"host":"localhost:8080",
"user-agent":"curl/7.64.1",
"accept":"*/*"
},
"requestIp":"0:0:0:0:0:0:0:1",
"requestMethod":"GET",
"requestParam":"{\"name\":\"admin\"}",
"requestUri":"/test",
"responseBody":"你好:admin",
"responseHeaders":{},
"serviceId":"apiboot-unified-manage-request-logs",
"serviceIp":"127.0.0.1",
"servicePort":"8080",
"spanId":"95a73ca0-831b-45df-aa43-2b5887e8d98d",
"startTime":1571641723776,
"timeConsuming":3,
"traceId":"25a7de96-b3dd-48e5-9854-1a8069a4a681"
}
]
  我们看到了Logging Admin console打印的report request log,不确定这个request的log是否已经存入数据库。接下来,我使用命令行查看数据库的日志信息。
  查看 loggingservicedetails 表中的数据
  mysql> select * from logging_service_details\G;
*************************** 1. row ***************************
lsd_id: b069366a-25dc-41ec-8f09-242d81755cd0
lsd_service_id: apiboot-unified-manage-request-logs
lsd_service_ip: 10.180.98.112
lsd_service_port: 8080
lsd_last_report_time: 2019-10-21 02:14:26
lsd_create_time: 2019-10-21 15:14:26
  logging_service_details 存储了上报请求日志的各个业务服务的基本信息。每个基本服务信息都会缓存在Logging Admin内存中,方便获取存放日志的service_id,根据ip端口service_id判断唯一性。保存一次。
  查看 loggingrequestlogs 表中的数据
  mysql> select * from logging_request_logs\G;
*************************** 1. row ***************************
lrl_id: c42761f6-b072-4744-8a17-d8e6097b85de
lrl_service_detail_id: b069366a-25dc-41ec-8f09-242d81755cd0
lrl_trace_id: 055329a0-cfc1-4606-baf0-4fb0cc905ba2
lrl_parent_span_id: NULL
lrl_span_id: aab83092-7749-4f88-8cb6-a949cc060197
lrl_start_time: 1571642065262
lrl_end_time: 1571642065286
lrl_http_status: 200
lrl_request_body:
lrl_request_headers: {"server-region":"JiNan","host":"localhost:8080","user-agent":"curl/7.64.1","accept":"*/*"}
lrl_request_ip: 0:0:0:0:0:0:0:1
lrl_request_method: GET
lrl_request_uri: /test
lrl_response_body: 你好:admin
lrl_response_headers: {}
lrl_time_consuming: 24
lrl_create_time: 2019-10-21 15:14:26
lrl_request_params: {"name":"admin"}
lrl_exception_stack: NULL
  敲黑板画重点
  在本章中,我们集成了ApiBoot Logging Admin,将业务服务的每个请求日志上报给Logging Admin,通过数据库保存请求日志,然后使用其他方法,可以通过spanId和traceId查看每个日志的日志-请求链路的从属关系和每个请求中耗时最多的span,可以准确优化服务性能。
  作者的个人博客
  使用开源框架ApiBoot,助你成为Api接口服务架构师
  总结:一篇文章看懂SEO,完整SEO优化方案,SEO是什么,网站如何进行SEO
  一篇文章文章了解SEO,完整的SEO优化方案,什么是SEO,网站怎么做SEO
  前言:今天的文章文章是我这几天写的最满意的一篇。之前一直在整理自己的想法,不是很满意。
  个人站长是个很努力的人,需要全方位的前端技术,要网站编辑、对外推广和数据分析。一个完整的网站应该从一开始就制作出来,后期的SEO推广部分也要考虑,这也是站长必备的技能。
  一个网站 SEO应该包括四个主要环节:网站前端制作、网站编辑、网站推广、数据分析。当然,这是一个笼统的说法。
  一、第一部分,前端制作。第一点,一个网站策划前期,要做好网站扁平化结构,各种辅助导航,内容页面需要有相关的文章建议,简短的页面结构,尽可能多的有效部分。网站代码优化第二点、robots文件、二级导航设置、404模板设置、301重定向、网站地图、图片Alt、标题标签、网站TDK、关键词密度、个体关键字密度、H1H2H3 中的关键字、关键字强调、向反向链接添加 nofollow、向页面添加元标记、丰富的片段(微数据、微格式和 RDFa)。
  
  第二部分,网站编辑工作。需要确定文章、原创或伪原创的来源,扫描的秘书、报纸、杂志等都可以作为文章的来源。然后是文章内容的写法,标题怎么写,关键词怎么布局,第一个描述性文章怎么写。何时何地添加什么样的长尾 关键词。内页的锚文本设置和图片的alt属性都是网站编辑的工作。
  第三部分是网站的SEO外推,即发送外链。外部链接强调高质量,不发送垃圾外部链接。外链的主要渠道包括:友情链接、博客、论坛、采集、黄页等,如果能发百度知道、百度文库、百度体验等,当然是最好的,对于国内的百度SEO,这是最重要的外部链接资源。
  
  第四部分是数据分析。流量统计工具看个人喜好,百度统计,CNZZ等,可以分析来源关键词,用户访问路径,用户热点击图等。第二点是竞争对手分析,分析竞争对手的关键词文章 写的,外部链接怎么发,关键词怎么设置,内部链接怎么布局,网站的结构是什么,文章是什么发布频率、网站结构等方面。
  综合阐述:一个网站最核心的SEO就是关键词的排名,所以关键词是一个很重要的工作,目标关键词,品牌关键词、核心关键词的选择&gt;、长尾关键词、长尾关键词的挖掘,需要挖掘什么样的长尾关键词,以及如何点击长尾 关键词。这里推荐几种常用的关键词挖矿方法,非常实用。百度索引、百度下拉框、百度相关搜索、百度知道、百度站长工具、各大SEO优化分析平台
  写到这里,已经完成了一个完善权缺的优化方案,能提到的点已经尽量提了,具体的实现还需要稍微完善一下。里面讲的东西的要点可以看的透彻,一些基础的SEO已经可以很厉害了。比较满意的文章结束了。接下来,我会写下每个实现的细节,敬请期待! 查看全部

  详细描述:将ApiBoot Logging采集的日志上报到Admin
  每个请求的详细信息可以通过 ApiBoot Logging 获取。在分布式部署方式中,一个请求可能会经过多个服务。如果每个服务独立保存请求日志信息,我们就无法实现统一控制。,并且会出现日志数据库和业务数据库不一致的情况(可能会使用多个数据源配置),因为这个问题,ApiBoot Logging提供了一个Admin概念,将客户端收到的每一条消息都转换成采集日志上报给管理员,管理员分析保存。
  创建一个日志管理项目
  由于ApiBoot Logging Admin可以汇总各个业务服务的请求日志(ApiBoot Logging),所以我们需要将各个业务服务采集订单的日志上报给Admin,所以应该独立部署。创建一个服务来专门采集请求日志并保存它们。
  初始化 Logging Admin 项目依赖项
  使用idea创建一个SpringBoot项目,pom.xml配置文件中的依赖如下:
  


org.springframework.boot
spring-boot-starter-web



org.minbox.framework
api-boot-starter-logging-admin



mysql
mysql-connector-java


com.zaxxer
HikariCP



org.minbox.framework
api-boot-starter-mybatis-enhance

  我们需要将采集的请求日志保存到数据库中,所以需要在项目中添加数据库驱动和数据库连接池相关的依赖。ApiBoot Logging Admin 通过 DataSource 操作数据,可以使用 ApiBoot MyBatis Enhance 的依赖。自动创建DataSource,摆脱手动创建,加入Spring IOC容器。
  添加 ApiBoot 统一版本依赖
  



org.minbox.framework
api-boot-dependencies
2.1.4.RELEASE
import
pom


  最新版本的 ApiBoot,请访问::api-boot-dependencies 查询。
  启用日志记录管理员
  添加 ApiBoot Logging Admin 依赖后,无法完全使用 Admin 功能。我们需要通过@EnableLoggingAdmin 注解来启用它,它会自动将Logging Admin 中需要的一些类注册到Spring IOC。将注解添加到入口类,如下所示:
  /**
* ApiBoot Logging Admin入口类
*/
@SpringBootApplication
@EnableLoggingAdmin
public class ApibootReportLogsByLoggingToAdminApplication {
public static void main(String[] args) {
SpringApplication.run(ApibootReportLogsByLoggingToAdminApplication.class, args);
}
}
  配置日志数据源
  application.yml配置文件中的数据源配置如下:
  # 服务名称
spring:
application:
name: apiboot-report-logs-by-logging-to-admin
# 数据源相关配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456
type: com.zaxxer.hikari.HikariDataSource
<p>
# 服务端口号
server:
port: 8081</p>
  控制台打印报告日志
  ApiBoot Logging Admin 可以通过配置文件控制是否将请求日志信息采集打印到控制台。在 application.yml 配置文件中添加以下内容:
  api:
boot:
logging:
# Logging Admin相关配置
admin:
# 控制台显示采集的日志信息
show-console-report-log: true
  注意:不要将此与 ApiBoot Logging 提供的 api.boot.logging.show-console-log 配置混淆。
  美化控制台打印的报表日志
  api:
boot:
logging:
# Logging Admin相关配置
admin:
# 控制台输出时美化采集到的日志
format-console-log-json: true
  注意:不要将此与 api.boot.logging.format-console-log-json 配置混淆。
  初始化日志表结构
  ApiBoot Logging Admin 使用固定的表结构来存储请求日志和服务信息。建表语句如下:
  SET NAMES utf8mb4 ;
--
-- Table structure for table `logging_request_logs`
--
CREATE TABLE `logging_request_logs` (
`lrl_id` varchar(36) COLLATE utf8mb4_general_ci NOT NULL COMMENT &#39;主键,UUID&#39;,
`lrl_service_detail_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;服务详情编号,关联logging_service_details主键&#39;,
`lrl_trace_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;链路ID&#39;,
`lrl_parent_span_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;上级跨度ID&#39;,
`lrl_span_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;跨度ID&#39;,
`lrl_start_time` mediumtext COLLATE utf8mb4_general_ci COMMENT &#39;请求开始时间&#39;,
`lrl_end_time` mediumtext COLLATE utf8mb4_general_ci COMMENT &#39;请求结束时间&#39;,
`lrl_http_status` int(11) DEFAULT NULL COMMENT &#39;请求响应状态码&#39;,
`lrl_request_body` longtext COLLATE utf8mb4_general_ci COMMENT &#39;请求主体内容&#39;,
`lrl_request_headers` text COLLATE utf8mb4_general_ci COMMENT &#39;请求头信息&#39;,
`lrl_request_ip` varchar(30) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;发起请求客户端的IP地址&#39;,
`lrl_request_method` varchar(10) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;请求方式&#39;,
`lrl_request_uri` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;请求路径&#39;,
`lrl_response_body` longtext COLLATE utf8mb4_general_ci COMMENT &#39;响应内容&#39;,
`lrl_response_headers` text COLLATE utf8mb4_general_ci COMMENT &#39;响应头信息&#39;,
`lrl_time_consuming` int(11) DEFAULT NULL COMMENT &#39;请求耗时&#39;,
`lrl_create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT &#39;日志保存时间&#39;,
`lrl_request_params` text COLLATE utf8mb4_general_ci,
`lrl_exception_stack` text COLLATE utf8mb4_general_ci,
PRIMARY KEY (`lrl_id`),
KEY `logging_request_logs_LRL_SERVICE_DETAIL_ID_index` (`lrl_service_detail_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT=&#39;请求日志信息表&#39;;
--
-- Table structure for table `logging_service_details`
--
CREATE TABLE `logging_service_details` (
`lsd_id` varchar(36) COLLATE utf8mb4_general_ci NOT NULL,
`lsd_service_id` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;上报服务的ID,对应spring.application.name配置值&#39;,
`lsd_service_ip` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;上报服务的IP地址&#39;,
`lsd_service_port` int(11) DEFAULT NULL COMMENT &#39;上报服务的端口号&#39;,
`lsd_last_report_time` timestamp NULL DEFAULT NULL COMMENT &#39;最后一次上报时间,每次上报更新&#39;,
`lsd_create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT &#39;首次上报时创建时间&#39;,
PRIMARY KEY (`lsd_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT=&#39;上报日志的客户端服务详情&#39;;
  到目前为止,ApiBoot Logging Admin 已准备就绪。接下来,我们需要修改业务服务,将请求日志上报给 Logging Admin。
  向指定的日志记录管理员报告日志
  我们将修改使用ApiBoot Logging统一管理请求日志的源码文章,在application.yml中添加Logging Admin的地址,如下图:
  api:
boot:
# ApiBoot Logging 日志组件配置
<p>
logging:
# 配置Logging Admin地址
admin:
server-address: 127.0.0.1:8081</p>
  api.boot.logging.admin-service-address的配置格式为:Ip:Port。我们只需要修改这个地方,其他的工作交给ApiBoot Logging内部完成。
  测试
  我们以Application的形式启动ApiBoot Logging Admin和业务服务。
  使用 curl 访问测试地址如下:
  ~ curl http://localhost:8080/test\?name\=admin
你好:admin
  我们查看 ApiBoot Logging 管理控制台日志如下:
  Receiving Service: 【apiboot-unified-manage-request-logs -> 127.0.0.1】, Request Log Report,Logging Content:[
{
"endTime":1571641723779,
"httpStatus":200,
"requestBody":"",
"requestHeaders":{
"server-region":"JiNan",
"host":"localhost:8080",
"user-agent":"curl/7.64.1",
"accept":"*/*"
},
"requestIp":"0:0:0:0:0:0:0:1",
"requestMethod":"GET",
"requestParam":"{\"name\":\"admin\"}",
"requestUri":"/test",
"responseBody":"你好:admin",
"responseHeaders":{},
"serviceId":"apiboot-unified-manage-request-logs",
"serviceIp":"127.0.0.1",
"servicePort":"8080",
"spanId":"95a73ca0-831b-45df-aa43-2b5887e8d98d",
"startTime":1571641723776,
"timeConsuming":3,
"traceId":"25a7de96-b3dd-48e5-9854-1a8069a4a681"
}
]
  我们看到了Logging Admin console打印的report request log,不确定这个request的log是否已经存入数据库。接下来,我使用命令行查看数据库的日志信息。
  查看 loggingservicedetails 表中的数据
  mysql> select * from logging_service_details\G;
*************************** 1. row ***************************
lsd_id: b069366a-25dc-41ec-8f09-242d81755cd0
lsd_service_id: apiboot-unified-manage-request-logs
lsd_service_ip: 10.180.98.112
lsd_service_port: 8080
lsd_last_report_time: 2019-10-21 02:14:26
lsd_create_time: 2019-10-21 15:14:26
  logging_service_details 存储了上报请求日志的各个业务服务的基本信息。每个基本服务信息都会缓存在Logging Admin内存中,方便获取存放日志的service_id,根据ip端口service_id判断唯一性。保存一次。
  查看 loggingrequestlogs 表中的数据
  mysql> select * from logging_request_logs\G;
*************************** 1. row ***************************
lrl_id: c42761f6-b072-4744-8a17-d8e6097b85de
lrl_service_detail_id: b069366a-25dc-41ec-8f09-242d81755cd0
lrl_trace_id: 055329a0-cfc1-4606-baf0-4fb0cc905ba2
lrl_parent_span_id: NULL
lrl_span_id: aab83092-7749-4f88-8cb6-a949cc060197
lrl_start_time: 1571642065262
lrl_end_time: 1571642065286
lrl_http_status: 200
lrl_request_body:
lrl_request_headers: {"server-region":"JiNan","host":"localhost:8080","user-agent":"curl/7.64.1","accept":"*/*"}
lrl_request_ip: 0:0:0:0:0:0:0:1
lrl_request_method: GET
lrl_request_uri: /test
lrl_response_body: 你好:admin
lrl_response_headers: {}
lrl_time_consuming: 24
lrl_create_time: 2019-10-21 15:14:26
lrl_request_params: {"name":"admin"}
lrl_exception_stack: NULL
  敲黑板画重点
  在本章中,我们集成了ApiBoot Logging Admin,将业务服务的每个请求日志上报给Logging Admin,通过数据库保存请求日志,然后使用其他方法,可以通过spanId和traceId查看每个日志的日志-请求链路的从属关系和每个请求中耗时最多的span,可以准确优化服务性能。
  作者的个人博客
  使用开源框架ApiBoot,助你成为Api接口服务架构师
  总结:一篇文章看懂SEO,完整SEO优化方案,SEO是什么,网站如何进行SEO
  一篇文章文章了解SEO,完整的SEO优化方案,什么是SEO,网站怎么做SEO
  前言:今天的文章文章是我这几天写的最满意的一篇。之前一直在整理自己的想法,不是很满意。
  个人站长是个很努力的人,需要全方位的前端技术,要网站编辑、对外推广和数据分析。一个完整的网站应该从一开始就制作出来,后期的SEO推广部分也要考虑,这也是站长必备的技能。
  一个网站 SEO应该包括四个主要环节:网站前端制作、网站编辑、网站推广、数据分析。当然,这是一个笼统的说法。
  一、第一部分,前端制作。第一点,一个网站策划前期,要做好网站扁平化结构,各种辅助导航,内容页面需要有相关的文章建议,简短的页面结构,尽可能多的有效部分。网站代码优化第二点、robots文件、二级导航设置、404模板设置、301重定向、网站地图、图片Alt、标题标签、网站TDK、关键词密度、个体关键字密度、H1H2H3 中的关键字、关键字强调、向反向链接添加 nofollow、向页面添加元标记、丰富的片段(微数据、微格式和 RDFa)。
  
  第二部分,网站编辑工作。需要确定文章、原创或伪原创的来源,扫描的秘书、报纸、杂志等都可以作为文章的来源。然后是文章内容的写法,标题怎么写,关键词怎么布局,第一个描述性文章怎么写。何时何地添加什么样的长尾 关键词。内页的锚文本设置和图片的alt属性都是网站编辑的工作。
  第三部分是网站的SEO外推,即发送外链。外部链接强调高质量,不发送垃圾外部链接。外链的主要渠道包括:友情链接、博客、论坛、采集、黄页等,如果能发百度知道、百度文库、百度体验等,当然是最好的,对于国内的百度SEO,这是最重要的外部链接资源。
  
  第四部分是数据分析。流量统计工具看个人喜好,百度统计,CNZZ等,可以分析来源关键词,用户访问路径,用户热点击图等。第二点是竞争对手分析,分析竞争对手的关键词文章 写的,外部链接怎么发,关键词怎么设置,内部链接怎么布局,网站的结构是什么,文章是什么发布频率、网站结构等方面。
  综合阐述:一个网站最核心的SEO就是关键词的排名,所以关键词是一个很重要的工作,目标关键词,品牌关键词、核心关键词的选择&gt;、长尾关键词、长尾关键词的挖掘,需要挖掘什么样的长尾关键词,以及如何点击长尾 关键词。这里推荐几种常用的关键词挖矿方法,非常实用。百度索引、百度下拉框、百度相关搜索、百度知道、百度站长工具、各大SEO优化分析平台
  写到这里,已经完成了一个完善权缺的优化方案,能提到的点已经尽量提了,具体的实现还需要稍微完善一下。里面讲的东西的要点可以看的透彻,一些基础的SEO已经可以很厉害了。比较满意的文章结束了。接下来,我会写下每个实现的细节,敬请期待!

优化的解决方案:API开发接口whatsapp采集工具之“好选客”

采集交流优采云 发表了文章 • 0 个评论 • 108 次浏览 • 2022-10-30 06:11 • 来自相关话题

  优化的解决方案:API开发接口whatsapp采集工具之“好选客”
  
  什么是APINet 这是一个用C#编写的API,但它可以在任何.NET语言中使用。它是WhatsAPINet的一个分支,基于WhatsAPI。这个分支的目标是让它再次工作并重构代码,添加文档并编写有关Whatsapp如何工作的文档。文档 FunXMPP 协议 - 协议 不幸的是,WhatsApp协议没有正式记录。在处理这个项目时,我将尝试将我的大部分进度记录在 docs 文件夹中。该协议基于基于 XML 的 XMPP 协议,这是一种记录严格的互联网消息传递协议。若要减少 XML 开销,请将 XML 结构和许多常用关键字转换为字节。有关更详细的说明,请参阅 docs/funxmpp .txt。不幸的是,XMPP标准并不是在所有地方都严格遵守。协议包装器:FunXMPP (见维基) 主协议:XMPP ( ) 身份验证
  
  解决方案:行业之星自助建站系统 osunit1.0 build20120905
  行业之星网站建站系统是一个多用户自助建站系统。它改变了以往企业网站建设的传统方式。它不需要企业编写任何程序或网页,不需要学习任何相关语言,也不需要第三方代表。编写或管理网站,只要会打字,就可以直接在线完成建站的所有工作。
  同时,系统为开源软件,客户可以随时要求第三方检查系统的安全性。
  行业之星免费开源多用户企业自助建站系统
  OSUnit V0.10 版本号:osunit1.020120905 下载&gt;&gt;
  特征:
  1、多用户自助建站系统(用户可申请自己的独立域名)
  2.日常维护栏和导航栏可以完全自定义
  3. 网站模板可编辑修改
  4.支持伪静态(需要apache环境)
  5. 将 文章 与产品相关联的 TAG
  6. 文章附属调查
  7、产品销售、经销商历史报价记录
  8. 经销商网站
  9. 品牌列表
  10、代理推广网站
  11.其他常规cms功能:发表评论、点赞、转发、图库
  12. 会员管理
  安装方法:
  
  1.上传文件到你需要安装的目录
  2.如果是linux系统修改
  config.inc.php 是 777 权限
  以下目录有 777 权限:
  图片 777
  模板 777
  主题 777
  数据 777
  3.执行简单的安装程序:******/install
  4.linux安装后修改data/config.inc.php为744权限
  5.如果要使用伪静态,请相应修改.htaccess文件对应的程序目录名
  apache启用伪静态方法:
  1.查看apache配置文件httpd.conf
  #LoadModule rewrite_module modules/mod_rewrite.so
  变成:
  LoadModule rewrite_module modules/mod_rewrite.so
  2. 虚拟主机
  服务器管理员
  DocumentRoot "e:/test"
  
  服务器名称
  服务器别名*。
  选项索引 FollowSymLinks
  允许覆盖所有
  命令允许,拒绝
  允许所有人
  其他说明:
  1.运行环境:php5+mysql
  2.字符集编码:utf8
  3.配置文件为:data/config.inc.php
  4.模板目录主题
  * 项目介绍:
  * ------------------------------------------------- --------------------------------------
  *版权归osunit所有,保留所有权利。
  * 网站地址:
  * ------------------------------------------------- --------------------------------------
  * 这是一个免费的开源软件;您可以在没有商业用途的情况下使用程序代码
  * 可能会被修改、使用和重新分发。 查看全部

  优化的解决方案:API开发接口whatsapp采集工具之“好选客”
  
  什么是APINet 这是一个用C#编写的API,但它可以在任何.NET语言中使用。它是WhatsAPINet的一个分支,基于WhatsAPI。这个分支的目标是让它再次工作并重构代码,添加文档并编写有关Whatsapp如何工作的文档。文档 FunXMPP 协议 - 协议 不幸的是,WhatsApp协议没有正式记录。在处理这个项目时,我将尝试将我的大部分进度记录在 docs 文件夹中。该协议基于基于 XML 的 XMPP 协议,这是一种记录严格的互联网消息传递协议。若要减少 XML 开销,请将 XML 结构和许多常用关键字转换为字节。有关更详细的说明,请参阅 docs/funxmpp .txt。不幸的是,XMPP标准并不是在所有地方都严格遵守。协议包装器:FunXMPP (见维基) 主协议:XMPP ( ) 身份验证
  
  解决方案:行业之星自助建站系统 osunit1.0 build20120905
  行业之星网站建站系统是一个多用户自助建站系统。它改变了以往企业网站建设的传统方式。它不需要企业编写任何程序或网页,不需要学习任何相关语言,也不需要第三方代表。编写或管理网站,只要会打字,就可以直接在线完成建站的所有工作。
  同时,系统为开源软件,客户可以随时要求第三方检查系统的安全性。
  行业之星免费开源多用户企业自助建站系统
  OSUnit V0.10 版本号:osunit1.020120905 下载&gt;&gt;
  特征:
  1、多用户自助建站系统(用户可申请自己的独立域名)
  2.日常维护栏和导航栏可以完全自定义
  3. 网站模板可编辑修改
  4.支持伪静态(需要apache环境)
  5. 将 文章 与产品相关联的 TAG
  6. 文章附属调查
  7、产品销售、经销商历史报价记录
  8. 经销商网站
  9. 品牌列表
  10、代理推广网站
  11.其他常规cms功能:发表评论、点赞、转发、图库
  12. 会员管理
  安装方法:
  
  1.上传文件到你需要安装的目录
  2.如果是linux系统修改
  config.inc.php 是 777 权限
  以下目录有 777 权限:
  图片 777
  模板 777
  主题 777
  数据 777
  3.执行简单的安装程序:******/install
  4.linux安装后修改data/config.inc.php为744权限
  5.如果要使用伪静态,请相应修改.htaccess文件对应的程序目录名
  apache启用伪静态方法:
  1.查看apache配置文件httpd.conf
  #LoadModule rewrite_module modules/mod_rewrite.so
  变成:
  LoadModule rewrite_module modules/mod_rewrite.so
  2. 虚拟主机
  服务器管理员
  DocumentRoot "e:/test"
  
  服务器名称
  服务器别名*。
  选项索引 FollowSymLinks
  允许覆盖所有
  命令允许,拒绝
  允许所有人
  其他说明:
  1.运行环境:php5+mysql
  2.字符集编码:utf8
  3.配置文件为:data/config.inc.php
  4.模板目录主题
  * 项目介绍:
  * ------------------------------------------------- --------------------------------------
  *版权归osunit所有,保留所有权利。
  * 网站地址:
  * ------------------------------------------------- --------------------------------------
  * 这是一个免费的开源软件;您可以在没有商业用途的情况下使用程序代码
  * 可能会被修改、使用和重新分发。

免费提供:免费wordpress采集发布管理器,操作极简

采集交流优采云 发表了文章 • 0 个评论 • 134 次浏览 • 2022-10-29 20:29 • 来自相关话题

  免费提供:免费wordpress采集发布管理器,操作极简
  wordpress资源下载管理器可以方便我们下载和管理公共开源数据。免费的wordpress资源下载管理器操作体验简单,只要点击我们需要的内容,无论是链接、图片、视频还是文字。都可以批量采集、批量编辑、批量发布或批量导出到本地。
  如果WordPress把我们喜欢的资源下载下来应用到我们自己的WordPress网站上,对于新闻和行业网站,我们可以根据行业关键词下载和管理全网文章。对于小说和影视,我们可以输入我们的目标网址,通过批量识别我们的下载链接或api进行爬取。方便的可视化操作让我们可以方便地管理我们的资源。
  WordPress资源下载管理器还具有批量图片处理、文章清理批量SEO等功能。拥有自己的WordPress网站可以有利于我们的推广工作,因为它让用户更容易发现我们在线业务。此外,它是一个有用的工具,可以在我们的行业中树立自己的名声并提高我们的转化率。WordPress网站 还使我们能够与我们的受众建立更加个性化的联系,并表明 网站 会定期更新内容。
  
  除了资源下载、文章SEO等数据文章获取处理功能,WordPress资源下载管理器还具有自动批量伪原创发布、主动链接推送到搜索引擎、内部链接抓取、内链收录查询等站长SEO功能。它不仅有利于我们优化 WordPress网站,还可以根据反馈数据实时调整我们的 SEO 实践。
  大多数网站 构建平台让我们只需单击一下即可为该网站 创建一个丰富的WordPress网站 页面,这意味着我们所要做的就是定期使用帖子并用图片填充它。如果我们想了解访问者对阅读的兴趣,我们需要对关键问题进行一些深入的研究。
  网络提供了各种免费的在线实用程序,例如搜索引擎趋势和公共问题的答案,它们显示了特定关键字的搜索量如何随时间变化。我们可以使用这些统计数据来确定哪些关键字应该在我们的 WordPress 网站 中获得最多的关注。
  
  来宾 WordPress 网站 涉及为其他 网站 撰写帖子,以将我们的品牌展示给新的受众,并通过创建从来宾帖子到我们的 网站 的反向链接来提升我们的 SEO。反向链接是有价值的 SEO 工具。因为它们向搜索引擎展示了其他 网站 认为我们是特定领域或行业的专家。
  寻找与我们领域相关的其他已建立的网站,研究每个 WordPress 上使用的语气网站选择您要撰写的 WordPress网站 后,您需要通过电子邮件或社交媒体进行连接跟他们。在我们撰写推介之前,最好阅读尽可能多的 WordPress网站 内容,以确保我们彼此非常适合并清楚地了解他们的写作风格。接下来,建议我们提出至少 3 个帖子创意发送给他们的编辑团队。每个想法都应该包括一个标题和一个 200 字的摘要。
  WordPress资源下载管理器可以方便的管理我们的WordPress,并且支持多个下载任务和每栏的自动更新。通过管理器可以实现同屏管理,快速更新网站的内容。wordpress资源下载管理器的分享就到这里了。如果你喜欢它,你不妨点击三个链接。
  解决方案:抖音商家采集软件
  如何快速轻松地采集抖音数据?
  抖音 数据采集软件PC版产品详细介绍
  1. 软件功能
  1. 基于抖音的公开数据采集。
  2.内置数据库保存采集数据,支持数十万数据,支持数据库中的重复数据删除,即采集到数据库的数据不会重复。
  3.多种采集算法,采集更多数据。
  
  4.数据记忆功能,意外关闭或下次打开时数据仍然存在。
  5.一键导出到CSV,EXCEL,VCF等文件。
  6.VCF文件可以导入手机通讯录,方便快捷。
  7.实时采集,而不是您自己的数据库。
  8.支持Windows操作系统,如Win7和Win10
  2. 使用帮助
  1. 点击 [登录抖音/快手]。
  2、点击登录,扫码登录抖音/快手。
  
  3. 单击关闭窗口。
  4. 点击主屏幕上的 [开始采集。
  5.关于防病毒软件的误报,
  由于软件保护,某些防病毒软件会出现误报,如拦截,请允许。建议使用火种安全。
  6.支持导出到VCF文件,
  VCF文件是标准的手机通讯录格式文件,可以导入到手机通讯录中。方法是通过QQ将VCF文件传输到手机上,点击打开VCF文件,选择用手机通讯录打开,根据提示导入。
  7. 搜索关键词最好是行业关键词。一次可以输入多个单词,每行一个单词,并且不能输入标点符号。 查看全部

  免费提供:免费wordpress采集发布管理器,操作极简
  wordpress资源下载管理器可以方便我们下载和管理公共开源数据。免费的wordpress资源下载管理器操作体验简单,只要点击我们需要的内容,无论是链接、图片、视频还是文字。都可以批量采集、批量编辑、批量发布或批量导出到本地。
  如果WordPress把我们喜欢的资源下载下来应用到我们自己的WordPress网站上,对于新闻和行业网站,我们可以根据行业关键词下载和管理全网文章。对于小说和影视,我们可以输入我们的目标网址,通过批量识别我们的下载链接或api进行爬取。方便的可视化操作让我们可以方便地管理我们的资源。
  WordPress资源下载管理器还具有批量图片处理、文章清理批量SEO等功能。拥有自己的WordPress网站可以有利于我们的推广工作,因为它让用户更容易发现我们在线业务。此外,它是一个有用的工具,可以在我们的行业中树立自己的名声并提高我们的转化率。WordPress网站 还使我们能够与我们的受众建立更加个性化的联系,并表明 网站 会定期更新内容。
  
  除了资源下载、文章SEO等数据文章获取处理功能,WordPress资源下载管理器还具有自动批量伪原创发布、主动链接推送到搜索引擎、内部链接抓取、内链收录查询等站长SEO功能。它不仅有利于我们优化 WordPress网站,还可以根据反馈数据实时调整我们的 SEO 实践。
  大多数网站 构建平台让我们只需单击一下即可为该网站 创建一个丰富的WordPress网站 页面,这意味着我们所要做的就是定期使用帖子并用图片填充它。如果我们想了解访问者对阅读的兴趣,我们需要对关键问题进行一些深入的研究。
  网络提供了各种免费的在线实用程序,例如搜索引擎趋势和公共问题的答案,它们显示了特定关键字的搜索量如何随时间变化。我们可以使用这些统计数据来确定哪些关键字应该在我们的 WordPress 网站 中获得最多的关注。
  
  来宾 WordPress 网站 涉及为其他 网站 撰写帖子,以将我们的品牌展示给新的受众,并通过创建从来宾帖子到我们的 网站 的反向链接来提升我们的 SEO。反向链接是有价值的 SEO 工具。因为它们向搜索引擎展示了其他 网站 认为我们是特定领域或行业的专家。
  寻找与我们领域相关的其他已建立的网站,研究每个 WordPress 上使用的语气网站选择您要撰写的 WordPress网站 后,您需要通过电子邮件或社交媒体进行连接跟他们。在我们撰写推介之前,最好阅读尽可能多的 WordPress网站 内容,以确保我们彼此非常适合并清楚地了解他们的写作风格。接下来,建议我们提出至少 3 个帖子创意发送给他们的编辑团队。每个想法都应该包括一个标题和一个 200 字的摘要。
  WordPress资源下载管理器可以方便的管理我们的WordPress,并且支持多个下载任务和每栏的自动更新。通过管理器可以实现同屏管理,快速更新网站的内容。wordpress资源下载管理器的分享就到这里了。如果你喜欢它,你不妨点击三个链接。
  解决方案:抖音商家采集软件
  如何快速轻松地采集抖音数据?
  抖音 数据采集软件PC版产品详细介绍
  1. 软件功能
  1. 基于抖音的公开数据采集。
  2.内置数据库保存采集数据,支持数十万数据,支持数据库中的重复数据删除,即采集到数据库的数据不会重复。
  3.多种采集算法,采集更多数据。
  
  4.数据记忆功能,意外关闭或下次打开时数据仍然存在。
  5.一键导出到CSV,EXCEL,VCF等文件。
  6.VCF文件可以导入手机通讯录,方便快捷。
  7.实时采集,而不是您自己的数据库。
  8.支持Windows操作系统,如Win7和Win10
  2. 使用帮助
  1. 点击 [登录抖音/快手]。
  2、点击登录,扫码登录抖音/快手。
  
  3. 单击关闭窗口。
  4. 点击主屏幕上的 [开始采集。
  5.关于防病毒软件的误报,
  由于软件保护,某些防病毒软件会出现误报,如拦截,请允许。建议使用火种安全。
  6.支持导出到VCF文件,
  VCF文件是标准的手机通讯录格式文件,可以导入到手机通讯录中。方法是通过QQ将VCF文件传输到手机上,点击打开VCF文件,选择用手机通讯录打开,根据提示导入。
  7. 搜索关键词最好是行业关键词。一次可以输入多个单词,每行一个单词,并且不能输入标点符号。

文章采集api 专业知识:API已改变SEO的玩法,不懂只能转行

采集交流优采云 发表了文章 • 0 个评论 • 148 次浏览 • 2022-10-29 10:23 • 来自相关话题

  文章采集api 专业知识:API已改变SEO的玩法,不懂只能转行
  作为一个有十三年经验的SEO司机,我经常想知道SEO的本质是什么?对于大多数 SEO 优化者来说,大多数人都理解 SEO = 外部链接 + 内容。其实这是一个很简单的理解,就是从一个非常低的角度来看待SEO工作。
  SEO的全称是Search Engine Optimization,帮助搜索引擎优化。SEO 正在帮助百度、谷歌和 360 改进他们的内容。从这个角度思考,你会发现SEO其实是一个伟大的事业,而不是白天和黑夜。交换链接和 伪原创。
  搜索引擎是怎么来的?
  互联网刚出现时,每台计算机都是一个信息孤岛。为了让这些岛屿上的信息更快被查询到,一些聪明人编写了一个简单的爬虫程序,对分布在网络中各种计算机上的文件进行索引。然后通过一个简单的搜索框,用户可以快速搜索孤岛信息,造福人类。
  搜索引擎最怕什么?
  我最怕我的用户找不到他们想要的结果。我希望尽可能的从各个信息孤岛中找到用户可能感兴趣的内容,并不断地把它们放入我自己的索引中。下次用户搜索时,他们可以非常满意地离开。
  SEO从业者是帮助搜索引擎优化的人。这并不意味着他们每天都会产生无数的垃圾邮件。这并不意味着每天建立无数的友好链接对其有帮助,而是帮助搜索引擎解决他们的实际问题。你觉得很棒吗?
  如果你不能认识到这一点,你可能无法适应SEO优化领域。现在不是狂野的早期时代,如果你一直依赖链接和伪原创,你只会有一种感觉,SEO真的不是人做的!
  我们怎样才能做得更好?
  1.拥有最全面准确的行业词库
  当我们操作某个网站或者专栏的时候,往往是垂直于一个行业的。每个行业都有自己的范围。一般来说,每个行业都有自己的一组核心关键词+长尾词。这些词定义了一个行业的范围,所以它有一个行业词库是全面掌握一个行业的必备品。
  例如,围绕金融行业的核心词如下:
  金融行业核心词下的长尾词列表如下:
  2. 使用词库找出搜索引擎最需要什么
  当我们掌握了一个行业的所有词汇时,我们才能真正了解这个行业以及这个行业用户的需求。
  接下来,我们需要在这近百万的金融词库中,找到能够带来最多流量的词。这里我们使用百度PC Index、360 Index、Baidu Mobile Index、Bid Planner PC Search Volume、Bid Planner Mobile Search Quantity、Bid Planner Competition:
  
  通过上面的公式,我们可以筛选出一批行业内能带来最多流量的词,从百万词库中筛选出104635个流量词。
  3.通过API关键词过滤掉搜索引擎最缺乏的内容
  将上面筛选出来的104635个流量词放到百度、360等搜索引擎中进行模拟查询,了解排名前20的网页的URL等级和标题,了解搜索引擎内容是否饱和.
  通过API商城中的百度PC TOP 50排名API(),我们可以轻松获取JSON格式的排名。
  下图中,我们以“什么是指数基金”一词为例,获取TOP20搜索结果的排名:
  返回的排名信息中有两种重要信息,域名权限信息和标题信息。
  域名权限信息代表前50名的域名是否都是权限比较低的域名,让你有机会挤进去。
  对Title信息的分析是指互联网上这个关键词的内容是否饱和,还是因为百度为了填写信息选择了一些补充信息来填充搜索结果。
  通过分析这两条信息,我们可以判断这个关键词是否值得优先做。
  让我们在这里做一个假设。如果我的网站5118权重是A,那么我们需要找出TOP20排名结果中是否有很多5118权重B级甚至C级网站排名结果。如果有那么我们还有机会占据他们的位置。
  另外还有一种情况,如果通过域名找不到机会,还有另一种机会,就是这些高权限域名的内容不完全符合搜索要求,也就是说,有些结果中的内容标题与 关键词 不完全匹配。
  比如上图中的Title中并没有完全收录“什么是指数基金”这个词,而只是搜索引擎为了补充结果而放置的一个索引,所以我们也可以将这些位置标记为机会。
  通过与上述类似的算法,我们可以得到每个单词的机会得分。我们可以设置一个筛选阈值,例如设置为 8。如果 TOP 20 的结果中有超过 8 个有机会,我们将这些 关键词 保留并进入第 4 阶段。
  4.帮助搜索引擎改进这些内容
  当我们通过前三步完成了性价比最高的SEO关键词的筛选后,可以安排编辑写文章或者专题,或者安排技术部进行文章采集,或者安排运营部门指导用户创作内容。
  通过这四个步骤的层层过滤,我们的内容运营工作会很有针对性。上面虽然写了这么多字,其实就是以下三个目的:
  
  5. 监控 SEO 表现
  随着内容的不断完善,我们需要对上面确定的内容策略的有效性进行整体评估,可能需要对一些参数、阈值甚至算法进行微调:
  因为只有监控这些参数才能知道你的内容创建后百度爬虫是否如期到达,没有遇到任何障碍,从而保证你的内容策略不会因为其他技术操作的干扰而失效和维护因素。
  收录 是排名的前提。如果内容不能为收录,爬更多爬虫就没意义了。如果内容不产生收录,也会对内容策略造成打击,所以收录的监控也很关键。
  随着内容和收录的不断增长,我们SEO的最终目标是获得好的排名。
  跟踪整体大趋势,以确保整体内容策略处于正确轨道上。
  2. 监控个人 关键词 排名以评估每个内容制作工作的稳定性,并注意细节。
  ▲ 可以使用5118关键词监控批量添加自己关键词进行监控
  ▲ 也可以使用 5118关键词ranking采集API 进行监控
  最后总结:
  现代人类文明的发展是一个追求极致自动化的过程。大数据时代的无人工厂、无人超市、无人机、SEO管理者也必须追求SEO自动化,与时俱进,实现自我突破。
  通过这样的内容生产过程,我们可以逐步优化我们的内容策略,最大限度地发挥内容生产流量的效果。还等什么,赶快使用这些大数据API,让你的推广变得轻松。
  5118,尽享神级运营视野
  更多API详情请访问5118官网!
  教程:网站内容批量更新有什么影响,好不好?
  网站海量更新内容有什么影响?做网站SEO优化的站长都知道网站内容更新是很重要的一环。对于搜索引擎和用户来说,他们也喜欢那些更新频率比较高的内容网站。那么,我们 网站 批量添加大量内容怎么样?它如何影响搜索引擎优化?
  网站的异常更新很容易引起搜索引擎的注意,即成为搜索引擎排查的重点,包括批量更新。至于影响,我们需要看不同的情况。
  网站高质量内容批量更新
  
  优质内容具有三个特点:具有一定的搜索需求和创意,内容质量相对稀缺,是行业热门话题,与历史内容相比不存在重复。有人说“内容为王”。我们知道搜索引擎喜欢这样高质量的内容。如果在短时间内添加这样的内容,即使数量很大,也会对搜索引擎非常友好和受欢迎。因此,有利于网站的优化,可以说是正面的影响。
  网站批量更新低质量内容
  对于低质量的内容,可能是自动采集或采集的内容,与历史内容重复率高,质量较差,也可能是软件自动生成,可读性差。在这两种情况下,内容更新都是搜索引擎不喜欢的,也很难在任何时候都有好的排名。如果网站突然添加很多这样的内容,对网站的优化是非常不利的,很可能会被搜索引擎惩罚。比如新站点批量更新低质量内容,就会进入沙盒期,审核时间会更长;而网站批量更新其他时段的低质量内容,会导致收录下降,网站权重和排名下降等。
  
  网站批量更新伪原创的内容
  这里提到的伪原创可能是由伪原创工具生成的,也可能是拼凑而成的。因此,伪原创 不是 100%原创,但它确实具有一些 原创 属性。对于批量更新等内容,可能的结果是优化效果先平稳上升,然后逐渐下降。因为,当你的网站质量达到一定的门槛时,搜索引擎就会开始审查内容的广度,逐步回归内容的质量。因此,如果你继续更新这样的伪原创,你也可能会受到搜索引擎的惩罚。
  综上所述,网站批量更新内容有利有弊,但其影响和效果取决于内容的质量。所以对于网站的内容更新,还是要注意内容的质量。只有保持优质内容的稳定更新,才会更有利于网站的排名。 查看全部

  文章采集api 专业知识:API已改变SEO的玩法,不懂只能转行
  作为一个有十三年经验的SEO司机,我经常想知道SEO的本质是什么?对于大多数 SEO 优化者来说,大多数人都理解 SEO = 外部链接 + 内容。其实这是一个很简单的理解,就是从一个非常低的角度来看待SEO工作。
  SEO的全称是Search Engine Optimization,帮助搜索引擎优化。SEO 正在帮助百度、谷歌和 360 改进他们的内容。从这个角度思考,你会发现SEO其实是一个伟大的事业,而不是白天和黑夜。交换链接和 伪原创
  搜索引擎是怎么来的?
  互联网刚出现时,每台计算机都是一个信息孤岛。为了让这些岛屿上的信息更快被查询到,一些聪明人编写了一个简单的爬虫程序,对分布在网络中各种计算机上的文件进行索引。然后通过一个简单的搜索框,用户可以快速搜索孤岛信息,造福人类。
  搜索引擎最怕什么?
  我最怕我的用户找不到他们想要的结果。我希望尽可能的从各个信息孤岛中找到用户可能感兴趣的内容,并不断地把它们放入我自己的索引中。下次用户搜索时,他们可以非常满意地离开。
  SEO从业者是帮助搜索引擎优化的人。这并不意味着他们每天都会产生无数的垃圾邮件。这并不意味着每天建立无数的友好链接对其有帮助,而是帮助搜索引擎解决他们的实际问题。你觉得很棒吗?
  如果你不能认识到这一点,你可能无法适应SEO优化领域。现在不是狂野的早期时代,如果你一直依赖链接和伪原创,你只会有一种感觉,SEO真的不是人做的!
  我们怎样才能做得更好?
  1.拥有最全面准确的行业词库
  当我们操作某个网站或者专栏的时候,往往是垂直于一个行业的。每个行业都有自己的范围。一般来说,每个行业都有自己的一组核心关键词+长尾词。这些词定义了一个行业的范围,所以它有一个行业词库是全面掌握一个行业的必备品。
  例如,围绕金融行业的核心词如下:
  金融行业核心词下的长尾词列表如下:
  2. 使用词库找出搜索引擎最需要什么
  当我们掌握了一个行业的所有词汇时,我们才能真正了解这个行业以及这个行业用户的需求。
  接下来,我们需要在这近百万的金融词库中,找到能够带来最多流量的词。这里我们使用百度PC Index、360 Index、Baidu Mobile Index、Bid Planner PC Search Volume、Bid Planner Mobile Search Quantity、Bid Planner Competition:
  
  通过上面的公式,我们可以筛选出一批行业内能带来最多流量的词,从百万词库中筛选出104635个流量词。
  3.通过API关键词过滤掉搜索引擎最缺乏的内容
  将上面筛选出来的104635个流量词放到百度、360等搜索引擎中进行模拟查询,了解排名前20的网页的URL等级和标题,了解搜索引擎内容是否饱和.
  通过API商城中的百度PC TOP 50排名API(),我们可以轻松获取JSON格式的排名。
  下图中,我们以“什么是指数基金”一词为例,获取TOP20搜索结果的排名:
  返回的排名信息中有两种重要信息,域名权限信息和标题信息。
  域名权限信息代表前50名的域名是否都是权限比较低的域名,让你有机会挤进去。
  对Title信息的分析是指互联网上这个关键词的内容是否饱和,还是因为百度为了填写信息选择了一些补充信息来填充搜索结果。
  通过分析这两条信息,我们可以判断这个关键词是否值得优先做。
  让我们在这里做一个假设。如果我的网站5118权重是A,那么我们需要找出TOP20排名结果中是否有很多5118权重B级甚至C级网站排名结果。如果有那么我们还有机会占据他们的位置。
  另外还有一种情况,如果通过域名找不到机会,还有另一种机会,就是这些高权限域名的内容不完全符合搜索要求,也就是说,有些结果中的内容标题与 关键词 不完全匹配。
  比如上图中的Title中并没有完全收录“什么是指数基金”这个词,而只是搜索引擎为了补充结果而放置的一个索引,所以我们也可以将这些位置标记为机会。
  通过与上述类似的算法,我们可以得到每个单词的机会得分。我们可以设置一个筛选阈值,例如设置为 8。如果 TOP 20 的结果中有超过 8 个有机会,我们将这些 关键词 保留并进入第 4 阶段。
  4.帮助搜索引擎改进这些内容
  当我们通过前三步完成了性价比最高的SEO关键词的筛选后,可以安排编辑写文章或者专题,或者安排技术部进行文章采集,或者安排运营部门指导用户创作内容。
  通过这四个步骤的层层过滤,我们的内容运营工作会很有针对性。上面虽然写了这么多字,其实就是以下三个目的:
  
  5. 监控 SEO 表现
  随着内容的不断完善,我们需要对上面确定的内容策略的有效性进行整体评估,可能需要对一些参数、阈值甚至算法进行微调:
  因为只有监控这些参数才能知道你的内容创建后百度爬虫是否如期到达,没有遇到任何障碍,从而保证你的内容策略不会因为其他技术操作的干扰而失效和维护因素。
  收录 是排名的前提。如果内容不能为收录,爬更多爬虫就没意义了。如果内容不产生收录,也会对内容策略造成打击,所以收录的监控也很关键。
  随着内容和收录的不断增长,我们SEO的最终目标是获得好的排名。
  跟踪整体大趋势,以确保整体内容策略处于正确轨道上。
  2. 监控个人 关键词 排名以评估每个内容制作工作的稳定性,并注意细节。
  ▲ 可以使用5118关键词监控批量添加自己关键词进行监控
  ▲ 也可以使用 5118关键词ranking采集API 进行监控
  最后总结:
  现代人类文明的发展是一个追求极致自动化的过程。大数据时代的无人工厂、无人超市、无人机、SEO管理者也必须追求SEO自动化,与时俱进,实现自我突破。
  通过这样的内容生产过程,我们可以逐步优化我们的内容策略,最大限度地发挥内容生产流量的效果。还等什么,赶快使用这些大数据API,让你的推广变得轻松。
  5118,尽享神级运营视野
  更多API详情请访问5118官网!
  教程:网站内容批量更新有什么影响,好不好?
  网站海量更新内容有什么影响?做网站SEO优化的站长都知道网站内容更新是很重要的一环。对于搜索引擎和用户来说,他们也喜欢那些更新频率比较高的内容网站。那么,我们 网站 批量添加大量内容怎么样?它如何影响搜索引擎优化?
  网站的异常更新很容易引起搜索引擎的注意,即成为搜索引擎排查的重点,包括批量更新。至于影响,我们需要看不同的情况。
  网站高质量内容批量更新
  
  优质内容具有三个特点:具有一定的搜索需求和创意,内容质量相对稀缺,是行业热门话题,与历史内容相比不存在重复。有人说“内容为王”。我们知道搜索引擎喜欢这样高质量的内容。如果在短时间内添加这样的内容,即使数量很大,也会对搜索引擎非常友好和受欢迎。因此,有利于网站的优化,可以说是正面的影响。
  网站批量更新低质量内容
  对于低质量的内容,可能是自动采集或采集的内容,与历史内容重复率高,质量较差,也可能是软件自动生成,可读性差。在这两种情况下,内容更新都是搜索引擎不喜欢的,也很难在任何时候都有好的排名。如果网站突然添加很多这样的内容,对网站的优化是非常不利的,很可能会被搜索引擎惩罚。比如新站点批量更新低质量内容,就会进入沙盒期,审核时间会更长;而网站批量更新其他时段的低质量内容,会导致收录下降,网站权重和排名下降等。
  
  网站批量更新伪原创的内容
  这里提到的伪原创可能是由伪原创工具生成的,也可能是拼凑而成的。因此,伪原创 不是 100%原创,但它确实具有一些 原创 属性。对于批量更新等内容,可能的结果是优化效果先平稳上升,然后逐渐下降。因为,当你的网站质量达到一定的门槛时,搜索引擎就会开始审查内容的广度,逐步回归内容的质量。因此,如果你继续更新这样的伪原创,你也可能会受到搜索引擎的惩罚。
  综上所述,网站批量更新内容有利有弊,但其影响和效果取决于内容的质量。所以对于网站的内容更新,还是要注意内容的质量。只有保持优质内容的稳定更新,才会更有利于网站的排名。

技巧:WordPress文章内容管理器:实现网站全过程管理

采集交流优采云 发表了文章 • 0 个评论 • 59 次浏览 • 2022-10-28 21:20 • 来自相关话题

  技巧:WordPress文章内容管理器:实现网站全过程管理
  WordPress文章内容更新是SEO中最焦虑的事情。每天高质量发布 WordPress文章 内容是一件苦差事。
  我们知道搜索引擎会通过蜘蛛抓取我们每日更新的 URL。搜索引擎会根据蜘蛛爬取的url分析我们的WordPress网站的更新频率和文章的内容质量,从而判断是否收录并给出关键词排名,所以维护我们的WordPress网站定期更新和文章内容优化是一项重要的工作。
  WordPress文章内容管理器可以轻松管理工作流程并以有效的格式组织文章内容。通过定时采集发布功能,实现网站的全流程管理,利用内置翻译api和文章SEO编辑模块实现的优化管理文章 内容
  WordPress文章内容管理器通过可视化操作面板实现对网站文章内容管理的简单管理,无需学习正则表达式即可完成全网文章内容采集. 内置的展示模块可以让我们设置发布模板,根据我们的需求发布我们的文章内容,批量网站标题、文章内容和文章属性优化发布.
  
  然而,只有少数人知道 WordPress文章 内容管理器不仅仅是一台服务器,在过去的几年里,WordPress文章 内容管理器已经开发了多台服务器,现在都可以使用在一个单独的包中使用。这些编辑器为用户提供了轻松创建自定义发布设置、自定义发布流程和改进整体流程的工具。我们可以用 WordPress文章Content Manager 做的一些事情包括:
  1.管理我们对网站的文章内容编辑,并向我们展示编辑前后的状态。
  2. 同一篇博文有多个作者;
  3、根据现场要求保留相关的文章标签和图片水印;
  4. 在 网站 上为我们创建不同的发布模板,使每个 文章 内容遵循相似的模式。
  
  WordPress文章内容管理器修订者。它允许我们提交、审查、讨论和安排修订。假设我们的一位作家编写 文章 内容并在 WordPress 之上起草。我们可以添加修订并将其分配给作者进行编辑。这使我们可以更轻松地编辑和发布 文章 内容,同时保留在 网站 仪表板上。编辑它,然后在平台上可用时将文档导入 WordPress。
  网站更新如果我们是 WordPress 博客作者或我 WordPress网站所有者正在寻找一个 文章 内容管理系统,可以简化我们的 网站文章 内容,WordPress文章内容管理器是我们不能忽视的。
  WordPress文章Content Manager 将我们的 网站文章 内容管理从 网站 管理解决方案转变为时间管理。仅通过时间跟踪和待办事项列表软件才能实现的功能现在可以在 WordPress 中实现。
  WordPress文章内容管理器对我们的网站文章内容管理提供了一定的帮助,并且在不断的优化中。通过不断的api访问,将是我们的网站文章内容管理。网站全流程自动化管理的趋势。这就是 WordPress文章 内容管理的共享。如果你喜欢它,请喜欢它。
  技术文章:SEO伪原创文章怎么能批量生成?
  文章的稳定性,有很多公司在使用我们的批量SEO伪原创文章,适用于大部分职业,可以放心。一些地方的操作也比较复杂。有能力的可以去测试一下,作为公司也可以找我们合作。下面说一下详细的批处理伪原创流程,大概有几个流程。
  1. 采集数据
  这个应该没问题,操作比较简单,采集数据的软件也很多。应该可以做一点研究。一般扩展功能需要付费,但基本功能一般可以满足小站的需求。你可以测试一下。如果你做不到,你可以找我们。我们也有 傻瓜式 和定制的。
  2.按关键词分类
  很多网络软件支持导出txt格式采集数据,有的只能导出excel格式的数据,不过没关系,我们可以批量从excel导出为txt格式,然后按照词库分类,根据将选定的关键词库分类到文件夹中,为下一步做准备。需要注意的一点是,所有采集到的数据都是在采集后进行处理,将不相关的文本、超链接等无用的文本导出进行分类。
  
  3. 过道、清扫
  分类后,就是准备洗稿了。第一阶段被打乱,都被同类型选中。因此,当您将它们分段组合时,您不必担心平滑度。选择操作有点乱。混沌关卡相互交叉,随机打乱,可以随机组合召唤。
  4. 语义分词处理
  这个操作也是需要软件的,但是处理的方法和市面上的网上SEO伪原创的东西不太一样。一个关键词可以出很多文章文章,形体字不一样。不一样,但意思是一样的,就是这样。
  5、排版
  批量排版没什么好说的。一般来说,就是将代码插入到stage中形成批量排版,然后导出成大型HTML格式文章,类似这样
  
  然后分批发布到网站。以上就是批处理高质量SEO伪原创文章的方法,也就是我们常说的洗稿,批处理伪原创,我们选择处理方法比较复杂,但必须保证质量。
  Growthman Growthman 专注于为企业提供数字营销服务。成长超人作为营销成长、高端网站建设、网站制作公司,先后为富士康、钉钉、泰菱、天虹、爱尔眼科、海澜集团、金蝶、飞亚达、云米等知名企业提供专业成长服务。
  官方网站: 查看全部

  技巧:WordPress文章内容管理器:实现网站全过程管理
  WordPress文章内容更新是SEO中最焦虑的事情。每天高质量发布 WordPress文章 内容是一件苦差事。
  我们知道搜索引擎会通过蜘蛛抓取我们每日更新的 URL。搜索引擎会根据蜘蛛爬取的url分析我们的WordPress网站的更新频率和文章的内容质量,从而判断是否收录并给出关键词排名,所以维护我们的WordPress网站定期更新和文章内容优化是一项重要的工作。
  WordPress文章内容管理器可以轻松管理工作流程并以有效的格式组织文章内容。通过定时采集发布功能,实现网站的全流程管理,利用内置翻译api和文章SEO编辑模块实现的优化管理文章 内容
  WordPress文章内容管理器通过可视化操作面板实现对网站文章内容管理的简单管理,无需学习正则表达式即可完成全网文章内容采集. 内置的展示模块可以让我们设置发布模板,根据我们的需求发布我们的文章内容,批量网站标题、文章内容和文章属性优化发布.
  
  然而,只有少数人知道 WordPress文章 内容管理器不仅仅是一台服务器,在过去的几年里,WordPress文章 内容管理器已经开发了多台服务器,现在都可以使用在一个单独的包中使用。这些编辑器为用户提供了轻松创建自定义发布设置、自定义发布流程和改进整体流程的工具。我们可以用 WordPress文章Content Manager 做的一些事情包括:
  1.管理我们对网站的文章内容编辑,并向我们展示编辑前后的状态。
  2. 同一篇博文有多个作者;
  3、根据现场要求保留相关的文章标签和图片水印;
  4. 在 网站 上为我们创建不同的发布模板,使每个 文章 内容遵循相似的模式。
  
  WordPress文章内容管理器修订者。它允许我们提交、审查、讨论和安排修订。假设我们的一位作家编写 文章 内容并在 WordPress 之上起草。我们可以添加修订并将其分配给作者进行编辑。这使我们可以更轻松地编辑和发布 文章 内容,同时保留在 网站 仪表板上。编辑它,然后在平台上可用时将文档导入 WordPress。
  网站更新如果我们是 WordPress 博客作者或我 WordPress网站所有者正在寻找一个 文章 内容管理系统,可以简化我们的 网站文章 内容,WordPress文章内容管理器是我们不能忽视的。
  WordPress文章Content Manager 将我们的 网站文章 内容管理从 网站 管理解决方案转变为时间管理。仅通过时间跟踪和待办事项列表软件才能实现的功能现在可以在 WordPress 中实现。
  WordPress文章内容管理器对我们的网站文章内容管理提供了一定的帮助,并且在不断的优化中。通过不断的api访问,将是我们的网站文章内容管理。网站全流程自动化管理的趋势。这就是 WordPress文章 内容管理的共享。如果你喜欢它,请喜欢它。
  技术文章:SEO伪原创文章怎么能批量生成?
  文章的稳定性,有很多公司在使用我们的批量SEO伪原创文章,适用于大部分职业,可以放心。一些地方的操作也比较复杂。有能力的可以去测试一下,作为公司也可以找我们合作。下面说一下详细的批处理伪原创流程,大概有几个流程。
  1. 采集数据
  这个应该没问题,操作比较简单,采集数据的软件也很多。应该可以做一点研究。一般扩展功能需要付费,但基本功能一般可以满足小站的需求。你可以测试一下。如果你做不到,你可以找我们。我们也有 傻瓜式 和定制的。
  2.按关键词分类
  很多网络软件支持导出txt格式采集数据,有的只能导出excel格式的数据,不过没关系,我们可以批量从excel导出为txt格式,然后按照词库分类,根据将选定的关键词库分类到文件夹中,为下一步做准备。需要注意的一点是,所有采集到的数据都是在采集后进行处理,将不相关的文本、超链接等无用的文本导出进行分类。
  
  3. 过道、清扫
  分类后,就是准备洗稿了。第一阶段被打乱,都被同类型选中。因此,当您将它们分段组合时,您不必担心平滑度。选择操作有点乱。混沌关卡相互交叉,随机打乱,可以随机组合召唤。
  4. 语义分词处理
  这个操作也是需要软件的,但是处理的方法和市面上的网上SEO伪原创的东西不太一样。一个关键词可以出很多文章文章,形体字不一样。不一样,但意思是一样的,就是这样。
  5、排版
  批量排版没什么好说的。一般来说,就是将代码插入到stage中形成批量排版,然后导出成大型HTML格式文章,类似这样
  
  然后分批发布到网站。以上就是批处理高质量SEO伪原创文章的方法,也就是我们常说的洗稿,批处理伪原创,我们选择处理方法比较复杂,但必须保证质量。
  Growthman Growthman 专注于为企业提供数字营销服务。成长超人作为营销成长、高端网站建设、网站制作公司,先后为富士康、钉钉、泰菱、天虹、爱尔眼科、海澜集团、金蝶、飞亚达、云米等知名企业提供专业成长服务。
  官方网站:

秘密:一文读懂数据仓库、数据平台、数据中台、数据湖的概念和区别

采集交流优采云 发表了文章 • 0 个评论 • 59 次浏览 • 2022-10-28 08:34 • 来自相关话题

  秘密:一文读懂数据仓库、数据平台、数据中台、数据湖的概念和区别
  在数据仓库、数据平台、数据中台、数据湖的相关概念中,都与数据相关,但它们之间有什么区别呢?本文介绍了它们的概念、架构和使用场景。让我们来看看。
  我们经常听到人们谈论数据仓库、数据平台、数据中心和数据湖的概念。它们都与数据有关,但它们之间有什么区别?下面我们将重点介绍数据仓库、数据平台和数据湖。介绍数据中心的概念、架构和使用场景。
  一、数据仓库 一、数据仓库概念
  数据仓库由 Bill Inmon(数据仓库之父)于 1990 年提出,其主要功能是存储大量数据,这些数据是企业系统中在线事务处理(OLTP)的长期障碍,并支持数据仓库理论所持有的数据存储。结构,做系统的分析和整理。
  随着企业的发展,业务系统的数据不断激增,存储在企业业务数据库(即关系型数据库Oracle、Microsoft SQL Server、MySQL等)中的数据会越来越多时间,这会使业务数据库有一定的负载,导致业务系统运行效率低下,而这个数据很大一部分是冷数据,而我们的业务系统一般会调用我们最近的数据,也就是热数据数据,更频繁,冷数据被更频繁地调用。减少使用频率。
  同时,随着企业数据驱动业务理念的兴起,企业需要提取各业务部门的业务数据进行数据分析挖掘,辅助高层分析决策。数据查询脚本和接口的访问降低了业务数据库的稳定性。
  为了避免冷数据和历史数据的积压对我们业务数据库性能的影响,企业需要定期从业务数据库中调出冷数据,并存放在专门用于存储历史数据的仓库中。各部门可根据自身业务特点提供统一的对外服务。数据服务,这个仓库就是数据仓库。
  2. 数据仓库功能
  数据仓库(Data Warehoese)的特点:面向主题、集成化、稳定、反映历史数据变化。
  3.OLTP和OLAP
  1) OLTP 和 OLAP 概念
  数据处理大致可以分为两类:在线事务处理OLTP(on-line transaction processing),在线分析处理OLAP(On-Line Analytical Processing)。
  OLTP 是传统关系型数据库的主要应用,主要用于基本的、日常的事务处理,例如银行交易。OLAP是数据仓库系统的主要应用,支持复杂的分析操作,注重决策支持,提供直观易懂的查询结果。
  2)OLTP和OLAP的区别
  OLTP系统强调数据库内存效率,强调内存、绑定变量、并发操作等各项指标的指挥率。OLAP 系统强调数据分析、SQL 执行市场、磁盘 I/O、分区等。
  3)OLAP与数据仓库的连接
  OLAP与数据仓库的关系依赖于互补性,一般以数据仓库为基础,即从数据仓库中提取详细数据的子集,通过必要的聚合存储在OLAP存储中,供数据分析工具读取。
  4.数据仓库的作用
  数据仓库聚合来自不同来源的结构化数据,以便在商业智能领域进行比较和分析。数据仓库是一个收录各种数据并且高度建模的存储库。
  如下图所示: 各个系统的元数据通过ETL同步到运营数据仓库ODS,ODS数据进行面向主题、面向领域的建模,形成DW(数据仓库)。DM就是为某个业务领域建立模型。决策层)查看DM生成的报告。
  什么是 ETL?(提取-转换-加载提取-转换-加载)
  传统的数据仓库集成处理架构是ETL,利用ETL平台的能力,E=从源数据库提取数据,L=清洗数据(不符合规则的数据),转换(表受根据业务需求不同维度、不同粒度)程度,计算不同的业务规则进行统计),T = 将处理后的表以增量、全量、不同时间加载到数据仓库中。
  什么是 ELT?(提取-加载-变换提取-加载-变换)
  大数据背景下的架构体系是ELT结构,根据上层的应用需求,随时从数据中心提取出需要的原创数据进行建模分析。
  ELT利用数据库的处理能力,E=从源数据库中提取数据,L=将数据加载到目标数据库的临时表中,T=对临时表中的数据进行变换,然后加载到目标表中的目标数据库。
  ELT 相对于 ETL 的优势:
  数据仓库系统的作用可以实现跨业务线、跨系统的数据集成,为管理分析和业务决策提供统一的数据支持。数据仓库可以从根本上帮助您将公司的运营数据转换为高价值的可访问信息(或知识),并在正确的时间以正确的方式将正确的信息传递给正确的人。下图是一个例子:
  数据仓库的作用主要体现在企业决策、分析、规划和响应的以下几个方面:
  
  数据仓库在实时数据处理和非结构化数据处理方面较弱,在预警和预测在业务中的应用有一定的局限性。
  二、数据平台 1、数据平台的概念
  在大数据时代,数据平台一般被称为大数据平台。
  狭义的数据平台:是解决数据仓库无法处理非结构化数据,报表开发周期长的问题。因此,我们首先抛开业务需求,将企业的所有数据提取出来,放在一起,形成一个大数据集。有结构化数据,非结构化数据等等。当业务方有需求时,将需要的几个小数据集分别抽取出来,以数据集的形式提供给数据应用。
  广义大数据平台:广义大数据平台通常被赋予更多的任务来处理海量数据存储、不间断流数据的计算和实时计算、离线计算、智能推荐、交互查询、数据湖建设等场景。一套为主的基础设施。典型的包括建立在 Hadoop 生态系统上的大数据平台。提供Hive、Spark、HBase、Flink、StarRocks、Iceberg、Alluxio等开源大数据计算和存储引擎,易于部署和管理。
  狭义数据平台与传统数据平台(数据仓库)功能相同,唯一不同的是技术架构和数据容量。
  广义的大数据平台是数据湖的基础。提供易于部署和管理泛Hadoop生态系统等存储计算引擎的PaaS平台,帮助企业构建企业级数据湖技术架构。
  提示:本文比较的是狭义的数据平台,并没有对狭义的数据平台进行过多的概述。
  三、数据中台 1、数据中台的概念
  数据中心的由来:2015年年中,马云带领阿里巴巴集团高管走访芬兰小游戏公司Supercell。这家员工不到 200 人的小型游戏公司每年产生 15 亿美元的税前利润!Supercell之所以能够支持多个团队快速敏捷地推出优质游戏作品,是因为其强大的中期能力。
  因此,在参观了Supercell之后,马云决定对阿里巴巴的组织体系架构进行整体调整,以阿里巴巴的产品技术和数据能力建立强大的中台,打造“大中台、小前台”的组织和业务。系统 。
  数据中心的主要目的是解决企业发展过程中因数据激增和业务扩展而导致的统计口径不一致、重复开发、指标开发需求响应慢、数据质量低、数据成本高的问题。通过一系列数据工具(元数据中心、数据指标中心、数据仓库模型中心、数据资产中心-资产质量/治理/安全、数据服务中心等),规范数据供应链的各个环节。
  2.数据中心的特点
  数据中心特点:支持前端数据标准化、安全、可靠、统一、共享、解耦、服务化的应用。
  3.数据中心的作用
  (阿里巴巴数据中台逻辑架构图)
  (数据中心产品能力图)
  数据中心通过对企业内外多源异构数据的构建、管理、分析和应用,优化内部数据管理提升业务价值,对外开展数据协同释放业务价值,使其成为企业数据资产管理中心。数据中心建成后,将形成数据API服务,为企业和客户提供高效、多样的数据服务。
  数据中心在企业数字化转型和可持续发展中发挥着至关重要的作用。数据中心为解耦而生。企业建设数据中心的最大意义在于实现应用与数据的解耦,让企业可以不受限制地构建满足业务需求的数据应用。
  构建了开放、灵活、可扩展的企业级统一数据管理和分析平台,可按需链接内外部数据,打破数据的系统边界。
  利用大数据智能分析、数据可视化等技术,实现数据共享、日报表自动生成、快速智能分析,满足企业各部门数据分析应用需求。
  深度挖掘数据价值,助力企业实现数字化转型。实现数据目录、模型、标准、问责、安全、可视化、共享的管理,实现数据集中存储、处理、分类和管理,建立大数据分析工具库、算法服务库,实现报表生成自动化、数据分析敏捷,数据挖掘可视化,实现数据质量评估、落地管理流程。
  4. 数据湖 1. 数据湖概念
  数据湖的起源:数据湖的起源应该追溯到2010年10月,由Pentaho的创始人兼CTO James Dixon提出。他的目的是根据当时的历史背景,推广自己的产品 Pentaho。当时要解决的核心问题是传统数仓报表分析面临的两个问题:
  我们现在讨论的数据湖已经远远超过了James Dixon一开始定义的数据湖,各个厂商对数据湖的定义也比较不同。
  1)AWS
  数据湖是一个集中式存储库,可让您以任意规模存储所有结构化和非结构化数据。您可以按原样存储数据,而无需首先构建数据,并运行不同类型的分析——从仪表板和可视化到大数据处理、实时分析和机器学习,以指导更好的决策。
  “数据湖是一个集中式存储库,可让您以任何规模存储所有结构化和非结构化数据。您可以按原样存储数据(无需先对其进行结构化)并运行不同类型的分析——从仪表板和可视化到大数据处理、实时分析和机器学习,以指导更好的决策。”
  2) 微软
  Azure Data Lake 收录使开发人员、数据科学家和分析师能够轻松存储任何大小、形状和速度的数据以及跨平台和语言进行所有类型的处理和分析所需的所有功能。它消除了摄取和存储所有数据的复杂性,同时通过批处理、流式处理和交互式分析更快地启动和运行。
  “Azure 的数据湖包括所有使开发人员、数据科学家和分析师更容易存储和处理数据的功能,这些功能允许用户存储任何大小、类型和速度的数据,并且可以跨平台、做所有类型跨语言分析处理。数据湖可以帮助用户加速应用数据,消除数据采集和存储的复杂性,还支持批处理、流计算、交互分析等。
  3)阿里云
  
  “数据湖是一个统一的存储池,可以对接多种数据输入方式,可以存储任意规模的结构化、半结构化、非结构化数据。数据湖可以无缝对接各种计算和分析平台,根据业务场景,可以选择相应的计算引擎对存储在数据湖中的数据进行处理和分析,从而打破孤岛,挖掘业务价值。”
  2. 数据湖内容
  数据湖包括结构化数据(行和列)、半结构化数据(如CSV、日志、XML、JSON)、非结构化数据(如电子邮件、文档、PDF等)和来自关系数据库的二进制数据数据(例如图像、音频、视频)。
  3. 数据湖的特点 4. 数据湖可以解决的问题
  1)数据湖整体架构
  最底层是分布式文件系统;
  第二层是数据加速层。数据湖架构是存储和计算完全分离的架构。如果所有数据访问都远程读取文件系统上的数据,那么性能和成本开销将是巨大的。如果可以在计算节点本地缓存一些经常访问的热点数据,那么实现冷热分离是很自然的。一方面可以获得良好的本地读取性能,另一方面可以节省远程访问的带宽。
  第三层是Table格式层,主要将一批数据文件封装成具有业务意义的表,提供ACID、snapshot、schema、partition等表级语义。
  最上层是针对不同计算场景的计算引擎。开源一般包括Spark、Flink、Hive、Presto、Hive MR等,这批计算引擎可以同时访问同一个数据湖中的表。
  2)数据湖能解决什么样的问题?
  数据分散,存储分散,形成数据孤岛,无法将数据组合起来发现更多价值。
  在这方面,数据湖其实是和数据仓库类似的问题,但不同的是,它的定义支持半结构化和非结构化数据的管理。传统数据仓库只能解决结构化数据的统一管理。
  在这个万物互联的时代,数据的来源多种多样。随着应用场景的不同,输出的数据格式也越来越丰富,不再局限于结构化数据。如何统一存储这些数据是一个亟待解决的问题。
  3) 存储成本
  数据库或数据仓库的存储受限于实现原理和硬件条件,导致海量数据存储成本高。为了解决这些问题,有HDFS/对象存储等技术方案。在数据湖场景下,如果采用这种低成本的存储技术架构,将为企业大大节省成本。结合生命周期管理的能力,湖中的数据可以更好的分层(冷热存储在不同的存储介质:HDD、SSD、MEM),不用担心数据是保留还是删除数据以节省成本。
  4)SQL已经不能满足的分析需求
  越来越多的数据类型意味着越来越多的分析方法。传统的 SQL 方法已经不能满足分析的需要。如何通过各种语言定制贴近业务的代码?如何通过机器学习挖掘更多?数据价值。
  5)存储/计算可扩展性不足
  在传统数据库等海量数据的情况下,比如规模到PB级别,由于技术架构的原因,已经不能满足扩容需求或者扩容成本极高。这种情况下,通过数据湖架构下的技术能力扩展,实现成本为0,硬件成本也是可控的。商业模式不确定,无法提前建模。
  传统的数据库和数据仓库都是 Schema-on-Write 模式,需要提前定义模式信息。在数据湖场景中,可以先保存数据,以后分析的时候发现Schema,即Schema-on-Read。
  五、对比一、数据仓库VS数据中心VS数据湖
  2. 数据仓库 vs 数据平台
  因为狭义的数据平台是由于数据仓库的历史特性,其存储的数据多为结构化数据,而数据平台的出现解决了数据仓库无法处理非结构化数据和报表的问题开发周期长。数据仓库和数据平台(狭义)是分开比较的。
  本质区别:技术架构和数据容量的差异。
  通过上面的讨论,我们发现数据平台和数据湖之间似乎有很多相似之处。两者的区别应该从个人的角度来分析。数据处理的角度是不同的。数据湖更侧重于原创数据的存储。,而数据平台和数据仓库一样,需要对原创数据进行清洗和转换,并在数据处理后按照统一的标准规范进行存储。
  6.总结
  根据以上对数据平台、数据仓库、数据湖、数据中台的概念讨论和对比,我们做如下总结:
  数据中心、数据仓库和数据湖之间没有直接关系;数据中心、数据平台、数据仓库和数据湖在一定维度上对业务产生价值的形式侧重点不同;数据仓库是数据驱动业务的逻辑概念,用于支持管理决策分析,为业务提供服务的主要方式是报表;数据中心是企业级的逻辑概念,体现了企业数据转化为业务价值的能力,为业务提供服务的主要方式是数据API;数据湖是企业级的技术逻辑概念,体现了企业级数据湖架构加速数据转化为商业价值的能力。为业务提供服务的主要方式是原创数据;数据中心和数据湖更贴近业务,可以更快 数据中心可以建立在数据仓库和数据平台之上,是加速企业从数据到业务价值过程的中间层;
  本文由@Mr.Z 发表 聊产品原创人人都是产品经理。未经许可禁止复制
  标题图片来自 Unsplash,基于 CC0 协议。
  本文观点仅代表作者本人,大家都是产品经理。平台仅提供信息存储空间服务。
  奖励作者,鼓励TA抓紧创作!
  欣赏
  横空出世:百家号热文采集工具-百家号爆文采集助手1.0 免费版
  百家号爆文采集Assistant是专门为百家号开发的一款小工具,你可以轻松使用本软件来采集流行文章,简单好用,需要的朋友可以过来下载!
  百家号爆文采集知识兔助手如何使用
  1.设置采集时间
  
  2.输入需要采集的链接,如果需要批量,可以设置为txt文档
  3.点击分析采集文章信息
  百家号介绍知识兔
  百家号是百度为内容创作者共享的内容发布、内容变现和粉丝管理平台。百家号于2016年6月上线并正式测试。9月,账号系统、分销策略升级、广告系统正式上线。9月28日,正式向所有作者开放。
  
  目前,百家号支持内容创作者轻松发布文章、图片、视频作品,未来将支持H5、VR、直播、动画等内容形式。内容一经提交,将通过手机百度、百度搜索、百度浏览器等多种渠道进行分发。
  点击下载
  下载体验
  点击下载 查看全部

  秘密:一文读懂数据仓库、数据平台、数据中台、数据湖的概念和区别
  在数据仓库、数据平台、数据中台、数据湖的相关概念中,都与数据相关,但它们之间有什么区别呢?本文介绍了它们的概念、架构和使用场景。让我们来看看。
  我们经常听到人们谈论数据仓库、数据平台、数据中心和数据湖的概念。它们都与数据有关,但它们之间有什么区别?下面我们将重点介绍数据仓库、数据平台和数据湖。介绍数据中心的概念、架构和使用场景。
  一、数据仓库 一、数据仓库概念
  数据仓库由 Bill Inmon(数据仓库之父)于 1990 年提出,其主要功能是存储大量数据,这些数据是企业系统中在线事务处理(OLTP)的长期障碍,并支持数据仓库理论所持有的数据存储。结构,做系统的分析和整理。
  随着企业的发展,业务系统的数据不断激增,存储在企业业务数据库(即关系型数据库Oracle、Microsoft SQL Server、MySQL等)中的数据会越来越多时间,这会使业务数据库有一定的负载,导致业务系统运行效率低下,而这个数据很大一部分是冷数据,而我们的业务系统一般会调用我们最近的数据,也就是热数据数据,更频繁,冷数据被更频繁地调用。减少使用频率。
  同时,随着企业数据驱动业务理念的兴起,企业需要提取各业务部门的业务数据进行数据分析挖掘,辅助高层分析决策。数据查询脚本和接口的访问降低了业务数据库的稳定性。
  为了避免冷数据和历史数据的积压对我们业务数据库性能的影响,企业需要定期从业务数据库中调出冷数据,并存放在专门用于存储历史数据的仓库中。各部门可根据自身业务特点提供统一的对外服务。数据服务,这个仓库就是数据仓库。
  2. 数据仓库功能
  数据仓库(Data Warehoese)的特点:面向主题、集成化、稳定、反映历史数据变化。
  3.OLTP和OLAP
  1) OLTP 和 OLAP 概念
  数据处理大致可以分为两类:在线事务处理OLTP(on-line transaction processing),在线分析处理OLAP(On-Line Analytical Processing)。
  OLTP 是传统关系型数据库的主要应用,主要用于基本的、日常的事务处理,例如银行交易。OLAP是数据仓库系统的主要应用,支持复杂的分析操作,注重决策支持,提供直观易懂的查询结果。
  2)OLTP和OLAP的区别
  OLTP系统强调数据库内存效率,强调内存、绑定变量、并发操作等各项指标的指挥率。OLAP 系统强调数据分析、SQL 执行市场、磁盘 I/O、分区等。
  3)OLAP与数据仓库的连接
  OLAP与数据仓库的关系依赖于互补性,一般以数据仓库为基础,即从数据仓库中提取详细数据的子集,通过必要的聚合存储在OLAP存储中,供数据分析工具读取。
  4.数据仓库的作用
  数据仓库聚合来自不同来源的结构化数据,以便在商业智能领域进行比较和分析。数据仓库是一个收录各种数据并且高度建模的存储库。
  如下图所示: 各个系统的元数据通过ETL同步到运营数据仓库ODS,ODS数据进行面向主题、面向领域的建模,形成DW(数据仓库)。DM就是为某个业务领域建立模型。决策层)查看DM生成的报告。
  什么是 ETL?(提取-转换-加载提取-转换-加载)
  传统的数据仓库集成处理架构是ETL,利用ETL平台的能力,E=从源数据库提取数据,L=清洗数据(不符合规则的数据),转换(表受根据业务需求不同维度、不同粒度)程度,计算不同的业务规则进行统计),T = 将处理后的表以增量、全量、不同时间加载到数据仓库中。
  什么是 ELT?(提取-加载-变换提取-加载-变换)
  大数据背景下的架构体系是ELT结构,根据上层的应用需求,随时从数据中心提取出需要的原创数据进行建模分析。
  ELT利用数据库的处理能力,E=从源数据库中提取数据,L=将数据加载到目标数据库的临时表中,T=对临时表中的数据进行变换,然后加载到目标表中的目标数据库。
  ELT 相对于 ETL 的优势:
  数据仓库系统的作用可以实现跨业务线、跨系统的数据集成,为管理分析和业务决策提供统一的数据支持。数据仓库可以从根本上帮助您将公司的运营数据转换为高价值的可访问信息(或知识),并在正确的时间以正确的方式将正确的信息传递给正确的人。下图是一个例子:
  数据仓库的作用主要体现在企业决策、分析、规划和响应的以下几个方面:
  
  数据仓库在实时数据处理和非结构化数据处理方面较弱,在预警和预测在业务中的应用有一定的局限性。
  二、数据平台 1、数据平台的概念
  在大数据时代,数据平台一般被称为大数据平台。
  狭义的数据平台:是解决数据仓库无法处理非结构化数据,报表开发周期长的问题。因此,我们首先抛开业务需求,将企业的所有数据提取出来,放在一起,形成一个大数据集。有结构化数据,非结构化数据等等。当业务方有需求时,将需要的几个小数据集分别抽取出来,以数据集的形式提供给数据应用。
  广义大数据平台:广义大数据平台通常被赋予更多的任务来处理海量数据存储、不间断流数据的计算和实时计算、离线计算、智能推荐、交互查询、数据湖建设等场景。一套为主的基础设施。典型的包括建立在 Hadoop 生态系统上的大数据平台。提供Hive、Spark、HBase、Flink、StarRocks、Iceberg、Alluxio等开源大数据计算和存储引擎,易于部署和管理。
  狭义数据平台与传统数据平台(数据仓库)功能相同,唯一不同的是技术架构和数据容量。
  广义的大数据平台是数据湖的基础。提供易于部署和管理泛Hadoop生态系统等存储计算引擎的PaaS平台,帮助企业构建企业级数据湖技术架构。
  提示:本文比较的是狭义的数据平台,并没有对狭义的数据平台进行过多的概述。
  三、数据中台 1、数据中台的概念
  数据中心的由来:2015年年中,马云带领阿里巴巴集团高管走访芬兰小游戏公司Supercell。这家员工不到 200 人的小型游戏公司每年产生 15 亿美元的税前利润!Supercell之所以能够支持多个团队快速敏捷地推出优质游戏作品,是因为其强大的中期能力。
  因此,在参观了Supercell之后,马云决定对阿里巴巴的组织体系架构进行整体调整,以阿里巴巴的产品技术和数据能力建立强大的中台,打造“大中台、小前台”的组织和业务。系统 。
  数据中心的主要目的是解决企业发展过程中因数据激增和业务扩展而导致的统计口径不一致、重复开发、指标开发需求响应慢、数据质量低、数据成本高的问题。通过一系列数据工具(元数据中心、数据指标中心、数据仓库模型中心、数据资产中心-资产质量/治理/安全、数据服务中心等),规范数据供应链的各个环节。
  2.数据中心的特点
  数据中心特点:支持前端数据标准化、安全、可靠、统一、共享、解耦、服务化的应用。
  3.数据中心的作用
  (阿里巴巴数据中台逻辑架构图)
  (数据中心产品能力图)
  数据中心通过对企业内外多源异构数据的构建、管理、分析和应用,优化内部数据管理提升业务价值,对外开展数据协同释放业务价值,使其成为企业数据资产管理中心。数据中心建成后,将形成数据API服务,为企业和客户提供高效、多样的数据服务。
  数据中心在企业数字化转型和可持续发展中发挥着至关重要的作用。数据中心为解耦而生。企业建设数据中心的最大意义在于实现应用与数据的解耦,让企业可以不受限制地构建满足业务需求的数据应用。
  构建了开放、灵活、可扩展的企业级统一数据管理和分析平台,可按需链接内外部数据,打破数据的系统边界。
  利用大数据智能分析、数据可视化等技术,实现数据共享、日报表自动生成、快速智能分析,满足企业各部门数据分析应用需求。
  深度挖掘数据价值,助力企业实现数字化转型。实现数据目录、模型、标准、问责、安全、可视化、共享的管理,实现数据集中存储、处理、分类和管理,建立大数据分析工具库、算法服务库,实现报表生成自动化、数据分析敏捷,数据挖掘可视化,实现数据质量评估、落地管理流程。
  4. 数据湖 1. 数据湖概念
  数据湖的起源:数据湖的起源应该追溯到2010年10月,由Pentaho的创始人兼CTO James Dixon提出。他的目的是根据当时的历史背景,推广自己的产品 Pentaho。当时要解决的核心问题是传统数仓报表分析面临的两个问题:
  我们现在讨论的数据湖已经远远超过了James Dixon一开始定义的数据湖,各个厂商对数据湖的定义也比较不同。
  1)AWS
  数据湖是一个集中式存储库,可让您以任意规模存储所有结构化和非结构化数据。您可以按原样存储数据,而无需首先构建数据,并运行不同类型的分析——从仪表板和可视化到大数据处理、实时分析和机器学习,以指导更好的决策。
  “数据湖是一个集中式存储库,可让您以任何规模存储所有结构化和非结构化数据。您可以按原样存储数据(无需先对其进行结构化)并运行不同类型的分析——从仪表板和可视化到大数据处理、实时分析和机器学习,以指导更好的决策。”
  2) 微软
  Azure Data Lake 收录使开发人员、数据科学家和分析师能够轻松存储任何大小、形状和速度的数据以及跨平台和语言进行所有类型的处理和分析所需的所有功能。它消除了摄取和存储所有数据的复杂性,同时通过批处理、流式处理和交互式分析更快地启动和运行。
  “Azure 的数据湖包括所有使开发人员、数据科学家和分析师更容易存储和处理数据的功能,这些功能允许用户存储任何大小、类型和速度的数据,并且可以跨平台、做所有类型跨语言分析处理。数据湖可以帮助用户加速应用数据,消除数据采集和存储的复杂性,还支持批处理、流计算、交互分析等。
  3)阿里云
  
  “数据湖是一个统一的存储池,可以对接多种数据输入方式,可以存储任意规模的结构化、半结构化、非结构化数据。数据湖可以无缝对接各种计算和分析平台,根据业务场景,可以选择相应的计算引擎对存储在数据湖中的数据进行处理和分析,从而打破孤岛,挖掘业务价值。”
  2. 数据湖内容
  数据湖包括结构化数据(行和列)、半结构化数据(如CSV、日志、XML、JSON)、非结构化数据(如电子邮件、文档、PDF等)和来自关系数据库的二进制数据数据(例如图像、音频、视频)。
  3. 数据湖的特点 4. 数据湖可以解决的问题
  1)数据湖整体架构
  最底层是分布式文件系统;
  第二层是数据加速层。数据湖架构是存储和计算完全分离的架构。如果所有数据访问都远程读取文件系统上的数据,那么性能和成本开销将是巨大的。如果可以在计算节点本地缓存一些经常访问的热点数据,那么实现冷热分离是很自然的。一方面可以获得良好的本地读取性能,另一方面可以节省远程访问的带宽。
  第三层是Table格式层,主要将一批数据文件封装成具有业务意义的表,提供ACID、snapshot、schema、partition等表级语义。
  最上层是针对不同计算场景的计算引擎。开源一般包括Spark、Flink、Hive、Presto、Hive MR等,这批计算引擎可以同时访问同一个数据湖中的表。
  2)数据湖能解决什么样的问题?
  数据分散,存储分散,形成数据孤岛,无法将数据组合起来发现更多价值。
  在这方面,数据湖其实是和数据仓库类似的问题,但不同的是,它的定义支持半结构化和非结构化数据的管理。传统数据仓库只能解决结构化数据的统一管理。
  在这个万物互联的时代,数据的来源多种多样。随着应用场景的不同,输出的数据格式也越来越丰富,不再局限于结构化数据。如何统一存储这些数据是一个亟待解决的问题。
  3) 存储成本
  数据库或数据仓库的存储受限于实现原理和硬件条件,导致海量数据存储成本高。为了解决这些问题,有HDFS/对象存储等技术方案。在数据湖场景下,如果采用这种低成本的存储技术架构,将为企业大大节省成本。结合生命周期管理的能力,湖中的数据可以更好的分层(冷热存储在不同的存储介质:HDD、SSD、MEM),不用担心数据是保留还是删除数据以节省成本。
  4)SQL已经不能满足的分析需求
  越来越多的数据类型意味着越来越多的分析方法。传统的 SQL 方法已经不能满足分析的需要。如何通过各种语言定制贴近业务的代码?如何通过机器学习挖掘更多?数据价值。
  5)存储/计算可扩展性不足
  在传统数据库等海量数据的情况下,比如规模到PB级别,由于技术架构的原因,已经不能满足扩容需求或者扩容成本极高。这种情况下,通过数据湖架构下的技术能力扩展,实现成本为0,硬件成本也是可控的。商业模式不确定,无法提前建模。
  传统的数据库和数据仓库都是 Schema-on-Write 模式,需要提前定义模式信息。在数据湖场景中,可以先保存数据,以后分析的时候发现Schema,即Schema-on-Read。
  五、对比一、数据仓库VS数据中心VS数据湖
  2. 数据仓库 vs 数据平台
  因为狭义的数据平台是由于数据仓库的历史特性,其存储的数据多为结构化数据,而数据平台的出现解决了数据仓库无法处理非结构化数据和报表的问题开发周期长。数据仓库和数据平台(狭义)是分开比较的。
  本质区别:技术架构和数据容量的差异。
  通过上面的讨论,我们发现数据平台和数据湖之间似乎有很多相似之处。两者的区别应该从个人的角度来分析。数据处理的角度是不同的。数据湖更侧重于原创数据的存储。,而数据平台和数据仓库一样,需要对原创数据进行清洗和转换,并在数据处理后按照统一的标准规范进行存储。
  6.总结
  根据以上对数据平台、数据仓库、数据湖、数据中台的概念讨论和对比,我们做如下总结:
  数据中心、数据仓库和数据湖之间没有直接关系;数据中心、数据平台、数据仓库和数据湖在一定维度上对业务产生价值的形式侧重点不同;数据仓库是数据驱动业务的逻辑概念,用于支持管理决策分析,为业务提供服务的主要方式是报表;数据中心是企业级的逻辑概念,体现了企业数据转化为业务价值的能力,为业务提供服务的主要方式是数据API;数据湖是企业级的技术逻辑概念,体现了企业级数据湖架构加速数据转化为商业价值的能力。为业务提供服务的主要方式是原创数据;数据中心和数据湖更贴近业务,可以更快 数据中心可以建立在数据仓库和数据平台之上,是加速企业从数据到业务价值过程的中间层;
  本文由@Mr.Z 发表 聊产品原创人人都是产品经理。未经许可禁止复制
  标题图片来自 Unsplash,基于 CC0 协议。
  本文观点仅代表作者本人,大家都是产品经理。平台仅提供信息存储空间服务。
  奖励作者,鼓励TA抓紧创作!
  欣赏
  横空出世:百家号热文采集工具-百家号爆文采集助手1.0 免费版
  百家号爆文采集Assistant是专门为百家号开发的一款小工具,你可以轻松使用本软件来采集流行文章,简单好用,需要的朋友可以过来下载!
  百家号爆文采集知识兔助手如何使用
  1.设置采集时间
  
  2.输入需要采集的链接,如果需要批量,可以设置为txt文档
  3.点击分析采集文章信息
  百家号介绍知识兔
  百家号是百度为内容创作者共享的内容发布、内容变现和粉丝管理平台。百家号于2016年6月上线并正式测试。9月,账号系统、分销策略升级、广告系统正式上线。9月28日,正式向所有作者开放。
  
  目前,百家号支持内容创作者轻松发布文章、图片、视频作品,未来将支持H5、VR、直播、动画等内容形式。内容一经提交,将通过手机百度、百度搜索、百度浏览器等多种渠道进行分发。
  点击下载
  下载体验
  点击下载

教程:14、美女福利图片API接口,免费好用

采集交流优采云 发表了文章 • 0 个评论 • 509 次浏览 • 2022-10-26 10:32 • 来自相关话题

  教程:14、美女福利图片API接口,免费好用
  1. 前言
  美女图片福利查询界面,这是RollToolsApi通用系列接口之一,包括1个小接口,可以获得一些年轻美女的图片,非常适合做一些演示。
  
  查看界面完整信息:
  RollToolsApi通用系列接口收录了很多免费的通用API接口,使用这些接口可以帮助你开发很多功能,稳定服务的小程序、APP或网页,无论是训练还是实战都是不错的选择。可以在此处查看所有接口的列表
  2. 接口细节
  
  注意:app_id和app_secret都是临时密钥,如果您真的使用它们,则需要申请自己的独占密钥。
  2.1 获取随机收益图片 2.2 获取收益图像列表
  技巧:4个好用的在线站长工具
  4个有用的在线站长查询工具
  1.Chinaz站长工具
  Chinaz的站长工具是知道的站长,甚至说是站长工具。它有最全面的网站分析工具,通过它你可以简单的了解一个网站的操作。站长之家(中国站长站)成立于2002年3月,是一位资深站长网站,虽然现在离个人站长有点远。在厦门。
  
  2. 爱站网
  爱站成立于2009年,是一家专门为中国网站提供服务的网站。域名反向查找非常有用。在深圳。
  3.上网
  
  是紫天网络继《我要你》免费统计后推出的又一款全新的站长工具。查询域名信息速度很快。在郑州。
  4. 站长助手
  站长助手网络成立于2008年,为站长和SEO工作者提供最有效的站长工具。以前经常用,感觉快了,现在没了。在上海。
  以上是常用的站长工具,还有很多其他的站长工具,数据可能不准确或者存在某种缺陷。 查看全部

  教程:14、美女福利图片API接口,免费好用
  1. 前言
  美女图片福利查询界面,这是RollToolsApi通用系列接口之一,包括1个小接口,可以获得一些年轻美女的图片,非常适合做一些演示。
  
  查看界面完整信息:
  RollToolsApi通用系列接口收录了很多免费的通用API接口,使用这些接口可以帮助你开发很多功能,稳定服务的小程序、APP或网页,无论是训练还是实战都是不错的选择。可以在此处查看所有接口的列表
  2. 接口细节
  
  注意:app_id和app_secret都是临时密钥,如果您真的使用它们,则需要申请自己的独占密钥。
  2.1 获取随机收益图片 2.2 获取收益图像列表
  技巧:4个好用的在线站长工具
  4个有用的在线站长查询工具
  1.Chinaz站长工具
  Chinaz的站长工具是知道的站长,甚至说是站长工具。它有最全面的网站分析工具,通过它你可以简单的了解一个网站的操作。站长之家(中国站长站)成立于2002年3月,是一位资深站长网站,虽然现在离个人站长有点远。在厦门。
  
  2. 爱站网
  爱站成立于2009年,是一家专门为中国网站提供服务的网站。域名反向查找非常有用。在深圳。
  3.上网
  
  是紫天网络继《我要你》免费统计后推出的又一款全新的站长工具。查询域名信息速度很快。在郑州。
  4. 站长助手
  站长助手网络成立于2008年,为站长和SEO工作者提供最有效的站长工具。以前经常用,感觉快了,现在没了。在上海。
  以上是常用的站长工具,还有很多其他的站长工具,数据可能不准确或者存在某种缺陷。

优化的解决方案:简单的API爬虫(和风天气数据获取)

采集交流优采云 发表了文章 • 0 个评论 • 122 次浏览 • 2022-10-25 11:25 • 来自相关话题

  优化的解决方案:简单的API爬虫(和风天气数据获取)
  内容简介
  不知不觉中,我已经快高三了,接触过 C、C++ 和 Python。但我觉得一切都可以一点点,但想了想,也无能为力,最后还是决定开始精通Python之路。从爬虫到数据分析,最后到机器学习。希望每天都有收获。今天开始系统地学习爬虫。
  1.什么是API?
  总之就是一个接口,你可以通过携带一些参数来访问这个接口来获取你想要的数据。
  这次我们使用 Zephyr Weather 提供的 API 来获取我们需要的天气数据。
  2. 步骤
  这一次,我们将编写一个程序,可以根据我们输入的城市名称获取相关的天气数据。
  1.注册一个Zephyr账号
  网址:
  注册后,登录并在应用管理中新建一个Web API类型的应用。记得在创建后复制KEY的值,这个很重要!!!
  然后,我们就可以根据泽风天气提供的API开发文档开始编写代码了。
  API开发文档
  2.获取位置
  首先,通过查询API开发文档,发现需要请求【请求参数】URL。有两个参数是必须携带的,一个是我上面提到的KEY值,另一个是代表城市的位置。location 可以是 LocationID 或逗号分隔的经度、纬度坐标(十进制)。
  泽风天气提供了一个存储LocationID的文档,也有对应的请求URL。LocationID 文件下载地址
  请求URL为【请求参数】,有两个参数必须携带,一个是KEY,一个是location(要查询的区域名称,支持文本,经纬度坐标(十进制)用英文隔开)逗号)、LocationID 或 Adcode(仅限中国城市)。
  我们首先请求第二个 URL 来获取 LocationID。
  代码显示如下:
  #coding:utf-8
import requests
import json
def getID(address,key):
# address=&#39;北京&#39;
url = f&#39;https://geoapi.qweather.com/v2 ... on%3D{address}&key={key}&#39;
datas = requests.get(url).json()
# print(data)
<p>
# print(type(datas))
for data in datas[&#39;location&#39;]:
if data[&#39;name&#39;] == address:
ID = data[&#39;id&#39;]
return ID
</p>
  获取到的数据是字符串类型的,我们通过将其转换为json格式来提取我们需要的位置。
  3.获取天气数据
  代码显示如下:
  def getData(address,ID,key):
url = f&#39;https://devapi.qweather.com/v7 ... on%3D{ID}&key={key}&#39;
datas = requests.get(url).json()
data_updateTime = datas[&#39;updateTime&#39;]
data_time = datas[&#39;now&#39;][&#39;obsTime&#39;]
data_temp = datas[&#39;now&#39;][&#39;temp&#39;]
data_feelsLike = datas[&#39;now&#39;][&#39;feelsLike&#39;]
data_text = datas[&#39;now&#39;][&#39;text&#39;]
data_vis = datas[&#39;now&#39;][&#39;vis&#39;]
print(&#39;{0} {5}\n更新时间:{1}\n观测时间:{2}\n温度:{3} 摄氏度\n体感温度:{4} 摄氏度\n能见度:{6} 公里\n&#39;.format(address,data_updateTime,data_time,data_temp,data_feelsLike,data_text,data_vis))
  这段代码不难,获取数据的格式是需要注意的。
  4.完整代码
  #coding:utf-8
import requests
import json
def getID(address,key):
# address = &#39;北京&#39;
url = f&#39;https://geoapi.qweather.com/v2 ... on%3D{address}&key={key}&#39;
<p>
datas = requests.get(url).json()
# print(data)
# print(type(datas))
for data in datas[&#39;location&#39;]:
if data[&#39;name&#39;] == address:
ID = data[&#39;id&#39;]
return ID
def getData(address,ID,key):
url = f&#39;https://devapi.qweather.com/v7 ... on%3D{ID}&key={key}&#39;
datas = requests.get(url).json()
data_updateTime = datas[&#39;updateTime&#39;]
data_time = datas[&#39;now&#39;][&#39;obsTime&#39;]
data_temp = datas[&#39;now&#39;][&#39;temp&#39;]
data_feelsLike = datas[&#39;now&#39;][&#39;feelsLike&#39;]
data_text = datas[&#39;now&#39;][&#39;text&#39;]
data_vis = datas[&#39;now&#39;][&#39;vis&#39;]
print(&#39;{0} {5}\n更新时间:{1}\n观测时间:{2}\n温度:{3} 摄氏度\n体感温度:{4} 摄氏度\n能见度:{6} 公里\n&#39;.format(address,data_updateTime,data_time,data_temp,data_feelsLike,data_text,data_vis))
if __name__ == &#39;__main__&#39;:
key = &#39;******&#39; //填入你自己的KEY值
address = input(&#39;请输入要查询的天气:&#39;)
ID = getID(address,key)
getData(address, ID, key)
</p>
  总结
  以上就是我们今天要讲的内容。本文仅简单介绍 API 的使用。我们可以通过API开发文档轻松获取我们需要的数据。
  如果需要其他关于泽风天气的数据,可以到API开发文档中获取。
  成熟的解决方案:阿里云如何打破Oracle迁移上云的壁垒
  摘要:在2018年第九届中国数据库技术大会上,阿里云数据库产品专家肖少聪就阿里云如何打破Oracle上云的壁垒发表了演讲。Oracle 指的是“数据库管理系统”。面对甲骨文迁移上云的壁垒,阿里云又该如何打破呢?本文提出了一种从 Oracle 迁移到云数据库的 PPAS 解决方案。为什么这个迁移方案比从Oracle迁移到MySQL系列更容易推广?答案即将揭晓。
  2018年第九届中国数据库技术大会上,阿里云数据库产品专家肖少聪就阿里云如何打破Oracle上云壁垒发表演讲。Oracle 指的是“数据库管理系统”。面对甲骨文迁移上云的壁垒,阿里云又该如何打破呢?本文提出了一种从 Oracle 迁移到云数据库的 PPAS 解决方案。为什么这个迁移方案比从Oracle迁移到MySQL系列更容易推广?答案即将揭晓。
  现场视频回顾
  PPT下载请点击
  以下是视频内容的亮点:
  Oracle 数据库迁移解决方案
  数据业务架构主要分为三大部分:服务器、应用程序、数据库系统和存储系统。解决云服务器和存储系统的问题相对容易,但解决应用程序和数据库系统的问题就有些困难了。因此,阿里云提供了上述解决方案。在这个方案中,用户可以通过不同的方式将数据库迁移到云端,我们可以继续在ECS中运行Oracle,也可以迁移到MySQL。当然,应用程序和数据库系统也可以迁移到 PPAS 版。凭借与Oracle的高度兼容性,降低了用户上云的难度,降低了系统长期运维的复杂度。
  阿里云不仅为云用户提供同城容灾、自动备份、时间点恢复等功能。阿里云数据库还会加入高可用HA,一般需要两个或更多节点进行复杂的配置。在阿里云中,用户一键即可拥有高可用HA,这样的HA集群不仅可以搭建在同一个数据中心,还可以支持同城双中心、异地容灾,同样的一键部署就完成了。同时,阿里云还为用户提供ADAM(Advanced Database &amp; Application Migration “亚当”)工具,借助PPAS的Oracle兼容性,协助用户进行快速迁移。那么接下来的迁移步骤应该如何进行呢?
  在Oracle上安装ADAM采集,ADMA会扮演三个角色:
  Oracle 迁移到 PPAS 比迁移到其他数据库更顺畅,因为有很多兼容的地方。Oracle数据库到PPAS要兼容SQL、存储过程、包、DBMS等,所以适合复杂事务的迁移。ApsaraDB for PPAS 提供高达 3TB 的本地高性能存储(据悉,该空间在今年内有机会超过 10TB)。如果业务数据超出本地存储容量,可以使用OSS存储进行外表处理。例如,历史数据可以存储在 OSS 外部表中。此信息不经常使用,但对数据分析很重要。因此,我们可以通过阿里云HybridDB for PostgreSQL直接从OSS获取数据进行业务分析。HybridDB for PostgreSQL 是阿里云 基于开源Greenplum Database分布式MPP数据库的自己的发布版本。可实现实时业务分析,将计算节点和空间横向扩展至PB级,特定场景下百亿条记录&lt;10ms*排序,支持Rank Hybrid、CUBE、ROLLUP、MADlib学习等。
  
  Oracle 数据库与 MySQL、PPAS 的比较
  为什么Oracle数据库迁移到MySQL家族难推?原因是Oracle数据库迁移到MySQL系列会增加ISV和企业迁移的风险。在整个迁移过程中,代码、存储过程和架构都需要做很大的改变,这会导致研发重新学习、DBA重新学习、代码重新学习。语法重写甚至业务架构重写最终会导致业务风险增加、人工成本增加、产品成本增加。
  Oracle 数据库到云数据库 PPAS 版的推广相对容易,在推广过程中提高了 Oracle 迁移上云的成功率。研发可以持续编写Oracle语法,降低迁移难度和工作量,阿里云可以自动运维和提升DBA SQL优化能力,代码语法几乎不需要改动,ADAM辅助精准分析。
  为什么 PPAS 与 Oralce 的兼容性更好?从上图可以看出,MySOL和Oracle的交集面积比PostgreSQL和Oracle的要小,没有达到预期的效果。预计云数据库PASS版的效果应该是Oracle的区域和PostgreSQL的区域几乎重叠。
  为什么需要这么多兼容的部件?因为这样可以将企业的开发团队、原有的开发成果和已有的应用快速上云。比如开发者开发的软件全部离线,但是客户要求上云,上云需要使用互联网,那么就需要改变原有的存储方式。为了在线和离线维护云架构,需要改变结构,这将需要大量的人力成本。如果有直接兼容Oracle语法的功能,这个时候放到云端会减轻整体负担。
  云数据库PPAS to Oracle兼容的数据类型有很多,如BLOB、CLOB、DATE等。他们每个人都有自己的别名和类型。例如,BLOB 的别名是 LONG RAW,它的类型是二进制数据。
  ADAM 可以通过全量迁移和增量迁移的方式,协助用户将 Oracle 数据库迁移到云端。如果 Oracle 数据量很大,可能需要一周甚至一个月的时间才能完成传输。这时候可以通过高速连接和高速通道来增加带宽,不需要经过互联网,防止传输错误的数据,也不会影响生产库。通过ADAM平台,Oracle数据到云数据库还将提供30天退货机制,为用户迁移割接过程提供最大保障。
  PPAS版不仅具有高可用,还支持同城容灾。用户可以选择使用单AZ集群或多AZ(同城容灾)集群,无需任何额外费用。有保障的企业级容灾需要保护。
  
  PPAS版不仅提供自动备份,还提供50%的免费备份空间。例如,如果用户购买了 1TB 的实例存储空间,他们将直接获得 500GB 的免费备份空间。
  ApsaraDB for PPAS 云管理是按时间点克隆实例。实例克隆功能将于2018年7月上线,支持最长730天的数据备份。目前,仅提供临时实例。
  阿里云 PostgreSQL 生态系统
  Oracle 应用可以迁移到 PPAS 版,它使用高性能本地存储来存储热的 OLTP 业务数据。历史信息存储在外部 OSS 上,OSS 上的数据可以直接被 HybridDB for PostgreSQL 读取和使用,也就是说 OLTP 可以进行业务处理,OLAP 可以直接使用阿里云数据仓库服务。开源Greenplum数据库分布式MPP架构。PostgreSQL 的混合数据库。
  同时,用户也可以保留原有的Oracle系统,只使用HybridDB for PostgreSQL进行分析业务。OLAP 的性能优势如下:
  HybridDB for PostgreSQL 混合分区
  存储可以分为三种存储,即行存储、列存储和OSS温存储。三种存储方式描述如下:
  原创链接 查看全部

  优化的解决方案:简单的API爬虫(和风天气数据获取)
  内容简介
  不知不觉中,我已经快高三了,接触过 C、C++ 和 Python。但我觉得一切都可以一点点,但想了想,也无能为力,最后还是决定开始精通Python之路。从爬虫到数据分析,最后到机器学习。希望每天都有收获。今天开始系统地学习爬虫。
  1.什么是API?
  总之就是一个接口,你可以通过携带一些参数来访问这个接口来获取你想要的数据。
  这次我们使用 Zephyr Weather 提供的 API 来获取我们需要的天气数据。
  2. 步骤
  这一次,我们将编写一个程序,可以根据我们输入的城市名称获取相关的天气数据。
  1.注册一个Zephyr账号
  网址:
  注册后,登录并在应用管理中新建一个Web API类型的应用。记得在创建后复制KEY的值,这个很重要!!!
  然后,我们就可以根据泽风天气提供的API开发文档开始编写代码了。
  API开发文档
  2.获取位置
  首先,通过查询API开发文档,发现需要请求【请求参数】URL。有两个参数是必须携带的,一个是我上面提到的KEY值,另一个是代表城市的位置。location 可以是 LocationID 或逗号分隔的经度、纬度坐标(十进制)。
  泽风天气提供了一个存储LocationID的文档,也有对应的请求URL。LocationID 文件下载地址
  请求URL为【请求参数】,有两个参数必须携带,一个是KEY,一个是location(要查询的区域名称,支持文本,经纬度坐标(十进制)用英文隔开)逗号)、LocationID 或 Adcode(仅限中国城市)。
  我们首先请求第二个 URL 来获取 LocationID。
  代码显示如下:
  #coding:utf-8
import requests
import json
def getID(address,key):
# address=&#39;北京&#39;
url = f&#39;https://geoapi.qweather.com/v2 ... on%3D{address}&key={key}&#39;
datas = requests.get(url).json()
# print(data)
<p>
# print(type(datas))
for data in datas[&#39;location&#39;]:
if data[&#39;name&#39;] == address:
ID = data[&#39;id&#39;]
return ID
</p>
  获取到的数据是字符串类型的,我们通过将其转换为json格式来提取我们需要的位置。
  3.获取天气数据
  代码显示如下:
  def getData(address,ID,key):
url = f&#39;https://devapi.qweather.com/v7 ... on%3D{ID}&key={key}&#39;
datas = requests.get(url).json()
data_updateTime = datas[&#39;updateTime&#39;]
data_time = datas[&#39;now&#39;][&#39;obsTime&#39;]
data_temp = datas[&#39;now&#39;][&#39;temp&#39;]
data_feelsLike = datas[&#39;now&#39;][&#39;feelsLike&#39;]
data_text = datas[&#39;now&#39;][&#39;text&#39;]
data_vis = datas[&#39;now&#39;][&#39;vis&#39;]
print(&#39;{0} {5}\n更新时间:{1}\n观测时间:{2}\n温度:{3} 摄氏度\n体感温度:{4} 摄氏度\n能见度:{6} 公里\n&#39;.format(address,data_updateTime,data_time,data_temp,data_feelsLike,data_text,data_vis))
  这段代码不难,获取数据的格式是需要注意的。
  4.完整代码
  #coding:utf-8
import requests
import json
def getID(address,key):
# address = &#39;北京&#39;
url = f&#39;https://geoapi.qweather.com/v2 ... on%3D{address}&key={key}&#39;
<p>
datas = requests.get(url).json()
# print(data)
# print(type(datas))
for data in datas[&#39;location&#39;]:
if data[&#39;name&#39;] == address:
ID = data[&#39;id&#39;]
return ID
def getData(address,ID,key):
url = f&#39;https://devapi.qweather.com/v7 ... on%3D{ID}&key={key}&#39;
datas = requests.get(url).json()
data_updateTime = datas[&#39;updateTime&#39;]
data_time = datas[&#39;now&#39;][&#39;obsTime&#39;]
data_temp = datas[&#39;now&#39;][&#39;temp&#39;]
data_feelsLike = datas[&#39;now&#39;][&#39;feelsLike&#39;]
data_text = datas[&#39;now&#39;][&#39;text&#39;]
data_vis = datas[&#39;now&#39;][&#39;vis&#39;]
print(&#39;{0} {5}\n更新时间:{1}\n观测时间:{2}\n温度:{3} 摄氏度\n体感温度:{4} 摄氏度\n能见度:{6} 公里\n&#39;.format(address,data_updateTime,data_time,data_temp,data_feelsLike,data_text,data_vis))
if __name__ == &#39;__main__&#39;:
key = &#39;******&#39; //填入你自己的KEY值
address = input(&#39;请输入要查询的天气:&#39;)
ID = getID(address,key)
getData(address, ID, key)
</p>
  总结
  以上就是我们今天要讲的内容。本文仅简单介绍 API 的使用。我们可以通过API开发文档轻松获取我们需要的数据。
  如果需要其他关于泽风天气的数据,可以到API开发文档中获取。
  成熟的解决方案:阿里云如何打破Oracle迁移上云的壁垒
  摘要:在2018年第九届中国数据库技术大会上,阿里云数据库产品专家肖少聪就阿里云如何打破Oracle上云的壁垒发表了演讲。Oracle 指的是“数据库管理系统”。面对甲骨文迁移上云的壁垒,阿里云又该如何打破呢?本文提出了一种从 Oracle 迁移到云数据库的 PPAS 解决方案。为什么这个迁移方案比从Oracle迁移到MySQL系列更容易推广?答案即将揭晓。
  2018年第九届中国数据库技术大会上,阿里云数据库产品专家肖少聪就阿里云如何打破Oracle上云壁垒发表演讲。Oracle 指的是“数据库管理系统”。面对甲骨文迁移上云的壁垒,阿里云又该如何打破呢?本文提出了一种从 Oracle 迁移到云数据库的 PPAS 解决方案。为什么这个迁移方案比从Oracle迁移到MySQL系列更容易推广?答案即将揭晓。
  现场视频回顾
  PPT下载请点击
  以下是视频内容的亮点:
  Oracle 数据库迁移解决方案
  数据业务架构主要分为三大部分:服务器、应用程序、数据库系统和存储系统。解决云服务器和存储系统的问题相对容易,但解决应用程序和数据库系统的问题就有些困难了。因此,阿里云提供了上述解决方案。在这个方案中,用户可以通过不同的方式将数据库迁移到云端,我们可以继续在ECS中运行Oracle,也可以迁移到MySQL。当然,应用程序和数据库系统也可以迁移到 PPAS 版。凭借与Oracle的高度兼容性,降低了用户上云的难度,降低了系统长期运维的复杂度。
  阿里云不仅为云用户提供同城容灾、自动备份、时间点恢复等功能。阿里云数据库还会加入高可用HA,一般需要两个或更多节点进行复杂的配置。在阿里云中,用户一键即可拥有高可用HA,这样的HA集群不仅可以搭建在同一个数据中心,还可以支持同城双中心、异地容灾,同样的一键部署就完成了。同时,阿里云还为用户提供ADAM(Advanced Database &amp; Application Migration “亚当”)工具,借助PPAS的Oracle兼容性,协助用户进行快速迁移。那么接下来的迁移步骤应该如何进行呢?
  在Oracle上安装ADAM采集,ADMA会扮演三个角色:
  Oracle 迁移到 PPAS 比迁移到其他数据库更顺畅,因为有很多兼容的地方。Oracle数据库到PPAS要兼容SQL、存储过程、包、DBMS等,所以适合复杂事务的迁移。ApsaraDB for PPAS 提供高达 3TB 的本地高性能存储(据悉,该空间在今年内有机会超过 10TB)。如果业务数据超出本地存储容量,可以使用OSS存储进行外表处理。例如,历史数据可以存储在 OSS 外部表中。此信息不经常使用,但对数据分析很重要。因此,我们可以通过阿里云HybridDB for PostgreSQL直接从OSS获取数据进行业务分析。HybridDB for PostgreSQL 是阿里云 基于开源Greenplum Database分布式MPP数据库的自己的发布版本。可实现实时业务分析,将计算节点和空间横向扩展至PB级,特定场景下百亿条记录&lt;10ms*排序,支持Rank Hybrid、CUBE、ROLLUP、MADlib学习等。
  
  Oracle 数据库与 MySQL、PPAS 的比较
  为什么Oracle数据库迁移到MySQL家族难推?原因是Oracle数据库迁移到MySQL系列会增加ISV和企业迁移的风险。在整个迁移过程中,代码、存储过程和架构都需要做很大的改变,这会导致研发重新学习、DBA重新学习、代码重新学习。语法重写甚至业务架构重写最终会导致业务风险增加、人工成本增加、产品成本增加。
  Oracle 数据库到云数据库 PPAS 版的推广相对容易,在推广过程中提高了 Oracle 迁移上云的成功率。研发可以持续编写Oracle语法,降低迁移难度和工作量,阿里云可以自动运维和提升DBA SQL优化能力,代码语法几乎不需要改动,ADAM辅助精准分析。
  为什么 PPAS 与 Oralce 的兼容性更好?从上图可以看出,MySOL和Oracle的交集面积比PostgreSQL和Oracle的要小,没有达到预期的效果。预计云数据库PASS版的效果应该是Oracle的区域和PostgreSQL的区域几乎重叠。
  为什么需要这么多兼容的部件?因为这样可以将企业的开发团队、原有的开发成果和已有的应用快速上云。比如开发者开发的软件全部离线,但是客户要求上云,上云需要使用互联网,那么就需要改变原有的存储方式。为了在线和离线维护云架构,需要改变结构,这将需要大量的人力成本。如果有直接兼容Oracle语法的功能,这个时候放到云端会减轻整体负担。
  云数据库PPAS to Oracle兼容的数据类型有很多,如BLOB、CLOB、DATE等。他们每个人都有自己的别名和类型。例如,BLOB 的别名是 LONG RAW,它的类型是二进制数据。
  ADAM 可以通过全量迁移和增量迁移的方式,协助用户将 Oracle 数据库迁移到云端。如果 Oracle 数据量很大,可能需要一周甚至一个月的时间才能完成传输。这时候可以通过高速连接和高速通道来增加带宽,不需要经过互联网,防止传输错误的数据,也不会影响生产库。通过ADAM平台,Oracle数据到云数据库还将提供30天退货机制,为用户迁移割接过程提供最大保障。
  PPAS版不仅具有高可用,还支持同城容灾。用户可以选择使用单AZ集群或多AZ(同城容灾)集群,无需任何额外费用。有保障的企业级容灾需要保护。
  
  PPAS版不仅提供自动备份,还提供50%的免费备份空间。例如,如果用户购买了 1TB 的实例存储空间,他们将直接获得 500GB 的免费备份空间。
  ApsaraDB for PPAS 云管理是按时间点克隆实例。实例克隆功能将于2018年7月上线,支持最长730天的数据备份。目前,仅提供临时实例。
  阿里云 PostgreSQL 生态系统
  Oracle 应用可以迁移到 PPAS 版,它使用高性能本地存储来存储热的 OLTP 业务数据。历史信息存储在外部 OSS 上,OSS 上的数据可以直接被 HybridDB for PostgreSQL 读取和使用,也就是说 OLTP 可以进行业务处理,OLAP 可以直接使用阿里云数据仓库服务。开源Greenplum数据库分布式MPP架构。PostgreSQL 的混合数据库。
  同时,用户也可以保留原有的Oracle系统,只使用HybridDB for PostgreSQL进行分析业务。OLAP 的性能优势如下:
  HybridDB for PostgreSQL 混合分区
  存储可以分为三种存储,即行存储、列存储和OSS温存储。三种存储方式描述如下:
  原创链接

文章采集api 终极:性能指标的信仰危机

采集交流优采云 发表了文章 • 0 个评论 • 116 次浏览 • 2022-10-23 16:49 • 来自相关话题

  文章采集api 终极:性能指标的信仰危机
  阅读这篇文章的你或多或少都接触过前端性能优化。这种联系可能来自您的阅读经历或工作经历。那么我们不妨从一个非常简单的思想实验开始。请根据您对该领域的理解回答以下问题:
  不要有压力,你可以慢慢思考和回答这些问题。你对第一个问题的回答可能会随着第二个和第三个问题的出现而不断调整。
  这篇文章的目的就是对以上三个问题进行探索和尝试性的回答。希望我的回答能给你一些启发。
  一次重播
  目前,我的项目长期依赖 GA(Google Analytic)作为衡量页面性能的唯一工具。在 GA 生态系统中,我们最重视 Avg Page Load Time(以下简称 APLT),通过它来决定我们网站当前的性能状态是什么。
  但是,在定期采集这个指标数据的过程中,我们发现用户的感受和数据显示可能并不一致。具体来说,数据看起来很流畅,但用户体验却直线下降。
  所以我们必须回答一个关键问题,APLT 究竟测量的是什么?
  什么是关键,因为它的答案决定了我们需要解决的下一个问题以及我们需要采取的行动:
  但是,官方文档对这个指标的解释是模棱两可的:
  平均页面加载时间:从开始网页浏览(例如,单击页面链接)到在浏览器中加载完成所花费的平均时间量(以秒为单位)。
  平均 页面加载时间由两部分组成:1)网络和服务器时间,2)浏览器时间。Explorer 选项卡的 Technical 部分提供有关网络的详细信息,剩余时间是用于解析和执行 JavaScript 以及呈现页面的浏览器开销。
  对于它的解释,我们有几个问题:
  遗传算法的实施
  GA底层是采集通过Navigation Timing API的性能数据
  GA 不计算每个阶段的数据。它将一些合并的指标重命名为新的指标,其中一些,例如 Document Interactive Loaded,实际上是某些阶段的统计信息的总和:
  GA 只计算与 DOM 文档相关的数据。APLT定义中提到的加载完成时间是指loadEventEnd事件发生的时间,即onLoad事件被触发的时间(当load事件被触发时,是指所有外部资源,包括iframe、图片、脚本、样式已加载)。因此,APLT 值是 GA 中所有指标中时间跨度最宽的。
  脚本对平均页面加载时间有什么影响
  如上图所示,浏览器在从上到下解析DOM树时,会遇到很多图片、样式、脚本等外部资源。所以它需要从缓存或网络中请求这些资源。
  页面的解析是同步的,所以脚本的加载会导致页面解析的暂停。浏览器在继续解析之前需要加载、编译和执行脚本,这是有道理的,因为 JavaScript 可能会使用 document.write() 等方法来改变 DOM 的结构。您可能听说过将 async 或 defer 属性添加到脚本标签以异步加载和执行脚本。但它在我们的生产中不起作用,因为 async 不保证脚本执行的顺序。但这种方案不一定适用于所有页面,因为 async 无法保证脚本的执行顺序。如果你的应用程序对脚本的执行顺序有严格的要求,那么它就帮不了你了。
  目前浏览器都配备了preloader机制来提前扫描页面中的外部元素,但是这个机制没有统一的标准,无法衡量效果,所以我们暂时不考虑它对我们的影响.
  脚本下载后,需要进行解析(parse/compile)和执行(run/execute)。解析阶段首先将 javascript 代码编译成机器语言,执行阶段将实际运行我们编写的代码。脚本的解析和执行也会阻塞页面的解析
  所以综上所述,我们可以得出结论,该脚本确实可以影响APLT。
  但是放弃衡量和谈论伤害都是流氓行为。它的影响范围有多大?也就是如果APLT是2秒,那么脚本用了多少时间?
  这里没有具体的数字,但也不能小觑,足以影响性能。Addy Osmani 在 2017 年的一篇文章 文章 中指出 Chrome 的脚本引擎会花费编译时间
  虽然 Chrome 此后优化了编译过程,但执行脚本过长的问题依然存在。同时这只是Chrome中的情况,我们无法确认其他浏览器在编译脚本时也能保证同样的效率
  如果APLT由不同的阶段组成,我们是否可以计算出每个阶段的具体时间?
  回顾上面对 GA 指标的定义,至少我们现在可以将服务器时间和浏览器时间分开。但是浏览器时间呢?比如脚本的下载时间和执行时间,我们无从得知。这些是额外的计算和 采集。
  综上所述,我们完全依赖APLT来诊断网站的性能问题是不可靠的,简单地认为脚本负担拖慢了性能也是不完全的。
  对指标的信任危机
  我想您可能会明白为什么我在上一节中花了这么多时间来解释仅一个指标的含义。因为一个指标可以揭示的信息可能比你想象的要复杂,领先和误导并存。
  首先,我不反对使用通用指标,并且这个 文章 并不是对它们的批评,它们在帮助我们解决性能问题方面提供了巨大的帮助。我这里要讨论的是,如果常规指标是性能监控的底线,那么上限在哪里?
  从以上描述不难看出,APLT的维度过于宽泛,更倾向于综合技术指标,向我们展示趋势而非细节。这有两个问题:
  接下来,我们深入讨论这两个问题。
  以用户为中心
  您可能已经注意到,当前前端性能监控的趋势正在逐渐向 User-Centric Performance Metrics 发展。为什么会出现这种情况?因为随着单页应用的普及和前端功能的“繁重”,经典的以资源为中心的性能指标(如 Onload、DOMContentLoaded)越来越无法准确反馈真实的用户体验和产品性能。在后端渲染的传统多页面应用模式中,资源加载完成意味着页面可供用户使用;而在单页模式下,资源加载的完成与产品的可用性之间存在一定的差距,因为只有这样,应用才能真正向用户请求个性化数据,呈现定制化的页面。
  一般来说,越来越多的重要和耗时的工作发生在资源加载之后,我们需要监控这部分工作的性能。
  好消息是浏览器原生为我们提供了这方面的支持。例如,Chrome 在 Performace API 中提供了 Paint Timing API,如首次绘制(FP)、首次内容绘制(FCP)、交互时间(tti)等指标。数据。顾名思义,这些指标试图从用户体验的角度显示应用在浏览器中呈现时的性能;坏消息是,这些指标在衡量真实用户体验方面仍然不准确。
  以上面提到的FP、FCP、TTI这三个指标为例,我将通过一个简单的例子来说明这三个指标是如何不够准确的:在单个页面的初始化过程中,我们通常会提供类似于“ “正在加载”视图,通常是占位符或骨架样式,将在数据请求完成后渲染实际视图:
  如果加载时间过长,浏览器会认为“加载中”的视图是用户可用的最终产品形式,并以此为基准计算上述三个指标
  
  下面的代码模拟了一个日常的情况,包括上面提到的情况:在组件加载时模拟两个请求,其中一个需要5秒的长时间等待,只有当两个请求都返回时,才能渲染数据。否则,总是提示用户加载。
  function App() {
const [data, setState] = useState([]);
useEffect(() => {
const longRequest = new Promise((resolve, reject) => {
setTimeout(() => {
resolve([]);
}, 1000 * 5)
});
const shortRequest = Promise.resolve([]);

Promise.all([longRequest, shortRequest]).then(([longRequestResponse, shortRequestResponse]) => {
setState([
[&#x27;&#x27;, &#x27;Tesla&#x27;, &#x27;Mercedes&#x27;, &#x27;Toyota&#x27;, &#x27;Volvo&#x27;],
[&#x27;2019&#x27;, 10, 11, 12, 13],
[&#x27;2020&#x27;, 20, 11, 14, 13],
[&#x27;2021&#x27;, 30, 15, 12, 13]
])
})
}, []);
return (

{data && data.length
?
: }

)
}
  复制
  如果您尝试在浏览器中运行上述应用程序,通过 Devtools 观察到的各种指标如下:
  可以通过开发者工具观察各种指标,如DCL(DOMContentLoaded Event)、FP、FCP、FMP(first有意义的绘制)、L(Onload Event)都在页面加载后的一秒左右发生。但是,从代码中我们可以肯定,用户至少需要 5 秒钟才能看到真实的内容。因此,上述指标并不能真正反馈用户遇到的性能问题。
  我已将该应用程序部署到该站点并可以在线访问它。并且你可以用它来做更详细的性能测试,它会给出和 devtools 一样的结果。网页测试是一个用于网站 性能测试的开源免费工具。早在 2012 年还没有 FP 等指标的时候,其原有的 Speed Index 指标就能够衡量用户体验。
  一般来说,如上图所示,浏览器提供的API只能衡量D阶段的性能,对E阶段和F阶段的表现帮助不大。
  这只是原生指标不准确的一个例子,可以总结为后端接口延迟过长。但是,还有一种情况是前端渲染时间过长。例如,当我们使用 Handsontable 组件渲染数千行数据表时,甚至会导致浏览器死机,这对 Paint Timing API 是免疫的。
  tti 指标呢?听起来它不是可以检测页面是否是交互式的吗?是不是无法检测到页面的假死?
  不幸的是,它仍然不起作用。
  如果你看一下 tti 指标的定义,你会发现 tti 本质上是一个算法:
  并且目前的原生 API 不支持 tti 指标,需要通过 polyfill 来实现。根据官方说明,目前并不适合所有网络应用。
  双向指示器
  
  这是知乎创作者中心页面的截图
  在此页面上,知乎 将每天向您更新过去 7 天的 文章 阅读、点赞、评论和其他数据的摘要。上图中的虚线是读数的数量。
  我知道它的目的是向创作者提供关于他们的数据的反馈,以帮助他们制作更好的内容,但至少对我来说它根本不起作用。因为我更想知道增长从哪里来,这样我就可以针对带来点击的内容。但它带给我的始终是聚合数据。
  这一要求也适用于性能监控。监控的目的是及时发现和解决问题。因此,在考察数据的过程中,我们更关心异常波动发生的时间和地点,也希望数据能在这方面对我有所帮助。
  当然,我们不可能无中生有地将一组汇总数据还原为详细数据,但在这个问题上我们可以从两个方向着手:
  在《Web Performance Calendar 2020 Edition 中的 Web 性能工具愿望清单》一文中,作者提出了他理想的性能工具应该满足的四个功能,即:
  其中第二个和第三个对我们选择指标也是有效的,这与我上面强调的不谋而合。
  最后,再次强调,这并不是对传统指标的否定。有数据的效果总比没有好。指标越多,绩效概况就越准确。以下是如何在这些基础上再接再厉,继续事半功倍,以提高我们寻求问题的效率。
  关于选择指标的一些建议
  上下文驱动
  我之所以不能在这里给你一个大而全面的解决方案是因为我认为这样的事情不存在,一切都取决于你的上下文。
  您可能更熟悉上下文驱动测试,但在我看来,当您选择性能指标或工具时,上下文驱动测试也适用。让我们看一下上下文测试的七个原则中的前两个:
  试想一下,如果把两句中的做法理解为一个度量,甚至直接用一个度量来代替,是不是没有什么不协调的感觉呢?
  乍一看,“上下文驱动”似乎是一个反驳的论点,但实际上它是我们提高监控效率的有效途径。指标本身没有对错之分,但不同人群对指标的看法不同:业务分析师想要的是能够直接展示业务价值的数据,比如点击率、弹窗率、用户转化等;DevOps同学,他们可能关心的是网站的“心跳”,资源的消耗,后端接口的速度;因此,不同的指标在不同的人群中处于潮起潮落的状态。这种分离也可以从技术角度进行划分。有的指标更注重资源,有的指标更注重用户体验。
  Metrics 只是发现问题的一种手段,现在我们有无数种手段可供选择:APM(应用程序性能管理)、日志分析、RUM(真实用户监控)、TTFB(Time to First Byte)……到底它迫使你回到问题的开头:我到底想测量什么?我想测量的对象可以用现有的指标来表达吗?我只想监控?如果我想调试或分析,还有其他选择吗?
  “好的软件测试是一个具有挑战性的智力过程。” (用性能调优代替测试),上下文驱动测试的第六条原则。
  微量元素
  如果说“资源已加载”不可靠,“浏览器开始绘制”不可靠,我认为唯一可靠的就是用户看到的。没有必要用各种数据来显示你的页面加载速度有多快,如果用户每次看到他想看的信息都要等十秒钟,那么这些数字只是自欺欺人。因此,我们不妨跟踪用户注意力信息对应的元素出现的时间。
  这不是创新。从早年的 Speed Index、“首屏”到今天的 web Vitals,都是这一理念的延续。指标的演进过程就像一个不断缩小过程中的圆圈,不断的向用户自身靠拢。只是由于技术手段的限制,他们只能走到这一步,而现在我们有了 MutationObserver 和 Perforamce API,我们可以准确定位元素,甚至元素上的属性发生变化,自然不会受到上面例子的影响。被占位符欺骗。
  对不起,这里不得不再次强调一下上下文:我们不能只关注“一个元素出现的时机”,还要从时间和代码扩展的角度来关注它的形成原因,这仍然需要我们结合环境,这取决于它是如何工作的。两个例子:
  上图中,如果组件D是向客户展示关键信息的关键元素,那么请求到达路由器的时间和组件C被路由器渲染的时间都会对D元素产生影响;从另一个维度:
  脚本和请求的加载和执行速度也会影响元素的外观。如果您需要诊断问题,了解这些问题背后的工作原理至关重要。
  但是跟踪元素还有一个问题,就是难以大规模应用。因为它是侵入性的,因为它要求您识别不同页面上的不同关键元素,并以一种近似硬代码的方式逐个跟踪它们。这种类型的工作会产生接近于维护前端 E2E 测试的维护成本。的确,我们可以通过分配统一的id或者类名来降低我们的维护成本,但是相比统一的GA代码,维护成本还是很高的。所以我建议用最简单的方式去监控最直接的元素,不要一个个地写你的监控代码,也不要让你的实现代码被监控代码绑定。
  让工具为您服务
  您可以在市场上找到无数声称可以帮助您提高绩效的工具。但首先你必须小心,他们所宣扬的并不是你真正需要的。
  例如 site24x7 是一家专门提供用户行为监控解决方案的公司。在他们关于 APM 的帮助页面上,指出监视和捕获 SAP(单页应用程序)性能数据实际上是当前技术的一项具有挑战性的工作:
  在单页应用程序的情况下,页面加载完成所用的时间无法通过页面加载事件获取,因为数据是使用从服务器动态获取的
  因此,对于每个 SPA 框架,页面加载指标是通过侦听特定于框架的特定事件来计算的。
  所以对于这种类型的页面,它们只捕获:
  对于每个动态页面加载,都会捕获相应的 URL、相应的 AJAX 调用、每个 AJAX 调用的响应时间、响应代码和错误(如果有)。
  但要知道,在当今流行的SPA中,这样的采集功能显得有些苍白。
  同样,如果您查看 Azure Application Insights 的 JavaScript SDK 中默认采集的页面信息:
  您的应用程序 XHR 和 Fetch 发出的网络依赖请求(默认情况下禁用获取集合)请求,包括有关用户信息(例如,位置、网络、IP)的信息设备信息(例如,浏览器、操作系统、版本、语言、型号)会话信息
  与其他平台提供的相比,我认为这些指标并没有增加额外的价值,它可以真正给我多少真正的“洞察力”。
  另一方面,不要让你的思维被工具限制:不要“因为xx工具只能做这么多,所以我只能采集这些指标”;而是“我想采集这些指标,所以我需要 xx 工具”。这里我列出一个我们正在探索的例子:使用 OpenTracing 工具 Jaeger 可视化前端性能图表。
  这里首先要赞一下Chrome内置的Performance工具,给我们调优性能带来了极大的便利。但我们总是有一些无法满足的额外需求。例如,我希望能够在结果演示中做一些自定义标记,或者在 Performance 选项卡下显示从 connect 到 resposne 的每个请求的每个阶段的状态。
  如下图所示,我们使用Jaeger开源工具跨界采集和展示自定义指标。可以说,不同纬度的指标以时间为线索链接,使页面加载阶段状态一览无余。容易定位问题。
  结束语
  我观察到,对于大部分前端工程师,或者以前的自己来说,做性能监控是一个被“喂”的过程,也就是会习惯性的采集已有的指标,不假思索地使用已有的工具。并且因为性能优化工作过程的前后结果的关系,我们只有在有需求的时候才会发现当前的结果并不是我们想要的。多一点思考将使我们的工作减少浪费。
  终极:解密搜索引擎的工作原理
  想获取更多干货教程,加Q群:173903050
  ★
  网站要想有好的排名,我们必须了解网站的基本优化,这就需要我们对搜索引擎的工作原理有一个很好的了解。只有这样,搜索引擎才会青睐我们的网站。
  知道什么是百度蜘蛛吗?百度蜘蛛是百度搜索引擎的自动程序。它的功能是访问和采集互联网上的网页、图片、视频等内容,然后按类别建立索引库,让用户可以搜索到你的网站网页、图片、视频等内容在百度搜索引擎中。
  搜索引擎在工作中主要进行以下几个步骤:
  ★
  1. 抢
  搜索引擎通过网站的链接不断爬取每个页面,不断采集整理互联网上的内容。这是爬行。我们可以发送外部链接,关注它们,创建高质量的外部链接。,路径要避开中文路径,路径太长,不利于爬行的因素被蜘蛛拒绝。
  
  2.过滤
  搜索引擎爬取后会存入临时数据库,同时过滤掉网站的垃圾内容,保留对用户有益的内容。
  常见的影响因素有:
  (一)文字、图片、视频、链接;
  (2) 速度;
  (3) 页面质量;
  (4)网站的权重和信用;
  (5) 页面的相似性;
  3. 收录
  搜索引擎过滤掉垃圾邮件后,会对剩余的网站内容执行收录。这时候可以使用site命令或者站长平台查看收录的状态。有收录才有排名,收录是保证排名的前提;收录 不一定有排名。
  
  收录 和索引之间的关系是包容关系。索引只能在收录之后建立,收录的数量大于索引的数量。百度站长平台链接提交工具是收录的入口。
  4.排序
  排序取决于两个因素:
  1、基础优化分数要求我们提高基础优化;
  2、用户投票评分需要良好的综合数据来提升用户体验。
  ★
  以上是我对搜索引擎工作原理的基本了解。通过查询我的网站收录的情况,可以判断出网站哪里出了问题,并找到解决方案,从而可以做的更好的优化。
  ★ 查看全部

  文章采集api 终极:性能指标的信仰危机
  阅读这篇文章的你或多或少都接触过前端性能优化。这种联系可能来自您的阅读经历或工作经历。那么我们不妨从一个非常简单的思想实验开始。请根据您对该领域的理解回答以下问题:
  不要有压力,你可以慢慢思考和回答这些问题。你对第一个问题的回答可能会随着第二个和第三个问题的出现而不断调整。
  这篇文章的目的就是对以上三个问题进行探索和尝试性的回答。希望我的回答能给你一些启发。
  一次重播
  目前,我的项目长期依赖 GA(Google Analytic)作为衡量页面性能的唯一工具。在 GA 生态系统中,我们最重视 Avg Page Load Time(以下简称 APLT),通过它来决定我们网站当前的性能状态是什么。
  但是,在定期采集这个指标数据的过程中,我们发现用户的感受和数据显示可能并不一致。具体来说,数据看起来很流畅,但用户体验却直线下降。
  所以我们必须回答一个关键问题,APLT 究竟测量的是什么?
  什么是关键,因为它的答案决定了我们需要解决的下一个问题以及我们需要采取的行动:
  但是,官方文档对这个指标的解释是模棱两可的:
  平均页面加载时间:从开始网页浏览(例如,单击页面链接)到在浏览器中加载完成所花费的平均时间量(以秒为单位)。
  平均 页面加载时间由两部分组成:1)网络和服务器时间,2)浏览器时间。Explorer 选项卡的 Technical 部分提供有关网络的详细信息,剩余时间是用于解析和执行 JavaScript 以及呈现页面的浏览器开销。
  对于它的解释,我们有几个问题:
  遗传算法的实施
  GA底层是采集通过Navigation Timing API的性能数据
  GA 不计算每个阶段的数据。它将一些合并的指标重命名为新的指标,其中一些,例如 Document Interactive Loaded,实际上是某些阶段的统计信息的总和:
  GA 只计算与 DOM 文档相关的数据。APLT定义中提到的加载完成时间是指loadEventEnd事件发生的时间,即onLoad事件被触发的时间(当load事件被触发时,是指所有外部资源,包括iframe、图片、脚本、样式已加载)。因此,APLT 值是 GA 中所有指标中时间跨度最宽的。
  脚本对平均页面加载时间有什么影响
  如上图所示,浏览器在从上到下解析DOM树时,会遇到很多图片、样式、脚本等外部资源。所以它需要从缓存或网络中请求这些资源。
  页面的解析是同步的,所以脚本的加载会导致页面解析的暂停。浏览器在继续解析之前需要加载、编译和执行脚本,这是有道理的,因为 JavaScript 可能会使用 document.write() 等方法来改变 DOM 的结构。您可能听说过将 async 或 defer 属性添加到脚本标签以异步加载和执行脚本。但它在我们的生产中不起作用,因为 async 不保证脚本执行的顺序。但这种方案不一定适用于所有页面,因为 async 无法保证脚本的执行顺序。如果你的应用程序对脚本的执行顺序有严格的要求,那么它就帮不了你了。
  目前浏览器都配备了preloader机制来提前扫描页面中的外部元素,但是这个机制没有统一的标准,无法衡量效果,所以我们暂时不考虑它对我们的影响.
  脚本下载后,需要进行解析(parse/compile)和执行(run/execute)。解析阶段首先将 javascript 代码编译成机器语言,执行阶段将实际运行我们编写的代码。脚本的解析和执行也会阻塞页面的解析
  所以综上所述,我们可以得出结论,该脚本确实可以影响APLT。
  但是放弃衡量和谈论伤害都是流氓行为。它的影响范围有多大?也就是如果APLT是2秒,那么脚本用了多少时间?
  这里没有具体的数字,但也不能小觑,足以影响性能。Addy Osmani 在 2017 年的一篇文章 文章 中指出 Chrome 的脚本引擎会花费编译时间
  虽然 Chrome 此后优化了编译过程,但执行脚本过长的问题依然存在。同时这只是Chrome中的情况,我们无法确认其他浏览器在编译脚本时也能保证同样的效率
  如果APLT由不同的阶段组成,我们是否可以计算出每个阶段的具体时间?
  回顾上面对 GA 指标的定义,至少我们现在可以将服务器时间和浏览器时间分开。但是浏览器时间呢?比如脚本的下载时间和执行时间,我们无从得知。这些是额外的计算和 采集。
  综上所述,我们完全依赖APLT来诊断网站的性能问题是不可靠的,简单地认为脚本负担拖慢了性能也是不完全的。
  对指标的信任危机
  我想您可能会明白为什么我在上一节中花了这么多时间来解释仅一个指标的含义。因为一个指标可以揭示的信息可能比你想象的要复杂,领先和误导并存。
  首先,我不反对使用通用指标,并且这个 文章 并不是对它们的批评,它们在帮助我们解决性能问题方面提供了巨大的帮助。我这里要讨论的是,如果常规指标是性能监控的底线,那么上限在哪里?
  从以上描述不难看出,APLT的维度过于宽泛,更倾向于综合技术指标,向我们展示趋势而非细节。这有两个问题:
  接下来,我们深入讨论这两个问题。
  以用户为中心
  您可能已经注意到,当前前端性能监控的趋势正在逐渐向 User-Centric Performance Metrics 发展。为什么会出现这种情况?因为随着单页应用的普及和前端功能的“繁重”,经典的以资源为中心的性能指标(如 Onload、DOMContentLoaded)越来越无法准确反馈真实的用户体验和产品性能。在后端渲染的传统多页面应用模式中,资源加载完成意味着页面可供用户使用;而在单页模式下,资源加载的完成与产品的可用性之间存在一定的差距,因为只有这样,应用才能真正向用户请求个性化数据,呈现定制化的页面。
  一般来说,越来越多的重要和耗时的工作发生在资源加载之后,我们需要监控这部分工作的性能。
  好消息是浏览器原生为我们提供了这方面的支持。例如,Chrome 在 Performace API 中提供了 Paint Timing API,如首次绘制(FP)、首次内容绘制(FCP)、交互时间(tti)等指标。数据。顾名思义,这些指标试图从用户体验的角度显示应用在浏览器中呈现时的性能;坏消息是,这些指标在衡量真实用户体验方面仍然不准确。
  以上面提到的FP、FCP、TTI这三个指标为例,我将通过一个简单的例子来说明这三个指标是如何不够准确的:在单个页面的初始化过程中,我们通常会提供类似于“ “正在加载”视图,通常是占位符或骨架样式,将在数据请求完成后渲染实际视图:
  如果加载时间过长,浏览器会认为“加载中”的视图是用户可用的最终产品形式,并以此为基准计算上述三个指标
  
  下面的代码模拟了一个日常的情况,包括上面提到的情况:在组件加载时模拟两个请求,其中一个需要5秒的长时间等待,只有当两个请求都返回时,才能渲染数据。否则,总是提示用户加载。
  function App() {
const [data, setState] = useState([]);
useEffect(() => {
const longRequest = new Promise((resolve, reject) => {
setTimeout(() => {
resolve([]);
}, 1000 * 5)
});
const shortRequest = Promise.resolve([]);

Promise.all([longRequest, shortRequest]).then(([longRequestResponse, shortRequestResponse]) => {
setState([
[&#x27;&#x27;, &#x27;Tesla&#x27;, &#x27;Mercedes&#x27;, &#x27;Toyota&#x27;, &#x27;Volvo&#x27;],
[&#x27;2019&#x27;, 10, 11, 12, 13],
[&#x27;2020&#x27;, 20, 11, 14, 13],
[&#x27;2021&#x27;, 30, 15, 12, 13]
])
})
}, []);
return (

{data && data.length
?
: }

)
}
  复制
  如果您尝试在浏览器中运行上述应用程序,通过 Devtools 观察到的各种指标如下:
  可以通过开发者工具观察各种指标,如DCL(DOMContentLoaded Event)、FP、FCP、FMP(first有意义的绘制)、L(Onload Event)都在页面加载后的一秒左右发生。但是,从代码中我们可以肯定,用户至少需要 5 秒钟才能看到真实的内容。因此,上述指标并不能真正反馈用户遇到的性能问题。
  我已将该应用程序部署到该站点并可以在线访问它。并且你可以用它来做更详细的性能测试,它会给出和 devtools 一样的结果。网页测试是一个用于网站 性能测试的开源免费工具。早在 2012 年还没有 FP 等指标的时候,其原有的 Speed Index 指标就能够衡量用户体验。
  一般来说,如上图所示,浏览器提供的API只能衡量D阶段的性能,对E阶段和F阶段的表现帮助不大。
  这只是原生指标不准确的一个例子,可以总结为后端接口延迟过长。但是,还有一种情况是前端渲染时间过长。例如,当我们使用 Handsontable 组件渲染数千行数据表时,甚至会导致浏览器死机,这对 Paint Timing API 是免疫的。
  tti 指标呢?听起来它不是可以检测页面是否是交互式的吗?是不是无法检测到页面的假死?
  不幸的是,它仍然不起作用。
  如果你看一下 tti 指标的定义,你会发现 tti 本质上是一个算法:
  并且目前的原生 API 不支持 tti 指标,需要通过 polyfill 来实现。根据官方说明,目前并不适合所有网络应用。
  双向指示器
  
  这是知乎创作者中心页面的截图
  在此页面上,知乎 将每天向您更新过去 7 天的 文章 阅读、点赞、评论和其他数据的摘要。上图中的虚线是读数的数量。
  我知道它的目的是向创作者提供关于他们的数据的反馈,以帮助他们制作更好的内容,但至少对我来说它根本不起作用。因为我更想知道增长从哪里来,这样我就可以针对带来点击的内容。但它带给我的始终是聚合数据。
  这一要求也适用于性能监控。监控的目的是及时发现和解决问题。因此,在考察数据的过程中,我们更关心异常波动发生的时间和地点,也希望数据能在这方面对我有所帮助。
  当然,我们不可能无中生有地将一组汇总数据还原为详细数据,但在这个问题上我们可以从两个方向着手:
  在《Web Performance Calendar 2020 Edition 中的 Web 性能工具愿望清单》一文中,作者提出了他理想的性能工具应该满足的四个功能,即:
  其中第二个和第三个对我们选择指标也是有效的,这与我上面强调的不谋而合。
  最后,再次强调,这并不是对传统指标的否定。有数据的效果总比没有好。指标越多,绩效概况就越准确。以下是如何在这些基础上再接再厉,继续事半功倍,以提高我们寻求问题的效率。
  关于选择指标的一些建议
  上下文驱动
  我之所以不能在这里给你一个大而全面的解决方案是因为我认为这样的事情不存在,一切都取决于你的上下文。
  您可能更熟悉上下文驱动测试,但在我看来,当您选择性能指标或工具时,上下文驱动测试也适用。让我们看一下上下文测试的七个原则中的前两个:
  试想一下,如果把两句中的做法理解为一个度量,甚至直接用一个度量来代替,是不是没有什么不协调的感觉呢?
  乍一看,“上下文驱动”似乎是一个反驳的论点,但实际上它是我们提高监控效率的有效途径。指标本身没有对错之分,但不同人群对指标的看法不同:业务分析师想要的是能够直接展示业务价值的数据,比如点击率、弹窗率、用户转化等;DevOps同学,他们可能关心的是网站的“心跳”,资源的消耗,后端接口的速度;因此,不同的指标在不同的人群中处于潮起潮落的状态。这种分离也可以从技术角度进行划分。有的指标更注重资源,有的指标更注重用户体验。
  Metrics 只是发现问题的一种手段,现在我们有无数种手段可供选择:APM(应用程序性能管理)、日志分析、RUM(真实用户监控)、TTFB(Time to First Byte)……到底它迫使你回到问题的开头:我到底想测量什么?我想测量的对象可以用现有的指标来表达吗?我只想监控?如果我想调试或分析,还有其他选择吗?
  “好的软件测试是一个具有挑战性的智力过程。” (用性能调优代替测试),上下文驱动测试的第六条原则。
  微量元素
  如果说“资源已加载”不可靠,“浏览器开始绘制”不可靠,我认为唯一可靠的就是用户看到的。没有必要用各种数据来显示你的页面加载速度有多快,如果用户每次看到他想看的信息都要等十秒钟,那么这些数字只是自欺欺人。因此,我们不妨跟踪用户注意力信息对应的元素出现的时间。
  这不是创新。从早年的 Speed Index、“首屏”到今天的 web Vitals,都是这一理念的延续。指标的演进过程就像一个不断缩小过程中的圆圈,不断的向用户自身靠拢。只是由于技术手段的限制,他们只能走到这一步,而现在我们有了 MutationObserver 和 Perforamce API,我们可以准确定位元素,甚至元素上的属性发生变化,自然不会受到上面例子的影响。被占位符欺骗。
  对不起,这里不得不再次强调一下上下文:我们不能只关注“一个元素出现的时机”,还要从时间和代码扩展的角度来关注它的形成原因,这仍然需要我们结合环境,这取决于它是如何工作的。两个例子:
  上图中,如果组件D是向客户展示关键信息的关键元素,那么请求到达路由器的时间和组件C被路由器渲染的时间都会对D元素产生影响;从另一个维度:
  脚本和请求的加载和执行速度也会影响元素的外观。如果您需要诊断问题,了解这些问题背后的工作原理至关重要。
  但是跟踪元素还有一个问题,就是难以大规模应用。因为它是侵入性的,因为它要求您识别不同页面上的不同关键元素,并以一种近似硬代码的方式逐个跟踪它们。这种类型的工作会产生接近于维护前端 E2E 测试的维护成本。的确,我们可以通过分配统一的id或者类名来降低我们的维护成本,但是相比统一的GA代码,维护成本还是很高的。所以我建议用最简单的方式去监控最直接的元素,不要一个个地写你的监控代码,也不要让你的实现代码被监控代码绑定。
  让工具为您服务
  您可以在市场上找到无数声称可以帮助您提高绩效的工具。但首先你必须小心,他们所宣扬的并不是你真正需要的。
  例如 site24x7 是一家专门提供用户行为监控解决方案的公司。在他们关于 APM 的帮助页面上,指出监视和捕获 SAP(单页应用程序)性能数据实际上是当前技术的一项具有挑战性的工作:
  在单页应用程序的情况下,页面加载完成所用的时间无法通过页面加载事件获取,因为数据是使用从服务器动态获取的
  因此,对于每个 SPA 框架,页面加载指标是通过侦听特定于框架的特定事件来计算的。
  所以对于这种类型的页面,它们只捕获:
  对于每个动态页面加载,都会捕获相应的 URL、相应的 AJAX 调用、每个 AJAX 调用的响应时间、响应代码和错误(如果有)。
  但要知道,在当今流行的SPA中,这样的采集功能显得有些苍白。
  同样,如果您查看 Azure Application Insights 的 JavaScript SDK 中默认采集的页面信息:
  您的应用程序 XHR 和 Fetch 发出的网络依赖请求(默认情况下禁用获取集合)请求,包括有关用户信息(例如,位置、网络、IP)的信息设备信息(例如,浏览器、操作系统、版本、语言、型号)会话信息
  与其他平台提供的相比,我认为这些指标并没有增加额外的价值,它可以真正给我多少真正的“洞察力”。
  另一方面,不要让你的思维被工具限制:不要“因为xx工具只能做这么多,所以我只能采集这些指标”;而是“我想采集这些指标,所以我需要 xx 工具”。这里我列出一个我们正在探索的例子:使用 OpenTracing 工具 Jaeger 可视化前端性能图表。
  这里首先要赞一下Chrome内置的Performance工具,给我们调优性能带来了极大的便利。但我们总是有一些无法满足的额外需求。例如,我希望能够在结果演示中做一些自定义标记,或者在 Performance 选项卡下显示从 connect 到 resposne 的每个请求的每个阶段的状态。
  如下图所示,我们使用Jaeger开源工具跨界采集和展示自定义指标。可以说,不同纬度的指标以时间为线索链接,使页面加载阶段状态一览无余。容易定位问题。
  结束语
  我观察到,对于大部分前端工程师,或者以前的自己来说,做性能监控是一个被“喂”的过程,也就是会习惯性的采集已有的指标,不假思索地使用已有的工具。并且因为性能优化工作过程的前后结果的关系,我们只有在有需求的时候才会发现当前的结果并不是我们想要的。多一点思考将使我们的工作减少浪费。
  终极:解密搜索引擎的工作原理
  想获取更多干货教程,加Q群:173903050
  ★
  网站要想有好的排名,我们必须了解网站的基本优化,这就需要我们对搜索引擎的工作原理有一个很好的了解。只有这样,搜索引擎才会青睐我们的网站。
  知道什么是百度蜘蛛吗?百度蜘蛛是百度搜索引擎的自动程序。它的功能是访问和采集互联网上的网页、图片、视频等内容,然后按类别建立索引库,让用户可以搜索到你的网站网页、图片、视频等内容在百度搜索引擎中。
  搜索引擎在工作中主要进行以下几个步骤:
  ★
  1. 抢
  搜索引擎通过网站的链接不断爬取每个页面,不断采集整理互联网上的内容。这是爬行。我们可以发送外部链接,关注它们,创建高质量的外部链接。,路径要避开中文路径,路径太长,不利于爬行的因素被蜘蛛拒绝。
  
  2.过滤
  搜索引擎爬取后会存入临时数据库,同时过滤掉网站的垃圾内容,保留对用户有益的内容。
  常见的影响因素有:
  (一)文字、图片、视频、链接;
  (2) 速度;
  (3) 页面质量;
  (4)网站的权重和信用;
  (5) 页面的相似性;
  3. 收录
  搜索引擎过滤掉垃圾邮件后,会对剩余的网站内容执行收录。这时候可以使用site命令或者站长平台查看收录的状态。有收录才有排名,收录是保证排名的前提;收录 不一定有排名。
  
  收录 和索引之间的关系是包容关系。索引只能在收录之后建立,收录的数量大于索引的数量。百度站长平台链接提交工具是收录的入口。
  4.排序
  排序取决于两个因素:
  1、基础优化分数要求我们提高基础优化;
  2、用户投票评分需要良好的综合数据来提升用户体验。
  ★
  以上是我对搜索引擎工作原理的基本了解。通过查询我的网站收录的情况,可以判断出网站哪里出了问题,并找到解决方案,从而可以做的更好的优化。
  ★

解决方案:Serverless在游戏运营行业进行数据采集分析的最佳实践

采集交流优采云 发表了文章 • 0 个评论 • 93 次浏览 • 2022-11-07 16:58 • 来自相关话题

  解决方案:Serverless在游戏运营行业进行数据采集分析的最佳实践
  • 触发器名称:defaultTrigger
  • 身份验证方法:匿名(即无需身份验证)
  • 请求方法:GET、POST
  创建函数后,我们通过在线编辑器编写代码:
  # -*- coding: utf-8 -*-
import logging
import json
import urllib.parse
HELLO_WORLD = b&#39;Hello world!\n&#39;
def handler(environ, start_response):
logger = logging.getLogger()
context = environ[&#39;fc.context&#39;]
request_uri = environ[&#39;fc.request_uri&#39;]
for k, v in environ.items():
if k.startswith(&#39;HTTP_&#39;):
# process custom request headers
pass
try:
request_body_size = int(environ.get(&#39;CONTENT_LENGTH&#39;, 0))
except (ValueError):
request_body_size = 0
# 接收回传的数据
request_body = environ[&#39;wsgi.input&#39;].read(request_body_size)
request_body_str = urllib.parse.unquote(request_body.decode("GBK"))
request_body_obj = json.loads(request_body_str)
logger.info(request_body_obj["action"])
logger.info(request_body_obj["articleAuthorId"])
status = &#39;200 OK&#39;
response_headers = [(&#39;Content-type&#39;, &#39;text/plain&#39;)]
start_response(status, response_headers)
return [HELLO_WORLD]
  这时候的代码很简单,就是要接收用户的参数,我们可以调用接口进行验证:
  您可以在函数的日志查询中看到此调用的日志:
  同时,我们还可以查看函数的link trace来分析每一步的调用时间,比如函数接收请求的过程→冷启动(没有活动实例时)→准备代码→执行初始化方法→执行入口函数逻辑:
  从调用链接图中可以看出,之前的请求收录了冷启动时间,因为当时没有活动实例,整个过程耗时418毫秒,入口函数代码的实际执行时间为8毫秒。
  再次调用该接口时,可以看到直接执行了入口函数的逻辑,因为此时已经有一个实例在运行,整个时间只有2.3毫秒:
  2. 处理数据的函数
  第一个函数是通过函数计算控制台在界面上创建的,运行环境选择Python3。我们可以在官方文档中查看预设的Python3运行环境中构建了哪些模块,因为第二个功能需要操作Kafka和RDS,所以需要确认对应的模块。
  从文档中可以看出,内置模块包括RDS的SDK模块,但没有Kafka的SDK模块。这时候我们需要手动安装Kafka SDK模块,创建功能也会使用另一种方式。
  Funcraft
  Funcraft是一款支持Serverless应用部署的命令行工具,可以帮助我们方便的管理函数计算、API网关、日志服务等资源。它通过资源配置文件(template.yml)帮助我们进行开发、构建和部署。
  所以第二个函数我们需要用Fun来操作,整个操作分为四步:
  • 安装有趣的工具。
  • 编写template.yml 模板文件来描述函数。
  • 安装我们需要的第 3 方依赖项。
  • 上传部署功能。
  安装乐趣
  Fun提供了三种安装方式:
  • 通过npm 包管理安装- 适用于所有平台(Windows/Mac/Linux)上预装npm 的开发人员。
  • 通过下载二进制文件安装- 适用于所有平台(Windows/Mac/Linux)。
  • 通过 Homebrew 包管理器安装——适用于 Mac 平台,更符合 MacOS 开发者习惯。
  文例环境是Mac,所以使用npm安装,很简单,一行命令搞定:
  sudo npm install @alicloud/fun -g
  安装完成后。在控制终端输入fun命令查看版本信息:
  $ fun --version
3.6.20
  第一次使用fun前,需要执行fun config命令进行配置,按照提示依次配置Account ID、Access Key Id、Secret Access Key、Default Region Name。Account ID 和 Access Key Id 可以在函数计算控制台首页右上角获取:
  有趣的配置
  ? 阿里云账号ID 01
  ? 阿里云Access Key ID qef6j
  ? 阿里云Access Key Secret ***UFJG
  ? 默认地域名称 cn-hangzhou
  ? 每个 SDK 客户端调用的超时时间(秒) 60
  ? 每个 SDK 客户端的最大重试次数 3
  编写模板.yml
  创建一个新目录,并在此目录中创建一个名为 template.yml 的 YAML 文件。该文件主要描述了要创建的函数的配置。说白了,函数计算控制台上配置的配置信息是用 YAML 格式写的。在文件中:
  ROSTemplateFormatVersion: &#39;2015-09-01&#39;
Transform: &#39;Aliyun::Serverless-2018-04-03&#39;
Resources:
FCBigDataDemo:
Type: &#39;Aliyun::Serverless::Service&#39;
Properties:
Description: &#39;local invoke demo&#39;
VpcConfig:
VpcId: &#39;vpc-xxxxxxxxxxx&#39;
VSwitchIds: [ &#39;vsw-xxxxxxxxxx&#39; ]
SecurityGroupId: &#39;sg-xxxxxxxxx&#39;
LogConfig:
Project: fcdemo
Logstore: fc_demo_store
dataToKafka:
Type: &#39;Aliyun::Serverless::Function&#39;
Properties:
Initializer: index.my_initializer
Handler: index.handler
CodeUri: &#39;./&#39;
Description: &#39;&#39;
Runtime: python3
  我们来解析一下上面文件的核心内容:
  • FCBigDataDemo:自定义服务名称。该服务由以下Type属性表示,即Aliyun::Serverless::Service。
  • 属性:属性下的属性都是服务的配置项。
  • VpcConfig:服务的VPC配置,包括:
  
  VpcId:VPC ID。VSwitchIds:交换机ID,这里是一个数组,可以配置多个交换机。SecurityGroupId:安全组 ID。
  • LogConfig:服务绑定日志服务 (SLS) 配置,包括:
  项目:日志服务项目。日志存储:日志存储名称。
  • dataToKafka:该服务下用户定义的函数名。该函数由以下Type属性表示,即Aliyun::Serverless::Function。
  • 属性:属性下的属性都是该功能的配置项。
  • Initializer:配置初始化函数。
  • Handler:配置入口函数。
  • 运行时:函数运行时环境。
  目录结构为:
  安装第三方依赖
  在创建了服务和功能的模板之后,让我们安装我们需要使用的第三方依赖项。在本例的场景中,第二个功能需要用到Kafka SDK,所以可以通过fun工具结合Python包管理工具pip来安装:
  有趣的安装 --runtime python3 --package-type pip kafka-python
  执行命令后,出现如下提示信息:
  此时我们会发现目录下会生成一个.fun文件夹,我们安装的依赖都在这个目录下:
  部署功能
  现在模板文件写好了,我们需要的Kafka SDK也安装好了,我们需要添加我们的代码文件index.py。代码内容如下:
  # -*- coding: utf-8 -*-
import logging
import json
import urllib.parse
from kafka import KafkaProducer
producer = None
def my_initializer(context):
logger = logging.getLogger()
logger.info("init kafka producer")
global producer
producer = KafkaProducer(bootstrap_servers=&#39;XX.XX.XX.XX:9092,XX.XX.XX.XX:9092,XX.XX.XX.XX:9092&#39;)
def handler(event, context):
logger = logging.getLogger()
# 接收回传的数据
event_str = json.loads(event)
event_obj = json.loads(event_str)
logger.info(event_obj["action"])
logger.info(event_obj["articleAuthorId"])
# 向Kafka发送消息
global producer
producer.send(&#39;ikf-demo&#39;, json.dumps(event_str).encode(&#39;utf-8&#39;))
producer.close()
return &#39;hello world&#39;
  代码很简单,这里简单分析一下:
  • my_initializer:当函数实例被拉起时,会先执行函数,然后再执行handler函数。当函数实例运行时,后续请求不会执行 my_initializer 函数。一般用于各种连接的初始化。初始化Kafka Producer的方法放在这里,避免重复初始化Producer。
  • handler:这个函数只有两个逻辑,接收返回的数据和将数据发送到Kafka的指定topic。
  让我们使用 fun deploy 命令来部署函数,它做了两件事:
  • 根据template.yml 中的配置创建服务和功能。
  • 将 index.py 和 .fun 上传到函数中。
  登录函数计算控制台,可以看到通过 fun 命令部署的服务和函数:
  进入函数,还可以清晰的看到第三方依赖包的目录结构:
  3.函数之间的调用
  目前,这两个功能都已创建。下面的工作就是在第一个函数接收到数据后,拉起第二个函数向Kafka发送消息。我们只需要对第一个函数进行一些更改:
  # -*- coding: utf-8 -*-
import logging
import json
import urllib.parse
import fc2
HELLO_WORLD = b&#39;Hello world!\n&#39;
client = None
def my_initializer(context):
logger = logging.getLogger()
logger.info("init fc client")
global client
client = fc2.Client(
endpoint="http://your_account_id.cn-hang ... ot%3B,
accessKeyID="your_ak",
accessKeySecret="your_sk"
)
def handler(environ, start_response):
logger = logging.getLogger()
context = environ[&#39;fc.context&#39;]
request_uri = environ[&#39;fc.request_uri&#39;]
for k, v in environ.items():
if k.startswith(&#39;HTTP_&#39;):
# process custom request headers
pass
try:
request_body_size = int(environ.get(&#39;CONTENT_LENGTH&#39;, 0))
except (ValueError):
request_body_size = 0
# 接收回传的数据
request_body = environ[&#39;wsgi.input&#39;].read(request_body_size)
request_body_str = urllib.parse.unquote(request_body.decode("GBK"))
request_body_obj = json.loads(request_body_str)
logger.info(request_body_obj["action"])
logger.info(request_body_obj["articleAuthorId"])
global client
client.invoke_function(
&#39;FCBigDataDemo&#39;,
&#39;dataToKafka&#39;,
payload=json.dumps(request_body_str),
headers = {&#39;x-fc-invocation-type&#39;: &#39;Async&#39;}
)
status = &#39;200 OK&#39;
response_headers = [(&#39;Content-type&#39;, &#39;text/plain&#39;)]
start_response(status, response_headers)
<p>
return [HELLO_WORLD]</p>
  如上代码所示,对第一个函数的代码做了三处改动:
  • 导入函数计算的库:import fc2
  • 添加创建函数计算客户端的初始化方法:
  def my_initializer(context):
logger = logging.getLogger()
logger.info("init fc client")
global client
client = fc2.Client(
endpoint="http://your_account_id.cn-hang ... ot%3B,
accessKeyID="your_ak",
accessKeySecret="your_sk"
)
  这里需要注意的是,我们在代码中添加初始化方法时,需要在函数配置中指定初始化方法的入口:
  • 通过函数计算客户端调用第二个函数:
  global client
client.invoke_function(
&#39;FCBigDataDemo&#39;,
&#39;dataToKafka&#39;,
payload=json.dumps(request_body_str),
headers = {&#39;x-fc-invocation-type&#39;: &#39;Async&#39;}
)
  invoke_function 函数有四个参数:
  • 第一个参数:调用函数的服务的名称。
  • 第二个参数:调用函数的函数名。
  • 第三个参数:传递给调用函数的数据。
  • 第四个参数:调用第二个函数Request Header 信息。这里x-fc-invocation-type的key用来设置是同步调用还是异步调用。这里 Async 设置为异步调用。
  通过这个设置,我们可以验证请求是通过第一个函数提供的HTTP接口发起的→采集数据→调用第二个函数→将数据作为消息传递给Kafka。
  使用两个函数的目的
  这里有同学可能会有疑问,为什么需要两个函数而不是第一个函数直接向Kafka发送数据呢?我们先来看这张图:
  当我们使用异步调用函数时,请求的数据会在函数内部默认放入消息队列进行第一次削峰填谷,然后每个队列会通过对应的函数实例的弹性拉起多个实例函数实例。进行第二次削峰填谷。所以这也是这个架构能够稳定承载大并发请求的核心原因之一。
  4.配置卡夫卡
  在游戏运营场景中,数据量比较大,所以对Kafka的性能要求比较高。与开源自建相比,使用云上的Kafka节省了大量的运维操作,例如:
  • 我们不再需要维护Kafka 集群的各个节点。
  • 无需关心主从节点之间的数据同步。
  • 可快速动态扩展Kafka集群规格,动态增加topic,动态增加partition数量。
  • 完善的指标监控功能和消息查询功能。
  一般来说,所有的SLA都被云端覆盖了,我们只需要关注消息发送和消息消费即可。
  因此,我们可以打开Kafka激活界面,根据实际场景需要一键激活Kafka实例,激活Kafka后登录控制台,在基本信息中查看Kafka接入点:
  • 默认接入点:VPC 内网场景的接入点。
  • SSL 接入点:公网场景中的接入点。
  您可以将默认接入点配置到函数计算的第二个功能中。
  ....
producer = KafkaProducer(bootstrap_servers=&#39;XX.XX.XX.XX:9092,XX.XX.XX.XX:9092,XX.XX.XX.XX:9092&#39;)
....
  然后点击左侧控制台的Topic Management,创建一个Topic:
  将创建的 Topic 配置到函数计算的第二个函数中。
  ...
# 第一个参数为Topic名称
producer.send(&#39;ikf-demo&#39;, json.dumps(event_str).encode(&#39;utf-8&#39;))
...
  上面已经列出了云上 Kafka 的优势,比如动态增加一个主题的分区数,我们可以在主题列表中动态调整一个主题的分区数:
  单个主题最多支持360个分区,这是开源自建无法实现的。
  接下来,点击控制台左侧的Consumer Group Management,创建一个Consumer Group:
  至此,云上的Kafka就配置好了,即Producer可以向刚刚创建的topic发送消息,Consumer可以设置刚刚创建的GID订阅该Topic进行消息的接收和消费。
  Flink 卡夫卡消费者
  在这种场景下,Kafka 后面往往会跟着 Flink,所以这里简单介绍一下如何在 Flink 中创建 Kafka Consumer 和消费数据。代码片段如下:
  final ParameterTool parameterTool = ParameterTool.fromArgs(args);
String kafkaTopic = parameterTool.get("kafka-topic","ikf-demo");
String brokers = parameterTool.get("brokers", "XX.XX.XX.XX:9092,XX.XX.XX.XX:9092,XX.XX.XX.XX:9092");
Properties kafkaProps = new Properties();
kafkaProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, brokers);
kafkaProps.put(ConsumerConfig.GROUP_ID_CONFIG, "ikf-demo");
FlinkKafkaConsumer kafka = new FlinkKafkaConsumer(kafkaTopic, new UserBehaviorEventSchema(), kafkaProps);
kafka.setStartFromLatest();
kafka.setCommitOffsetsOnCheckpoints(false);
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource dataStreamByEventTime = env.addSource(kafka);
  以上是构建 Flink Kafka Consumer 并添加 Kafka Source 的代码片段,非常简单。
  压力测试验证
  至此,整个数据采集的架构已经搭建完成。接下来,我们将通过压力测试来测试整个架构的性能。这里使用阿里云PTS进行压力测试。
  创建压力测试场景
  打开PTS控制台,点击左侧菜单创建压力测试/创建PTS场景:
  在场景配置中,使用第一个函数计算函数暴露的HTTP接口作为串口,如下图所示:
  接口配置好之后,我们来配置压力:
  • 压力模式:
  • 并发模式:指定有多少并发用户同时发出请求。
  • RPS 模式:指定每秒有多少请求。
  • 增量模式:在压力测量过程中,可以手动调节压力,也可以按百分比自动增加压力。
  • 最大并发:有多少虚拟用户可以同时发起请求。
  • 增量百分比:如果是自动增量,则在此处按百分比增量。
  • 单级持续时间:当未完全达到全压时,每一级梯度的压力保持持续时间。
  • 压力测试总持续时间:压力测试的总持续时间。
  这里由于资源成本的原因,将并发用户数设置为2500进行验证。
  从上图压测的情况来看,TPS已经达到2w上限,549w+请求,99.99%的请求成功,369异常也可以点击查看,都是请求超时造成的的压力测试工具。
  总结
  至此,整个基于serverless的大数据采集传输架构搭建完成,并进行了压力测试,验证整体性能也不错,整个架构非常简单易懂。这种架构不仅适用于游戏运营行业,其实任何大数据采集传输场景都适用。目前,已经有很多客户在基于serverless架构的生产环境中运行,或者正在对serverless架构进行改造。在途中。
  解决方案:模拟手工采集美团网商家的数据采集产品详细介绍-美团商家
  模拟手动采集美团商户数据采集软件,可以采集指定城市,指定关键词商户信息,包括姓名、地址、电话、来源网址、等等
  美团商户数据采集产品详情
  一、软件功能
  1.基于美团网公开数据采集。
  2.内置数据库保存采集的数据,支持数十万条数据,支持库内去重,即采集到数据库的数据不会被删除重复。
  3. 多种采集算法采集更多数据。
  
  4.数据记忆功能商务手机采集器,意外关机或下次开机数据还在。
  5、一键导出为CSV、EXCEL、VCF等文件。
  6.可将VCF文件导入手机通讯录,方便快捷。
  7.实时采集,而不是查看自己的数据库。
  8.支持Win XP、Win7和Win10等操作系统
  
  2.使用帮助
  1.手动选择城市商务电话的电话号码软件采集器采集,可以选择多个。
  2.软件采集过程中,为了效率,软件界面只显示不超过3000条数据。软件内置数据库保存采集的数据,支持数十万条数据。
  3、关于杀毒软件的误报,部分杀毒软件会因为软件保护原因误报误报。如果它被阻止,请允许它。建议使用或金山毒霸。
  4.支持导出到VCF文件。VCF文件是标准的手机通讯录格式文件,可以导入到手机通讯录中。方法是通过qq将vcf文件传输到手机,点击打开vcf文件,选择用手机通讯录打开,按照提示导入即可。
  5. 搜索关键词最好按行业关键词。一次输入一个单词,不带标点符号。6. 选择城市和关键词后,点击“开始采集”按钮。美团商户数据采集-数据采集软件-顺鑫科技官网|百度地图数据采集器|高德地图数据采集器|抖音快手数据采集器 查看全部

  解决方案:Serverless在游戏运营行业进行数据采集分析的最佳实践
  • 触发器名称:defaultTrigger
  • 身份验证方法:匿名(即无需身份验证)
  • 请求方法:GET、POST
  创建函数后,我们通过在线编辑器编写代码:
  # -*- coding: utf-8 -*-
import logging
import json
import urllib.parse
HELLO_WORLD = b&#39;Hello world!\n&#39;
def handler(environ, start_response):
logger = logging.getLogger()
context = environ[&#39;fc.context&#39;]
request_uri = environ[&#39;fc.request_uri&#39;]
for k, v in environ.items():
if k.startswith(&#39;HTTP_&#39;):
# process custom request headers
pass
try:
request_body_size = int(environ.get(&#39;CONTENT_LENGTH&#39;, 0))
except (ValueError):
request_body_size = 0
# 接收回传的数据
request_body = environ[&#39;wsgi.input&#39;].read(request_body_size)
request_body_str = urllib.parse.unquote(request_body.decode("GBK"))
request_body_obj = json.loads(request_body_str)
logger.info(request_body_obj["action"])
logger.info(request_body_obj["articleAuthorId"])
status = &#39;200 OK&#39;
response_headers = [(&#39;Content-type&#39;, &#39;text/plain&#39;)]
start_response(status, response_headers)
return [HELLO_WORLD]
  这时候的代码很简单,就是要接收用户的参数,我们可以调用接口进行验证:
  您可以在函数的日志查询中看到此调用的日志:
  同时,我们还可以查看函数的link trace来分析每一步的调用时间,比如函数接收请求的过程→冷启动(没有活动实例时)→准备代码→执行初始化方法→执行入口函数逻辑:
  从调用链接图中可以看出,之前的请求收录了冷启动时间,因为当时没有活动实例,整个过程耗时418毫秒,入口函数代码的实际执行时间为8毫秒。
  再次调用该接口时,可以看到直接执行了入口函数的逻辑,因为此时已经有一个实例在运行,整个时间只有2.3毫秒:
  2. 处理数据的函数
  第一个函数是通过函数计算控制台在界面上创建的,运行环境选择Python3。我们可以在官方文档中查看预设的Python3运行环境中构建了哪些模块,因为第二个功能需要操作Kafka和RDS,所以需要确认对应的模块。
  从文档中可以看出,内置模块包括RDS的SDK模块,但没有Kafka的SDK模块。这时候我们需要手动安装Kafka SDK模块,创建功能也会使用另一种方式。
  Funcraft
  Funcraft是一款支持Serverless应用部署的命令行工具,可以帮助我们方便的管理函数计算、API网关、日志服务等资源。它通过资源配置文件(template.yml)帮助我们进行开发、构建和部署。
  所以第二个函数我们需要用Fun来操作,整个操作分为四步:
  • 安装有趣的工具。
  • 编写template.yml 模板文件来描述函数。
  • 安装我们需要的第 3 方依赖项。
  • 上传部署功能。
  安装乐趣
  Fun提供了三种安装方式:
  • 通过npm 包管理安装- 适用于所有平台(Windows/Mac/Linux)上预装npm 的开发人员。
  • 通过下载二进制文件安装- 适用于所有平台(Windows/Mac/Linux)。
  • 通过 Homebrew 包管理器安装——适用于 Mac 平台,更符合 MacOS 开发者习惯。
  文例环境是Mac,所以使用npm安装,很简单,一行命令搞定:
  sudo npm install @alicloud/fun -g
  安装完成后。在控制终端输入fun命令查看版本信息:
  $ fun --version
3.6.20
  第一次使用fun前,需要执行fun config命令进行配置,按照提示依次配置Account ID、Access Key Id、Secret Access Key、Default Region Name。Account ID 和 Access Key Id 可以在函数计算控制台首页右上角获取:
  有趣的配置
  ? 阿里云账号ID 01
  ? 阿里云Access Key ID qef6j
  ? 阿里云Access Key Secret ***UFJG
  ? 默认地域名称 cn-hangzhou
  ? 每个 SDK 客户端调用的超时时间(秒) 60
  ? 每个 SDK 客户端的最大重试次数 3
  编写模板.yml
  创建一个新目录,并在此目录中创建一个名为 template.yml 的 YAML 文件。该文件主要描述了要创建的函数的配置。说白了,函数计算控制台上配置的配置信息是用 YAML 格式写的。在文件中:
  ROSTemplateFormatVersion: &#39;2015-09-01&#39;
Transform: &#39;Aliyun::Serverless-2018-04-03&#39;
Resources:
FCBigDataDemo:
Type: &#39;Aliyun::Serverless::Service&#39;
Properties:
Description: &#39;local invoke demo&#39;
VpcConfig:
VpcId: &#39;vpc-xxxxxxxxxxx&#39;
VSwitchIds: [ &#39;vsw-xxxxxxxxxx&#39; ]
SecurityGroupId: &#39;sg-xxxxxxxxx&#39;
LogConfig:
Project: fcdemo
Logstore: fc_demo_store
dataToKafka:
Type: &#39;Aliyun::Serverless::Function&#39;
Properties:
Initializer: index.my_initializer
Handler: index.handler
CodeUri: &#39;./&#39;
Description: &#39;&#39;
Runtime: python3
  我们来解析一下上面文件的核心内容:
  • FCBigDataDemo:自定义服务名称。该服务由以下Type属性表示,即Aliyun::Serverless::Service。
  • 属性:属性下的属性都是服务的配置项。
  • VpcConfig:服务的VPC配置,包括:
  
  VpcId:VPC ID。VSwitchIds:交换机ID,这里是一个数组,可以配置多个交换机。SecurityGroupId:安全组 ID。
  • LogConfig:服务绑定日志服务 (SLS) 配置,包括:
  项目:日志服务项目。日志存储:日志存储名称。
  • dataToKafka:该服务下用户定义的函数名。该函数由以下Type属性表示,即Aliyun::Serverless::Function。
  • 属性:属性下的属性都是该功能的配置项。
  • Initializer:配置初始化函数。
  • Handler:配置入口函数。
  • 运行时:函数运行时环境。
  目录结构为:
  安装第三方依赖
  在创建了服务和功能的模板之后,让我们安装我们需要使用的第三方依赖项。在本例的场景中,第二个功能需要用到Kafka SDK,所以可以通过fun工具结合Python包管理工具pip来安装:
  有趣的安装 --runtime python3 --package-type pip kafka-python
  执行命令后,出现如下提示信息:
  此时我们会发现目录下会生成一个.fun文件夹,我们安装的依赖都在这个目录下:
  部署功能
  现在模板文件写好了,我们需要的Kafka SDK也安装好了,我们需要添加我们的代码文件index.py。代码内容如下:
  # -*- coding: utf-8 -*-
import logging
import json
import urllib.parse
from kafka import KafkaProducer
producer = None
def my_initializer(context):
logger = logging.getLogger()
logger.info("init kafka producer")
global producer
producer = KafkaProducer(bootstrap_servers=&#39;XX.XX.XX.XX:9092,XX.XX.XX.XX:9092,XX.XX.XX.XX:9092&#39;)
def handler(event, context):
logger = logging.getLogger()
# 接收回传的数据
event_str = json.loads(event)
event_obj = json.loads(event_str)
logger.info(event_obj["action"])
logger.info(event_obj["articleAuthorId"])
# 向Kafka发送消息
global producer
producer.send(&#39;ikf-demo&#39;, json.dumps(event_str).encode(&#39;utf-8&#39;))
producer.close()
return &#39;hello world&#39;
  代码很简单,这里简单分析一下:
  • my_initializer:当函数实例被拉起时,会先执行函数,然后再执行handler函数。当函数实例运行时,后续请求不会执行 my_initializer 函数。一般用于各种连接的初始化。初始化Kafka Producer的方法放在这里,避免重复初始化Producer。
  • handler:这个函数只有两个逻辑,接收返回的数据和将数据发送到Kafka的指定topic。
  让我们使用 fun deploy 命令来部署函数,它做了两件事:
  • 根据template.yml 中的配置创建服务和功能。
  • 将 index.py 和 .fun 上传到函数中。
  登录函数计算控制台,可以看到通过 fun 命令部署的服务和函数:
  进入函数,还可以清晰的看到第三方依赖包的目录结构:
  3.函数之间的调用
  目前,这两个功能都已创建。下面的工作就是在第一个函数接收到数据后,拉起第二个函数向Kafka发送消息。我们只需要对第一个函数进行一些更改:
  # -*- coding: utf-8 -*-
import logging
import json
import urllib.parse
import fc2
HELLO_WORLD = b&#39;Hello world!\n&#39;
client = None
def my_initializer(context):
logger = logging.getLogger()
logger.info("init fc client")
global client
client = fc2.Client(
endpoint="http://your_account_id.cn-hang ... ot%3B,
accessKeyID="your_ak",
accessKeySecret="your_sk"
)
def handler(environ, start_response):
logger = logging.getLogger()
context = environ[&#39;fc.context&#39;]
request_uri = environ[&#39;fc.request_uri&#39;]
for k, v in environ.items():
if k.startswith(&#39;HTTP_&#39;):
# process custom request headers
pass
try:
request_body_size = int(environ.get(&#39;CONTENT_LENGTH&#39;, 0))
except (ValueError):
request_body_size = 0
# 接收回传的数据
request_body = environ[&#39;wsgi.input&#39;].read(request_body_size)
request_body_str = urllib.parse.unquote(request_body.decode("GBK"))
request_body_obj = json.loads(request_body_str)
logger.info(request_body_obj["action"])
logger.info(request_body_obj["articleAuthorId"])
global client
client.invoke_function(
&#39;FCBigDataDemo&#39;,
&#39;dataToKafka&#39;,
payload=json.dumps(request_body_str),
headers = {&#39;x-fc-invocation-type&#39;: &#39;Async&#39;}
)
status = &#39;200 OK&#39;
response_headers = [(&#39;Content-type&#39;, &#39;text/plain&#39;)]
start_response(status, response_headers)
<p>
return [HELLO_WORLD]</p>
  如上代码所示,对第一个函数的代码做了三处改动:
  • 导入函数计算的库:import fc2
  • 添加创建函数计算客户端的初始化方法:
  def my_initializer(context):
logger = logging.getLogger()
logger.info("init fc client")
global client
client = fc2.Client(
endpoint="http://your_account_id.cn-hang ... ot%3B,
accessKeyID="your_ak",
accessKeySecret="your_sk"
)
  这里需要注意的是,我们在代码中添加初始化方法时,需要在函数配置中指定初始化方法的入口:
  • 通过函数计算客户端调用第二个函数:
  global client
client.invoke_function(
&#39;FCBigDataDemo&#39;,
&#39;dataToKafka&#39;,
payload=json.dumps(request_body_str),
headers = {&#39;x-fc-invocation-type&#39;: &#39;Async&#39;}
)
  invoke_function 函数有四个参数:
  • 第一个参数:调用函数的服务的名称。
  • 第二个参数:调用函数的函数名。
  • 第三个参数:传递给调用函数的数据。
  • 第四个参数:调用第二个函数Request Header 信息。这里x-fc-invocation-type的key用来设置是同步调用还是异步调用。这里 Async 设置为异步调用。
  通过这个设置,我们可以验证请求是通过第一个函数提供的HTTP接口发起的→采集数据→调用第二个函数→将数据作为消息传递给Kafka。
  使用两个函数的目的
  这里有同学可能会有疑问,为什么需要两个函数而不是第一个函数直接向Kafka发送数据呢?我们先来看这张图:
  当我们使用异步调用函数时,请求的数据会在函数内部默认放入消息队列进行第一次削峰填谷,然后每个队列会通过对应的函数实例的弹性拉起多个实例函数实例。进行第二次削峰填谷。所以这也是这个架构能够稳定承载大并发请求的核心原因之一。
  4.配置卡夫卡
  在游戏运营场景中,数据量比较大,所以对Kafka的性能要求比较高。与开源自建相比,使用云上的Kafka节省了大量的运维操作,例如:
  • 我们不再需要维护Kafka 集群的各个节点。
  • 无需关心主从节点之间的数据同步。
  • 可快速动态扩展Kafka集群规格,动态增加topic,动态增加partition数量。
  • 完善的指标监控功能和消息查询功能。
  一般来说,所有的SLA都被云端覆盖了,我们只需要关注消息发送和消息消费即可。
  因此,我们可以打开Kafka激活界面,根据实际场景需要一键激活Kafka实例,激活Kafka后登录控制台,在基本信息中查看Kafka接入点:
  • 默认接入点:VPC 内网场景的接入点。
  • SSL 接入点:公网场景中的接入点。
  您可以将默认接入点配置到函数计算的第二个功能中。
  ....
producer = KafkaProducer(bootstrap_servers=&#39;XX.XX.XX.XX:9092,XX.XX.XX.XX:9092,XX.XX.XX.XX:9092&#39;)
....
  然后点击左侧控制台的Topic Management,创建一个Topic:
  将创建的 Topic 配置到函数计算的第二个函数中。
  ...
# 第一个参数为Topic名称
producer.send(&#39;ikf-demo&#39;, json.dumps(event_str).encode(&#39;utf-8&#39;))
...
  上面已经列出了云上 Kafka 的优势,比如动态增加一个主题的分区数,我们可以在主题列表中动态调整一个主题的分区数:
  单个主题最多支持360个分区,这是开源自建无法实现的。
  接下来,点击控制台左侧的Consumer Group Management,创建一个Consumer Group:
  至此,云上的Kafka就配置好了,即Producer可以向刚刚创建的topic发送消息,Consumer可以设置刚刚创建的GID订阅该Topic进行消息的接收和消费。
  Flink 卡夫卡消费者
  在这种场景下,Kafka 后面往往会跟着 Flink,所以这里简单介绍一下如何在 Flink 中创建 Kafka Consumer 和消费数据。代码片段如下:
  final ParameterTool parameterTool = ParameterTool.fromArgs(args);
String kafkaTopic = parameterTool.get("kafka-topic","ikf-demo");
String brokers = parameterTool.get("brokers", "XX.XX.XX.XX:9092,XX.XX.XX.XX:9092,XX.XX.XX.XX:9092");
Properties kafkaProps = new Properties();
kafkaProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, brokers);
kafkaProps.put(ConsumerConfig.GROUP_ID_CONFIG, "ikf-demo");
FlinkKafkaConsumer kafka = new FlinkKafkaConsumer(kafkaTopic, new UserBehaviorEventSchema(), kafkaProps);
kafka.setStartFromLatest();
kafka.setCommitOffsetsOnCheckpoints(false);
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource dataStreamByEventTime = env.addSource(kafka);
  以上是构建 Flink Kafka Consumer 并添加 Kafka Source 的代码片段,非常简单。
  压力测试验证
  至此,整个数据采集的架构已经搭建完成。接下来,我们将通过压力测试来测试整个架构的性能。这里使用阿里云PTS进行压力测试。
  创建压力测试场景
  打开PTS控制台,点击左侧菜单创建压力测试/创建PTS场景:
  在场景配置中,使用第一个函数计算函数暴露的HTTP接口作为串口,如下图所示:
  接口配置好之后,我们来配置压力:
  • 压力模式:
  • 并发模式:指定有多少并发用户同时发出请求。
  • RPS 模式:指定每秒有多少请求。
  • 增量模式:在压力测量过程中,可以手动调节压力,也可以按百分比自动增加压力。
  • 最大并发:有多少虚拟用户可以同时发起请求。
  • 增量百分比:如果是自动增量,则在此处按百分比增量。
  • 单级持续时间:当未完全达到全压时,每一级梯度的压力保持持续时间。
  • 压力测试总持续时间:压力测试的总持续时间。
  这里由于资源成本的原因,将并发用户数设置为2500进行验证。
  从上图压测的情况来看,TPS已经达到2w上限,549w+请求,99.99%的请求成功,369异常也可以点击查看,都是请求超时造成的的压力测试工具。
  总结
  至此,整个基于serverless的大数据采集传输架构搭建完成,并进行了压力测试,验证整体性能也不错,整个架构非常简单易懂。这种架构不仅适用于游戏运营行业,其实任何大数据采集传输场景都适用。目前,已经有很多客户在基于serverless架构的生产环境中运行,或者正在对serverless架构进行改造。在途中。
  解决方案:模拟手工采集美团网商家的数据采集产品详细介绍-美团商家
  模拟手动采集美团商户数据采集软件,可以采集指定城市,指定关键词商户信息,包括姓名、地址、电话、来源网址、等等
  美团商户数据采集产品详情
  一、软件功能
  1.基于美团网公开数据采集。
  2.内置数据库保存采集的数据,支持数十万条数据,支持库内去重,即采集到数据库的数据不会被删除重复。
  3. 多种采集算法采集更多数据。
  
  4.数据记忆功能商务手机采集器,意外关机或下次开机数据还在。
  5、一键导出为CSV、EXCEL、VCF等文件。
  6.可将VCF文件导入手机通讯录,方便快捷。
  7.实时采集,而不是查看自己的数据库。
  8.支持Win XP、Win7和Win10等操作系统
  
  2.使用帮助
  1.手动选择城市商务电话的电话号码软件采集器采集,可以选择多个。
  2.软件采集过程中,为了效率,软件界面只显示不超过3000条数据。软件内置数据库保存采集的数据,支持数十万条数据。
  3、关于杀毒软件的误报,部分杀毒软件会因为软件保护原因误报误报。如果它被阻止,请允许它。建议使用或金山毒霸。
  4.支持导出到VCF文件。VCF文件是标准的手机通讯录格式文件,可以导入到手机通讯录中。方法是通过qq将vcf文件传输到手机,点击打开vcf文件,选择用手机通讯录打开,按照提示导入即可。
  5. 搜索关键词最好按行业关键词。一次输入一个单词,不带标点符号。6. 选择城市和关键词后,点击“开始采集”按钮。美团商户数据采集-数据采集软件-顺鑫科技官网|百度地图数据采集器|高德地图数据采集器|抖音快手数据采集器

分享的内容:采集文章图片,上传到本地或者七牛云

采集交流优采云 发表了文章 • 0 个评论 • 85 次浏览 • 2022-11-06 09:21 • 来自相关话题

  分享的内容:采集文章图片,上传到本地或者七牛云
  &gt; &gt; 采集文章图片,上传到本地或七牛云
  采集文章图片,上传到本地或七牛云
  开发技术开发技术2022-10-23 浏览量
  最近写了一个新需求,需求是文章 from 采集,图片换成自己的url,可以选择保存在本地或者七牛云
  七牛云原来的解决方案是下载到本地,但是如果不能获取,可以停止,使用七牛云的异步第三方资源抓取解决方案。
  请参考具体代码
<p> 查看全部

  分享的内容:采集文章图片,上传到本地或者七牛云
  &gt; &gt; 采集文章图片,上传到本地或七牛云
  采集文章图片,上传到本地或七牛云
  开发技术开发技术2022-10-23 浏览量
  最近写了一个新需求,需求是文章 from 采集,图片换成自己的url,可以选择保存在本地或者七牛云
  七牛云原来的解决方案是下载到本地,但是如果不能获取,可以停止,使用七牛云的异步第三方资源抓取解决方案。
  请参考具体代码
<p>

背后的故事:快收藏,一小时教你装逼采集网易云音乐5亿首歌

采集交流优采云 发表了文章 • 0 个评论 • 230 次浏览 • 2022-11-04 18:28 • 来自相关话题

  背后的故事:快收藏,一小时教你装逼采集网易云音乐5亿首歌
  本期为极客系列的第三期。第二期由于客户论文重复的问题,暂时不开放源码。第二期比第三期有点长,最近有很多事情发生。本期使用的语言是java,创建多线程,支持断点采集,URL去重,广度优先+深度组合,如何使用已经搭建好的轮子快速开发发力。好了,吹完了,现在我们进入教程阶段。
  爬虫
  本期目标: 本期工具:采集结果:
  采集结果写入excel
  WebCollector 简介
  WebCollector是一个无需配置,方便二次开发的JAVA爬虫框架。它提供了精简的API,只需少量代码即可实现强大的爬虫。WebCollector-Hadoop 是支持分布式爬取的 WebCollector 的 Hadoop 版本。并且在2.x版本中提供了selenium,可以处理javascript生成的数据。我们先来看WebCollector的核心架构图:
  爬虫架构图
  
  不过,我们不用那么麻烦使用WebCollector来写爬虫。我们只需要在爬虫框架中集成BreadthCrawler类,重写访问方法即可。我们来看看官网上的例子:
  官网示例
  节目说明:
  访问()方法
  在整个爬取过程中,只要抓到一个复合页面,wc就会回调这个方法,传入一个收录所有页面信息的页面对象。
  添加种子()
  添加种子,在爬虫启动前,种子链接会添加到上述爬取信息中,并标记为未爬取。这个过程称为注入。
  添加正则表达式
  对于url正则表达式,过滤掉.js .jpg .css等不必要的链接,或者指定抓取链接的规则。比如我在使用的时候,有一个正则模式:[0-9]+.html,那么我的爬虫只会爬取域名下2015-01-16日期以.html结尾的链接。
  
  开始()
  表示启动爬虫,传入参数5表示抓取5层(深度为5)。如何理解5的深度?当只添加一个种子时,抓取这个种子链接作为第一层,根据规则解析种子链接页面,过滤出想要的链接,保存到待爬取的记录中。然后第二层就是抓取第一层保存的记录,解析并保存新的记录,以此类推。
  Web云音乐页面分析:
  我们先看下网易云音乐的歌曲页面链接:#/album?id=2884361,观察这个url,发现是查询平台。通过查询id可以得到不同的歌曲,这样就可以遍历整个网易云音乐,通过提取与上面url类似的网页就可以得到网易云音乐的所有歌曲。
  这时,我们遇到了第二个问题。得到歌曲的页面后,如何才能得到音乐的真实地址呢?我们通过抓包分析发现网易云音乐有一个api接口,可以得到歌曲的真实地址,api地址:,这个接口有几个参数:
  然后访问api得到一段json,里面收录了歌曲几个版本的音源地址。至于如何捕获和分析地址,下一篇教程将为您提供。
  不多说,在代码上,所有的核心代码都进行了注释,整个爬虫思路是这样的:
  网络爬虫源代码
  附上 Github 地址:. 欢迎关注极客科学,学习遵循有趣的技巧。
  分享的内容:外链平台有哪些,外链发展情况介绍
  众所周知,网站的外链是网站的SEO优化的重要组成部分。当然,分析竞争对手的外部链接也很重要。所谓“知己知彼”,就是千方百计的战斗,只要你知道对手的外链是怎么做的。,那么你就可以在外链上超越竞争对手。当然,在这种情况下,网站的综合排名也可以随意超越竞争对手。那么如何使用SEO工具准确查询竞争对手的反向链接呢?
  1. 站长工具
  站长工具是每个人都经常使用的软件。输入自己的网址,会有网站权重、页面收录、网站外链等数字。点击外链数量会跳转到百度网盘页面,可以看到自己的网站外链。
  优点:查询速度快
  缺点:查询质量差,假外链多。仅查询文本链接
  
  2.百度站长平台
  百度站长平台在过去两年一直是百度的主要站长工具。百度站长平台优化维护页面有外链分析。点击外链分析可以看到你的网站的外链主域和总链接数。
  优点:可靠
  缺点:时效性差,数据往往是一个月前的(这个主要看百度站长平台的数据更新时间)
  3. Majesticseo 外链查询工具
  一个国外的SEO查询工具网站,直接看图:
  
  图1
  图1准确显示了SEO的外部链接是否知道网站,并给出了对应的参考域名、参考IP等。
  图二
  图 2 反向链接的分割 区分网站的图片链接或文本链接,图表清晰地展示了链接到该域/子域/URL的不同类型的反向链接;在锚文本部分,您可以清楚地看到 网站 占主要外部链接中锚文本的分配量。在这里,您可以深入分析每个 关键词 以找出使用此 关键词 反向链接的引用域和外部链接。
  一般情况下,使用百度站长平台和majesticseo查询可以充分分析竞争对手的外链,然后我们可以通过观察竞争对手发布的外链数量来预测我们需要发布的外链数量。,让我们的SEO工作更有针对性,可以通过观察竞争对手的外链来寻找一些优质的外链资源。
  做SEO是关于毅力的。网站 的外部链接对于网站 来说是一个非常重要的因素。因此,作为站长,我们必须积累优质有效的外链。几乎每个优秀的站长手头都会有大量的资源。这些资源就是站长财富和排名的秘密。所以,大部分站长都不会随便透露。因此,外链资源的积累任重而道远! 查看全部

  背后的故事:快收藏,一小时教你装逼采集网易云音乐5亿首歌
  本期为极客系列的第三期。第二期由于客户论文重复的问题,暂时不开放源码。第二期比第三期有点长,最近有很多事情发生。本期使用的语言是java,创建多线程,支持断点采集,URL去重,广度优先+深度组合,如何使用已经搭建好的轮子快速开发发力。好了,吹完了,现在我们进入教程阶段。
  爬虫
  本期目标: 本期工具:采集结果:
  采集结果写入excel
  WebCollector 简介
  WebCollector是一个无需配置,方便二次开发的JAVA爬虫框架。它提供了精简的API,只需少量代码即可实现强大的爬虫。WebCollector-Hadoop 是支持分布式爬取的 WebCollector 的 Hadoop 版本。并且在2.x版本中提供了selenium,可以处理javascript生成的数据。我们先来看WebCollector的核心架构图:
  爬虫架构图
  
  不过,我们不用那么麻烦使用WebCollector来写爬虫。我们只需要在爬虫框架中集成BreadthCrawler类,重写访问方法即可。我们来看看官网上的例子:
  官网示例
  节目说明:
  访问()方法
  在整个爬取过程中,只要抓到一个复合页面,wc就会回调这个方法,传入一个收录所有页面信息的页面对象。
  添加种子()
  添加种子,在爬虫启动前,种子链接会添加到上述爬取信息中,并标记为未爬取。这个过程称为注入。
  添加正则表达式
  对于url正则表达式,过滤掉.js .jpg .css等不必要的链接,或者指定抓取链接的规则。比如我在使用的时候,有一个正则模式:[0-9]+.html,那么我的爬虫只会爬取域名下2015-01-16日期以.html结尾的链接。
  
  开始()
  表示启动爬虫,传入参数5表示抓取5层(深度为5)。如何理解5的深度?当只添加一个种子时,抓取这个种子链接作为第一层,根据规则解析种子链接页面,过滤出想要的链接,保存到待爬取的记录中。然后第二层就是抓取第一层保存的记录,解析并保存新的记录,以此类推。
  Web云音乐页面分析:
  我们先看下网易云音乐的歌曲页面链接:#/album?id=2884361,观察这个url,发现是查询平台。通过查询id可以得到不同的歌曲,这样就可以遍历整个网易云音乐,通过提取与上面url类似的网页就可以得到网易云音乐的所有歌曲。
  这时,我们遇到了第二个问题。得到歌曲的页面后,如何才能得到音乐的真实地址呢?我们通过抓包分析发现网易云音乐有一个api接口,可以得到歌曲的真实地址,api地址:,这个接口有几个参数:
  然后访问api得到一段json,里面收录了歌曲几个版本的音源地址。至于如何捕获和分析地址,下一篇教程将为您提供。
  不多说,在代码上,所有的核心代码都进行了注释,整个爬虫思路是这样的:
  网络爬虫源代码
  附上 Github 地址:. 欢迎关注极客科学,学习遵循有趣的技巧。
  分享的内容:外链平台有哪些,外链发展情况介绍
  众所周知,网站的外链是网站的SEO优化的重要组成部分。当然,分析竞争对手的外部链接也很重要。所谓“知己知彼”,就是千方百计的战斗,只要你知道对手的外链是怎么做的。,那么你就可以在外链上超越竞争对手。当然,在这种情况下,网站的综合排名也可以随意超越竞争对手。那么如何使用SEO工具准确查询竞争对手的反向链接呢?
  1. 站长工具
  站长工具是每个人都经常使用的软件。输入自己的网址,会有网站权重、页面收录、网站外链等数字。点击外链数量会跳转到百度网盘页面,可以看到自己的网站外链。
  优点:查询速度快
  缺点:查询质量差,假外链多。仅查询文本链接
  
  2.百度站长平台
  百度站长平台在过去两年一直是百度的主要站长工具。百度站长平台优化维护页面有外链分析。点击外链分析可以看到你的网站的外链主域和总链接数。
  优点:可靠
  缺点:时效性差,数据往往是一个月前的(这个主要看百度站长平台的数据更新时间)
  3. Majesticseo 外链查询工具
  一个国外的SEO查询工具网站,直接看图:
  
  图1
  图1准确显示了SEO的外部链接是否知道网站,并给出了对应的参考域名、参考IP等。
  图二
  图 2 反向链接的分割 区分网站的图片链接或文本链接,图表清晰地展示了链接到该域/子域/URL的不同类型的反向链接;在锚文本部分,您可以清楚地看到 网站 占主要外部链接中锚文本的分配量。在这里,您可以深入分析每个 关键词 以找出使用此 关键词 反向链接的引用域和外部链接。
  一般情况下,使用百度站长平台和majesticseo查询可以充分分析竞争对手的外链,然后我们可以通过观察竞争对手发布的外链数量来预测我们需要发布的外链数量。,让我们的SEO工作更有针对性,可以通过观察竞争对手的外链来寻找一些优质的外链资源。
  做SEO是关于毅力的。网站 的外部链接对于网站 来说是一个非常重要的因素。因此,作为站长,我们必须积累优质有效的外链。几乎每个优秀的站长手头都会有大量的资源。这些资源就是站长财富和排名的秘密。所以,大部分站长都不会随便透露。因此,外链资源的积累任重而道远!

总结:埋点,数据产品经理必备的技能

采集交流优采云 发表了文章 • 0 个评论 • 65 次浏览 • 2022-11-04 18:28 • 来自相关话题

  总结:埋点,数据产品经理必备的技能
  数据是数据产品的基础,埋点是数据的起点;如果没有埋点,数据产品就是被动水。
  可以说,埋没是互联网行业遇到的一个关键且无法回避的问题。
  以下是企业不同岗位学员的内部操作系统:
  商科同学不知道埋什么,也不知道埋什么;所以他们经常做功能但不做掩埋。需要数据分析的时候,他们去找数据组要数据,数据组会反问:“你埋了吗?”
  对于数据产品来说,由于对业务没有深入的了解,经常会出现遗漏、误葬的情况,最终导致无数理想的结果。
  业务开发,本质上就是解决业务相关的问题,而数据开发对他们来说是额外的工作,所以他们的开发成本会随着埋点需求的增加而增加,也可能伴随着项目延期的风险;隐藏的开发需求也可能导致代码冗余。
  对于数据分析,他们更多地使用数据,找不到数据埋藏的规律,从而无法通过数据驱动很好地进行分析。
  1、data采集的过程是什么?数据从何而来
  外部数据交互:如API数据的传输、数据文件的传输等。目前某平台的大数据标注系统就是通过这种方式传输完成企业的人群标注。
  从整个数据链路来看,数据产品基本上可以分为以下几个流程:
  首先数据采集我们需要从不同的终端获取不同的数据采集,然后进行数据清洗和处理(ETL),然后聚合到数据仓库中进行用户分析,用户画像、精准营销等;
  在我们知道了data采集和data embedding的重要性之后,在提出实际的业务功能需求的时候,一定要提到相关的embedding需求,那么接下来我们就需要关注如何让data采集是什么样的了过程?
  业务方确认功能并发起跟踪需求:提交页面、触发控件、触发场景等;专门的跟踪团队将进行系统验证以确保命名约定和一致性,BI将审查跟踪应用程序和统计要求是否合理或缺失等;审查后,嵌入点采集框架的设计开发与实现,嵌入点的开发,嵌入点完成后的测试;测试预写可以覆盖所有场景的业务场景,测试通过更新需求状态;业务验证、数据开发和数据分析;
  以上环节缺一不可,归根结底只有标准化的流程才能找到正确的现状问题。
  
  二、如何选择埋点方案?
  目前,互联网行业主流的埋地解决方案主要分为四种:
  1、第一类:代码嵌入,分为前端嵌入和后端嵌入;前端嵌入是通过前端代码嵌入来监控用户触发页面的数据采集
  前端嵌入点优势很明显,但劣势也很明显。因为前端嵌入点的数据是通过延迟上报机制上报的,比如用户点击页面上的按钮,不会立即上报,而是累计到一定值后才会累计。批量工作受到当前网络条件的限制。如果出现网络拥塞等问题,数据包就会丢失。所以前端埋点的丢包率比较高,一般在5%~10%。
  而如果前端埋点缺失或埋错,则必须通过app发布进行优化,客户端发布需要较长时间。
  2.第二种:服务器端埋点:在API接口中植入埋点代码段
  好处是每次用户触发这个请求,都会触发嵌入代码进行数据统计,所以不需要发布版本,及时触发及时更新。
  缺点是服务端埋点需要依赖服务请求,无法覆盖所有前端交互,对于用户路径采集来说比较弱。
  3、第三种:全埋;这是在互联网上增加用户资本的公司提出的一个埋葬想法。通过地埋SDK的接入,实现了页面上所有采集页面元素的浏览和点击行为。统一采集,不​​是按时间和需求采集,而是全部提前采集
  优点是开发成本高,SDK接入后维护成本低,埋藏过程也很简单;采集 先定义再定义,在一定程度上可以避免错位错位。
  缺点是数据冗余,使得很多数据无用,而数据采集的范围只是页面的可见元素,比如曝光,无法采集访问;数据的准确性也存在问题。
  4、第四类:可视化埋点;也是连接埋点SDK,但不是随时随地采集,而是按需采集,通过视觉圈选触发埋点采集
  优点是操作简单,按需埋点不会采集无效数据,开发成本比较低;并且数据埋点可以支持undo操作,一般来说数据量会比全埋点小很多。
  缺点:历史数据无法恢复,因为我们圈选动作之前的数据不能是采集;统计范围只支持页面最前面的动作,比如曝光,不能是采集采集。
  3、了解了各种埋地方案后,在实际工作中如何选择埋地方案?
  
  选择埋点方案的参考主要基于三点:
  业务发展阶段:开发投入成本、业务迭代速度业务属性:交互应用、业务交易分析深度:用户行为分析、业务分析、业务应用
  例如,我们可以根据业务发展的阶段来决定。比如现在业务发展迅速,版本迭代速度快,开发投入成本高。那么就不适合我们做client-side和server-side embedding,因为可能不是这样。版本更新需要多长时间,所以full embedding和visual embedding比较合适;
  对于比较强的业务数据分析场景,需要增加前端客户端嵌入点;并且需要考虑分析的深度。如果只是想看用户的前端行为路径,那么全嵌入点和视觉嵌入点都可以满足需求。,但如果分析整个业务流程,则必须配合代码埋点。
  我推荐全埋点+代码埋点的组合,服务端怎么做,服务端优先,这样数据准确率会更高。
  4、确定埋点选择后,开始详细设计埋点。
  事件是跟踪点中最重要的元素。如果要明确定位跟踪点,就必须从六个维度进行定义。我们可以将其概括为谁、何时、何地、什么、为什么和如何;这些元素用于构建事件的基本元素。
  事件主要分为三种类型:
  互动事件:浏览、点击、采集、支付、曝光、关闭;系统事件:APP启动、APP崩溃;业务状态:支付成功、用户续费等(这很大程度上取决于服务器的返回)。
  通过以上,我们基本可以判断出我们需要记录用户什么行为,什么数据采集,后续分析什么。
  写在最后,在我的工作生活中,过去的坑告诉我一个好的跟踪管理平台是多么重要。
  首先,流程是在线的。我们经常会迷失在一封来自埋点的电子邮件中,但如果是在线申请,申请、处理、访问、验证和测试都非常方便快捷,避免了信息交流。失踪;
  其次,可以标准化管理,埋点统一管理,信息集中管理,便于后期分析使用;
  最重要的是实现实时监控,减少泄漏和误埋。
  当然,如果您没有跟踪管理平台,确定一个标准化的跟踪流程,选择适合您当前业务的跟踪解决方案,相信您也可以做好跟踪,通过数据完成丰富的场景分析!
  作者:晚安;聚焦用户、产品等运营领域。
  本文由@Goodnight 发布。原创 每个人都是产品经理。未经许可禁止复制
  题图来自Unsplash,基于CC0协议
  解决方案:全自动易企CMS采集,一站式采集发布(图文详解)
  易企cms采集,当网站发布时,面临的最大问题是网站内容不足或更新不及时。网站越大,维护能力就越大,网站运营商长期以来一直在寻求以最大的成本降低实现最高质量的网站内容。依托高效强大的网络信息采集与整合,E-企业cms采集与网站对接后,持续为网站提供优质、实时的数据,节省人工投入和更大的人力,随时随地寻找文章资源。
  如果网站位于专用网络范围内,则网站
  将陷入网络扩展和内容补充,只能依靠人工采集互联网上的相关信息,然后复制到内网导入位于专网的网站。有了电商cms采集,现在就不用那么繁琐了,它可以自动采集发布编辑,让网站管理者可以专注于内容质量审查,网站整体SEO。
  
  E-Enterprisecms采集预设30多个插件来提高网站排名,通过这些插件对发布的内容进行排名和优化,从而在很长一段时间内提高网站的排名。您可以根据网站所在的行业,从发布到网站的每条内容中自动提取“长尾词”,并自动调整已发布内容的关键词密度。自动创建已发布图片的alt属性,并根据发布的内容自动生成内容中图片的匹配alt描述。
  电子商务cms采集具有4种高效的网络信息采集功能。在专题采集中,只需输入关键字即可采集符合网站专题设置要求的网络信息,不再需要手动搜索。定向采集可以与其他类似网站同步,只需输入目标网站的地址,即可自动采集同网站的信息进行过滤。
  
  易企cms采集再通过定向采集,这样就无需在新闻源平台上手动采集有关行业的文章,通过定向采集功能,只需目标网站的地址和关键词即可。采集配置中,网站可以设置要采集的信息源深度,以确保数据内容采集准确、完整,并满足您的网站要求。
  易企业cms采集通过5层网络信息过滤,使网站不会产生垃圾内容链接。数据过滤由指向目标网站原创信息源的链接的通道和链接类型执行。此外,通过对采集数据源的标题进行关键字区分和标题重复检查来执行标题筛选。内容筛选,通过将 HASH 算法应用于采集数据内容,以确保采集内容不重复。
  结合字段筛选
  ,可以对采集内容的字段值进行筛选和比较,以确保每个字段内容采集满足要求。组合过滤:对采集内容的多个字段值进行组合过滤和比较,确保多个字段组合后的内容符合要求。 查看全部

  总结:埋点,数据产品经理必备的技能
  数据是数据产品的基础,埋点是数据的起点;如果没有埋点,数据产品就是被动水。
  可以说,埋没是互联网行业遇到的一个关键且无法回避的问题。
  以下是企业不同岗位学员的内部操作系统:
  商科同学不知道埋什么,也不知道埋什么;所以他们经常做功能但不做掩埋。需要数据分析的时候,他们去找数据组要数据,数据组会反问:“你埋了吗?”
  对于数据产品来说,由于对业务没有深入的了解,经常会出现遗漏、误葬的情况,最终导致无数理想的结果。
  业务开发,本质上就是解决业务相关的问题,而数据开发对他们来说是额外的工作,所以他们的开发成本会随着埋点需求的增加而增加,也可能伴随着项目延期的风险;隐藏的开发需求也可能导致代码冗余。
  对于数据分析,他们更多地使用数据,找不到数据埋藏的规律,从而无法通过数据驱动很好地进行分析。
  1、data采集的过程是什么?数据从何而来
  外部数据交互:如API数据的传输、数据文件的传输等。目前某平台的大数据标注系统就是通过这种方式传输完成企业的人群标注。
  从整个数据链路来看,数据产品基本上可以分为以下几个流程:
  首先数据采集我们需要从不同的终端获取不同的数据采集,然后进行数据清洗和处理(ETL),然后聚合到数据仓库中进行用户分析,用户画像、精准营销等;
  在我们知道了data采集和data embedding的重要性之后,在提出实际的业务功能需求的时候,一定要提到相关的embedding需求,那么接下来我们就需要关注如何让data采集是什么样的了过程?
  业务方确认功能并发起跟踪需求:提交页面、触发控件、触发场景等;专门的跟踪团队将进行系统验证以确保命名约定和一致性,BI将审查跟踪应用程序和统计要求是否合理或缺失等;审查后,嵌入点采集框架的设计开发与实现,嵌入点的开发,嵌入点完成后的测试;测试预写可以覆盖所有场景的业务场景,测试通过更新需求状态;业务验证、数据开发和数据分析;
  以上环节缺一不可,归根结底只有标准化的流程才能找到正确的现状问题。
  
  二、如何选择埋点方案?
  目前,互联网行业主流的埋地解决方案主要分为四种:
  1、第一类:代码嵌入,分为前端嵌入和后端嵌入;前端嵌入是通过前端代码嵌入来监控用户触发页面的数据采集
  前端嵌入点优势很明显,但劣势也很明显。因为前端嵌入点的数据是通过延迟上报机制上报的,比如用户点击页面上的按钮,不会立即上报,而是累计到一定值后才会累计。批量工作受到当前网络条件的限制。如果出现网络拥塞等问题,数据包就会丢失。所以前端埋点的丢包率比较高,一般在5%~10%。
  而如果前端埋点缺失或埋错,则必须通过app发布进行优化,客户端发布需要较长时间。
  2.第二种:服务器端埋点:在API接口中植入埋点代码段
  好处是每次用户触发这个请求,都会触发嵌入代码进行数据统计,所以不需要发布版本,及时触发及时更新。
  缺点是服务端埋点需要依赖服务请求,无法覆盖所有前端交互,对于用户路径采集来说比较弱。
  3、第三种:全埋;这是在互联网上增加用户资本的公司提出的一个埋葬想法。通过地埋SDK的接入,实现了页面上所有采集页面元素的浏览和点击行为。统一采集,不​​是按时间和需求采集,而是全部提前采集
  优点是开发成本高,SDK接入后维护成本低,埋藏过程也很简单;采集 先定义再定义,在一定程度上可以避免错位错位。
  缺点是数据冗余,使得很多数据无用,而数据采集的范围只是页面的可见元素,比如曝光,无法采集访问;数据的准确性也存在问题。
  4、第四类:可视化埋点;也是连接埋点SDK,但不是随时随地采集,而是按需采集,通过视觉圈选触发埋点采集
  优点是操作简单,按需埋点不会采集无效数据,开发成本比较低;并且数据埋点可以支持undo操作,一般来说数据量会比全埋点小很多。
  缺点:历史数据无法恢复,因为我们圈选动作之前的数据不能是采集;统计范围只支持页面最前面的动作,比如曝光,不能是采集采集。
  3、了解了各种埋地方案后,在实际工作中如何选择埋地方案?
  
  选择埋点方案的参考主要基于三点:
  业务发展阶段:开发投入成本、业务迭代速度业务属性:交互应用、业务交易分析深度:用户行为分析、业务分析、业务应用
  例如,我们可以根据业务发展的阶段来决定。比如现在业务发展迅速,版本迭代速度快,开发投入成本高。那么就不适合我们做client-side和server-side embedding,因为可能不是这样。版本更新需要多长时间,所以full embedding和visual embedding比较合适;
  对于比较强的业务数据分析场景,需要增加前端客户端嵌入点;并且需要考虑分析的深度。如果只是想看用户的前端行为路径,那么全嵌入点和视觉嵌入点都可以满足需求。,但如果分析整个业务流程,则必须配合代码埋点。
  我推荐全埋点+代码埋点的组合,服务端怎么做,服务端优先,这样数据准确率会更高。
  4、确定埋点选择后,开始详细设计埋点。
  事件是跟踪点中最重要的元素。如果要明确定位跟踪点,就必须从六个维度进行定义。我们可以将其概括为谁、何时、何地、什么、为什么和如何;这些元素用于构建事件的基本元素。
  事件主要分为三种类型:
  互动事件:浏览、点击、采集、支付、曝光、关闭;系统事件:APP启动、APP崩溃;业务状态:支付成功、用户续费等(这很大程度上取决于服务器的返回)。
  通过以上,我们基本可以判断出我们需要记录用户什么行为,什么数据采集,后续分析什么。
  写在最后,在我的工作生活中,过去的坑告诉我一个好的跟踪管理平台是多么重要。
  首先,流程是在线的。我们经常会迷失在一封来自埋点的电子邮件中,但如果是在线申请,申请、处理、访问、验证和测试都非常方便快捷,避免了信息交流。失踪;
  其次,可以标准化管理,埋点统一管理,信息集中管理,便于后期分析使用;
  最重要的是实现实时监控,减少泄漏和误埋。
  当然,如果您没有跟踪管理平台,确定一个标准化的跟踪流程,选择适合您当前业务的跟踪解决方案,相信您也可以做好跟踪,通过数据完成丰富的场景分析!
  作者:晚安;聚焦用户、产品等运营领域。
  本文由@Goodnight 发布。原创 每个人都是产品经理。未经许可禁止复制
  题图来自Unsplash,基于CC0协议
  解决方案:全自动易企CMS采集,一站式采集发布(图文详解)
  易企cms采集,当网站发布时,面临的最大问题是网站内容不足或更新不及时。网站越大,维护能力就越大,网站运营商长期以来一直在寻求以最大的成本降低实现最高质量的网站内容。依托高效强大的网络信息采集与整合,E-企业cms采集与网站对接后,持续为网站提供优质、实时的数据,节省人工投入和更大的人力,随时随地寻找文章资源。
  如果网站位于专用网络范围内,则网站
  将陷入网络扩展和内容补充,只能依靠人工采集互联网上的相关信息,然后复制到内网导入位于专网的网站。有了电商cms采集,现在就不用那么繁琐了,它可以自动采集发布编辑,让网站管理者可以专注于内容质量审查,网站整体SEO。
  
  E-Enterprisecms采集预设30多个插件来提高网站排名,通过这些插件对发布的内容进行排名和优化,从而在很长一段时间内提高网站的排名。您可以根据网站所在的行业,从发布到网站的每条内容中自动提取“长尾词”,并自动调整已发布内容的关键词密度。自动创建已发布图片的alt属性,并根据发布的内容自动生成内容中图片的匹配alt描述。
  电子商务cms采集具有4种高效的网络信息采集功能。在专题采集中,只需输入关键字即可采集符合网站专题设置要求的网络信息,不再需要手动搜索。定向采集可以与其他类似网站同步,只需输入目标网站的地址,即可自动采集同网站的信息进行过滤。
  
  易企cms采集再通过定向采集,这样就无需在新闻源平台上手动采集有关行业的文章,通过定向采集功能,只需目标网站的地址和关键词即可。采集配置中,网站可以设置要采集的信息源深度,以确保数据内容采集准确、完整,并满足您的网站要求。
  易企业cms采集通过5层网络信息过滤,使网站不会产生垃圾内容链接。数据过滤由指向目标网站原创信息源的链接的通道和链接类型执行。此外,通过对采集数据源的标题进行关键字区分和标题重复检查来执行标题筛选。内容筛选,通过将 HASH 算法应用于采集数据内容,以确保采集内容不重复。
  结合字段筛选
  ,可以对采集内容的字段值进行筛选和比较,以确保每个字段内容采集满足要求。组合过滤:对采集内容的多个字段值进行组合过滤和比较,确保多个字段组合后的内容符合要求。

通用解决方案:API(接口)是什么

采集交流优采云 发表了文章 • 0 个评论 • 265 次浏览 • 2022-11-03 11:37 • 来自相关话题

  通用解决方案:API(接口)是什么
  什么是 API(接口)?举个常见的例子,在京东下单并付款后,商户选择顺丰快递发货,然后就可以在京东上实时查看当前物流信息。京东和顺丰作为两家独立的公司,可以在京东上实时看到顺丰的快递信息。这需要 API。在查看自己的快递信息时,京东可以使用顺丰提供的API接口进行实时检索。信息单独呈现网站。此外,您还可以在快递100上输入订单号查询快递信息。只要有合作或许可,其他公司可以通过顺丰提供的API接口检索快递信息。由于有多个调用,
  我们来看看百度是如何给出API的定义的:
  API(应用程序编程接口)是预定义的函数,旨在为应用程序和开发人员提供访问基于软件或硬件的一组例程的能力,而无需访问源代码或了解该机制的内部工作细节。
  从百度的定义来看,我们首先关注:功能,提供应用和开发者,无需访问源代码,例程。注意这四个短语。其中,例程是系统对外提供的功能接口或服务的集合。本文重点介绍API的数据服务功能接口。
  首先,在下面的文章中,我将首先演示如何使用浏览器,无需编程,无需访问源代码,调用免费的API接口,让您使用最简单的接口;
  然后,将演示如何通过编程调用接口;
  最后,演示启动WEB服务,编写一个简单的API接口来体现API的功能(y=f(x))。
  您也可以尝试复制代码。通过自己的实验,你会学到一些关于后端、前端的知识,加深你对 API 的理解。那么开始吧,我们先来一张图:通过API提供信息(数据)的功能,看看数据是如何流动的。如果您为 API 指定特定位置,它将位于下图的中心。
  为了改变理解,我穿插了一个故事人物。假设世界太大了,你想在非洲大陆看到它,成为一名水手,在一次航行中被一位著名的航海家带走(你有船上唯一的卫星计算机),你会不可避免地成为途中的领航员。它将让您确定下一个城市的纬度和经度。这时候导航器让你确定深圳的经纬度。
  1.你是个人肉API
  这时候,你可以想到一个简单的方法就是去百度搜索。除了领航员,船上的高级水手和大副很可能会问你。这时候你其实就是一个接口,大家来找你获取地理位置信息。作为一个接口,你自己不产生信息,你只是信息的采集器和传递者,提供人肉数据服务。
  2.使用免费的经纬API接口
  在百度搜索过程中,很多网友给出的经纬度不一致,要反复对比才能辨别真伪。时间长了,你可能会觉得大家都在问位置,太烦人了。我的人肉API效率太慢了。有没有更快的方法。
  这时候,你发现了一个阿里云的免费API接口:深圳。您在浏览器的地址栏中输入此 URL,即可获得正确的纬度和经度。你把网址里的深圳换成别的城市,就可以找到了。这时候,通过这个界面,就可以大大提高为大家确定位置的效率。
  3.您对此不满意
  你觉得这个接口很好,你就是懂Python,为什么不写点代码,注意这个时候你的角色变了:你已经从人类API变成了开发者(注意这是百度里的API定义关键词),你现在的目标是编写可以自动获取这个地方的经纬度的代码。
  #python
import requests
r = requests.get("http://gc.ditu.aliyun.com/geocoding?a=深圳")
loc = r.json()
print loc
#打印出的结果:{u&#39;alevel&#39;: 4, u&#39;lon&#39;: 114.05786, u&#39;level&#39;: 2, u&#39;cityName&#39;: u&#39;&#39;, u&#39;address&#39;: u&#39;&#39;, u&#39;lat&#39;: 22.54309}
# 与在浏览器输入地址的结果一致
print "深圳的经度是%s,纬度是%s" % (loc["lon"], loc["lat"])
#打印出的结果是:深圳的经度是114.05786,纬度是22.54309
  至此,我们来回顾一下百度对API的定义。目前,作为开发者,您只需编写几行代码即可访问“阿里巴巴云经纬度接口”。您无需访问此 API 的源代码,也无需了解此 API 是如何制作的。也就是说,无论是通过浏览器还是编程语言,您现在已经在使用简单的 API。
  4.使用简单的API接口后,进一步想知道它的内部机制是什么
  基于可以使用的知识,API的源代码及其内部机制是什么?目前可以调用经纬度API,单纯获取位置是不够的。你可能想自己写一个API接口,而不是紧紧地提供位置信息,同时添加对城市的介绍。
  使用 Python 的 tornado 模块构建 Web 服务。让我们创建一个脚本空文件 web_server.py 并将以下代码复制到其中
  # -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding(&#39;utf-8&#39;)
import tornado.ioloop
import tornado.web
import json
import requests
lists = {u"深圳": "是经济特区,紧邻广州,接壤香港,人口约1200万",
u"青岛": "旅游城市,濒临黄海,特产啤酒,人口约920万"
}
def get_loc(city):
r = requests.get("http://gc.ditu.aliyun.com/geocoding?a=%s" % city.encode(&#39;UTF-8&#39;))
<p>
loc = r.json()
return "经度是%s,纬度是%s" % (loc["lon"], loc["lat"])
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
return self.get_secure_cookie("user")
class MainHandler(BaseHandler):
def get(self):
if self.request.arguments.has_key("id"):
greeting = self.get_argument(&#39;id&#39;, &#39;Hello&#39;)
if greeting in lists:
self.write(greeting + ": " + str(get_loc(greeting)) + "," + str(lists[greeting]))
else:
self.write("none")
settings = dict(cookie_secret="P1/V61oETzdkLmGeJJFuYh7Eo5KXQAGaYgEQnp2XdTo=", debug=True)
application = tornado.web.Application([(r"/", MainHandler), ], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.current().start()</p>
  执行web_server.py,执行后会启动一个web服务
  接下来我们在浏览器中输入192.168.199.204:8888/?id=Shenzhen
  注意我自己电脑的局域网IP是192.168.199.204,需要换成自己电脑(或者虚拟机)的ip。
  从上图中,我们实现了和“阿里巴巴云经纬度界面”一样的功能,得到了除了经纬度之外的城市的简要描述。随着航次越来越多,您让船上的每个人不仅了解地理信息,还了解每个城市的经济和文化状况。随着信息和数据的增加,特别需要能够先保存数据,使用时直接调用API的东西。
  5.数据存储,按需调整
  上面,我们模仿阿里云的API,搭建了一个Web服务,提供更详细的API地理位置信息服务。现在想想,我们代码里只有深圳和青岛两个城市,还有很多城市没有提到。此外,城市还有经济发展、饮食文化等。我们将深圳和青岛的城市信息存储到mysql中。
  保存后,我们直接从mysql中获取数据,通过API直接展示给浏览器。更改 web_server.py 脚本
  # -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding(&#39;utf-8&#39;)
import tornado.ioloop
import tornado.web
import json
import requests
import MySQLdb.constants
def get_mysql(sql_string):
conn = MySQLdb.connect(host=&#39;localhost&#39;, port = 3306, user = &#39;root&#39;, passwd = &#39;123456&#39;, db = &#39;test&#39;, charset = &#39;utf8&#39;)
cursor = conn.cursor()
cursor.execute(sql_string)
resultList = {}
for data in cursor.fetchall():
<p>
city_name = data[0]
city_introduce = data[1]
resultList[city_name] = city_introduce
return resultList
cursor.close()
conn1.close()
def get_loc(city):
r = requests.get("http://gc.ditu.aliyun.com/geocoding?a=%s" % city.encode(&#39;UTF-8&#39;))
loc = r.json()
return "经度是%s,纬度是%s" % (loc["lon"], loc["lat"])
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
return self.get_secure_cookie("user")
class MainHandler(BaseHandler):
def get(self):
if self.request.arguments.has_key("id"):
greeting = self.get_argument(&#39;id&#39;, &#39;Hello&#39;)
lists = get_mysql("select name,introduce from test.city where name =&#39;%s&#39; " % greeting.encode(&#39;UTF-8&#39;)) #直接从mysql里读取城市信息,特别注意这里的SQL
if greeting in lists:
self.write(greeting + ": " + str(get_loc(greeting)) + "," + str(lists[greeting]))
else:
self.write("none")
settings = dict(cookie_secret="P1/V61oETzdkLmGeJJFuYh7Eo5KXQAGaYgEQnp2XdTo=", debug=True)
application = tornado.web.Application([(r"/", MainHandler), ], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.current().start()
</p>
  保存web_server.py后,再次执行重启,在浏览器地址输入192.168.199.204:8888/?id=Shenzhen,出现与步骤4相同的结果,不过这次是从mysql中取数据,通过API显示界面浏览器。至此,你不仅会用到API,还会通过tornado打开web服务,打开一个API查询接口。
  最后,总结一下,从上面的文章,我先画了一张图,结合数据流向,描述了API的位置,然后用了一个信息采集器的故事,如何使用现有的接口,去提供更好的界面。当然,这太简单了。但我认为它也可以解释 API 的基本含义。生产环境中API的复杂性涉及数据复杂性、接口稳定性、高可用性和安全性。
  (本文结束,如有疑问请留言)
  推荐链接:
  1.知乎上API的答案
  /question/38594466/answer/228418422
  /question/38594466/answer/215257117
  API的作用:
  - 对于软件提供者,可以留出API供其他应用调用,形成生态系统,让软件发挥最大价值,变得更有生命力。(同时其他人看不到代码,不伤商业机密。)(可以顺丰京东为例)
  - 对于应用开发者来说,通过开放的API,可以直接调用多家公司制作的功能,制作自己的应用,无需自己动手,节省能源。
  /question/21691705/answer/26406216
  API(应用程序编程接口)
  翻译成中文是“应用程序接口”,其实这个翻译不好,应该说是“程序通信接口”。
  翻译成接口,顾名思义,就是用来沟通两种不同的东西,通常由一组函数库组成。
  同一平台下的两个不同的事物(程序或系统),为了访问彼此的功能等,
  因此,一个 X 程序编写了一组函数,以允许同一平台上的其他程序访问该 X 程序的函数。
  那套函数可以说是X程序对外开放的API。
  整套解决方案:wangmarket: 网市场云建站系统
  方法二:使用serverless版本快速做网站(建议先试试这个方法,毕竟不用花钱买服务器)
  做网站,不用买服务器,一年几毛钱的流量费和html文件存储费。对于只做一个或几个网站的朋友,这是首选,强烈推荐。毕竟只是做几个网站,谁愿意承担增加一台服务器的费用。
  下载链接:
  方法三:上线,华为云服务器,花1元快速部署上线使用
  根据本站开户、选台服务器,在线部署和使用网市云建站系统仅需一元,无需其他额外费用!
  (这个版本可能是5.2的镜像,有点旧,但是正常使用没问题,建议参与以下活动,我们会帮你安装最新版本)
  方式四:自定义部署,比如部署到私服、阿里云、腾讯云等(这种方式用得最多)
  参考:
  如果您要部署到服务器,建议您这样做。
  配套软件:Pa网站工具、模板计算工具
  看哪个网站,拉出来做个模板。我看到的 网站 可以被我使用!/mail_osc/templatespider
  系统二次开发目前使用的开源框架介绍
  SpringBoot2.6.1、Shiro、Redis5、Mysql5.7(必须是这个版本)、ElasticSearch 7.10.1、
  前端信息提示msg.js,客服代理kefu.js,网站管理后台Layui
  开发前注意事项
  用Java开发,有两种数据库,默认使用sqlite 3,也可以配置使用mysql。
  
  一定要注意版本号不要写错,jdk1.8和mysql用的是5.7,重要的事情说三遍
  另外,请使用 Eclipse 进行开发。我们从来没有使用过idea。如果idea出现异常,可以自行百度搜索解决方法,因为idea还有其他的朋友,很多都可以正常运行,但是我们没用过idea。如果您有想法 如果出现问题,我们将无法提供任何帮助。
  以下是一些入门步骤:
  本地环境和git导入项目配置Mysql数据库(可选,不做这一步完全可以运行) 代码起来后,通过安装向导,安装系统三分钟导入模板快速创建自己的网站
  从网市云建站系统v5.0版本中,我们提取了网市云建站系统底层基础支持,如常用工具、权限控制等,并调整打包了一套集成开发框架。叫它wm。也就是说,在网上市场搭建云站点的基本操作都收录在wm文档中。wm的基础开发文档包括数据库操作、文件操作、日志操作、短信发送、ajax请求等最基本的功能模块。通过它,软件系的应届毕业生可以在一个月内快速进入开发状态,具备项目开发能力。点击这里查看wm开发文档
  当前目录结构
  wangmarket 项目
├─src 项目源代码 ( Maven )
├─pom.xml 项目源代码 pom ( Maven )
├─else 其他的杂七杂八相关文件,一般用不到
│ ├─wangmarket.sql 项目运行所需要的数据库文件( Mysql数据库,默认sqlite3)
└─README.md 说明
  进行二次开发
  在二次开发过程中,我们不建议您直接在本项目中进行更改,否则您将失去跟随我们版本升级的能力。众所周知的织梦cms也被称为安全漏洞,因为版本未升级而失去维护。
  我们建议您可以扩展这个项目,开发您想要的模块和功能,以及一些原创功能和页面更改。例如,登陆页面的重写。
  当我们市场有新版本时,只需直接更新WEB-INF/lib/wangmarket-xxx.jar即可完成版本升级
  
  云模板库
  您的时间非常宝贵!它不会让你一接触就学会自己制作模板。我们自带云模板库,点击查看
  虽然模板不多,只有几百套,但创建网站后一键导入,直接使用!一键导入后,会自动创建栏目和页面。您只需要更改栏目名称,更改文字和图片,即可达到成本网站交付标准!作为一个早期的你,这足以服务客户并熟悉整个系统!另外,我们模板库的模板会不断增加。你看到的任何 网站 都可以被我使用 - 无限模板计划
  项目经验
  网市云建站系统,2009年开始使用php开发wap系统建站。用java重构后,2010年底发布了第一版Java版建站系统。历经十余年不断更新迭代,功能完善...
  活动,免费帮助安装+调试/发送授权/发送代理
  微信扫码关注公众号,花10分钟参与提示活动,即可换取我们在安装、调试、授权、代理等方面的帮助。
  作者的话
  我们支持白人卖淫,但我们不想做无意义的卖淫!很多工作室和小微公司想要生存下来,赚到一些钱,实属不易。在资本积累方面,如果你购买牌照,你显然会有很大的负担。如果您属于该领域,建议您参与我们的活动并关注微信公众号。“wangmarket”可以看到活动,不花钱用我们的开源很不容易,还得赚钱养家糊口。我们的精力真的很有限,所以我们只能把时间花在真正想用它的朋友身上。如果你能花10分钟参加活动,不管你能不能用,至少你有一个想法,愿意投入一点点去做,我们也愿意帮助您。联系微信:xnx3com
  常见问题-Q&amp;A 安装后只有一个网站,或者有代理后台可以打开多个网站
  安装功能齐全,包括代理后端。这样安装之后,其实就是你自己私有部署的一个SAAS云建站系统。代理后台的使用请参考:
  可以一键生成html网页吗?或伪静态
  是一键生成的html网页,是真静态,不是伪静态
  网站 如何与手机匹配?
  在我们模板库的数百个模板中,大部分模板都支持手机和电脑同时访问。其实这个问题与我们的建站系统无关。如何适配手机取决于你制作的模板中CSS样式是怎么写的,是否响应式适配手机。
  其他【帮助文档、系统使用帮助说明】()模板文档、模板开发说明、模板标签 查看全部

  通用解决方案:API(接口)是什么
  什么是 API(接口)?举个常见的例子,在京东下单并付款后,商户选择顺丰快递发货,然后就可以在京东上实时查看当前物流信息。京东和顺丰作为两家独立的公司,可以在京东上实时看到顺丰的快递信息。这需要 API。在查看自己的快递信息时,京东可以使用顺丰提供的API接口进行实时检索。信息单独呈现网站。此外,您还可以在快递100上输入订单号查询快递信息。只要有合作或许可,其他公司可以通过顺丰提供的API接口检索快递信息。由于有多个调用,
  我们来看看百度是如何给出API的定义的:
  API(应用程序编程接口)是预定义的函数,旨在为应用程序和开发人员提供访问基于软件或硬件的一组例程的能力,而无需访问源代码或了解该机制的内部工作细节。
  从百度的定义来看,我们首先关注:功能,提供应用和开发者,无需访问源代码,例程。注意这四个短语。其中,例程是系统对外提供的功能接口或服务的集合。本文重点介绍API的数据服务功能接口。
  首先,在下面的文章中,我将首先演示如何使用浏览器,无需编程,无需访问源代码,调用免费的API接口,让您使用最简单的接口;
  然后,将演示如何通过编程调用接口;
  最后,演示启动WEB服务,编写一个简单的API接口来体现API的功能(y=f(x))。
  您也可以尝试复制代码。通过自己的实验,你会学到一些关于后端、前端的知识,加深你对 API 的理解。那么开始吧,我们先来一张图:通过API提供信息(数据)的功能,看看数据是如何流动的。如果您为 API 指定特定位置,它将位于下图的中心。
  为了改变理解,我穿插了一个故事人物。假设世界太大了,你想在非洲大陆看到它,成为一名水手,在一次航行中被一位著名的航海家带走(你有船上唯一的卫星计算机),你会不可避免地成为途中的领航员。它将让您确定下一个城市的纬度和经度。这时候导航器让你确定深圳的经纬度。
  1.你是个人肉API
  这时候,你可以想到一个简单的方法就是去百度搜索。除了领航员,船上的高级水手和大副很可能会问你。这时候你其实就是一个接口,大家来找你获取地理位置信息。作为一个接口,你自己不产生信息,你只是信息的采集器和传递者,提供人肉数据服务。
  2.使用免费的经纬API接口
  在百度搜索过程中,很多网友给出的经纬度不一致,要反复对比才能辨别真伪。时间长了,你可能会觉得大家都在问位置,太烦人了。我的人肉API效率太慢了。有没有更快的方法。
  这时候,你发现了一个阿里云的免费API接口:深圳。您在浏览器的地址栏中输入此 URL,即可获得正确的纬度和经度。你把网址里的深圳换成别的城市,就可以找到了。这时候,通过这个界面,就可以大大提高为大家确定位置的效率。
  3.您对此不满意
  你觉得这个接口很好,你就是懂Python,为什么不写点代码,注意这个时候你的角色变了:你已经从人类API变成了开发者(注意这是百度里的API定义关键词),你现在的目标是编写可以自动获取这个地方的经纬度的代码。
  #python
import requests
r = requests.get("http://gc.ditu.aliyun.com/geocoding?a=深圳")
loc = r.json()
print loc
#打印出的结果:{u&#39;alevel&#39;: 4, u&#39;lon&#39;: 114.05786, u&#39;level&#39;: 2, u&#39;cityName&#39;: u&#39;&#39;, u&#39;address&#39;: u&#39;&#39;, u&#39;lat&#39;: 22.54309}
# 与在浏览器输入地址的结果一致
print "深圳的经度是%s,纬度是%s" % (loc["lon"], loc["lat"])
#打印出的结果是:深圳的经度是114.05786,纬度是22.54309
  至此,我们来回顾一下百度对API的定义。目前,作为开发者,您只需编写几行代码即可访问“阿里巴巴云经纬度接口”。您无需访问此 API 的源代码,也无需了解此 API 是如何制作的。也就是说,无论是通过浏览器还是编程语言,您现在已经在使用简单的 API。
  4.使用简单的API接口后,进一步想知道它的内部机制是什么
  基于可以使用的知识,API的源代码及其内部机制是什么?目前可以调用经纬度API,单纯获取位置是不够的。你可能想自己写一个API接口,而不是紧紧地提供位置信息,同时添加对城市的介绍。
  使用 Python 的 tornado 模块构建 Web 服务。让我们创建一个脚本空文件 web_server.py 并将以下代码复制到其中
  # -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding(&#39;utf-8&#39;)
import tornado.ioloop
import tornado.web
import json
import requests
lists = {u"深圳": "是经济特区,紧邻广州,接壤香港,人口约1200万",
u"青岛": "旅游城市,濒临黄海,特产啤酒,人口约920万"
}
def get_loc(city):
r = requests.get("http://gc.ditu.aliyun.com/geocoding?a=%s" % city.encode(&#39;UTF-8&#39;))
<p>
loc = r.json()
return "经度是%s,纬度是%s" % (loc["lon"], loc["lat"])
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
return self.get_secure_cookie("user")
class MainHandler(BaseHandler):
def get(self):
if self.request.arguments.has_key("id"):
greeting = self.get_argument(&#39;id&#39;, &#39;Hello&#39;)
if greeting in lists:
self.write(greeting + ": " + str(get_loc(greeting)) + "," + str(lists[greeting]))
else:
self.write("none")
settings = dict(cookie_secret="P1/V61oETzdkLmGeJJFuYh7Eo5KXQAGaYgEQnp2XdTo=", debug=True)
application = tornado.web.Application([(r"/", MainHandler), ], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.current().start()</p>
  执行web_server.py,执行后会启动一个web服务
  接下来我们在浏览器中输入192.168.199.204:8888/?id=Shenzhen
  注意我自己电脑的局域网IP是192.168.199.204,需要换成自己电脑(或者虚拟机)的ip。
  从上图中,我们实现了和“阿里巴巴云经纬度界面”一样的功能,得到了除了经纬度之外的城市的简要描述。随着航次越来越多,您让船上的每个人不仅了解地理信息,还了解每个城市的经济和文化状况。随着信息和数据的增加,特别需要能够先保存数据,使用时直接调用API的东西。
  5.数据存储,按需调整
  上面,我们模仿阿里云的API,搭建了一个Web服务,提供更详细的API地理位置信息服务。现在想想,我们代码里只有深圳和青岛两个城市,还有很多城市没有提到。此外,城市还有经济发展、饮食文化等。我们将深圳和青岛的城市信息存储到mysql中。
  保存后,我们直接从mysql中获取数据,通过API直接展示给浏览器。更改 web_server.py 脚本
  # -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding(&#39;utf-8&#39;)
import tornado.ioloop
import tornado.web
import json
import requests
import MySQLdb.constants
def get_mysql(sql_string):
conn = MySQLdb.connect(host=&#39;localhost&#39;, port = 3306, user = &#39;root&#39;, passwd = &#39;123456&#39;, db = &#39;test&#39;, charset = &#39;utf8&#39;)
cursor = conn.cursor()
cursor.execute(sql_string)
resultList = {}
for data in cursor.fetchall():
<p>
city_name = data[0]
city_introduce = data[1]
resultList[city_name] = city_introduce
return resultList
cursor.close()
conn1.close()
def get_loc(city):
r = requests.get("http://gc.ditu.aliyun.com/geocoding?a=%s" % city.encode(&#39;UTF-8&#39;))
loc = r.json()
return "经度是%s,纬度是%s" % (loc["lon"], loc["lat"])
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
return self.get_secure_cookie("user")
class MainHandler(BaseHandler):
def get(self):
if self.request.arguments.has_key("id"):
greeting = self.get_argument(&#39;id&#39;, &#39;Hello&#39;)
lists = get_mysql("select name,introduce from test.city where name =&#39;%s&#39; " % greeting.encode(&#39;UTF-8&#39;)) #直接从mysql里读取城市信息,特别注意这里的SQL
if greeting in lists:
self.write(greeting + ": " + str(get_loc(greeting)) + "," + str(lists[greeting]))
else:
self.write("none")
settings = dict(cookie_secret="P1/V61oETzdkLmGeJJFuYh7Eo5KXQAGaYgEQnp2XdTo=", debug=True)
application = tornado.web.Application([(r"/", MainHandler), ], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.current().start()
</p>
  保存web_server.py后,再次执行重启,在浏览器地址输入192.168.199.204:8888/?id=Shenzhen,出现与步骤4相同的结果,不过这次是从mysql中取数据,通过API显示界面浏览器。至此,你不仅会用到API,还会通过tornado打开web服务,打开一个API查询接口。
  最后,总结一下,从上面的文章,我先画了一张图,结合数据流向,描述了API的位置,然后用了一个信息采集器的故事,如何使用现有的接口,去提供更好的界面。当然,这太简单了。但我认为它也可以解释 API 的基本含义。生产环境中API的复杂性涉及数据复杂性、接口稳定性、高可用性和安全性。
  (本文结束,如有疑问请留言)
  推荐链接:
  1.知乎上API的答案
  /question/38594466/answer/228418422
  /question/38594466/answer/215257117
  API的作用:
  - 对于软件提供者,可以留出API供其他应用调用,形成生态系统,让软件发挥最大价值,变得更有生命力。(同时其他人看不到代码,不伤商业机密。)(可以顺丰京东为例)
  - 对于应用开发者来说,通过开放的API,可以直接调用多家公司制作的功能,制作自己的应用,无需自己动手,节省能源。
  /question/21691705/answer/26406216
  API(应用程序编程接口)
  翻译成中文是“应用程序接口”,其实这个翻译不好,应该说是“程序通信接口”。
  翻译成接口,顾名思义,就是用来沟通两种不同的东西,通常由一组函数库组成。
  同一平台下的两个不同的事物(程序或系统),为了访问彼此的功能等,
  因此,一个 X 程序编写了一组函数,以允许同一平台上的其他程序访问该 X 程序的函数。
  那套函数可以说是X程序对外开放的API。
  整套解决方案:wangmarket: 网市场云建站系统
  方法二:使用serverless版本快速做网站(建议先试试这个方法,毕竟不用花钱买服务器)
  做网站,不用买服务器,一年几毛钱的流量费和html文件存储费。对于只做一个或几个网站的朋友,这是首选,强烈推荐。毕竟只是做几个网站,谁愿意承担增加一台服务器的费用。
  下载链接:
  方法三:上线,华为云服务器,花1元快速部署上线使用
  根据本站开户、选台服务器,在线部署和使用网市云建站系统仅需一元,无需其他额外费用!
  (这个版本可能是5.2的镜像,有点旧,但是正常使用没问题,建议参与以下活动,我们会帮你安装最新版本)
  方式四:自定义部署,比如部署到私服、阿里云、腾讯云等(这种方式用得最多)
  参考:
  如果您要部署到服务器,建议您这样做。
  配套软件:Pa网站工具、模板计算工具
  看哪个网站,拉出来做个模板。我看到的 网站 可以被我使用!/mail_osc/templatespider
  系统二次开发目前使用的开源框架介绍
  SpringBoot2.6.1、Shiro、Redis5、Mysql5.7(必须是这个版本)、ElasticSearch 7.10.1、
  前端信息提示msg.js,客服代理kefu.js,网站管理后台Layui
  开发前注意事项
  用Java开发,有两种数据库,默认使用sqlite 3,也可以配置使用mysql。
  
  一定要注意版本号不要写错,jdk1.8和mysql用的是5.7,重要的事情说三遍
  另外,请使用 Eclipse 进行开发。我们从来没有使用过idea。如果idea出现异常,可以自行百度搜索解决方法,因为idea还有其他的朋友,很多都可以正常运行,但是我们没用过idea。如果您有想法 如果出现问题,我们将无法提供任何帮助。
  以下是一些入门步骤:
  本地环境和git导入项目配置Mysql数据库(可选,不做这一步完全可以运行) 代码起来后,通过安装向导,安装系统三分钟导入模板快速创建自己的网站
  从网市云建站系统v5.0版本中,我们提取了网市云建站系统底层基础支持,如常用工具、权限控制等,并调整打包了一套集成开发框架。叫它wm。也就是说,在网上市场搭建云站点的基本操作都收录在wm文档中。wm的基础开发文档包括数据库操作、文件操作、日志操作、短信发送、ajax请求等最基本的功能模块。通过它,软件系的应届毕业生可以在一个月内快速进入开发状态,具备项目开发能力。点击这里查看wm开发文档
  当前目录结构
  wangmarket 项目
├─src 项目源代码 ( Maven )
├─pom.xml 项目源代码 pom ( Maven )
├─else 其他的杂七杂八相关文件,一般用不到
│ ├─wangmarket.sql 项目运行所需要的数据库文件( Mysql数据库,默认sqlite3)
└─README.md 说明
  进行二次开发
  在二次开发过程中,我们不建议您直接在本项目中进行更改,否则您将失去跟随我们版本升级的能力。众所周知的织梦cms也被称为安全漏洞,因为版本未升级而失去维护。
  我们建议您可以扩展这个项目,开发您想要的模块和功能,以及一些原创功能和页面更改。例如,登陆页面的重写。
  当我们市场有新版本时,只需直接更新WEB-INF/lib/wangmarket-xxx.jar即可完成版本升级
  
  云模板库
  您的时间非常宝贵!它不会让你一接触就学会自己制作模板。我们自带云模板库,点击查看
  虽然模板不多,只有几百套,但创建网站后一键导入,直接使用!一键导入后,会自动创建栏目和页面。您只需要更改栏目名称,更改文字和图片,即可达到成本网站交付标准!作为一个早期的你,这足以服务客户并熟悉整个系统!另外,我们模板库的模板会不断增加。你看到的任何 网站 都可以被我使用 - 无限模板计划
  项目经验
  网市云建站系统,2009年开始使用php开发wap系统建站。用java重构后,2010年底发布了第一版Java版建站系统。历经十余年不断更新迭代,功能完善...
  活动,免费帮助安装+调试/发送授权/发送代理
  微信扫码关注公众号,花10分钟参与提示活动,即可换取我们在安装、调试、授权、代理等方面的帮助。
  作者的话
  我们支持白人卖淫,但我们不想做无意义的卖淫!很多工作室和小微公司想要生存下来,赚到一些钱,实属不易。在资本积累方面,如果你购买牌照,你显然会有很大的负担。如果您属于该领域,建议您参与我们的活动并关注微信公众号。“wangmarket”可以看到活动,不花钱用我们的开源很不容易,还得赚钱养家糊口。我们的精力真的很有限,所以我们只能把时间花在真正想用它的朋友身上。如果你能花10分钟参加活动,不管你能不能用,至少你有一个想法,愿意投入一点点去做,我们也愿意帮助您。联系微信:xnx3com
  常见问题-Q&amp;A 安装后只有一个网站,或者有代理后台可以打开多个网站
  安装功能齐全,包括代理后端。这样安装之后,其实就是你自己私有部署的一个SAAS云建站系统。代理后台的使用请参考:
  可以一键生成html网页吗?或伪静态
  是一键生成的html网页,是真静态,不是伪静态
  网站 如何与手机匹配?
  在我们模板库的数百个模板中,大部分模板都支持手机和电脑同时访问。其实这个问题与我们的建站系统无关。如何适配手机取决于你制作的模板中CSS样式是怎么写的,是否响应式适配手机。
  其他【帮助文档、系统使用帮助说明】()模板文档、模板开发说明、模板标签

技术分享:爬虫 | 如何构建技术文章聚合平台(二)

采集交流优采云 发表了文章 • 0 个评论 • 82 次浏览 • 2022-11-02 17:22 • 来自相关话题

  技术分享:爬虫 | 如何构建技术文章聚合平台(二)
  作者 | 张马文
  来源 | 掘金
  上一篇文章《教你如何用Crawlab搭建技术文章聚合平台(一)》介绍了如何使用和搭建Crawlab运行环境,并将Puppeteer与Crawlab集成,对掘金很有帮助, SegmentFault , CSDN 爬取技术文章,最后可以查看爬取结果。本文文章将继续讲解如何使用Flask+Vue编写一个精简的聚合平台来展示捕获到的文章内容。
  文章内容爬虫
  首先,我们需要对爬虫部分做一个小的补充。在上一篇文章中,我们只写了一个爬取文章网址的爬虫。我们还需要爬取文章内容,所以也需要编写爬虫这部分。上次爬虫的结果集合全部改成results,文章的内容会保存在数据库的content字段中。
  经过分析,我们知道每个技术网站的文章页面都有一个固定的标签,抓取这个标签下的所有HTML就可以了。具体代码分析就不展开了,这里贴出具体代码。
  <p>const puppeteer = require('puppeteer');
  const MongoClient = require('mongodb').MongoClient;
  (async => {
  // browser
  const browser = await (puppeteer.launch({
  headless: true
  }));
  // page
  const page = await browser.newPage;
  // open database connection
  const client = await MongoClient.connect('mongodb://192.168.99.100:27017');
  let db = await client.db('crawlab_test');
  const colName = process.env.CRAWLAB_COLLECTION || 'results';
  const col = db.collection(colName);
  const col_src = db.collection('results');
  const results = await col_src.find({content: {$exists: false}}).toArray;
  for (let i = 0; i < results.length; i++) {
  let item = results[i];
  // define article anchor
  let anchor;
  if (item.source === 'juejin') {
  anchor = '.article-content';
  } else if (item.source === 'segmentfault') {
  anchor = '.article';
  } else if (item.source === 'csdn') {
  anchor = '#content_views';
  } else {
  continue;
  }
  console.log(`anchor: ${anchor}`);
  // navigate to the article
  try {
  await page.goto(item.url, {waitUntil: 'domcontentloaded'});
  await page.waitFor(2000);
  } catch (e) {
  console.error(e);
  continue;
  }
  // scrape article content
  item.content = await page.$eval(anchor, el => el.innerHTML);
  // save to database
  await col.save(item);
  console.log(`saved item: ${JSON.stringify(item)}`)
  }
  // close mongodb
  client.close;
  // close browser
  browser.close;
  });</p>
  然后按照上一篇文章的步骤部署运行爬虫,就可以采集到详细的文章内容了。
  文章内容爬虫的代码已经更新到Github了。
  接下来,我们可以开始对这些 文章 做 文章。
  前后分离
  从目前的技术发展来看,前后端分离已经成为主流:一是前端技术越来越复杂,需要模块化和工程化;第二,前后端分离,让前后端团队分工协作,更高效地开发应用。由于本文的聚合平台是一个轻量级的应用,所以我们使用Python的轻量级Web应用框架Flask来编写后端界面,而我们使用的是近年来非常流行的Vue,前端也很容易上手-结尾。
  烧瓶
  Flask全称为Micro Framework,可见其轻量级,几行代码就能写出一个Web应用。它依赖扩展插件来扩展其特定功能,例如登录身份验证、RESTful、数据模型等。在本节中,我们将构建一个 RESTful 后端 API 应用程序。
  安装
  首先安装相关的依赖。
  <p>pip install flask flask_restful flask_cors pymongo</p>
  基本应用
  安装完成后,我们可以新建一个app.py文件,输入如下代码
  <p>from flask import Flask
  from flask_cors import CORS
  from flask_restful import Api
  # 生成Flask App实例
  app = Flask(__name__)
  # 生成API实例
  api = Api(app)
  # 支持CORS跨域
  CORS(app, supports_credentials=True)
  if __name__ == '__main__':
  app.run</p>
  这个基本的 Flask 应用程序可以通过在命令行输入 python app.py 来运行。
  编写 API
  接下来,我们需要编写获取文章的接口。首先,让我们简要分析一下需求。
  这个 Flask 应用程序要实现的功能是:
  从数据库中获取捕获的文章,并将文章ID、标题、摘要、捕获时间返回给前端,作为文章列表使用;
  
  对于给定的 文章ID,从数据库中返回相应的 文章 内容,以供前端用作详细信息页面。
  因此,我们需要实现上述两个API。让我们开始编写界面。
  列表界面
  在 app.py 中添加如下代码作为列表界面。
  <p>class ListApi(Resource):
  def get(self):
  # 查询
  items = col.find({'content': {'$exists': True}}).sort('_id', DESCENDING).limit(40)
  data =
  for item in items:
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  data.append({
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S')
  })
  return data</p>
  详情界面
  同样,在 app.py 中输入以下代码。
  <p>class DetailApi(Resource):
  def get(self, id):
  item = col.find_one({'_id': ObjectId(id)})
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  return {
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S'),
  'content': _item['content']
  }</p>
  映射接口
  编写好接口后,我们需要将它们映射到相应的 URL。
  <p>api.add_resource(ListApi, '/results')
  api.add_resource(DetailApi, '/results/')</p>
  完整代码
  下面是完整的Flask应用代码,非常简单,实现了文章list和文章details两个功能。接下来,我们将开始开发前端部分。
  <p>import json
  from bson import json_util, ObjectId
  from flask import Flask, jsonify
  from flask_cors import CORS
  from flask_restful import Api, Resource
  from pymongo import MongoClient, DESCENDING
  # 生成Flask App实例
  app = Flask(__name__)
  # 生成MongoDB实例
  mongo = MongoClient(host='192.168.99.100')
  db = mongo['crawlab_test']
  col = db['results']
  # 生成API实例
  api = Api(app)
  # 支持CORS跨域
  CORS(app, supports_credentials=True)
  class ListApi(Resource):
  def get(self):
  # 查询
  items = col.find({}).sort('_id', DESCENDING).limit(20)
  data =
  for item in items:
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  data.append({
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S')
  })
  return data
  class DetailApi(Resource):
  def get(self, id):
  item = col.find_one({'_id': ObjectId(id)})
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  return {
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S'),
  'content': _item['content']
  }
  api.add_resource(ListApi, '/results')
  api.add_resource(DetailApi, '/results/')
  if __name__ == '__main__':
  app.run</p>
  运行 python app.py 运行后台接口服务器。
  Vue
  Vue这几年非常火。它已经在 Github 上超越 React,成为三大开源框架(React、Vue 和 Angular)中 Star 最多的项目。与 React 和 Angular 相比,Vue 非常容易上手。您可以使用双向绑定数据快速开始构建简单的应用程序,也可以使用 Vuex 单向数据传输构建大型应用程序。这种灵活性是它受到大多数开发人员欢迎的原因之一。
  为了构建一个简单的 Vue 应用程序,我们将使用 vue-cli3,一个 Vue 项目的脚手架。首先,我们从 npm 安装脚手架。
  安装 vue-cli3
  <p>yarn add @vue/cli</p>
  如果你还没有安装yarn,执行下面的命令安装。
  <p>npm i -g yarn</p>
  创建项目
  接下来,我们需要使用 vue-cli3 构建一个项目。执行以下命令。
  <p>vue create frontend</p>
  命令行会弹出以下选项,选择默认即可。
  
  <p>? Please pick a preset: (Use arrow keys)
  ❯ default (babel, eslint)
  preset (vue-router, vuex, node-sass, babel, eslint, unit-jest)
  Manually select features </p>
  然后 vue-cli3 将开始准备必要的依赖项来构建项目并生成项目结构。
  此外,我们还需要安装完成其他功能所需的包。
  <p>yarn add axios</p>
  文章列表页面
  在 views 目录中创建一个 List.vue 文件,内容如下。
  <p>
  {{article.title}}
  
  {{article.ts}}
  import axios from 'axios'
  export default {
  name: 'List',
  data {
  return {
  list:
  }
  },
  methods: {
  showArticle (id) {
  this.$router.push(`/${id}`)
  }
  },
  created {
  axios.get('http://localhost:5000/results')
  .then(response => {
  this.list = response.data
  })
  }
  }
  .list {
  display: flex;
  }
  .left {
  flex-basis: 20%;
  }
  .right {
  flex-basis: 20%;
  }
  .article-list {
  text-align: left;
  list-style: none;
  }
  .article-item {
  background: #c3edfb;
  border-radius: 5px;
  padding: 5px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
  }
  .title {
  flex-basis: auto;
  color: #58769d;
  }
  .time {
  font-size: 10px;
  text-align: right;
  flex-basis: 180px;
  }</p>
  其中,ajax与API交互引用axios,这里获取list接口。该布局用于经典的双圣杯布局。methods中的showArticle方法接收到id参数,跳转到详情页。
  文章详情页面
  在views目录下,创建一个Detail.vue文件,输入如下内容。
  <p>{{article.title}}
  import axios from 'axios'
  export default {
  name: 'Detail',
  data {
  return {
  article: {}
  }
  },
  computed: {
  id {
  return this.$route.params.id
  }
  },
  created {
  axios.get(`http://localhost:5000/results/${this.id}`)
  .then(response => {
  this.article = response.data
  })
  }
  }
  .detail {
  display: flex;
  }
  .left {
  flex-basis: 20%;
  }
  .right {
  flex-basis: 20%;
  }
  .center {
  flex-basis: 60%;
  text-align: left;
  }
  .title {
  }</p>
  这个页面也是经典的双圣杯布局,中间占40%。API获取的文章内容输出到content,并通过v-html绑定。其实这里可以做进一步的CSS优化,只是作者太懒了,这个任务留给读者自己去完成。
  添加路线
  编辑 router.js 文件并将其修改为以下内容。
  <p>import Vue from 'vue'
  import Router from 'vue-router'
  import List from './views/List'
  import Detail from './views/Detail'
  Vue.use(Router)
  export default new Router({
  mode: 'hash',
  base: process.env.BASE_URL,
  routes: [
  {
  path: '/',
  name: 'List',
  component: List
  },
  {
  path: '/:id',
  name: 'Detail',
  component: Detail
  }
  ]
  })</p>
  运行前端
  在命令行中输入以下命令,打开:8080可以看到文章的列表。
  <p>npm run serve</p>
  最终效果
  最终聚合平台效果截图如下,可以看到基本样式已经出来了。
  总结
  本文在上一篇文章《教你如何用Crawlab搭建技术文章聚合平台(一)》的基础上,介绍了Flask+Vue的使用方法以及之前抓取的文章数据,搭建一个简单的技术文章聚合平台。使用的技术非常基础。当然,肯定还有很大的优化和改进空间。这是留给读者和大人物的。
  直观:通过网络爬虫采集大数据
  2021-07-02
  网络数据采集是指通过网络爬虫或网站公共API从网站获取数据信息。该方法可以从网页中提取非结构化数据,存储为统一的本地数据文件,并以结构化的方式存储。支持图片、音频、视频等文件或附件的采集,附件可以自动与文本关联。
  在互联网时代,网络爬虫主要为搜索引擎提供最全面、最新的数据。
  本节首先简要介绍网络爬虫的原理和工作流程,然后讨论网络爬虫的爬取策略,最后介绍典型的网络工具。
  网络爬虫的原理
  网络爬虫是根据一定的规则自动爬取网络信息的程序或脚本。
  网络爬虫可以自动采集所有可以访问的页面内容,为搜索引擎和大数据分析提供数据源。从功能上来说,爬虫一般具有数据采集、处理和存储三个功能,如图1所示。
  图1 网络爬虫示意图
  除了供用户阅读的文字信息外,网页还收录一些超链接信息。
  网络爬虫系统正是通过网页中的超链接信息不断获取网络上的其他网页。网络爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL。在爬取网页的过程中,不断地从当前页面中提取新的 URL 并放入队列中,直到满足系统的某些停止条件。
  网络爬虫系统一般会选择一些比较重要的、出度(网页链接出的超链接数)网站较大的URL作为种子URL集。
  网络爬虫系统使用这些种子集作为初始 URL 来开始数据爬取。因为网页中收录链接信息,所以会通过已有网页的URL获取一些新的URL。
  网页之间的指向结构可以看成一片森林,每个种子URL对应的网页就是森林中一棵树的根节点,这样网络爬虫系统就可以按照广度优先搜索算法遍历所有信息或深度优先搜索算法。网页。
  由于深度优先搜索算法可能导致爬虫系统陷入网站内部,不利于搜索距离网站首页比较近的网页信息,因此广度优先搜索算法一般使用采集网页。
  网络爬虫系统首先将种子 URL 放入下载队列,简单地从队列头部取一个 URL 下载其对应的网页,获取网页内容并存储,然后解析链接信息网页以获取一些新的 URL。
  其次,根据一定的网页分析算法,过滤掉与主题无关的链接,保留有用的链接,放入待抓取的URL队列中。
  最后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。
  网络爬虫工作流程
  如图 2 所示,网络爬虫的基本工作流程如下。
  1) 首先选择种子 URL 的一部分。
  2)将这些网址放入待抓取的网址队列中。
  3)从待爬取URL队列中取出待爬取URL,解析DNS,获取主机IP地址,下载该URL对应的网页,存入下载的网页库中。此外,将这些 URL 放入 Crawl URLs 队列。
  4)分析URL队列中已经爬取的URL,分析其中的其他URL,将这些URL放入待爬取的URL队列,从而进入下一个循环。
  图2 网络爬虫基本工作流程
  网络爬虫抓取策略
  谷歌、百度等常见搜索引擎抓取的网页数量通常以数十亿计。那么,面对如此多的网页,网络爬虫如何才能尽可能的遍历所有网页呢?如果您对大数据开发感兴趣,想系统地学习大数据,可以加入大数据技术学习交流群:458号345号782获取学习资源,从而扩大网页信息的覆盖范围可能,这是网络爬虫系统面临的一个非常关键的问题。在网络爬虫系统中,爬取策略决定了网页被爬取的顺序。
  本节首先简要介绍网络爬取策略中使用的基本概念。
  1)网页之间的关系模型
  从互联网的结构来看,网页通过各种超链接相互连接,形成一个巨大而复杂的相互关联的有向图。
  
  如图3所示,如果把网页看成图中的一个节点,把网页中其他网页的链接看成这个节点到其他节点的边,那么我们就可以轻松查看整个互联网网页被建模为有向图。
  理论上,通过遍历算法对图进行遍历,几乎可以访问互联网上的任何网页。
  图3 网页关系模型图
  2)网页分类
  从爬虫的角度来划分互联网,可以将互联网的所有页面分为5个部分:已下载未过期网页、已下载已过期网页、待下载网页、已知网页和未知网页,如图4.
  本地爬取的网页实际上是互联网内容的镜像和备份。互联网正在动态变化。当互联网的一部分内容发生变化时,本地抓取的网页就会失效。因此,下载的网页分为两类:下载的未过期网页和下载的过期网页。
  图4 网页分类
  要下载的页面是 URL 队列中要抓取的页面。
  可以看出,网页是指尚未被爬取且不在待爬取URL队列中的网页,但可以通过分析爬取的页面或待爬取URL对应的页面得到。
  还有一些网页是网络爬虫无法直接爬取下载的,称为不可知网页。
  下面重点介绍几种常见的爬取策略。
  1.万能网络爬虫
  通用网络爬虫也称为全网爬虫。爬取对象从一些种子URL延伸到整个网络,主要针对门户网站搜索引擎和大型网络服务商采集数据。
  为了提高工作效率,一般的网络爬虫都会采用一定的爬取策略。常用的爬取策略有深度优先策略和广度优先策略。
  1) 深度优先策略
  深度优先策略意味着网络爬虫将从起始页面开始,并逐个链接地跟踪它,直到无法再深入为止。
  完成一个爬取分支后,网络爬虫返回上一个链接节点,进一步搜索其他链接。当所有的链接都遍历完后,爬取任务结束。
  这种策略比较适合垂直搜索或者站内搜索,但是在抓取页面内容比较深的网站时会造成巨大的资源浪费。
  以图3为例,遍历的路径为1→2→5→6→3→7→4→8。
  在深度优先策略中,当搜索一个节点时,该节点的子节点和子节点的后继节点都在该节点的兄弟节点之前,深度优先策略在搜索空间中。有时,它会尝试尽可能深入,并且仅在找不到节点的后继节点时才考虑其兄弟节点。
  这样的策略决定了深度优先策略不一定能找到最优解,甚至由于深度的限制而无法找到解。
  如果不加以限制,它将沿着一条路径无限扩展,这将“捕获”成大量数据。一般来说,使用深度优先策略会选择一个合适的深度,然后反复搜索直到找到一个解,这样会降低搜索的效率。因此,当搜索数据量较小时,一般采用深度优先策略。
  2) 广度优先策略
  广度优先策略根据网页内容目录层次的深度对页面进行爬取,较浅的目录层次的页面先爬取。当同一级别的页面被爬取时,爬虫进入下一级继续爬取。
  还是以图3为例,遍历的路径是1→2→3→4→5→6→7→8
  由于广度优先策略是在第 N 层的节点扩展完成后进入第 N+1 层,保证了通过最短路径找到解。
  该策略可以有效控制页面的爬取深度,避免遇到无限深分支时无法结束爬取的问题。易于实现,不需要存储大量的中间节点。缺点是爬到更深的目录级别需要很长时间。页。
  如果搜索的分支太多,即节点的后继节点太多,算法就会耗尽资源,在可用空间中找不到解。
  2.专注于网络爬虫
  聚焦网络爬虫,也称为主题网络爬虫,是选择性地爬取与预定义主题相关的页面的网络爬虫。
  
  1)基于内容评价的爬取策略
  DeBra 将文本相似度的计算方法引入网络爬虫,提出了 Fish Search 算法。
  该算法以用户输入的查询词为主题,将收录查询词的页面视为与该主题相关的页面,其局限性在于无法评估该页面与该主题的相关性。
  Herseovic 对 Fish Search 算法进行了改进,提出了 Shark Search 算法,该算法使用空间向量模型来计算页面和主题之间的相关度。
  通过采用基于连续值计算链接值的方法,我们不仅可以计算出哪些捕获的链接与主题相关,而且可以得到相关性的量化大小。
  2)基于链接结构评估的爬取策略
  与普通文本不同,网页是收录大量结构化信息的半结构化文档。
  网页不是单独存在的。页面中的链接表示页面之间的关系。基于链接结构的搜索策略模式利用这些结构特征来评估页面和链接的重要性,从而确定搜索顺序。其中,PageRank算法就是这种搜索策略模式的代表。
  PageRank算法的基本原理是,如果一个网页被多次引用,它可能是一个重要的网页;如果一个网页没有被多次引用,而是被一个重要网页引用,那么它也可能是一个重要网页。一个网页的重要性同样传递给它所指的网页。
  链接页面的PageRank是通过将某个页面的PageRank除以该页面上存在的前向链接,并将得到的值分别与前向链接所指向的页面的PageRank相加得到。
  如图 5 所示,PageRank 为 100 的页面将其重要性平等地传递给它所引用的两个页面,每个页面获得 50,而 PageRank 为 9 的同一页面将其重要性传递给它所引用的三个页面。页面的每一页都传递一个值 3。
  PageRank 为 53 的页面的值源自引用它的两个页面传递的值。
  ,
  图5 PageRank算法示例
  3)基于强化学习的爬取策略
  Rennie 和 McCallum 将强化学习引入聚焦爬虫,使用贝叶斯分类器根据整个网页文本和链接文本对超链接进行分类,并计算每个链接的重要性以确定链接被访问的顺序。
  4)基于上下文图的爬取策略
  勤勉等人。提出了一种爬取策略,通过构建上下文图来学习网页之间的相关性。该策略可以训练一个机器学习系统,通过该系统可以计算当前页面到相关网页的距离。中的链接具有优先访问权。
  3.增量网络爬虫
  增量网络爬虫是指对下载的网页进行增量更新,只爬取新生成或更改的网页的爬虫。可以在一定程度上保证爬取的页面尽可能的新。
  增量网络爬虫有两个目标:
  为了实现第一个目标,增量网络爬虫需要通过重访网页来更新本地页面集中的页面内容。常用的方法有统一更新法、个体更新法和分类更新法。
  为了实现第二个目标,增量网络爬虫需要对网页的重要性进行排名。常见的策略包括广度优先策略和PageRank优先策略。
  4. 深网爬虫
  网页按存在方式可分为表层网页和深层网页。
  深网爬虫架构由六个基本功能模块(爬取控制器、解析器、表单分析器、表单处理器、响应分析器、LVS控制器)和两个爬虫内部数据结构(URL列表和LVS表)组成。
  其中,LVS(LabelValueSet)表示标签和值的集合,用来表示填写表格的数据源。在爬取过程中,最重要的部分是表单填写,包括基于领域知识的表单填写和基于网页结构分析的表单填写。
  分类:
  技术要点:
  相关文章: 查看全部

  技术分享:爬虫 | 如何构建技术文章聚合平台(二)
  作者 | 张马文
  来源 | 掘金
  上一篇文章《教你如何用Crawlab搭建技术文章聚合平台(一)》介绍了如何使用和搭建Crawlab运行环境,并将Puppeteer与Crawlab集成,对掘金很有帮助, SegmentFault , CSDN 爬取技术文章,最后可以查看爬取结果。本文文章将继续讲解如何使用Flask+Vue编写一个精简的聚合平台来展示捕获到的文章内容。
  文章内容爬虫
  首先,我们需要对爬虫部分做一个小的补充。在上一篇文章中,我们只写了一个爬取文章网址的爬虫。我们还需要爬取文章内容,所以也需要编写爬虫这部分。上次爬虫的结果集合全部改成results,文章的内容会保存在数据库的content字段中。
  经过分析,我们知道每个技术网站的文章页面都有一个固定的标签,抓取这个标签下的所有HTML就可以了。具体代码分析就不展开了,这里贴出具体代码。
  <p>const puppeteer = require('puppeteer');
  const MongoClient = require('mongodb').MongoClient;
  (async => {
  // browser
  const browser = await (puppeteer.launch({
  headless: true
  }));
  // page
  const page = await browser.newPage;
  // open database connection
  const client = await MongoClient.connect('mongodb://192.168.99.100:27017');
  let db = await client.db('crawlab_test');
  const colName = process.env.CRAWLAB_COLLECTION || 'results';
  const col = db.collection(colName);
  const col_src = db.collection('results');
  const results = await col_src.find({content: {$exists: false}}).toArray;
  for (let i = 0; i < results.length; i++) {
  let item = results[i];
  // define article anchor
  let anchor;
  if (item.source === 'juejin') {
  anchor = '.article-content';
  } else if (item.source === 'segmentfault') {
  anchor = '.article';
  } else if (item.source === 'csdn') {
  anchor = '#content_views';
  } else {
  continue;
  }
  console.log(`anchor: ${anchor}`);
  // navigate to the article
  try {
  await page.goto(item.url, {waitUntil: 'domcontentloaded'});
  await page.waitFor(2000);
  } catch (e) {
  console.error(e);
  continue;
  }
  // scrape article content
  item.content = await page.$eval(anchor, el => el.innerHTML);
  // save to database
  await col.save(item);
  console.log(`saved item: ${JSON.stringify(item)}`)
  }
  // close mongodb
  client.close;
  // close browser
  browser.close;
  });</p>
  然后按照上一篇文章的步骤部署运行爬虫,就可以采集到详细的文章内容了。
  文章内容爬虫的代码已经更新到Github了。
  接下来,我们可以开始对这些 文章 做 文章。
  前后分离
  从目前的技术发展来看,前后端分离已经成为主流:一是前端技术越来越复杂,需要模块化和工程化;第二,前后端分离,让前后端团队分工协作,更高效地开发应用。由于本文的聚合平台是一个轻量级的应用,所以我们使用Python的轻量级Web应用框架Flask来编写后端界面,而我们使用的是近年来非常流行的Vue,前端也很容易上手-结尾。
  烧瓶
  Flask全称为Micro Framework,可见其轻量级,几行代码就能写出一个Web应用。它依赖扩展插件来扩展其特定功能,例如登录身份验证、RESTful、数据模型等。在本节中,我们将构建一个 RESTful 后端 API 应用程序。
  安装
  首先安装相关的依赖。
  <p>pip install flask flask_restful flask_cors pymongo</p>
  基本应用
  安装完成后,我们可以新建一个app.py文件,输入如下代码
  <p>from flask import Flask
  from flask_cors import CORS
  from flask_restful import Api
  # 生成Flask App实例
  app = Flask(__name__)
  # 生成API实例
  api = Api(app)
  # 支持CORS跨域
  CORS(app, supports_credentials=True)
  if __name__ == '__main__':
  app.run</p>
  这个基本的 Flask 应用程序可以通过在命令行输入 python app.py 来运行。
  编写 API
  接下来,我们需要编写获取文章的接口。首先,让我们简要分析一下需求。
  这个 Flask 应用程序要实现的功能是:
  从数据库中获取捕获的文章,并将文章ID、标题、摘要、捕获时间返回给前端,作为文章列表使用;
  
  对于给定的 文章ID,从数据库中返回相应的 文章 内容,以供前端用作详细信息页面。
  因此,我们需要实现上述两个API。让我们开始编写界面。
  列表界面
  在 app.py 中添加如下代码作为列表界面。
  <p>class ListApi(Resource):
  def get(self):
  # 查询
  items = col.find({'content': {'$exists': True}}).sort('_id', DESCENDING).limit(40)
  data =
  for item in items:
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  data.append({
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S')
  })
  return data</p>
  详情界面
  同样,在 app.py 中输入以下代码。
  <p>class DetailApi(Resource):
  def get(self, id):
  item = col.find_one({'_id': ObjectId(id)})
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  return {
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S'),
  'content': _item['content']
  }</p>
  映射接口
  编写好接口后,我们需要将它们映射到相应的 URL。
  <p>api.add_resource(ListApi, '/results')
  api.add_resource(DetailApi, '/results/')</p>
  完整代码
  下面是完整的Flask应用代码,非常简单,实现了文章list和文章details两个功能。接下来,我们将开始开发前端部分。
  <p>import json
  from bson import json_util, ObjectId
  from flask import Flask, jsonify
  from flask_cors import CORS
  from flask_restful import Api, Resource
  from pymongo import MongoClient, DESCENDING
  # 生成Flask App实例
  app = Flask(__name__)
  # 生成MongoDB实例
  mongo = MongoClient(host='192.168.99.100')
  db = mongo['crawlab_test']
  col = db['results']
  # 生成API实例
  api = Api(app)
  # 支持CORS跨域
  CORS(app, supports_credentials=True)
  class ListApi(Resource):
  def get(self):
  # 查询
  items = col.find({}).sort('_id', DESCENDING).limit(20)
  data =
  for item in items:
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  data.append({
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S')
  })
  return data
  class DetailApi(Resource):
  def get(self, id):
  item = col.find_one({'_id': ObjectId(id)})
  # 将pymongo object转化为python object
  _item = json.loads(json_util.dumps(item))
  return {
  '_id': _item['_id']['$oid'],
  'title': _item['title'],
  'source': _item['source'],
  'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S'),
  'content': _item['content']
  }
  api.add_resource(ListApi, '/results')
  api.add_resource(DetailApi, '/results/')
  if __name__ == '__main__':
  app.run</p>
  运行 python app.py 运行后台接口服务器。
  Vue
  Vue这几年非常火。它已经在 Github 上超越 React,成为三大开源框架(React、Vue 和 Angular)中 Star 最多的项目。与 React 和 Angular 相比,Vue 非常容易上手。您可以使用双向绑定数据快速开始构建简单的应用程序,也可以使用 Vuex 单向数据传输构建大型应用程序。这种灵活性是它受到大多数开发人员欢迎的原因之一。
  为了构建一个简单的 Vue 应用程序,我们将使用 vue-cli3,一个 Vue 项目的脚手架。首先,我们从 npm 安装脚手架。
  安装 vue-cli3
  <p>yarn add @vue/cli</p>
  如果你还没有安装yarn,执行下面的命令安装。
  <p>npm i -g yarn</p>
  创建项目
  接下来,我们需要使用 vue-cli3 构建一个项目。执行以下命令。
  <p>vue create frontend</p>
  命令行会弹出以下选项,选择默认即可。
  
  <p>? Please pick a preset: (Use arrow keys)
  ❯ default (babel, eslint)
  preset (vue-router, vuex, node-sass, babel, eslint, unit-jest)
  Manually select features </p>
  然后 vue-cli3 将开始准备必要的依赖项来构建项目并生成项目结构。
  此外,我们还需要安装完成其他功能所需的包。
  <p>yarn add axios</p>
  文章列表页面
  在 views 目录中创建一个 List.vue 文件,内容如下。
  <p>
  {{article.title}}
  
  {{article.ts}}
  import axios from 'axios'
  export default {
  name: 'List',
  data {
  return {
  list:
  }
  },
  methods: {
  showArticle (id) {
  this.$router.push(`/${id}`)
  }
  },
  created {
  axios.get('http://localhost:5000/results')
  .then(response => {
  this.list = response.data
  })
  }
  }
  .list {
  display: flex;
  }
  .left {
  flex-basis: 20%;
  }
  .right {
  flex-basis: 20%;
  }
  .article-list {
  text-align: left;
  list-style: none;
  }
  .article-item {
  background: #c3edfb;
  border-radius: 5px;
  padding: 5px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
  }
  .title {
  flex-basis: auto;
  color: #58769d;
  }
  .time {
  font-size: 10px;
  text-align: right;
  flex-basis: 180px;
  }</p>
  其中,ajax与API交互引用axios,这里获取list接口。该布局用于经典的双圣杯布局。methods中的showArticle方法接收到id参数,跳转到详情页。
  文章详情页面
  在views目录下,创建一个Detail.vue文件,输入如下内容。
  <p>{{article.title}}
  import axios from 'axios'
  export default {
  name: 'Detail',
  data {
  return {
  article: {}
  }
  },
  computed: {
  id {
  return this.$route.params.id
  }
  },
  created {
  axios.get(`http://localhost:5000/results/${this.id}`)
  .then(response => {
  this.article = response.data
  })
  }
  }
  .detail {
  display: flex;
  }
  .left {
  flex-basis: 20%;
  }
  .right {
  flex-basis: 20%;
  }
  .center {
  flex-basis: 60%;
  text-align: left;
  }
  .title {
  }</p>
  这个页面也是经典的双圣杯布局,中间占40%。API获取的文章内容输出到content,并通过v-html绑定。其实这里可以做进一步的CSS优化,只是作者太懒了,这个任务留给读者自己去完成。
  添加路线
  编辑 router.js 文件并将其修改为以下内容。
  <p>import Vue from 'vue'
  import Router from 'vue-router'
  import List from './views/List'
  import Detail from './views/Detail'
  Vue.use(Router)
  export default new Router({
  mode: 'hash',
  base: process.env.BASE_URL,
  routes: [
  {
  path: '/',
  name: 'List',
  component: List
  },
  {
  path: '/:id',
  name: 'Detail',
  component: Detail
  }
  ]
  })</p>
  运行前端
  在命令行中输入以下命令,打开:8080可以看到文章的列表。
  <p>npm run serve</p>
  最终效果
  最终聚合平台效果截图如下,可以看到基本样式已经出来了。
  总结
  本文在上一篇文章《教你如何用Crawlab搭建技术文章聚合平台(一)》的基础上,介绍了Flask+Vue的使用方法以及之前抓取的文章数据,搭建一个简单的技术文章聚合平台。使用的技术非常基础。当然,肯定还有很大的优化和改进空间。这是留给读者和大人物的。
  直观:通过网络爬虫采集大数据
  2021-07-02
  网络数据采集是指通过网络爬虫或网站公共API从网站获取数据信息。该方法可以从网页中提取非结构化数据,存储为统一的本地数据文件,并以结构化的方式存储。支持图片、音频、视频等文件或附件的采集,附件可以自动与文本关联。
  在互联网时代,网络爬虫主要为搜索引擎提供最全面、最新的数据。
  本节首先简要介绍网络爬虫的原理和工作流程,然后讨论网络爬虫的爬取策略,最后介绍典型的网络工具。
  网络爬虫的原理
  网络爬虫是根据一定的规则自动爬取网络信息的程序或脚本。
  网络爬虫可以自动采集所有可以访问的页面内容,为搜索引擎和大数据分析提供数据源。从功能上来说,爬虫一般具有数据采集、处理和存储三个功能,如图1所示。
  图1 网络爬虫示意图
  除了供用户阅读的文字信息外,网页还收录一些超链接信息。
  网络爬虫系统正是通过网页中的超链接信息不断获取网络上的其他网页。网络爬虫从一个或多个初始网页的URL开始,获取初始网页上的URL。在爬取网页的过程中,不断地从当前页面中提取新的 URL 并放入队列中,直到满足系统的某些停止条件。
  网络爬虫系统一般会选择一些比较重要的、出度(网页链接出的超链接数)网站较大的URL作为种子URL集。
  网络爬虫系统使用这些种子集作为初始 URL 来开始数据爬取。因为网页中收录链接信息,所以会通过已有网页的URL获取一些新的URL。
  网页之间的指向结构可以看成一片森林,每个种子URL对应的网页就是森林中一棵树的根节点,这样网络爬虫系统就可以按照广度优先搜索算法遍历所有信息或深度优先搜索算法。网页。
  由于深度优先搜索算法可能导致爬虫系统陷入网站内部,不利于搜索距离网站首页比较近的网页信息,因此广度优先搜索算法一般使用采集网页。
  网络爬虫系统首先将种子 URL 放入下载队列,简单地从队列头部取一个 URL 下载其对应的网页,获取网页内容并存储,然后解析链接信息网页以获取一些新的 URL。
  其次,根据一定的网页分析算法,过滤掉与主题无关的链接,保留有用的链接,放入待抓取的URL队列中。
  最后取出一个URL,下载其对应的网页,然后解析,以此类推,直到遍历全网或者满足某个条件。
  网络爬虫工作流程
  如图 2 所示,网络爬虫的基本工作流程如下。
  1) 首先选择种子 URL 的一部分。
  2)将这些网址放入待抓取的网址队列中。
  3)从待爬取URL队列中取出待爬取URL,解析DNS,获取主机IP地址,下载该URL对应的网页,存入下载的网页库中。此外,将这些 URL 放入 Crawl URLs 队列。
  4)分析URL队列中已经爬取的URL,分析其中的其他URL,将这些URL放入待爬取的URL队列,从而进入下一个循环。
  图2 网络爬虫基本工作流程
  网络爬虫抓取策略
  谷歌、百度等常见搜索引擎抓取的网页数量通常以数十亿计。那么,面对如此多的网页,网络爬虫如何才能尽可能的遍历所有网页呢?如果您对大数据开发感兴趣,想系统地学习大数据,可以加入大数据技术学习交流群:458号345号782获取学习资源,从而扩大网页信息的覆盖范围可能,这是网络爬虫系统面临的一个非常关键的问题。在网络爬虫系统中,爬取策略决定了网页被爬取的顺序。
  本节首先简要介绍网络爬取策略中使用的基本概念。
  1)网页之间的关系模型
  从互联网的结构来看,网页通过各种超链接相互连接,形成一个巨大而复杂的相互关联的有向图。
  
  如图3所示,如果把网页看成图中的一个节点,把网页中其他网页的链接看成这个节点到其他节点的边,那么我们就可以轻松查看整个互联网网页被建模为有向图。
  理论上,通过遍历算法对图进行遍历,几乎可以访问互联网上的任何网页。
  图3 网页关系模型图
  2)网页分类
  从爬虫的角度来划分互联网,可以将互联网的所有页面分为5个部分:已下载未过期网页、已下载已过期网页、待下载网页、已知网页和未知网页,如图4.
  本地爬取的网页实际上是互联网内容的镜像和备份。互联网正在动态变化。当互联网的一部分内容发生变化时,本地抓取的网页就会失效。因此,下载的网页分为两类:下载的未过期网页和下载的过期网页。
  图4 网页分类
  要下载的页面是 URL 队列中要抓取的页面。
  可以看出,网页是指尚未被爬取且不在待爬取URL队列中的网页,但可以通过分析爬取的页面或待爬取URL对应的页面得到。
  还有一些网页是网络爬虫无法直接爬取下载的,称为不可知网页。
  下面重点介绍几种常见的爬取策略。
  1.万能网络爬虫
  通用网络爬虫也称为全网爬虫。爬取对象从一些种子URL延伸到整个网络,主要针对门户网站搜索引擎和大型网络服务商采集数据。
  为了提高工作效率,一般的网络爬虫都会采用一定的爬取策略。常用的爬取策略有深度优先策略和广度优先策略。
  1) 深度优先策略
  深度优先策略意味着网络爬虫将从起始页面开始,并逐个链接地跟踪它,直到无法再深入为止。
  完成一个爬取分支后,网络爬虫返回上一个链接节点,进一步搜索其他链接。当所有的链接都遍历完后,爬取任务结束。
  这种策略比较适合垂直搜索或者站内搜索,但是在抓取页面内容比较深的网站时会造成巨大的资源浪费。
  以图3为例,遍历的路径为1→2→5→6→3→7→4→8。
  在深度优先策略中,当搜索一个节点时,该节点的子节点和子节点的后继节点都在该节点的兄弟节点之前,深度优先策略在搜索空间中。有时,它会尝试尽可能深入,并且仅在找不到节点的后继节点时才考虑其兄弟节点。
  这样的策略决定了深度优先策略不一定能找到最优解,甚至由于深度的限制而无法找到解。
  如果不加以限制,它将沿着一条路径无限扩展,这将“捕获”成大量数据。一般来说,使用深度优先策略会选择一个合适的深度,然后反复搜索直到找到一个解,这样会降低搜索的效率。因此,当搜索数据量较小时,一般采用深度优先策略。
  2) 广度优先策略
  广度优先策略根据网页内容目录层次的深度对页面进行爬取,较浅的目录层次的页面先爬取。当同一级别的页面被爬取时,爬虫进入下一级继续爬取。
  还是以图3为例,遍历的路径是1→2→3→4→5→6→7→8
  由于广度优先策略是在第 N 层的节点扩展完成后进入第 N+1 层,保证了通过最短路径找到解。
  该策略可以有效控制页面的爬取深度,避免遇到无限深分支时无法结束爬取的问题。易于实现,不需要存储大量的中间节点。缺点是爬到更深的目录级别需要很长时间。页。
  如果搜索的分支太多,即节点的后继节点太多,算法就会耗尽资源,在可用空间中找不到解。
  2.专注于网络爬虫
  聚焦网络爬虫,也称为主题网络爬虫,是选择性地爬取与预定义主题相关的页面的网络爬虫。
  
  1)基于内容评价的爬取策略
  DeBra 将文本相似度的计算方法引入网络爬虫,提出了 Fish Search 算法。
  该算法以用户输入的查询词为主题,将收录查询词的页面视为与该主题相关的页面,其局限性在于无法评估该页面与该主题的相关性。
  Herseovic 对 Fish Search 算法进行了改进,提出了 Shark Search 算法,该算法使用空间向量模型来计算页面和主题之间的相关度。
  通过采用基于连续值计算链接值的方法,我们不仅可以计算出哪些捕获的链接与主题相关,而且可以得到相关性的量化大小。
  2)基于链接结构评估的爬取策略
  与普通文本不同,网页是收录大量结构化信息的半结构化文档。
  网页不是单独存在的。页面中的链接表示页面之间的关系。基于链接结构的搜索策略模式利用这些结构特征来评估页面和链接的重要性,从而确定搜索顺序。其中,PageRank算法就是这种搜索策略模式的代表。
  PageRank算法的基本原理是,如果一个网页被多次引用,它可能是一个重要的网页;如果一个网页没有被多次引用,而是被一个重要网页引用,那么它也可能是一个重要网页。一个网页的重要性同样传递给它所指的网页。
  链接页面的PageRank是通过将某个页面的PageRank除以该页面上存在的前向链接,并将得到的值分别与前向链接所指向的页面的PageRank相加得到。
  如图 5 所示,PageRank 为 100 的页面将其重要性平等地传递给它所引用的两个页面,每个页面获得 50,而 PageRank 为 9 的同一页面将其重要性传递给它所引用的三个页面。页面的每一页都传递一个值 3。
  PageRank 为 53 的页面的值源自引用它的两个页面传递的值。
  ,
  图5 PageRank算法示例
  3)基于强化学习的爬取策略
  Rennie 和 McCallum 将强化学习引入聚焦爬虫,使用贝叶斯分类器根据整个网页文本和链接文本对超链接进行分类,并计算每个链接的重要性以确定链接被访问的顺序。
  4)基于上下文图的爬取策略
  勤勉等人。提出了一种爬取策略,通过构建上下文图来学习网页之间的相关性。该策略可以训练一个机器学习系统,通过该系统可以计算当前页面到相关网页的距离。中的链接具有优先访问权。
  3.增量网络爬虫
  增量网络爬虫是指对下载的网页进行增量更新,只爬取新生成或更改的网页的爬虫。可以在一定程度上保证爬取的页面尽可能的新。
  增量网络爬虫有两个目标:
  为了实现第一个目标,增量网络爬虫需要通过重访网页来更新本地页面集中的页面内容。常用的方法有统一更新法、个体更新法和分类更新法。
  为了实现第二个目标,增量网络爬虫需要对网页的重要性进行排名。常见的策略包括广度优先策略和PageRank优先策略。
  4. 深网爬虫
  网页按存在方式可分为表层网页和深层网页。
  深网爬虫架构由六个基本功能模块(爬取控制器、解析器、表单分析器、表单处理器、响应分析器、LVS控制器)和两个爬虫内部数据结构(URL列表和LVS表)组成。
  其中,LVS(LabelValueSet)表示标签和值的集合,用来表示填写表格的数据源。在爬取过程中,最重要的部分是表单填写,包括基于领域知识的表单填写和基于网页结构分析的表单填写。
  分类:
  技术要点:
  相关文章:

解决方案:Python使用xslt提取网页数据

采集交流优采云 发表了文章 • 0 个评论 • 74 次浏览 • 2022-11-01 14:22 • 来自相关话题

  解决方案:Python使用xslt提取网页数据
  1 简介
  在 Python 网络爬虫内容提取器一文中,我们详细讲解了核心组件:可插拔内容提取器类 gsExtractor。本文记录了在确定gsExtractor技术路线过程中所做的编程实验。这是第一部分,尝试使用xslt方法提取静态网页内容并一次性转换为xml格式。
  2.使用lxml库提取网页内容
  lxml是python的一个库,可以快速灵活地处理XML。它支持 XML 路径语言 (XPath) 和可扩展样式表语言转换 (XSLT),并实现通用的 ElementTree API。
  这2天,我在python中测试了通过xslt提取网页内容,记录如下:
  2.1、抓取目标
  假设要提取jisoke官网老论坛的帖子标题和回复数,如下图,需要提取整个列表并保存为xml格式
  2.2、源码1:只抓取当前页面,结果显示在控制台
  Python的优势在于它可以用少量的代码解决一个问题。请注意,以下代码看起来很长。其实python函数调用的并不多。xslt 脚本占用了很大的空间。在这段代码中,只是一个长字符串。至于为什么选择 xslt 而不是离散的 xpath 或令人头疼的正则表达式,请参考《Python Instant Web Crawler Project Startup Instructions》。我们期望使用这种架构可以将程序员的时间节省一半以上。
  可以复制运行以下代码(windows10下测试,python3.2通过):
  from urllib import request
from lxml import etree
url="http://www.gooseeker.com/cn/forum/7"
conn=request.urlopen(url)
doc = etree.HTML(conn.read())
xslt_root = etree.XML("""\
<p>
""")
transform = etree.XSLT(xslt_root)
result_tree = transform(doc)
print(result_tree)</p>
  源码可以从文末的 GitHub 源码下载。
  2.3、抓取结果
  得到的爬取结果如下:
  2.4、源码2:翻页取取,结果存入文件
  我们对2.2的代码做了进一步的修改,增加了翻页和保存结果文件的功能。代码如下:
  from urllib import request
from lxml import etree
import time
xslt_root = etree.XML("""\
<p>
""")
baseurl="http://www.gooseeker.com/cn/forum/7"
basefilebegin="jsk_bbs_"
basefileend=".xml"
count=1
while (count  查看全部

  解决方案:Python使用xslt提取网页数据
  1 简介
  在 Python 网络爬虫内容提取器一文中,我们详细讲解了核心组件:可插拔内容提取器类 gsExtractor。本文记录了在确定gsExtractor技术路线过程中所做的编程实验。这是第一部分,尝试使用xslt方法提取静态网页内容并一次性转换为xml格式。
  2.使用lxml库提取网页内容
  lxml是python的一个库,可以快速灵活地处理XML。它支持 XML 路径语言 (XPath) 和可扩展样式表语言转换 (XSLT),并实现通用的 ElementTree API。
  这2天,我在python中测试了通过xslt提取网页内容,记录如下:
  2.1、抓取目标
  假设要提取jisoke官网老论坛的帖子标题和回复数,如下图,需要提取整个列表并保存为xml格式
  2.2、源码1:只抓取当前页面,结果显示在控制台
  Python的优势在于它可以用少量的代码解决一个问题。请注意,以下代码看起来很长。其实python函数调用的并不多。xslt 脚本占用了很大的空间。在这段代码中,只是一个长字符串。至于为什么选择 xslt 而不是离散的 xpath 或令人头疼的正则表达式,请参考《Python Instant Web Crawler Project Startup Instructions》。我们期望使用这种架构可以将程序员的时间节省一半以上。
  可以复制运行以下代码(windows10下测试,python3.2通过):
  from urllib import request
from lxml import etree
url="http://www.gooseeker.com/cn/forum/7"
conn=request.urlopen(url)
doc = etree.HTML(conn.read())
xslt_root = etree.XML("""\
<p>
""")
transform = etree.XSLT(xslt_root)
result_tree = transform(doc)
print(result_tree)</p>
  源码可以从文末的 GitHub 源码下载。
  2.3、抓取结果
  得到的爬取结果如下:
  2.4、源码2:翻页取取,结果存入文件
  我们对2.2的代码做了进一步的修改,增加了翻页和保存结果文件的功能。代码如下:
  from urllib import request
from lxml import etree
import time
xslt_root = etree.XML("""\
<p>
""")
baseurl="http://www.gooseeker.com/cn/forum/7"
basefilebegin="jsk_bbs_"
basefileend=".xml"
count=1
while (count 

最新版:轻量级云原生日志收集方案 Loki 中文入门指南

采集交流优采云 发表了文章 • 0 个评论 • 112 次浏览 • 2022-10-31 15:50 • 来自相关话题

  最新版:轻量级云原生日志收集方案 Loki 中文入门指南
  公众号关注“精彩Linux世界”
  把它定为“明星”,带你享受Linux每一天!
  您好,很高兴为您介绍掘金开发者平台上的轻量级kubernetes日志采集解决方案。我自己在生产环境中使用过这个解决方案。令我惊讶的是,与 ELK 方案相比,它在 Kubernetes 中占用的资源确实微不足道。那就跟着这个文章开始学习吧……
  为什么使用 Loki
  本文章重点介绍grafana开发的loki日志采集应用。Loki 是一个轻量级的日志采集和分析应用程序。它使用 promtail 获取日志内容并将其发送到 loki 进行存储。最后在grafana的数据源中添加一个数据源,用于日志展示和查询。
  Loki 的持久化存储支持 azure、gcs、s3、swift、local 5 种类型,其中 s3 和 local 比较常用。此外,它还支持多种类型的日志采集,比如最常用的logstash和fluentbit也在官方支持列表中。
  那么它有哪些优势呢?各个日志采集组件的优势,简单比较按名称安装的组件
  麋鹿/EFK
  弹性搜索、logstash、kibana、filebeat、kafka/redis
  支持自定义grok定期分析复杂日志内容;仪表盘支持丰富的可视化展示
  洛基
  格拉法纳,洛基,promtail
  占地面积小;原生支持 grafana;查询速度快;
  Loki 的工作原理 日志解析格式
  从上图我们可以看出,它在解析日志的时候,主要是基于index。index 包括 pod 的时间戳和部分标签(其他标签是文件名、容器等),剩下的就是日志内容。具体查询效果如下:
  {app="loki",namespace="kube-public"} 是索引。
  日志采集架构模式
  在使用过程中,官方推荐使用promtail作为代理,以DaemonSet方式部署在kubernetes的worker节点上进行日志采集。此外,您还可以使用上面提到的其他日志采集工具进行采集。这个文章最后会附上其他工具的配置方法。
  Loki 部署模式有哪些?
  Loki 是用许多组件微服务构建的,有 5 个微服务组件。在这 5 个中添加缓存,将数据放在一起以加快查询速度。数据放置在共享存储中,并且配置了 memberlist_config 部分,并在实例之间共享状态,从而允许 Loki 无限扩展。配置 memberlist_config 部分后,使用轮询方法查找数据。为了使用方便,官方将所有微服务编译成二进制,可以通过命令行参数-target控制,支持all、read、write。我们可以在部署时根据日志卷的大小指定不同的模式。
  全部(读写模式)
  服务启动后,我们所做的所有数据查询和数据写入都来自这个节点。请参见下图:
  读/写(读写分离模式)
  在读写拆分模式下运行时,前端查询查询将流量转发到读取节点。querier、ruler、fronted在读节点上保留,distributor和ingester在写节点上保留。
  以微服务模式运行
  在微服务模式下,通过不同的配置参数启动不同的角色,每个进程引用其目标角色服务。
  组件名称功能
  分销商/调度器(分销商)
  验证数据合规性;数据排序;哈希一致性;QPS 限制;转发;数据拷贝保证不丢失
  采集器(摄取器)
  时间戳排序;文件系统支持;WAL 预写;
  查询前端
  提供页面操作,向后端存储发送数据查询;query-queueing 可以防止在大容量查询时触发OOM;query-split 可以拆分大批量查询,最后进行数据聚合
  查询者
  使用logql语言查询后端存储中的日志
  缓存
  将查询到的日志缓存起来以备后用,如果数据不全,重新查询丢失的数据
  大显身手的服务器端部署
  
  上面我们已经谈了很多关于 loki 及其工作模式的内容。您还必须预料到它将如何部署,对吧?!关于如何部署,在哪里部署,部署后如何使用的问题,都会浮现在你的脑海中。部署前需要准备一个 k8s 集群。那就好,那就耐心的往下看吧……
  应用图像
  洛基
  格拉法纳/洛基:2.5.0
  促销
  格拉法纳/promtail:2.5.0
  AllInOne部署方式①k8s部署
  我们从github下载的程序没有配置文件,需要提前准备一份文件。此处提供了完整的 allInOne 配置文件,并进行了一些优化。
  配置文件内容如下
  auth_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />target: all<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ballast_bytes: 20480<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />server:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_listen_port: 9095<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_listen_port: 3100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  graceful_shutdown_timeout: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_listen_address: "0.0.0.0"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_listen_network: "tcp"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_server_max_concurrent_streams: 100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_server_max_recv_msg_size: 4194304<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_server_max_send_msg_size: 4194304<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_server_idle_timeout: 2m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_listen_address: "0.0.0.0"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_listen_network: "tcp"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_server_read_timeout: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_server_write_timeout: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_source_ips_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## http_path_prefix如果需要更改,在推送日志的时候前缀都需要加指定的内容<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## http_path_prefix: "/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  register_instrumentation: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_format: json<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_level: info<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />distributor:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_timeout: 3s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: collectors/<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      ## 需要提前创建好consul集群<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##   consul:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     http_client_timeout: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     consistent_reads: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     host: 127.0.0.1:8500<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     watch_burst_size: 2<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     watch_rate_limit: 2<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />querier:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  engine:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_look_back_period: 20s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    timeout: 3m0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  extra_query_delay: 100ms <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_concurrent: 10 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  multi_tenant_queries_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_ingester_only: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_ingesters_within: 3h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_store_only: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_timeout: 5m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  tail_max_duration: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />query_scheduler:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_outstanding_requests_per_tenant: 2048<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_client_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_recv_msg_size: 104857600<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_send_msg_size: 16777216<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    grpc_compression: gzip<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    rate_limit: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    rate_limit_burst: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    backoff_on_ratelimits: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    backoff_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      min_period: 50ms<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_period: 15s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_retries: 5 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  use_scheduler_ring: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  scheduler_ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: "collectors/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_period: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_timeout: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## 默认第一个网卡的名称<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_interface_names<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_addr: 127.0.0.1<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## 默认server.grpc-listen-port<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    instance_port: 9095<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />frontend:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_outstanding_per_tenant: 4096<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  querier_forget_delay: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  compress_responses: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_queries_longer_than: 2m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_body_size: 104857600<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_stats_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  scheduler_dns_lookup_period: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  scheduler_worker_concurrency: 15<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />query_range:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  align_queries_with_step: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  cache_results: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  parallelise_shardable_queries: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_retries: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  results_cache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    cache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      enable_fifocache: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      default_validity: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      background:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        writeback_buffer: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      redis:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        endpoint: 127.0.0.1:6379<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        timeout: 1s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        expiration: 0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        db: 9<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        pool_size: 128 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        password: 1521Qyx6^<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        idle_timeout: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        max_connection_age: 8h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ruler:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  enable_api: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  enable_sharding: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  alertmanager_refresh_interval: 1m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  disable_rule_group_label: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  evaluation_interval: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  flush_period: 3m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  for_grace_period: 20m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  for_outage_tolerance: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  notification_queue_capacity: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  notification_timeout: 4s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  poll_interval: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_stats_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  remote_write:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    config_refresh_period: 10s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  resend_delay: 2m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  rule_path: /rulers<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  search_pending_for: 5m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  storage:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    local:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      directory: /data/loki/rulers<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    type: configdb<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  sharding_strategy: default<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  wal_cleaner:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    period:  240h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    min_age: 12h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  wal:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    dir: /data/loki/ruler_wal<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_age: 4h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    min_age: 5m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    truncate_frequency: 1h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: "collectors/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_period: 5s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_timeout: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_addr: "127.0.0.1"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_id: "miyamoto.en0"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_interface_names: ["en0","lo0"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    instance_port: 9500<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    num_tokens: 100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ingester_client:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  pool_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    health_check_ingesters: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    client_cleanup_period: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    remote_timeout: 3s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  remote_timeout: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ingester:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  autoforget_unhealthy: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_encoding: gzip<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_target_size: 1572864<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_transfer_retries: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  sync_min_utilization: 3.5<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  sync_period: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  flush_check_period: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  flush_op_timeout: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_retain_period: 1m30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_block_size: 262144<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_idle_period: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_returned_stream_errors: 20<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  concurrent_flushes: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  index_shards: 32<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_chunk_age: 2h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_store_max_look_back_period: 3h30m30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  wal:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    dir: /data/loki/wal <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    flush_on_shutdown: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    checkpoint_duration: 15m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    replay_memory_ceiling: 2GB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  lifecycler:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        prefix: "collectors/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      heartbeat_timeout: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      replication_factor: 1<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    num_tokens: 128<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_period: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    join_after: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    observe_period: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## interface_names: ["en0","lo0"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    final_sleep: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    min_ready_duration: 15s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />storage_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  boltdb:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    directory: /data/loki/boltdb <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  boltdb_shipper:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    active_index_directory: /data/loki/active_index<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    build_per_tenant_index: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    cache_location: /data/loki/cache <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    cache_ttl: 48h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    resync_interval: 5m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    query_ready_num_days: 5<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    index_gateway_client:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      grpc_client_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  filesystem:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    directory: /data/loki/chunks<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />chunk_store_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_cache_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_fifocache: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    default_validity: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    background:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      writeback_buffer: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    redis:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      endpoint: 192.168.3.56:6379<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      timeout: 1s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      expiration: 0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      db: 8 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      pool_size: 128 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      password: 1521Qyx6^<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      idle_timeout: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_connection_age: 8h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    fifocache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      ttl: 1h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      validity: 30m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_items: 2000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_bytes: 500MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  write_dedupe_cache_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_fifocache: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    default_validity: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    background:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      writeback_buffer: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    redis:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      endpoint: 127.0.0.1:6379<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      timeout: 1s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      expiration: 0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      db: 7<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      pool_size: 128 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      password: 1521Qyx6^<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      idle_timeout: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_connection_age: 8h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    fifocache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      ttl: 1h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      validity: 30m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_items: 2000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_bytes: 500MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  cache_lookups_older_than: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## 压缩碎片索引<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />compactor:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  shared_store: filesystem<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  shared_store_key_prefix: index/<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  working_directory: /data/loki/compactor<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  compaction_interval: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_delete_delay: 2h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_delete_worker_count: 150<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  delete_request_cancel_period: 24h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_compaction_parallelism: 2<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## compactor_ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />frontend_worker:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  match_max_concurrent: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  parallelism: 10<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  dns_lookup_duration: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## runtime_config 这里没有配置任何信息<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## runtime_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />common:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  storage:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    filesystem:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      chunks_directory: /data/loki/chunks<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      fules_directory: /data/loki/rulers<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  replication_factor: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  persist_tokens: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## instance_interface_names: ["en0","eth0","ens33"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />analytics:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  reporting_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />limits_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ingestion_rate_strategy: global<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ingestion_rate_mb: 100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ingestion_burst_size_mb: 18<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_label_name_length: 2096<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_label_value_length: 2048<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_label_names_per_series: 60<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  enforce_metric_name: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_entries_limit_per_query: 5000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  reject_old_samples: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  reject_old_samples_max_age: 168h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  creation_grace_period: 20m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_global_streams_per_user: 5000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  unordered_writes: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_chunks_per_query: 200000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_length: 721h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_parallelism: 64 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_series: 700<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  cardinality_limit: 100000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_streams_matchers_per_query: 1000 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_concurrent_tail_requests: 10 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_evaluation_delay_duration: 3s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_max_rules_per_rule_group: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_max_rule_groups_per_tenant: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_period: 700h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  per_tenant_override_period: 20s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_cache_freshness_per_query: 2m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_queriers_per_tenant: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  per_stream_rate_limit: 6MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  per_stream_rate_limit_burst: 50MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_lookback: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_remote_write_disabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  min_sharding_lookback: 0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  split_queries_by_interval: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_line_size: 30mb<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_line_size_truncate: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_streams_per_user: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" /><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## memberlist_conig模块配置gossip用于在分发服务器、摄取器和查询器之间发现和连接。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## 所有三个组件的配置都是唯一的,以确保单个共享环。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## 至少定义了1个join_members配置后,将自动为分发服务器、摄取器和ring 配置memberlist类型的kvstore<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />memberlist:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  randomize_node_name: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  stream_timeout: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retransmit_factor: 4<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  join_members:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  - 'loki-memberlist'<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  abort_if_cluster_join_fails: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  advertise_addr: 0.0.0.0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  advertise_port: 7946<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  bind_addr: ["0.0.0.0"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  bind_port: 7946<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  compression_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  dead_node_reclaim_time: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  gossip_interval: 100ms<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  gossip_nodes: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  gossip_to_dead_nodes_time: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## join:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  leave_timeout: 15s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  left_ingesters_timeout: 3m0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_join_backoff: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_join_retries: 5<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  message_history_buffer_bytes: 4096<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  min_join_backoff: 2s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## node_name: miyamoto<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  packet_dial_timeout: 5s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  packet_write_timeout: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  pull_push_interval: 100ms<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  rejoin_interval: 10s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />schema_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  configs:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  - from: "2020-10-24"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    index:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      period: 24h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: index_<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    object_store: filesystem<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    schema: v11<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    store: boltdb-shipper<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    chunks:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      period: 168h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    row_shards: 32<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />table_manager:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_deletes_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_period: 0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  throughput_updates_disabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  poll_interval: 3m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  creation_grace_period: 20m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  index_tables_provisioning:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    provisioned_write_throughput: 1000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    provisioned_read_throughput: 500<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_write_throughput: 4<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_read_throughput: 300<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_write_scale_lastn: 50 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_inactive_throughput_on_demand_mode: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_ondemand_throughput_mode: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_read_scale_lastn: 10 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    查看全部

  最新版:轻量级云原生日志收集方案 Loki 中文入门指南
  公众号关注“精彩Linux世界”
  把它定为“明星”,带你享受Linux每一天!
  您好,很高兴为您介绍掘金开发者平台上的轻量级kubernetes日志采集解决方案。我自己在生产环境中使用过这个解决方案。令我惊讶的是,与 ELK 方案相比,它在 Kubernetes 中占用的资源确实微不足道。那就跟着这个文章开始学习吧……
  为什么使用 Loki
  本文章重点介绍grafana开发的loki日志采集应用。Loki 是一个轻量级的日志采集和分析应用程序。它使用 promtail 获取日志内容并将其发送到 loki 进行存储。最后在grafana的数据源中添加一个数据源,用于日志展示和查询。
  Loki 的持久化存储支持 azure、gcs、s3、swift、local 5 种类型,其中 s3 和 local 比较常用。此外,它还支持多种类型的日志采集,比如最常用的logstash和fluentbit也在官方支持列表中。
  那么它有哪些优势呢?各个日志采集组件的优势,简单比较按名称安装的组件
  麋鹿/EFK
  弹性搜索、logstash、kibana、filebeat、kafka/redis
  支持自定义grok定期分析复杂日志内容;仪表盘支持丰富的可视化展示
  洛基
  格拉法纳,洛基,promtail
  占地面积小;原生支持 grafana;查询速度快;
  Loki 的工作原理 日志解析格式
  从上图我们可以看出,它在解析日志的时候,主要是基于index。index 包括 pod 的时间戳和部分标签(其他标签是文件名、容器等),剩下的就是日志内容。具体查询效果如下:
  {app="loki",namespace="kube-public"} 是索引。
  日志采集架构模式
  在使用过程中,官方推荐使用promtail作为代理,以DaemonSet方式部署在kubernetes的worker节点上进行日志采集。此外,您还可以使用上面提到的其他日志采集工具进行采集。这个文章最后会附上其他工具的配置方法。
  Loki 部署模式有哪些?
  Loki 是用许多组件微服务构建的,有 5 个微服务组件。在这 5 个中添加缓存,将数据放在一起以加快查询速度。数据放置在共享存储中,并且配置了 memberlist_config 部分,并在实例之间共享状态,从而允许 Loki 无限扩展。配置 memberlist_config 部分后,使用轮询方法查找数据。为了使用方便,官方将所有微服务编译成二进制,可以通过命令行参数-target控制,支持all、read、write。我们可以在部署时根据日志卷的大小指定不同的模式。
  全部(读写模式)
  服务启动后,我们所做的所有数据查询和数据写入都来自这个节点。请参见下图:
  读/写(读写分离模式)
  在读写拆分模式下运行时,前端查询查询将流量转发到读取节点。querier、ruler、fronted在读节点上保留,distributor和ingester在写节点上保留。
  以微服务模式运行
  在微服务模式下,通过不同的配置参数启动不同的角色,每个进程引用其目标角色服务。
  组件名称功能
  分销商/调度器(分销商)
  验证数据合规性;数据排序;哈希一致性;QPS 限制;转发;数据拷贝保证不丢失
  采集器(摄取器)
  时间戳排序;文件系统支持;WAL 预写;
  查询前端
  提供页面操作,向后端存储发送数据查询;query-queueing 可以防止在大容量查询时触发OOM;query-split 可以拆分大批量查询,最后进行数据聚合
  查询者
  使用logql语言查询后端存储中的日志
  缓存
  将查询到的日志缓存起来以备后用,如果数据不全,重新查询丢失的数据
  大显身手的服务器端部署
  
  上面我们已经谈了很多关于 loki 及其工作模式的内容。您还必须预料到它将如何部署,对吧?!关于如何部署,在哪里部署,部署后如何使用的问题,都会浮现在你的脑海中。部署前需要准备一个 k8s 集群。那就好,那就耐心的往下看吧……
  应用图像
  洛基
  格拉法纳/洛基:2.5.0
  促销
  格拉法纳/promtail:2.5.0
  AllInOne部署方式①k8s部署
  我们从github下载的程序没有配置文件,需要提前准备一份文件。此处提供了完整的 allInOne 配置文件,并进行了一些优化。
  配置文件内容如下
  auth_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />target: all<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ballast_bytes: 20480<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />server:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_listen_port: 9095<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_listen_port: 3100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  graceful_shutdown_timeout: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_listen_address: "0.0.0.0"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_listen_network: "tcp"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_server_max_concurrent_streams: 100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_server_max_recv_msg_size: 4194304<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_server_max_send_msg_size: 4194304<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_server_idle_timeout: 2m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_listen_address: "0.0.0.0"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_listen_network: "tcp"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_server_read_timeout: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  http_server_write_timeout: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_source_ips_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## http_path_prefix如果需要更改,在推送日志的时候前缀都需要加指定的内容<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## http_path_prefix: "/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  register_instrumentation: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_format: json<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_level: info<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />distributor:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_timeout: 3s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: collectors/<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      ## 需要提前创建好consul集群<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##   consul:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     http_client_timeout: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     consistent_reads: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     host: 127.0.0.1:8500<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     watch_burst_size: 2<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ##     watch_rate_limit: 2<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />querier:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  engine:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_look_back_period: 20s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    timeout: 3m0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  extra_query_delay: 100ms <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_concurrent: 10 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  multi_tenant_queries_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_ingester_only: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_ingesters_within: 3h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_store_only: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_timeout: 5m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  tail_max_duration: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />query_scheduler:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_outstanding_requests_per_tenant: 2048<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  grpc_client_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_recv_msg_size: 104857600<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_send_msg_size: 16777216<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    grpc_compression: gzip<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    rate_limit: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    rate_limit_burst: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    backoff_on_ratelimits: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    backoff_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      min_period: 50ms<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_period: 15s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_retries: 5 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  use_scheduler_ring: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  scheduler_ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: "collectors/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_period: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_timeout: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## 默认第一个网卡的名称<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_interface_names<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_addr: 127.0.0.1<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## 默认server.grpc-listen-port<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    instance_port: 9095<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />frontend:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_outstanding_per_tenant: 4096<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  querier_forget_delay: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  compress_responses: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  log_queries_longer_than: 2m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_body_size: 104857600<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_stats_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  scheduler_dns_lookup_period: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  scheduler_worker_concurrency: 15<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />query_range:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  align_queries_with_step: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  cache_results: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  parallelise_shardable_queries: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_retries: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  results_cache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    cache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      enable_fifocache: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      default_validity: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      background:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        writeback_buffer: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      redis:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        endpoint: 127.0.0.1:6379<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        timeout: 1s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        expiration: 0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        db: 9<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        pool_size: 128 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        password: 1521Qyx6^<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        idle_timeout: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        max_connection_age: 8h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ruler:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  enable_api: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  enable_sharding: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  alertmanager_refresh_interval: 1m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  disable_rule_group_label: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  evaluation_interval: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  flush_period: 3m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  for_grace_period: 20m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  for_outage_tolerance: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  notification_queue_capacity: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  notification_timeout: 4s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  poll_interval: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_stats_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  remote_write:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    config_refresh_period: 10s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  resend_delay: 2m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  rule_path: /rulers<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  search_pending_for: 5m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  storage:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    local:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      directory: /data/loki/rulers<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    type: configdb<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  sharding_strategy: default<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  wal_cleaner:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    period:  240h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    min_age: 12h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  wal:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    dir: /data/loki/ruler_wal<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    max_age: 4h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    min_age: 5m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    truncate_frequency: 1h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: "collectors/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_period: 5s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_timeout: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_addr: "127.0.0.1"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_id: "miyamoto.en0"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## instance_interface_names: ["en0","lo0"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    instance_port: 9500<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    num_tokens: 100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ingester_client:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  pool_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    health_check_ingesters: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    client_cleanup_period: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    remote_timeout: 3s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  remote_timeout: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />ingester:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  autoforget_unhealthy: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_encoding: gzip<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_target_size: 1572864<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_transfer_retries: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  sync_min_utilization: 3.5<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  sync_period: 20s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  flush_check_period: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  flush_op_timeout: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_retain_period: 1m30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_block_size: 262144<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_idle_period: 1h0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_returned_stream_errors: 20<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  concurrent_flushes: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  index_shards: 32<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_chunk_age: 2h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  query_store_max_look_back_period: 3h30m30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  wal:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    dir: /data/loki/wal <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    flush_on_shutdown: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    checkpoint_duration: 15m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    replay_memory_ceiling: 2GB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  lifecycler:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      kvstore:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        store: memberlist<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        prefix: "collectors/"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      heartbeat_timeout: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      replication_factor: 1<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    num_tokens: 128<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    heartbeat_period: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    join_after: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    observe_period: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ## interface_names: ["en0","lo0"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    final_sleep: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    min_ready_duration: 15s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />storage_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  boltdb:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    directory: /data/loki/boltdb <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  boltdb_shipper:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    active_index_directory: /data/loki/active_index<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    build_per_tenant_index: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    cache_location: /data/loki/cache <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    cache_ttl: 48h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    resync_interval: 5m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    query_ready_num_days: 5<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    index_gateway_client:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      grpc_client_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  filesystem:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    directory: /data/loki/chunks<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />chunk_store_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  chunk_cache_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_fifocache: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    default_validity: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    background:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      writeback_buffer: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    redis:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      endpoint: 192.168.3.56:6379<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      timeout: 1s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      expiration: 0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      db: 8 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      pool_size: 128 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      password: 1521Qyx6^<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      idle_timeout: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_connection_age: 8h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    fifocache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      ttl: 1h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      validity: 30m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_items: 2000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_bytes: 500MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  write_dedupe_cache_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_fifocache: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    default_validity: 30s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    background:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      writeback_buffer: 10000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    redis:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      endpoint: 127.0.0.1:6379<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      timeout: 1s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      expiration: 0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      db: 7<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      pool_size: 128 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      password: 1521Qyx6^<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      idle_timeout: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_connection_age: 8h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    fifocache:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      ttl: 1h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      validity: 30m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_items: 2000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      max_size_bytes: 500MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  cache_lookups_older_than: 10s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## 压缩碎片索引<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />compactor:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  shared_store: filesystem<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  shared_store_key_prefix: index/<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  working_directory: /data/loki/compactor<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  compaction_interval: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_delete_delay: 2h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_delete_worker_count: 150<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  delete_request_cancel_period: 24h0m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_compaction_parallelism: 2<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## compactor_ring:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />frontend_worker:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  match_max_concurrent: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  parallelism: 10<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  dns_lookup_duration: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## runtime_config 这里没有配置任何信息<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## runtime_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />common:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  storage:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    filesystem:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      chunks_directory: /data/loki/chunks<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      fules_directory: /data/loki/rulers<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  replication_factor: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  persist_tokens: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## instance_interface_names: ["en0","eth0","ens33"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />analytics:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  reporting_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />limits_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ingestion_rate_strategy: global<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ingestion_rate_mb: 100<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ingestion_burst_size_mb: 18<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_label_name_length: 2096<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_label_value_length: 2048<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_label_names_per_series: 60<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  enforce_metric_name: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_entries_limit_per_query: 5000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  reject_old_samples: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  reject_old_samples_max_age: 168h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  creation_grace_period: 20m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_global_streams_per_user: 5000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  unordered_writes: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_chunks_per_query: 200000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_length: 721h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_parallelism: 64 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_series: 700<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  cardinality_limit: 100000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_streams_matchers_per_query: 1000 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_concurrent_tail_requests: 10 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_evaluation_delay_duration: 3s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_max_rules_per_rule_group: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_max_rule_groups_per_tenant: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_period: 700h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  per_tenant_override_period: 20s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_cache_freshness_per_query: 2m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_queriers_per_tenant: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  per_stream_rate_limit: 6MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  per_stream_rate_limit_burst: 50MB<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_query_lookback: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ruler_remote_write_disabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  min_sharding_lookback: 0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  split_queries_by_interval: 10m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_line_size: 30mb<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_line_size_truncate: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_streams_per_user: 0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" /><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## memberlist_conig模块配置gossip用于在分发服务器、摄取器和查询器之间发现和连接。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## 所有三个组件的配置都是唯一的,以确保单个共享环。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />## 至少定义了1个join_members配置后,将自动为分发服务器、摄取器和ring 配置memberlist类型的kvstore<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />memberlist:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  randomize_node_name: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  stream_timeout: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retransmit_factor: 4<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  join_members:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  - 'loki-memberlist'<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  abort_if_cluster_join_fails: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  advertise_addr: 0.0.0.0<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  advertise_port: 7946<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  bind_addr: ["0.0.0.0"]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  bind_port: 7946<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  compression_enabled: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  dead_node_reclaim_time: 30s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  gossip_interval: 100ms<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  gossip_nodes: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  gossip_to_dead_nodes_time: 3<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## join:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  leave_timeout: 15s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  left_ingesters_timeout: 3m0s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_join_backoff: 1m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  max_join_retries: 5<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  message_history_buffer_bytes: 4096<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  min_join_backoff: 2s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  ## node_name: miyamoto<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  packet_dial_timeout: 5s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  packet_write_timeout: 5s <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  pull_push_interval: 100ms<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  rejoin_interval: 10s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  tls_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  tls_insecure_skip_verify: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />schema_config:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  configs:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  - from: "2020-10-24"<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    index:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      period: 24h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      prefix: index_<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    object_store: filesystem<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    schema: v11<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    store: boltdb-shipper<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    chunks:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />      period: 168h<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    row_shards: 32<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />table_manager:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_deletes_enabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  retention_period: 0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  throughput_updates_disabled: false<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  poll_interval: 3m0s<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  creation_grace_period: 20m<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />  index_tables_provisioning:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    provisioned_write_throughput: 1000<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    provisioned_read_throughput: 500<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_write_throughput: 4<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_read_throughput: 300<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_write_scale_lastn: 50 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_inactive_throughput_on_demand_mode: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    enable_ondemand_throughput_mode: true<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    inactive_read_scale_lastn: 10 <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />   

分享:可能吧的文章是如何排版的?

采集交流优采云 发表了文章 • 0 个评论 • 55 次浏览 • 2022-10-31 15:49 • 来自相关话题

  分享:可能吧的文章是如何排版的?
  Achan Jason Ng
  阅读这篇文章
  大约
  6 分钟
  我发现不管我写了哪篇文章文章,读者总是会在评论区问我用什么编辑器来排版我的文章,我的回答是,市面上的微信排版器我两者都不要使用,不是因为它们设计不好,而是因为所有排字机都不符合书写规则。
  这个 文章 会告诉你我的 文章 是如何排版的。
  1
  排版不仅仅是锦上添花
  我在 2006 年开始写博客,我相信内容是核心,排版并不重要。但在阅读了 2008 年有关屏幕阅读体验的一些研究后,我开始关注排版,并开始在我的博客上尝试不同的排版。我不能说我的排版是最好看的,但是在一个小圈子里,它被注意到了。如果你在 Google 上搜索“也许排版”,你会发现很多 文章 人都在研究我当时是如何打字的。
  好的排版不仅赏心悦目,更重要的是,我们可以适当调整排版,使内容的呈现符合用户在屏幕上的阅读习惯。
  我在“可能学院”开设了讲座课程“微信内容运营”。在本课程中,我定义了一个新职位:内容管理员。
  产品经理关注用户需求,根据用户需求开发功能。产品经理不是什么都专精,但是什么都懂一点。内容管理者不再是传统意义上的记者或编辑,而是专注于内容生产管道之上的角色。他们根据读者的需求制作内容。他们似乎对所有事情都不专业,但他们对所有事情都了解一点。
  注意上面提到的“生产”二字。在关注读者需求的时代,内容不是单纯的写作,而是“生产”。在“制作”的过程中,阅读体验和阅读习惯是内容管理者必须关心的环节。它们不是锦上添花,而是整个内容生产线中不可或缺的一部分。
  2
  写作规则是什么?
  我的文章一般比较长,比如""有8000多个字符,""有6000多个字符。这些文章都是一口气写完的,前者我写了5个小时左右,后者4个小时。
  但是,写作的时间并不是主要的,主要的时间都花在了材料的采集上。比如写这篇文章文章之前,我既阅读了微信公众平台的API文档,也阅读了Google PWA文档,在谷歌采集了很多资料,最后才开始写。
  把所有的材料采集起来放在脑海里后,我开始闭关写作。
  写作是一口气完成的。
  意思是我采集了足够的材料,把自己放在别人不能打扰的空间里,比如家,比如咖啡店,比如酒店,从第一个字到最后一个字,放文章完毕。
  我尝试写了太多次文章,但我并不满意,因为它使文章 在情感上不连贯。比如今天觉得支付宝脑子进了屎,就写了半篇文章,第二天可能觉得还行,他们就下水了。这样一来,文章前后的情绪就会不一致。这样的 文章 会让读者感到困惑。
  所以,我习惯性地一口气写一个文章。相信大部分作家也有这样的习惯。
  3
  为什么我不用微信排版?
  微信公众平台的编辑功能确实很弱,使用其默认功能很难做出优秀的排版。所以很多公司都开发了微信排字机。
  几乎所有的微信排版机,页面结构类似于下面的排版机:
  用户选择左侧的内容类型,然后选择样式,编辑器中会出现收录该样式的卡片,然后用户将在卡片中填充内容。
  我不使用任何排版机的原因包括:
  容易撞衫:你使用的款式也会被其他公众号使用,没有什么特别之处。
  
  不够精致:大部分排字机的样式,从颜色的使用、行距、字体大小等,都没有特别精心设计。
  不遵守写作规则
  第3点是重点。
  写作是一个一站式的过程,但大多数微信排版人人为地拆分了一站式过程。本来,你写完字幕,就应该马上把内容打出来,但是在这些排字机里,你需要先选择一个模板,然后在模板里填写内容。你必须打断你的写作,把你的手从键盘移到鼠标上,然后再移回来。
  对我来说,体验很糟糕。
  有人可能会说,你可以先写在平板上,然后在排版器中逐个部分粘贴,这样就可以一口气写完,然后“专心”排版?
  想想看,《不要开发应用程序》的文章文章文章有8000字,10到20个二级标题和三级标题,我需要多少努力才能完成排版?
  对我来说,体验仍然很糟糕。
  4
  文章 怎么可能是排版的?
  昨天,一个可能性学院的学生问我每次写文章都花多少时间排版。我的回答是,快时 1 秒,但一般是 10-20 秒。
  这就是我写作和排版的方式。
  4.1
  开始在安静的编辑器中输入
  在 Mac 和 iPhone 上,我都买了 Ulysses,我认为它是最好的书写工具,因为它足够安静:
  如上图所示,我经常全屏写,文章 一口气写完。
  4.2
  使用降价
  Markdown 是专为作家设计的排版语言。它不是一种编程语言。学习 Markdown 通常只需要 5-10 分钟。
  使用 Markdown 的好处是,当您需要输入文本时,您无需将手从键盘上移开。比如需要写二级标题,在正文前面加两个#号,三级标题后面加三个#号。要使文本变为粗体,请在文本的两侧添加两个星号。
  就像上图一样简单。
  你可以在 Google 上轻松找到各种 Markdown 教程,相信我,只需 5-10 分钟即可学会。
  4.3
  书写文章的一键排版
  使用 Markdown 和 Ulysses 编写的好处是完成后的 文章 可以直接输出为 HTML 格式。所以我写了一个脚本,用我的排版样式批量替换 HTML 中的标签。整个过程在1秒内完成。
  例如,我会把段落标记
  批量替换为字体大小为 15px、字距为 1px、行距为 28px 的文本。
  再举个例子,我自己定义了标记,批量替换时,这个标题会被替换为文章顶部的阅读时间块。
  对我来说,写作必须一口气完成,排版不能打断写作。在流水线上,排版是在写作之后。
  4.4
  将排版文章粘贴到微信编辑器中
  
  一键替换后,文章仍然是HTML格式。如果在浏览器中打开,全选复制粘贴到微信编辑器中,可能会出现样式混乱。
  我的做法是复制HTML文件的源码,将源码粘贴到​​在线CKEditor编辑器中,然后复制到微信编辑器中,这样样式就不会乱了。
  5
  问题是,如何一键排版?
  没做过个人主页或者没有技术背景的人看之前的排版流程,可能会有些迷茫。其实不难,我不是技术出身,也不是设计师出身,所有的设计排版代码都是通过google学习和尝试的。
  如果你根本不懂 HTML 和 CSS,你有两种选择:
  5.1
  选一个
  这是最好的选择。
  从公司找一位设计师为您设计一种或多种排版样式。
  找公司的前端工程师帮你把这些设计好的样式写成HTML和CSS。需要注意的是,微信并不支持所有的 CSS 代码。
  还在找这个前端工程师,让他帮你写个脚本,批量替换纯HTML为排版样式。‍
  5.2
  选项二
  这是我的路径,你可以参考一下。
  花半天时间学习 HTML 标记。
  花 2 天时间学习常见的 CSS 标签。
  在公众号后台写一篇文章文章,发给自己预览,在电脑上用Chrome打开。
  打开 Chrome 的开发者工具,找到你要调整的元素,写下你学过的 CSS 标记,调整到你觉得好看为止。
  记下要替换的样式 H2、H3、P 和其他标签。
  花 1 天时间学习如何编写一个收录替换函数的简单 Python 脚本。
  将要替换的元素写入此 Python 脚本。
  一键排版。
  不要被这 8 个“复杂”的步骤吓倒。在电脑上调试样式时,浏览器不会崩溃或死机。关键是多尝试,用谷歌查找学习资料和解决方案。
  6
  不要依赖模板化的教程
  以上是我的布局方法。
  我不会在这个文章中,也不会在以后的文章中告诉你,应该取多少字号,用什么颜色,行距应该多高。
  其实网上很容易找到各种(微信)排版教程,告诉你应该使用16px的字体大小,#888的字体颜色,1.2 rem的行距等。
  不要把这些教程当作铁律。如果有人告诉你 16px 字号最适合微信排版,请不要相信。所有基于模板的教程都是教学示例。好在你按照这些例子,会得到很多启发,但是不要照搬,因为不同的公众号,不同的内容类型对排版的要求是不一样的。的。
  关键是要多尝试。谷歌是我们尝试一切的好帮手。还有,不管你怎么试,电脑都不会坏,你还怕什么?
  顺便说一句,关于“不要开发应用程序”的话题,我们邀请了在微信公众号中做得很好的Yoli,与可能性学院分享。点击阅读原文报名本次分享。
  干货内容:公众号原创文章效果放大10倍的秘诀,茅塞顿开!(马上实操)
  这些爆文也很容易找到,这些平台都会展示出来。排名靠前的 文章 都是具有 100,000 个读数的 爆文。如果您正在寻找一个类别,请选择相应的类别。比如你是年轻女性,时尚娱乐八卦文章都可以选择。
  找到文章后,把爆文的标题复制到搜狗微信搜索中搜索,就可以找到所有发布过这个文章的公众号,而这些号也是你的目标,它们是都有这个需要。
  按照上面的方法,找到大量的账目,做个表格做汇总。然后进行第二步。
  2 账户初步筛选
  在找到大量目标账户并制作表格后,需要进行初步筛选,以免磨刀时误伤木工。这一步是必要的。
  我们需要找到一些属性真正匹配、阅读量不错、质量相对较高的账号。关键是他们确实经常转载​​文章。
  可以使用微信、新帮、西瓜助手、青博等分析工具查看他们的历史文章阅读量,并对公众号文章的发布情况做一个简单的观察,看看是否有转载足够大。
  然后移除一些不符合标准的公众号,留下确定为主动授权的公众号。
  3 批量开启白名单
  经过简单的筛选,他们开始主动将这些公众号加入白名单。
  前期需要一个个添加公众号给他们授权文章,但是授权一次后,可以直接全选,一键批量授权。
  一次100,一次100,直接一天500,真的是授权狂人。
  
  在这个阶段,还需要注意的是所有的操作也需要同步表,哪些号码被授权,什么时候被授权,都需要收录在表中。
  4 统计
  定期统计这些主动授权的公众号是否转载了你的文章,一定要做好统计,否则会失明。
  您可以在公众号原创文章的管理中查看转载详情,统计文章对应的公众号有哪些转载。如下:
  这是必须要做的,没有统计数据就无法进行下一步的优化。我们要的不是数据,而是数据背后的结果。
  5 用操作思维优化筛选
  我们需要用操作的思维来做这件事,包括上一步的每一步的表统计,以便更好的放大授权效果。
  仅对已找到的目标账户进行直接授权是不够的。我们需要在后期继续优化和过滤。例如:
  哪些账户运作良好,哪些账户运作不佳;
  一周中的什么时间最适合全天授权;
  一天之内,授权在什么时候总体上运作良好;
  这些必须有意识地进行测试,在一周的不同时间刻意授权,在一天中的不同时间刻意授权,看看效果如何变化。
  统计所有运营数据,然后通过对比分析,找到最佳授权时间,找到最佳授权类型,筛选出效果最好的公众号,删除几乎没用的账号。补新一批号,以此类推,不断放大授权效果。
  这里还有一点,我们在操作公众号的时候一定要有数据思维,不需要很复杂的分析,但是一定要知道你操作前后关键指标有没有变化,否则我们会盲目操作,走运。
  
  另外,对于效果特别好的目标账号,还可以拉群或者加编辑到微信中,进行长线推送。
  总的来说,就是不断优化,循环运行。
  以上就是变身狂魔的正确姿势。
  有一瞬间,我犹豫要不要和你分享。
  但我很快就清醒过来了,当然我必须把它写出来,因为我知道我没有分享它,这不是我的风格,也不是我一直在谈论的想法。
  反正只要你想看,我感觉我还是可以写的。
  想起老罗在发布会上说的一句话:感觉自己的精神状态还是可以用一百年来形容的。
  我没有那么大的感觉。
  只要,
  一点点触动。
  木木老贼(公众号:mumuseo)
  这是一个无所不谈的营销运营公众号,新鲜有趣,信息量大。多一些真诚,少一些套路,给在理想道路上努力奋斗的营销人员更多的燃料。 查看全部

  分享:可能吧的文章是如何排版的?
  Achan Jason Ng
  阅读这篇文章
  大约
  6 分钟
  我发现不管我写了哪篇文章文章,读者总是会在评论区问我用什么编辑器来排版我的文章,我的回答是,市面上的微信排版器我两者都不要使用,不是因为它们设计不好,而是因为所有排字机都不符合书写规则。
  这个 文章 会告诉你我的 文章 是如何排版的。
  1
  排版不仅仅是锦上添花
  我在 2006 年开始写博客,我相信内容是核心,排版并不重要。但在阅读了 2008 年有关屏幕阅读体验的一些研究后,我开始关注排版,并开始在我的博客上尝试不同的排版。我不能说我的排版是最好看的,但是在一个小圈子里,它被注意到了。如果你在 Google 上搜索“也许排版”,你会发现很多 文章 人都在研究我当时是如何打字的。
  好的排版不仅赏心悦目,更重要的是,我们可以适当调整排版,使内容的呈现符合用户在屏幕上的阅读习惯。
  我在“可能学院”开设了讲座课程“微信内容运营”。在本课程中,我定义了一个新职位:内容管理员。
  产品经理关注用户需求,根据用户需求开发功能。产品经理不是什么都专精,但是什么都懂一点。内容管理者不再是传统意义上的记者或编辑,而是专注于内容生产管道之上的角色。他们根据读者的需求制作内容。他们似乎对所有事情都不专业,但他们对所有事情都了解一点。
  注意上面提到的“生产”二字。在关注读者需求的时代,内容不是单纯的写作,而是“生产”。在“制作”的过程中,阅读体验和阅读习惯是内容管理者必须关心的环节。它们不是锦上添花,而是整个内容生产线中不可或缺的一部分。
  2
  写作规则是什么?
  我的文章一般比较长,比如""有8000多个字符,""有6000多个字符。这些文章都是一口气写完的,前者我写了5个小时左右,后者4个小时。
  但是,写作的时间并不是主要的,主要的时间都花在了材料的采集上。比如写这篇文章文章之前,我既阅读了微信公众平台的API文档,也阅读了Google PWA文档,在谷歌采集了很多资料,最后才开始写。
  把所有的材料采集起来放在脑海里后,我开始闭关写作。
  写作是一口气完成的。
  意思是我采集了足够的材料,把自己放在别人不能打扰的空间里,比如家,比如咖啡店,比如酒店,从第一个字到最后一个字,放文章完毕。
  我尝试写了太多次文章,但我并不满意,因为它使文章 在情感上不连贯。比如今天觉得支付宝脑子进了屎,就写了半篇文章,第二天可能觉得还行,他们就下水了。这样一来,文章前后的情绪就会不一致。这样的 文章 会让读者感到困惑。
  所以,我习惯性地一口气写一个文章。相信大部分作家也有这样的习惯。
  3
  为什么我不用微信排版?
  微信公众平台的编辑功能确实很弱,使用其默认功能很难做出优秀的排版。所以很多公司都开发了微信排字机。
  几乎所有的微信排版机,页面结构类似于下面的排版机:
  用户选择左侧的内容类型,然后选择样式,编辑器中会出现收录该样式的卡片,然后用户将在卡片中填充内容。
  我不使用任何排版机的原因包括:
  容易撞衫:你使用的款式也会被其他公众号使用,没有什么特别之处。
  
  不够精致:大部分排字机的样式,从颜色的使用、行距、字体大小等,都没有特别精心设计。
  不遵守写作规则
  第3点是重点。
  写作是一个一站式的过程,但大多数微信排版人人为地拆分了一站式过程。本来,你写完字幕,就应该马上把内容打出来,但是在这些排字机里,你需要先选择一个模板,然后在模板里填写内容。你必须打断你的写作,把你的手从键盘移到鼠标上,然后再移回来。
  对我来说,体验很糟糕。
  有人可能会说,你可以先写在平板上,然后在排版器中逐个部分粘贴,这样就可以一口气写完,然后“专心”排版?
  想想看,《不要开发应用程序》的文章文章文章有8000字,10到20个二级标题和三级标题,我需要多少努力才能完成排版?
  对我来说,体验仍然很糟糕。
  4
  文章 怎么可能是排版的?
  昨天,一个可能性学院的学生问我每次写文章都花多少时间排版。我的回答是,快时 1 秒,但一般是 10-20 秒。
  这就是我写作和排版的方式。
  4.1
  开始在安静的编辑器中输入
  在 Mac 和 iPhone 上,我都买了 Ulysses,我认为它是最好的书写工具,因为它足够安静:
  如上图所示,我经常全屏写,文章 一口气写完。
  4.2
  使用降价
  Markdown 是专为作家设计的排版语言。它不是一种编程语言。学习 Markdown 通常只需要 5-10 分钟。
  使用 Markdown 的好处是,当您需要输入文本时,您无需将手从键盘上移开。比如需要写二级标题,在正文前面加两个#号,三级标题后面加三个#号。要使文本变为粗体,请在文本的两侧添加两个星号。
  就像上图一样简单。
  你可以在 Google 上轻松找到各种 Markdown 教程,相信我,只需 5-10 分钟即可学会。
  4.3
  书写文章的一键排版
  使用 Markdown 和 Ulysses 编写的好处是完成后的 文章 可以直接输出为 HTML 格式。所以我写了一个脚本,用我的排版样式批量替换 HTML 中的标签。整个过程在1秒内完成。
  例如,我会把段落标记
  批量替换为字体大小为 15px、字距为 1px、行距为 28px 的文本。
  再举个例子,我自己定义了标记,批量替换时,这个标题会被替换为文章顶部的阅读时间块。
  对我来说,写作必须一口气完成,排版不能打断写作。在流水线上,排版是在写作之后。
  4.4
  将排版文章粘贴到微信编辑器中
  
  一键替换后,文章仍然是HTML格式。如果在浏览器中打开,全选复制粘贴到微信编辑器中,可能会出现样式混乱。
  我的做法是复制HTML文件的源码,将源码粘贴到​​在线CKEditor编辑器中,然后复制到微信编辑器中,这样样式就不会乱了。
  5
  问题是,如何一键排版?
  没做过个人主页或者没有技术背景的人看之前的排版流程,可能会有些迷茫。其实不难,我不是技术出身,也不是设计师出身,所有的设计排版代码都是通过google学习和尝试的。
  如果你根本不懂 HTML 和 CSS,你有两种选择:
  5.1
  选一个
  这是最好的选择。
  从公司找一位设计师为您设计一种或多种排版样式。
  找公司的前端工程师帮你把这些设计好的样式写成HTML和CSS。需要注意的是,微信并不支持所有的 CSS 代码。
  还在找这个前端工程师,让他帮你写个脚本,批量替换纯HTML为排版样式。‍
  5.2
  选项二
  这是我的路径,你可以参考一下。
  花半天时间学习 HTML 标记。
  花 2 天时间学习常见的 CSS 标签。
  在公众号后台写一篇文章文章,发给自己预览,在电脑上用Chrome打开。
  打开 Chrome 的开发者工具,找到你要调整的元素,写下你学过的 CSS 标记,调整到你觉得好看为止。
  记下要替换的样式 H2、H3、P 和其他标签。
  花 1 天时间学习如何编写一个收录替换函数的简单 Python 脚本。
  将要替换的元素写入此 Python 脚本。
  一键排版。
  不要被这 8 个“复杂”的步骤吓倒。在电脑上调试样式时,浏览器不会崩溃或死机。关键是多尝试,用谷歌查找学习资料和解决方案。
  6
  不要依赖模板化的教程
  以上是我的布局方法。
  我不会在这个文章中,也不会在以后的文章中告诉你,应该取多少字号,用什么颜色,行距应该多高。
  其实网上很容易找到各种(微信)排版教程,告诉你应该使用16px的字体大小,#888的字体颜色,1.2 rem的行距等。
  不要把这些教程当作铁律。如果有人告诉你 16px 字号最适合微信排版,请不要相信。所有基于模板的教程都是教学示例。好在你按照这些例子,会得到很多启发,但是不要照搬,因为不同的公众号,不同的内容类型对排版的要求是不一样的。的。
  关键是要多尝试。谷歌是我们尝试一切的好帮手。还有,不管你怎么试,电脑都不会坏,你还怕什么?
  顺便说一句,关于“不要开发应用程序”的话题,我们邀请了在微信公众号中做得很好的Yoli,与可能性学院分享。点击阅读原文报名本次分享。
  干货内容:公众号原创文章效果放大10倍的秘诀,茅塞顿开!(马上实操)
  这些爆文也很容易找到,这些平台都会展示出来。排名靠前的 文章 都是具有 100,000 个读数的 爆文。如果您正在寻找一个类别,请选择相应的类别。比如你是年轻女性,时尚娱乐八卦文章都可以选择。
  找到文章后,把爆文的标题复制到搜狗微信搜索中搜索,就可以找到所有发布过这个文章的公众号,而这些号也是你的目标,它们是都有这个需要。
  按照上面的方法,找到大量的账目,做个表格做汇总。然后进行第二步。
  2 账户初步筛选
  在找到大量目标账户并制作表格后,需要进行初步筛选,以免磨刀时误伤木工。这一步是必要的。
  我们需要找到一些属性真正匹配、阅读量不错、质量相对较高的账号。关键是他们确实经常转载​​文章。
  可以使用微信、新帮、西瓜助手、青博等分析工具查看他们的历史文章阅读量,并对公众号文章的发布情况做一个简单的观察,看看是否有转载足够大。
  然后移除一些不符合标准的公众号,留下确定为主动授权的公众号。
  3 批量开启白名单
  经过简单的筛选,他们开始主动将这些公众号加入白名单。
  前期需要一个个添加公众号给他们授权文章,但是授权一次后,可以直接全选,一键批量授权。
  一次100,一次100,直接一天500,真的是授权狂人。
  
  在这个阶段,还需要注意的是所有的操作也需要同步表,哪些号码被授权,什么时候被授权,都需要收录在表中。
  4 统计
  定期统计这些主动授权的公众号是否转载了你的文章,一定要做好统计,否则会失明。
  您可以在公众号原创文章的管理中查看转载详情,统计文章对应的公众号有哪些转载。如下:
  这是必须要做的,没有统计数据就无法进行下一步的优化。我们要的不是数据,而是数据背后的结果。
  5 用操作思维优化筛选
  我们需要用操作的思维来做这件事,包括上一步的每一步的表统计,以便更好的放大授权效果。
  仅对已找到的目标账户进行直接授权是不够的。我们需要在后期继续优化和过滤。例如:
  哪些账户运作良好,哪些账户运作不佳;
  一周中的什么时间最适合全天授权;
  一天之内,授权在什么时候总体上运作良好;
  这些必须有意识地进行测试,在一周的不同时间刻意授权,在一天中的不同时间刻意授权,看看效果如何变化。
  统计所有运营数据,然后通过对比分析,找到最佳授权时间,找到最佳授权类型,筛选出效果最好的公众号,删除几乎没用的账号。补新一批号,以此类推,不断放大授权效果。
  这里还有一点,我们在操作公众号的时候一定要有数据思维,不需要很复杂的分析,但是一定要知道你操作前后关键指标有没有变化,否则我们会盲目操作,走运。
  
  另外,对于效果特别好的目标账号,还可以拉群或者加编辑到微信中,进行长线推送。
  总的来说,就是不断优化,循环运行。
  以上就是变身狂魔的正确姿势。
  有一瞬间,我犹豫要不要和你分享。
  但我很快就清醒过来了,当然我必须把它写出来,因为我知道我没有分享它,这不是我的风格,也不是我一直在谈论的想法。
  反正只要你想看,我感觉我还是可以写的。
  想起老罗在发布会上说的一句话:感觉自己的精神状态还是可以用一百年来形容的。
  我没有那么大的感觉。
  只要,
  一点点触动。
  木木老贼(公众号:mumuseo)
  这是一个无所不谈的营销运营公众号,新鲜有趣,信息量大。多一些真诚,少一些套路,给在理想道路上努力奋斗的营销人员更多的燃料。

经验:我所读过的最好的一篇分布式技术文章

采集交流优采云 发表了文章 • 0 个评论 • 63 次浏览 • 2022-10-31 15:48 • 来自相关话题

  经验:我所读过的最好的一篇分布式技术文章
  (点击上方公众号快速关注)。
  资料来源:foreach_break,
  前言
  这是一份学习笔记。
  该材料来自Jay Kreps关于Log的博客文章。
  原文很长,但我坚持阅读,收获颇丰,对 Jay 的技术能力、架构能力和对分布式系统的深刻理解印象深刻。同时,他有点沾沾自喜,因为他的一些理解与周杰伦的观点相吻合。
  Jay Kreps是LinkedIn的前首席参谋工程师,现在是Confluent的联合创始人兼首席执行官,也是Kafka和Samza的主要作者。
  所谓笔记,就是读文章做笔记,因为周杰伦哥自己在这一章里组织得太好了,他自己的科学素养和哲学素养也很高,所以他认为突出的也不会省略。
  一、来源
  日志:每个软件工程师都应该知道的关于实时数据的统一抽象()
  二、注意事项
  2.1 日志的值
  1)日志是以下系统的核心:
  2)日志可能与计算机一样古老,是分布式数据系统和实时计算系统的核心。
  3)日志有很多名称:
  4)不了解日志就无法完全理解日志
  2.2 什么是日志?
  2.2.1 概述
  记录的顺序定义了这样一个概念:时间。
  因为离记录越远,记录得越早。
  的概念
  条目的序列号可以用作时间戳,记录顺序作为时间的概念可能看起来很奇怪,但您很快就会发现,将“时间”与任何特定的物理时钟分离很容易。
  日志与普通文件和表没有太大区别。
  这样,你可能会觉得日志这么简单,还有需要讨论的吗?
  其实日志的核心含义是:
  日志记录发生了什么以及何时发生。
  而这个通常是分布式系统最核心的东西。
  请注意,这里有必要澄清几个概念:
  2.2.2 数据库中的日志
  Log的起源未知,就像发明二进制搜索的人一样,很难意识到这项发明是一项发明。
  日志记录早在IBM的System R中就出现了。
  在数据库中,您需要在数据库崩溃时保持不同的数据结构和索引同步。
  为了确保原子性和持久性,数据库需要在提交对数据结构和索引的更改之前记录要修改的内容。
  因此,日志记录了何时发生的情况,每个表和索引本身就是此历史信息的映射。
  由于日志会立即持久化,因此它们成为在发生崩溃时还原其他持久性结构的可靠来源。
  日志已从 ACID 特征的实现演变为数据库之间的数据复制方式。
  显然,数据库中发生的一系列数据更改成为保持数据库之间同步的最需要的信息。
  Oracle,MySQL和PostgreSQL都收录一个日志传输协议,该协议将日志的一部分发送到用于维护复制的从属数据库。
  Oracle的XStreams和GoldenState使用日志作为通用数据订阅机制来提供非Oracle数据库订阅数据。
  MySQL和PostgreSQL提供了类似的组件,这些组件是数据系统架构的核心。
  面向机器的日志不仅可以用于数据库,还可以用于:
  2.2.3 分布式系统中的日志
  日志解决了分布式数据系统中的两个重要问题:
  1) 有序数据更改
  2) 数据分发
  所谓的状态机复制原理
  如果两个确定性过程(以相同的状态和相同的顺序开始)接收相同的输入,则它们将产生相同的输出并以相同的状态结束。
  这
  所谓确定性是指处理过程与时间无关,其处理结果不受额外输入的影响。
  可以通过非确定性示例来理解:
  所谓状态可以是机器上的任何数据,无论是在机器的内存中还是经过处理后的磁盘上。值得注意的是,相同的
  输入以相同的顺序产生相同的结果,这就是为什么日志如此重要的原因,这是一个直观的概念:如果你将相同的日志输入两个确定性程序,它们将产生相同的输出。
  在分布式系统的构建中,意识到这一点可以:
  让所有机器都做同样的事情,协议是:
  构建分布式、一致的日志系统,为所有处理系统提供输入。
  日志系统的作用是消除所有输入流的不确定性,并确保处理相同输入的所有复制节点保持同步。
  此方法的最佳部分是,您可以将索引日志的时间戳视为所有复制节点的时钟:通过使用复制节点处理的日志
  中最大的时间戳作为复制节点的唯一 ID,时间戳与日志相结合可以唯一地表示该节点的整个状态。
  应用此方法的方法也有很多:
  从理论上讲,我们可以记录一系列机器指令,或者被调用方法的名称和参数,只要数据处理过程的行为相同,这些过程就可以保证节点之间的一致性。
  经常玩数据库的人会以不同的方式处理逻辑日志和物理日志:
  对于分布式系统,通常有两种方法来处理复制和数据处理:
  1) 状态机模型(主动 – 主动)
  2) 主回模型(主动 – 被动)
  如下图所示:
  为了理解上述两种方式之间的区别,让我们看一个简单的例子:
  现在,集群需要提供一个简单的服务来执行算术运算,例如加法和乘法。最初,维护一个数字,例如 0。
  上面的例子还揭示了为什么顺序是复制节点之间一致性的关键因素,如果这些操作的顺序被打乱,将获得不同的结果。
  分布式日志,可以作为某些一致性算法的数据结构:
  表示有关下一个值的一系列决策的日志。
  2.2.4 更新日志
  从数据库的角度来看,记录数据更改的一组更改日志和表是双重且可互操作的。
  1)根据记录数据变化的日志,可以重构处于某种状态的表(也可以是非关系存储系统中带有键的记录)。
  2)相反,如果表发生变化,则可以在日志中计算更改。
  这正是您想要近乎实时复制的地方!
  这与版本控制的作用非常相似:管理分布式、并发和状态修改。
  版本控制工具维护反映更改的修补程序,该修补程序实际上是一个日志,并且您与分支的签出快照进行交互,该快照等效于数据库中的表。您会发现,在版本控制和分布式系统中,复制都是基于日志的:更新版本时,只需提取反映版本更改的修补程序并将其应用于当前分支快照。
  2.3 数据集成
  2.3.1 数据集成的含义
  数据集成是来自组织中所有服务和系统的数据。
  事实上,数据的有效利用非常符合马斯洛的层次需求理论。
  在金字塔的底部,数据被采集并集成到应用程序中(无论是实时计算引擎、文本文件还是 Python 脚本)。
  这些数据需要转换,以保持易于阅读和处理的统一、标准化和干净的格式。
  当满足上述要求时,就可以开始考虑各种数据处理方法,如map-reduce或实时查询系统。
  显然,如果没有可靠、完整的数据流,Hadoop 只是一个昂贵的、难以集成的加热器(集群是否昂贵?)。
  相反,如果可以确保数据流可靠、可用且完整,则可以考虑更高级的游戏玩法、更好的数据模型以及一致、更易于理解的语义。
  然后,重点可以转移到可视化、报告、算法和预测(挖掘深度)。
  2.3.2 数据集成的两种复杂性
  事件事件
  数据记录事件是如何发生的,而不仅仅是发生了什么,通常被视为应用程序日志,因为它通常由应用程序系统写入。但这实际上混淆了日志的功能。
  事实上,谷歌的财富是由建立在(用户)点击流和好恶(体验)上的关联管道产生的,点击流和展示是事件。
  各类专业数据系统的爆炸式增长
  这些系统存在的原因:
  显然,将数据集成到这样的系统中是极其困难的。
  2.3.3 基于日志结构的数据流
  每个逻辑数据源都可以根据日志进行建模。
  数据源可以是记录事件(命中和 PV)的应用程序,也可以是接受更改的数据库表。
  每个订阅服务器都会尽快从这些数据源生成的日志中获取新记录,将其应用于本地存储系统,并增加其在日志中的读取偏移量。订阅者可以是任何数据系统,例如缓存、Hadoop、另一个站点的数据库或搜索引擎。
  登录
  事实上,提供了一个逻辑时钟,可以测量不同订阅者响应数据变化的状态,因为这些订阅者在日志中具有不同且独立的读取偏移量,这就像时间意义上的“时刻”。
  
  考虑这样一个示例、数据库和一些缓存服务器:
  日志提供了同步所有缓存服务器并推送其“时刻”的能力。
  假设我们写了一个数字为 X 的日志,想要从缓存服务器读取数据,为了不读取旧数据,我们只需要确保在缓存服务器将数据(同步)复制到 X 位置之前,我们不会从这个缓存中读取任何内容。
  此外,log 还提供了充当缓冲区的功能,以异步方式支持生产者和使用者行为。
  支持异步的最关键原因之一是订阅系统可能会崩溃,脱机进行维护,然后重新联机,在这种情况下,每个订阅者都按照自己的节奏使用数据。
  批处理系统(如 Hadoop 或数据仓库)使用数据
  以小时或数天为单位,而实时系统通常在几秒钟内消耗数据。
  数据源或日志不知道使用数据的订阅者的任何信息,因此有必要在管道中无缝添加订阅者和删除订阅者。
  更重要的是,订阅者只需要知道日志,而不是他们使用的数据源,无论该数据源是RDBMS,Hadoop还是新流行的K-V数据库等。之所以说日志,而不是消息系统,是因为不同的消息系统
  保证了不同的特性,而使用word消息系统,很难全面准确地表达某种语义,因为消息系统更重要的重定向消息。
  但是,日志可以理解为提供持久性保证和强序语义的消息系统,这在通信系统中称为原子广播。
  2.4 LinkedIn
  LinkedIn目前的主要系统包括(注:2013年):
  每个系统在其专业领域都提供专门的高级功能。
  (这一段太长太长了,周杰伦哥很有口才,所以挑重点记住!
  1)引入数据流的概念,是因为需要在Oracle数据库的表之上建立一个抽象的缓存层,为搜索引擎索引构建和社交图谱更新提供扩展能力。
  2)为了更好的处理LinkedIn的一些推荐算法,我们开始构建Hadoop集群,但团队在这方面的经验还很浅,所以走了不少弯路。
  3)一开始,这只是一个粗略的想法,只是将数据从Oracle数据仓库中提取出来并将其扔到Hadoop中就可以了。首先,从 Oracle 数据仓库快速导出数据是一场噩梦;其次,也是更糟糕的是,数据仓库中的一些数据没有得到正确处理,导致Hadoop批处理任务无法按预期产生结果,并且通过Hadoop批处理执行任务通常是不可逆的,尤其是在报告发布之后。
  4)最后,团队放弃了将数据从数据仓库中提取出来的方式,直接进入数据库和日志作为数据源。然后建造了一个轮子:K-V 存储(伏地魔)。
  5)即使是数据复制这样的小任务,也会占用团队大量的时间来处理它,更糟糕的是,一旦数据处理管道中出现了一个点,Hadoop立即变得浪费,因为无论算法在错误的数据上运行多么出色,只有一个后果,那就是生成更多错误的数据。
  6)即使团队构建了一些具有高度抽象的东西,它也需要为每个数据源进行特定的配置,这是许多错误和失败的根源。7)大量的程序员想要
  跟进,每个程序员都有大量的想法,集成这个系统,添加这个功能,集成这个功能,或者想要自定义数据源。
  8)周杰伦弟兄开始意识到:
  首先,他们建造的管道仍然粗糙,但非常有价值。即使解决数据在Hadoop等新系统中可用的问题,也可以解锁大量可能性。以前困难的计算开始成为可能。只需从其他系统解锁数据并集成它们,即可轻松制作新产品和分析。其次,很明显,可靠的数据加载
  需要更坚实的支持,如果可以捕获所有结构,Hadoop数据加载就可以完全自动化,而无需添加新数据源或手动修改数据模式。数据神奇地出现在 HDFS 中,当添加新数据源时,Hive 的表会自动生成,并使用适当的列自适应地生成。
  第三,数据覆盖面远远不够。因为很难处理很多新的数据源。
  9)为了解决新数据源加入后的数据加载问题,团队开始了这样的尝试:
  很快,他们发现这行不通,因为发布和订阅,生产和消费,数据流通常仍然是双向的,这变成了O(n^2)问题。
  所以,他们需要的是这样的模型:
  每个使用者都需要与数据源隔离,理想情况下只与一个数据存储库进行交互,该存储库为他们提供对任意数据的访问权限。
  10)消息系统+日志=卡夫卡,卡夫卡诞生了。
  2.5 日志ETL与数据仓库的关系
  2.5.1 数据仓库
  1) 一个干净、结构化、集成的数据存储库,用于分析。
  2)虽然这个想法很棒,但获取数据的方式有点过时了:定期从数据库中获取数据并将其转换为更易读的格式。
  3)以前的数据仓库问题是干净数据和数据仓库的高度耦合。
  数据仓库应该是查询功能的集合,服务于上报、搜索、AD热分析,包括计数、聚合、过滤等操作,所以应该是批处理系统。
  但是干净数据和这样的批处理系统的高度耦合意味着这些数据不能被实时系统消费,例如搜索引擎索引构建、实时计算和实时监控系统等。
  2.5.2 ETL
  Jay弟兄认为ETL只做两件事:
  1)提取并清理数据以从特定系统中解锁数据
  2)重构数据,以便可以通过数据仓库进行查询。例如,将数据类型更改为关系数据库的类型,将架构转换为星形或雪花模式,或将其分解为面向列的存储格式。
  但是将这两件事结合在一起是一个大问题,因为集成的、干净的数据应该被其他实时系统、索引构建系统和低延迟处理系统使用。
  数据仓库团队是
  负责采集和清理数据,但这些数据的生成者经常输出难以提取和清理的数据,因为他们不清楚数据仓库团队的数据处理需求。
  同时,由于核心业务团队对跟上公司其他部门的步伐不敏感,真正可以处理的数据覆盖率低,数据流脆弱,难以快速响应变化。
  因此,更好的方法是:
  如果要在干净的数据集上做一些搜索、实时监控趋势图和实时告警,不宜使用原创数据仓库或 Hadoop 集群作为基础设施。更糟糕的是,ETL为数据仓库构建了一个数据加载系统,该系统对其他(实时)系统几乎没有用处。最好的模型是在数据发布者发布
  数据之前清理数据,因为只有发布者最了解其数据的外观。在此阶段完成的所有操作都应该是无损和可逆的。
  所有丰富的语义或附加值的实时转换都应在原创日志发布后进行后处理,包括为事件数据建立会话或添加一些感兴趣的字段。原创日志仍然可以单独使用,但此类实时应用程序也会派生新的参数化日志。
  最后,只有与特定目标系统对应的数据聚合操作才应作为数据加载的一部分执行,例如转换为星型或雪花型架构,以便在数据仓库中进行分析和报告。因为这个阶段,就像传统的ETL一样,由于非常干净和规范的数据流,(带有日志)现在非常简单。
  2.6 日志文件和事件
  以日志为中心的架构还有一个额外的好处,即易于实现非耦合的事件驱动系统。
  捕获用户活动和系统更改的传统方法是将此信息写入文本日志,然后将其提取到数据仓库或Hadoop集群中进行聚合和处理,这类似于前面描述的数据仓库和ETL问题:数据与数据仓库高度耦合。
  在LinkedIn,它构建了一个基于kafka的事件数据处理系统。为各种操作定义了数百种事件类型,从 PV、用户广告展示、搜索到服务呼叫和应用程序异常等。
  要了解上述事件驱动系统的好处,请看一个简单的事件示例
  在“职业”页面上,提供机会。此页面应仅负责如何呈现机会,不应收录太多其他逻辑。但是,您会发现,在相当大的网站中执行此操作很容易涉及越来越多的逻辑,而这些逻辑与展示的机会无关。
  例如,我们要集成以下系统功能:
  1)我们需要将数据发送到Hadoop和数据仓库进行离线处理。
  2)我们需要计算页面浏览量,以确保某些视图不是用于抓取Web内容或任何东西。
  3) 我们需要汇总有关此页面的浏览信息,以便在业务机会发布者的分析页面上显示。
  4)我们需要记录一个用户浏览这个页面的历史记录,以确保我们向这个用户提供任何有价值的、有适合这个用户的良好体验的工作机会,而不是一遍又一遍地为这个用户重复一个机会(想想只有老婆不在家的时候才能玩的游戏, 红绿蓝闪烁的特效,配上爆炸性的DJ风格舞曲,或是摇摆专注的事业巅峰和Qi X短裙的女生,再点进去才发现是标题派对的广告!)。
  5)我们的推荐系统需要记录此页面的浏览历史记录,以便正确跟踪此工作机会的受欢迎程度。
  很快,仅显示机会的页面逻辑变得复杂。虽然我们也增加了这个机会在移动设备上的展示,但我们也必须迁移逻辑,这增加了复杂性。还没有,困难的部分是在此页面上工作的工程师需要了解其他系统,以确保上述功能正确集成。
  这只是一个极其简单的例子,在实践中,情况只会更加复杂。
  事件驱动可以使这变得容易。负责展示机会的
  页面只需要展示机会并记录一些与演示相关的因素,例如与工作机会相关的属性、查看页面的人员以及与演示文稿相关的其他有用信息。页面不需要维护其他系统的知识和知识,例如推荐系统、安全系统、机会发布者分析系统和数据仓库,所有这些系统只需要订阅者、订阅事件,然后独立处理它们,而呈现机会的页面不需要在新订阅者或消费者加入时进行修改。
  2.7 构建可扩展日志
  分离发布者和订阅者并不是什么新鲜事,但日志系统很难确保多个订阅者可以实时处理消息,同时确保可扩展性。
  如果日志不是构建
  速度快,开销低,可扩展性强,那么在这个日志系统上构建的所有美妙之处就不多说了。
  许多人可能认为日志系统在分布式系统中是一项缓慢而昂贵的工作,并且仅用于处理 ZooKeeper 更适合的一些信息,例如元数据。
  但是现在LinkedIn(注:2013年)每天在kafka中处理600亿次不同的消息写入(如果算上数据中心镜像,则为数千亿次写入)。
  周杰伦兄弟,他们是怎么做到的?
  1) 对日志进行分区
  2) 通过批量读取和写入优化吞吐量
  3) 避免不必要的数据复制
  通过将日志切片为多个分区来提供可扩展性:
  1)每个分区都是有序日志,但分区之间没有全局顺序。
  2)将消息写入哪个分区完全由编写器控制,通过某种类型的键(例如user_id)对其进行拆分。
  3)分段允许在分片之间不协调的情况下执行额外的日志操作,并确保系统的吞吐量与Kafka集群的大小呈线性相关。
  4)虽然没有提供全局订单(有
  实际上是成千上万的消费者或订阅者,讨论它们的全局顺序通常没有什么价值),Kafka 提供了一个保证,即发送方以什么顺序将消息发送到分区,消息以什么顺序(以什么顺序,以什么顺序)从该分区传递。
  5)每个分区按照配置的编号进行复制,如果一个领导节点挂断,其他节点将成为新的主节点。
  6)一个日志,和文件系统一样,线性读写模式可以优化,小的读写日志可以形成更大的、高吞吐量的操作。卡夫卡正在激烈地做这件事。批处理用于各种场景,例如客户端向服务器发送数据、将数据写入磁盘、服务器之间的数据复制、向消费者传输数据、确认提交数据等。
  7)最后,Kafka对内存日志、磁盘日志和通过网络发送的日志采用了非常简单的二进制格式,以方便使用各种优化技术,例如零拷贝数据传输。
  许多优化技术相结合,允许您以磁盘或网络可以提供的最大容量读取和写入数据,即使内存已满也是如此。
  2.8 日志和实时处理
  你认为周杰伦提供了一种如此漂亮的方法来复制数据并复制它吗?
  你!错!完成!日志是
  流式处理的另一种说法,日志是流处理的核心。
  2.8.1 什么是流处理
  周杰伦哥认为:
  1)流处理是连续数据处理的基础设施。
  2)流处理的计算模型,如MapReduce或其他分布式处理框架,只需要保证低延迟。
  3)批量数据采集模式导致批量数据处理模式。
  4)采集数据的连续模式导致连续的数据处理模式。
  5)杰伊弟兄谈到了美国人口普查局解释批处理的方式。
  在LinkedIn,活动数据和数据库中的变化是连续的。
  
  每天批处理数据,连续计算将窗口设置为一天以重合。
  因此,流处理是一个这样的过程:
  6)在处理数据时,有了时间的概念,不需要维护数据的静态快照,因此可以按照用户定义的频率输出结果,而无需等待数据集达到某个“结束”状态。
  7)从这个意义上说,流处理是批处理的泛化,鉴于实时数据的普及,这是一个极其重要的泛化。
  8)许多商业公司无法构建流处理引擎,通常是因为他们无法构建流数据采集引擎。
  9) 流处理弥合了实时响应服务和离线批处理基础设施之间的差距。
  10)日志系统解决了流处理模式下的许多关键问题,其中最大的问题是如何在实时多订阅者模式下提供可用数据(流数据采集)。
  2.9 数据流图
  关于流处理最有趣的事情是它扩展了源的概念。
  无论是日志、源还是事件,逐行数据记录,都来自应用程序的活动。
  但是,流处理还允许我们处理来自其他源的数据,这些数据与原创数据到使用者没有什么不同,并且这些派生源可以收录任何程度的复杂性。
  流处理任务应如下所示:从日志中读取数据并将输出写入日志或其他系统。
  作为输入和输出日志,将这些进程本身与其他进程连接起来,形成一个图形。
  事实上,以日志为中心的系统允许您将组织中的数据捕获、转换和数据流视为日志和写入它们的处理的组合。
  流处理程序不必很大:它可以是一个进程或一组进程,但它可以提供一些额外的基础结构和支持,以便更轻松地管理用于处理的代码。
  引入日志有两个目的:
  1)确保数据集可以支持多种订阅者模式,并且有序。
  2)可以用作应用程序的缓冲区。这很重要,因为在异步数据处理过程中,如果上游生产者可以更快地生成数据,而使用者无法跟上,在这种情况下,要么处理过程被阻塞,要么引入缓冲区,要么删除数据。
  丢弃数据似乎不是一个好的选择,阻塞处理过程会导致所有数据流的处理图中的处理过程卡住。另一方面,Log 是一个大的、超大的、非常大的缓冲区,它允许重新启动处理进程,以便在进程失败后,它不会影响流处理图中的其他进程。这对于大型组织扩展数据流至关重要,因为不同的团队有不同的处理任务,显然整个流处理过程不会因为一个任务中的错误而卡住。
  Storm 和 Samza 就是这样的流处理引擎,它们都使用 kafka 或其他类似的系统作为它们的日志系统。
  (注:周杰伦哥哥挺凶悍的,卡夫卡在前,萨马扎在后。
  2.10 有状态实时处理
  许多流处理
  引擎是无状态的,一次记录,但许多用例需要在一定大小的特定时间窗口内进行复杂的计数、聚合和联接操作,以进行流处理。
  例如,在点击流中,联接用户信息。
  然后,这种用例需要状态支持。在处理数据时,需要维护一段数据的状态。
  问题是,当处理器可能挂断时,如何保持正确?
  在内存中维护状态可能是最简单的,但它经不起崩溃。
  如果仅在某个时间窗口内保持状态,当发生挂断或故障时,则可以将处理直接重播到窗口的开头,但如果窗口长达 1 小时,这可能不起作用。
  另一种简单的解决方案是将状态存储在远程存储系统或数据库中,但这会丢失数据的局部性并产生大量的网络往返。
  回想一下上面提到的数据库中表和日志的双重性。
  可以使用本地存储或索引维护状态的流处理组件:
  通过记录有关本地索引的更改日志,它用于在崩溃后还原状态。此机制实际上揭示了一种通用状态,该状态可以存储为任意索引类型,并与输入流同时进行共分区。
  当处理进程崩溃时,它可以从更改日志中恢复索引,更改日志充当角色,将本地状态转换为基于基于时间的备份的某种增量记录。
  这种机制还提供了将进程本身的状态记录为日志的优雅功能,其他进程显然可以订阅该日志。
  结合数据库中的日志技术,对于数据集成的场景,往往可以做非常强大的事情:
  通过从数据库中提取日志并在各种流处理系统中为它们编制索引,可以加入不同的事件流。
  2.11 日志合并
  显然,不可能使用日志来记录全时状态更改信息。
  Kafka 使用日志合并或日志垃圾回收
  1) 对于事件数据,Kafka 只保留一个时间窗口(可以按时间配置为天或按空间配置)。
  2)对于键控更新,Kafka使用压缩技术。这种类型的日志可用于通过另一个系统中的重放技术重建源系统的状态。
  如果始终保留完整的日志数量,数据会随着时间的推移变得越来越大,重放过程也会越来越长。
  Kafka 不是简单地丢弃旧的日志消息,而是通过合并来丢弃过时的记录,例如,如果消息的主键最近已更新。
  2.12 系统构建
  2.12.1 分布式系统
  日志,在分布式数据库的数据流系统中所扮演的角色是一致的:
  您可以将组织中的应用程序和数据流视为单个分布式数据库。
  将面向查询的独立系统(如 Redis、SOLR、Hive 表等)视为特殊的顶级数据索引。
  将 Storm 和 Samza 等流处理系统视为设计良好的触发器或具体化视图机制。
  各种数据系统的爆发式涌现,其实这种复杂性早已存在。在关系数据库
  的辉煌时期(鼎盛时期),公司或组织有多种关系数据库。
  显然,不可能将所有内容都放入Hadoop集群并期望它解决所有问题。那么,如何构建一个好的系统,可能是这样的:
  构建一个分布式系统,其中每个组件都是一个小集群,每个组件不一定提供完整的安全性、性能隔离或良好的可扩展性,但每个问题都可以(专业地)解决。
  Jay认为,各种系统之所以爆炸式增长,是因为构建一个强大的分布式系统非常困难。如果将用例限制为简单的场景(例如查询),则每个系统都有足够的能力来解决问题,但很难集成这些系统。
  Jay认为未来构建系统有三种可能性
  1)维持现状。在这种情况下,数据集成仍然是最大的问题,因此外部日志系统很重要(kafka!
  2)一个强大的(如辉煌时期的关系数据库)似乎不太可能解决所有问题。
  3)新一代系统大多是开源的,这就揭示了第三种可能:数据基础设施可以离散化成一组服务,还有面向应用的系统API,各种服务各做各司其职,每一种都不完整,但可以专业解决专门的问题,其实现有的Java技术栈可见一斑:
  从某种角度来看,构建这样的分布式系统就像某种版本的乐高积木。这显然与更关心API的最终用户没有太大关系,但它揭示了构建健壮系统并保持简单状态的途径:
  显然,如果构建分布式系统的时间从数年减少到数周,那么自行构建大型系统的复杂性将消失,而这一定是由于出现了更可靠、更灵活的“构建块”。
  2.12.2 登录系统构建状态
  如果系统受外部日志系统支持,
  那么每个独立的系统都可以通过共享一个日志来降低自身的复杂性,Jay 认为日志的作用是:
  1)处理数据一致性。通过序列化节点上的并发操作可以实现即时和最终一致性。
  2) 提供节点间的数据复制。
  3)提供“提交”的语义。例如,如果您认为写入操作不会丢失,则为操作确认。
  4) 提供可由外部系统订阅的源。
  5) 提供在节点因故障而丢失数据时恢复或重建新复制节点的功能。
  6) 处理节点之间的负载均衡。
  以上,可能是应该在完整的分布式系统中提供的大部分功能(Jay brother真的很喜欢Log!其余的是客户端的 API 和构建索引之类的东西,例如需要提取所有分区的全文索引,以及针对只需要提取分区中的数据的主键的查询。
  (那就解释其余的,周杰伦哥哥很厉害!
  该系统可以分为两个逻辑组件(这是强大的理解和技能):
  1) 日志层
  2) 服务层
  日志层以序列化和有序的方式捕获状态更改,而服务层存储外部查询所需的索引,例如可能需要 B 树和稳定索引的 K-V 存储,以及需要倒排索引的搜索服务。
  写入操作可以直接输入到日志层中,也可以通过服务层代理。写入日志会生成逻辑时间戳(日志的索引),例如数字 ID,如果系统已分区,则服务层和日志层将具有相同的分区(但它们各自的计算机编号可能不同)。
  服务层订阅日志层,以
  最快的速度按照日志存储的顺序追逐日志,将数据和状态变化同步到自己的本地索引中。
  客户端将获得读写语义:
  通过携带查询时任何节点写入时间的时间戳,服务的节点
  Layer 接收此查询,将时间戳与其本地索引进行比较,如有必要,为了防止返回过期的旧数据,将请求的执行推迟到服务节点的索引与时间戳同步。
  服务层的节点可能需要也可能不需要知道领导者的概念。在许多简单的用例中,服务层无法构建领导节点,因为日志是事实的来源。
  还有一个问题是如何处理节点故障后的恢复。为此,可以在日志中保留固定大小的时间窗口,同时维护数据的快照。您也可以让日志保留数据的完整备份,并使用日志合并技术完成日志本身的垃圾回收。这种方法将服务层的大部分复杂性转移到日志层,因为服务层是特定于系统的,并且日志层可以是通用的。
  基于日志系统,可以提供一套完整的API供开发和使用,可以作为其他系统的ETL数据源,供其他系统订阅。
  全栈 ! :
  显然,以日志为核心的分布式系统立即成为可以为其他系统提供数据加载支持和数据流处理的角色。同样,流处理系统也可以同时使用多个数据流,并通过索引这些数据流然后输出另一个系统来向外界提供服务。
  构建系统
  基于日志层和服务层,使查询相关因素与系统的可用性和一致性脱钩。
  也许很多人认为在日志中单独备份数据,尤其是制作数据的完整副本,太浪费和奢侈,但事实并非如此:
  1)LinkedIn(注:2013)Kafka生产集群每个数据中心维护75TB的数据,应用程序集群比kafka集群需要更高的存储空间和存储条件(SSD+更多内存)。
  2)全文搜索索引最好加载到内存中,日志都可以使用,因为它们都是线性读写,所以可以使用廉价的大容量磁盘。
  3)由于Kafka集群实际上是在多订阅者模式下运行的,多个系统消耗数据,因此日志集群的成本是摊销的。
  4)由于上述所有原因,外部日志系统(kafka或类似系统)的开销变得非常小。
  2.13 结论
  最后,周杰伦哥不仅大方地留下了大量有价值的学术和工程论文和参考链接,还虚心留下了这样一句话:
  如果你做到了这一步,你就知道我对日志的大部分了解。
  发现这篇文章对您有帮助吗?请与更多人分享
  关注“进口新品”,看科技干货
  事实:要大量文章,内容伪原创工具哪个好用?
  1.我使用的文章伪原创工具是ATM AI批量写入工具。
  功能:在线伪原创、批量伪原创、自定义文本替换等。
  优点:伪原创之后的文章可读性强,文章流畅,原创率高,伪原创易操作,伪原创文章 速度快,免费使用
  此外,ATM AI 批写助手公众号近日观察到,3.0 版本将会更新。似乎在之前版本的基础上增加了更多的功能。有兴趣的朋友可以了解一下。
  1.在线伪原创:
  
  
  2. 批处理 伪原创:
  
  2.我使用的文章采集工具是优采云采集器和优采云
  1. 优采云采集
  功能:网站各类网站的大部分内容都可以实现采集,采集中的文章支持本地编辑,也支持在线发布到网站
  优点:文章采集速度不错,可以抓取各种网站数据采集,这个采集工具功能非常多,喜欢的朋友需要它可以自己研究。
  
  
  2. 优采云采集
  与上面提到的优采云采集相比,这个优采云采集工具操作起来更简单,设置的地方也不多,相当有一个傻瓜式采集工具,采集的文章速度一样快,文章的内容干净(文本模式下不会出现多余的标签码)在优采云,需要自己设置是否保留标签,比设置复杂一点。
  功能:静态页面内容采集
  优点:采集速度快,操作简单,采集的文章干净(优采云采集不支持在线发布,但是优采云还有各种网站内容更新器,需要另外下载)
   查看全部

  经验:我所读过的最好的一篇分布式技术文章
  (点击上方公众号快速关注)。
  资料来源:foreach_break,
  前言
  这是一份学习笔记。
  该材料来自Jay Kreps关于Log的博客文章。
  原文很长,但我坚持阅读,收获颇丰,对 Jay 的技术能力、架构能力和对分布式系统的深刻理解印象深刻。同时,他有点沾沾自喜,因为他的一些理解与周杰伦的观点相吻合。
  Jay Kreps是LinkedIn的前首席参谋工程师,现在是Confluent的联合创始人兼首席执行官,也是Kafka和Samza的主要作者。
  所谓笔记,就是读文章做笔记,因为周杰伦哥自己在这一章里组织得太好了,他自己的科学素养和哲学素养也很高,所以他认为突出的也不会省略。
  一、来源
  日志:每个软件工程师都应该知道的关于实时数据的统一抽象()
  二、注意事项
  2.1 日志的值
  1)日志是以下系统的核心:
  2)日志可能与计算机一样古老,是分布式数据系统和实时计算系统的核心。
  3)日志有很多名称:
  4)不了解日志就无法完全理解日志
  2.2 什么是日志?
  2.2.1 概述
  记录的顺序定义了这样一个概念:时间。
  因为离记录越远,记录得越早。
  的概念
  条目的序列号可以用作时间戳,记录顺序作为时间的概念可能看起来很奇怪,但您很快就会发现,将“时间”与任何特定的物理时钟分离很容易。
  日志与普通文件和表没有太大区别。
  这样,你可能会觉得日志这么简单,还有需要讨论的吗?
  其实日志的核心含义是:
  日志记录发生了什么以及何时发生。
  而这个通常是分布式系统最核心的东西。
  请注意,这里有必要澄清几个概念:
  2.2.2 数据库中的日志
  Log的起源未知,就像发明二进制搜索的人一样,很难意识到这项发明是一项发明。
  日志记录早在IBM的System R中就出现了。
  在数据库中,您需要在数据库崩溃时保持不同的数据结构和索引同步。
  为了确保原子性和持久性,数据库需要在提交对数据结构和索引的更改之前记录要修改的内容。
  因此,日志记录了何时发生的情况,每个表和索引本身就是此历史信息的映射。
  由于日志会立即持久化,因此它们成为在发生崩溃时还原其他持久性结构的可靠来源。
  日志已从 ACID 特征的实现演变为数据库之间的数据复制方式。
  显然,数据库中发生的一系列数据更改成为保持数据库之间同步的最需要的信息。
  Oracle,MySQL和PostgreSQL都收录一个日志传输协议,该协议将日志的一部分发送到用于维护复制的从属数据库。
  Oracle的XStreams和GoldenState使用日志作为通用数据订阅机制来提供非Oracle数据库订阅数据。
  MySQL和PostgreSQL提供了类似的组件,这些组件是数据系统架构的核心。
  面向机器的日志不仅可以用于数据库,还可以用于:
  2.2.3 分布式系统中的日志
  日志解决了分布式数据系统中的两个重要问题:
  1) 有序数据更改
  2) 数据分发
  所谓的状态机复制原理
  如果两个确定性过程(以相同的状态和相同的顺序开始)接收相同的输入,则它们将产生相同的输出并以相同的状态结束。
  这
  所谓确定性是指处理过程与时间无关,其处理结果不受额外输入的影响。
  可以通过非确定性示例来理解:
  所谓状态可以是机器上的任何数据,无论是在机器的内存中还是经过处理后的磁盘上。值得注意的是,相同的
  输入以相同的顺序产生相同的结果,这就是为什么日志如此重要的原因,这是一个直观的概念:如果你将相同的日志输入两个确定性程序,它们将产生相同的输出。
  在分布式系统的构建中,意识到这一点可以:
  让所有机器都做同样的事情,协议是:
  构建分布式、一致的日志系统,为所有处理系统提供输入。
  日志系统的作用是消除所有输入流的不确定性,并确保处理相同输入的所有复制节点保持同步。
  此方法的最佳部分是,您可以将索引日志的时间戳视为所有复制节点的时钟:通过使用复制节点处理的日志
  中最大的时间戳作为复制节点的唯一 ID,时间戳与日志相结合可以唯一地表示该节点的整个状态。
  应用此方法的方法也有很多:
  从理论上讲,我们可以记录一系列机器指令,或者被调用方法的名称和参数,只要数据处理过程的行为相同,这些过程就可以保证节点之间的一致性。
  经常玩数据库的人会以不同的方式处理逻辑日志和物理日志:
  对于分布式系统,通常有两种方法来处理复制和数据处理:
  1) 状态机模型(主动 – 主动)
  2) 主回模型(主动 – 被动)
  如下图所示:
  为了理解上述两种方式之间的区别,让我们看一个简单的例子:
  现在,集群需要提供一个简单的服务来执行算术运算,例如加法和乘法。最初,维护一个数字,例如 0。
  上面的例子还揭示了为什么顺序是复制节点之间一致性的关键因素,如果这些操作的顺序被打乱,将获得不同的结果。
  分布式日志,可以作为某些一致性算法的数据结构:
  表示有关下一个值的一系列决策的日志。
  2.2.4 更新日志
  从数据库的角度来看,记录数据更改的一组更改日志和表是双重且可互操作的。
  1)根据记录数据变化的日志,可以重构处于某种状态的表(也可以是非关系存储系统中带有键的记录)。
  2)相反,如果表发生变化,则可以在日志中计算更改。
  这正是您想要近乎实时复制的地方!
  这与版本控制的作用非常相似:管理分布式、并发和状态修改。
  版本控制工具维护反映更改的修补程序,该修补程序实际上是一个日志,并且您与分支的签出快照进行交互,该快照等效于数据库中的表。您会发现,在版本控制和分布式系统中,复制都是基于日志的:更新版本时,只需提取反映版本更改的修补程序并将其应用于当前分支快照。
  2.3 数据集成
  2.3.1 数据集成的含义
  数据集成是来自组织中所有服务和系统的数据。
  事实上,数据的有效利用非常符合马斯洛的层次需求理论。
  在金字塔的底部,数据被采集并集成到应用程序中(无论是实时计算引擎、文本文件还是 Python 脚本)。
  这些数据需要转换,以保持易于阅读和处理的统一、标准化和干净的格式。
  当满足上述要求时,就可以开始考虑各种数据处理方法,如map-reduce或实时查询系统。
  显然,如果没有可靠、完整的数据流,Hadoop 只是一个昂贵的、难以集成的加热器(集群是否昂贵?)。
  相反,如果可以确保数据流可靠、可用且完整,则可以考虑更高级的游戏玩法、更好的数据模型以及一致、更易于理解的语义。
  然后,重点可以转移到可视化、报告、算法和预测(挖掘深度)。
  2.3.2 数据集成的两种复杂性
  事件事件
  数据记录事件是如何发生的,而不仅仅是发生了什么,通常被视为应用程序日志,因为它通常由应用程序系统写入。但这实际上混淆了日志的功能。
  事实上,谷歌的财富是由建立在(用户)点击流和好恶(体验)上的关联管道产生的,点击流和展示是事件。
  各类专业数据系统的爆炸式增长
  这些系统存在的原因:
  显然,将数据集成到这样的系统中是极其困难的。
  2.3.3 基于日志结构的数据流
  每个逻辑数据源都可以根据日志进行建模。
  数据源可以是记录事件(命中和 PV)的应用程序,也可以是接受更改的数据库表。
  每个订阅服务器都会尽快从这些数据源生成的日志中获取新记录,将其应用于本地存储系统,并增加其在日志中的读取偏移量。订阅者可以是任何数据系统,例如缓存、Hadoop、另一个站点的数据库或搜索引擎。
  登录
  事实上,提供了一个逻辑时钟,可以测量不同订阅者响应数据变化的状态,因为这些订阅者在日志中具有不同且独立的读取偏移量,这就像时间意义上的“时刻”。
  
  考虑这样一个示例、数据库和一些缓存服务器:
  日志提供了同步所有缓存服务器并推送其“时刻”的能力。
  假设我们写了一个数字为 X 的日志,想要从缓存服务器读取数据,为了不读取旧数据,我们只需要确保在缓存服务器将数据(同步)复制到 X 位置之前,我们不会从这个缓存中读取任何内容。
  此外,log 还提供了充当缓冲区的功能,以异步方式支持生产者和使用者行为。
  支持异步的最关键原因之一是订阅系统可能会崩溃,脱机进行维护,然后重新联机,在这种情况下,每个订阅者都按照自己的节奏使用数据。
  批处理系统(如 Hadoop 或数据仓库)使用数据
  以小时或数天为单位,而实时系统通常在几秒钟内消耗数据。
  数据源或日志不知道使用数据的订阅者的任何信息,因此有必要在管道中无缝添加订阅者和删除订阅者。
  更重要的是,订阅者只需要知道日志,而不是他们使用的数据源,无论该数据源是RDBMS,Hadoop还是新流行的K-V数据库等。之所以说日志,而不是消息系统,是因为不同的消息系统
  保证了不同的特性,而使用word消息系统,很难全面准确地表达某种语义,因为消息系统更重要的重定向消息。
  但是,日志可以理解为提供持久性保证和强序语义的消息系统,这在通信系统中称为原子广播。
  2.4 LinkedIn
  LinkedIn目前的主要系统包括(注:2013年):
  每个系统在其专业领域都提供专门的高级功能。
  (这一段太长太长了,周杰伦哥很有口才,所以挑重点记住!
  1)引入数据流的概念,是因为需要在Oracle数据库的表之上建立一个抽象的缓存层,为搜索引擎索引构建和社交图谱更新提供扩展能力。
  2)为了更好的处理LinkedIn的一些推荐算法,我们开始构建Hadoop集群,但团队在这方面的经验还很浅,所以走了不少弯路。
  3)一开始,这只是一个粗略的想法,只是将数据从Oracle数据仓库中提取出来并将其扔到Hadoop中就可以了。首先,从 Oracle 数据仓库快速导出数据是一场噩梦;其次,也是更糟糕的是,数据仓库中的一些数据没有得到正确处理,导致Hadoop批处理任务无法按预期产生结果,并且通过Hadoop批处理执行任务通常是不可逆的,尤其是在报告发布之后。
  4)最后,团队放弃了将数据从数据仓库中提取出来的方式,直接进入数据库和日志作为数据源。然后建造了一个轮子:K-V 存储(伏地魔)。
  5)即使是数据复制这样的小任务,也会占用团队大量的时间来处理它,更糟糕的是,一旦数据处理管道中出现了一个点,Hadoop立即变得浪费,因为无论算法在错误的数据上运行多么出色,只有一个后果,那就是生成更多错误的数据。
  6)即使团队构建了一些具有高度抽象的东西,它也需要为每个数据源进行特定的配置,这是许多错误和失败的根源。7)大量的程序员想要
  跟进,每个程序员都有大量的想法,集成这个系统,添加这个功能,集成这个功能,或者想要自定义数据源。
  8)周杰伦弟兄开始意识到:
  首先,他们建造的管道仍然粗糙,但非常有价值。即使解决数据在Hadoop等新系统中可用的问题,也可以解锁大量可能性。以前困难的计算开始成为可能。只需从其他系统解锁数据并集成它们,即可轻松制作新产品和分析。其次,很明显,可靠的数据加载
  需要更坚实的支持,如果可以捕获所有结构,Hadoop数据加载就可以完全自动化,而无需添加新数据源或手动修改数据模式。数据神奇地出现在 HDFS 中,当添加新数据源时,Hive 的表会自动生成,并使用适当的列自适应地生成。
  第三,数据覆盖面远远不够。因为很难处理很多新的数据源。
  9)为了解决新数据源加入后的数据加载问题,团队开始了这样的尝试:
  很快,他们发现这行不通,因为发布和订阅,生产和消费,数据流通常仍然是双向的,这变成了O(n^2)问题。
  所以,他们需要的是这样的模型:
  每个使用者都需要与数据源隔离,理想情况下只与一个数据存储库进行交互,该存储库为他们提供对任意数据的访问权限。
  10)消息系统+日志=卡夫卡,卡夫卡诞生了。
  2.5 日志ETL与数据仓库的关系
  2.5.1 数据仓库
  1) 一个干净、结构化、集成的数据存储库,用于分析。
  2)虽然这个想法很棒,但获取数据的方式有点过时了:定期从数据库中获取数据并将其转换为更易读的格式。
  3)以前的数据仓库问题是干净数据和数据仓库的高度耦合。
  数据仓库应该是查询功能的集合,服务于上报、搜索、AD热分析,包括计数、聚合、过滤等操作,所以应该是批处理系统。
  但是干净数据和这样的批处理系统的高度耦合意味着这些数据不能被实时系统消费,例如搜索引擎索引构建、实时计算和实时监控系统等。
  2.5.2 ETL
  Jay弟兄认为ETL只做两件事:
  1)提取并清理数据以从特定系统中解锁数据
  2)重构数据,以便可以通过数据仓库进行查询。例如,将数据类型更改为关系数据库的类型,将架构转换为星形或雪花模式,或将其分解为面向列的存储格式。
  但是将这两件事结合在一起是一个大问题,因为集成的、干净的数据应该被其他实时系统、索引构建系统和低延迟处理系统使用。
  数据仓库团队是
  负责采集和清理数据,但这些数据的生成者经常输出难以提取和清理的数据,因为他们不清楚数据仓库团队的数据处理需求。
  同时,由于核心业务团队对跟上公司其他部门的步伐不敏感,真正可以处理的数据覆盖率低,数据流脆弱,难以快速响应变化。
  因此,更好的方法是:
  如果要在干净的数据集上做一些搜索、实时监控趋势图和实时告警,不宜使用原创数据仓库或 Hadoop 集群作为基础设施。更糟糕的是,ETL为数据仓库构建了一个数据加载系统,该系统对其他(实时)系统几乎没有用处。最好的模型是在数据发布者发布
  数据之前清理数据,因为只有发布者最了解其数据的外观。在此阶段完成的所有操作都应该是无损和可逆的。
  所有丰富的语义或附加值的实时转换都应在原创日志发布后进行后处理,包括为事件数据建立会话或添加一些感兴趣的字段。原创日志仍然可以单独使用,但此类实时应用程序也会派生新的参数化日志。
  最后,只有与特定目标系统对应的数据聚合操作才应作为数据加载的一部分执行,例如转换为星型或雪花型架构,以便在数据仓库中进行分析和报告。因为这个阶段,就像传统的ETL一样,由于非常干净和规范的数据流,(带有日志)现在非常简单。
  2.6 日志文件和事件
  以日志为中心的架构还有一个额外的好处,即易于实现非耦合的事件驱动系统。
  捕获用户活动和系统更改的传统方法是将此信息写入文本日志,然后将其提取到数据仓库或Hadoop集群中进行聚合和处理,这类似于前面描述的数据仓库和ETL问题:数据与数据仓库高度耦合。
  在LinkedIn,它构建了一个基于kafka的事件数据处理系统。为各种操作定义了数百种事件类型,从 PV、用户广告展示、搜索到服务呼叫和应用程序异常等。
  要了解上述事件驱动系统的好处,请看一个简单的事件示例
  在“职业”页面上,提供机会。此页面应仅负责如何呈现机会,不应收录太多其他逻辑。但是,您会发现,在相当大的网站中执行此操作很容易涉及越来越多的逻辑,而这些逻辑与展示的机会无关。
  例如,我们要集成以下系统功能:
  1)我们需要将数据发送到Hadoop和数据仓库进行离线处理。
  2)我们需要计算页面浏览量,以确保某些视图不是用于抓取Web内容或任何东西。
  3) 我们需要汇总有关此页面的浏览信息,以便在业务机会发布者的分析页面上显示。
  4)我们需要记录一个用户浏览这个页面的历史记录,以确保我们向这个用户提供任何有价值的、有适合这个用户的良好体验的工作机会,而不是一遍又一遍地为这个用户重复一个机会(想想只有老婆不在家的时候才能玩的游戏, 红绿蓝闪烁的特效,配上爆炸性的DJ风格舞曲,或是摇摆专注的事业巅峰和Qi X短裙的女生,再点进去才发现是标题派对的广告!)。
  5)我们的推荐系统需要记录此页面的浏览历史记录,以便正确跟踪此工作机会的受欢迎程度。
  很快,仅显示机会的页面逻辑变得复杂。虽然我们也增加了这个机会在移动设备上的展示,但我们也必须迁移逻辑,这增加了复杂性。还没有,困难的部分是在此页面上工作的工程师需要了解其他系统,以确保上述功能正确集成。
  这只是一个极其简单的例子,在实践中,情况只会更加复杂。
  事件驱动可以使这变得容易。负责展示机会的
  页面只需要展示机会并记录一些与演示相关的因素,例如与工作机会相关的属性、查看页面的人员以及与演示文稿相关的其他有用信息。页面不需要维护其他系统的知识和知识,例如推荐系统、安全系统、机会发布者分析系统和数据仓库,所有这些系统只需要订阅者、订阅事件,然后独立处理它们,而呈现机会的页面不需要在新订阅者或消费者加入时进行修改。
  2.7 构建可扩展日志
  分离发布者和订阅者并不是什么新鲜事,但日志系统很难确保多个订阅者可以实时处理消息,同时确保可扩展性。
  如果日志不是构建
  速度快,开销低,可扩展性强,那么在这个日志系统上构建的所有美妙之处就不多说了。
  许多人可能认为日志系统在分布式系统中是一项缓慢而昂贵的工作,并且仅用于处理 ZooKeeper 更适合的一些信息,例如元数据。
  但是现在LinkedIn(注:2013年)每天在kafka中处理600亿次不同的消息写入(如果算上数据中心镜像,则为数千亿次写入)。
  周杰伦兄弟,他们是怎么做到的?
  1) 对日志进行分区
  2) 通过批量读取和写入优化吞吐量
  3) 避免不必要的数据复制
  通过将日志切片为多个分区来提供可扩展性:
  1)每个分区都是有序日志,但分区之间没有全局顺序。
  2)将消息写入哪个分区完全由编写器控制,通过某种类型的键(例如user_id)对其进行拆分。
  3)分段允许在分片之间不协调的情况下执行额外的日志操作,并确保系统的吞吐量与Kafka集群的大小呈线性相关。
  4)虽然没有提供全局订单(有
  实际上是成千上万的消费者或订阅者,讨论它们的全局顺序通常没有什么价值),Kafka 提供了一个保证,即发送方以什么顺序将消息发送到分区,消息以什么顺序(以什么顺序,以什么顺序)从该分区传递。
  5)每个分区按照配置的编号进行复制,如果一个领导节点挂断,其他节点将成为新的主节点。
  6)一个日志,和文件系统一样,线性读写模式可以优化,小的读写日志可以形成更大的、高吞吐量的操作。卡夫卡正在激烈地做这件事。批处理用于各种场景,例如客户端向服务器发送数据、将数据写入磁盘、服务器之间的数据复制、向消费者传输数据、确认提交数据等。
  7)最后,Kafka对内存日志、磁盘日志和通过网络发送的日志采用了非常简单的二进制格式,以方便使用各种优化技术,例如零拷贝数据传输。
  许多优化技术相结合,允许您以磁盘或网络可以提供的最大容量读取和写入数据,即使内存已满也是如此。
  2.8 日志和实时处理
  你认为周杰伦提供了一种如此漂亮的方法来复制数据并复制它吗?
  你!错!完成!日志是
  流式处理的另一种说法,日志是流处理的核心。
  2.8.1 什么是流处理
  周杰伦哥认为:
  1)流处理是连续数据处理的基础设施。
  2)流处理的计算模型,如MapReduce或其他分布式处理框架,只需要保证低延迟。
  3)批量数据采集模式导致批量数据处理模式。
  4)采集数据的连续模式导致连续的数据处理模式。
  5)杰伊弟兄谈到了美国人口普查局解释批处理的方式。
  在LinkedIn,活动数据和数据库中的变化是连续的。
  
  每天批处理数据,连续计算将窗口设置为一天以重合。
  因此,流处理是一个这样的过程:
  6)在处理数据时,有了时间的概念,不需要维护数据的静态快照,因此可以按照用户定义的频率输出结果,而无需等待数据集达到某个“结束”状态。
  7)从这个意义上说,流处理是批处理的泛化,鉴于实时数据的普及,这是一个极其重要的泛化。
  8)许多商业公司无法构建流处理引擎,通常是因为他们无法构建流数据采集引擎。
  9) 流处理弥合了实时响应服务和离线批处理基础设施之间的差距。
  10)日志系统解决了流处理模式下的许多关键问题,其中最大的问题是如何在实时多订阅者模式下提供可用数据(流数据采集)。
  2.9 数据流图
  关于流处理最有趣的事情是它扩展了源的概念。
  无论是日志、源还是事件,逐行数据记录,都来自应用程序的活动。
  但是,流处理还允许我们处理来自其他源的数据,这些数据与原创数据到使用者没有什么不同,并且这些派生源可以收录任何程度的复杂性。
  流处理任务应如下所示:从日志中读取数据并将输出写入日志或其他系统。
  作为输入和输出日志,将这些进程本身与其他进程连接起来,形成一个图形。
  事实上,以日志为中心的系统允许您将组织中的数据捕获、转换和数据流视为日志和写入它们的处理的组合。
  流处理程序不必很大:它可以是一个进程或一组进程,但它可以提供一些额外的基础结构和支持,以便更轻松地管理用于处理的代码。
  引入日志有两个目的:
  1)确保数据集可以支持多种订阅者模式,并且有序。
  2)可以用作应用程序的缓冲区。这很重要,因为在异步数据处理过程中,如果上游生产者可以更快地生成数据,而使用者无法跟上,在这种情况下,要么处理过程被阻塞,要么引入缓冲区,要么删除数据。
  丢弃数据似乎不是一个好的选择,阻塞处理过程会导致所有数据流的处理图中的处理过程卡住。另一方面,Log 是一个大的、超大的、非常大的缓冲区,它允许重新启动处理进程,以便在进程失败后,它不会影响流处理图中的其他进程。这对于大型组织扩展数据流至关重要,因为不同的团队有不同的处理任务,显然整个流处理过程不会因为一个任务中的错误而卡住。
  Storm 和 Samza 就是这样的流处理引擎,它们都使用 kafka 或其他类似的系统作为它们的日志系统。
  (注:周杰伦哥哥挺凶悍的,卡夫卡在前,萨马扎在后。
  2.10 有状态实时处理
  许多流处理
  引擎是无状态的,一次记录,但许多用例需要在一定大小的特定时间窗口内进行复杂的计数、聚合和联接操作,以进行流处理。
  例如,在点击流中,联接用户信息。
  然后,这种用例需要状态支持。在处理数据时,需要维护一段数据的状态。
  问题是,当处理器可能挂断时,如何保持正确?
  在内存中维护状态可能是最简单的,但它经不起崩溃。
  如果仅在某个时间窗口内保持状态,当发生挂断或故障时,则可以将处理直接重播到窗口的开头,但如果窗口长达 1 小时,这可能不起作用。
  另一种简单的解决方案是将状态存储在远程存储系统或数据库中,但这会丢失数据的局部性并产生大量的网络往返。
  回想一下上面提到的数据库中表和日志的双重性。
  可以使用本地存储或索引维护状态的流处理组件:
  通过记录有关本地索引的更改日志,它用于在崩溃后还原状态。此机制实际上揭示了一种通用状态,该状态可以存储为任意索引类型,并与输入流同时进行共分区。
  当处理进程崩溃时,它可以从更改日志中恢复索引,更改日志充当角色,将本地状态转换为基于基于时间的备份的某种增量记录。
  这种机制还提供了将进程本身的状态记录为日志的优雅功能,其他进程显然可以订阅该日志。
  结合数据库中的日志技术,对于数据集成的场景,往往可以做非常强大的事情:
  通过从数据库中提取日志并在各种流处理系统中为它们编制索引,可以加入不同的事件流。
  2.11 日志合并
  显然,不可能使用日志来记录全时状态更改信息。
  Kafka 使用日志合并或日志垃圾回收
  1) 对于事件数据,Kafka 只保留一个时间窗口(可以按时间配置为天或按空间配置)。
  2)对于键控更新,Kafka使用压缩技术。这种类型的日志可用于通过另一个系统中的重放技术重建源系统的状态。
  如果始终保留完整的日志数量,数据会随着时间的推移变得越来越大,重放过程也会越来越长。
  Kafka 不是简单地丢弃旧的日志消息,而是通过合并来丢弃过时的记录,例如,如果消息的主键最近已更新。
  2.12 系统构建
  2.12.1 分布式系统
  日志,在分布式数据库的数据流系统中所扮演的角色是一致的:
  您可以将组织中的应用程序和数据流视为单个分布式数据库。
  将面向查询的独立系统(如 Redis、SOLR、Hive 表等)视为特殊的顶级数据索引。
  将 Storm 和 Samza 等流处理系统视为设计良好的触发器或具体化视图机制。
  各种数据系统的爆发式涌现,其实这种复杂性早已存在。在关系数据库
  的辉煌时期(鼎盛时期),公司或组织有多种关系数据库。
  显然,不可能将所有内容都放入Hadoop集群并期望它解决所有问题。那么,如何构建一个好的系统,可能是这样的:
  构建一个分布式系统,其中每个组件都是一个小集群,每个组件不一定提供完整的安全性、性能隔离或良好的可扩展性,但每个问题都可以(专业地)解决。
  Jay认为,各种系统之所以爆炸式增长,是因为构建一个强大的分布式系统非常困难。如果将用例限制为简单的场景(例如查询),则每个系统都有足够的能力来解决问题,但很难集成这些系统。
  Jay认为未来构建系统有三种可能性
  1)维持现状。在这种情况下,数据集成仍然是最大的问题,因此外部日志系统很重要(kafka!
  2)一个强大的(如辉煌时期的关系数据库)似乎不太可能解决所有问题。
  3)新一代系统大多是开源的,这就揭示了第三种可能:数据基础设施可以离散化成一组服务,还有面向应用的系统API,各种服务各做各司其职,每一种都不完整,但可以专业解决专门的问题,其实现有的Java技术栈可见一斑:
  从某种角度来看,构建这样的分布式系统就像某种版本的乐高积木。这显然与更关心API的最终用户没有太大关系,但它揭示了构建健壮系统并保持简单状态的途径:
  显然,如果构建分布式系统的时间从数年减少到数周,那么自行构建大型系统的复杂性将消失,而这一定是由于出现了更可靠、更灵活的“构建块”。
  2.12.2 登录系统构建状态
  如果系统受外部日志系统支持,
  那么每个独立的系统都可以通过共享一个日志来降低自身的复杂性,Jay 认为日志的作用是:
  1)处理数据一致性。通过序列化节点上的并发操作可以实现即时和最终一致性。
  2) 提供节点间的数据复制。
  3)提供“提交”的语义。例如,如果您认为写入操作不会丢失,则为操作确认。
  4) 提供可由外部系统订阅的源。
  5) 提供在节点因故障而丢失数据时恢复或重建新复制节点的功能。
  6) 处理节点之间的负载均衡。
  以上,可能是应该在完整的分布式系统中提供的大部分功能(Jay brother真的很喜欢Log!其余的是客户端的 API 和构建索引之类的东西,例如需要提取所有分区的全文索引,以及针对只需要提取分区中的数据的主键的查询。
  (那就解释其余的,周杰伦哥哥很厉害!
  该系统可以分为两个逻辑组件(这是强大的理解和技能):
  1) 日志层
  2) 服务层
  日志层以序列化和有序的方式捕获状态更改,而服务层存储外部查询所需的索引,例如可能需要 B 树和稳定索引的 K-V 存储,以及需要倒排索引的搜索服务。
  写入操作可以直接输入到日志层中,也可以通过服务层代理。写入日志会生成逻辑时间戳(日志的索引),例如数字 ID,如果系统已分区,则服务层和日志层将具有相同的分区(但它们各自的计算机编号可能不同)。
  服务层订阅日志层,以
  最快的速度按照日志存储的顺序追逐日志,将数据和状态变化同步到自己的本地索引中。
  客户端将获得读写语义:
  通过携带查询时任何节点写入时间的时间戳,服务的节点
  Layer 接收此查询,将时间戳与其本地索引进行比较,如有必要,为了防止返回过期的旧数据,将请求的执行推迟到服务节点的索引与时间戳同步。
  服务层的节点可能需要也可能不需要知道领导者的概念。在许多简单的用例中,服务层无法构建领导节点,因为日志是事实的来源。
  还有一个问题是如何处理节点故障后的恢复。为此,可以在日志中保留固定大小的时间窗口,同时维护数据的快照。您也可以让日志保留数据的完整备份,并使用日志合并技术完成日志本身的垃圾回收。这种方法将服务层的大部分复杂性转移到日志层,因为服务层是特定于系统的,并且日志层可以是通用的。
  基于日志系统,可以提供一套完整的API供开发和使用,可以作为其他系统的ETL数据源,供其他系统订阅。
  全栈 ! :
  显然,以日志为核心的分布式系统立即成为可以为其他系统提供数据加载支持和数据流处理的角色。同样,流处理系统也可以同时使用多个数据流,并通过索引这些数据流然后输出另一个系统来向外界提供服务。
  构建系统
  基于日志层和服务层,使查询相关因素与系统的可用性和一致性脱钩。
  也许很多人认为在日志中单独备份数据,尤其是制作数据的完整副本,太浪费和奢侈,但事实并非如此:
  1)LinkedIn(注:2013)Kafka生产集群每个数据中心维护75TB的数据,应用程序集群比kafka集群需要更高的存储空间和存储条件(SSD+更多内存)。
  2)全文搜索索引最好加载到内存中,日志都可以使用,因为它们都是线性读写,所以可以使用廉价的大容量磁盘。
  3)由于Kafka集群实际上是在多订阅者模式下运行的,多个系统消耗数据,因此日志集群的成本是摊销的。
  4)由于上述所有原因,外部日志系统(kafka或类似系统)的开销变得非常小。
  2.13 结论
  最后,周杰伦哥不仅大方地留下了大量有价值的学术和工程论文和参考链接,还虚心留下了这样一句话:
  如果你做到了这一步,你就知道我对日志的大部分了解。
  发现这篇文章对您有帮助吗?请与更多人分享
  关注“进口新品”,看科技干货
  事实:要大量文章,内容伪原创工具哪个好用?
  1.我使用的文章伪原创工具是ATM AI批量写入工具。
  功能:在线伪原创、批量伪原创、自定义文本替换等。
  优点:伪原创之后的文章可读性强,文章流畅,原创率高,伪原创易操作,伪原创文章 速度快,免费使用
  此外,ATM AI 批写助手公众号近日观察到,3.0 版本将会更新。似乎在之前版本的基础上增加了更多的功能。有兴趣的朋友可以了解一下。
  1.在线伪原创:
  
  
  2. 批处理 伪原创:
  
  2.我使用的文章采集工具是优采云采集器和优采云
  1. 优采云采集
  功能:网站各类网站的大部分内容都可以实现采集,采集中的文章支持本地编辑,也支持在线发布到网站
  优点:文章采集速度不错,可以抓取各种网站数据采集,这个采集工具功能非常多,喜欢的朋友需要它可以自己研究。
  
  
  2. 优采云采集
  与上面提到的优采云采集相比,这个优采云采集工具操作起来更简单,设置的地方也不多,相当有一个傻瓜式采集工具,采集的文章速度一样快,文章的内容干净(文本模式下不会出现多余的标签码)在优采云,需要自己设置是否保留标签,比设置复杂一点。
  功能:静态页面内容采集
  优点:采集速度快,操作简单,采集的文章干净(优采云采集不支持在线发布,但是优采云还有各种网站内容更新器,需要另外下载)
  

技巧:红蓝对抗之域名搜集方法总结

采集交流优采云 发表了文章 • 0 个评论 • 104 次浏览 • 2022-10-31 15:45 • 来自相关话题

  技巧:红蓝对抗之域名搜集方法总结
  腾讯蓝军实习生
  jax, yhy, A1oe
  前言
  在以往的HW、红蓝对抗、渗透测试项目中,外网信息的采集是一个至关重要的环节。外网信息采集全面,可能有四、两种拨号效果,直接突破外网边界,进入内网。
  最近,我们三人加入了腾讯蓝军,学习渗透技能。讲师要求我们对域名资产的采集方法进行全面的研究。子域是域名信息采集的重要组成部分。在防御措施严密的情况下,我们不能直接拿下主域名,所以可以采取迂回战术,拿下子域名,然后无限接近主域名。
  方法原理介绍
  1. 收获具有证书透明度的子域
  原则
  引用谷歌的项目介绍:“为了给用户提供加密流量,网站必须先向可信的证书颁发机构(CA)申请一个证书。然后,当用户尝试访问对应的网站时,这个证书提供给浏览器以验证 网站。近年来,由于 HTTPS 证书系统的结构缺陷,证书以及颁发证书的 CA 很容易受到黑客攻击和操纵。Google 的证书透明项目( ) 旨在通过提供一个用于监控和审核 HTTPS 证书的开放框架来保护证书颁发过程。”
  那么,通过像这样的证书透明项目,我们可以从中获得一些有价值的域名。
  执行:
  访问以下链接,搜索您需要查询的域名,如:
  (1)crtsh:
  (2) 脸书:
  (3)委托:
  (4) 证书检测器:
  (5) 窥探:
  (6) 中央统计局:
  (7) 谷歌:
  2. 例行检查采集子域
  2.1 域名转移
  原则
  区域转移操作是指备服务器查询主服务器以刷新其区域数据库以确保数据一致性。此操作的目的是防止主名称服务器由于意外故障而变得不可用的全局影响。通常,只有在网络中有备用域名 DNS 服务器时,才需要进行 DNS 区域传输操作。一旦 DNS 服务器被错误配置为向任何发出请求的人提供区域数据库的副本,它就可能被攻击者利用。
  执行
  1.挖掘命令
  作为挖掘@axfr
  是提供数据的服务器,是要传输的关键字,axfr是区域传输选项。
  2.python中的dns库
  xfr = dns.query.xfr(where=server,zone=self.domain,timeout=5.0,lifetime=10.0)
  zone = dns.zone.from_xfr(xfr)
  这儿存在一个问题
  一般来说,如果DNS服务器配置正确、DNS传输被禁用或设置了白名单,漏洞利用成功的概率很低。
  2.2 站点配置文件
  原则
  信息泄露的主要问题是某个域名下的一些文件会存储一些相关的域名,比如子域。此类文件包括跨域策略文件crossdomain.xml、站点地图文件。
  执行
  创建文件列表,拼接域名后直接访问,判断修改后的文件是否存在。如果存在则提取数据,如果不存在则跳过。
  1.crossdomain.xml文件
  直接访问crossdomain.xml路径
  2.站点地图文件
  直接访问 sitemap.xml、sitemap.txt、sitemap.html、sitemapindex.xml、sitemapindex.xml 路径
  这儿存在一个问题
  文件往往不存在,即使存在,域名信息也不充分或不完整。
  2.3 检查内容安全策略
  原则
  内容安全策略 (CSP) 是一种声明性安全机制,它使 网站 操作员能够控制符合 CSP 的用户代理(通常是浏览器)的行为。通过控制启用哪些功能以及从何处下载内容,您可以减少 网站 的攻击面。CSP 的主要目的是防御跨站点脚本 (XSS) 攻击。例如,CSP 可以完全禁止内联 JavaScript 并控制从何处加载外部代码。它还可以禁用动态代码执行。禁用所有攻击源后,XSS 攻击变得更加困难。CSP 中的关键字是 default-src、img-src、object-src 和 script-src。其中,*-src 可能收录域名信息。
  执行
  1.手动抓包
  HTTP 标头的 Content-Security-Policy 属性
  2. Python的Requests获取
  导入请求
  res = requests.post(url=url, headers=headers, data=data, allow_redirects=False)
  如果不是 res.headers['Content-Security-Policy']:
  print("标头中没有 Content-Security-Policy")
  别的:
  # 进程主体代码
  2.4 使用DNS查询采集子域
  原则
  子域srv是通过枚举常见的SRV记录并进行查询来采集的,子域是通过查询域名的DNS记录中的MX、NS、SOA、TXT记录来采集的。
  SRV 记录
  这是在添加服务记录服务器时添加的服务记录,SRV记录哪台计算机提供了哪项服务。格式为:服务名称。协议的类型(例如:example-server.tcp)。
  以下命令枚举给定域名的 SRV 记录:
  nmap --script dns-srv-enum.nse --script-args "dns-srv-enum.domain=''"
  MX 记录
  要创建邮件服务,它会指向邮件服务器地址,并且需要设置 MX 记录。创建邮件地址时,一般根据邮件服务商提供的MX记录填写此记录。
  NS 记录
  域名解析服务器记录。如果要指定域名服务器解析子域,需要设置NS记录。
  SOA 记录
  
  SOA 称为起始权限记录,NS 用于标识多个域名解析服务器,SOA 记录用于标识众多 NS 记录中哪一个是主服务器。
  TXT 记录
  可以任意填写,可以为空。这个项目一般在做一些验证记录的时候用到,比如:SPF(anti-spam)记录。
  3. 利用 DNS 数据集采集子域
  使用 DNS 记录公开数据采集
  *注:将需要的{domain}替换为需要查询的域名,目标是我们认为更有效的。
  (1) ip138:
  {域}/domain.htm
  (2)百度云观察:
  {领域}
  (3) 黑客目标:
  (4) 谜语人:
  :{领域}
  (5) 缓冲:
  {领域}
  (6) dnsdb:
  {领域}
  (7) ipv4info:
  (8) 罗布特斯:
  (9)中国:
  (10) 网络技术:
  (11) dnsdumpster:
  (12) 网站档案:
  (13) 查找子域:
  4. 利用威胁情报平台数据采集子域
  *注:将需要的{domain}替换为需要查询的域名,以下平台需要注册,注册后免费试用
  (1) {domain}/{section}
  {section} 指其他命令和动作,API 的使用请参考文档。
  (2) {domain}/子域
  (3) {域名}
  API:域
  (4)
  {领域}
  (5) {domain}/子域
  或 {domain}/关系
  (6)
  #
  5.使用搜索引擎发现子域
  5.1 谷歌搜索语法——站点
  当使用站点提交查询时,Google 会将查询限制在某个网站/某个域。这个时候最好配合其他指令。例如,使用减号“-”排除不需要的数据。域名。
  5.2 站点:xxx *(目标IP)
  当我们得到子域的真实IP后,可以尝试搜索site:xxx*进行C段搜索,也可以通过这种方法找到很多其他有价值的相关域名。经过笔者的尝试,这种方法在搜狗和谷歌搜索引擎上都有效,谷歌搜索引擎效果更好。
  如图所示:
  6. 域名注册与资产归集
  原则
  在采集一些大型目标的信息时,您还可以通过查找域名注册信息,找到具有相同记录的其他域名资产。比如在采集qq的子域时,最常用的方法就是采集子域。此时,其他顶级域名资产将被遗漏。
  搜索网站:
  如上图所示,通过查看网站的记录/许可号,再逆向查看,可以找到其他具有相同记录的顶级域名资产。
  通过域名注册搜索具有相同记录的其他域名资产,可以更全面地采集目标资产信息,增加发现漏洞的概率。
  7.whois查询和关联查询
  工具:网站管理员工具
  这里我们将演示如何执行whois查询和反向检查
  7.1 查询whois
  7.2 查看whois
  **&amp;ddlSearchMode=1&amp;domain=
  获取相关域信息。
  8. 领域爆炸
  爆破的原理其实是通过枚举实现的,通过不断拼接字典的内容来枚举域名的A记录,但是这种方式一般需要解决泛解析的问题。
  比如开源工具oneforall会先随机访问一个不存在的域,通过返回结果来判断是否有泛解析。确认有泛解析后,程序会开始连续循环生成随机域名,去服务器查询,每次查询都会返回服务器。记录IP和TTL,直到大部分IP地址出现两次以上,IP黑名单采集结束。拿到IP黑名单后,oneforall再将其字典中的每一项与指定要查询的域名进行拼接。爆破过程中根据IP黑名单过滤。
  但是,这种广泛的过滤很容易导致漏报,因此 oneforall 也将 TTL 作为黑名单规则的一部分。判断依据是:在权威DNS中,泛解析记录的TTL必须相同。如果子域记录相同,但 TTL 不同,那么这条记录可以说绝对不是泛解析记录。
  优秀的开源工具
  我们研究了市面上的各种开源子域采集工具,列举了很多优秀工具的功能和优势。这是一个采集其子域的示例。简单比较每个工具的性能和效果。
  工具名称:oneforall
  
  项目地址:
  工具说明:
  oneforall 是近年来出现的比较好的子域采集工具之一,并且还在不断的更新和优化中。这个工具整合了各种域名信息采集的“姿势”,手段可谓非常全面。包括使用证书透明、例行检查、使用网络爬虫(进行中)、DNS数据集、DNS查询、威胁情报平台、搜索引擎等,但笔者发现其对域名泛解析的处理是不是特别理想,而且有很多错误。同时也存在消耗时间长等缺点。
  工具名称:SubdomainBrute
  项目地址:
  工具说明:
  李洁洁的SubdomainBrute是业内比较知名的子域名采集工具。该工具使用协程加速爆破速度,使用114DNS、百度DNS、阿里DNS查询快速可靠的公共DNS。精度高,效果更好。但是泛解析的处理规则是:如果超过10个域名指向同一个IP,则发现指向该IP的其他域名将被丢弃。这个方法可能会被误删,但不可否认,这个规则在一定程度上是有的。简单有效。
  工具名称:ESD
  项目地址:
  工具说明:
  ESD的爆破速度极快。62万条数据只需要4分30秒左右。该工具的缺点之一是它具有很高的性能要求。1G2核心服务器CPU使用率达到100%。另外,输出结果也比较不稳定。在同一网络下采集同一个域名时,结果的数量会出现数倍的变化。
  工具名称:子查找器
  项目地址:
  工具说明:
  使用subfinder采集子域信息,输出结果多,基数大,速度快,输出格式多,便于后续处理(oneforall也有同样的优点)。
  美中不足的是这个工具没有爆破功能,被动源比其他工具少。
  各种工具的效果比较
  每种工具的优缺点比较如下:
  *注:由于各个工具提供的默认字典不同,字典往往需要自己定义才能发挥更大的作用,所以各个工具下载后不修改,使用自己的默认字典进行爆破。使用单个域名测试并不通用,爆破结果仅供参考。
  从上图来看,单从数据层面来看,OneForAll在四大工具中表现突出,李洁洁的subdomainBrute也很优秀。可访问子域的百分比和时间非常好。域名相对较少。
  子域采集常见问题
  1.DNS缓存问题
  不同的DNS服务器可能有不同的缓存策略,也可能有不同的缓存结果,导致域名查询时解析结果没有及时更新。通常,解决上述问题需要多次 DNS 查询来强制 DNS 服务器刷新缓存以获得正确的结果。这无疑增加了泛分辨率判断和子域爆破的难度。
  事实上,这个问题在 OneForAll 中并没有得到很好的解决。在判断是否存在一般解析问题时,OneForAll 使用了函数detect_wildcard(domain, ns_ip_list)。在该函数中,OneForAll 使用不存在的子域名进行查询,判断是否有通用解析。但是只做一次决定是不够准确的,可能会导致误判。
  2.“刚性”词典
  爆破是子域采集方法的重要组成部分。对于这些工具中的大多数,字典的质量决定了最终的爆破效果。但大多数字典只是遍历字符集,使用常见的高频词,没有及时更新。当字典文件过大时,爆破速度变得很慢,效率低下的字典即使再大也达不到预期的效果。
  在实际的域名爆破中,能够自动更新的字典无疑会比普通的字典更好。在这里,我们提出了一种自动字典更新的方案。
  动态词典
  在本节中,我们更详细地描述自动字典更新的方案,可以分为三个步骤:更新词的权重➡️删除原创字典中权重低的词➡️从数据集中提取高频词和将它们添加到字典中,以更新字典。
  测试工具:Subdomainbrute
  流程图如下:
  1.体重更新
  首先使用工具subdomainbrute及其默认字典对子域进行爆破,并使用如下脚本对得到的结果进行进一步的批量检测,判断该域名是否可以被外网访问,并保存可以访问的域名一般是从外网到success.txt。
  接下来将mydic中单词的权重全部初始化为0。然后对比success.txt中的三级域名,mydic中对应单词的权重加1,其他单词的权重不变。另外,需要记录本次查询的域名。以后查询同一个域名时,mydic中词的权重不会重复更新。
  *注:mydic用于记录字典中的单词和对应的权重,格式如www,0
  2.单词删除
  使用字典爆破不同域名n次(例如20次)后,更新字典,即删除字典中的单词。具体步骤如下:
  首先,使用record_num.txt文件记录字典的使用次数。当record_num.txt文件不存在时,会生成。使用不同域名的每个查询+1。同一个域名的重复查询只算一次。
  每次程序运行后,判断是否需要reset mydic。如果需要更新,先删除record_num.txt文件,然后根据权重大小对mydic中的数据进行排序,排序后删除后30%的数据。
  3.词典更新
  删除原字典中30%的值后,需要向字典中添加新值。我们解析公共 DNS 记录以更新我们自己的字典。由于下载的数据集大小一般为几十G,直接处理比较困难,所以我们先对数据进行切分,降低处理难度。
  首先将数据集划分为每个100MB左右的数据文件,然后从这些数据文件中随机抽取一部分,将其中的所有子域提取出来,拼接到字典的“数据源”中. 对提取的子域数据进行词频分析,按照频率降序对内容进行排序。选择最频繁出现的值并将其添加到字典中,直到新字典与旧字典的大小相同。最后,新字典中所有值的权重需要清零。
  总结
  1.除了使用爆破工具,采集子域的方法还有很多。比如域名转移漏洞、DNS查询等常规手段,以及证书透明化、DNS数据集、威胁情报平台、搜索引擎、域名注册和whois查询的使用。总而言之,威胁情报平台在这些方法中表现最好,其次是证书透明度和 DNS 数据集。
  2.在这篇文章文章中,我们也研究和比较了几个业内优秀的工具。在子域的采集测试中,subfinder 和 OneForAll 表现更为突出。
  3.子域采集中的一些主要问题是域名泛解析,不同线路不同IP的解析,子域爆破时字典效率低。
  4、针对词典问题,提出了词典自动更新方案。
  网上采集子域的方法和工具有很多,但在实际使用中效果并不理想和全面。为了得到一个高效且有价值的子域列表,我们需要结合不同的方法,使用工具来合理的采集它们。
  为了方便在实战环境中使用,我们整理了大部分常用的方法,整合到这个文章中。作为学习记录,本文可能存在一些错误。如果有任何错误,请纠正我。希望大家和我们一起探索更多更高效的采集子域的方法,共同学习,共同进步。
  最后,还要感谢Leon和Xiaowu导师的帮助和指导。
  附录
  Google 证书透明度项目
  枚举子域
  DNS域名转移漏洞
  史上最全的子域采集方法:
  我们是台橡
  互联网安全卫士
  用户数据安全的捍卫者
  我们发现漏洞,检查入侵,防止攻击
  携手安防行业精英共建互联网生态安全
  期待您与我们的正能量联盟!
  seo站长工具 方法和技巧:SEO新手如何学起?
  SEO新手学习框架
  作为新手,起步阶段主要是搭建SEO基础知识的框架。而这些都可以通过各大搜索引擎初学者的指南文档获得。
  初学者指南
  百度搜索优化知识
  Google SEO 初学者指南
  掌握了这些基础知识体系之后,接下来就是通过实践来检验各种知识点的使用,还需要使用一些基础的SEO工具,包括各大搜索引擎百度、谷歌、必应等主流的站长工具,Yandex 、Naver等小语言;衍生产品插件:5118、爱站、Semrush、Moz、Ahrefs等。
  这可以通过在有SEO团队的公司中加入基础职位来完成,实战是检验知识的唯一标准。自建网站也是一种方式,毕竟搭建个人小网站的成本(包括资金投入和技术投入)已经很低了。
  同时,我们要时刻关注搜索引擎的发展变化和技术更新,不断更新自己的系统认知。
  各大引擎算法的历史和各大白皮书也应该熟悉和掌握。这就是大道所在,能在意识上形成正确的战略方向。
  算法更新历史和白皮书
  算法更新历史
  
  白皮书
  谷歌搜索中心
  百度白皮书:
  百度搜索页面质量标准规范
  百度APP移动搜索登陆页面体验白皮书5.0
  当然,一些灰帽子和黑帽子的技术也应该知道,也可以在自己的资源中做一些实验。但在服务型公司,除非公司有明确要求做黑帽,否则其他人坚决不尝试,毕竟SEO不是一日之功,这样做风险太大。
  竞品的研究也需要不断跟进,这会给你在SEO策略方案上一些启发。
  最后,SEO要成为高级点,必须经过几轮算法循环,对网站进行过多的操作。
  但归根结底,SEO只是一种吸引流量的手段,用它为服务公司和自身带来价值增长才是硬道理。但是SEO思维对我们有很大的积极影响。
  如果你喜欢SEO,就应该时刻保持好奇,不断学习,加强沟通,多做实战。
  以下谷歌seo信息学习博客供参考
  谷歌搜索最新消息
  
  搜索引擎期刊 SEO 专栏
  搜索引擎登陆SEO专栏
  SE圆桌
  以上就是整个SEO新手系统学习SEO的框架。
  为公司建立独立站做外贸的SEO新手
  在本节中,您可以先完善独立站基础SEO标签的基础SEO信息。你可以参考SEO新手指南,按照步骤练习。
  再次重申,关键词这个阶段的研究也很重要,可以使用指南配合google ads、Semrush等一些关键词研究工具配合竞争对手研究(可以搜索核心谷歌搜索中独立网站产品的词)排名前 20 位研究的结果)
  对整个独立站结构进行细化,站内部分首页列表页包括详情页。在选词策略上,关注首页列表页的核心词,详情页的长尾词。具体的内容结构侧重于对产品的理解和用户的需求。内容部署是其中之一,其二是看同类竞品词排名靠前的页面结构部署(意思是引擎通过user确定了用户最需要什么样的内容结构和内容行为),初步内容先做这个,然后根据用户反馈数据做进一步的调整。
  性能方面,可以参考站长工具后台网站的核心指标和人性化的体验进行相应的优化。
  我是Jesse,一个喜欢SEO研究的SEOer,一直在路上,欢迎交流。 查看全部

  技巧:红蓝对抗之域名搜集方法总结
  腾讯蓝军实习生
  jax, yhy, A1oe
  前言
  在以往的HW、红蓝对抗、渗透测试项目中,外网信息的采集是一个至关重要的环节。外网信息采集全面,可能有四、两种拨号效果,直接突破外网边界,进入内网。
  最近,我们三人加入了腾讯蓝军,学习渗透技能。讲师要求我们对域名资产的采集方法进行全面的研究。子域是域名信息采集的重要组成部分。在防御措施严密的情况下,我们不能直接拿下主域名,所以可以采取迂回战术,拿下子域名,然后无限接近主域名。
  方法原理介绍
  1. 收获具有证书透明度的子域
  原则
  引用谷歌的项目介绍:“为了给用户提供加密流量,网站必须先向可信的证书颁发机构(CA)申请一个证书。然后,当用户尝试访问对应的网站时,这个证书提供给浏览器以验证 网站。近年来,由于 HTTPS 证书系统的结构缺陷,证书以及颁发证书的 CA 很容易受到黑客攻击和操纵。Google 的证书透明项目( ) 旨在通过提供一个用于监控和审核 HTTPS 证书的开放框架来保护证书颁发过程。”
  那么,通过像这样的证书透明项目,我们可以从中获得一些有价值的域名。
  执行:
  访问以下链接,搜索您需要查询的域名,如:
  (1)crtsh:
  (2) 脸书:
  (3)委托:
  (4) 证书检测器:
  (5) 窥探:
  (6) 中央统计局:
  (7) 谷歌:
  2. 例行检查采集子域
  2.1 域名转移
  原则
  区域转移操作是指备服务器查询主服务器以刷新其区域数据库以确保数据一致性。此操作的目的是防止主名称服务器由于意外故障而变得不可用的全局影响。通常,只有在网络中有备用域名 DNS 服务器时,才需要进行 DNS 区域传输操作。一旦 DNS 服务器被错误配置为向任何发出请求的人提供区域数据库的副本,它就可能被攻击者利用。
  执行
  1.挖掘命令
  作为挖掘@axfr
  是提供数据的服务器,是要传输的关键字,axfr是区域传输选项。
  2.python中的dns库
  xfr = dns.query.xfr(where=server,zone=self.domain,timeout=5.0,lifetime=10.0)
  zone = dns.zone.from_xfr(xfr)
  这儿存在一个问题
  一般来说,如果DNS服务器配置正确、DNS传输被禁用或设置了白名单,漏洞利用成功的概率很低。
  2.2 站点配置文件
  原则
  信息泄露的主要问题是某个域名下的一些文件会存储一些相关的域名,比如子域。此类文件包括跨域策略文件crossdomain.xml、站点地图文件。
  执行
  创建文件列表,拼接域名后直接访问,判断修改后的文件是否存在。如果存在则提取数据,如果不存在则跳过。
  1.crossdomain.xml文件
  直接访问crossdomain.xml路径
  2.站点地图文件
  直接访问 sitemap.xml、sitemap.txt、sitemap.html、sitemapindex.xml、sitemapindex.xml 路径
  这儿存在一个问题
  文件往往不存在,即使存在,域名信息也不充分或不完整。
  2.3 检查内容安全策略
  原则
  内容安全策略 (CSP) 是一种声明性安全机制,它使 网站 操作员能够控制符合 CSP 的用户代理(通常是浏览器)的行为。通过控制启用哪些功能以及从何处下载内容,您可以减少 网站 的攻击面。CSP 的主要目的是防御跨站点脚本 (XSS) 攻击。例如,CSP 可以完全禁止内联 JavaScript 并控制从何处加载外部代码。它还可以禁用动态代码执行。禁用所有攻击源后,XSS 攻击变得更加困难。CSP 中的关键字是 default-src、img-src、object-src 和 script-src。其中,*-src 可能收录域名信息。
  执行
  1.手动抓包
  HTTP 标头的 Content-Security-Policy 属性
  2. Python的Requests获取
  导入请求
  res = requests.post(url=url, headers=headers, data=data, allow_redirects=False)
  如果不是 res.headers['Content-Security-Policy']:
  print("标头中没有 Content-Security-Policy")
  别的:
  # 进程主体代码
  2.4 使用DNS查询采集子域
  原则
  子域srv是通过枚举常见的SRV记录并进行查询来采集的,子域是通过查询域名的DNS记录中的MX、NS、SOA、TXT记录来采集的。
  SRV 记录
  这是在添加服务记录服务器时添加的服务记录,SRV记录哪台计算机提供了哪项服务。格式为:服务名称。协议的类型(例如:example-server.tcp)。
  以下命令枚举给定域名的 SRV 记录:
  nmap --script dns-srv-enum.nse --script-args "dns-srv-enum.domain=''"
  MX 记录
  要创建邮件服务,它会指向邮件服务器地址,并且需要设置 MX 记录。创建邮件地址时,一般根据邮件服务商提供的MX记录填写此记录。
  NS 记录
  域名解析服务器记录。如果要指定域名服务器解析子域,需要设置NS记录。
  SOA 记录
  
  SOA 称为起始权限记录,NS 用于标识多个域名解析服务器,SOA 记录用于标识众多 NS 记录中哪一个是主服务器。
  TXT 记录
  可以任意填写,可以为空。这个项目一般在做一些验证记录的时候用到,比如:SPF(anti-spam)记录。
  3. 利用 DNS 数据集采集子域
  使用 DNS 记录公开数据采集
  *注:将需要的{domain}替换为需要查询的域名,目标是我们认为更有效的。
  (1) ip138:
  {域}/domain.htm
  (2)百度云观察:
  {领域}
  (3) 黑客目标:
  (4) 谜语人:
  :{领域}
  (5) 缓冲:
  {领域}
  (6) dnsdb:
  {领域}
  (7) ipv4info:
  (8) 罗布特斯:
  (9)中国:
  (10) 网络技术:
  (11) dnsdumpster:
  (12) 网站档案:
  (13) 查找子域:
  4. 利用威胁情报平台数据采集子域
  *注:将需要的{domain}替换为需要查询的域名,以下平台需要注册,注册后免费试用
  (1) {domain}/{section}
  {section} 指其他命令和动作,API 的使用请参考文档。
  (2) {domain}/子域
  (3) {域名}
  API:域
  (4)
  {领域}
  (5) {domain}/子域
  或 {domain}/关系
  (6)
  #
  5.使用搜索引擎发现子域
  5.1 谷歌搜索语法——站点
  当使用站点提交查询时,Google 会将查询限制在某个网站/某个域。这个时候最好配合其他指令。例如,使用减号“-”排除不需要的数据。域名。
  5.2 站点:xxx *(目标IP)
  当我们得到子域的真实IP后,可以尝试搜索site:xxx*进行C段搜索,也可以通过这种方法找到很多其他有价值的相关域名。经过笔者的尝试,这种方法在搜狗和谷歌搜索引擎上都有效,谷歌搜索引擎效果更好。
  如图所示:
  6. 域名注册与资产归集
  原则
  在采集一些大型目标的信息时,您还可以通过查找域名注册信息,找到具有相同记录的其他域名资产。比如在采集qq的子域时,最常用的方法就是采集子域。此时,其他顶级域名资产将被遗漏。
  搜索网站:
  如上图所示,通过查看网站的记录/许可号,再逆向查看,可以找到其他具有相同记录的顶级域名资产。
  通过域名注册搜索具有相同记录的其他域名资产,可以更全面地采集目标资产信息,增加发现漏洞的概率。
  7.whois查询和关联查询
  工具:网站管理员工具
  这里我们将演示如何执行whois查询和反向检查
  7.1 查询whois
  7.2 查看whois
  **&amp;ddlSearchMode=1&amp;domain=
  获取相关域信息。
  8. 领域爆炸
  爆破的原理其实是通过枚举实现的,通过不断拼接字典的内容来枚举域名的A记录,但是这种方式一般需要解决泛解析的问题。
  比如开源工具oneforall会先随机访问一个不存在的域,通过返回结果来判断是否有泛解析。确认有泛解析后,程序会开始连续循环生成随机域名,去服务器查询,每次查询都会返回服务器。记录IP和TTL,直到大部分IP地址出现两次以上,IP黑名单采集结束。拿到IP黑名单后,oneforall再将其字典中的每一项与指定要查询的域名进行拼接。爆破过程中根据IP黑名单过滤。
  但是,这种广泛的过滤很容易导致漏报,因此 oneforall 也将 TTL 作为黑名单规则的一部分。判断依据是:在权威DNS中,泛解析记录的TTL必须相同。如果子域记录相同,但 TTL 不同,那么这条记录可以说绝对不是泛解析记录。
  优秀的开源工具
  我们研究了市面上的各种开源子域采集工具,列举了很多优秀工具的功能和优势。这是一个采集其子域的示例。简单比较每个工具的性能和效果。
  工具名称:oneforall
  
  项目地址:
  工具说明:
  oneforall 是近年来出现的比较好的子域采集工具之一,并且还在不断的更新和优化中。这个工具整合了各种域名信息采集的“姿势”,手段可谓非常全面。包括使用证书透明、例行检查、使用网络爬虫(进行中)、DNS数据集、DNS查询、威胁情报平台、搜索引擎等,但笔者发现其对域名泛解析的处理是不是特别理想,而且有很多错误。同时也存在消耗时间长等缺点。
  工具名称:SubdomainBrute
  项目地址:
  工具说明:
  李洁洁的SubdomainBrute是业内比较知名的子域名采集工具。该工具使用协程加速爆破速度,使用114DNS、百度DNS、阿里DNS查询快速可靠的公共DNS。精度高,效果更好。但是泛解析的处理规则是:如果超过10个域名指向同一个IP,则发现指向该IP的其他域名将被丢弃。这个方法可能会被误删,但不可否认,这个规则在一定程度上是有的。简单有效。
  工具名称:ESD
  项目地址:
  工具说明:
  ESD的爆破速度极快。62万条数据只需要4分30秒左右。该工具的缺点之一是它具有很高的性能要求。1G2核心服务器CPU使用率达到100%。另外,输出结果也比较不稳定。在同一网络下采集同一个域名时,结果的数量会出现数倍的变化。
  工具名称:子查找器
  项目地址:
  工具说明:
  使用subfinder采集子域信息,输出结果多,基数大,速度快,输出格式多,便于后续处理(oneforall也有同样的优点)。
  美中不足的是这个工具没有爆破功能,被动源比其他工具少。
  各种工具的效果比较
  每种工具的优缺点比较如下:
  *注:由于各个工具提供的默认字典不同,字典往往需要自己定义才能发挥更大的作用,所以各个工具下载后不修改,使用自己的默认字典进行爆破。使用单个域名测试并不通用,爆破结果仅供参考。
  从上图来看,单从数据层面来看,OneForAll在四大工具中表现突出,李洁洁的subdomainBrute也很优秀。可访问子域的百分比和时间非常好。域名相对较少。
  子域采集常见问题
  1.DNS缓存问题
  不同的DNS服务器可能有不同的缓存策略,也可能有不同的缓存结果,导致域名查询时解析结果没有及时更新。通常,解决上述问题需要多次 DNS 查询来强制 DNS 服务器刷新缓存以获得正确的结果。这无疑增加了泛分辨率判断和子域爆破的难度。
  事实上,这个问题在 OneForAll 中并没有得到很好的解决。在判断是否存在一般解析问题时,OneForAll 使用了函数detect_wildcard(domain, ns_ip_list)。在该函数中,OneForAll 使用不存在的子域名进行查询,判断是否有通用解析。但是只做一次决定是不够准确的,可能会导致误判。
  2.“刚性”词典
  爆破是子域采集方法的重要组成部分。对于这些工具中的大多数,字典的质量决定了最终的爆破效果。但大多数字典只是遍历字符集,使用常见的高频词,没有及时更新。当字典文件过大时,爆破速度变得很慢,效率低下的字典即使再大也达不到预期的效果。
  在实际的域名爆破中,能够自动更新的字典无疑会比普通的字典更好。在这里,我们提出了一种自动字典更新的方案。
  动态词典
  在本节中,我们更详细地描述自动字典更新的方案,可以分为三个步骤:更新词的权重➡️删除原创字典中权重低的词➡️从数据集中提取高频词和将它们添加到字典中,以更新字典。
  测试工具:Subdomainbrute
  流程图如下:
  1.体重更新
  首先使用工具subdomainbrute及其默认字典对子域进行爆破,并使用如下脚本对得到的结果进行进一步的批量检测,判断该域名是否可以被外网访问,并保存可以访问的域名一般是从外网到success.txt。
  接下来将mydic中单词的权重全部初始化为0。然后对比success.txt中的三级域名,mydic中对应单词的权重加1,其他单词的权重不变。另外,需要记录本次查询的域名。以后查询同一个域名时,mydic中词的权重不会重复更新。
  *注:mydic用于记录字典中的单词和对应的权重,格式如www,0
  2.单词删除
  使用字典爆破不同域名n次(例如20次)后,更新字典,即删除字典中的单词。具体步骤如下:
  首先,使用record_num.txt文件记录字典的使用次数。当record_num.txt文件不存在时,会生成。使用不同域名的每个查询+1。同一个域名的重复查询只算一次。
  每次程序运行后,判断是否需要reset mydic。如果需要更新,先删除record_num.txt文件,然后根据权重大小对mydic中的数据进行排序,排序后删除后30%的数据。
  3.词典更新
  删除原字典中30%的值后,需要向字典中添加新值。我们解析公共 DNS 记录以更新我们自己的字典。由于下载的数据集大小一般为几十G,直接处理比较困难,所以我们先对数据进行切分,降低处理难度。
  首先将数据集划分为每个100MB左右的数据文件,然后从这些数据文件中随机抽取一部分,将其中的所有子域提取出来,拼接到字典的“数据源”中. 对提取的子域数据进行词频分析,按照频率降序对内容进行排序。选择最频繁出现的值并将其添加到字典中,直到新字典与旧字典的大小相同。最后,新字典中所有值的权重需要清零。
  总结
  1.除了使用爆破工具,采集子域的方法还有很多。比如域名转移漏洞、DNS查询等常规手段,以及证书透明化、DNS数据集、威胁情报平台、搜索引擎、域名注册和whois查询的使用。总而言之,威胁情报平台在这些方法中表现最好,其次是证书透明度和 DNS 数据集。
  2.在这篇文章文章中,我们也研究和比较了几个业内优秀的工具。在子域的采集测试中,subfinder 和 OneForAll 表现更为突出。
  3.子域采集中的一些主要问题是域名泛解析,不同线路不同IP的解析,子域爆破时字典效率低。
  4、针对词典问题,提出了词典自动更新方案。
  网上采集子域的方法和工具有很多,但在实际使用中效果并不理想和全面。为了得到一个高效且有价值的子域列表,我们需要结合不同的方法,使用工具来合理的采集它们。
  为了方便在实战环境中使用,我们整理了大部分常用的方法,整合到这个文章中。作为学习记录,本文可能存在一些错误。如果有任何错误,请纠正我。希望大家和我们一起探索更多更高效的采集子域的方法,共同学习,共同进步。
  最后,还要感谢Leon和Xiaowu导师的帮助和指导。
  附录
  Google 证书透明度项目
  枚举子域
  DNS域名转移漏洞
  史上最全的子域采集方法:
  我们是台橡
  互联网安全卫士
  用户数据安全的捍卫者
  我们发现漏洞,检查入侵,防止攻击
  携手安防行业精英共建互联网生态安全
  期待您与我们的正能量联盟!
  seo站长工具 方法和技巧:SEO新手如何学起?
  SEO新手学习框架
  作为新手,起步阶段主要是搭建SEO基础知识的框架。而这些都可以通过各大搜索引擎初学者的指南文档获得。
  初学者指南
  百度搜索优化知识
  Google SEO 初学者指南
  掌握了这些基础知识体系之后,接下来就是通过实践来检验各种知识点的使用,还需要使用一些基础的SEO工具,包括各大搜索引擎百度、谷歌、必应等主流的站长工具,Yandex 、Naver等小语言;衍生产品插件:5118、爱站、Semrush、Moz、Ahrefs等。
  这可以通过在有SEO团队的公司中加入基础职位来完成,实战是检验知识的唯一标准。自建网站也是一种方式,毕竟搭建个人小网站的成本(包括资金投入和技术投入)已经很低了。
  同时,我们要时刻关注搜索引擎的发展变化和技术更新,不断更新自己的系统认知。
  各大引擎算法的历史和各大白皮书也应该熟悉和掌握。这就是大道所在,能在意识上形成正确的战略方向。
  算法更新历史和白皮书
  算法更新历史
  
  白皮书
  谷歌搜索中心
  百度白皮书:
  百度搜索页面质量标准规范
  百度APP移动搜索登陆页面体验白皮书5.0
  当然,一些灰帽子和黑帽子的技术也应该知道,也可以在自己的资源中做一些实验。但在服务型公司,除非公司有明确要求做黑帽,否则其他人坚决不尝试,毕竟SEO不是一日之功,这样做风险太大。
  竞品的研究也需要不断跟进,这会给你在SEO策略方案上一些启发。
  最后,SEO要成为高级点,必须经过几轮算法循环,对网站进行过多的操作。
  但归根结底,SEO只是一种吸引流量的手段,用它为服务公司和自身带来价值增长才是硬道理。但是SEO思维对我们有很大的积极影响。
  如果你喜欢SEO,就应该时刻保持好奇,不断学习,加强沟通,多做实战。
  以下谷歌seo信息学习博客供参考
  谷歌搜索最新消息
  
  搜索引擎期刊 SEO 专栏
  搜索引擎登陆SEO专栏
  SE圆桌
  以上就是整个SEO新手系统学习SEO的框架。
  为公司建立独立站做外贸的SEO新手
  在本节中,您可以先完善独立站基础SEO标签的基础SEO信息。你可以参考SEO新手指南,按照步骤练习。
  再次重申,关键词这个阶段的研究也很重要,可以使用指南配合google ads、Semrush等一些关键词研究工具配合竞争对手研究(可以搜索核心谷歌搜索中独立网站产品的词)排名前 20 位研究的结果)
  对整个独立站结构进行细化,站内部分首页列表页包括详情页。在选词策略上,关注首页列表页的核心词,详情页的长尾词。具体的内容结构侧重于对产品的理解和用户的需求。内容部署是其中之一,其二是看同类竞品词排名靠前的页面结构部署(意思是引擎通过user确定了用户最需要什么样的内容结构和内容行为),初步内容先做这个,然后根据用户反馈数据做进一步的调整。
  性能方面,可以参考站长工具后台网站的核心指标和人性化的体验进行相应的优化。
  我是Jesse,一个喜欢SEO研究的SEOer,一直在路上,欢迎交流。

详细描述:将ApiBoot Logging采集的日志上报到Admin

采集交流优采云 发表了文章 • 0 个评论 • 102 次浏览 • 2022-10-31 05:15 • 来自相关话题

  详细描述:将ApiBoot Logging采集的日志上报到Admin
  每个请求的详细信息可以通过 ApiBoot Logging 获取。在分布式部署方式中,一个请求可能会经过多个服务。如果每个服务独立保存请求日志信息,我们就无法实现统一控制。,并且会出现日志数据库和业务数据库不一致的情况(可能会使用多个数据源配置),因为这个问题,ApiBoot Logging提供了一个Admin概念,将客户端收到的每一条消息都转换成采集日志上报给管理员,管理员分析保存。
  创建一个日志管理项目
  由于ApiBoot Logging Admin可以汇总各个业务服务的请求日志(ApiBoot Logging),所以我们需要将各个业务服务采集订单的日志上报给Admin,所以应该独立部署。创建一个服务来专门采集请求日志并保存它们。
  初始化 Logging Admin 项目依赖项
  使用idea创建一个SpringBoot项目,pom.xml配置文件中的依赖如下:
  


org.springframework.boot
spring-boot-starter-web



org.minbox.framework
api-boot-starter-logging-admin



mysql
mysql-connector-java


com.zaxxer
HikariCP



org.minbox.framework
api-boot-starter-mybatis-enhance

  我们需要将采集的请求日志保存到数据库中,所以需要在项目中添加数据库驱动和数据库连接池相关的依赖。ApiBoot Logging Admin 通过 DataSource 操作数据,可以使用 ApiBoot MyBatis Enhance 的依赖。自动创建DataSource,摆脱手动创建,加入Spring IOC容器。
  添加 ApiBoot 统一版本依赖
  



org.minbox.framework
api-boot-dependencies
2.1.4.RELEASE
import
pom


  最新版本的 ApiBoot,请访问::api-boot-dependencies 查询。
  启用日志记录管理员
  添加 ApiBoot Logging Admin 依赖后,无法完全使用 Admin 功能。我们需要通过@EnableLoggingAdmin 注解来启用它,它会自动将Logging Admin 中需要的一些类注册到Spring IOC。将注解添加到入口类,如下所示:
  /**
* ApiBoot Logging Admin入口类
*/
@SpringBootApplication
@EnableLoggingAdmin
public class ApibootReportLogsByLoggingToAdminApplication {
public static void main(String[] args) {
SpringApplication.run(ApibootReportLogsByLoggingToAdminApplication.class, args);
}
}
  配置日志数据源
  application.yml配置文件中的数据源配置如下:
  # 服务名称
spring:
application:
name: apiboot-report-logs-by-logging-to-admin
# 数据源相关配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456
type: com.zaxxer.hikari.HikariDataSource
<p>
# 服务端口号
server:
port: 8081</p>
  控制台打印报告日志
  ApiBoot Logging Admin 可以通过配置文件控制是否将请求日志信息采集打印到控制台。在 application.yml 配置文件中添加以下内容:
  api:
boot:
logging:
# Logging Admin相关配置
admin:
# 控制台显示采集的日志信息
show-console-report-log: true
  注意:不要将此与 ApiBoot Logging 提供的 api.boot.logging.show-console-log 配置混淆。
  美化控制台打印的报表日志
  api:
boot:
logging:
# Logging Admin相关配置
admin:
# 控制台输出时美化采集到的日志
format-console-log-json: true
  注意:不要将此与 api.boot.logging.format-console-log-json 配置混淆。
  初始化日志表结构
  ApiBoot Logging Admin 使用固定的表结构来存储请求日志和服务信息。建表语句如下:
  SET NAMES utf8mb4 ;
--
-- Table structure for table `logging_request_logs`
--
CREATE TABLE `logging_request_logs` (
`lrl_id` varchar(36) COLLATE utf8mb4_general_ci NOT NULL COMMENT &#39;主键,UUID&#39;,
`lrl_service_detail_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;服务详情编号,关联logging_service_details主键&#39;,
`lrl_trace_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;链路ID&#39;,
`lrl_parent_span_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;上级跨度ID&#39;,
`lrl_span_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;跨度ID&#39;,
`lrl_start_time` mediumtext COLLATE utf8mb4_general_ci COMMENT &#39;请求开始时间&#39;,
`lrl_end_time` mediumtext COLLATE utf8mb4_general_ci COMMENT &#39;请求结束时间&#39;,
`lrl_http_status` int(11) DEFAULT NULL COMMENT &#39;请求响应状态码&#39;,
`lrl_request_body` longtext COLLATE utf8mb4_general_ci COMMENT &#39;请求主体内容&#39;,
`lrl_request_headers` text COLLATE utf8mb4_general_ci COMMENT &#39;请求头信息&#39;,
`lrl_request_ip` varchar(30) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;发起请求客户端的IP地址&#39;,
`lrl_request_method` varchar(10) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;请求方式&#39;,
`lrl_request_uri` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;请求路径&#39;,
`lrl_response_body` longtext COLLATE utf8mb4_general_ci COMMENT &#39;响应内容&#39;,
`lrl_response_headers` text COLLATE utf8mb4_general_ci COMMENT &#39;响应头信息&#39;,
`lrl_time_consuming` int(11) DEFAULT NULL COMMENT &#39;请求耗时&#39;,
`lrl_create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT &#39;日志保存时间&#39;,
`lrl_request_params` text COLLATE utf8mb4_general_ci,
`lrl_exception_stack` text COLLATE utf8mb4_general_ci,
PRIMARY KEY (`lrl_id`),
KEY `logging_request_logs_LRL_SERVICE_DETAIL_ID_index` (`lrl_service_detail_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT=&#39;请求日志信息表&#39;;
--
-- Table structure for table `logging_service_details`
--
CREATE TABLE `logging_service_details` (
`lsd_id` varchar(36) COLLATE utf8mb4_general_ci NOT NULL,
`lsd_service_id` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;上报服务的ID,对应spring.application.name配置值&#39;,
`lsd_service_ip` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;上报服务的IP地址&#39;,
`lsd_service_port` int(11) DEFAULT NULL COMMENT &#39;上报服务的端口号&#39;,
`lsd_last_report_time` timestamp NULL DEFAULT NULL COMMENT &#39;最后一次上报时间,每次上报更新&#39;,
`lsd_create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT &#39;首次上报时创建时间&#39;,
PRIMARY KEY (`lsd_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT=&#39;上报日志的客户端服务详情&#39;;
  到目前为止,ApiBoot Logging Admin 已准备就绪。接下来,我们需要修改业务服务,将请求日志上报给 Logging Admin。
  向指定的日志记录管理员报告日志
  我们将修改使用ApiBoot Logging统一管理请求日志的源码文章,在application.yml中添加Logging Admin的地址,如下图:
  api:
boot:
# ApiBoot Logging 日志组件配置
<p>
logging:
# 配置Logging Admin地址
admin:
server-address: 127.0.0.1:8081</p>
  api.boot.logging.admin-service-address的配置格式为:Ip:Port。我们只需要修改这个地方,其他的工作交给ApiBoot Logging内部完成。
  测试
  我们以Application的形式启动ApiBoot Logging Admin和业务服务。
  使用 curl 访问测试地址如下:
  ~ curl http://localhost:8080/test\?name\=admin
你好:admin
  我们查看 ApiBoot Logging 管理控制台日志如下:
  Receiving Service: 【apiboot-unified-manage-request-logs -> 127.0.0.1】, Request Log Report,Logging Content:[
{
"endTime":1571641723779,
"httpStatus":200,
"requestBody":"",
"requestHeaders":{
"server-region":"JiNan",
"host":"localhost:8080",
"user-agent":"curl/7.64.1",
"accept":"*/*"
},
"requestIp":"0:0:0:0:0:0:0:1",
"requestMethod":"GET",
"requestParam":"{\"name\":\"admin\"}",
"requestUri":"/test",
"responseBody":"你好:admin",
"responseHeaders":{},
"serviceId":"apiboot-unified-manage-request-logs",
"serviceIp":"127.0.0.1",
"servicePort":"8080",
"spanId":"95a73ca0-831b-45df-aa43-2b5887e8d98d",
"startTime":1571641723776,
"timeConsuming":3,
"traceId":"25a7de96-b3dd-48e5-9854-1a8069a4a681"
}
]
  我们看到了Logging Admin console打印的report request log,不确定这个request的log是否已经存入数据库。接下来,我使用命令行查看数据库的日志信息。
  查看 loggingservicedetails 表中的数据
  mysql> select * from logging_service_details\G;
*************************** 1. row ***************************
lsd_id: b069366a-25dc-41ec-8f09-242d81755cd0
lsd_service_id: apiboot-unified-manage-request-logs
lsd_service_ip: 10.180.98.112
lsd_service_port: 8080
lsd_last_report_time: 2019-10-21 02:14:26
lsd_create_time: 2019-10-21 15:14:26
  logging_service_details 存储了上报请求日志的各个业务服务的基本信息。每个基本服务信息都会缓存在Logging Admin内存中,方便获取存放日志的service_id,根据ip端口service_id判断唯一性。保存一次。
  查看 loggingrequestlogs 表中的数据
  mysql> select * from logging_request_logs\G;
*************************** 1. row ***************************
lrl_id: c42761f6-b072-4744-8a17-d8e6097b85de
lrl_service_detail_id: b069366a-25dc-41ec-8f09-242d81755cd0
lrl_trace_id: 055329a0-cfc1-4606-baf0-4fb0cc905ba2
lrl_parent_span_id: NULL
lrl_span_id: aab83092-7749-4f88-8cb6-a949cc060197
lrl_start_time: 1571642065262
lrl_end_time: 1571642065286
lrl_http_status: 200
lrl_request_body:
lrl_request_headers: {"server-region":"JiNan","host":"localhost:8080","user-agent":"curl/7.64.1","accept":"*/*"}
lrl_request_ip: 0:0:0:0:0:0:0:1
lrl_request_method: GET
lrl_request_uri: /test
lrl_response_body: 你好:admin
lrl_response_headers: {}
lrl_time_consuming: 24
lrl_create_time: 2019-10-21 15:14:26
lrl_request_params: {"name":"admin"}
lrl_exception_stack: NULL
  敲黑板画重点
  在本章中,我们集成了ApiBoot Logging Admin,将业务服务的每个请求日志上报给Logging Admin,通过数据库保存请求日志,然后使用其他方法,可以通过spanId和traceId查看每个日志的日志-请求链路的从属关系和每个请求中耗时最多的span,可以准确优化服务性能。
  作者的个人博客
  使用开源框架ApiBoot,助你成为Api接口服务架构师
  总结:一篇文章看懂SEO,完整SEO优化方案,SEO是什么,网站如何进行SEO
  一篇文章文章了解SEO,完整的SEO优化方案,什么是SEO,网站怎么做SEO
  前言:今天的文章文章是我这几天写的最满意的一篇。之前一直在整理自己的想法,不是很满意。
  个人站长是个很努力的人,需要全方位的前端技术,要网站编辑、对外推广和数据分析。一个完整的网站应该从一开始就制作出来,后期的SEO推广部分也要考虑,这也是站长必备的技能。
  一个网站 SEO应该包括四个主要环节:网站前端制作、网站编辑、网站推广、数据分析。当然,这是一个笼统的说法。
  一、第一部分,前端制作。第一点,一个网站策划前期,要做好网站扁平化结构,各种辅助导航,内容页面需要有相关的文章建议,简短的页面结构,尽可能多的有效部分。网站代码优化第二点、robots文件、二级导航设置、404模板设置、301重定向、网站地图、图片Alt、标题标签、网站TDK、关键词密度、个体关键字密度、H1H2H3 中的关键字、关键字强调、向反向链接添加 nofollow、向页面添加元标记、丰富的片段(微数据、微格式和 RDFa)。
  
  第二部分,网站编辑工作。需要确定文章、原创或伪原创的来源,扫描的秘书、报纸、杂志等都可以作为文章的来源。然后是文章内容的写法,标题怎么写,关键词怎么布局,第一个描述性文章怎么写。何时何地添加什么样的长尾 关键词。内页的锚文本设置和图片的alt属性都是网站编辑的工作。
  第三部分是网站的SEO外推,即发送外链。外部链接强调高质量,不发送垃圾外部链接。外链的主要渠道包括:友情链接、博客、论坛、采集、黄页等,如果能发百度知道、百度文库、百度体验等,当然是最好的,对于国内的百度SEO,这是最重要的外部链接资源。
  
  第四部分是数据分析。流量统计工具看个人喜好,百度统计,CNZZ等,可以分析来源关键词,用户访问路径,用户热点击图等。第二点是竞争对手分析,分析竞争对手的关键词文章 写的,外部链接怎么发,关键词怎么设置,内部链接怎么布局,网站的结构是什么,文章是什么发布频率、网站结构等方面。
  综合阐述:一个网站最核心的SEO就是关键词的排名,所以关键词是一个很重要的工作,目标关键词,品牌关键词、核心关键词的选择&gt;、长尾关键词、长尾关键词的挖掘,需要挖掘什么样的长尾关键词,以及如何点击长尾 关键词。这里推荐几种常用的关键词挖矿方法,非常实用。百度索引、百度下拉框、百度相关搜索、百度知道、百度站长工具、各大SEO优化分析平台
  写到这里,已经完成了一个完善权缺的优化方案,能提到的点已经尽量提了,具体的实现还需要稍微完善一下。里面讲的东西的要点可以看的透彻,一些基础的SEO已经可以很厉害了。比较满意的文章结束了。接下来,我会写下每个实现的细节,敬请期待! 查看全部

  详细描述:将ApiBoot Logging采集的日志上报到Admin
  每个请求的详细信息可以通过 ApiBoot Logging 获取。在分布式部署方式中,一个请求可能会经过多个服务。如果每个服务独立保存请求日志信息,我们就无法实现统一控制。,并且会出现日志数据库和业务数据库不一致的情况(可能会使用多个数据源配置),因为这个问题,ApiBoot Logging提供了一个Admin概念,将客户端收到的每一条消息都转换成采集日志上报给管理员,管理员分析保存。
  创建一个日志管理项目
  由于ApiBoot Logging Admin可以汇总各个业务服务的请求日志(ApiBoot Logging),所以我们需要将各个业务服务采集订单的日志上报给Admin,所以应该独立部署。创建一个服务来专门采集请求日志并保存它们。
  初始化 Logging Admin 项目依赖项
  使用idea创建一个SpringBoot项目,pom.xml配置文件中的依赖如下:
  


org.springframework.boot
spring-boot-starter-web



org.minbox.framework
api-boot-starter-logging-admin



mysql
mysql-connector-java


com.zaxxer
HikariCP



org.minbox.framework
api-boot-starter-mybatis-enhance

  我们需要将采集的请求日志保存到数据库中,所以需要在项目中添加数据库驱动和数据库连接池相关的依赖。ApiBoot Logging Admin 通过 DataSource 操作数据,可以使用 ApiBoot MyBatis Enhance 的依赖。自动创建DataSource,摆脱手动创建,加入Spring IOC容器。
  添加 ApiBoot 统一版本依赖
  



org.minbox.framework
api-boot-dependencies
2.1.4.RELEASE
import
pom


  最新版本的 ApiBoot,请访问::api-boot-dependencies 查询。
  启用日志记录管理员
  添加 ApiBoot Logging Admin 依赖后,无法完全使用 Admin 功能。我们需要通过@EnableLoggingAdmin 注解来启用它,它会自动将Logging Admin 中需要的一些类注册到Spring IOC。将注解添加到入口类,如下所示:
  /**
* ApiBoot Logging Admin入口类
*/
@SpringBootApplication
@EnableLoggingAdmin
public class ApibootReportLogsByLoggingToAdminApplication {
public static void main(String[] args) {
SpringApplication.run(ApibootReportLogsByLoggingToAdminApplication.class, args);
}
}
  配置日志数据源
  application.yml配置文件中的数据源配置如下:
  # 服务名称
spring:
application:
name: apiboot-report-logs-by-logging-to-admin
# 数据源相关配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456
type: com.zaxxer.hikari.HikariDataSource
<p>
# 服务端口号
server:
port: 8081</p>
  控制台打印报告日志
  ApiBoot Logging Admin 可以通过配置文件控制是否将请求日志信息采集打印到控制台。在 application.yml 配置文件中添加以下内容:
  api:
boot:
logging:
# Logging Admin相关配置
admin:
# 控制台显示采集的日志信息
show-console-report-log: true
  注意:不要将此与 ApiBoot Logging 提供的 api.boot.logging.show-console-log 配置混淆。
  美化控制台打印的报表日志
  api:
boot:
logging:
# Logging Admin相关配置
admin:
# 控制台输出时美化采集到的日志
format-console-log-json: true
  注意:不要将此与 api.boot.logging.format-console-log-json 配置混淆。
  初始化日志表结构
  ApiBoot Logging Admin 使用固定的表结构来存储请求日志和服务信息。建表语句如下:
  SET NAMES utf8mb4 ;
--
-- Table structure for table `logging_request_logs`
--
CREATE TABLE `logging_request_logs` (
`lrl_id` varchar(36) COLLATE utf8mb4_general_ci NOT NULL COMMENT &#39;主键,UUID&#39;,
`lrl_service_detail_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;服务详情编号,关联logging_service_details主键&#39;,
`lrl_trace_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;链路ID&#39;,
`lrl_parent_span_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;上级跨度ID&#39;,
`lrl_span_id` varchar(36) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;跨度ID&#39;,
`lrl_start_time` mediumtext COLLATE utf8mb4_general_ci COMMENT &#39;请求开始时间&#39;,
`lrl_end_time` mediumtext COLLATE utf8mb4_general_ci COMMENT &#39;请求结束时间&#39;,
`lrl_http_status` int(11) DEFAULT NULL COMMENT &#39;请求响应状态码&#39;,
`lrl_request_body` longtext COLLATE utf8mb4_general_ci COMMENT &#39;请求主体内容&#39;,
`lrl_request_headers` text COLLATE utf8mb4_general_ci COMMENT &#39;请求头信息&#39;,
`lrl_request_ip` varchar(30) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;发起请求客户端的IP地址&#39;,
`lrl_request_method` varchar(10) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;请求方式&#39;,
`lrl_request_uri` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;请求路径&#39;,
`lrl_response_body` longtext COLLATE utf8mb4_general_ci COMMENT &#39;响应内容&#39;,
`lrl_response_headers` text COLLATE utf8mb4_general_ci COMMENT &#39;响应头信息&#39;,
`lrl_time_consuming` int(11) DEFAULT NULL COMMENT &#39;请求耗时&#39;,
`lrl_create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT &#39;日志保存时间&#39;,
`lrl_request_params` text COLLATE utf8mb4_general_ci,
`lrl_exception_stack` text COLLATE utf8mb4_general_ci,
PRIMARY KEY (`lrl_id`),
KEY `logging_request_logs_LRL_SERVICE_DETAIL_ID_index` (`lrl_service_detail_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT=&#39;请求日志信息表&#39;;
--
-- Table structure for table `logging_service_details`
--
CREATE TABLE `logging_service_details` (
`lsd_id` varchar(36) COLLATE utf8mb4_general_ci NOT NULL,
`lsd_service_id` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;上报服务的ID,对应spring.application.name配置值&#39;,
`lsd_service_ip` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT &#39;上报服务的IP地址&#39;,
`lsd_service_port` int(11) DEFAULT NULL COMMENT &#39;上报服务的端口号&#39;,
`lsd_last_report_time` timestamp NULL DEFAULT NULL COMMENT &#39;最后一次上报时间,每次上报更新&#39;,
`lsd_create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT &#39;首次上报时创建时间&#39;,
PRIMARY KEY (`lsd_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT=&#39;上报日志的客户端服务详情&#39;;
  到目前为止,ApiBoot Logging Admin 已准备就绪。接下来,我们需要修改业务服务,将请求日志上报给 Logging Admin。
  向指定的日志记录管理员报告日志
  我们将修改使用ApiBoot Logging统一管理请求日志的源码文章,在application.yml中添加Logging Admin的地址,如下图:
  api:
boot:
# ApiBoot Logging 日志组件配置
<p>
logging:
# 配置Logging Admin地址
admin:
server-address: 127.0.0.1:8081</p>
  api.boot.logging.admin-service-address的配置格式为:Ip:Port。我们只需要修改这个地方,其他的工作交给ApiBoot Logging内部完成。
  测试
  我们以Application的形式启动ApiBoot Logging Admin和业务服务。
  使用 curl 访问测试地址如下:
  ~ curl http://localhost:8080/test\?name\=admin
你好:admin
  我们查看 ApiBoot Logging 管理控制台日志如下:
  Receiving Service: 【apiboot-unified-manage-request-logs -> 127.0.0.1】, Request Log Report,Logging Content:[
{
"endTime":1571641723779,
"httpStatus":200,
"requestBody":"",
"requestHeaders":{
"server-region":"JiNan",
"host":"localhost:8080",
"user-agent":"curl/7.64.1",
"accept":"*/*"
},
"requestIp":"0:0:0:0:0:0:0:1",
"requestMethod":"GET",
"requestParam":"{\"name\":\"admin\"}",
"requestUri":"/test",
"responseBody":"你好:admin",
"responseHeaders":{},
"serviceId":"apiboot-unified-manage-request-logs",
"serviceIp":"127.0.0.1",
"servicePort":"8080",
"spanId":"95a73ca0-831b-45df-aa43-2b5887e8d98d",
"startTime":1571641723776,
"timeConsuming":3,
"traceId":"25a7de96-b3dd-48e5-9854-1a8069a4a681"
}
]
  我们看到了Logging Admin console打印的report request log,不确定这个request的log是否已经存入数据库。接下来,我使用命令行查看数据库的日志信息。
  查看 loggingservicedetails 表中的数据
  mysql> select * from logging_service_details\G;
*************************** 1. row ***************************
lsd_id: b069366a-25dc-41ec-8f09-242d81755cd0
lsd_service_id: apiboot-unified-manage-request-logs
lsd_service_ip: 10.180.98.112
lsd_service_port: 8080
lsd_last_report_time: 2019-10-21 02:14:26
lsd_create_time: 2019-10-21 15:14:26
  logging_service_details 存储了上报请求日志的各个业务服务的基本信息。每个基本服务信息都会缓存在Logging Admin内存中,方便获取存放日志的service_id,根据ip端口service_id判断唯一性。保存一次。
  查看 loggingrequestlogs 表中的数据
  mysql> select * from logging_request_logs\G;
*************************** 1. row ***************************
lrl_id: c42761f6-b072-4744-8a17-d8e6097b85de
lrl_service_detail_id: b069366a-25dc-41ec-8f09-242d81755cd0
lrl_trace_id: 055329a0-cfc1-4606-baf0-4fb0cc905ba2
lrl_parent_span_id: NULL
lrl_span_id: aab83092-7749-4f88-8cb6-a949cc060197
lrl_start_time: 1571642065262
lrl_end_time: 1571642065286
lrl_http_status: 200
lrl_request_body:
lrl_request_headers: {"server-region":"JiNan","host":"localhost:8080","user-agent":"curl/7.64.1","accept":"*/*"}
lrl_request_ip: 0:0:0:0:0:0:0:1
lrl_request_method: GET
lrl_request_uri: /test
lrl_response_body: 你好:admin
lrl_response_headers: {}
lrl_time_consuming: 24
lrl_create_time: 2019-10-21 15:14:26
lrl_request_params: {"name":"admin"}
lrl_exception_stack: NULL
  敲黑板画重点
  在本章中,我们集成了ApiBoot Logging Admin,将业务服务的每个请求日志上报给Logging Admin,通过数据库保存请求日志,然后使用其他方法,可以通过spanId和traceId查看每个日志的日志-请求链路的从属关系和每个请求中耗时最多的span,可以准确优化服务性能。
  作者的个人博客
  使用开源框架ApiBoot,助你成为Api接口服务架构师
  总结:一篇文章看懂SEO,完整SEO优化方案,SEO是什么,网站如何进行SEO
  一篇文章文章了解SEO,完整的SEO优化方案,什么是SEO,网站怎么做SEO
  前言:今天的文章文章是我这几天写的最满意的一篇。之前一直在整理自己的想法,不是很满意。
  个人站长是个很努力的人,需要全方位的前端技术,要网站编辑、对外推广和数据分析。一个完整的网站应该从一开始就制作出来,后期的SEO推广部分也要考虑,这也是站长必备的技能。
  一个网站 SEO应该包括四个主要环节:网站前端制作、网站编辑、网站推广、数据分析。当然,这是一个笼统的说法。
  一、第一部分,前端制作。第一点,一个网站策划前期,要做好网站扁平化结构,各种辅助导航,内容页面需要有相关的文章建议,简短的页面结构,尽可能多的有效部分。网站代码优化第二点、robots文件、二级导航设置、404模板设置、301重定向、网站地图、图片Alt、标题标签、网站TDK、关键词密度、个体关键字密度、H1H2H3 中的关键字、关键字强调、向反向链接添加 nofollow、向页面添加元标记、丰富的片段(微数据、微格式和 RDFa)。
  
  第二部分,网站编辑工作。需要确定文章、原创或伪原创的来源,扫描的秘书、报纸、杂志等都可以作为文章的来源。然后是文章内容的写法,标题怎么写,关键词怎么布局,第一个描述性文章怎么写。何时何地添加什么样的长尾 关键词。内页的锚文本设置和图片的alt属性都是网站编辑的工作。
  第三部分是网站的SEO外推,即发送外链。外部链接强调高质量,不发送垃圾外部链接。外链的主要渠道包括:友情链接、博客、论坛、采集、黄页等,如果能发百度知道、百度文库、百度体验等,当然是最好的,对于国内的百度SEO,这是最重要的外部链接资源。
  
  第四部分是数据分析。流量统计工具看个人喜好,百度统计,CNZZ等,可以分析来源关键词,用户访问路径,用户热点击图等。第二点是竞争对手分析,分析竞争对手的关键词文章 写的,外部链接怎么发,关键词怎么设置,内部链接怎么布局,网站的结构是什么,文章是什么发布频率、网站结构等方面。
  综合阐述:一个网站最核心的SEO就是关键词的排名,所以关键词是一个很重要的工作,目标关键词,品牌关键词、核心关键词的选择&gt;、长尾关键词、长尾关键词的挖掘,需要挖掘什么样的长尾关键词,以及如何点击长尾 关键词。这里推荐几种常用的关键词挖矿方法,非常实用。百度索引、百度下拉框、百度相关搜索、百度知道、百度站长工具、各大SEO优化分析平台
  写到这里,已经完成了一个完善权缺的优化方案,能提到的点已经尽量提了,具体的实现还需要稍微完善一下。里面讲的东西的要点可以看的透彻,一些基础的SEO已经可以很厉害了。比较满意的文章结束了。接下来,我会写下每个实现的细节,敬请期待!

优化的解决方案:API开发接口whatsapp采集工具之“好选客”

采集交流优采云 发表了文章 • 0 个评论 • 108 次浏览 • 2022-10-30 06:11 • 来自相关话题

  优化的解决方案:API开发接口whatsapp采集工具之“好选客”
  
  什么是APINet 这是一个用C#编写的API,但它可以在任何.NET语言中使用。它是WhatsAPINet的一个分支,基于WhatsAPI。这个分支的目标是让它再次工作并重构代码,添加文档并编写有关Whatsapp如何工作的文档。文档 FunXMPP 协议 - 协议 不幸的是,WhatsApp协议没有正式记录。在处理这个项目时,我将尝试将我的大部分进度记录在 docs 文件夹中。该协议基于基于 XML 的 XMPP 协议,这是一种记录严格的互联网消息传递协议。若要减少 XML 开销,请将 XML 结构和许多常用关键字转换为字节。有关更详细的说明,请参阅 docs/funxmpp .txt。不幸的是,XMPP标准并不是在所有地方都严格遵守。协议包装器:FunXMPP (见维基) 主协议:XMPP ( ) 身份验证
  
  解决方案:行业之星自助建站系统 osunit1.0 build20120905
  行业之星网站建站系统是一个多用户自助建站系统。它改变了以往企业网站建设的传统方式。它不需要企业编写任何程序或网页,不需要学习任何相关语言,也不需要第三方代表。编写或管理网站,只要会打字,就可以直接在线完成建站的所有工作。
  同时,系统为开源软件,客户可以随时要求第三方检查系统的安全性。
  行业之星免费开源多用户企业自助建站系统
  OSUnit V0.10 版本号:osunit1.020120905 下载&gt;&gt;
  特征:
  1、多用户自助建站系统(用户可申请自己的独立域名)
  2.日常维护栏和导航栏可以完全自定义
  3. 网站模板可编辑修改
  4.支持伪静态(需要apache环境)
  5. 将 文章 与产品相关联的 TAG
  6. 文章附属调查
  7、产品销售、经销商历史报价记录
  8. 经销商网站
  9. 品牌列表
  10、代理推广网站
  11.其他常规cms功能:发表评论、点赞、转发、图库
  12. 会员管理
  安装方法:
  
  1.上传文件到你需要安装的目录
  2.如果是linux系统修改
  config.inc.php 是 777 权限
  以下目录有 777 权限:
  图片 777
  模板 777
  主题 777
  数据 777
  3.执行简单的安装程序:******/install
  4.linux安装后修改data/config.inc.php为744权限
  5.如果要使用伪静态,请相应修改.htaccess文件对应的程序目录名
  apache启用伪静态方法:
  1.查看apache配置文件httpd.conf
  #LoadModule rewrite_module modules/mod_rewrite.so
  变成:
  LoadModule rewrite_module modules/mod_rewrite.so
  2. 虚拟主机
  服务器管理员
  DocumentRoot "e:/test"
  
  服务器名称
  服务器别名*。
  选项索引 FollowSymLinks
  允许覆盖所有
  命令允许,拒绝
  允许所有人
  其他说明:
  1.运行环境:php5+mysql
  2.字符集编码:utf8
  3.配置文件为:data/config.inc.php
  4.模板目录主题
  * 项目介绍:
  * ------------------------------------------------- --------------------------------------
  *版权归osunit所有,保留所有权利。
  * 网站地址:
  * ------------------------------------------------- --------------------------------------
  * 这是一个免费的开源软件;您可以在没有商业用途的情况下使用程序代码
  * 可能会被修改、使用和重新分发。 查看全部

  优化的解决方案:API开发接口whatsapp采集工具之“好选客”
  
  什么是APINet 这是一个用C#编写的API,但它可以在任何.NET语言中使用。它是WhatsAPINet的一个分支,基于WhatsAPI。这个分支的目标是让它再次工作并重构代码,添加文档并编写有关Whatsapp如何工作的文档。文档 FunXMPP 协议 - 协议 不幸的是,WhatsApp协议没有正式记录。在处理这个项目时,我将尝试将我的大部分进度记录在 docs 文件夹中。该协议基于基于 XML 的 XMPP 协议,这是一种记录严格的互联网消息传递协议。若要减少 XML 开销,请将 XML 结构和许多常用关键字转换为字节。有关更详细的说明,请参阅 docs/funxmpp .txt。不幸的是,XMPP标准并不是在所有地方都严格遵守。协议包装器:FunXMPP (见维基) 主协议:XMPP ( ) 身份验证
  
  解决方案:行业之星自助建站系统 osunit1.0 build20120905
  行业之星网站建站系统是一个多用户自助建站系统。它改变了以往企业网站建设的传统方式。它不需要企业编写任何程序或网页,不需要学习任何相关语言,也不需要第三方代表。编写或管理网站,只要会打字,就可以直接在线完成建站的所有工作。
  同时,系统为开源软件,客户可以随时要求第三方检查系统的安全性。
  行业之星免费开源多用户企业自助建站系统
  OSUnit V0.10 版本号:osunit1.020120905 下载&gt;&gt;
  特征:
  1、多用户自助建站系统(用户可申请自己的独立域名)
  2.日常维护栏和导航栏可以完全自定义
  3. 网站模板可编辑修改
  4.支持伪静态(需要apache环境)
  5. 将 文章 与产品相关联的 TAG
  6. 文章附属调查
  7、产品销售、经销商历史报价记录
  8. 经销商网站
  9. 品牌列表
  10、代理推广网站
  11.其他常规cms功能:发表评论、点赞、转发、图库
  12. 会员管理
  安装方法:
  
  1.上传文件到你需要安装的目录
  2.如果是linux系统修改
  config.inc.php 是 777 权限
  以下目录有 777 权限:
  图片 777
  模板 777
  主题 777
  数据 777
  3.执行简单的安装程序:******/install
  4.linux安装后修改data/config.inc.php为744权限
  5.如果要使用伪静态,请相应修改.htaccess文件对应的程序目录名
  apache启用伪静态方法:
  1.查看apache配置文件httpd.conf
  #LoadModule rewrite_module modules/mod_rewrite.so
  变成:
  LoadModule rewrite_module modules/mod_rewrite.so
  2. 虚拟主机
  服务器管理员
  DocumentRoot "e:/test"
  
  服务器名称
  服务器别名*。
  选项索引 FollowSymLinks
  允许覆盖所有
  命令允许,拒绝
  允许所有人
  其他说明:
  1.运行环境:php5+mysql
  2.字符集编码:utf8
  3.配置文件为:data/config.inc.php
  4.模板目录主题
  * 项目介绍:
  * ------------------------------------------------- --------------------------------------
  *版权归osunit所有,保留所有权利。
  * 网站地址:
  * ------------------------------------------------- --------------------------------------
  * 这是一个免费的开源软件;您可以在没有商业用途的情况下使用程序代码
  * 可能会被修改、使用和重新分发。

免费提供:免费wordpress采集发布管理器,操作极简

采集交流优采云 发表了文章 • 0 个评论 • 134 次浏览 • 2022-10-29 20:29 • 来自相关话题

  免费提供:免费wordpress采集发布管理器,操作极简
  wordpress资源下载管理器可以方便我们下载和管理公共开源数据。免费的wordpress资源下载管理器操作体验简单,只要点击我们需要的内容,无论是链接、图片、视频还是文字。都可以批量采集、批量编辑、批量发布或批量导出到本地。
  如果WordPress把我们喜欢的资源下载下来应用到我们自己的WordPress网站上,对于新闻和行业网站,我们可以根据行业关键词下载和管理全网文章。对于小说和影视,我们可以输入我们的目标网址,通过批量识别我们的下载链接或api进行爬取。方便的可视化操作让我们可以方便地管理我们的资源。
  WordPress资源下载管理器还具有批量图片处理、文章清理批量SEO等功能。拥有自己的WordPress网站可以有利于我们的推广工作,因为它让用户更容易发现我们在线业务。此外,它是一个有用的工具,可以在我们的行业中树立自己的名声并提高我们的转化率。WordPress网站 还使我们能够与我们的受众建立更加个性化的联系,并表明 网站 会定期更新内容。
  
  除了资源下载、文章SEO等数据文章获取处理功能,WordPress资源下载管理器还具有自动批量伪原创发布、主动链接推送到搜索引擎、内部链接抓取、内链收录查询等站长SEO功能。它不仅有利于我们优化 WordPress网站,还可以根据反馈数据实时调整我们的 SEO 实践。
  大多数网站 构建平台让我们只需单击一下即可为该网站 创建一个丰富的WordPress网站 页面,这意味着我们所要做的就是定期使用帖子并用图片填充它。如果我们想了解访问者对阅读的兴趣,我们需要对关键问题进行一些深入的研究。
  网络提供了各种免费的在线实用程序,例如搜索引擎趋势和公共问题的答案,它们显示了特定关键字的搜索量如何随时间变化。我们可以使用这些统计数据来确定哪些关键字应该在我们的 WordPress 网站 中获得最多的关注。
  
  来宾 WordPress 网站 涉及为其他 网站 撰写帖子,以将我们的品牌展示给新的受众,并通过创建从来宾帖子到我们的 网站 的反向链接来提升我们的 SEO。反向链接是有价值的 SEO 工具。因为它们向搜索引擎展示了其他 网站 认为我们是特定领域或行业的专家。
  寻找与我们领域相关的其他已建立的网站,研究每个 WordPress 上使用的语气网站选择您要撰写的 WordPress网站 后,您需要通过电子邮件或社交媒体进行连接跟他们。在我们撰写推介之前,最好阅读尽可能多的 WordPress网站 内容,以确保我们彼此非常适合并清楚地了解他们的写作风格。接下来,建议我们提出至少 3 个帖子创意发送给他们的编辑团队。每个想法都应该包括一个标题和一个 200 字的摘要。
  WordPress资源下载管理器可以方便的管理我们的WordPress,并且支持多个下载任务和每栏的自动更新。通过管理器可以实现同屏管理,快速更新网站的内容。wordpress资源下载管理器的分享就到这里了。如果你喜欢它,你不妨点击三个链接。
  解决方案:抖音商家采集软件
  如何快速轻松地采集抖音数据?
  抖音 数据采集软件PC版产品详细介绍
  1. 软件功能
  1. 基于抖音的公开数据采集。
  2.内置数据库保存采集数据,支持数十万数据,支持数据库中的重复数据删除,即采集到数据库的数据不会重复。
  3.多种采集算法,采集更多数据。
  
  4.数据记忆功能,意外关闭或下次打开时数据仍然存在。
  5.一键导出到CSV,EXCEL,VCF等文件。
  6.VCF文件可以导入手机通讯录,方便快捷。
  7.实时采集,而不是您自己的数据库。
  8.支持Windows操作系统,如Win7和Win10
  2. 使用帮助
  1. 点击 [登录抖音/快手]。
  2、点击登录,扫码登录抖音/快手。
  
  3. 单击关闭窗口。
  4. 点击主屏幕上的 [开始采集。
  5.关于防病毒软件的误报,
  由于软件保护,某些防病毒软件会出现误报,如拦截,请允许。建议使用火种安全。
  6.支持导出到VCF文件,
  VCF文件是标准的手机通讯录格式文件,可以导入到手机通讯录中。方法是通过QQ将VCF文件传输到手机上,点击打开VCF文件,选择用手机通讯录打开,根据提示导入。
  7. 搜索关键词最好是行业关键词。一次可以输入多个单词,每行一个单词,并且不能输入标点符号。 查看全部

  免费提供:免费wordpress采集发布管理器,操作极简
  wordpress资源下载管理器可以方便我们下载和管理公共开源数据。免费的wordpress资源下载管理器操作体验简单,只要点击我们需要的内容,无论是链接、图片、视频还是文字。都可以批量采集、批量编辑、批量发布或批量导出到本地。
  如果WordPress把我们喜欢的资源下载下来应用到我们自己的WordPress网站上,对于新闻和行业网站,我们可以根据行业关键词下载和管理全网文章。对于小说和影视,我们可以输入我们的目标网址,通过批量识别我们的下载链接或api进行爬取。方便的可视化操作让我们可以方便地管理我们的资源。
  WordPress资源下载管理器还具有批量图片处理、文章清理批量SEO等功能。拥有自己的WordPress网站可以有利于我们的推广工作,因为它让用户更容易发现我们在线业务。此外,它是一个有用的工具,可以在我们的行业中树立自己的名声并提高我们的转化率。WordPress网站 还使我们能够与我们的受众建立更加个性化的联系,并表明 网站 会定期更新内容。
  
  除了资源下载、文章SEO等数据文章获取处理功能,WordPress资源下载管理器还具有自动批量伪原创发布、主动链接推送到搜索引擎、内部链接抓取、内链收录查询等站长SEO功能。它不仅有利于我们优化 WordPress网站,还可以根据反馈数据实时调整我们的 SEO 实践。
  大多数网站 构建平台让我们只需单击一下即可为该网站 创建一个丰富的WordPress网站 页面,这意味着我们所要做的就是定期使用帖子并用图片填充它。如果我们想了解访问者对阅读的兴趣,我们需要对关键问题进行一些深入的研究。
  网络提供了各种免费的在线实用程序,例如搜索引擎趋势和公共问题的答案,它们显示了特定关键字的搜索量如何随时间变化。我们可以使用这些统计数据来确定哪些关键字应该在我们的 WordPress 网站 中获得最多的关注。
  
  来宾 WordPress 网站 涉及为其他 网站 撰写帖子,以将我们的品牌展示给新的受众,并通过创建从来宾帖子到我们的 网站 的反向链接来提升我们的 SEO。反向链接是有价值的 SEO 工具。因为它们向搜索引擎展示了其他 网站 认为我们是特定领域或行业的专家。
  寻找与我们领域相关的其他已建立的网站,研究每个 WordPress 上使用的语气网站选择您要撰写的 WordPress网站 后,您需要通过电子邮件或社交媒体进行连接跟他们。在我们撰写推介之前,最好阅读尽可能多的 WordPress网站 内容,以确保我们彼此非常适合并清楚地了解他们的写作风格。接下来,建议我们提出至少 3 个帖子创意发送给他们的编辑团队。每个想法都应该包括一个标题和一个 200 字的摘要。
  WordPress资源下载管理器可以方便的管理我们的WordPress,并且支持多个下载任务和每栏的自动更新。通过管理器可以实现同屏管理,快速更新网站的内容。wordpress资源下载管理器的分享就到这里了。如果你喜欢它,你不妨点击三个链接。
  解决方案:抖音商家采集软件
  如何快速轻松地采集抖音数据?
  抖音 数据采集软件PC版产品详细介绍
  1. 软件功能
  1. 基于抖音的公开数据采集。
  2.内置数据库保存采集数据,支持数十万数据,支持数据库中的重复数据删除,即采集到数据库的数据不会重复。
  3.多种采集算法,采集更多数据。
  
  4.数据记忆功能,意外关闭或下次打开时数据仍然存在。
  5.一键导出到CSV,EXCEL,VCF等文件。
  6.VCF文件可以导入手机通讯录,方便快捷。
  7.实时采集,而不是您自己的数据库。
  8.支持Windows操作系统,如Win7和Win10
  2. 使用帮助
  1. 点击 [登录抖音/快手]。
  2、点击登录,扫码登录抖音/快手。
  
  3. 单击关闭窗口。
  4. 点击主屏幕上的 [开始采集。
  5.关于防病毒软件的误报,
  由于软件保护,某些防病毒软件会出现误报,如拦截,请允许。建议使用火种安全。
  6.支持导出到VCF文件,
  VCF文件是标准的手机通讯录格式文件,可以导入到手机通讯录中。方法是通过QQ将VCF文件传输到手机上,点击打开VCF文件,选择用手机通讯录打开,根据提示导入。
  7. 搜索关键词最好是行业关键词。一次可以输入多个单词,每行一个单词,并且不能输入标点符号。

文章采集api 专业知识:API已改变SEO的玩法,不懂只能转行

采集交流优采云 发表了文章 • 0 个评论 • 148 次浏览 • 2022-10-29 10:23 • 来自相关话题

  文章采集api 专业知识:API已改变SEO的玩法,不懂只能转行
  作为一个有十三年经验的SEO司机,我经常想知道SEO的本质是什么?对于大多数 SEO 优化者来说,大多数人都理解 SEO = 外部链接 + 内容。其实这是一个很简单的理解,就是从一个非常低的角度来看待SEO工作。
  SEO的全称是Search Engine Optimization,帮助搜索引擎优化。SEO 正在帮助百度、谷歌和 360 改进他们的内容。从这个角度思考,你会发现SEO其实是一个伟大的事业,而不是白天和黑夜。交换链接和 伪原创。
  搜索引擎是怎么来的?
  互联网刚出现时,每台计算机都是一个信息孤岛。为了让这些岛屿上的信息更快被查询到,一些聪明人编写了一个简单的爬虫程序,对分布在网络中各种计算机上的文件进行索引。然后通过一个简单的搜索框,用户可以快速搜索孤岛信息,造福人类。
  搜索引擎最怕什么?
  我最怕我的用户找不到他们想要的结果。我希望尽可能的从各个信息孤岛中找到用户可能感兴趣的内容,并不断地把它们放入我自己的索引中。下次用户搜索时,他们可以非常满意地离开。
  SEO从业者是帮助搜索引擎优化的人。这并不意味着他们每天都会产生无数的垃圾邮件。这并不意味着每天建立无数的友好链接对其有帮助,而是帮助搜索引擎解决他们的实际问题。你觉得很棒吗?
  如果你不能认识到这一点,你可能无法适应SEO优化领域。现在不是狂野的早期时代,如果你一直依赖链接和伪原创,你只会有一种感觉,SEO真的不是人做的!
  我们怎样才能做得更好?
  1.拥有最全面准确的行业词库
  当我们操作某个网站或者专栏的时候,往往是垂直于一个行业的。每个行业都有自己的范围。一般来说,每个行业都有自己的一组核心关键词+长尾词。这些词定义了一个行业的范围,所以它有一个行业词库是全面掌握一个行业的必备品。
  例如,围绕金融行业的核心词如下:
  金融行业核心词下的长尾词列表如下:
  2. 使用词库找出搜索引擎最需要什么
  当我们掌握了一个行业的所有词汇时,我们才能真正了解这个行业以及这个行业用户的需求。
  接下来,我们需要在这近百万的金融词库中,找到能够带来最多流量的词。这里我们使用百度PC Index、360 Index、Baidu Mobile Index、Bid Planner PC Search Volume、Bid Planner Mobile Search Quantity、Bid Planner Competition:
  
  通过上面的公式,我们可以筛选出一批行业内能带来最多流量的词,从百万词库中筛选出104635个流量词。
  3.通过API关键词过滤掉搜索引擎最缺乏的内容
  将上面筛选出来的104635个流量词放到百度、360等搜索引擎中进行模拟查询,了解排名前20的网页的URL等级和标题,了解搜索引擎内容是否饱和.
  通过API商城中的百度PC TOP 50排名API(),我们可以轻松获取JSON格式的排名。
  下图中,我们以“什么是指数基金”一词为例,获取TOP20搜索结果的排名:
  返回的排名信息中有两种重要信息,域名权限信息和标题信息。
  域名权限信息代表前50名的域名是否都是权限比较低的域名,让你有机会挤进去。
  对Title信息的分析是指互联网上这个关键词的内容是否饱和,还是因为百度为了填写信息选择了一些补充信息来填充搜索结果。
  通过分析这两条信息,我们可以判断这个关键词是否值得优先做。
  让我们在这里做一个假设。如果我的网站5118权重是A,那么我们需要找出TOP20排名结果中是否有很多5118权重B级甚至C级网站排名结果。如果有那么我们还有机会占据他们的位置。
  另外还有一种情况,如果通过域名找不到机会,还有另一种机会,就是这些高权限域名的内容不完全符合搜索要求,也就是说,有些结果中的内容标题与 关键词 不完全匹配。
  比如上图中的Title中并没有完全收录“什么是指数基金”这个词,而只是搜索引擎为了补充结果而放置的一个索引,所以我们也可以将这些位置标记为机会。
  通过与上述类似的算法,我们可以得到每个单词的机会得分。我们可以设置一个筛选阈值,例如设置为 8。如果 TOP 20 的结果中有超过 8 个有机会,我们将这些 关键词 保留并进入第 4 阶段。
  4.帮助搜索引擎改进这些内容
  当我们通过前三步完成了性价比最高的SEO关键词的筛选后,可以安排编辑写文章或者专题,或者安排技术部进行文章采集,或者安排运营部门指导用户创作内容。
  通过这四个步骤的层层过滤,我们的内容运营工作会很有针对性。上面虽然写了这么多字,其实就是以下三个目的:
  
  5. 监控 SEO 表现
  随着内容的不断完善,我们需要对上面确定的内容策略的有效性进行整体评估,可能需要对一些参数、阈值甚至算法进行微调:
  因为只有监控这些参数才能知道你的内容创建后百度爬虫是否如期到达,没有遇到任何障碍,从而保证你的内容策略不会因为其他技术操作的干扰而失效和维护因素。
  收录 是排名的前提。如果内容不能为收录,爬更多爬虫就没意义了。如果内容不产生收录,也会对内容策略造成打击,所以收录的监控也很关键。
  随着内容和收录的不断增长,我们SEO的最终目标是获得好的排名。
  跟踪整体大趋势,以确保整体内容策略处于正确轨道上。
  2. 监控个人 关键词 排名以评估每个内容制作工作的稳定性,并注意细节。
  ▲ 可以使用5118关键词监控批量添加自己关键词进行监控
  ▲ 也可以使用 5118关键词ranking采集API 进行监控
  最后总结:
  现代人类文明的发展是一个追求极致自动化的过程。大数据时代的无人工厂、无人超市、无人机、SEO管理者也必须追求SEO自动化,与时俱进,实现自我突破。
  通过这样的内容生产过程,我们可以逐步优化我们的内容策略,最大限度地发挥内容生产流量的效果。还等什么,赶快使用这些大数据API,让你的推广变得轻松。
  5118,尽享神级运营视野
  更多API详情请访问5118官网!
  教程:网站内容批量更新有什么影响,好不好?
  网站海量更新内容有什么影响?做网站SEO优化的站长都知道网站内容更新是很重要的一环。对于搜索引擎和用户来说,他们也喜欢那些更新频率比较高的内容网站。那么,我们 网站 批量添加大量内容怎么样?它如何影响搜索引擎优化?
  网站的异常更新很容易引起搜索引擎的注意,即成为搜索引擎排查的重点,包括批量更新。至于影响,我们需要看不同的情况。
  网站高质量内容批量更新
  
  优质内容具有三个特点:具有一定的搜索需求和创意,内容质量相对稀缺,是行业热门话题,与历史内容相比不存在重复。有人说“内容为王”。我们知道搜索引擎喜欢这样高质量的内容。如果在短时间内添加这样的内容,即使数量很大,也会对搜索引擎非常友好和受欢迎。因此,有利于网站的优化,可以说是正面的影响。
  网站批量更新低质量内容
  对于低质量的内容,可能是自动采集或采集的内容,与历史内容重复率高,质量较差,也可能是软件自动生成,可读性差。在这两种情况下,内容更新都是搜索引擎不喜欢的,也很难在任何时候都有好的排名。如果网站突然添加很多这样的内容,对网站的优化是非常不利的,很可能会被搜索引擎惩罚。比如新站点批量更新低质量内容,就会进入沙盒期,审核时间会更长;而网站批量更新其他时段的低质量内容,会导致收录下降,网站权重和排名下降等。
  
  网站批量更新伪原创的内容
  这里提到的伪原创可能是由伪原创工具生成的,也可能是拼凑而成的。因此,伪原创 不是 100%原创,但它确实具有一些 原创 属性。对于批量更新等内容,可能的结果是优化效果先平稳上升,然后逐渐下降。因为,当你的网站质量达到一定的门槛时,搜索引擎就会开始审查内容的广度,逐步回归内容的质量。因此,如果你继续更新这样的伪原创,你也可能会受到搜索引擎的惩罚。
  综上所述,网站批量更新内容有利有弊,但其影响和效果取决于内容的质量。所以对于网站的内容更新,还是要注意内容的质量。只有保持优质内容的稳定更新,才会更有利于网站的排名。 查看全部

  文章采集api 专业知识:API已改变SEO的玩法,不懂只能转行
  作为一个有十三年经验的SEO司机,我经常想知道SEO的本质是什么?对于大多数 SEO 优化者来说,大多数人都理解 SEO = 外部链接 + 内容。其实这是一个很简单的理解,就是从一个非常低的角度来看待SEO工作。
  SEO的全称是Search Engine Optimization,帮助搜索引擎优化。SEO 正在帮助百度、谷歌和 360 改进他们的内容。从这个角度思考,你会发现SEO其实是一个伟大的事业,而不是白天和黑夜。交换链接和 伪原创
  搜索引擎是怎么来的?
  互联网刚出现时,每台计算机都是一个信息孤岛。为了让这些岛屿上的信息更快被查询到,一些聪明人编写了一个简单的爬虫程序,对分布在网络中各种计算机上的文件进行索引。然后通过一个简单的搜索框,用户可以快速搜索孤岛信息,造福人类。
  搜索引擎最怕什么?
  我最怕我的用户找不到他们想要的结果。我希望尽可能的从各个信息孤岛中找到用户可能感兴趣的内容,并不断地把它们放入我自己的索引中。下次用户搜索时,他们可以非常满意地离开。
  SEO从业者是帮助搜索引擎优化的人。这并不意味着他们每天都会产生无数的垃圾邮件。这并不意味着每天建立无数的友好链接对其有帮助,而是帮助搜索引擎解决他们的实际问题。你觉得很棒吗?
  如果你不能认识到这一点,你可能无法适应SEO优化领域。现在不是狂野的早期时代,如果你一直依赖链接和伪原创,你只会有一种感觉,SEO真的不是人做的!
  我们怎样才能做得更好?
  1.拥有最全面准确的行业词库
  当我们操作某个网站或者专栏的时候,往往是垂直于一个行业的。每个行业都有自己的范围。一般来说,每个行业都有自己的一组核心关键词+长尾词。这些词定义了一个行业的范围,所以它有一个行业词库是全面掌握一个行业的必备品。
  例如,围绕金融行业的核心词如下:
  金融行业核心词下的长尾词列表如下:
  2. 使用词库找出搜索引擎最需要什么
  当我们掌握了一个行业的所有词汇时,我们才能真正了解这个行业以及这个行业用户的需求。
  接下来,我们需要在这近百万的金融词库中,找到能够带来最多流量的词。这里我们使用百度PC Index、360 Index、Baidu Mobile Index、Bid Planner PC Search Volume、Bid Planner Mobile Search Quantity、Bid Planner Competition:
  
  通过上面的公式,我们可以筛选出一批行业内能带来最多流量的词,从百万词库中筛选出104635个流量词。
  3.通过API关键词过滤掉搜索引擎最缺乏的内容
  将上面筛选出来的104635个流量词放到百度、360等搜索引擎中进行模拟查询,了解排名前20的网页的URL等级和标题,了解搜索引擎内容是否饱和.
  通过API商城中的百度PC TOP 50排名API(),我们可以轻松获取JSON格式的排名。
  下图中,我们以“什么是指数基金”一词为例,获取TOP20搜索结果的排名:
  返回的排名信息中有两种重要信息,域名权限信息和标题信息。
  域名权限信息代表前50名的域名是否都是权限比较低的域名,让你有机会挤进去。
  对Title信息的分析是指互联网上这个关键词的内容是否饱和,还是因为百度为了填写信息选择了一些补充信息来填充搜索结果。
  通过分析这两条信息,我们可以判断这个关键词是否值得优先做。
  让我们在这里做一个假设。如果我的网站5118权重是A,那么我们需要找出TOP20排名结果中是否有很多5118权重B级甚至C级网站排名结果。如果有那么我们还有机会占据他们的位置。
  另外还有一种情况,如果通过域名找不到机会,还有另一种机会,就是这些高权限域名的内容不完全符合搜索要求,也就是说,有些结果中的内容标题与 关键词 不完全匹配。
  比如上图中的Title中并没有完全收录“什么是指数基金”这个词,而只是搜索引擎为了补充结果而放置的一个索引,所以我们也可以将这些位置标记为机会。
  通过与上述类似的算法,我们可以得到每个单词的机会得分。我们可以设置一个筛选阈值,例如设置为 8。如果 TOP 20 的结果中有超过 8 个有机会,我们将这些 关键词 保留并进入第 4 阶段。
  4.帮助搜索引擎改进这些内容
  当我们通过前三步完成了性价比最高的SEO关键词的筛选后,可以安排编辑写文章或者专题,或者安排技术部进行文章采集,或者安排运营部门指导用户创作内容。
  通过这四个步骤的层层过滤,我们的内容运营工作会很有针对性。上面虽然写了这么多字,其实就是以下三个目的:
  
  5. 监控 SEO 表现
  随着内容的不断完善,我们需要对上面确定的内容策略的有效性进行整体评估,可能需要对一些参数、阈值甚至算法进行微调:
  因为只有监控这些参数才能知道你的内容创建后百度爬虫是否如期到达,没有遇到任何障碍,从而保证你的内容策略不会因为其他技术操作的干扰而失效和维护因素。
  收录 是排名的前提。如果内容不能为收录,爬更多爬虫就没意义了。如果内容不产生收录,也会对内容策略造成打击,所以收录的监控也很关键。
  随着内容和收录的不断增长,我们SEO的最终目标是获得好的排名。
  跟踪整体大趋势,以确保整体内容策略处于正确轨道上。
  2. 监控个人 关键词 排名以评估每个内容制作工作的稳定性,并注意细节。
  ▲ 可以使用5118关键词监控批量添加自己关键词进行监控
  ▲ 也可以使用 5118关键词ranking采集API 进行监控
  最后总结:
  现代人类文明的发展是一个追求极致自动化的过程。大数据时代的无人工厂、无人超市、无人机、SEO管理者也必须追求SEO自动化,与时俱进,实现自我突破。
  通过这样的内容生产过程,我们可以逐步优化我们的内容策略,最大限度地发挥内容生产流量的效果。还等什么,赶快使用这些大数据API,让你的推广变得轻松。
  5118,尽享神级运营视野
  更多API详情请访问5118官网!
  教程:网站内容批量更新有什么影响,好不好?
  网站海量更新内容有什么影响?做网站SEO优化的站长都知道网站内容更新是很重要的一环。对于搜索引擎和用户来说,他们也喜欢那些更新频率比较高的内容网站。那么,我们 网站 批量添加大量内容怎么样?它如何影响搜索引擎优化?
  网站的异常更新很容易引起搜索引擎的注意,即成为搜索引擎排查的重点,包括批量更新。至于影响,我们需要看不同的情况。
  网站高质量内容批量更新
  
  优质内容具有三个特点:具有一定的搜索需求和创意,内容质量相对稀缺,是行业热门话题,与历史内容相比不存在重复。有人说“内容为王”。我们知道搜索引擎喜欢这样高质量的内容。如果在短时间内添加这样的内容,即使数量很大,也会对搜索引擎非常友好和受欢迎。因此,有利于网站的优化,可以说是正面的影响。
  网站批量更新低质量内容
  对于低质量的内容,可能是自动采集或采集的内容,与历史内容重复率高,质量较差,也可能是软件自动生成,可读性差。在这两种情况下,内容更新都是搜索引擎不喜欢的,也很难在任何时候都有好的排名。如果网站突然添加很多这样的内容,对网站的优化是非常不利的,很可能会被搜索引擎惩罚。比如新站点批量更新低质量内容,就会进入沙盒期,审核时间会更长;而网站批量更新其他时段的低质量内容,会导致收录下降,网站权重和排名下降等。
  
  网站批量更新伪原创的内容
  这里提到的伪原创可能是由伪原创工具生成的,也可能是拼凑而成的。因此,伪原创 不是 100%原创,但它确实具有一些 原创 属性。对于批量更新等内容,可能的结果是优化效果先平稳上升,然后逐渐下降。因为,当你的网站质量达到一定的门槛时,搜索引擎就会开始审查内容的广度,逐步回归内容的质量。因此,如果你继续更新这样的伪原创,你也可能会受到搜索引擎的惩罚。
  综上所述,网站批量更新内容有利有弊,但其影响和效果取决于内容的质量。所以对于网站的内容更新,还是要注意内容的质量。只有保持优质内容的稳定更新,才会更有利于网站的排名。

技巧:WordPress文章内容管理器:实现网站全过程管理

采集交流优采云 发表了文章 • 0 个评论 • 59 次浏览 • 2022-10-28 21:20 • 来自相关话题

  技巧:WordPress文章内容管理器:实现网站全过程管理
  WordPress文章内容更新是SEO中最焦虑的事情。每天高质量发布 WordPress文章 内容是一件苦差事。
  我们知道搜索引擎会通过蜘蛛抓取我们每日更新的 URL。搜索引擎会根据蜘蛛爬取的url分析我们的WordPress网站的更新频率和文章的内容质量,从而判断是否收录并给出关键词排名,所以维护我们的WordPress网站定期更新和文章内容优化是一项重要的工作。
  WordPress文章内容管理器可以轻松管理工作流程并以有效的格式组织文章内容。通过定时采集发布功能,实现网站的全流程管理,利用内置翻译api和文章SEO编辑模块实现的优化管理文章 内容
  WordPress文章内容管理器通过可视化操作面板实现对网站文章内容管理的简单管理,无需学习正则表达式即可完成全网文章内容采集. 内置的展示模块可以让我们设置发布模板,根据我们的需求发布我们的文章内容,批量网站标题、文章内容和文章属性优化发布.
  
  然而,只有少数人知道 WordPress文章 内容管理器不仅仅是一台服务器,在过去的几年里,WordPress文章 内容管理器已经开发了多台服务器,现在都可以使用在一个单独的包中使用。这些编辑器为用户提供了轻松创建自定义发布设置、自定义发布流程和改进整体流程的工具。我们可以用 WordPress文章Content Manager 做的一些事情包括:
  1.管理我们对网站的文章内容编辑,并向我们展示编辑前后的状态。
  2. 同一篇博文有多个作者;
  3、根据现场要求保留相关的文章标签和图片水印;
  4. 在 网站 上为我们创建不同的发布模板,使每个 文章 内容遵循相似的模式。
  
  WordPress文章内容管理器修订者。它允许我们提交、审查、讨论和安排修订。假设我们的一位作家编写 文章 内容并在 WordPress 之上起草。我们可以添加修订并将其分配给作者进行编辑。这使我们可以更轻松地编辑和发布 文章 内容,同时保留在 网站 仪表板上。编辑它,然后在平台上可用时将文档导入 WordPress。
  网站更新如果我们是 WordPress 博客作者或我 WordPress网站所有者正在寻找一个 文章 内容管理系统,可以简化我们的 网站文章 内容,WordPress文章内容管理器是我们不能忽视的。
  WordPress文章Content Manager 将我们的 网站文章 内容管理从 网站 管理解决方案转变为时间管理。仅通过时间跟踪和待办事项列表软件才能实现的功能现在可以在 WordPress 中实现。
  WordPress文章内容管理器对我们的网站文章内容管理提供了一定的帮助,并且在不断的优化中。通过不断的api访问,将是我们的网站文章内容管理。网站全流程自动化管理的趋势。这就是 WordPress文章 内容管理的共享。如果你喜欢它,请喜欢它。
  技术文章:SEO伪原创文章怎么能批量生成?
  文章的稳定性,有很多公司在使用我们的批量SEO伪原创文章,适用于大部分职业,可以放心。一些地方的操作也比较复杂。有能力的可以去测试一下,作为公司也可以找我们合作。下面说一下详细的批处理伪原创流程,大概有几个流程。
  1. 采集数据
  这个应该没问题,操作比较简单,采集数据的软件也很多。应该可以做一点研究。一般扩展功能需要付费,但基本功能一般可以满足小站的需求。你可以测试一下。如果你做不到,你可以找我们。我们也有 傻瓜式 和定制的。
  2.按关键词分类
  很多网络软件支持导出txt格式采集数据,有的只能导出excel格式的数据,不过没关系,我们可以批量从excel导出为txt格式,然后按照词库分类,根据将选定的关键词库分类到文件夹中,为下一步做准备。需要注意的一点是,所有采集到的数据都是在采集后进行处理,将不相关的文本、超链接等无用的文本导出进行分类。
  
  3. 过道、清扫
  分类后,就是准备洗稿了。第一阶段被打乱,都被同类型选中。因此,当您将它们分段组合时,您不必担心平滑度。选择操作有点乱。混沌关卡相互交叉,随机打乱,可以随机组合召唤。
  4. 语义分词处理
  这个操作也是需要软件的,但是处理的方法和市面上的网上SEO伪原创的东西不太一样。一个关键词可以出很多文章文章,形体字不一样。不一样,但意思是一样的,就是这样。
  5、排版
  批量排版没什么好说的。一般来说,就是将代码插入到stage中形成批量排版,然后导出成大型HTML格式文章,类似这样
  
  然后分批发布到网站。以上就是批处理高质量SEO伪原创文章的方法,也就是我们常说的洗稿,批处理伪原创,我们选择处理方法比较复杂,但必须保证质量。
  Growthman Growthman 专注于为企业提供数字营销服务。成长超人作为营销成长、高端网站建设、网站制作公司,先后为富士康、钉钉、泰菱、天虹、爱尔眼科、海澜集团、金蝶、飞亚达、云米等知名企业提供专业成长服务。
  官方网站: 查看全部

  技巧:WordPress文章内容管理器:实现网站全过程管理
  WordPress文章内容更新是SEO中最焦虑的事情。每天高质量发布 WordPress文章 内容是一件苦差事。
  我们知道搜索引擎会通过蜘蛛抓取我们每日更新的 URL。搜索引擎会根据蜘蛛爬取的url分析我们的WordPress网站的更新频率和文章的内容质量,从而判断是否收录并给出关键词排名,所以维护我们的WordPress网站定期更新和文章内容优化是一项重要的工作。
  WordPress文章内容管理器可以轻松管理工作流程并以有效的格式组织文章内容。通过定时采集发布功能,实现网站的全流程管理,利用内置翻译api和文章SEO编辑模块实现的优化管理文章 内容
  WordPress文章内容管理器通过可视化操作面板实现对网站文章内容管理的简单管理,无需学习正则表达式即可完成全网文章内容采集. 内置的展示模块可以让我们设置发布模板,根据我们的需求发布我们的文章内容,批量网站标题、文章内容和文章属性优化发布.
  
  然而,只有少数人知道 WordPress文章 内容管理器不仅仅是一台服务器,在过去的几年里,WordPress文章 内容管理器已经开发了多台服务器,现在都可以使用在一个单独的包中使用。这些编辑器为用户提供了轻松创建自定义发布设置、自定义发布流程和改进整体流程的工具。我们可以用 WordPress文章Content Manager 做的一些事情包括:
  1.管理我们对网站的文章内容编辑,并向我们展示编辑前后的状态。
  2. 同一篇博文有多个作者;
  3、根据现场要求保留相关的文章标签和图片水印;
  4. 在 网站 上为我们创建不同的发布模板,使每个 文章 内容遵循相似的模式。
  
  WordPress文章内容管理器修订者。它允许我们提交、审查、讨论和安排修订。假设我们的一位作家编写 文章 内容并在 WordPress 之上起草。我们可以添加修订并将其分配给作者进行编辑。这使我们可以更轻松地编辑和发布 文章 内容,同时保留在 网站 仪表板上。编辑它,然后在平台上可用时将文档导入 WordPress。
  网站更新如果我们是 WordPress 博客作者或我 WordPress网站所有者正在寻找一个 文章 内容管理系统,可以简化我们的 网站文章 内容,WordPress文章内容管理器是我们不能忽视的。
  WordPress文章Content Manager 将我们的 网站文章 内容管理从 网站 管理解决方案转变为时间管理。仅通过时间跟踪和待办事项列表软件才能实现的功能现在可以在 WordPress 中实现。
  WordPress文章内容管理器对我们的网站文章内容管理提供了一定的帮助,并且在不断的优化中。通过不断的api访问,将是我们的网站文章内容管理。网站全流程自动化管理的趋势。这就是 WordPress文章 内容管理的共享。如果你喜欢它,请喜欢它。
  技术文章:SEO伪原创文章怎么能批量生成?
  文章的稳定性,有很多公司在使用我们的批量SEO伪原创文章,适用于大部分职业,可以放心。一些地方的操作也比较复杂。有能力的可以去测试一下,作为公司也可以找我们合作。下面说一下详细的批处理伪原创流程,大概有几个流程。
  1. 采集数据
  这个应该没问题,操作比较简单,采集数据的软件也很多。应该可以做一点研究。一般扩展功能需要付费,但基本功能一般可以满足小站的需求。你可以测试一下。如果你做不到,你可以找我们。我们也有 傻瓜式 和定制的。
  2.按关键词分类
  很多网络软件支持导出txt格式采集数据,有的只能导出excel格式的数据,不过没关系,我们可以批量从excel导出为txt格式,然后按照词库分类,根据将选定的关键词库分类到文件夹中,为下一步做准备。需要注意的一点是,所有采集到的数据都是在采集后进行处理,将不相关的文本、超链接等无用的文本导出进行分类。
  
  3. 过道、清扫
  分类后,就是准备洗稿了。第一阶段被打乱,都被同类型选中。因此,当您将它们分段组合时,您不必担心平滑度。选择操作有点乱。混沌关卡相互交叉,随机打乱,可以随机组合召唤。
  4. 语义分词处理
  这个操作也是需要软件的,但是处理的方法和市面上的网上SEO伪原创的东西不太一样。一个关键词可以出很多文章文章,形体字不一样。不一样,但意思是一样的,就是这样。
  5、排版
  批量排版没什么好说的。一般来说,就是将代码插入到stage中形成批量排版,然后导出成大型HTML格式文章,类似这样
  
  然后分批发布到网站。以上就是批处理高质量SEO伪原创文章的方法,也就是我们常说的洗稿,批处理伪原创,我们选择处理方法比较复杂,但必须保证质量。
  Growthman Growthman 专注于为企业提供数字营销服务。成长超人作为营销成长、高端网站建设、网站制作公司,先后为富士康、钉钉、泰菱、天虹、爱尔眼科、海澜集团、金蝶、飞亚达、云米等知名企业提供专业成长服务。
  官方网站:

秘密:一文读懂数据仓库、数据平台、数据中台、数据湖的概念和区别

采集交流优采云 发表了文章 • 0 个评论 • 59 次浏览 • 2022-10-28 08:34 • 来自相关话题

  秘密:一文读懂数据仓库、数据平台、数据中台、数据湖的概念和区别
  在数据仓库、数据平台、数据中台、数据湖的相关概念中,都与数据相关,但它们之间有什么区别呢?本文介绍了它们的概念、架构和使用场景。让我们来看看。
  我们经常听到人们谈论数据仓库、数据平台、数据中心和数据湖的概念。它们都与数据有关,但它们之间有什么区别?下面我们将重点介绍数据仓库、数据平台和数据湖。介绍数据中心的概念、架构和使用场景。
  一、数据仓库 一、数据仓库概念
  数据仓库由 Bill Inmon(数据仓库之父)于 1990 年提出,其主要功能是存储大量数据,这些数据是企业系统中在线事务处理(OLTP)的长期障碍,并支持数据仓库理论所持有的数据存储。结构,做系统的分析和整理。
  随着企业的发展,业务系统的数据不断激增,存储在企业业务数据库(即关系型数据库Oracle、Microsoft SQL Server、MySQL等)中的数据会越来越多时间,这会使业务数据库有一定的负载,导致业务系统运行效率低下,而这个数据很大一部分是冷数据,而我们的业务系统一般会调用我们最近的数据,也就是热数据数据,更频繁,冷数据被更频繁地调用。减少使用频率。
  同时,随着企业数据驱动业务理念的兴起,企业需要提取各业务部门的业务数据进行数据分析挖掘,辅助高层分析决策。数据查询脚本和接口的访问降低了业务数据库的稳定性。
  为了避免冷数据和历史数据的积压对我们业务数据库性能的影响,企业需要定期从业务数据库中调出冷数据,并存放在专门用于存储历史数据的仓库中。各部门可根据自身业务特点提供统一的对外服务。数据服务,这个仓库就是数据仓库。
  2. 数据仓库功能
  数据仓库(Data Warehoese)的特点:面向主题、集成化、稳定、反映历史数据变化。
  3.OLTP和OLAP
  1) OLTP 和 OLAP 概念
  数据处理大致可以分为两类:在线事务处理OLTP(on-line transaction processing),在线分析处理OLAP(On-Line Analytical Processing)。
  OLTP 是传统关系型数据库的主要应用,主要用于基本的、日常的事务处理,例如银行交易。OLAP是数据仓库系统的主要应用,支持复杂的分析操作,注重决策支持,提供直观易懂的查询结果。
  2)OLTP和OLAP的区别
  OLTP系统强调数据库内存效率,强调内存、绑定变量、并发操作等各项指标的指挥率。OLAP 系统强调数据分析、SQL 执行市场、磁盘 I/O、分区等。
  3)OLAP与数据仓库的连接
  OLAP与数据仓库的关系依赖于互补性,一般以数据仓库为基础,即从数据仓库中提取详细数据的子集,通过必要的聚合存储在OLAP存储中,供数据分析工具读取。
  4.数据仓库的作用
  数据仓库聚合来自不同来源的结构化数据,以便在商业智能领域进行比较和分析。数据仓库是一个收录各种数据并且高度建模的存储库。
  如下图所示: 各个系统的元数据通过ETL同步到运营数据仓库ODS,ODS数据进行面向主题、面向领域的建模,形成DW(数据仓库)。DM就是为某个业务领域建立模型。决策层)查看DM生成的报告。
  什么是 ETL?(提取-转换-加载提取-转换-加载)
  传统的数据仓库集成处理架构是ETL,利用ETL平台的能力,E=从源数据库提取数据,L=清洗数据(不符合规则的数据),转换(表受根据业务需求不同维度、不同粒度)程度,计算不同的业务规则进行统计),T = 将处理后的表以增量、全量、不同时间加载到数据仓库中。
  什么是 ELT?(提取-加载-变换提取-加载-变换)
  大数据背景下的架构体系是ELT结构,根据上层的应用需求,随时从数据中心提取出需要的原创数据进行建模分析。
  ELT利用数据库的处理能力,E=从源数据库中提取数据,L=将数据加载到目标数据库的临时表中,T=对临时表中的数据进行变换,然后加载到目标表中的目标数据库。
  ELT 相对于 ETL 的优势:
  数据仓库系统的作用可以实现跨业务线、跨系统的数据集成,为管理分析和业务决策提供统一的数据支持。数据仓库可以从根本上帮助您将公司的运营数据转换为高价值的可访问信息(或知识),并在正确的时间以正确的方式将正确的信息传递给正确的人。下图是一个例子:
  数据仓库的作用主要体现在企业决策、分析、规划和响应的以下几个方面:
  
  数据仓库在实时数据处理和非结构化数据处理方面较弱,在预警和预测在业务中的应用有一定的局限性。
  二、数据平台 1、数据平台的概念
  在大数据时代,数据平台一般被称为大数据平台。
  狭义的数据平台:是解决数据仓库无法处理非结构化数据,报表开发周期长的问题。因此,我们首先抛开业务需求,将企业的所有数据提取出来,放在一起,形成一个大数据集。有结构化数据,非结构化数据等等。当业务方有需求时,将需要的几个小数据集分别抽取出来,以数据集的形式提供给数据应用。
  广义大数据平台:广义大数据平台通常被赋予更多的任务来处理海量数据存储、不间断流数据的计算和实时计算、离线计算、智能推荐、交互查询、数据湖建设等场景。一套为主的基础设施。典型的包括建立在 Hadoop 生态系统上的大数据平台。提供Hive、Spark、HBase、Flink、StarRocks、Iceberg、Alluxio等开源大数据计算和存储引擎,易于部署和管理。
  狭义数据平台与传统数据平台(数据仓库)功能相同,唯一不同的是技术架构和数据容量。
  广义的大数据平台是数据湖的基础。提供易于部署和管理泛Hadoop生态系统等存储计算引擎的PaaS平台,帮助企业构建企业级数据湖技术架构。
  提示:本文比较的是狭义的数据平台,并没有对狭义的数据平台进行过多的概述。
  三、数据中台 1、数据中台的概念
  数据中心的由来:2015年年中,马云带领阿里巴巴集团高管走访芬兰小游戏公司Supercell。这家员工不到 200 人的小型游戏公司每年产生 15 亿美元的税前利润!Supercell之所以能够支持多个团队快速敏捷地推出优质游戏作品,是因为其强大的中期能力。
  因此,在参观了Supercell之后,马云决定对阿里巴巴的组织体系架构进行整体调整,以阿里巴巴的产品技术和数据能力建立强大的中台,打造“大中台、小前台”的组织和业务。系统 。
  数据中心的主要目的是解决企业发展过程中因数据激增和业务扩展而导致的统计口径不一致、重复开发、指标开发需求响应慢、数据质量低、数据成本高的问题。通过一系列数据工具(元数据中心、数据指标中心、数据仓库模型中心、数据资产中心-资产质量/治理/安全、数据服务中心等),规范数据供应链的各个环节。
  2.数据中心的特点
  数据中心特点:支持前端数据标准化、安全、可靠、统一、共享、解耦、服务化的应用。
  3.数据中心的作用
  (阿里巴巴数据中台逻辑架构图)
  (数据中心产品能力图)
  数据中心通过对企业内外多源异构数据的构建、管理、分析和应用,优化内部数据管理提升业务价值,对外开展数据协同释放业务价值,使其成为企业数据资产管理中心。数据中心建成后,将形成数据API服务,为企业和客户提供高效、多样的数据服务。
  数据中心在企业数字化转型和可持续发展中发挥着至关重要的作用。数据中心为解耦而生。企业建设数据中心的最大意义在于实现应用与数据的解耦,让企业可以不受限制地构建满足业务需求的数据应用。
  构建了开放、灵活、可扩展的企业级统一数据管理和分析平台,可按需链接内外部数据,打破数据的系统边界。
  利用大数据智能分析、数据可视化等技术,实现数据共享、日报表自动生成、快速智能分析,满足企业各部门数据分析应用需求。
  深度挖掘数据价值,助力企业实现数字化转型。实现数据目录、模型、标准、问责、安全、可视化、共享的管理,实现数据集中存储、处理、分类和管理,建立大数据分析工具库、算法服务库,实现报表生成自动化、数据分析敏捷,数据挖掘可视化,实现数据质量评估、落地管理流程。
  4. 数据湖 1. 数据湖概念
  数据湖的起源:数据湖的起源应该追溯到2010年10月,由Pentaho的创始人兼CTO James Dixon提出。他的目的是根据当时的历史背景,推广自己的产品 Pentaho。当时要解决的核心问题是传统数仓报表分析面临的两个问题:
  我们现在讨论的数据湖已经远远超过了James Dixon一开始定义的数据湖,各个厂商对数据湖的定义也比较不同。
  1)AWS
  数据湖是一个集中式存储库,可让您以任意规模存储所有结构化和非结构化数据。您可以按原样存储数据,而无需首先构建数据,并运行不同类型的分析——从仪表板和可视化到大数据处理、实时分析和机器学习,以指导更好的决策。
  “数据湖是一个集中式存储库,可让您以任何规模存储所有结构化和非结构化数据。您可以按原样存储数据(无需先对其进行结构化)并运行不同类型的分析——从仪表板和可视化到大数据处理、实时分析和机器学习,以指导更好的决策。”
  2) 微软
  Azure Data Lake 收录使开发人员、数据科学家和分析师能够轻松存储任何大小、形状和速度的数据以及跨平台和语言进行所有类型的处理和分析所需的所有功能。它消除了摄取和存储所有数据的复杂性,同时通过批处理、流式处理和交互式分析更快地启动和运行。
  “Azure 的数据湖包括所有使开发人员、数据科学家和分析师更容易存储和处理数据的功能,这些功能允许用户存储任何大小、类型和速度的数据,并且可以跨平台、做所有类型跨语言分析处理。数据湖可以帮助用户加速应用数据,消除数据采集和存储的复杂性,还支持批处理、流计算、交互分析等。
  3)阿里云
  
  “数据湖是一个统一的存储池,可以对接多种数据输入方式,可以存储任意规模的结构化、半结构化、非结构化数据。数据湖可以无缝对接各种计算和分析平台,根据业务场景,可以选择相应的计算引擎对存储在数据湖中的数据进行处理和分析,从而打破孤岛,挖掘业务价值。”
  2. 数据湖内容
  数据湖包括结构化数据(行和列)、半结构化数据(如CSV、日志、XML、JSON)、非结构化数据(如电子邮件、文档、PDF等)和来自关系数据库的二进制数据数据(例如图像、音频、视频)。
  3. 数据湖的特点 4. 数据湖可以解决的问题
  1)数据湖整体架构
  最底层是分布式文件系统;
  第二层是数据加速层。数据湖架构是存储和计算完全分离的架构。如果所有数据访问都远程读取文件系统上的数据,那么性能和成本开销将是巨大的。如果可以在计算节点本地缓存一些经常访问的热点数据,那么实现冷热分离是很自然的。一方面可以获得良好的本地读取性能,另一方面可以节省远程访问的带宽。
  第三层是Table格式层,主要将一批数据文件封装成具有业务意义的表,提供ACID、snapshot、schema、partition等表级语义。
  最上层是针对不同计算场景的计算引擎。开源一般包括Spark、Flink、Hive、Presto、Hive MR等,这批计算引擎可以同时访问同一个数据湖中的表。
  2)数据湖能解决什么样的问题?
  数据分散,存储分散,形成数据孤岛,无法将数据组合起来发现更多价值。
  在这方面,数据湖其实是和数据仓库类似的问题,但不同的是,它的定义支持半结构化和非结构化数据的管理。传统数据仓库只能解决结构化数据的统一管理。
  在这个万物互联的时代,数据的来源多种多样。随着应用场景的不同,输出的数据格式也越来越丰富,不再局限于结构化数据。如何统一存储这些数据是一个亟待解决的问题。
  3) 存储成本
  数据库或数据仓库的存储受限于实现原理和硬件条件,导致海量数据存储成本高。为了解决这些问题,有HDFS/对象存储等技术方案。在数据湖场景下,如果采用这种低成本的存储技术架构,将为企业大大节省成本。结合生命周期管理的能力,湖中的数据可以更好的分层(冷热存储在不同的存储介质:HDD、SSD、MEM),不用担心数据是保留还是删除数据以节省成本。
  4)SQL已经不能满足的分析需求
  越来越多的数据类型意味着越来越多的分析方法。传统的 SQL 方法已经不能满足分析的需要。如何通过各种语言定制贴近业务的代码?如何通过机器学习挖掘更多?数据价值。
  5)存储/计算可扩展性不足
  在传统数据库等海量数据的情况下,比如规模到PB级别,由于技术架构的原因,已经不能满足扩容需求或者扩容成本极高。这种情况下,通过数据湖架构下的技术能力扩展,实现成本为0,硬件成本也是可控的。商业模式不确定,无法提前建模。
  传统的数据库和数据仓库都是 Schema-on-Write 模式,需要提前定义模式信息。在数据湖场景中,可以先保存数据,以后分析的时候发现Schema,即Schema-on-Read。
  五、对比一、数据仓库VS数据中心VS数据湖
  2. 数据仓库 vs 数据平台
  因为狭义的数据平台是由于数据仓库的历史特性,其存储的数据多为结构化数据,而数据平台的出现解决了数据仓库无法处理非结构化数据和报表的问题开发周期长。数据仓库和数据平台(狭义)是分开比较的。
  本质区别:技术架构和数据容量的差异。
  通过上面的讨论,我们发现数据平台和数据湖之间似乎有很多相似之处。两者的区别应该从个人的角度来分析。数据处理的角度是不同的。数据湖更侧重于原创数据的存储。,而数据平台和数据仓库一样,需要对原创数据进行清洗和转换,并在数据处理后按照统一的标准规范进行存储。
  6.总结
  根据以上对数据平台、数据仓库、数据湖、数据中台的概念讨论和对比,我们做如下总结:
  数据中心、数据仓库和数据湖之间没有直接关系;数据中心、数据平台、数据仓库和数据湖在一定维度上对业务产生价值的形式侧重点不同;数据仓库是数据驱动业务的逻辑概念,用于支持管理决策分析,为业务提供服务的主要方式是报表;数据中心是企业级的逻辑概念,体现了企业数据转化为业务价值的能力,为业务提供服务的主要方式是数据API;数据湖是企业级的技术逻辑概念,体现了企业级数据湖架构加速数据转化为商业价值的能力。为业务提供服务的主要方式是原创数据;数据中心和数据湖更贴近业务,可以更快 数据中心可以建立在数据仓库和数据平台之上,是加速企业从数据到业务价值过程的中间层;
  本文由@Mr.Z 发表 聊产品原创人人都是产品经理。未经许可禁止复制
  标题图片来自 Unsplash,基于 CC0 协议。
  本文观点仅代表作者本人,大家都是产品经理。平台仅提供信息存储空间服务。
  奖励作者,鼓励TA抓紧创作!
  欣赏
  横空出世:百家号热文采集工具-百家号爆文采集助手1.0 免费版
  百家号爆文采集Assistant是专门为百家号开发的一款小工具,你可以轻松使用本软件来采集流行文章,简单好用,需要的朋友可以过来下载!
  百家号爆文采集知识兔助手如何使用
  1.设置采集时间
  
  2.输入需要采集的链接,如果需要批量,可以设置为txt文档
  3.点击分析采集文章信息
  百家号介绍知识兔
  百家号是百度为内容创作者共享的内容发布、内容变现和粉丝管理平台。百家号于2016年6月上线并正式测试。9月,账号系统、分销策略升级、广告系统正式上线。9月28日,正式向所有作者开放。
  
  目前,百家号支持内容创作者轻松发布文章、图片、视频作品,未来将支持H5、VR、直播、动画等内容形式。内容一经提交,将通过手机百度、百度搜索、百度浏览器等多种渠道进行分发。
  点击下载
  下载体验
  点击下载 查看全部

  秘密:一文读懂数据仓库、数据平台、数据中台、数据湖的概念和区别
  在数据仓库、数据平台、数据中台、数据湖的相关概念中,都与数据相关,但它们之间有什么区别呢?本文介绍了它们的概念、架构和使用场景。让我们来看看。
  我们经常听到人们谈论数据仓库、数据平台、数据中心和数据湖的概念。它们都与数据有关,但它们之间有什么区别?下面我们将重点介绍数据仓库、数据平台和数据湖。介绍数据中心的概念、架构和使用场景。
  一、数据仓库 一、数据仓库概念
  数据仓库由 Bill Inmon(数据仓库之父)于 1990 年提出,其主要功能是存储大量数据,这些数据是企业系统中在线事务处理(OLTP)的长期障碍,并支持数据仓库理论所持有的数据存储。结构,做系统的分析和整理。
  随着企业的发展,业务系统的数据不断激增,存储在企业业务数据库(即关系型数据库Oracle、Microsoft SQL Server、MySQL等)中的数据会越来越多时间,这会使业务数据库有一定的负载,导致业务系统运行效率低下,而这个数据很大一部分是冷数据,而我们的业务系统一般会调用我们最近的数据,也就是热数据数据,更频繁,冷数据被更频繁地调用。减少使用频率。
  同时,随着企业数据驱动业务理念的兴起,企业需要提取各业务部门的业务数据进行数据分析挖掘,辅助高层分析决策。数据查询脚本和接口的访问降低了业务数据库的稳定性。
  为了避免冷数据和历史数据的积压对我们业务数据库性能的影响,企业需要定期从业务数据库中调出冷数据,并存放在专门用于存储历史数据的仓库中。各部门可根据自身业务特点提供统一的对外服务。数据服务,这个仓库就是数据仓库。
  2. 数据仓库功能
  数据仓库(Data Warehoese)的特点:面向主题、集成化、稳定、反映历史数据变化。
  3.OLTP和OLAP
  1) OLTP 和 OLAP 概念
  数据处理大致可以分为两类:在线事务处理OLTP(on-line transaction processing),在线分析处理OLAP(On-Line Analytical Processing)。
  OLTP 是传统关系型数据库的主要应用,主要用于基本的、日常的事务处理,例如银行交易。OLAP是数据仓库系统的主要应用,支持复杂的分析操作,注重决策支持,提供直观易懂的查询结果。
  2)OLTP和OLAP的区别
  OLTP系统强调数据库内存效率,强调内存、绑定变量、并发操作等各项指标的指挥率。OLAP 系统强调数据分析、SQL 执行市场、磁盘 I/O、分区等。
  3)OLAP与数据仓库的连接
  OLAP与数据仓库的关系依赖于互补性,一般以数据仓库为基础,即从数据仓库中提取详细数据的子集,通过必要的聚合存储在OLAP存储中,供数据分析工具读取。
  4.数据仓库的作用
  数据仓库聚合来自不同来源的结构化数据,以便在商业智能领域进行比较和分析。数据仓库是一个收录各种数据并且高度建模的存储库。
  如下图所示: 各个系统的元数据通过ETL同步到运营数据仓库ODS,ODS数据进行面向主题、面向领域的建模,形成DW(数据仓库)。DM就是为某个业务领域建立模型。决策层)查看DM生成的报告。
  什么是 ETL?(提取-转换-加载提取-转换-加载)
  传统的数据仓库集成处理架构是ETL,利用ETL平台的能力,E=从源数据库提取数据,L=清洗数据(不符合规则的数据),转换(表受根据业务需求不同维度、不同粒度)程度,计算不同的业务规则进行统计),T = 将处理后的表以增量、全量、不同时间加载到数据仓库中。
  什么是 ELT?(提取-加载-变换提取-加载-变换)
  大数据背景下的架构体系是ELT结构,根据上层的应用需求,随时从数据中心提取出需要的原创数据进行建模分析。
  ELT利用数据库的处理能力,E=从源数据库中提取数据,L=将数据加载到目标数据库的临时表中,T=对临时表中的数据进行变换,然后加载到目标表中的目标数据库。
  ELT 相对于 ETL 的优势:
  数据仓库系统的作用可以实现跨业务线、跨系统的数据集成,为管理分析和业务决策提供统一的数据支持。数据仓库可以从根本上帮助您将公司的运营数据转换为高价值的可访问信息(或知识),并在正确的时间以正确的方式将正确的信息传递给正确的人。下图是一个例子:
  数据仓库的作用主要体现在企业决策、分析、规划和响应的以下几个方面:
  
  数据仓库在实时数据处理和非结构化数据处理方面较弱,在预警和预测在业务中的应用有一定的局限性。
  二、数据平台 1、数据平台的概念
  在大数据时代,数据平台一般被称为大数据平台。
  狭义的数据平台:是解决数据仓库无法处理非结构化数据,报表开发周期长的问题。因此,我们首先抛开业务需求,将企业的所有数据提取出来,放在一起,形成一个大数据集。有结构化数据,非结构化数据等等。当业务方有需求时,将需要的几个小数据集分别抽取出来,以数据集的形式提供给数据应用。
  广义大数据平台:广义大数据平台通常被赋予更多的任务来处理海量数据存储、不间断流数据的计算和实时计算、离线计算、智能推荐、交互查询、数据湖建设等场景。一套为主的基础设施。典型的包括建立在 Hadoop 生态系统上的大数据平台。提供Hive、Spark、HBase、Flink、StarRocks、Iceberg、Alluxio等开源大数据计算和存储引擎,易于部署和管理。
  狭义数据平台与传统数据平台(数据仓库)功能相同,唯一不同的是技术架构和数据容量。
  广义的大数据平台是数据湖的基础。提供易于部署和管理泛Hadoop生态系统等存储计算引擎的PaaS平台,帮助企业构建企业级数据湖技术架构。
  提示:本文比较的是狭义的数据平台,并没有对狭义的数据平台进行过多的概述。
  三、数据中台 1、数据中台的概念
  数据中心的由来:2015年年中,马云带领阿里巴巴集团高管走访芬兰小游戏公司Supercell。这家员工不到 200 人的小型游戏公司每年产生 15 亿美元的税前利润!Supercell之所以能够支持多个团队快速敏捷地推出优质游戏作品,是因为其强大的中期能力。
  因此,在参观了Supercell之后,马云决定对阿里巴巴的组织体系架构进行整体调整,以阿里巴巴的产品技术和数据能力建立强大的中台,打造“大中台、小前台”的组织和业务。系统 。
  数据中心的主要目的是解决企业发展过程中因数据激增和业务扩展而导致的统计口径不一致、重复开发、指标开发需求响应慢、数据质量低、数据成本高的问题。通过一系列数据工具(元数据中心、数据指标中心、数据仓库模型中心、数据资产中心-资产质量/治理/安全、数据服务中心等),规范数据供应链的各个环节。
  2.数据中心的特点
  数据中心特点:支持前端数据标准化、安全、可靠、统一、共享、解耦、服务化的应用。
  3.数据中心的作用
  (阿里巴巴数据中台逻辑架构图)
  (数据中心产品能力图)
  数据中心通过对企业内外多源异构数据的构建、管理、分析和应用,优化内部数据管理提升业务价值,对外开展数据协同释放业务价值,使其成为企业数据资产管理中心。数据中心建成后,将形成数据API服务,为企业和客户提供高效、多样的数据服务。
  数据中心在企业数字化转型和可持续发展中发挥着至关重要的作用。数据中心为解耦而生。企业建设数据中心的最大意义在于实现应用与数据的解耦,让企业可以不受限制地构建满足业务需求的数据应用。
  构建了开放、灵活、可扩展的企业级统一数据管理和分析平台,可按需链接内外部数据,打破数据的系统边界。
  利用大数据智能分析、数据可视化等技术,实现数据共享、日报表自动生成、快速智能分析,满足企业各部门数据分析应用需求。
  深度挖掘数据价值,助力企业实现数字化转型。实现数据目录、模型、标准、问责、安全、可视化、共享的管理,实现数据集中存储、处理、分类和管理,建立大数据分析工具库、算法服务库,实现报表生成自动化、数据分析敏捷,数据挖掘可视化,实现数据质量评估、落地管理流程。
  4. 数据湖 1. 数据湖概念
  数据湖的起源:数据湖的起源应该追溯到2010年10月,由Pentaho的创始人兼CTO James Dixon提出。他的目的是根据当时的历史背景,推广自己的产品 Pentaho。当时要解决的核心问题是传统数仓报表分析面临的两个问题:
  我们现在讨论的数据湖已经远远超过了James Dixon一开始定义的数据湖,各个厂商对数据湖的定义也比较不同。
  1)AWS
  数据湖是一个集中式存储库,可让您以任意规模存储所有结构化和非结构化数据。您可以按原样存储数据,而无需首先构建数据,并运行不同类型的分析——从仪表板和可视化到大数据处理、实时分析和机器学习,以指导更好的决策。
  “数据湖是一个集中式存储库,可让您以任何规模存储所有结构化和非结构化数据。您可以按原样存储数据(无需先对其进行结构化)并运行不同类型的分析——从仪表板和可视化到大数据处理、实时分析和机器学习,以指导更好的决策。”
  2) 微软
  Azure Data Lake 收录使开发人员、数据科学家和分析师能够轻松存储任何大小、形状和速度的数据以及跨平台和语言进行所有类型的处理和分析所需的所有功能。它消除了摄取和存储所有数据的复杂性,同时通过批处理、流式处理和交互式分析更快地启动和运行。
  “Azure 的数据湖包括所有使开发人员、数据科学家和分析师更容易存储和处理数据的功能,这些功能允许用户存储任何大小、类型和速度的数据,并且可以跨平台、做所有类型跨语言分析处理。数据湖可以帮助用户加速应用数据,消除数据采集和存储的复杂性,还支持批处理、流计算、交互分析等。
  3)阿里云
  
  “数据湖是一个统一的存储池,可以对接多种数据输入方式,可以存储任意规模的结构化、半结构化、非结构化数据。数据湖可以无缝对接各种计算和分析平台,根据业务场景,可以选择相应的计算引擎对存储在数据湖中的数据进行处理和分析,从而打破孤岛,挖掘业务价值。”
  2. 数据湖内容
  数据湖包括结构化数据(行和列)、半结构化数据(如CSV、日志、XML、JSON)、非结构化数据(如电子邮件、文档、PDF等)和来自关系数据库的二进制数据数据(例如图像、音频、视频)。
  3. 数据湖的特点 4. 数据湖可以解决的问题
  1)数据湖整体架构
  最底层是分布式文件系统;
  第二层是数据加速层。数据湖架构是存储和计算完全分离的架构。如果所有数据访问都远程读取文件系统上的数据,那么性能和成本开销将是巨大的。如果可以在计算节点本地缓存一些经常访问的热点数据,那么实现冷热分离是很自然的。一方面可以获得良好的本地读取性能,另一方面可以节省远程访问的带宽。
  第三层是Table格式层,主要将一批数据文件封装成具有业务意义的表,提供ACID、snapshot、schema、partition等表级语义。
  最上层是针对不同计算场景的计算引擎。开源一般包括Spark、Flink、Hive、Presto、Hive MR等,这批计算引擎可以同时访问同一个数据湖中的表。
  2)数据湖能解决什么样的问题?
  数据分散,存储分散,形成数据孤岛,无法将数据组合起来发现更多价值。
  在这方面,数据湖其实是和数据仓库类似的问题,但不同的是,它的定义支持半结构化和非结构化数据的管理。传统数据仓库只能解决结构化数据的统一管理。
  在这个万物互联的时代,数据的来源多种多样。随着应用场景的不同,输出的数据格式也越来越丰富,不再局限于结构化数据。如何统一存储这些数据是一个亟待解决的问题。
  3) 存储成本
  数据库或数据仓库的存储受限于实现原理和硬件条件,导致海量数据存储成本高。为了解决这些问题,有HDFS/对象存储等技术方案。在数据湖场景下,如果采用这种低成本的存储技术架构,将为企业大大节省成本。结合生命周期管理的能力,湖中的数据可以更好的分层(冷热存储在不同的存储介质:HDD、SSD、MEM),不用担心数据是保留还是删除数据以节省成本。
  4)SQL已经不能满足的分析需求
  越来越多的数据类型意味着越来越多的分析方法。传统的 SQL 方法已经不能满足分析的需要。如何通过各种语言定制贴近业务的代码?如何通过机器学习挖掘更多?数据价值。
  5)存储/计算可扩展性不足
  在传统数据库等海量数据的情况下,比如规模到PB级别,由于技术架构的原因,已经不能满足扩容需求或者扩容成本极高。这种情况下,通过数据湖架构下的技术能力扩展,实现成本为0,硬件成本也是可控的。商业模式不确定,无法提前建模。
  传统的数据库和数据仓库都是 Schema-on-Write 模式,需要提前定义模式信息。在数据湖场景中,可以先保存数据,以后分析的时候发现Schema,即Schema-on-Read。
  五、对比一、数据仓库VS数据中心VS数据湖
  2. 数据仓库 vs 数据平台
  因为狭义的数据平台是由于数据仓库的历史特性,其存储的数据多为结构化数据,而数据平台的出现解决了数据仓库无法处理非结构化数据和报表的问题开发周期长。数据仓库和数据平台(狭义)是分开比较的。
  本质区别:技术架构和数据容量的差异。
  通过上面的讨论,我们发现数据平台和数据湖之间似乎有很多相似之处。两者的区别应该从个人的角度来分析。数据处理的角度是不同的。数据湖更侧重于原创数据的存储。,而数据平台和数据仓库一样,需要对原创数据进行清洗和转换,并在数据处理后按照统一的标准规范进行存储。
  6.总结
  根据以上对数据平台、数据仓库、数据湖、数据中台的概念讨论和对比,我们做如下总结:
  数据中心、数据仓库和数据湖之间没有直接关系;数据中心、数据平台、数据仓库和数据湖在一定维度上对业务产生价值的形式侧重点不同;数据仓库是数据驱动业务的逻辑概念,用于支持管理决策分析,为业务提供服务的主要方式是报表;数据中心是企业级的逻辑概念,体现了企业数据转化为业务价值的能力,为业务提供服务的主要方式是数据API;数据湖是企业级的技术逻辑概念,体现了企业级数据湖架构加速数据转化为商业价值的能力。为业务提供服务的主要方式是原创数据;数据中心和数据湖更贴近业务,可以更快 数据中心可以建立在数据仓库和数据平台之上,是加速企业从数据到业务价值过程的中间层;
  本文由@Mr.Z 发表 聊产品原创人人都是产品经理。未经许可禁止复制
  标题图片来自 Unsplash,基于 CC0 协议。
  本文观点仅代表作者本人,大家都是产品经理。平台仅提供信息存储空间服务。
  奖励作者,鼓励TA抓紧创作!
  欣赏
  横空出世:百家号热文采集工具-百家号爆文采集助手1.0 免费版
  百家号爆文采集Assistant是专门为百家号开发的一款小工具,你可以轻松使用本软件来采集流行文章,简单好用,需要的朋友可以过来下载!
  百家号爆文采集知识兔助手如何使用
  1.设置采集时间
  
  2.输入需要采集的链接,如果需要批量,可以设置为txt文档
  3.点击分析采集文章信息
  百家号介绍知识兔
  百家号是百度为内容创作者共享的内容发布、内容变现和粉丝管理平台。百家号于2016年6月上线并正式测试。9月,账号系统、分销策略升级、广告系统正式上线。9月28日,正式向所有作者开放。
  
  目前,百家号支持内容创作者轻松发布文章、图片、视频作品,未来将支持H5、VR、直播、动画等内容形式。内容一经提交,将通过手机百度、百度搜索、百度浏览器等多种渠道进行分发。
  点击下载
  下载体验
  点击下载

教程:14、美女福利图片API接口,免费好用

采集交流优采云 发表了文章 • 0 个评论 • 509 次浏览 • 2022-10-26 10:32 • 来自相关话题

  教程:14、美女福利图片API接口,免费好用
  1. 前言
  美女图片福利查询界面,这是RollToolsApi通用系列接口之一,包括1个小接口,可以获得一些年轻美女的图片,非常适合做一些演示。
  
  查看界面完整信息:
  RollToolsApi通用系列接口收录了很多免费的通用API接口,使用这些接口可以帮助你开发很多功能,稳定服务的小程序、APP或网页,无论是训练还是实战都是不错的选择。可以在此处查看所有接口的列表
  2. 接口细节
  
  注意:app_id和app_secret都是临时密钥,如果您真的使用它们,则需要申请自己的独占密钥。
  2.1 获取随机收益图片 2.2 获取收益图像列表
  技巧:4个好用的在线站长工具
  4个有用的在线站长查询工具
  1.Chinaz站长工具
  Chinaz的站长工具是知道的站长,甚至说是站长工具。它有最全面的网站分析工具,通过它你可以简单的了解一个网站的操作。站长之家(中国站长站)成立于2002年3月,是一位资深站长网站,虽然现在离个人站长有点远。在厦门。
  
  2. 爱站网
  爱站成立于2009年,是一家专门为中国网站提供服务的网站。域名反向查找非常有用。在深圳。
  3.上网
  
  是紫天网络继《我要你》免费统计后推出的又一款全新的站长工具。查询域名信息速度很快。在郑州。
  4. 站长助手
  站长助手网络成立于2008年,为站长和SEO工作者提供最有效的站长工具。以前经常用,感觉快了,现在没了。在上海。
  以上是常用的站长工具,还有很多其他的站长工具,数据可能不准确或者存在某种缺陷。 查看全部

  教程:14、美女福利图片API接口,免费好用
  1. 前言
  美女图片福利查询界面,这是RollToolsApi通用系列接口之一,包括1个小接口,可以获得一些年轻美女的图片,非常适合做一些演示。
  
  查看界面完整信息:
  RollToolsApi通用系列接口收录了很多免费的通用API接口,使用这些接口可以帮助你开发很多功能,稳定服务的小程序、APP或网页,无论是训练还是实战都是不错的选择。可以在此处查看所有接口的列表
  2. 接口细节
  
  注意:app_id和app_secret都是临时密钥,如果您真的使用它们,则需要申请自己的独占密钥。
  2.1 获取随机收益图片 2.2 获取收益图像列表
  技巧:4个好用的在线站长工具
  4个有用的在线站长查询工具
  1.Chinaz站长工具
  Chinaz的站长工具是知道的站长,甚至说是站长工具。它有最全面的网站分析工具,通过它你可以简单的了解一个网站的操作。站长之家(中国站长站)成立于2002年3月,是一位资深站长网站,虽然现在离个人站长有点远。在厦门。
  
  2. 爱站网
  爱站成立于2009年,是一家专门为中国网站提供服务的网站。域名反向查找非常有用。在深圳。
  3.上网
  
  是紫天网络继《我要你》免费统计后推出的又一款全新的站长工具。查询域名信息速度很快。在郑州。
  4. 站长助手
  站长助手网络成立于2008年,为站长和SEO工作者提供最有效的站长工具。以前经常用,感觉快了,现在没了。在上海。
  以上是常用的站长工具,还有很多其他的站长工具,数据可能不准确或者存在某种缺陷。

优化的解决方案:简单的API爬虫(和风天气数据获取)

采集交流优采云 发表了文章 • 0 个评论 • 122 次浏览 • 2022-10-25 11:25 • 来自相关话题

  优化的解决方案:简单的API爬虫(和风天气数据获取)
  内容简介
  不知不觉中,我已经快高三了,接触过 C、C++ 和 Python。但我觉得一切都可以一点点,但想了想,也无能为力,最后还是决定开始精通Python之路。从爬虫到数据分析,最后到机器学习。希望每天都有收获。今天开始系统地学习爬虫。
  1.什么是API?
  总之就是一个接口,你可以通过携带一些参数来访问这个接口来获取你想要的数据。
  这次我们使用 Zephyr Weather 提供的 API 来获取我们需要的天气数据。
  2. 步骤
  这一次,我们将编写一个程序,可以根据我们输入的城市名称获取相关的天气数据。
  1.注册一个Zephyr账号
  网址:
  注册后,登录并在应用管理中新建一个Web API类型的应用。记得在创建后复制KEY的值,这个很重要!!!
  然后,我们就可以根据泽风天气提供的API开发文档开始编写代码了。
  API开发文档
  2.获取位置
  首先,通过查询API开发文档,发现需要请求【请求参数】URL。有两个参数是必须携带的,一个是我上面提到的KEY值,另一个是代表城市的位置。location 可以是 LocationID 或逗号分隔的经度、纬度坐标(十进制)。
  泽风天气提供了一个存储LocationID的文档,也有对应的请求URL。LocationID 文件下载地址
  请求URL为【请求参数】,有两个参数必须携带,一个是KEY,一个是location(要查询的区域名称,支持文本,经纬度坐标(十进制)用英文隔开)逗号)、LocationID 或 Adcode(仅限中国城市)。
  我们首先请求第二个 URL 来获取 LocationID。
  代码显示如下:
  #coding:utf-8
import requests
import json
def getID(address,key):
# address=&#39;北京&#39;
url = f&#39;https://geoapi.qweather.com/v2 ... on%3D{address}&key={key}&#39;
datas = requests.get(url).json()
# print(data)
<p>
# print(type(datas))
for data in datas[&#39;location&#39;]:
if data[&#39;name&#39;] == address:
ID = data[&#39;id&#39;]
return ID
</p>
  获取到的数据是字符串类型的,我们通过将其转换为json格式来提取我们需要的位置。
  3.获取天气数据
  代码显示如下:
  def getData(address,ID,key):
url = f&#39;https://devapi.qweather.com/v7 ... on%3D{ID}&key={key}&#39;
datas = requests.get(url).json()
data_updateTime = datas[&#39;updateTime&#39;]
data_time = datas[&#39;now&#39;][&#39;obsTime&#39;]
data_temp = datas[&#39;now&#39;][&#39;temp&#39;]
data_feelsLike = datas[&#39;now&#39;][&#39;feelsLike&#39;]
data_text = datas[&#39;now&#39;][&#39;text&#39;]
data_vis = datas[&#39;now&#39;][&#39;vis&#39;]
print(&#39;{0} {5}\n更新时间:{1}\n观测时间:{2}\n温度:{3} 摄氏度\n体感温度:{4} 摄氏度\n能见度:{6} 公里\n&#39;.format(address,data_updateTime,data_time,data_temp,data_feelsLike,data_text,data_vis))
  这段代码不难,获取数据的格式是需要注意的。
  4.完整代码
  #coding:utf-8
import requests
import json
def getID(address,key):
# address = &#39;北京&#39;
url = f&#39;https://geoapi.qweather.com/v2 ... on%3D{address}&key={key}&#39;
<p>
datas = requests.get(url).json()
# print(data)
# print(type(datas))
for data in datas[&#39;location&#39;]:
if data[&#39;name&#39;] == address:
ID = data[&#39;id&#39;]
return ID
def getData(address,ID,key):
url = f&#39;https://devapi.qweather.com/v7 ... on%3D{ID}&key={key}&#39;
datas = requests.get(url).json()
data_updateTime = datas[&#39;updateTime&#39;]
data_time = datas[&#39;now&#39;][&#39;obsTime&#39;]
data_temp = datas[&#39;now&#39;][&#39;temp&#39;]
data_feelsLike = datas[&#39;now&#39;][&#39;feelsLike&#39;]
data_text = datas[&#39;now&#39;][&#39;text&#39;]
data_vis = datas[&#39;now&#39;][&#39;vis&#39;]
print(&#39;{0} {5}\n更新时间:{1}\n观测时间:{2}\n温度:{3} 摄氏度\n体感温度:{4} 摄氏度\n能见度:{6} 公里\n&#39;.format(address,data_updateTime,data_time,data_temp,data_feelsLike,data_text,data_vis))
if __name__ == &#39;__main__&#39;:
key = &#39;******&#39; //填入你自己的KEY值
address = input(&#39;请输入要查询的天气:&#39;)
ID = getID(address,key)
getData(address, ID, key)
</p>
  总结
  以上就是我们今天要讲的内容。本文仅简单介绍 API 的使用。我们可以通过API开发文档轻松获取我们需要的数据。
  如果需要其他关于泽风天气的数据,可以到API开发文档中获取。
  成熟的解决方案:阿里云如何打破Oracle迁移上云的壁垒
  摘要:在2018年第九届中国数据库技术大会上,阿里云数据库产品专家肖少聪就阿里云如何打破Oracle上云的壁垒发表了演讲。Oracle 指的是“数据库管理系统”。面对甲骨文迁移上云的壁垒,阿里云又该如何打破呢?本文提出了一种从 Oracle 迁移到云数据库的 PPAS 解决方案。为什么这个迁移方案比从Oracle迁移到MySQL系列更容易推广?答案即将揭晓。
  2018年第九届中国数据库技术大会上,阿里云数据库产品专家肖少聪就阿里云如何打破Oracle上云壁垒发表演讲。Oracle 指的是“数据库管理系统”。面对甲骨文迁移上云的壁垒,阿里云又该如何打破呢?本文提出了一种从 Oracle 迁移到云数据库的 PPAS 解决方案。为什么这个迁移方案比从Oracle迁移到MySQL系列更容易推广?答案即将揭晓。
  现场视频回顾
  PPT下载请点击
  以下是视频内容的亮点:
  Oracle 数据库迁移解决方案
  数据业务架构主要分为三大部分:服务器、应用程序、数据库系统和存储系统。解决云服务器和存储系统的问题相对容易,但解决应用程序和数据库系统的问题就有些困难了。因此,阿里云提供了上述解决方案。在这个方案中,用户可以通过不同的方式将数据库迁移到云端,我们可以继续在ECS中运行Oracle,也可以迁移到MySQL。当然,应用程序和数据库系统也可以迁移到 PPAS 版。凭借与Oracle的高度兼容性,降低了用户上云的难度,降低了系统长期运维的复杂度。
  阿里云不仅为云用户提供同城容灾、自动备份、时间点恢复等功能。阿里云数据库还会加入高可用HA,一般需要两个或更多节点进行复杂的配置。在阿里云中,用户一键即可拥有高可用HA,这样的HA集群不仅可以搭建在同一个数据中心,还可以支持同城双中心、异地容灾,同样的一键部署就完成了。同时,阿里云还为用户提供ADAM(Advanced Database &amp; Application Migration “亚当”)工具,借助PPAS的Oracle兼容性,协助用户进行快速迁移。那么接下来的迁移步骤应该如何进行呢?
  在Oracle上安装ADAM采集,ADMA会扮演三个角色:
  Oracle 迁移到 PPAS 比迁移到其他数据库更顺畅,因为有很多兼容的地方。Oracle数据库到PPAS要兼容SQL、存储过程、包、DBMS等,所以适合复杂事务的迁移。ApsaraDB for PPAS 提供高达 3TB 的本地高性能存储(据悉,该空间在今年内有机会超过 10TB)。如果业务数据超出本地存储容量,可以使用OSS存储进行外表处理。例如,历史数据可以存储在 OSS 外部表中。此信息不经常使用,但对数据分析很重要。因此,我们可以通过阿里云HybridDB for PostgreSQL直接从OSS获取数据进行业务分析。HybridDB for PostgreSQL 是阿里云 基于开源Greenplum Database分布式MPP数据库的自己的发布版本。可实现实时业务分析,将计算节点和空间横向扩展至PB级,特定场景下百亿条记录&lt;10ms*排序,支持Rank Hybrid、CUBE、ROLLUP、MADlib学习等。
  
  Oracle 数据库与 MySQL、PPAS 的比较
  为什么Oracle数据库迁移到MySQL家族难推?原因是Oracle数据库迁移到MySQL系列会增加ISV和企业迁移的风险。在整个迁移过程中,代码、存储过程和架构都需要做很大的改变,这会导致研发重新学习、DBA重新学习、代码重新学习。语法重写甚至业务架构重写最终会导致业务风险增加、人工成本增加、产品成本增加。
  Oracle 数据库到云数据库 PPAS 版的推广相对容易,在推广过程中提高了 Oracle 迁移上云的成功率。研发可以持续编写Oracle语法,降低迁移难度和工作量,阿里云可以自动运维和提升DBA SQL优化能力,代码语法几乎不需要改动,ADAM辅助精准分析。
  为什么 PPAS 与 Oralce 的兼容性更好?从上图可以看出,MySOL和Oracle的交集面积比PostgreSQL和Oracle的要小,没有达到预期的效果。预计云数据库PASS版的效果应该是Oracle的区域和PostgreSQL的区域几乎重叠。
  为什么需要这么多兼容的部件?因为这样可以将企业的开发团队、原有的开发成果和已有的应用快速上云。比如开发者开发的软件全部离线,但是客户要求上云,上云需要使用互联网,那么就需要改变原有的存储方式。为了在线和离线维护云架构,需要改变结构,这将需要大量的人力成本。如果有直接兼容Oracle语法的功能,这个时候放到云端会减轻整体负担。
  云数据库PPAS to Oracle兼容的数据类型有很多,如BLOB、CLOB、DATE等。他们每个人都有自己的别名和类型。例如,BLOB 的别名是 LONG RAW,它的类型是二进制数据。
  ADAM 可以通过全量迁移和增量迁移的方式,协助用户将 Oracle 数据库迁移到云端。如果 Oracle 数据量很大,可能需要一周甚至一个月的时间才能完成传输。这时候可以通过高速连接和高速通道来增加带宽,不需要经过互联网,防止传输错误的数据,也不会影响生产库。通过ADAM平台,Oracle数据到云数据库还将提供30天退货机制,为用户迁移割接过程提供最大保障。
  PPAS版不仅具有高可用,还支持同城容灾。用户可以选择使用单AZ集群或多AZ(同城容灾)集群,无需任何额外费用。有保障的企业级容灾需要保护。
  
  PPAS版不仅提供自动备份,还提供50%的免费备份空间。例如,如果用户购买了 1TB 的实例存储空间,他们将直接获得 500GB 的免费备份空间。
  ApsaraDB for PPAS 云管理是按时间点克隆实例。实例克隆功能将于2018年7月上线,支持最长730天的数据备份。目前,仅提供临时实例。
  阿里云 PostgreSQL 生态系统
  Oracle 应用可以迁移到 PPAS 版,它使用高性能本地存储来存储热的 OLTP 业务数据。历史信息存储在外部 OSS 上,OSS 上的数据可以直接被 HybridDB for PostgreSQL 读取和使用,也就是说 OLTP 可以进行业务处理,OLAP 可以直接使用阿里云数据仓库服务。开源Greenplum数据库分布式MPP架构。PostgreSQL 的混合数据库。
  同时,用户也可以保留原有的Oracle系统,只使用HybridDB for PostgreSQL进行分析业务。OLAP 的性能优势如下:
  HybridDB for PostgreSQL 混合分区
  存储可以分为三种存储,即行存储、列存储和OSS温存储。三种存储方式描述如下:
  原创链接 查看全部

  优化的解决方案:简单的API爬虫(和风天气数据获取)
  内容简介
  不知不觉中,我已经快高三了,接触过 C、C++ 和 Python。但我觉得一切都可以一点点,但想了想,也无能为力,最后还是决定开始精通Python之路。从爬虫到数据分析,最后到机器学习。希望每天都有收获。今天开始系统地学习爬虫。
  1.什么是API?
  总之就是一个接口,你可以通过携带一些参数来访问这个接口来获取你想要的数据。
  这次我们使用 Zephyr Weather 提供的 API 来获取我们需要的天气数据。
  2. 步骤
  这一次,我们将编写一个程序,可以根据我们输入的城市名称获取相关的天气数据。
  1.注册一个Zephyr账号
  网址:
  注册后,登录并在应用管理中新建一个Web API类型的应用。记得在创建后复制KEY的值,这个很重要!!!
  然后,我们就可以根据泽风天气提供的API开发文档开始编写代码了。
  API开发文档
  2.获取位置
  首先,通过查询API开发文档,发现需要请求【请求参数】URL。有两个参数是必须携带的,一个是我上面提到的KEY值,另一个是代表城市的位置。location 可以是 LocationID 或逗号分隔的经度、纬度坐标(十进制)。
  泽风天气提供了一个存储LocationID的文档,也有对应的请求URL。LocationID 文件下载地址
  请求URL为【请求参数】,有两个参数必须携带,一个是KEY,一个是location(要查询的区域名称,支持文本,经纬度坐标(十进制)用英文隔开)逗号)、LocationID 或 Adcode(仅限中国城市)。
  我们首先请求第二个 URL 来获取 LocationID。
  代码显示如下:
  #coding:utf-8
import requests
import json
def getID(address,key):
# address=&#39;北京&#39;
url = f&#39;https://geoapi.qweather.com/v2 ... on%3D{address}&key={key}&#39;
datas = requests.get(url).json()
# print(data)
<p>
# print(type(datas))
for data in datas[&#39;location&#39;]:
if data[&#39;name&#39;] == address:
ID = data[&#39;id&#39;]
return ID
</p>
  获取到的数据是字符串类型的,我们通过将其转换为json格式来提取我们需要的位置。
  3.获取天气数据
  代码显示如下:
  def getData(address,ID,key):
url = f&#39;https://devapi.qweather.com/v7 ... on%3D{ID}&key={key}&#39;
datas = requests.get(url).json()
data_updateTime = datas[&#39;updateTime&#39;]
data_time = datas[&#39;now&#39;][&#39;obsTime&#39;]
data_temp = datas[&#39;now&#39;][&#39;temp&#39;]
data_feelsLike = datas[&#39;now&#39;][&#39;feelsLike&#39;]
data_text = datas[&#39;now&#39;][&#39;text&#39;]
data_vis = datas[&#39;now&#39;][&#39;vis&#39;]
print(&#39;{0} {5}\n更新时间:{1}\n观测时间:{2}\n温度:{3} 摄氏度\n体感温度:{4} 摄氏度\n能见度:{6} 公里\n&#39;.format(address,data_updateTime,data_time,data_temp,data_feelsLike,data_text,data_vis))
  这段代码不难,获取数据的格式是需要注意的。
  4.完整代码
  #coding:utf-8
import requests
import json
def getID(address,key):
# address = &#39;北京&#39;
url = f&#39;https://geoapi.qweather.com/v2 ... on%3D{address}&key={key}&#39;
<p>
datas = requests.get(url).json()
# print(data)
# print(type(datas))
for data in datas[&#39;location&#39;]:
if data[&#39;name&#39;] == address:
ID = data[&#39;id&#39;]
return ID
def getData(address,ID,key):
url = f&#39;https://devapi.qweather.com/v7 ... on%3D{ID}&key={key}&#39;
datas = requests.get(url).json()
data_updateTime = datas[&#39;updateTime&#39;]
data_time = datas[&#39;now&#39;][&#39;obsTime&#39;]
data_temp = datas[&#39;now&#39;][&#39;temp&#39;]
data_feelsLike = datas[&#39;now&#39;][&#39;feelsLike&#39;]
data_text = datas[&#39;now&#39;][&#39;text&#39;]
data_vis = datas[&#39;now&#39;][&#39;vis&#39;]
print(&#39;{0} {5}\n更新时间:{1}\n观测时间:{2}\n温度:{3} 摄氏度\n体感温度:{4} 摄氏度\n能见度:{6} 公里\n&#39;.format(address,data_updateTime,data_time,data_temp,data_feelsLike,data_text,data_vis))
if __name__ == &#39;__main__&#39;:
key = &#39;******&#39; //填入你自己的KEY值
address = input(&#39;请输入要查询的天气:&#39;)
ID = getID(address,key)
getData(address, ID, key)
</p>
  总结
  以上就是我们今天要讲的内容。本文仅简单介绍 API 的使用。我们可以通过API开发文档轻松获取我们需要的数据。
  如果需要其他关于泽风天气的数据,可以到API开发文档中获取。
  成熟的解决方案:阿里云如何打破Oracle迁移上云的壁垒
  摘要:在2018年第九届中国数据库技术大会上,阿里云数据库产品专家肖少聪就阿里云如何打破Oracle上云的壁垒发表了演讲。Oracle 指的是“数据库管理系统”。面对甲骨文迁移上云的壁垒,阿里云又该如何打破呢?本文提出了一种从 Oracle 迁移到云数据库的 PPAS 解决方案。为什么这个迁移方案比从Oracle迁移到MySQL系列更容易推广?答案即将揭晓。
  2018年第九届中国数据库技术大会上,阿里云数据库产品专家肖少聪就阿里云如何打破Oracle上云壁垒发表演讲。Oracle 指的是“数据库管理系统”。面对甲骨文迁移上云的壁垒,阿里云又该如何打破呢?本文提出了一种从 Oracle 迁移到云数据库的 PPAS 解决方案。为什么这个迁移方案比从Oracle迁移到MySQL系列更容易推广?答案即将揭晓。
  现场视频回顾
  PPT下载请点击
  以下是视频内容的亮点:
  Oracle 数据库迁移解决方案
  数据业务架构主要分为三大部分:服务器、应用程序、数据库系统和存储系统。解决云服务器和存储系统的问题相对容易,但解决应用程序和数据库系统的问题就有些困难了。因此,阿里云提供了上述解决方案。在这个方案中,用户可以通过不同的方式将数据库迁移到云端,我们可以继续在ECS中运行Oracle,也可以迁移到MySQL。当然,应用程序和数据库系统也可以迁移到 PPAS 版。凭借与Oracle的高度兼容性,降低了用户上云的难度,降低了系统长期运维的复杂度。
  阿里云不仅为云用户提供同城容灾、自动备份、时间点恢复等功能。阿里云数据库还会加入高可用HA,一般需要两个或更多节点进行复杂的配置。在阿里云中,用户一键即可拥有高可用HA,这样的HA集群不仅可以搭建在同一个数据中心,还可以支持同城双中心、异地容灾,同样的一键部署就完成了。同时,阿里云还为用户提供ADAM(Advanced Database &amp; Application Migration “亚当”)工具,借助PPAS的Oracle兼容性,协助用户进行快速迁移。那么接下来的迁移步骤应该如何进行呢?
  在Oracle上安装ADAM采集,ADMA会扮演三个角色:
  Oracle 迁移到 PPAS 比迁移到其他数据库更顺畅,因为有很多兼容的地方。Oracle数据库到PPAS要兼容SQL、存储过程、包、DBMS等,所以适合复杂事务的迁移。ApsaraDB for PPAS 提供高达 3TB 的本地高性能存储(据悉,该空间在今年内有机会超过 10TB)。如果业务数据超出本地存储容量,可以使用OSS存储进行外表处理。例如,历史数据可以存储在 OSS 外部表中。此信息不经常使用,但对数据分析很重要。因此,我们可以通过阿里云HybridDB for PostgreSQL直接从OSS获取数据进行业务分析。HybridDB for PostgreSQL 是阿里云 基于开源Greenplum Database分布式MPP数据库的自己的发布版本。可实现实时业务分析,将计算节点和空间横向扩展至PB级,特定场景下百亿条记录&lt;10ms*排序,支持Rank Hybrid、CUBE、ROLLUP、MADlib学习等。
  
  Oracle 数据库与 MySQL、PPAS 的比较
  为什么Oracle数据库迁移到MySQL家族难推?原因是Oracle数据库迁移到MySQL系列会增加ISV和企业迁移的风险。在整个迁移过程中,代码、存储过程和架构都需要做很大的改变,这会导致研发重新学习、DBA重新学习、代码重新学习。语法重写甚至业务架构重写最终会导致业务风险增加、人工成本增加、产品成本增加。
  Oracle 数据库到云数据库 PPAS 版的推广相对容易,在推广过程中提高了 Oracle 迁移上云的成功率。研发可以持续编写Oracle语法,降低迁移难度和工作量,阿里云可以自动运维和提升DBA SQL优化能力,代码语法几乎不需要改动,ADAM辅助精准分析。
  为什么 PPAS 与 Oralce 的兼容性更好?从上图可以看出,MySOL和Oracle的交集面积比PostgreSQL和Oracle的要小,没有达到预期的效果。预计云数据库PASS版的效果应该是Oracle的区域和PostgreSQL的区域几乎重叠。
  为什么需要这么多兼容的部件?因为这样可以将企业的开发团队、原有的开发成果和已有的应用快速上云。比如开发者开发的软件全部离线,但是客户要求上云,上云需要使用互联网,那么就需要改变原有的存储方式。为了在线和离线维护云架构,需要改变结构,这将需要大量的人力成本。如果有直接兼容Oracle语法的功能,这个时候放到云端会减轻整体负担。
  云数据库PPAS to Oracle兼容的数据类型有很多,如BLOB、CLOB、DATE等。他们每个人都有自己的别名和类型。例如,BLOB 的别名是 LONG RAW,它的类型是二进制数据。
  ADAM 可以通过全量迁移和增量迁移的方式,协助用户将 Oracle 数据库迁移到云端。如果 Oracle 数据量很大,可能需要一周甚至一个月的时间才能完成传输。这时候可以通过高速连接和高速通道来增加带宽,不需要经过互联网,防止传输错误的数据,也不会影响生产库。通过ADAM平台,Oracle数据到云数据库还将提供30天退货机制,为用户迁移割接过程提供最大保障。
  PPAS版不仅具有高可用,还支持同城容灾。用户可以选择使用单AZ集群或多AZ(同城容灾)集群,无需任何额外费用。有保障的企业级容灾需要保护。
  
  PPAS版不仅提供自动备份,还提供50%的免费备份空间。例如,如果用户购买了 1TB 的实例存储空间,他们将直接获得 500GB 的免费备份空间。
  ApsaraDB for PPAS 云管理是按时间点克隆实例。实例克隆功能将于2018年7月上线,支持最长730天的数据备份。目前,仅提供临时实例。
  阿里云 PostgreSQL 生态系统
  Oracle 应用可以迁移到 PPAS 版,它使用高性能本地存储来存储热的 OLTP 业务数据。历史信息存储在外部 OSS 上,OSS 上的数据可以直接被 HybridDB for PostgreSQL 读取和使用,也就是说 OLTP 可以进行业务处理,OLAP 可以直接使用阿里云数据仓库服务。开源Greenplum数据库分布式MPP架构。PostgreSQL 的混合数据库。
  同时,用户也可以保留原有的Oracle系统,只使用HybridDB for PostgreSQL进行分析业务。OLAP 的性能优势如下:
  HybridDB for PostgreSQL 混合分区
  存储可以分为三种存储,即行存储、列存储和OSS温存储。三种存储方式描述如下:
  原创链接

文章采集api 终极:性能指标的信仰危机

采集交流优采云 发表了文章 • 0 个评论 • 116 次浏览 • 2022-10-23 16:49 • 来自相关话题

  文章采集api 终极:性能指标的信仰危机
  阅读这篇文章的你或多或少都接触过前端性能优化。这种联系可能来自您的阅读经历或工作经历。那么我们不妨从一个非常简单的思想实验开始。请根据您对该领域的理解回答以下问题:
  不要有压力,你可以慢慢思考和回答这些问题。你对第一个问题的回答可能会随着第二个和第三个问题的出现而不断调整。
  这篇文章的目的就是对以上三个问题进行探索和尝试性的回答。希望我的回答能给你一些启发。
  一次重播
  目前,我的项目长期依赖 GA(Google Analytic)作为衡量页面性能的唯一工具。在 GA 生态系统中,我们最重视 Avg Page Load Time(以下简称 APLT),通过它来决定我们网站当前的性能状态是什么。
  但是,在定期采集这个指标数据的过程中,我们发现用户的感受和数据显示可能并不一致。具体来说,数据看起来很流畅,但用户体验却直线下降。
  所以我们必须回答一个关键问题,APLT 究竟测量的是什么?
  什么是关键,因为它的答案决定了我们需要解决的下一个问题以及我们需要采取的行动:
  但是,官方文档对这个指标的解释是模棱两可的:
  平均页面加载时间:从开始网页浏览(例如,单击页面链接)到在浏览器中加载完成所花费的平均时间量(以秒为单位)。
  平均 页面加载时间由两部分组成:1)网络和服务器时间,2)浏览器时间。Explorer 选项卡的 Technical 部分提供有关网络的详细信息,剩余时间是用于解析和执行 JavaScript 以及呈现页面的浏览器开销。
  对于它的解释,我们有几个问题:
  遗传算法的实施
  GA底层是采集通过Navigation Timing API的性能数据
  GA 不计算每个阶段的数据。它将一些合并的指标重命名为新的指标,其中一些,例如 Document Interactive Loaded,实际上是某些阶段的统计信息的总和:
  GA 只计算与 DOM 文档相关的数据。APLT定义中提到的加载完成时间是指loadEventEnd事件发生的时间,即onLoad事件被触发的时间(当load事件被触发时,是指所有外部资源,包括iframe、图片、脚本、样式已加载)。因此,APLT 值是 GA 中所有指标中时间跨度最宽的。
  脚本对平均页面加载时间有什么影响
  如上图所示,浏览器在从上到下解析DOM树时,会遇到很多图片、样式、脚本等外部资源。所以它需要从缓存或网络中请求这些资源。
  页面的解析是同步的,所以脚本的加载会导致页面解析的暂停。浏览器在继续解析之前需要加载、编译和执行脚本,这是有道理的,因为 JavaScript 可能会使用 document.write() 等方法来改变 DOM 的结构。您可能听说过将 async 或 defer 属性添加到脚本标签以异步加载和执行脚本。但它在我们的生产中不起作用,因为 async 不保证脚本执行的顺序。但这种方案不一定适用于所有页面,因为 async 无法保证脚本的执行顺序。如果你的应用程序对脚本的执行顺序有严格的要求,那么它就帮不了你了。
  目前浏览器都配备了preloader机制来提前扫描页面中的外部元素,但是这个机制没有统一的标准,无法衡量效果,所以我们暂时不考虑它对我们的影响.
  脚本下载后,需要进行解析(parse/compile)和执行(run/execute)。解析阶段首先将 javascript 代码编译成机器语言,执行阶段将实际运行我们编写的代码。脚本的解析和执行也会阻塞页面的解析
  所以综上所述,我们可以得出结论,该脚本确实可以影响APLT。
  但是放弃衡量和谈论伤害都是流氓行为。它的影响范围有多大?也就是如果APLT是2秒,那么脚本用了多少时间?
  这里没有具体的数字,但也不能小觑,足以影响性能。Addy Osmani 在 2017 年的一篇文章 文章 中指出 Chrome 的脚本引擎会花费编译时间
  虽然 Chrome 此后优化了编译过程,但执行脚本过长的问题依然存在。同时这只是Chrome中的情况,我们无法确认其他浏览器在编译脚本时也能保证同样的效率
  如果APLT由不同的阶段组成,我们是否可以计算出每个阶段的具体时间?
  回顾上面对 GA 指标的定义,至少我们现在可以将服务器时间和浏览器时间分开。但是浏览器时间呢?比如脚本的下载时间和执行时间,我们无从得知。这些是额外的计算和 采集。
  综上所述,我们完全依赖APLT来诊断网站的性能问题是不可靠的,简单地认为脚本负担拖慢了性能也是不完全的。
  对指标的信任危机
  我想您可能会明白为什么我在上一节中花了这么多时间来解释仅一个指标的含义。因为一个指标可以揭示的信息可能比你想象的要复杂,领先和误导并存。
  首先,我不反对使用通用指标,并且这个 文章 并不是对它们的批评,它们在帮助我们解决性能问题方面提供了巨大的帮助。我这里要讨论的是,如果常规指标是性能监控的底线,那么上限在哪里?
  从以上描述不难看出,APLT的维度过于宽泛,更倾向于综合技术指标,向我们展示趋势而非细节。这有两个问题:
  接下来,我们深入讨论这两个问题。
  以用户为中心
  您可能已经注意到,当前前端性能监控的趋势正在逐渐向 User-Centric Performance Metrics 发展。为什么会出现这种情况?因为随着单页应用的普及和前端功能的“繁重”,经典的以资源为中心的性能指标(如 Onload、DOMContentLoaded)越来越无法准确反馈真实的用户体验和产品性能。在后端渲染的传统多页面应用模式中,资源加载完成意味着页面可供用户使用;而在单页模式下,资源加载的完成与产品的可用性之间存在一定的差距,因为只有这样,应用才能真正向用户请求个性化数据,呈现定制化的页面。
  一般来说,越来越多的重要和耗时的工作发生在资源加载之后,我们需要监控这部分工作的性能。
  好消息是浏览器原生为我们提供了这方面的支持。例如,Chrome 在 Performace API 中提供了 Paint Timing API,如首次绘制(FP)、首次内容绘制(FCP)、交互时间(tti)等指标。数据。顾名思义,这些指标试图从用户体验的角度显示应用在浏览器中呈现时的性能;坏消息是,这些指标在衡量真实用户体验方面仍然不准确。
  以上面提到的FP、FCP、TTI这三个指标为例,我将通过一个简单的例子来说明这三个指标是如何不够准确的:在单个页面的初始化过程中,我们通常会提供类似于“ “正在加载”视图,通常是占位符或骨架样式,将在数据请求完成后渲染实际视图:
  如果加载时间过长,浏览器会认为“加载中”的视图是用户可用的最终产品形式,并以此为基准计算上述三个指标
  
  下面的代码模拟了一个日常的情况,包括上面提到的情况:在组件加载时模拟两个请求,其中一个需要5秒的长时间等待,只有当两个请求都返回时,才能渲染数据。否则,总是提示用户加载。
  function App() {
const [data, setState] = useState([]);
useEffect(() => {
const longRequest = new Promise((resolve, reject) => {
setTimeout(() => {
resolve([]);
}, 1000 * 5)
});
const shortRequest = Promise.resolve([]);

Promise.all([longRequest, shortRequest]).then(([longRequestResponse, shortRequestResponse]) => {
setState([
[&#x27;&#x27;, &#x27;Tesla&#x27;, &#x27;Mercedes&#x27;, &#x27;Toyota&#x27;, &#x27;Volvo&#x27;],
[&#x27;2019&#x27;, 10, 11, 12, 13],
[&#x27;2020&#x27;, 20, 11, 14, 13],
[&#x27;2021&#x27;, 30, 15, 12, 13]
])
})
}, []);
return (

{data && data.length
?
: }

)
}
  复制
  如果您尝试在浏览器中运行上述应用程序,通过 Devtools 观察到的各种指标如下:
  可以通过开发者工具观察各种指标,如DCL(DOMContentLoaded Event)、FP、FCP、FMP(first有意义的绘制)、L(Onload Event)都在页面加载后的一秒左右发生。但是,从代码中我们可以肯定,用户至少需要 5 秒钟才能看到真实的内容。因此,上述指标并不能真正反馈用户遇到的性能问题。
  我已将该应用程序部署到该站点并可以在线访问它。并且你可以用它来做更详细的性能测试,它会给出和 devtools 一样的结果。网页测试是一个用于网站 性能测试的开源免费工具。早在 2012 年还没有 FP 等指标的时候,其原有的 Speed Index 指标就能够衡量用户体验。
  一般来说,如上图所示,浏览器提供的API只能衡量D阶段的性能,对E阶段和F阶段的表现帮助不大。
  这只是原生指标不准确的一个例子,可以总结为后端接口延迟过长。但是,还有一种情况是前端渲染时间过长。例如,当我们使用 Handsontable 组件渲染数千行数据表时,甚至会导致浏览器死机,这对 Paint Timing API 是免疫的。
  tti 指标呢?听起来它不是可以检测页面是否是交互式的吗?是不是无法检测到页面的假死?
  不幸的是,它仍然不起作用。
  如果你看一下 tti 指标的定义,你会发现 tti 本质上是一个算法:
  并且目前的原生 API 不支持 tti 指标,需要通过 polyfill 来实现。根据官方说明,目前并不适合所有网络应用。
  双向指示器
  
  这是知乎创作者中心页面的截图
  在此页面上,知乎 将每天向您更新过去 7 天的 文章 阅读、点赞、评论和其他数据的摘要。上图中的虚线是读数的数量。
  我知道它的目的是向创作者提供关于他们的数据的反馈,以帮助他们制作更好的内容,但至少对我来说它根本不起作用。因为我更想知道增长从哪里来,这样我就可以针对带来点击的内容。但它带给我的始终是聚合数据。
  这一要求也适用于性能监控。监控的目的是及时发现和解决问题。因此,在考察数据的过程中,我们更关心异常波动发生的时间和地点,也希望数据能在这方面对我有所帮助。
  当然,我们不可能无中生有地将一组汇总数据还原为详细数据,但在这个问题上我们可以从两个方向着手:
  在《Web Performance Calendar 2020 Edition 中的 Web 性能工具愿望清单》一文中,作者提出了他理想的性能工具应该满足的四个功能,即:
  其中第二个和第三个对我们选择指标也是有效的,这与我上面强调的不谋而合。
  最后,再次强调,这并不是对传统指标的否定。有数据的效果总比没有好。指标越多,绩效概况就越准确。以下是如何在这些基础上再接再厉,继续事半功倍,以提高我们寻求问题的效率。
  关于选择指标的一些建议
  上下文驱动
  我之所以不能在这里给你一个大而全面的解决方案是因为我认为这样的事情不存在,一切都取决于你的上下文。
  您可能更熟悉上下文驱动测试,但在我看来,当您选择性能指标或工具时,上下文驱动测试也适用。让我们看一下上下文测试的七个原则中的前两个:
  试想一下,如果把两句中的做法理解为一个度量,甚至直接用一个度量来代替,是不是没有什么不协调的感觉呢?
  乍一看,“上下文驱动”似乎是一个反驳的论点,但实际上它是我们提高监控效率的有效途径。指标本身没有对错之分,但不同人群对指标的看法不同:业务分析师想要的是能够直接展示业务价值的数据,比如点击率、弹窗率、用户转化等;DevOps同学,他们可能关心的是网站的“心跳”,资源的消耗,后端接口的速度;因此,不同的指标在不同的人群中处于潮起潮落的状态。这种分离也可以从技术角度进行划分。有的指标更注重资源,有的指标更注重用户体验。
  Metrics 只是发现问题的一种手段,现在我们有无数种手段可供选择:APM(应用程序性能管理)、日志分析、RUM(真实用户监控)、TTFB(Time to First Byte)……到底它迫使你回到问题的开头:我到底想测量什么?我想测量的对象可以用现有的指标来表达吗?我只想监控?如果我想调试或分析,还有其他选择吗?
  “好的软件测试是一个具有挑战性的智力过程。” (用性能调优代替测试),上下文驱动测试的第六条原则。
  微量元素
  如果说“资源已加载”不可靠,“浏览器开始绘制”不可靠,我认为唯一可靠的就是用户看到的。没有必要用各种数据来显示你的页面加载速度有多快,如果用户每次看到他想看的信息都要等十秒钟,那么这些数字只是自欺欺人。因此,我们不妨跟踪用户注意力信息对应的元素出现的时间。
  这不是创新。从早年的 Speed Index、“首屏”到今天的 web Vitals,都是这一理念的延续。指标的演进过程就像一个不断缩小过程中的圆圈,不断的向用户自身靠拢。只是由于技术手段的限制,他们只能走到这一步,而现在我们有了 MutationObserver 和 Perforamce API,我们可以准确定位元素,甚至元素上的属性发生变化,自然不会受到上面例子的影响。被占位符欺骗。
  对不起,这里不得不再次强调一下上下文:我们不能只关注“一个元素出现的时机”,还要从时间和代码扩展的角度来关注它的形成原因,这仍然需要我们结合环境,这取决于它是如何工作的。两个例子:
  上图中,如果组件D是向客户展示关键信息的关键元素,那么请求到达路由器的时间和组件C被路由器渲染的时间都会对D元素产生影响;从另一个维度:
  脚本和请求的加载和执行速度也会影响元素的外观。如果您需要诊断问题,了解这些问题背后的工作原理至关重要。
  但是跟踪元素还有一个问题,就是难以大规模应用。因为它是侵入性的,因为它要求您识别不同页面上的不同关键元素,并以一种近似硬代码的方式逐个跟踪它们。这种类型的工作会产生接近于维护前端 E2E 测试的维护成本。的确,我们可以通过分配统一的id或者类名来降低我们的维护成本,但是相比统一的GA代码,维护成本还是很高的。所以我建议用最简单的方式去监控最直接的元素,不要一个个地写你的监控代码,也不要让你的实现代码被监控代码绑定。
  让工具为您服务
  您可以在市场上找到无数声称可以帮助您提高绩效的工具。但首先你必须小心,他们所宣扬的并不是你真正需要的。
  例如 site24x7 是一家专门提供用户行为监控解决方案的公司。在他们关于 APM 的帮助页面上,指出监视和捕获 SAP(单页应用程序)性能数据实际上是当前技术的一项具有挑战性的工作:
  在单页应用程序的情况下,页面加载完成所用的时间无法通过页面加载事件获取,因为数据是使用从服务器动态获取的
  因此,对于每个 SPA 框架,页面加载指标是通过侦听特定于框架的特定事件来计算的。
  所以对于这种类型的页面,它们只捕获:
  对于每个动态页面加载,都会捕获相应的 URL、相应的 AJAX 调用、每个 AJAX 调用的响应时间、响应代码和错误(如果有)。
  但要知道,在当今流行的SPA中,这样的采集功能显得有些苍白。
  同样,如果您查看 Azure Application Insights 的 JavaScript SDK 中默认采集的页面信息:
  您的应用程序 XHR 和 Fetch 发出的网络依赖请求(默认情况下禁用获取集合)请求,包括有关用户信息(例如,位置、网络、IP)的信息设备信息(例如,浏览器、操作系统、版本、语言、型号)会话信息
  与其他平台提供的相比,我认为这些指标并没有增加额外的价值,它可以真正给我多少真正的“洞察力”。
  另一方面,不要让你的思维被工具限制:不要“因为xx工具只能做这么多,所以我只能采集这些指标”;而是“我想采集这些指标,所以我需要 xx 工具”。这里我列出一个我们正在探索的例子:使用 OpenTracing 工具 Jaeger 可视化前端性能图表。
  这里首先要赞一下Chrome内置的Performance工具,给我们调优性能带来了极大的便利。但我们总是有一些无法满足的额外需求。例如,我希望能够在结果演示中做一些自定义标记,或者在 Performance 选项卡下显示从 connect 到 resposne 的每个请求的每个阶段的状态。
  如下图所示,我们使用Jaeger开源工具跨界采集和展示自定义指标。可以说,不同纬度的指标以时间为线索链接,使页面加载阶段状态一览无余。容易定位问题。
  结束语
  我观察到,对于大部分前端工程师,或者以前的自己来说,做性能监控是一个被“喂”的过程,也就是会习惯性的采集已有的指标,不假思索地使用已有的工具。并且因为性能优化工作过程的前后结果的关系,我们只有在有需求的时候才会发现当前的结果并不是我们想要的。多一点思考将使我们的工作减少浪费。
  终极:解密搜索引擎的工作原理
  想获取更多干货教程,加Q群:173903050
  ★
  网站要想有好的排名,我们必须了解网站的基本优化,这就需要我们对搜索引擎的工作原理有一个很好的了解。只有这样,搜索引擎才会青睐我们的网站。
  知道什么是百度蜘蛛吗?百度蜘蛛是百度搜索引擎的自动程序。它的功能是访问和采集互联网上的网页、图片、视频等内容,然后按类别建立索引库,让用户可以搜索到你的网站网页、图片、视频等内容在百度搜索引擎中。
  搜索引擎在工作中主要进行以下几个步骤:
  ★
  1. 抢
  搜索引擎通过网站的链接不断爬取每个页面,不断采集整理互联网上的内容。这是爬行。我们可以发送外部链接,关注它们,创建高质量的外部链接。,路径要避开中文路径,路径太长,不利于爬行的因素被蜘蛛拒绝。
  
  2.过滤
  搜索引擎爬取后会存入临时数据库,同时过滤掉网站的垃圾内容,保留对用户有益的内容。
  常见的影响因素有:
  (一)文字、图片、视频、链接;
  (2) 速度;
  (3) 页面质量;
  (4)网站的权重和信用;
  (5) 页面的相似性;
  3. 收录
  搜索引擎过滤掉垃圾邮件后,会对剩余的网站内容执行收录。这时候可以使用site命令或者站长平台查看收录的状态。有收录才有排名,收录是保证排名的前提;收录 不一定有排名。
  
  收录 和索引之间的关系是包容关系。索引只能在收录之后建立,收录的数量大于索引的数量。百度站长平台链接提交工具是收录的入口。
  4.排序
  排序取决于两个因素:
  1、基础优化分数要求我们提高基础优化;
  2、用户投票评分需要良好的综合数据来提升用户体验。
  ★
  以上是我对搜索引擎工作原理的基本了解。通过查询我的网站收录的情况,可以判断出网站哪里出了问题,并找到解决方案,从而可以做的更好的优化。
  ★ 查看全部

  文章采集api 终极:性能指标的信仰危机
  阅读这篇文章的你或多或少都接触过前端性能优化。这种联系可能来自您的阅读经历或工作经历。那么我们不妨从一个非常简单的思想实验开始。请根据您对该领域的理解回答以下问题:
  不要有压力,你可以慢慢思考和回答这些问题。你对第一个问题的回答可能会随着第二个和第三个问题的出现而不断调整。
  这篇文章的目的就是对以上三个问题进行探索和尝试性的回答。希望我的回答能给你一些启发。
  一次重播
  目前,我的项目长期依赖 GA(Google Analytic)作为衡量页面性能的唯一工具。在 GA 生态系统中,我们最重视 Avg Page Load Time(以下简称 APLT),通过它来决定我们网站当前的性能状态是什么。
  但是,在定期采集这个指标数据的过程中,我们发现用户的感受和数据显示可能并不一致。具体来说,数据看起来很流畅,但用户体验却直线下降。
  所以我们必须回答一个关键问题,APLT 究竟测量的是什么?
  什么是关键,因为它的答案决定了我们需要解决的下一个问题以及我们需要采取的行动:
  但是,官方文档对这个指标的解释是模棱两可的:
  平均页面加载时间:从开始网页浏览(例如,单击页面链接)到在浏览器中加载完成所花费的平均时间量(以秒为单位)。
  平均 页面加载时间由两部分组成:1)网络和服务器时间,2)浏览器时间。Explorer 选项卡的 Technical 部分提供有关网络的详细信息,剩余时间是用于解析和执行 JavaScript 以及呈现页面的浏览器开销。
  对于它的解释,我们有几个问题:
  遗传算法的实施
  GA底层是采集通过Navigation Timing API的性能数据
  GA 不计算每个阶段的数据。它将一些合并的指标重命名为新的指标,其中一些,例如 Document Interactive Loaded,实际上是某些阶段的统计信息的总和:
  GA 只计算与 DOM 文档相关的数据。APLT定义中提到的加载完成时间是指loadEventEnd事件发生的时间,即onLoad事件被触发的时间(当load事件被触发时,是指所有外部资源,包括iframe、图片、脚本、样式已加载)。因此,APLT 值是 GA 中所有指标中时间跨度最宽的。
  脚本对平均页面加载时间有什么影响
  如上图所示,浏览器在从上到下解析DOM树时,会遇到很多图片、样式、脚本等外部资源。所以它需要从缓存或网络中请求这些资源。
  页面的解析是同步的,所以脚本的加载会导致页面解析的暂停。浏览器在继续解析之前需要加载、编译和执行脚本,这是有道理的,因为 JavaScript 可能会使用 document.write() 等方法来改变 DOM 的结构。您可能听说过将 async 或 defer 属性添加到脚本标签以异步加载和执行脚本。但它在我们的生产中不起作用,因为 async 不保证脚本执行的顺序。但这种方案不一定适用于所有页面,因为 async 无法保证脚本的执行顺序。如果你的应用程序对脚本的执行顺序有严格的要求,那么它就帮不了你了。
  目前浏览器都配备了preloader机制来提前扫描页面中的外部元素,但是这个机制没有统一的标准,无法衡量效果,所以我们暂时不考虑它对我们的影响.
  脚本下载后,需要进行解析(parse/compile)和执行(run/execute)。解析阶段首先将 javascript 代码编译成机器语言,执行阶段将实际运行我们编写的代码。脚本的解析和执行也会阻塞页面的解析
  所以综上所述,我们可以得出结论,该脚本确实可以影响APLT。
  但是放弃衡量和谈论伤害都是流氓行为。它的影响范围有多大?也就是如果APLT是2秒,那么脚本用了多少时间?
  这里没有具体的数字,但也不能小觑,足以影响性能。Addy Osmani 在 2017 年的一篇文章 文章 中指出 Chrome 的脚本引擎会花费编译时间
  虽然 Chrome 此后优化了编译过程,但执行脚本过长的问题依然存在。同时这只是Chrome中的情况,我们无法确认其他浏览器在编译脚本时也能保证同样的效率
  如果APLT由不同的阶段组成,我们是否可以计算出每个阶段的具体时间?
  回顾上面对 GA 指标的定义,至少我们现在可以将服务器时间和浏览器时间分开。但是浏览器时间呢?比如脚本的下载时间和执行时间,我们无从得知。这些是额外的计算和 采集。
  综上所述,我们完全依赖APLT来诊断网站的性能问题是不可靠的,简单地认为脚本负担拖慢了性能也是不完全的。
  对指标的信任危机
  我想您可能会明白为什么我在上一节中花了这么多时间来解释仅一个指标的含义。因为一个指标可以揭示的信息可能比你想象的要复杂,领先和误导并存。
  首先,我不反对使用通用指标,并且这个 文章 并不是对它们的批评,它们在帮助我们解决性能问题方面提供了巨大的帮助。我这里要讨论的是,如果常规指标是性能监控的底线,那么上限在哪里?
  从以上描述不难看出,APLT的维度过于宽泛,更倾向于综合技术指标,向我们展示趋势而非细节。这有两个问题:
  接下来,我们深入讨论这两个问题。
  以用户为中心
  您可能已经注意到,当前前端性能监控的趋势正在逐渐向 User-Centric Performance Metrics 发展。为什么会出现这种情况?因为随着单页应用的普及和前端功能的“繁重”,经典的以资源为中心的性能指标(如 Onload、DOMContentLoaded)越来越无法准确反馈真实的用户体验和产品性能。在后端渲染的传统多页面应用模式中,资源加载完成意味着页面可供用户使用;而在单页模式下,资源加载的完成与产品的可用性之间存在一定的差距,因为只有这样,应用才能真正向用户请求个性化数据,呈现定制化的页面。
  一般来说,越来越多的重要和耗时的工作发生在资源加载之后,我们需要监控这部分工作的性能。
  好消息是浏览器原生为我们提供了这方面的支持。例如,Chrome 在 Performace API 中提供了 Paint Timing API,如首次绘制(FP)、首次内容绘制(FCP)、交互时间(tti)等指标。数据。顾名思义,这些指标试图从用户体验的角度显示应用在浏览器中呈现时的性能;坏消息是,这些指标在衡量真实用户体验方面仍然不准确。
  以上面提到的FP、FCP、TTI这三个指标为例,我将通过一个简单的例子来说明这三个指标是如何不够准确的:在单个页面的初始化过程中,我们通常会提供类似于“ “正在加载”视图,通常是占位符或骨架样式,将在数据请求完成后渲染实际视图:
  如果加载时间过长,浏览器会认为“加载中”的视图是用户可用的最终产品形式,并以此为基准计算上述三个指标
  
  下面的代码模拟了一个日常的情况,包括上面提到的情况:在组件加载时模拟两个请求,其中一个需要5秒的长时间等待,只有当两个请求都返回时,才能渲染数据。否则,总是提示用户加载。
  function App() {
const [data, setState] = useState([]);
useEffect(() => {
const longRequest = new Promise((resolve, reject) => {
setTimeout(() => {
resolve([]);
}, 1000 * 5)
});
const shortRequest = Promise.resolve([]);

Promise.all([longRequest, shortRequest]).then(([longRequestResponse, shortRequestResponse]) => {
setState([
[&#x27;&#x27;, &#x27;Tesla&#x27;, &#x27;Mercedes&#x27;, &#x27;Toyota&#x27;, &#x27;Volvo&#x27;],
[&#x27;2019&#x27;, 10, 11, 12, 13],
[&#x27;2020&#x27;, 20, 11, 14, 13],
[&#x27;2021&#x27;, 30, 15, 12, 13]
])
})
}, []);
return (

{data && data.length
?
: }

)
}
  复制
  如果您尝试在浏览器中运行上述应用程序,通过 Devtools 观察到的各种指标如下:
  可以通过开发者工具观察各种指标,如DCL(DOMContentLoaded Event)、FP、FCP、FMP(first有意义的绘制)、L(Onload Event)都在页面加载后的一秒左右发生。但是,从代码中我们可以肯定,用户至少需要 5 秒钟才能看到真实的内容。因此,上述指标并不能真正反馈用户遇到的性能问题。
  我已将该应用程序部署到该站点并可以在线访问它。并且你可以用它来做更详细的性能测试,它会给出和 devtools 一样的结果。网页测试是一个用于网站 性能测试的开源免费工具。早在 2012 年还没有 FP 等指标的时候,其原有的 Speed Index 指标就能够衡量用户体验。
  一般来说,如上图所示,浏览器提供的API只能衡量D阶段的性能,对E阶段和F阶段的表现帮助不大。
  这只是原生指标不准确的一个例子,可以总结为后端接口延迟过长。但是,还有一种情况是前端渲染时间过长。例如,当我们使用 Handsontable 组件渲染数千行数据表时,甚至会导致浏览器死机,这对 Paint Timing API 是免疫的。
  tti 指标呢?听起来它不是可以检测页面是否是交互式的吗?是不是无法检测到页面的假死?
  不幸的是,它仍然不起作用。
  如果你看一下 tti 指标的定义,你会发现 tti 本质上是一个算法:
  并且目前的原生 API 不支持 tti 指标,需要通过 polyfill 来实现。根据官方说明,目前并不适合所有网络应用。
  双向指示器
  
  这是知乎创作者中心页面的截图
  在此页面上,知乎 将每天向您更新过去 7 天的 文章 阅读、点赞、评论和其他数据的摘要。上图中的虚线是读数的数量。
  我知道它的目的是向创作者提供关于他们的数据的反馈,以帮助他们制作更好的内容,但至少对我来说它根本不起作用。因为我更想知道增长从哪里来,这样我就可以针对带来点击的内容。但它带给我的始终是聚合数据。
  这一要求也适用于性能监控。监控的目的是及时发现和解决问题。因此,在考察数据的过程中,我们更关心异常波动发生的时间和地点,也希望数据能在这方面对我有所帮助。
  当然,我们不可能无中生有地将一组汇总数据还原为详细数据,但在这个问题上我们可以从两个方向着手:
  在《Web Performance Calendar 2020 Edition 中的 Web 性能工具愿望清单》一文中,作者提出了他理想的性能工具应该满足的四个功能,即:
  其中第二个和第三个对我们选择指标也是有效的,这与我上面强调的不谋而合。
  最后,再次强调,这并不是对传统指标的否定。有数据的效果总比没有好。指标越多,绩效概况就越准确。以下是如何在这些基础上再接再厉,继续事半功倍,以提高我们寻求问题的效率。
  关于选择指标的一些建议
  上下文驱动
  我之所以不能在这里给你一个大而全面的解决方案是因为我认为这样的事情不存在,一切都取决于你的上下文。
  您可能更熟悉上下文驱动测试,但在我看来,当您选择性能指标或工具时,上下文驱动测试也适用。让我们看一下上下文测试的七个原则中的前两个:
  试想一下,如果把两句中的做法理解为一个度量,甚至直接用一个度量来代替,是不是没有什么不协调的感觉呢?
  乍一看,“上下文驱动”似乎是一个反驳的论点,但实际上它是我们提高监控效率的有效途径。指标本身没有对错之分,但不同人群对指标的看法不同:业务分析师想要的是能够直接展示业务价值的数据,比如点击率、弹窗率、用户转化等;DevOps同学,他们可能关心的是网站的“心跳”,资源的消耗,后端接口的速度;因此,不同的指标在不同的人群中处于潮起潮落的状态。这种分离也可以从技术角度进行划分。有的指标更注重资源,有的指标更注重用户体验。
  Metrics 只是发现问题的一种手段,现在我们有无数种手段可供选择:APM(应用程序性能管理)、日志分析、RUM(真实用户监控)、TTFB(Time to First Byte)……到底它迫使你回到问题的开头:我到底想测量什么?我想测量的对象可以用现有的指标来表达吗?我只想监控?如果我想调试或分析,还有其他选择吗?
  “好的软件测试是一个具有挑战性的智力过程。” (用性能调优代替测试),上下文驱动测试的第六条原则。
  微量元素
  如果说“资源已加载”不可靠,“浏览器开始绘制”不可靠,我认为唯一可靠的就是用户看到的。没有必要用各种数据来显示你的页面加载速度有多快,如果用户每次看到他想看的信息都要等十秒钟,那么这些数字只是自欺欺人。因此,我们不妨跟踪用户注意力信息对应的元素出现的时间。
  这不是创新。从早年的 Speed Index、“首屏”到今天的 web Vitals,都是这一理念的延续。指标的演进过程就像一个不断缩小过程中的圆圈,不断的向用户自身靠拢。只是由于技术手段的限制,他们只能走到这一步,而现在我们有了 MutationObserver 和 Perforamce API,我们可以准确定位元素,甚至元素上的属性发生变化,自然不会受到上面例子的影响。被占位符欺骗。
  对不起,这里不得不再次强调一下上下文:我们不能只关注“一个元素出现的时机”,还要从时间和代码扩展的角度来关注它的形成原因,这仍然需要我们结合环境,这取决于它是如何工作的。两个例子:
  上图中,如果组件D是向客户展示关键信息的关键元素,那么请求到达路由器的时间和组件C被路由器渲染的时间都会对D元素产生影响;从另一个维度:
  脚本和请求的加载和执行速度也会影响元素的外观。如果您需要诊断问题,了解这些问题背后的工作原理至关重要。
  但是跟踪元素还有一个问题,就是难以大规模应用。因为它是侵入性的,因为它要求您识别不同页面上的不同关键元素,并以一种近似硬代码的方式逐个跟踪它们。这种类型的工作会产生接近于维护前端 E2E 测试的维护成本。的确,我们可以通过分配统一的id或者类名来降低我们的维护成本,但是相比统一的GA代码,维护成本还是很高的。所以我建议用最简单的方式去监控最直接的元素,不要一个个地写你的监控代码,也不要让你的实现代码被监控代码绑定。
  让工具为您服务
  您可以在市场上找到无数声称可以帮助您提高绩效的工具。但首先你必须小心,他们所宣扬的并不是你真正需要的。
  例如 site24x7 是一家专门提供用户行为监控解决方案的公司。在他们关于 APM 的帮助页面上,指出监视和捕获 SAP(单页应用程序)性能数据实际上是当前技术的一项具有挑战性的工作:
  在单页应用程序的情况下,页面加载完成所用的时间无法通过页面加载事件获取,因为数据是使用从服务器动态获取的
  因此,对于每个 SPA 框架,页面加载指标是通过侦听特定于框架的特定事件来计算的。
  所以对于这种类型的页面,它们只捕获:
  对于每个动态页面加载,都会捕获相应的 URL、相应的 AJAX 调用、每个 AJAX 调用的响应时间、响应代码和错误(如果有)。
  但要知道,在当今流行的SPA中,这样的采集功能显得有些苍白。
  同样,如果您查看 Azure Application Insights 的 JavaScript SDK 中默认采集的页面信息:
  您的应用程序 XHR 和 Fetch 发出的网络依赖请求(默认情况下禁用获取集合)请求,包括有关用户信息(例如,位置、网络、IP)的信息设备信息(例如,浏览器、操作系统、版本、语言、型号)会话信息
  与其他平台提供的相比,我认为这些指标并没有增加额外的价值,它可以真正给我多少真正的“洞察力”。
  另一方面,不要让你的思维被工具限制:不要“因为xx工具只能做这么多,所以我只能采集这些指标”;而是“我想采集这些指标,所以我需要 xx 工具”。这里我列出一个我们正在探索的例子:使用 OpenTracing 工具 Jaeger 可视化前端性能图表。
  这里首先要赞一下Chrome内置的Performance工具,给我们调优性能带来了极大的便利。但我们总是有一些无法满足的额外需求。例如,我希望能够在结果演示中做一些自定义标记,或者在 Performance 选项卡下显示从 connect 到 resposne 的每个请求的每个阶段的状态。
  如下图所示,我们使用Jaeger开源工具跨界采集和展示自定义指标。可以说,不同纬度的指标以时间为线索链接,使页面加载阶段状态一览无余。容易定位问题。
  结束语
  我观察到,对于大部分前端工程师,或者以前的自己来说,做性能监控是一个被“喂”的过程,也就是会习惯性的采集已有的指标,不假思索地使用已有的工具。并且因为性能优化工作过程的前后结果的关系,我们只有在有需求的时候才会发现当前的结果并不是我们想要的。多一点思考将使我们的工作减少浪费。
  终极:解密搜索引擎的工作原理
  想获取更多干货教程,加Q群:173903050
  ★
  网站要想有好的排名,我们必须了解网站的基本优化,这就需要我们对搜索引擎的工作原理有一个很好的了解。只有这样,搜索引擎才会青睐我们的网站。
  知道什么是百度蜘蛛吗?百度蜘蛛是百度搜索引擎的自动程序。它的功能是访问和采集互联网上的网页、图片、视频等内容,然后按类别建立索引库,让用户可以搜索到你的网站网页、图片、视频等内容在百度搜索引擎中。
  搜索引擎在工作中主要进行以下几个步骤:
  ★
  1. 抢
  搜索引擎通过网站的链接不断爬取每个页面,不断采集整理互联网上的内容。这是爬行。我们可以发送外部链接,关注它们,创建高质量的外部链接。,路径要避开中文路径,路径太长,不利于爬行的因素被蜘蛛拒绝。
  
  2.过滤
  搜索引擎爬取后会存入临时数据库,同时过滤掉网站的垃圾内容,保留对用户有益的内容。
  常见的影响因素有:
  (一)文字、图片、视频、链接;
  (2) 速度;
  (3) 页面质量;
  (4)网站的权重和信用;
  (5) 页面的相似性;
  3. 收录
  搜索引擎过滤掉垃圾邮件后,会对剩余的网站内容执行收录。这时候可以使用site命令或者站长平台查看收录的状态。有收录才有排名,收录是保证排名的前提;收录 不一定有排名。
  
  收录 和索引之间的关系是包容关系。索引只能在收录之后建立,收录的数量大于索引的数量。百度站长平台链接提交工具是收录的入口。
  4.排序
  排序取决于两个因素:
  1、基础优化分数要求我们提高基础优化;
  2、用户投票评分需要良好的综合数据来提升用户体验。
  ★
  以上是我对搜索引擎工作原理的基本了解。通过查询我的网站收录的情况,可以判断出网站哪里出了问题,并找到解决方案,从而可以做的更好的优化。
  ★

官方客服QQ群

微信人工客服

QQ人工客服


线