Code Monkey home page Code Monkey logo

r-nacos's People

Contributors

asmpg avatar aurorxa avatar dickens7 avatar freedomfirebody avatar heqingpan avatar zzyandzzy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

r-nacos's Issues

只保留一个控制台

8848那个控制台没有权限控制,是否可以考虑关掉8848的控制台 或者将10848的控制台合并到8848 只保留一个控制台

项目总体开发计划

项目总体上主要分下面几个大块:

  1. 面向 client sdk功能模块,这部分需要和 nacos server完全兼容。目前这块已基本完全兼容,如果还有问题就算 bug,可以提 issuce 反馈,bug会优先解决。
  2. 面向开发、管理员的控制台模块,这部分不需要、不要求与 nacos server兼容。目前控制台基本功能已经可用,主要是没有访问校验,不能对外面环境提供管理功能。后继准备开发新控制台,支持新开一个独立http端口、支持用户密码登陆、支持对外网暴露。
  3. 面向集群模块,这部分使用 raft 协议与distro协议,不需要与 nacos server 兼容。功能上目前已基本开发完成、基本可用,主要是对配置中心的写入性能还有提升空间。后继准备优化 raft 协议实现,提升配置中心写入性能。
  4. 面向本项目开发者的支持模块。目前功能、性能测试用例只是半自动化,覆盖面也有所不足,有提升空间。
  5. 面向使用本服务的运维用户。这部分主要对集群部署便捷性、友好性的支撑开发,以及提供友好的文档、用例。 比如支持docker 、k8s 部署用例与文档说明。

兼容 java nacos-client 1.3.x

rnacos 基于actix-web实现http服务。
actix-web post请求自动构建参数 web::Form<T> 要求 http请求 header要设置Content-Type: application/x-www-form-urlencoded

java nacos-client 1.3.x 的 post http 请求header没有设置Content-Type: application/x-www-form-urlencoded ,导致请求处理失败。

通过将 web::Form<T> 自动构建参数对象的方式更新为从 request body 手动构建参数,兼容兼容 java nacos-client 1.3.x 。

关于建议使用组织来管理r-nacos 项目,正在推进中

我个人之前对怎么管理开源项目其实是没有经验的,在了解组织管理的更合适多人共同协作功能后,基本认同这个建议。

目前r-nacos组织已经申请下来,后继的步骤还在探索中。

等完全迁移好之后,会在新组织项目中推进项目开发工作;同时在本仓库readme 加对应说明,并对本仓库动静存档。

(没关闭本 issue 前说明没有迁移完成,还会在本仓库开发。)

java.io.FileNotFoundException: /nacos/v1/ns/operator/metrics

Nacos-Java-Client:v1.4.1

rnacos:v0.3.7 Release解压启动

启动服务时报错:

2023-09-29 17:25:56.832 ERROR  [on(8)-192.168.12.110] com.alibaba.nacos.client.naming          [ 617] : [NA] failed to request
java.io.FileNotFoundException: http://localhost:8848/nacos/v1/ns/operator/metrics?app=unknown&namespaceId=public
	at sun.reflect.GeneratedConstructorAccessor96.newInstance(Unknown Source)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at sun.net.www.protocol.http.HttpURLConnection$10.run(HttpURLConnection.java:1964)
	at sun.net.www.protocol.http.HttpURLConnection$10.run(HttpURLConnection.java:1959)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.net.www.protocol.http.HttpURLConnection.getChainedException(HttpURLConnection.java:1958)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1528)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1512)
	at com.alibaba.nacos.common.http.client.response.JdkHttpClientResponse.getBody(JdkHttpClientResponse.java:60)
	at com.alibaba.nacos.common.http.client.handler.AbstractResponseHandler.handleError(AbstractResponseHandler.java:51)
	at com.alibaba.nacos.common.http.client.handler.AbstractResponseHandler.handle(AbstractResponseHandler.java:44)
	at com.alibaba.nacos.common.http.client.NacosRestTemplate.execute(NacosRestTemplate.java:483)
	at com.alibaba.nacos.common.http.client.NacosRestTemplate.exchangeForm(NacosRestTemplate.java:427)
	at com.alibaba.nacos.client.naming.net.NamingProxy.callServer(NamingProxy.java:603)
	at com.alibaba.nacos.client.naming.net.NamingProxy.reqApi(NamingProxy.java:526)
	at com.alibaba.nacos.client.naming.net.NamingProxy.reqApi(NamingProxy.java:498)
	at com.alibaba.nacos.client.naming.net.NamingProxy.reqApi(NamingProxy.java:493)
	at com.alibaba.nacos.client.naming.net.NamingProxy.serverHealthy(NamingProxy.java:445)
	at com.alibaba.nacos.client.naming.NacosNamingService.getServerStatus(NacosNamingService.java:512)
	at com.alibaba.cloud.nacos.discovery.actuate.health.NacosDiscoveryHealthIndicator.doHealthCheck(NacosDiscoveryHealthIndicator.java:43)
	at org.springframework.boot.actuate.health.AbstractHealthIndicator.health(AbstractHealthIndicator.java:82)
	at org.springframework.boot.actuate.health.HealthIndicator.getHealth(HealthIndicator.java:37)
	at org.springframework.boot.actuate.health.HealthEndpoint.getHealth(HealthEndpoint.java:77)
	at org.springframework.boot.actuate.health.HealthEndpoint.getHealth(HealthEndpoint.java:40)
	at org.springframework.boot.actuate.health.HealthEndpointSupport.getContribution(HealthEndpointSupport.java:130)
	at org.springframework.boot.actuate.health.HealthEndpointSupport.getAggregateContribution(HealthEndpointSupport.java:141)
	at org.springframework.boot.actuate.health.HealthEndpointSupport.getContribution(HealthEndpointSupport.java:126)
	at org.springframework.boot.actuate.health.HealthEndpointSupport.getHealth(HealthEndpointSupport.java:95)
	at org.springframework.boot.actuate.health.HealthEndpointSupport.getHealth(HealthEndpointSupport.java:66)
	at org.springframework.boot.actuate.health.HealthEndpoint.health(HealthEndpoint.java:71)
	at org.springframework.boot.actuate.health.HealthEndpoint.health(HealthEndpoint.java:61)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282)
	at org.springframework.boot.actuate.endpoint.invoke.reflect.ReflectiveOperationInvoker.invoke(ReflectiveOperationInvoker.java:74)
	at org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOperation.invoke(AbstractDiscoveredOperation.java:60)
	at org.springframework.boot.actuate.endpoint.jmx.EndpointMBean.invoke(EndpointMBean.java:121)
	at org.springframework.boot.actuate.endpoint.jmx.EndpointMBean.invoke(EndpointMBean.java:96)
	at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
	at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
	at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468)
	at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76)
	at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309)
	at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1401)
	at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829)
	at sun.reflect.GeneratedMethodAccessor136.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357)
	at sun.rmi.transport.Transport$1.run(Transport.java:200)
	at sun.rmi.transport.Transport$1.run(Transport.java:197)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
	at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.FileNotFoundException: http://localhost:8848/nacos/v1/ns/operator/metrics?app=unknown&namespaceId=public
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1910)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1512)
	at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
	at com.alibaba.nacos.common.http.client.response.JdkHttpClientResponse.getStatusCode(JdkHttpClientResponse.java:75)
	at com.alibaba.nacos.common.http.client.handler.AbstractResponseHandler.handle(AbstractResponseHandler.java:43)
	... 52 common frames omitted
