09 | 线上服务:如何在线上提供高并发的推荐服务?
一个工业级的推荐服务器内部究竟都做了哪些事情?像阿里、字节、腾讯这样级别的公司,它们的推荐系统是怎么承接住每秒百万甚至上千万的推荐请求的?我们自己该如何搭建一个工业级推荐服务器的雏形呢?
下面就是我们 Sparrow Recsys 中创建推荐服务器的代码,我已经在所有关键的地方添加了注释,你可以逐句解读一下。
public class RecSysServer {
//主函数,创建推荐服务器并运行
public static void main(String[] args) throws Exception {
new RecSysServer().run();
}
//推荐服务器的默认服务端口6010
private static final int DEFAULT_PORT = 6010;
//运行推荐服务器的函数
public void run() throws Exception{
int port = DEFAULT_PORT;
//绑定IP地址和端口,0.0.0.0代表本地运行
InetSocketAddress inetAddress = new InetSocketAddress("0.0.0.0", port);
//创建Jetty服务器
Server server = new Server(inetAddress);
//创建Jetty服务器的环境handler
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
context.setWelcomeFiles(new String[] { "index.html" });
//添加API,getMovie,获取电影相关数据
context.addServlet(new ServletHolder(new MovieService()), "/getmovie");
//添加API,getuser,获取用户相关数据
context.addServlet(new ServletHolder(new UserService()), "/getuser");
//添加API,getsimilarmovie,获取相似电影推荐
context.addServlet(new ServletHolder(new SimilarMovieService()), "/getsimilarmovie");
//添加API,getrecommendation,获取各类电影推荐
context.addServlet(new ServletHolder(new RecommendationService()), "/getrecommendation");
//设置Jetty的环境handler
server.setHandler(context);
//启动Jetty服务器
server.start();
server.join();
}
你可以看到,创建 Jetty 服务的过程非常简单直观,十几行代码就可以搭建起一套推荐服务。当然,推荐服务的主要业务逻辑并不在这里,而是在每个注册到 Jetty Context 中的 Servlet 服务中。这里我们用其中最简单的 Servlet 服务 MovieService,来看一看 Jetty 中的 Servlet 服务是怎么写的。
//MovieService需要继承Jetty的HttpServlet
public class MovieService extends HttpServlet {
//实现servlet中的get method
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws IOException {
try {
//该接口返回json对象,所以设置json类型
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
response.setCharacterEncoding("UTF-8");
response.setHeader("Access-Control-Allow-Origin", "*");
//获得请求中的id参数,转换为movie id
String movieId = request.getParameter("id");
//从数据库中获取该movie的数据对象
Movie movie = DataManager.getInstance().getMovieById(Integer.parseInt(movieId));
if (null != movie) {
//使用fasterxml.jackson库把movie对象转换成json对象
ObjectMapper mapper = new ObjectMapper();
String jsonMovie = mapper.writeValueAsString(movie);
//返回json对象
response.getWriter().println(jsonMovie);
}else {
response.getWriter().println("");
}
} catch (Exception e) {
e.printStackTrace();
response.getWriter().println("");
}
}
熟悉了这个 Servlet 服务,其他服务就依葫芦画瓢就可以啦。唯一的不同就是其中的业务逻辑。如果你已经从 GitHub 上下载了 Sparrow Recsys 项目把它运行起来,并且在浏览器中输入 http://localhost:6010/getmovie?id=1,就可以看到 getMovie 接口的返回对象了。
小结
这节课我们既学习了怎么“造火箭”,又实践了怎么“拧螺丝”。对于一个合格的算法工程师来说,这两方面缺一不可。“造火箭”的知识包括工业级推荐服务器的具体功能,以及实现工业级高并发推荐服务的主要机制。其中,推荐服务器的具体功能主要有:模型服务、数据库接口、推荐模块逻辑、补充业务逻辑等等,而工业级高并发推荐服务的主要机制有负载均衡、缓存和服务降级。“拧螺丝”的技能我们也掌握了不少,我们利用 Jetty 实践并搭建起了我们 SparrowRecSys 的推荐服务接口。这个过程中,我们需要重点关注的是,每个注册到 Jetty Context 的 Servlet 服务中的主要业务逻辑,只要掌握了一个,在实际工作中我们就能举一反三了。老规矩,我今天继续用表格的形式帮你整理了这节课的主要知识点,你可以看看。
此文章为3月Day25学习笔记,内容来源于极客时间《深度学习推荐系统实战》,强烈推荐该课程!