3

鹅长微服务发现与治理巨作PolarisMesh实践-上 - itxiaoshen

 1 year ago
source link: https://www.cnblogs.com/itxiaoshen/p/16837841.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

鹅长微服务发现与治理巨作PolarisMesh实践-上

PolarisMesh 官网地址 https://polarismesh.cn/

PolarisMesh 官网中文文档 https://polarismesh.cn/zh/doc/北极星是什么/简介.html

PolarisMesh GitHub源码地址 https://github.com/polarismesh

PolarisMesh(北极星)是腾讯开源的支持多语言、多框架的云原生服务发现和治理中心,提供高性能SDK和无侵入Sidecar两种接入方式。

前面多篇文章讲解Spring Cloud Alibaba微服务一站式解决全组件的原理和实践,Spring Cloud Alibaba主要服务于Java技术栈,而PolarisMesh提供多语言、框架无关、服务网格的实现,当之无愧的集大成者。北极星在腾讯内部的服务注册数量超过百万,日接口调用量超过十万亿,通用性和稳定性都得到了大规模的验证。

PolarisMesh不仅提供无侵入Sidecar,还提供高性能SDK,实现语义相同的服务发现和治理功能,用户可以根据业务场景自行选择。对于请求量大和资源消耗敏感用户,可以在业务应用或者开发框架中集成北极星SDK,快速补齐服务发现和治理功能。

PolarisMesh的功能都是基于插件化设计,可单独使用,采用计算存储分离,计算层节点可以随着客户端节点的增加平行扩展,轻松支持百万级节点接入。从功能大类来看,分为注册中心、配置中心以及服务网格三类功能

    • 服务注册发现及服务健康检查:以服务为中心的分布式应用架构,通过服务和注册发现的方式维护不断变化的请求地址,提高应用的扩展能力,降低应用的迁移成本。北极星提供对注册上来的服务实例进行健康检查,阻止主调方对不健康的服务实例发送请求,同时也提供了保护能力,实例剔除超过一定数量则停止剔除,防止因不健康实例过多导致雪崩效应。
    • 动态配置:提供配置管理的功能,支持应用配置、公共配置的订阅发布、版本管理、变更通知,实现应用配置动态生效。
    • 路由和负载均衡:根据请求标签、实例标签和标签匹配规则,对线上流量进行动态调度,可以应用于按地域就近、单元化隔离和金丝雀发布等多种场景。
    • 熔断降级和限流:及时熔断异常的服务、接口、实例或者实例分组,降低请求失败率。针对不同的请求来源和系统资源进行访问限流,避免服务被压垮。
    • 可观测性:支持请求量、请求延时和请求成功率的指标查询,支持服务调用关系和多维度的流量曲线查询,实现服务治理功能和流量观测一体化。
    • Proxyless与Proxy接入:提供多语言SDK、以及无侵入的JavaAgent,适配用户高性能低长尾时延以Porxyless模式的接入场景;同时提供独立的Sidecar,支持用户的低侵入性、基于流量接管的Proxy模式接入场景。
image-20221025182246574

组件和生态

PolarisMesh分为控制平面、数据平面以及生态组件3大类,通过这3大类组件,组成一套完整的微服务治理体系。

image-20221027154828127