2023-09-29 17:25:56.833 ERROR  [on(8)-192.168.12.110] com.alibaba.nacos.client.naming          [ 552] : request: /nacos/v1/ns/operator/metrics failed, servers: [localhost:8848], code: 500, msg: http://localhost:8848/nacos/v1/ns/operator/metrics?app=unknown&namespaceId=public
2023-09-29 17:25:57.215  INFO  [lient.naming.updater] com.alibaba.nacos.client.naming          [ 228] : new ips(1) service: DEFAULT_GROUP@@service@@DEFAULT -> [{"instanceId":"192.168.12.110#8010","ip":"192.168.12.110","port":8010,"weight":1.0,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"DEFAULT","serviceName":"DEFAULT_GROUP@@service","metadata":{"preserved.register.source":"SPRING_CLOUD"},"instanceHeartBeatInterval":5000,"instanceHeartBeatTimeOut":15000,"ipDeleteTimeout":30000}]
2023-09-29 17:25:57.230  INFO  [lient.naming.updater] com.alibaba.nacos.client.naming          [ 267] : current ips:(1) service: DEFAULT_GROUP@@service@@DEFAULT -> [{"instanceId":"192.168.12.110#8010","ip":"192.168.12.110","port":8010,"weight":1.0,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"DEFAULT","serviceName":"DEFAULT_GROUP@@service","metadata":{"preserved.register.source":"SPRING_CLOUD"},"instanceHeartBeatInterval":5000,"instanceHeartBeatTimeOut":15000,"ipDeleteTimeout":30000}]
2023-09-29 17:26:24.067  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 486] : [fixed-localhost_8848] [polling-resp] config changed. dataId=service, group=DEFAULT_GROUP
2023-09-29 17:26:24.075  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 486] : [fixed-localhost_8848] [polling-resp] config changed. dataId=service.yml, group=DEFAULT_GROUP
2023-09-29 17:26:24.076  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 598] : get changedGroupKeys:[service+DEFAULT_GROUP, service.yml+DEFAULT_GROUP]
2023-09-29 17:26:24.095  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 616] : [fixed-localhost_8848] [data-received] dataId=service, group=DEFAULT_GROUP, tenant=null, md5=, content=, type=null
2023-09-29 17:26:24.105  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 616] : [fixed-localhost_8848] [data-received] dataId=service.yml, group=DEFAULT_GROUP, tenant=null, md5=, content=, type=null
2023-09-29 17:26:24.263  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 486] : [fixed-localhost_8848] [polling-resp] config changed. dataId=service, group=DEFAULT_GROUP
2023-09-29 17:26:24.265  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 486] : [fixed-localhost_8848] [polling-resp] config changed. dataId=service.yml, group=DEFAULT_GROUP
2023-09-29 17:26:24.265  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 598] : get changedGroupKeys:[service+DEFAULT_GROUP, service.yml+DEFAULT_GROUP]
2023-09-29 17:26:24.270  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 616] : [fixed-localhost_8848] [data-received] dataId=service, group=DEFAULT_GROUP, tenant=null, md5=, content=, type=null
2023-09-29 17:26:24.273  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 616] : [fixed-localhost_8848] [data-received] dataId=service.yml, group=DEFAULT_GROUP, tenant=null, md5=, content=, type=null
2023-09-29 17:26:24.464  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 486] : [fixed-localhost_8848] [polling-resp] config changed. dataId=service, group=DEFAULT_GROUP
2023-09-29 17:26:24.466  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 486] : [fixed-localhost_8848] [polling-resp] config changed. dataId=service.yml, group=DEFAULT_GROUP
2023-09-29 17:26:24.466  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 598] : get changedGroupKeys:[service+DEFAULT_GROUP, service.yml+DEFAULT_GROUP]
2023-09-29 17:26:24.472  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 616] : [fixed-localhost_8848] [data-received] dataId=service, group=DEFAULT_GROUP, tenant=null, md5=, content=, type=null
2023-09-29 17:26:24.476  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 616] : [fixed-localhost_8848] [data-received] dataId=service.yml, group=DEFAULT_GROUP, tenant=null, md5=, content=, type=null
2023-09-29 17:26:24.660  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 486] : [fixed-localhost_8848] [polling-resp] config changed. dataId=service, group=DEFAULT_GROUP
2023-09-29 17:26:24.664  INFO  [fixed-localhost_8848] c.a.n.client.config.impl.ClientWorker    [ 486] : [fixed-localhost_8848] [polling-resp] config changed. dataId=service.yml, group=DEFAULT_GROUP
......

后面五行就一直重复

大佬,我想参与到开发当中,请问是否可以?

我这边,工作中也是用 Java+Nacos 的,学了 Rust 之后一直不知道干啥。
如果大佬觉得可以的话,可以给我分配几个任务,我在工作以外的时间尽量完成,目前也是在熟悉项目的过程中。
anyway,谢谢。

想先了解下该项目重写的方式

想问下老师,您用rust重写nacos server的方式,是以java语言的方式编写rust来重写,还是以rust语言本身的习惯来重写的,还是其他什么方式?

接入依赖注入容器,简化有相互依赖的actor实例构造【feature】

rnacos主体逻辑是基于actix框架实现。

目前存在不少actor有相互依赖,一个actor 不是直接访问另一个 actor,通过消息传递信息,依赖关系构造维护有点复杂。

准备接入依赖注入容器,初始化时统一从容器取依赖的 actor 地址,简化有相互依赖的actor实例构造。

nginx服务器配置

操作系统:AlmaLinux8
我尝试了开放10848端口,可以正常访问控制台
但是我放到nginx中,怎么配置都不行,提示:
image

// 这个看起来302失败 ?看下面的端口7890,是内部跳转么,我看服务器没有这个端口的信息。
//开放端口时,我看应该是302到了 http://127.0.0.1:18848/p/login...... 这个url,不知道是否有什么影响
image


