前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >字节二面,问得贼细!!

字节二面,问得贼细!!

作者头像
千羽
发布2023-12-20 16:37:45
1150
发布2023-12-20 16:37:45
举报
文章被收录于专栏:程序员千羽程序员千羽

哈喽~,大家好,我是千羽。

下面分享我认识的一位大佬华中科技大学985硕,字节秋招二面。

感觉今天二面回答的还是比较不错,问得特别细,后续等待排序,希望别挂别挂!!!!

  • ✔1、自我介绍
  • ✔2、简单介绍团队实习概况(5min)
  • ✔3、对RPC有什么了解(从RPC讲到service mesh技术)
  • 🤷‍♂️4、RPC的一个调用过程有哪些步骤(以dubbo为例举例)
  • 👌5、RPC和Restful API有什么区别和联系
  • ✨6、service mesh解决了什么问题
  • ✔7、对于框架来说,sidecar帮助框架完成了什么问题
  • 😢8、Java语言的多线程有哪些同步方式?有何异同
  • 🙌9、Java的字节码可以用于实现哪些功能?
  • 🤦‍♂️10、假设Java程序在某个地方卡死,如何找到
  • 🙌11、Golang的defer语句执行顺序
  • 🙌12、defer语句在return之前还是之后执行(X)
  • ✔13、golang的协程和Java线程有什么区别
  • ✔14、编程题:实现一个带有TTL的LRUCache

✔1、自我介绍

大家好,我叫XXX,是一名XXX学校研二,目前专注于Java后端开发领域。我拥有丰富的项目经验,从需求分析、设计、编码、测试到维护,我能够熟练地运用Java语言和相关技术,独立或与团队一起完成各种复杂的开发任务。

在大学期间,我就开始接触编程,通过自学和实践,我掌握了Java基础语法、面向对象编程、常用数据结构与算法等知识。在工作中,我进一步深入学习了Java Web开发、Spring框架、MyBatis框架等后端开发技术,并积累了丰富的实践经验。

除了Java本身,我还对数据库技术有深入的了解和实践经验,包括MySQL、Oracle等关系型数据库和Redis等NoSQL数据库。同时,我也熟悉Linux操作系统和Shell脚本编程,能够高效地进行系统管理和运维工作。

在团队合作方面,我注重沟通与协作,能够与不同背景的团队成员有效合作,共同解决问题。同时,我具备强烈的责任心和自我驱动能力,能够在压力下保持冷静并按时完成高质量的工作。期待可以加入贵公司。

✔2、简单介绍团队实习概况(5min)

✔3、对RPC有什么了解(从RPC讲到service mesh技术)

RPC(Remote Procedure Call)是一种远程过程调用的通信协议,允许程序调用另一个地址空间(通常是网络上的另一台机器)的过程或函数。RPC使得开发者可以像调用本地函数一样调用远程计算机上的函数,隐藏了网络通信的细节。

RPC 的基本工作流程:

  1. 客户端调用:客户端发起远程调用请求,传递参数给服务端。
  2. 远程过程执行:远程服务器执行相应的过程或函数,并计算结果。
  3. 结果返回:结果返回给客户端,客户端获得远程调用的返回值。

在 RPC 中,涉及到一些核心概念和组件:

  • Stub(存根):客户端和服务端都有的代理,用于封装远程调用的细节。
  • Serialization(序列化):将数据转换成字节流,便于在网络上传输。
  • Transport(传输层):负责在客户端和服务端之间传输数据,可以使用 TCP、HTTP 等协议。
  • Service Interface(服务接口):定义了远程过程调用的接口。

Service Mesh:

Service Mesh 是一个用于处理服务间通信的基础设施层,它构建在现有的微服务架构上,提供了一些关键功能,如服务发现、负载均衡、安全、监控等。Service Mesh 通常使用 sidecar 代理来处理服务间通信。

