【Hadoop_06】MapReduce的概述与wc案例

news2024/11/23 0:22:27

  • 1、MapReduce概述
    • 1.1 MapReduce定义
    • 1.2 MapReduce优点
    • 1.3 MapReduce缺点
    • 1.4 MapReduce核心思想
    • 1.5 MapReduce进程
    • 1.6 常用数据序列化类型
    • 1.7 源码与MapReduce编程规范
  • 2、WordCount案例实操
    • 2.1 本地测试
    • 2.2 提交到集群测试

1、MapReduce概述

1.1 MapReduce定义

MapReduce是一个分布式运算程序的编程框架,是用户开发“基于Hadoop的数据分析应用”的核心框架。
MapReduce核心功能是将用户编写的业务逻辑代码自带默认组件整合成一个完整的分布式运算程序,并发运行在一个Hadoop集群上。

1.2 MapReduce优点

1)MapReduce易于编程

==它简单的实现一些接口,就可以完成一个分布式程序,===这个分布式程序可以分布到大量廉价的PC机器上运行。也就是说你写一个分布式程序,跟写一个简单的串行程序是一模一样的。就是因为这个特点使得MapReduce编程变得非常流行。

2)良好的扩展性

当你的计算资源不能得到满足的时候,你可以通过简单的增加机器来扩展它的计算能力。

3)高容错性

MapReduce设计的初衷就是使程序能够部署在廉价的PC机器上,这就要求它具有很高的容错性。比如其中一台机器挂了,它可以把上面的计算任务转移到另外一个节点上运行,不至于这个任务运行失败,而且这个过程不需要人工参与,而完全是由Hadoop内部完成的。

4)适合PB级以上海量数据的离线处理

可以实现上千台服务器集群并发工作,提供数据处理能力。

1.3 MapReduce缺点

1)不擅长实时计算

MapReduce无法像MySQL一样,在毫秒或者秒级内返回结果。

2)不擅长流式计算

流式计算的输入数据是动态的,而MapReduce的输入数据集是静态的,不能动态变化。这是因为MapReduce自身的设计特点决定了数据源必须是静态的。

3)不擅长DAG(有向无环图)计算

多个应用程序存在依赖关系,后一个应用程序的输入为前一个的输出。在这种情况下,MapReduce并不是不能做,而是使用后,每个MapReduce作业的输出结果都会写入到磁盘,会造成大量的磁盘IO,导致性能非常的低下。

1.4 MapReduce核心思想

现在有一个需求:要统计一个文件当中每一个单词出现的总次数(并将查询结果a-p字母保存一个文件,q-z字母保存一个文件),则可以按照图示步骤

在这里插入图片描述
(1)分布式的运算程序往往需要分成至少2个阶段。map+reduce
(2)第一个阶段的MapTask并发实例,完全并行运行,互不相干。统计次数,形成键值对,<H,1>、<S,1>、<H,1>,但是次数之间不相加。
(3)第二个阶段的ReduceTask并发实例互不相干,但是他们的数据依赖于上一个阶段的所有MapTask并发实例的输出。将统计的次数相加求和。
(4)MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户的业务逻辑非常复杂,那就只能多个MapReduce程序,串行运行。

总结:分析WordCount数据流走向深入理解MapReduce核心思想。

1.5 MapReduce进程

mr、job、任务指的都是一个应用程序。例如:跑一个wordcount,可以说这是一个job或者任务。

未来在运行MapReduce程序的时候,会启动哪些进程呢?

一个完整的MapReduce程序在分布式运行时有三类实例进程:
(1)MrAppMaster:负责整个程序的过程调度及状态协调。
(2)MapTask:负责Map阶段的整个数据处理流程。
(3)ReduceTask:负责Reduce阶段的整个数据处理流程。

1.6 常用数据序列化类型

Java类型Hadoop Writable类型
BooleanBooleanWritable
ByteByteWritable
IntIntWritable
FloatFloatWritable
LongLongWritable
DoubleDoubleWritable
StringText
MapMapWritable
ArrayArrayWritable
NullNullWritable
  • 除了string,其他的都是在java类型的基础上加上writable