我的nginx正常配置:
location /rnacos {
proxy_pass http://127.0.0.1:18848;
}
求指导。

关于项目名称更改,初步确定更改为 r-nacos

之前的项目名称为rnacos 这个看起来很像macos有歧义,所以需要改名称使其更清晰。

最开始项目名想定为 racos,不过这个名称在 crates已被占用。

新的名称暂定为 r-nacos

后继项目的readme与文章都会使用新的名称r-nacos

github中的项目地址被之前的一些文章引用,暂时不动。

尝试使用k8s部署,节点 IP 地址变更问题

我尝试将 rnacos 部署到K8S中,当pod重启后pod的ip会发生变化。

当其中的节点(pod)重启后控制台中【集群信息】中显示的IP也与实际IP不一致,重启后的从节点都各自启动为了独立的节点

  • web 控制台显示信息
    image

  • 实际 IP 信息
    image

  • 主节点错误日志如下

[2024-01-10T07:33:29.308378Z ERROR async_raft_ext::replication] error sending AppendEntries RPC to target|LineRate| error=status: Unknown, message: "transport error: error trying to connect: tcp connect error: Connection refused (os error 111)", details: [], metadata: MetadataMap { headers: {} }
[2024-01-10T07:33:30.311986Z ERROR async_raft_ext::replication] timeout while sending AppendEntries RPC to target error=deadline has elapsed
[2024-01-10T07:33:30.815980Z ERROR async_raft_ext::replication] timeout while sending AppendEntries RPC to target error=deadline has elapsed
[2024-01-10T07:33:31.319909Z ERROR async_raft_ext::replication] timeout while sending AppendEntries RPC to target error=deadline has elapsed

nacos鉴权

是不是最新的版本还不支持鉴权操作,还有个就是有linux arm架构的包吗?

openapi接口重构和补充

调整open api结构,之前是分散在注册、配置中心的内核模块中。

补充部分非面向sdk的openapi v1接口。

配置中心使用raft协议支持集群部署

  1. 根据raft协议论文,熟悉raft 交互逻辑

  2. rust 有几个raft库,初定在openraft和async-raft中选一个

    • openraft 的样例完成度比较高,先选 openraft
    • 因 openraft 版本性能不太理想,切换成async-raft实现。
  3. 完成一版接入raft的结构设计
    t003

  4. 开发

    • 初步完主体成功能开发 ,三个实例的集群写入同步功能验证通过
    • 整理代码,处理代码报警和格式化问题。
    • 调整配置,支持单机模式与集群模式。单机默认使用单节点集群模式。
  5. 测试验收

    • 配置中心写入压测
      • 2023-07-16 压测结果不理想。 openraft leader 节点优先处理请求,但几乎没有同步到从节点,停止压测流量后,才开始同步到从节点。 也可能是我使用方式不对,还需要进一步确认原因。
      • 2023-07-22 切换到async-raft实现版本,写入性能可接受。性能还有优化空间,先实现功能后继再进一步优化性能。
    • 分别完成主节点、从节点的写入、查询功能测试。
  6. 合并代码到主干

    • 补充集群模式配置说明文档。
    • 合并代码到主干。

简化控制台登录验证码

收到用户反馈:目前控制台登录验证码比较复杂,容易输入错误。

计划简化验证码的图案复杂度,验证码内容固定为4位。

同时透出可配置控制台登录过期的配置项,让用户可自定义登录过期时间。

gateway链接rnacos异常

gateway 4.0.4 alibaba2022.0.0 nacosclient 版本2.2.3 boot版本3.1.0 cloud版本2022.0.2