一些常见的 Service Mesh 工具包括 Istio、Linkerd、Consul 等。它们通过注入 sidecar 代理来实现对服务间通信的监控、控制和管理,提供了诸多功能,如流量管理、故障恢复、安全策略等。

Service Mesh 与 RPC 的关系:

RPC 可以被视为 Service Mesh 中的一种通信方式,Service Mesh 提供了更多针对服务间通信的功能和管理能力,使得在分布式系统中更容易实现服务间通信、监控和管理。

🤷‍♂️4、RPC的一个调用过程有哪些步骤(以dubbo为例举例)

  1. 服务提供者注册
    1. 服务注册:服务提供者将自己提供的服务注册到注册中心(比如 ZooKeeper)。
    2. 发布服务:服务提供者向注册中心发布自己提供的服务。
  2. 服务消费者订阅
    1. 服务订阅:服务消费者从注册中心订阅感兴趣的服务列表和提供者地址。
  3. 远程调用过程
    1. 服务调用:服务消费者发起远程服务调用请求。
    2. 负载均衡:负载均衡模块根据一定策略选择合适的提供者。
    3. 通信协议:Dubbo 使用 Netty 作为默认的通信框架,进行客户端和服务端之间的通信。
    4. 序列化与反序列化:将调用参数序列化为字节流,传输到服务提供者端后反序列化为对象。
    5. 服务执行:服务提供者接收请求,执行相应的服务逻辑。
    6. 结果返回:服务提供者将执行结果序列化后返回给服务消费者。
    7. 结果处理:服务消费者接收到结果,进行反序列化处理,并返回给调用方。

4. 结果处理和调用完成

  1. 调用结果:调用方获取到服务提供者返回的结果或异常信息。
  2. 异常处理:处理调用过程中可能出现的异常情况。

👌5、RPC和Restful API有什么区别和联系

RPC(远程过程调用)和RESTful API(基于REST的API)是两种不同的网络通信方式,它们在设计和使用上有一些区别和联系。

区别:

  1. 通信方式:RPC是一种基于自定义协议的远程过程调用,它通过自定义的协议进行通信。而RESTful API则是一种基于HTTP协议的接口调用方式,它通过HTTP协议进行通信。
  2. 资源定位:RPC通常需要明确指定调用的远程过程或方法,而RESTful API则通过资源定位来访问特定的数据或服务。
  3. 请求方式:RPC通常使用同步请求方式,即客户端需要等待服务器响应才能继续执行。而RESTful API则可以使用同步或异步请求方式,客户端可以在不等待服务器响应的情况下继续执行其他任务。
  4. 状态管理:RPC通常不涉及状态管理,而RESTful API则可以通过HTTP状态码和状态消息来管理请求的状态。

联系:

  1. 都是网络通信方式:RPC和RESTful API都是通过网络进行通信的,它们都需要在网络上传输数据。
  2. 都需要进行序列化和反序列化:无论是RPC还是RESTful API,都需要将数据序列化为二进制或文本格式,以便在网络上传输。在接收端,又需要将数据反序列化回原始格式。
  3. 都可用于构建分布式系统:RPC和RESTful API都可以用于构建分布式系统,它们都可以实现不同服务之间的通信和交互。

✨6、service mesh解决了什么问题

Service Mesh解决了一系列在微服务架构中遇到的问题,主要包括以下几个方面:

  1. 服务间通信的抽象协议层:Service Mesh将微服务通信下沉到基础设施层,屏蔽了微服务处理各种通信问题的复杂度,形成微服务之间的抽象协议层。
  2. 请求的可靠传递:Service Mesh的目标是确保请求的可靠传递,通过轻量级网络代理的部署方式,实现对业务无侵入。
  3. 安全性的提升:Service Mesh提供了保护网络调用的能力和基础设施,主要体现在服务的认证、服务间通讯的加密、安全相关策略的强制执行等方面。

✔7、对于框架来说,sidecar帮助框架完成了什么问题