1.7 源码与MapReduce编程规范

在这里插入图片描述

用户编写的程序分成三个部分:Mapper、Reducer和Driver。

在这里插入图片描述

在这里插入图片描述

源码如下:

package org.apache.hadoop.examples;

import java.io.IOException;
import java.io.PrintStream;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Mapper.Context;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.Reducer.Context;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

public class WordCount
{
  public static void main(String[] args)
    throws Exception
  {
    Configuration conf = new Configuration();
    String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
    if (otherArgs.length < 2) {
      System.err.println("Usage: wordcount <in> [<in>...] <out>");
      System.exit(2);
    }
    Job job = Job.getInstance(conf, "word count");
    job.setJarByClass(WordCount.class);
    job.setMapperClass(TokenizerMapper.class);
    job.setCombinerClass(IntSumReducer.class);
    job.setReducerClass(IntSumReducer.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(IntWritable.class);
    for (int i = 0; i < otherArgs.length - 1; i++) {
      FileInputFormat.addInputPath(job, new Path(otherArgs[i]));
    }
    FileOutputFormat.setOutputPath(job, new Path(otherArgs[(otherArgs.length - 1)]));

    System.exit(job.waitForCompletion(true) ? 0 : 1);
  }

  public static class IntSumReducer extends Reducer<Text, IntWritable, Text, IntWritable>
  {
    private IntWritable result = new IntWritable();

    public void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context)
      throws IOException, InterruptedException
    {
      int sum = 0;
      for (IntWritable val : values) {
        sum += val.get();
      }
      this.result.set(sum);
      context.write(key, this.result);
    }
  }

  public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable>
  {
    private static final IntWritable one = new IntWritable(1);
    private Text word = new Text();

    public void map(Object key, Text value, Mapper<Object, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException
    {
      StringTokenizer itr = new StringTokenizer(value.toString());
      while (itr.hasMoreTokens()) {
        this.word.set(itr.nextToken());
        context.write(this.word, one);
      }
    }
  }
}
  • 上面一共有三个方法,分别是main方法,map方法和reduce方法。
  • 定义一个类,继承mapper,之后重写里面的mapper方法,实现自己的业务逻辑。

在这里插入图片描述
在这里插入图片描述

MapReduce的编程规范如下:

在这里插入图片描述
在这里插入图片描述

2、WordCount案例实操

2.1 本地测试

1)需求

在给定的文本文件中统计输出每一个单词出现的总次数
(1)输入数据

(2)期望输出数据

wenxin	2
banzhang	1
cls	2
hadoop	1
jiao	1
ss	2
xue	1
  • 可以发现上面的数据涉及首字母排序的问题。

2)需求分析

按照MapReduce编程规范,分别编写Mapper,Reducer,Driver。

在这里插入图片描述

(1)创建maven工程,MapReduceDemo

(2)在pom.xml文件中添加如下依赖

<dependencies>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>3.1.3</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.30</version>
    </dependency>
</dependencies>

(2)在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入。

log4j.rootLogger=INFO, stdout  
log4j.appender.stdout=org.apache.log4j.ConsoleAppender  
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout  
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n  
log4j.appender.logfile=org.apache.log4j.FileAppender  
log4j.appender.logfile.File=target/spring.log  
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout  
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

(3)创建包名:com.wenxin.mapreduce.wordcount

在这里插入图片描述

Mapper的源码:

@Public
@Stable
public class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
    public Mapper() {
    }

    protected void setup(Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>.Context context) throws IOException, InterruptedException {
    }

    protected void map(KEYIN key, VALUEIN value, Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>.Context context) throws IOException, InterruptedException {
        context.write(key, value);
    }

    protected void cleanup(Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>.Context context) throws IOException, InterruptedException {
    }

    public void run(Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>.Context context) throws IOException, InterruptedException {
        this.setup(context);

        try {
            while(context.nextKeyValue()) {
                this.map(context.getCurrentKey(), context.getCurrentValue(), context);
            }
        } finally {
            this.cleanup(context);
        }

    }

    public abstract class Context implements MapContext<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
        public Context() {
        }
    }
}