网关会间隔性报错
2023-08-24 18:56:08.692 | [requestId:] | [19] | ERROR com.alibaba.cloud.nacos.discovery.NacosDiscoveryClient 86 getServices | get service name from nacos server failed. com.alibaba.nacos.api.exception.NacosException: ServiceListRequest RequestHandler Not Found
at com.alibaba.nacos.common.remote.client.RpcClient.request(RpcClient.java:662) ~[nacos-client-2.2.3.jar:?]
at com.alibaba.nacos.common.remote.client.RpcClient.request(RpcClient.java:623) ~[nacos-client-2.2.3.jar:?]
at com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy.requestToServer(NamingGrpcClientProxy.java:357) ~[nacos-client-2.2.3.jar:?]
at com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy.getServiceList(NamingGrpcClientProxy.java:283) ~[nacos-client-2.2.3.jar:?]
at com.alibaba.nacos.client.naming.remote.NamingClientProxyDelegate.getServiceList(NamingClientProxyDelegate.java:162) ~[nacos-client-2.2.3.jar:?]
at com.alibaba.nacos.client.naming.NacosNamingService.getServicesOfServer(NacosNamingService.java:452) ~[nacos-client-2.2.3.jar:?]
at com.alibaba.nacos.client.naming.NacosNamingService.getServicesOfServer(NacosNamingService.java:440) ~[nacos-client-2.2.3.jar:?]
at com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery.getServices(NacosServiceDiscovery.java:70) ~[spring-cloud-starter-alibaba-nacos-discovery-2022.0.0.0.jar:2022.0.0.0]
at com.alibaba.cloud.nacos.discovery.NacosDiscoveryClient.getServices(NacosDiscoveryClient.java:80) ~[spring-cloud-starter-alibaba-nacos-discovery-2022.0.0.0.jar:2022.0.0.0]
at org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient.getServices(CompositeDiscoveryClient.java:67) ~[spring-cloud-commons-4.0.2.jar:4.0.2]
at org.springframework.cloud.client.discovery.health.DiscoveryClientHealthIndicator.health(DiscoveryClientHealthIndicator.java:73) ~[spring-cloud-commons-4.0.2.jar:4.0.2]
at org.springframework.boot.actuate.health.HealthIndicator.getHealth(HealthIndicator.java:37) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.health.HealthEndpoint.getHealth(HealthEndpoint.java:82) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.health.HealthEndpoint.getHealth(HealthEndpoint.java:41) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.health.HealthEndpointSupport.getLoggedHealth(HealthEndpointSupport.java:172) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.health.HealthEndpointSupport.getContribution(HealthEndpointSupport.java:145) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.health.HealthEndpointSupport.getAggregateContribution(HealthEndpointSupport.java:156) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.health.HealthEndpointSupport.getContribution(HealthEndpointSupport.java:141) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.health.HealthEndpointSupport.getAggregateContribution(HealthEndpointSupport.java:156) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.health.HealthEndpointSupport.getContribution(HealthEndpointSupport.java:141) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.health.HealthEndpointSupport.getHealth(HealthEndpointSupport.java:110) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.health.HealthEndpointSupport.getHealth(HealthEndpointSupport.java:81) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.health.HealthEndpoint.health(HealthEndpoint.java:76) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.health.HealthEndpoint.health(HealthEndpoint.java:66) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-6.0.9.jar:6.0.9]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) ~[spring-aop-6.0.9.jar:6.0.9]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-6.0.9.jar:6.0.9]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-6.0.9.jar:6.0.9]
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) ~[spring-aop-6.0.9.jar:6.0.9]
at io.github.vino42.endpoint.EndPointAspect.judgeIfSafeRequestToActuator(EndPointAspect.java:77) ~[lll-metadata-1.0-SNAPSHOT.jar:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:637) ~[spring-aop-6.0.9.jar:6.0.9]
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:627) ~[spring-aop-6.0.9.jar:6.0.9]
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) ~[spring-aop-6.0.9.jar:6.0.9]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) ~[spring-aop-6.0.9.jar:6.0.9]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-6.0.9.jar:6.0.9]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-6.0.9.jar:6.0.9]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.0.9.jar:6.0.9]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-6.0.9.jar:6.0.9]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:702) ~[spring-aop-6.0.9.jar:6.0.9]
at org.springframework.boot.actuate.health.HealthEndpoint$$SpringCGLIB$$0.health() ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:281) ~[spring-core-6.0.9.jar:6.0.9]
at org.springframework.boot.actuate.endpoint.invoke.reflect.ReflectiveOperationInvoker.invoke(ReflectiveOperationInvoker.java:74) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOperation.invoke(AbstractDiscoveredOperation.java:60) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.endpoint.jmx.EndpointMBean.invoke(EndpointMBean.java:124) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at org.springframework.boot.actuate.endpoint.jmx.EndpointMBean.invoke(EndpointMBean.java:97) ~[spring-boot-actuator-3.1.0.jar:3.1.0]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:814) ~[?:?]
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:802) ~[?:?]
at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1472) ~[?:?]
at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1310) ~[?:?]
at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1405) ~[?:?]
at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829) ~[?:?]
at jdk.internal.reflect.GeneratedMethodAccessor68.invoke(Unknown Source) ~[?:?]
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360) ~[?:?]
at sun.rmi.transport.Transport$1.run(Transport.java:200) ~[?:?]
at sun.rmi.transport.Transport$1.run(Transport.java:197) ~[?:?]
at java.security.AccessController.doPrivileged(AccessController.java:712) [?:?]
at sun.rmi.transport.Transport.serviceCall(Transport.java:196) ~[?:?]
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:587) ~[?:?]
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828) ~[?:?]
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:705) ~[?:?]
at java.security.AccessController.doPrivileged(AccessController.java:399) [?:?]
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:704) [?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) [?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) [?:?]
at java.lang.Thread.run(Thread.java:833) [?:?]