PolarisMesh兼容常用的开源框架、网关和 kubernetes。主要包含服务发现和治理中心、多语言应用开发、DNS 和 Proxy、网关。

  • 服务发现和治理中心

    • polaris-console:北极星的可视化控制台,直接面对终端用户,提供可视化界面供用户进行服务管理、配置管理、服务治理规则管理、可观测性等操作。
    • polaris:北极星的注册配置中心,暴露API接口供服务、配置以及治理规则获取及编辑。支持集群化部署,多个polaris集群之间可以共享同一份数据,支持客户端就近接入。
    • polaris-controller:北极星对接k8s的适配组件,可以将k8s的service以及endpoint的数据变更按需同步到北极星,实现 k8s service 和框架服务的统一管理。
    • polaris-limiter:北极星分布式限流的token服务,支持限流配额的汇总以及下发分配。
  • 多语言应用开发:支持Java、Go、C、C++、PHP、Lua,不劫持业务请求,几乎不增加请求延时,CPU 消耗低,不需要部署和运维 Sidecar。支持 grpc 等框架和北极星 SDK 的集成,框架用户不需要直接使用北极星 SDK。比如:

    • Java应用开发:polaris-java(Polaris Java客户端实现)、grpc-java-polaris(使用grpc-java与polaris-java的集成)、spring-cloud-tencent(SpringCloud与腾讯开源中间件的集成解决方案)、spring-boot-polaris(SpringBoot与polaris-java的集成)、polaris-java-agent(polaris-java注入到SpringCloud和Dubbo)。
    • Go应用开发polaris-go(Polaris Go客户端)、grpc-go-polaris(grpc-java与polaris-go的集成)、go-kratos(go-kratos与polaris-go的集成)、go-zero(go-zero与polaris-go的集成)、go-frame(go-frame与polaris-go的集成)、dubbo-go(dubbo-go与polaris-go的集成)、kitex(kitex与polaris-go的集成)。
  • Sidecar:劫持业务请求,有一定的请求延时,CPU 消耗较高,适用于无侵入的开发场景。

  • JavaAgent:对于Java的应用,直接通过字节码的方式加载到进程中,通过拦截器实现无感的接入。

  • 支持 nginx 等网关和北极星 SDK 的集成,支持网关将请求转发到北极星服务。

  • 支持 k8s service 自动注册到北极星,实现 k8s service 和框架服务的统一管理。

  • 一站式服务治理中心:集服务注册中心和服务治理控制面于一体,帮助业务解决分布式或者微服务架构面临的注册发现、故障容错、流量控制和安全问题。
  • 支持多种开发语言:提供Java、Go和C++等多种高性能、功能语义相同的SDK,可以轻松集成到不同的技术栈,帮助企业实现统一的服务发现和治理。
  • 支持常用开发框架:北极星服务治理SDK可以集成到gRPC和Spring Cloud等开发框架中,帮助框架完善服务治理功能。框架用户不感知,接入成本低。
  • 支持Kubernetes:提供原生的k8s polaris-controller,支持k8s service自动注入,帮助k8s无缝兼容微服务框架体系,实现跨集群的服务发现和治理。
  • 服务网格:提供高性能SDK和无侵入Sidecar两种接入方式,采用SDK和Sidecar的服务可以互相访问,功能语义相同,适用于不同的业务场景。
  • 大规模生产应用:腾讯服务治理中心的开源版本,为腾讯百万服务提供标准的服务治理功能,沉淀了腾讯从虚拟机到容器时代的分布式服务治理经验

解决哪些问题

在分布式架构及微服务架构实施过程中,业务可能面临以下四类问题。北极星以服务为中心,提供一站式解决方案。

image-20221026122419459

官方性能数据

在长时间的压力测试下,不同规格的北极星集群均维持正常运行状态,集群可承载的实例容量从1k实例到10w实例,相关依赖组件的系统资源消耗也均在预期内,并未出现相关依赖组件高负载不可用现象。通过压测,不同规格的北极星集群可以稳定支撑服务实例数量均满足预期。

  • 注册实例的TPS最高可达35912,符合接口预期
  • 服务发现的QPS最高可达116021,符合接口预期
  • 实例心跳的TPS最高可达78077,符合接口预期
  • 注销实例的TPS最高可达14356,符合接口预期

PolarisMesh的资源模型与前面学习Nacos很相似,包括如下:

  • 命名空间:提供了一种在相同注册中心下资源的逻辑隔离的机制,同一命名空间下的资源命名必须唯一,但是跨命名空间允许存在同名的资源。命名空间常用于多个团队或者项目之间的资源的区分隔离。
  • 服务:一种资源对外暴露的抽象方式,资源本身通过端口监听的方式提供网络访问,并通过提供一系列预定义的服务接口,给主调端进行调用。
  • 实例分组:是由一个或多个具有相同标签属性的实例组成,这些实例往往具备相同的特征,比如属于同一版本、属于同一个地域、属于同一环境。
  • 服务实例:对应的是暴露一个或多个API接口供主调应用进行网络调用的节点,通过IP:PORT的方式进行唯一标识。

PolarisMesh是服务发现与治理中心,其主要应用在微服务之间的RPC调用过程中服务可见、流量控制、故障容错等场景,涉及服务注册、服务发现、动态路由、负载均衡、健康检查、访问限流、熔断降级。

image-20221027161936076

整体流程如下:

  • RPC调用过程的参与者主要涉及两个角色:主调方和被调方。
  • 首先,被调方使用服务注册功能,向北极星注册自身服务数据,包括节点列表,治理规则等。
  • 第二,主调方通过服务发现功能,拉取被调方的全量服务数据。
  • 第三,主调方通过路由和负载均衡功能,筛选出一个合适的被调方实例,进行RPC调用。
  • 第四,主调方记录RPC调用的成功失败结果,通过熔断降级功能,剔除出现故障的被调方节点。
  • 第五,北极星通过健康检查功能,主动剔除已经下线的被调方节点。
  • 第六,被调方通过访问限流功能,保护自身不被主调方的异常流量给击溃。