对于框架来说,Sidecar可以帮助框架解决以下问题:

  1. 监控和追踪:Sidecar可以负责收集监控数据、分布式追踪数据和日志,从而为整个微服务架构提供实时的性能监控和故障排查能力。
  2. 横切关注点的处理:Sidecar可以用于处理横切关注点,如安全性、监控、日志记录等,而不会对主服务的核心逻辑产生直接影响。
  3. 统一管理:Sidecar可以作为一个独立的进程或容器运行,并通过相同的编排和管理工具进行管理,从而简化了整个系统的部署和运维。
  4. 复用和共享:多个服务实例可以共享同一个Sidecar实例,提高了资源的利用率,并减少了冗余的功能组件。

在容器编排系统(如Kubernetes)中,Sidecar模式通常通过共享同一Pod来实现,其中主服务和Sidecar共享相同的网络命名空间和存储卷。这种方式使得它们能够更加紧密地协同工作。

😢8、Java语言的多线程有哪些同步方式?有何异同

Java语言的多线程同步主要有以下几种方式:

  1. synchronized关键字:这是最简单的一种方式,也是使用最广泛的一种。它可以用于代码块和方法。当一个线程进入synchronized代码块或者方法时,它会获取一个锁,其他线程如果想要进入这个代码块或者方法,就需要等待这个锁被释放。这种方式主要用于保证线程对共享资源的访问的互斥性。
  2. ReentrantLock:ReentrantLock是Java提供的一种显式锁机制,它和synchronized相比,具有更高的灵活性。ReentrantLock可以提供公平锁和非公平锁,而synchronized只能提供非公平锁。ReentrantLock还提供了可以中断获取锁的机制,synchronized则没有。
  3. Semaphore(信号量):Semaphore是一种计数器,用于限制对共享资源的访问权限。它允许你设置一个许可的最大数量,当许可被用完时,新的线程会被阻塞,直到有许可被释放。
  4. CountDownLatch:CountDownLatch是一个同步辅助工具类,它允许一个或多个线程等待,直到在其他线程进行的一组操作完成。
  5. CyclicBarrier:CyclicBarrier是一个同步辅助工具类,它允许一组线程互相等待,直到所有线程都到达某个公共屏障点(Barrier point)。
  6. Exchanger:Exchanger是一个同步辅助工具类,它允许两个线程在某个公共交换点交换数据。
  7. Phaser:Phaser是一种更复杂的同步辅助工具类,它用于帮助协调多个线程的执行顺序。

用途和异同:

  • synchronized和ReentrantLock主要用于实现线程间的互斥,保证同一时间只有一个线程可以访问共享资源。其中,synchronized是内置的锁机制,使用起来比较简单,但功能相对较少;ReentrantLock则提供了更多的灵活性和功能。
  • 这些同步方式有些是可重入的(如synchronized和ReentrantLock),有些则不可重入(如Semaphore)。可重入锁意味着一个线程可以多次获取同一个锁,而不会产生死锁。
  • 有些同步方式是公平的(如ReentrantLock),即等待时间最长的线程会获得锁;有些则是非公平的(如synchronized),即先请求锁的线程会获得锁。

🙌9、Java的字节码可以用于实现哪些功能?

Java的字节码是一种中间代码,用于在Java虚拟机(JVM)上运行Java程序。字节码可以在各种不同的平台上运行,因为它们不是直接运行在硬件上,而是运行在Java虚拟机上。

  1. 编译优化:在运行时,Java虚拟机可以对字节码进行优化,以提高程序的性能。例如,它可以进行即时编译(JIT),将字节码转换为本地代码,以便更高效地运行程序。
  2. 安全性和封装:Java的字节码提供了一种安全性封装的方式。它通过将类和资源封装在单个的类加载器中,从而防止对系统资源的直接访问。这有助于保护系统的安全性和稳定性。
  3. 跨版本兼容性:由于Java字节码是平台无关的,因此它可以用于实现跨版本的兼容性。你可以在不更改代码的情况下更改应用程序的运行环境或Java虚拟机版本。
  4. 实现加密和混淆:Java字节码可以用于实现代码的加密和混淆,以增加对源代码的保护。这有助于防止代码被篡改或盗用。