使用r-nacos的同学请帮忙登记下使用信息,以便后继路过的同学判断项目的可靠性,谢谢。

登记模板:

  • 使用主体:个人或公司;
  • 使用功能:配置中心、注册中心;
  • 使用过程是否遇到问题:

例子1:

  • 使用主体:个人;
  • 使用功能:配置中心;
  • 使用过程是否遇到问题:无;

例子2:

  • 使用主体:某某公司 (如果有官网地址方便的话也可放上);
  • 使用功能:注册中心和配置中心;
  • 使用过程是否遇到问题:无;

关于 rnacos 中使用 raft 协议的疑问

你好,看到这个项目之后非常兴奋。
这也是我一直打算去做的事情。很高兴发现您已经实现了👍。

我有个疑问要请教,rnacos 中使用了 raft 协议来处理存储方面的功能。
但是我没有看到有类似 etcd snapshot 的方案来压缩数据。
请问当前有处理数据压缩的功能方案么? 或者有后续计划么

控制台前端资源请求支持开启gzip以提升页面首屏加载速度

收到用户反馈控制台加载大js文件耗时过长。

计划在控制台前端资源请求支持开启gzip以提升页面首屏加载速度。

暂时只在独立端口号的新控制台增加 gzip 支持。

老的控制台与nacos http 接口使用同一个端口号,全局开启gzip会影响应用使用性能。

实现类Distro协议使注册中心支持集群信息同步。

使用类distro 协议实现集群信息的同步,不追求和java版的distro协议完全兼容。

主要逻辑:

  1. 每个节点有全量的数据,都可提供注册信息查询服务。
  2. 注册中心每个节点平等,按hash划分每个节点负责的内容;节点对负责的服务可写,否则转发到对应负责的节点处理。
  3. 通过 grpc协议注册的服务,接收的节点直接处理。

开发功能项列表:

  1. 集群节点管理器:取 raft 节点列表为distro集群节点列表,通过单独的心跳确认节点是否可用,确认每个节点负责内容范围。
    • 集群节点管理器
    • 注册请求拦截转发器
  2. 实现对指定节点负责的注册信息同步机制(第一次启动时触发)
    • 单节点提供查询节点全量注册信息服务 (可考虑支持分批查询,避免一次查询内容过大)
    • 请求方支持把查询到的内容注册到当前节点中; 遍历集群节点请求一遍即可完成集群全量信息同步。
  3. 增量注册信息同步
    • 信息变更方主动同步信息给其它节点,并维护好心跳;
    • 信息接收方把收到的增量注册同步到当前节点注册中心;
  4. 服务同步信息检测机制
    • 检测同步信息通信是否有异常,如果有异常触发主动查询服务实例列表同步数据。
  5. 集群功能测试,确认各种场景功能逻辑符合预期
  6. 集群性能压力测试,确认集群性能基线
  7. 更新说明文档,发布正式版本

配置数据单机存储从 sqlite 切换到sled

TODO:

  • 熟悉项目内部, sqlite 的使用情况
  • 熟悉 sled 的用法,在 demo 中进行实践
  • 在rnacos项目中,使用 sled 替换 sqlite【目前仅涉及 config】
  • 本地单元测试完成后,提交 PR

控制台接口与页面优化与重构

r-nacos开源后有持续收到用户反馈关于控制台功能优化的需求。为了后续更好的支持这方面功能,我们决定对控制台做一次优化与重构。

  1. 目前控制台接口共25个,其中有部分是复用面向sdk的接口,导致接口返回值结构没有统一。计划把控制台接口现实与页面sdk接口完成区分开,减少相互间的干扰;同时统一控制台接口返回值结构。
  2. 之前r-nacos的前后端都是由我一个人开发;因自身前端也不够专业,当时对前端投入精力不够,页面组件设计投入不足,复用性和一些细节都有优化空间。我们决定对控制台页面做一些代码结构方面的重构,以便更好支持后续的页面功能。控制台页面这部分,后面计划由新加入共建的前端开发同学 @DaqiongYang 负责开发。