在这里插入图片描述
在这里插入图片描述

4)编写程序

(1)编写Mapper类

package com.wenxin.mapreduce.wordcount;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;

/**
 * @author Susie-Wen
 * @version 1.0
 * @description:
 * @date 2023/12/13 9:56
 */
/*
KEYIN,map阶段输入的key的类型:LongWritable
VALUEINT,map阶段输入的value的类型:Text
KEYOUT,map阶段输出的Key的类型:Text
VALUEOUT,map阶段输出的value类型:IntWritable
 */
public class WordCountMapper<map> extends Mapper<LongWritable, Text,Text, IntWritable> {
    //
    private Text outK=new Text();
    private IntWritable outV=new IntWritable(1);
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        /*
        LongWritable key,输入的key,偏移量
        Text value,输入的value
        Context context,对应的上下文
         */
        //1.获取一行
        String line = value.toString();
        
        //2.对一行数据进行切割(因为原始数据使用的是空格,因此这里使用空格切割)
        String[] words = line.split(" ");
        
        //3.循环写出
        for(String word:words){
            //封装outK
            outK.set(word);
            //写出
            context.write(outK,outV);
        }
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(2)编写Reducer类

package com.wenxin.mapreduce.wordcount;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
/**
 * @author Susie-Wen
 * @version 1.0
 * @description:
 * @date 2023/12/13 9:56
 */
/*
KEYIN,reduce阶段输入的key的类型:Text
VALUEINT,reduce阶段输入的value的类型:IntWritable
KEYOUT,reduce阶段输出的Key的类型:Text
VALUEOUT,reduce阶段输出的value类型:IntWritable
 */
public class WordCountReducer extends Reducer<Text, IntWritable,Text,IntWritable> {
    IntWritable outV=new IntWritable();
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        int sum =0;//定义一个变量,进行累加
        //传进来的值:wenxin,(1,1)
        for(IntWritable value:values){
            sum +=value.get();//累加,不能直接加上value,因为value是IntWritable类型,要使用get方法
        }
        outV.set(sum);
        //写出
        context.write(key,outV);
    }
}

在这里插入图片描述

(3)编写Driver驱动类

  • driver当中有7步,都是固定的;其次需要注意不要导错包了!
package com.atguigu.mapreduce.wordcount;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class WordCountDriver {

	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {

		// 1 获取配置信息以及获取job对象
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);

		// 2 关联本Driver程序的jar
		job.setJarByClass(WordCountDriver.class);

		// 3 关联Mapper和Reducer的jar
		job.setMapperClass(WordCountMapper.class);
		job.setReducerClass(WordCountReducer.class);

		// 4 设置Mapper输出的kv类型
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(IntWritable.class);

		// 5 设置最终输出kv类型
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(IntWritable.class);
		
		// 6 设置输入和输出路径
		FileInputFormat.setInputPaths(job, new Path(args[0]));
		FileOutputFormat.setOutputPath(job, new Path(args[1]));

		// 7 提交job
		boolean result = job.waitForCompletion(true);
		System.exit(result ? 0 : 1);
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 可以看到hadoop默认会对数据进行排序
  • 如果此时再次点击运行的话,会报错,显示输出路径存在;因此对于mapreduce程序,如果输出路径存在了,就会报错。

5)本地测试

(1)需要首先配置好HADOOP_HOME变量以及Windows运行依赖

(2)在IDEA/Eclipse上运行程序

在这里插入图片描述

在这里插入图片描述

2.2 提交到集群测试

集群上测试

(1)用maven打jar包,需要添加的打包插件依赖

<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

注意:如果工程上显示红叉。在项目上右键->maven->Reimport刷新即可。

(2)将程序打成jar包
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(3)修改不带依赖的jar包名称为wc.jar,并拷贝该jar包到Hadoop集群的/home/wenxin/module/hadoop-3.1.3路径。

(4)启动Hadoop集群

[root@hadoop102 hadoop-3.1.3]sbin/start-dfs.sh
[root@hadoop103 hadoop-3.1.3]$ sbin/start-yarn.sh

在这里插入图片描述

在这里插入图片描述

(5)执行WordCount程序
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

[root@hadoop102 hadoop-3.1.3]$ hadoop jar  wc.jar
 com.wenxin.mapreduce.wordcount.WordCountDriver /user/wenxin/input /user/wenxin/output

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1308437.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WPF-一个简单登录界面

一个简单登录界面 文章目录 一个简单登录界面一、效果展示二、准备代码 一、效果展示 二、准备代码 创建一个WPF工程&#xff0c;创建名为 Login5 的WPF项目。 添加Nuget包 MaterialDesignThemes 界面的整体布局和样式代码 <Window x:Class"Login5.MainWindow&quo…

hive数据仓库工具

1、hive是一套操作数据仓库的应用工具&#xff0c;通过这个工具可实现mapreduce的功能 2、hive的语言是hql[hive query language] 3、官网hive.apache.org 下载hive软件包地址 Welcome! - The Apache Software Foundationhttps://archive.apache.org/ 4、hive在管理数据时分为元…

Array数组和List的序列化和反序列化

一、前言 数组类型对象和普通对象一样&#xff0c;使用toJson/fromJson即可完成序列化与反序列化。 二、Array数组的序列化和反序列化 1.创建User类 public class User {Exposeprivate String userName;Exposeprivate String password;Exposeprivate int age;Exposeprivate …

Ubuntu22.04_修改用户名_添加用户_修改电脑名

概要&#xff1a; 本篇所讲述的操作都是在图形化界面中进行。点击顶部栏右侧&#xff0c;展开系统菜单&#xff0c;打开设置 一、修改自己的用户名 1、修改之前查看信息 cat /etc/passwd 2、修改 输入完成&#xff0c;回车即可 3、修改之后查看信息 cat /etc/passwd 4、解…

Python 反射

Python 反射是什么&#xff1f; 学习了几天&#xff0c;做个总结留给自己看。 感觉跟 SQL 入门要掌握的原理一样&#xff0c;Python 反射看起来也会做4件事&#xff0c;“增删查获” 增 - 增加属性&#xff0c;方法 setattr 删 - 删除属性&#xff0c;方法 delattr 查 - …

【超详细】创建vue3+ts项目(引入ElementPlus、Axios)

目录 前言1、使用vue脚手架创建项目1.1检查vue版本1.2 使用vue脚手架创建项目 2、删除项目多余文件&#xff0c;修改配置项目2.1、删除以下文件2.1、在views下创建index文件2.2、修改router/index.ts路由文件&#xff1a;2.3、修改App.vue文件&#xff1a;2.4、初始化页面样式以…

HTML---表单

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.表单概念 HTML表单是网页上用于收集用户输入信息的一种元素。它由一系列输入字段&#xff08;input&#xff09;、选择字段&#xff08;select&#xff09;、文本区域&#xff08;textarea&a…

CV计算机视觉每日开源代码Paper with code速览-2023.12.8

点击计算机视觉&#xff0c;关注更多CV干货 论文已打包&#xff0c;点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【显著目标检测】Texture-Semantic Collaboration Network for ORSI Salient Object Detection 论文地址&#xff1a;https://arxiv.org//pdf/…

深入理解Java虚拟机---Java内存模型

JMM Java内存模型主内存和工作内存volatile Java内存模型 Java内存模型是Java虚拟机规范中试图定义一种Java内存模型(JMM)来屏蔽掉各种硬件和操作系统的内存访问差异&#xff0c;以实现让Java程序在各种平台上都能达到一致的内存访问效果。可以理解为JMM定义一套在多线程读写共…

leetcode 34. 在排序数组中查找元素的第一个和最后一个位置(优质解法)

代码&#xff1a; class Solution {public int[] searchRange(int[] nums, int target) {int[] resultnew int[2];result[0]result[1]-1;//排除特殊情况if(numsnull||nums.length0){return result;}//查找左边界int left0;int rightnums.length-1;while (left<right){int m…

独立完成软件的功能的测试(4)