🤦‍♂️10、假设Java程序在某个地方卡死,如何找到

  1. 查看错误日志:首先检查程序的错误日志或控制台输出。这可能提供了有关错误原因的线索。
  2. 使用调试器:大多数IDE(如Eclipse、IntelliJ IDEA等)都提供了强大的调试工具。你可以设置断点,然后逐步执行代码,查看变量的值,从而找出问题所在。
  3. 堆栈跟踪:当程序卡死时,尝试捕获程序的堆栈跟踪。这可以显示程序在卡死时的调用堆栈,帮助你定位问题。
  4. 性能分析工具:使用性能分析工具(如VisualVM、JProfiler等)来检查程序的性能瓶颈和内存使用情况。这有助于找到可能导致程序卡死的原因。
  5. 代码审查:仔细审查可能导致问题的代码段。检查是否存在无限循环、死锁或其他可能导致程序卡死的问题。
  6. 单元测试:编写单元测试来验证代码的各个部分是否按预期工作。这有助于隔离问题并确定问题的根源。

🙌11、Golang的defer语句执行顺序

在Go语言中,defer语句用于延迟(defer)函数或方法的执行,使其在包含defer语句的函数返回之前执行。defer语句的执行顺序遵循后进先出(LIFO)的原则。

具体来说,当包含defer语句的函数执行时,被延迟执行的函数或方法会被压入一个栈中。当包含defer语句的函数返回时,被延迟执行的函数或方法会按照后进先出的顺序从栈中弹出并执行。

下面是一个示例代码,演示了defer语句的执行顺序:

代码语言:javascript
复制
func main() {  
    defer fmt.Println("First")  
    defer fmt.Println("Second")  
    defer fmt.Println("Third")  
}

在上面的代码中,我们使用了三个defer语句分别延迟了三个fmt.Println函数的执行。当main函数返回时,这三个函数会按照后进先出的顺序执行。

输出结果如下:

代码语言:javascript
复制
Third  
Second  
First

可以看到,Third是第一个被执行的,因为它是最早被延迟的。然后是Second,最后是First。这是因为它们按照后进先出的原则从栈中弹出并执行。

🙌12、defer语句在return之前还是之后执行(X)

在 Go 语言中,defer 语句中的函数调用会在函数执行结束前执行,但在 return 语句之后、函数即将返回之前执行。

具体来说,当函数中包含 defer 语句时,这些 defer 语句中的函数调用会被添加到一个栈中,并在当前函数执行结束前(包括执行结束前的错误情况)按照后进先出(LIFO)的顺序执行。这也包括函数中的 return 语句,但 return 语句实际上并不是最后执行的语句,它会先将返回值赋给函数的返回变量,在随后执行 defer 语句。

代码语言:javascript
复制
package main

import (
 "fmt"
)

func main() {
 fmt.Println("start")
 fmt.Println(deferDemo())
 fmt.Println("end")
}

func deferDemo() int {
 defer fmt.Println("defer 1")
 defer fmt.Println("defer 2")
 defer fmt.Println("defer 3")
 return 10
}

defer 语句中的函数调用会在 return 语句之后、函数即将返回之前执行。因此,输出顺序是先打印 "defer 3"、然后是 "defer 2"、最后是 "defer 1"。

✔13、golang的协程和Java线程有什么区别