这部分的优先级比较高,后续的部分功能对其有依赖,计划最晚在2024-04-20前完成整体调整。

Open API兼容性问题和token生成问题

hello, 偶然发现一个nacos的rust实现,下载看了下,很轻巧,页面也很友好,正在研究能否替换内部项目的nacos,发现一些问题,还请作者看看

  1. token生成问题
    http POST http://127.0.0.1:8848/nacos/v1/auth/login username=nacos password=nacos

返回值:
image

token值为mock_token,不知道是否有意为之,还是还未实现到这步,看源码是写死的
image

  1. open api返回值兼容性
    http GET http://127.0.0.1:8848/nacos/v1/console/namespaces

r-nacos 返回值
image

nacos官方API返回值
image

返回值data属性字段是对不上的,如namespaceShowName-->namespaceName,这就导致目前原有代码无法直接兼容r-nacos

不知道是否可做兼容

开发r-nacos新控制台,支持新开一个http端口、支持用户密码登陆、支持对外网暴露。

目前r-nacos已通过raft协议在集群支持用户、缓存信息储存(r-nacos可当做是一个分布式数据库),后面可以开始支持用户登录鉴权。

  1. 支持另开一个http端口专门用于新控制台,可以单独开放新控制台的端口到外网使用。
  2. 新控制台http端口请求,增加一个统一的登录校验拦截,支持登录校验频率等必要的校验,以支持对外网暴露。
    1. 登录状态拦截中间件
    2. 获取登录验证码接口
    3. 登录校验接口
    4. 查询使用信息接口
    5. 更新用户密码接口
    6. 退出登录接口
    7. 登录校验失败频率限制,防止暴力破解用户密码
  3. 启用新控制台时,默认增加一个管理员。
  4. 新控制台增加一个用户管理模块,管理用户,与用户权限。
    1. 用户表信息支持存储权限角色信息
    2. 管理管理增删查改接口
  5. 新控制台维护一个简易权限控制模块
    1. 角色与权限关系维护
    2. 按角色返回可用的菜单列表接口给前端使用
    3. 控制台请求后端增加权限控制校验
  6. 新控制台 web前端页面实现
    1. 登陆页面
    2. 退出登录
    3. 修改当前用户密码
    4. 用户信息管理
    5. 根据权限控制用户可访问页面

延伸:

  • 后面新控制台基本功能稳定后,会考虑支持OpenID Connect登陆与自定义http鉴权等扩展登录方式。

修复v0.5.0版本raft在初始化index文件分两次写入弟一次写入成功弟二次写入失败,导致重启时index内容不全启动失败的问题。

  • 服务版本: v0.5.0
  • 问题发现方式:用户反馈
  • 问题现像:控制台无法登陆(raft写入失败);同时nacos_db目录只有一个index文件,没有log文件。
  • 问题复现:不好复现
  • 问题定位:
    • 联系发现问题的用户,提供运行失败现场数据文件。
    • 根据文件分析确认index中的两部分数据(last_applied_log_index + index_info)只包含last_applied_log_index,没有index_info部分数据。
    • 进一步确认是index初始化是分两次连续写入,如果弟一次写入成功弟二次写入失败都会出现这个问题。
  • 问题触发条件: 在第一次启动服务之后快速关闭,有小概率触发这个问题。
  • 问题影响范围:只影响初始化异常的服务;如果启动后能正常运行,后续不会触发这个问题。
  • 问题解决方案:
    • 不升级的解决方案,a)关闭服务 b)删除nacos_db c)重新运行服务
    • 升级版本,预计是v0.5.1

问题修复方案:

  1. 初始化index文件时,使用一个write_all一次写入两部分数据;
  2. 加戴index时,兼容支持加载只包含第一部分的数据。

nacos-client 2.2.1的auth、query和configChange问题

因为我们项目使用的nacos版本是2.2.1,目前遇到以下一些问题:

1、nacos 2.2.1 auth的url为:/nacos/v1/auth/users/login,以前的是(/nacos/v1/auth/login)

2、rpc调用query的问题,因为项目本地开发使用dev环境,nacos在查询不到配置的时候会默认查询dev后缀的配置,如:data-id为gateway.yml查询不到就会去查询gateway-dev.yml,但前提是返回的error_code为300,nacos相关源代码:

// ~/.m2/repository/com/alibaba/nacos/nacos-client/2.2.1/nacos-client-2.2.1-sources.jar!/com/alibaba/nacos/client/config/impl/ClientWorker.java#queryConfig
 if (response.isSuccess()) {
    // ...
    return configResponse;
} else if (response.getErrorCode() == ConfigQueryResponse.CONFIG_NOT_FOUND) {
    // ConfigQueryResponse.CONFIG_NOT_FOUND = 300,尝试重新查询dev环境
    LocalConfigInfoProcessor.saveSnapshot(this.getName(), dataId, group, tenant, null);
    LocalEncryptedDataKeyProcessor.saveEncryptDataKeySnapshot(agent.getName(), dataId, group, tenant, null);
    return configResponse;
}

3、我在修改了以上两处bug后又遇到configChange不为空导致无限查询的问题,问题代码在于这里:

// ~/.m2/repository/com/alibaba/nacos/nacos-client/2.2.1/nacos-client-2.2.1-sources.jar!/com/alibaba/nacos/client/config/impl/ClientWorker.java#executeConfigListen

public void executeConfigListen() {
    // ...
    RpcClient rpcClient = ensureRpcClient(taskId);
    ConfigChangeBatchListenResponse configChangeBatchListenResponse = (ConfigChangeBatchListenResponse) requestProxy(rpcClient, configChangeListenRequest);
    if (configChangeBatchListenResponse.isSuccess()) {
    Set<String> changeKeys = new HashSet<>();
    //handle changed keys,notify listener
    // 问题出在这儿,当配置改变的时候,changedConfigs才不为空,但是面前rnacos的rpc是查询到有该配置就返回,所以造成了bug
    if (!CollectionUtils.isEmpty(configChangeBatchListenResponse.getChangedConfigs())) {
        // ...
    }
}

目前我通过注释config_change_batch_listen.rs里面直接返回空值修复改bug,后续肯定是要加上缓存机制完善代码的。

/nacos/v1/ns/instance/beat exception

docker 启动

nacos-client:1.4.6

心跳返回restResult.getData()是个对象,直接(String)restResult.getData();报错

10:48:19.536 [com.alibaba.nacos.naming.beat.sender] DEBUG com.alibaba.nacos.client.naming:476 [] - HTTP method: PUT, url: http://xxxxxx:8850/nacos/v1/ns/instance/beat?app=api-service&serviceName=dev%40%40api-service&namespaceId=public&port=7066&clusterName=DEFAULT&ip=xxxxxx, body: {beat={"port":7066,"ip":"xxxxxxx","weight":1.0,"serviceName":"dev@@API-Service","cluster":"DEFAULT","metadata":{"preserved.register.source":"SPRING_CLOUD"},"scheduled":false,"period":5000,"stopped":false}}
10:48:19.566 [com.alibaba.nacos.naming.beat.sender] ERROR com.alibaba.nacos.client.naming:201 [] - [CLIENT-BEAT] failed to send beat: {"port":7066,"ip":"xxxxxxx","weight":1.0,"serviceName":"dev@@API-Service","cluster":"DEFAULT","metadata":{"preserved.register.source":"SPRING_CLOUD"},"scheduled":false,"period":5000,"stopped":false}, unknown exception msg: errCode: 101, errMsg: Nacos deserialize failed.
com.alibaba.nacos.api.exception.runtime.NacosDeserializationException: errCode: 101, errMsg: Nacos deserialize failed.
at com.alibaba.nacos.common.utils.JacksonUtils.toObj(JacksonUtils.java:227)
at com.alibaba.nacos.client.naming.net.NamingProxy.sendBeat(NamingProxy.java:443)
at com.alibaba.nacos.client.naming.beat.BeatReactor$BeatTask.run(BeatReactor.java:166)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
at java.util.concurrent.FutureTask.run(FutureTask.java)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:750)
Caused by: com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'ok': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
at [Source: (String)"ok"; line: 1, column: 3]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:2391)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:745)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.java:2961)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._handleOddValue(ReaderBasedJsonParser.java:2002)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:802)
at com.fasterxml.jackson.databind.ObjectMapper._readTreeAndClose(ObjectMapper.java:4703)
at com.fasterxml.jackson.databind.ObjectMapper.readTree(ObjectMapper.java:3076)
at com.alibaba.nacos.common.utils.JacksonUtils.toObj(JacksonUtils.java:225)
... 10 common frames omitted

Task Track: 支持查询服务监听列表

TODOs:

  • actix-web 中 actor 的相关内容,以及是如何使用的
  • [-] 看一看 nacos 源码,熟悉这块对应的内容如何实现的 【逻辑实现不太一致】
  • [/] 着手实现 config 这边对应的接口
  • 本地自测、提交PR

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.