独立完成软件的功能的测试&#xff08;4&#xff09; &#xff08;12.14&#xff09;&#xff08;功能测试>头条项目实战&#xff09; 项目总体概述 项目背景和定位&#xff1a;一款汇聚科技咨询&#xff0c;技术文章和问答交流的用户移动终端产品&#xff0c;用户可以通过…

【玩转TableAgent数据智能分析】TableAgent全功能详解及多领域数据分析实践(下)数据分析过程及总结展望

6 TableAgent的数据分析过程解析 TableAgent的整个分析过程包括以下步骤&#xff0c;形成一个有机结构&#xff0c;让我们理清其工作原理。 6.1 Data Graph阶段 TableAgent首先绘制数据图&#xff0c;以解决问题。这个图形表示了问题的分解和细化&#xff0c;将大问题分解成…

在WPF窗口中增加水印效果

** 原理&#xff1a; ** 以Canvas作为水印显示载体&#xff0c;在Canvas中创建若干个TextBlock控件用来显示水印文案&#xff0c;如下图所示 然后以每一个TextBlock的左上角为中心旋转-30&#xff0c;最终效果会是如图红线所示&#xff1a; 为了达到第一行旋转后刚好与窗口…

深算院YashanDB与长亮科技联合,推出国产数据库金融核心解决方案

近期&#xff0c;深圳计算科学研究院&#xff08;简称“深算院”&#xff09;携手深圳市长亮科技股份有限公司&#xff08;简称“长亮科技”&#xff09;重磅推出基于崖山数据库YashanDB的金融核心解决方案&#xff0c;为推动金融机构实现技术自主可控与数字化转型全面赋能。 …

C# 从代码入门 Mysql 数据库事务

在业务开发中&#xff0c;使用数据库事务是必不可少的。而开发中往往会使用各种 ORM 执行数据库操作&#xff0c;简化代码复杂度&#xff0c;不过&#xff0c;由于各种 ORM 的封装特性&#xff0c;开发者的使用方式也不一样&#xff0c;开发者想要了解 ORM 对事务做了什么处理是…

Facebook的DINO,无监督模型,可用于分类和分割任务

Facebook的DINO 参考&#xff1a;https://blog.csdn.net/hello_dear_you/article/details/133695006 代码&#xff1a;https://github.com/facebookresearch/dino/tree/main DINO本质上是一种自监督学习方法&#xff0c;其核心思想是通过在大规模的无标签数据集上进行对比学习&…

华为云之轻松搭建 Nginx 静态网站

华为云之轻松搭建 Nginx 静态网站 一、本次实践介绍1. 本次实践目的2. 本次实践环境 二、ECS弹性云服务器介绍三、准备实践环境1. 预置环境2. 查看ECS服务器的账号密码信息3. 登录华为云4. 远程登录ECS服务器 四、安装配置 Nginx1. 安装nginx2. 启动nginx3. 浏览器中访问nginx服…

【Spark精讲】Spark内存管理

目录 前言 Java内存管理 Java运行时数据区 Java堆 垃圾回收机制 Executor内存管理 内存类型 堆内内存 堆外内存 内存管理模式 静态内存管理 统一内存管理 ​编辑 执行内存管理 多任务间内存分配 Shuffle 的内存占用 MemoryOverHead详解 任务内存调节 错误类型…

HarmonyOS给应用添加弹窗

给您的应用添加弹窗 概述 在我们日常使用应用的时候&#xff0c;可能会进行一些敏感的操作&#xff0c;比如删除联系人&#xff0c;这时候我们给应用添加弹窗来提示用户是否需要执行该操作&#xff0c;如下图所示&#xff1a; 弹窗是一种模态窗口&#xff0c;通常用来展示用户…

gRPC-Gateway:高效转换 RESTful 接口 | 开源日报 No.105

grpc-ecosystem/grpc-gateway Stars: 16.4k License: BSD-3-Clause gRPC-Gateway 是一个遵循 gRPC HTTP 规范的 gRPC 到 JSON 代理生成器。它是 Google 协议缓冲编译器 protoc 的插件&#xff0c;可以读取 protobuf 服务定义并生成反向代理服务器&#xff0c;将 RESTful HTTP…