Go语言的协程(goroutine)和Java的线程在以下方面存在区别:

  1. 实现方式:Java线程是由Java虚拟机(JVM)管理的,而Go语言的协程是由Go运行时(runtime)系统管理的。
  2. 调度方式:Java线程是抢占式调度,而Go语言的协程是协作式调度。这意味着Java线程的执行时间由操作系统决定,而Go协程的执行时间由Go运行时系统决定。
  3. 并发能力:Go语言通过协程实现了轻量级的并发,而Java线程需要消耗更多的系统资源。因此,Go语言可以创建更多的协程,而Java线程在创建过多时可能会导致系统资源耗尽。
  4. 上下文切换开销:由于Go协程是轻量级的,其上下文切换的开销相对较小。而Java线程的上下文切换开销较大,因为涉及到操作系统级别的资源。
  5. 栈大小:Go协程的栈大小相对较小,而Java线程的栈大小可以根据需要进行调整。
  6. 资源占用:由于Go协程是轻量级的,因此它们占用的资源相对较少。而Java线程需要更多的内存和CPU资源。
  7. 错误处理:在Go语言中,协程的错误处理是通过panic和recover机制实现的。而Java线程则通过异常处理机制进行错误处理。

Go语言的协程和Java的线程在实现方式、调度方式、并发能力、上下文切换开销、栈大小、资源占用以及错误处理等方面存在差异。

✔14、编程题:实现一个带有TTL的LRUCache

在Java中,可以使用LinkedHashMap实现一个带有TTL(生存时间)的LRU(最近最少使用)缓存。下面是一个简单的实现:

代码语言:javascript
复制
import java.util.LinkedHashMap;  
import java.util.Map;  
import java.util.concurrent.TimeUnit;  
  
public class TTLLRUCache<K, V> {  
    private final int capacity;  
    private final long ttl;  
    private final long ttlUnit;  
    private final LinkedHashMap<K, V> cache;  
  
    public TTLLRUCache(int capacity, long ttl, TimeUnit ttlUnit) {  
        this.capacity = capacity;  
        this.ttl = ttl;  
        this.ttlUnit = ttlUnit.toNanos(ttl);  
        this.cache = new LinkedHashMap<>(capacity, 0.75f, false) {  
            protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {  
                return size() > capacity || getEntry(eldest.getKey()).getValue() < System.nanoTime() - ttlUnit;  
            }  
        };  
    }  
  
    public V get(K key) {  
        return cache.get(key);  
    }  
  
    public void put(K key, V value) {  
        cache.put(key, value);  
    }  
}

这个实现使用了LinkedHashMapremoveEldestEntry方法来自动删除最老的条目(即最近最少使用的条目)。当条目数量超过容量或者条目已经过期时,最老的条目将被删除。put方法将新的键值对添加到缓存中,如果缓存已满,则删除最老的条目。get方法只是简单地返回给定键的值,如果键不存在,则返回null


golang实现:

在Go语言中,可以使用container/list包和container/heap包来实现带有TTL的LRUCache。

LRUCache是一个带有最近最少使用记录的缓存,它可以在缓存满时自动删除最老的记录。TTL表示缓存中每个记录的生存时间,当记录达到生存时间时,它将被自动删除。

下面是一个使用container/list包和container/heap包实现的带有TTL的LRUCache的示例代码:

代码语言:javascript
复制
package main  
  
import (  
    "container/heap"  
    "fmt"  
    "sync"  
    "time"  
)  
  
// Item 表示缓存中的记录  
type Item struct {  
    value    interface{} // 记录的值  
    expire   time.Time   // 记录的过期时间  
    priority int         // 记录的优先级,越小优先级越高  
}  
  
// PriorityQueue 实现了 heap.Interface 接口,用于实现优先级队列  
type PriorityQueue []*Item  
  
func (pq PriorityQueue) Len() int { return len(pq) }  
  
func (pq PriorityQueue) Less(i, j int) bool {  
    return pq[i].priority < pq[j].priority  
}  
  
func (pq PriorityQueue) Swap(i, j int) {  
    pq[i], pq[j] = pq[j], pq[i]  
}  
  