服务注册指的是被调方按照服务模型将自身的服务数据注册到PolarisMesh,以供主调方进行服务发现。服务数据主要包括以下部分:

  • 服务名:服务的唯一标识,区分大小写。
  • 服务元数据:服务的标签信息,KV格式,可对服务进行分类,可用于过滤。
  • 服务实例:提供服务的节点列表,以IP:PORT的方式提供。
  • 服务实例元数据:服务实例的标签信息,KV格式,通常用于描述节点的集群、版本等,用于后续流量治理等操作。
image-20221027173742909

支持以下4种服务注册方式:

  • 通过SDK注册:北极星提供了多语言SDK,服务可以通过集成SDK,调用registerInstance接口完成服务注册。
  • 通过服务框架注册:服务一般与服务框架集成(比如Spring Cloud Tencent (opens new window)),框架本身会提供服务自动注册功能,服务启动后,框架会将服务信息自动注册到北极星。
  • 通过k8s同步的方式注册:用户通过k8s部署服务,并注册为k8s的service,北极星通过controller的机制,从k8s中将service和endpoint信息同步到北极星,完成服务注册。
  • 通过OpenAPI注册:北极星控制面提供基于Rest标准的OpenAPI,用户可通过OpenAPI完成服务注册的操作。

服务发现指的主调方是根据服务名标识,拉取服务实例列表,以供后续进行服务调用的操作。

image-20221027175918206

支持以下4种方式进行服务发现:

  • 通过SDK服务发现:北极星提供了多语言SDK,服务可以通过集成SDK,调用getAllInstances接口完成全量服务列表拉取。
  • 使用框架服务发现:北极星支持对接多个主流的服务框架(比如Spring Cloud Tencent (opens new window)),主调方服务通过服务框架进行发现RPC请求,即可通过框架内部扩展机制使用北极星服务发现能力。
  • 使用sidecar服务发现:北极星提供服务网格能力,服务程序可以基于sidecar的方式,通过DNS或者流量拦截,进行服务发现。
  • 使用OpenAPI服务发现:北极星控制面提供基于Rest标准的OpenAPI,用户可通过OpenAPI完成服务发现的操作。

由于单机安装比较简单,我们这里就直接选择集群安装,准备好两台部署服务器,而MySQL、Redis、Promethes的安装可以参考前面对应的文章,这里就直接使用。

image-20221027182654541
组件 类型 功能说明
polaris 最新stable版本 系统组件 服务治理控制面
polaris-console 最新stable版本 系统组件 服务治理控制台
MySQL >= 5.7 第三方依赖 服务数据存储
Redis >=4.0 第三方依赖 心跳状态数据缓存
Prometheus >=2.28.0 第三方依赖 可观测性
  • 初始数据导入
# 下载polaris最新版本v1.12.1
wget https://github.com/polarismesh/polaris/releases/download/v1.12.1/polaris-server-release_v1.12.1.linux.amd64.zip
# 下载polaris-console最新版本v1.9.1
wget https://github.com/polarismesh/polaris-console/releases/download/v1.9.1/polaris-console-release_v1.9.1.linux.amd64.zip
# 解压polaris-server
unzip polaris-server-release_v1.12.1.linux.amd64.zip
# 解压polaris-console
unzip polaris-console-release_v1.9.1.linux.amd64.zip
# 进入polaris-server目录
cd polaris-server-release_v1.12.1.linux.amd64
# 执行mysql脚本导入到mysql数据库
mysql -u root -p 123456 -h 192.168.50.100 < store/sqldb/scripts/polaris_server.sql

将文件拷贝到两台服务器上,下面操作两台一样

  • 配置数据库参数:修改polaris-server.yaml里面的store配置,去掉单机文件存储的boltdbStore相关配置,并放开defaultStore相关配置。
# 存储配置
store:
# 数据库存储插件
  name: defaultStore
  option:
    master:
      dbType: mysql
      dbName: polaris_server
      dbAddr: 192.168.50.100:3306
      dbUser: root
      dbPwd: 123456
  • 开启自动注册:修改polaris-server.yaml里面的服务自注册配置,将enable_register改成true,并填入probe_address:
bootstrap:
  polaris_service:
    # 设置为true代表启用自动注册
    enable_register: true
    # 填入数据库地址,用于获取当前节点ip信息
    probe_address:192.168.50.100:3306
  • 配置Redis参数:修改polaris-server.yaml里面的healthcheck配置,去掉heartbeatMemory相关配置,并放开heartbeatRedis相关配置。
healthcheck:
  checkers:
  - name: heartbeatRedis
    option:
	  #填入redis的IP以及端口
      kvAddr: 192.168.50.100:6379
	  #填入redis的密码
      kvPasswd: 123456
      maxIdle: 200
      idleTimeout: 120s
      connectTimeout: 200ms
      msgTimeout: 200ms
      concurrency: 200  
  • 启动polaris-discover:
bash ./tool/start.sh
bash ./tool/p.sh

image-20221028133446497

  • 修改prometheus配置:打开 prometheus.yml文件,修改prometheus的job配置,增加http_sd_configs,其作用是告知prometheus需要从北极星获取应用的监控上报的地址。
  - job_name: 'prometheus'
    static_configs:
    - targets: ['localhost:9090']

    http_sd_configs:
      - url: http://192.169.5.52:9000/prometheus/v1/clients

    honor_labels: true   
  • 启动prometheus:
nohup ./prometheus --web.enable-lifecycle --web.enable-admin-api >> prometheus.out 2>&1 &
  • 进入polaris-console目录,修改polaris-console的配置:打开polaris-console.yaml文件,修改monitorServer的地址,将原来的127.0.0.1:9090替换成prometheus的监听地址
monitorServer:
  address: "192.168.5.52:9090"
  • 启动polaris-console:
bash ./tool/start.sh
bash ./tool/p.sh

image-20221028133606495

  • 访问http://192.168.5.52:8080,可以看到登录页面,输入登录控制台的默认登录账户信息polaris/polaris,登录后可以成功看到北极星服务治理控制台内容
image-20221028133710676

SpringCloud应用接入

Spring Cloud 是 Java 语言生态下的分布式微服务架构的一站式解决方案,为了方便 Spring Cloud 用户快速接入北极星,我们通过以下几个示例帮助用户如何在 Spring Cloud 中体验北极星的相关功能。 Spring Cloud 版本相对应的 Spring Cloud Tencent 版本如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nw4H2svH-1666971286536)(image-20221028134706394.png)]

选择Spring Cloud 版本为 2021.0.3、Spring Cloud Tencent 版本为 1.7.0-2021.0.3

创建演示父项目

在Idea中新建一个空的maven项目,Pom文件增加与Spring Cloud Tencent 的父依赖spring-cloud-tencent-dependencies和SpringBoot的父依赖spring-boot-starter-parent。

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">                <parent>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-parent</artifactId>        <version>2.6.9</version>        <relativePath/> <!-- lookup parent from repository -->    </parent>    <dependencyManagement>        <dependencies>            <dependency>                <groupId>com.tencent.cloud</groupId>                <artifactId>spring-cloud-tencent-dependencies</artifactId>                <version>1.7.0-2021.0.3</version>                <type>pom</type>                <scope>import</scope>            </dependency>            <dependency>                <groupId>org.springframework.cloud</groupId>                <artifactId>spring-cloud-dependencies</artifactId>                <version>2021.0.3</version>                <type>pom</type>                <scope>import</scope>            </dependency>        </dependencies>    </dependencyManagement>    <dependencies>        <!-- 简单的 Spring Cloud Web 依赖 -->        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <!-- 引入 Spring Cloud Tencent 的服务注册发现依赖 -->        <dependency>            <groupId>com.tencent.cloud</groupId>            <artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>        </dependency>    </dependencies></project>

提供者微服务示例

在项目中添加一个provider-service模块,在提供者微服务的pom依赖中添加父Maven项目的依赖、 Web 服务依赖、polaris服务注册依赖

  <parent>    <groupId>cn.itxs</groupId>    <artifactId>spring-cloud-tencent-demo</artifactId>    <version>1.0-SNAPSHOT</version>  </parent>        <!-- 简单的 Spring Cloud Web 依赖 -->    <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-web</artifactId>    </dependency>    <!-- 引入 Spring Cloud Tencent 的服务注册发现依赖 -->    <dependency>      <groupId>com.tencent.cloud</groupId>      <artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>    </dependency>             <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-autoconfigure</artifactId>    </dependency>

在provider-service的 resources 目录下创建 application.yml 文件,并按照如下进行配置