func (pq *PriorityQueue) Push(x interface{}) {  
    item := x.(*Item)  
    *pq = append(*pq, item)  
}  
  
func (pq *PriorityQueue) Pop() interface{} {  
    old := *pq  
    n := len(old)  
    item := old[n-1]  
    old[n-1] = nil  // 避免内存泄漏  
    *pq = old[0 : n-1]  
    return item  
}  
  
// LRUCache 实现了带有TTL的LRUCache  
type LRUCache struct {  
    capacity int           // 缓存的最大容量  
    ttl      time.Duration   // 缓存中记录的生存时间  
    pq       PriorityQueue   // 优先级队列,用于维护记录的顺序和优先级  
    mu       sync.Mutex      // 互斥锁,用于保护缓存的并发访问  
}  
  
// NewLRUCache 创建一个带有TTL的LRUCache实例  
func NewLRUCache(capacity int, ttl time.Duration) *LRUCache {  
    return &LRUCache{capacity: capacity, ttl: ttl, pq: make(PriorityQueue, 0)}  
}  
  
// Get 从缓存中获取给定键的值,如果键存在且未过期,则返回值;否则返回nil。  
func (c *LRUCache) Get(key interface{}) interface{} {  
    c.mu.Lock()  
    defer c.mu.Unlock()  
    item, ok := c.pq.value[key] // 从优先级队列中获取键对应的记录  
    if !ok || time.Now().After(item.expire) { // 如果键不存在或已过期,返回nil  
        return nil  
    } else { // 如果键存在且未过期,将该记录的优先级设为最高并重新放入优先级队列中,然后返回其值  
        item.priority = heap.Pop(&c.pq).(*Item).priority + 1000000000000000000 // 将该记录的优先级设为最高并重新放入优先级队列中(不会被优化掉)  
        heap.Push(&c.pq, item) // 将该记录重新放入优先级队列中(会被优化掉)
  • 原文链接:https://github.com/warthecatalyst/What-to-in-Graduate-School/blob/main/%E7%A7%8B%E6%8B%9B%E7%9A%84%E9%9D%A2%E7%BB%8F/%E5%8D%8E%E7%A7%91%E8%AE%A1%E7%A7%91%E7%AC%AC%E4%BA%8C%E4%BA%BA%E7%9A%84%E7%A7%8B%E6%8B%9B%E6%8A%A5%E5%91%8A.md
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-12-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 千羽的编程时光 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ✔1、自我介绍
  • ✔2、简单介绍团队实习概况(5min)
  • ✔3、对RPC有什么了解(从RPC讲到service mesh技术)
  • 🤷‍♂️4、RPC的一个调用过程有哪些步骤(以dubbo为例举例)
  • 👌5、RPC和Restful API有什么区别和联系
  • ✨6、service mesh解决了什么问题
  • ✔7、对于框架来说,sidecar帮助框架完成了什么问题
  • 😢8、Java语言的多线程有哪些同步方式?有何异同
  • 🙌9、Java的字节码可以用于实现哪些功能?
  • 🤦‍♂️10、假设Java程序在某个地方卡死,如何找到
  • 🙌11、Golang的defer语句执行顺序
  • 🙌12、defer语句在return之前还是之后执行(X)
  • ✔13、golang的协程和Java线程有什么区别
  • ✔14、编程题:实现一个带有TTL的LRUCache
相关产品与服务
Serverless HTTP 服务
Serverless HTTP 服务基于腾讯云 API 网关 和 Web Cloud Function(以下简称“Web Function”)建站云函数(云函数的一种类型)的产品能力,可以支持各种类型的 HTTP 服务开发,实现了 Serverless 与 Web 服务最优雅的结合。用户可以快速构建 Web 原生框架,把本地的 Express、Koa、Nextjs、Nuxtjs 等框架项目快速迁移到云端,同时也支持 Wordpress、Discuz Q 等现有应用模版一键快速创建。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档