server:  port: 28888spring:  application:    name: provider-service  cloud:    polaris:      # 配置polaris servre地址      address: grpc://192.168.5.52:8091      discovery:        enabled: true      stat:        enabled: true        port: 28082

创建提供者微服务演示控制器ProviderHelloController.java

package cn.itxs.controller;import com.tencent.cloud.polaris.PolarisDiscoveryProperties;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class ProviderHelloController {    private final PolarisDiscoveryProperties properties;    ProviderHelloController(PolarisDiscoveryProperties properties) {        this.properties = properties;    }    @RequestMapping("/hello/{val}")    public String echo(@PathVariable String val) {        return "Hello PolarisMesh,this is it xiao shen," + val + ", I'm " + properties.getService();    }}

启动类ProviderApplication.java

package cn.itxs;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class ProviderApplication{    public static void main(String[] args) {        SpringApplication.run(ProviderApplication.class, args);    }}

启动提供者微服务ProviderApplication

image-20221028160102151

查看控制台页面服务列表可以看到提供者微服务已经注册到北极星中default命名空间

image-20221028160200456

消费者微服务示例

与上面服务提供类似,在项目中添加一个consumer-service模块,在消费者微服务的pom依赖中添加父Maven项目的依赖、 Web 服务依赖、polaris服务注册依赖

   <parent>
    <groupId>cn.itxs</groupId>
    <artifactId>spring-cloud-tencent-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>   

	<dependencies>
        <!-- 简单的 Spring Cloud Web 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 引入 Spring Cloud Tencent 的服务注册发现依赖 -->
        <dependency>
            <groupId>com.tencent.cloud</groupId>
            <artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
        </dependency>
        <!-- 引入 Feign 依赖实现 Feign 调用 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

在consumer-service的 resources 目录下创建 application.yml 文件,并按照如下进行配置

server:
  port: 38888
spring:
  application:
    name: consumer-service
  cloud:
    polaris:
      address: grpc://192.168.5.52:8091
      discovery:
        enabled: true
      stat:
        enabled: true
        port: 38082

创建Feign接口HelloService.java,通过feign实现远程方法的调用

package cn.itxs.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Service
@FeignClient(name = "provider-service")
public interface HelloService {

    @RequestMapping("/hello/{value}")
    String hello(@PathVariable("value") String value);
}

创建提供者微服务演示控制器ProviderHelloController.java

package cn.itxs.controller;

import cn.itxs.service.HelloService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ConsumerHelloController {

    private final HelloService helloService;

    ConsumerHelloController(HelloService helloService) {
        this.helloService = helloService;
    }

    @RequestMapping(value = "/hello/{val}")
    public String echo(@PathVariable String val) {
        return helloService.hello(val);
    }
}

启动类ConsumerApplication.java

package cn.itxs;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class ConsumerApplication
{
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}

启动消费者微服务ProviderApplication

image-20221028162531204

查看控制台页面服务列表可以看到提供者微服务已经注册到北极星中default命名空间

image-20221028162618308

通过消费者提供控制器访问接口访问,http://192.168.44.161:38888/hello/1 ,返回服务提供者的结果,成功实现服务注册和发现。

image-20221028162723954

动态配置示例

引入spring-cloud-starter-tencent-polaris-config 实现 Spring Cloud 配置的动态管理,spring-cloud-starter-bootstrap 以便可以支持 bootstrap.yml 的识别与加载。添加依赖如下:

    <dependency>
      <groupId>com.tencent.cloud</groupId>
      <artifactId>spring-cloud-starter-tencent-polaris-config</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-bootstrap</artifactId>
    </dependency>

在 resources 目录下创建 bootstrap.yml 文件,并按照如下进行配置

server:
  port: 48084
spring:
  application:
    name: config-group
  cloud:
    polaris:
      address: grpc://192.168.5.52:8091
      namespace: default
      config:
        auto-refresh: true # auto refresh when config file changed
        groups:
          - name: ${spring.application.name} # group name
            files: [ "config/user.yaml" ]

创建配置分组以及配置文件

  • 创建配置分组 config-group
  • 创建配置文件 config/user.yaml,编辑和发布配置,编辑配置项内容为name: zhangsan

创建提供者微服务演示控制器ConfigController.java

package cn.itxs.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RefreshScope
public class ConfigController {

    @Value("${name}")
    private String name;

    @RequestMapping("/name")
    public String name() {
        return name;
    }
}
image-20221028171609318

启动后访问http://192.168.44.161:48084/name,成功读到北极星配置中心的配置

image-20221028170327198

**本人博客网站 **IT小神 www.itxiaoshen.com


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK